2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 package org.altusmetrum.altoslib_14;
24 public class AltosCSV implements AltosWriter {
27 boolean header_written;
38 boolean has_flight_state;
44 boolean has_companion;
45 boolean has_motor_pressure;
47 AltosFlightSeries series;
50 static final int ALTOS_CSV_VERSION = 6;
59 * time (seconds since boost)
61 * Radio info (if available)
74 * accelerometer speed (m/s)
75 * barometer speed (m/s)
83 * Advanced sensors (if available)
95 * Extra igniter voltages (if available)
102 * GPS data (if available)
105 * nsat (used for solution)
116 * from_pad_azimuth (deg true)
118 * from_pad_elevation (deg from horizon)
124 * C/N0 data for all 32 valid SDIDs
127 * companion_id (1-255. 10 is TeleScience)
128 * time of last companion data (seconds since boost)
129 * update_period (0.1-2.55 minimum telemetry interval)
131 * channel data for all 12 possible channels
134 void write_general_header() {
135 out.printf(Locale.ROOT,"version,serial,flight");
136 if (series.cal_data().callsign != null)
137 out.printf(Locale.ROOT,",call");
138 out.printf(Locale.ROOT,",time");
142 return series.time(indices);
145 void write_general() {
146 out.printf(Locale.ROOT,"%s, %d, %d",
148 series.cal_data().serial,
149 series.cal_data().flight);
150 if (series.cal_data().callsign != null)
151 out.printf(Locale.ROOT,",%s", series.cal_data().callsign);
152 out.printf(Locale.ROOT,", %8.2f", time());
155 void write_radio_header() {
156 out.printf(Locale.ROOT,"rssi,lqi");
160 return (int) series.value(AltosFlightSeries.rssi_name, indices);
164 return (int) series.value(AltosFlightSeries.status_name, indices);
168 out.printf(Locale.ROOT,"%4d, %3d",
169 rssi(), status() & 0x7f);
172 void write_flight_header() {
173 out.printf(Locale.ROOT,"state,state_name");
177 return (int) series.value(AltosFlightSeries.state_name, indices);
180 void write_flight() {
182 out.printf(Locale.ROOT,"%2d,%8s", state, AltosLib.state_name(state));
185 void write_basic_header() {
187 out.printf(Locale.ROOT,"acceleration,");
189 out.printf(Locale.ROOT,"pressure,altitude,");
190 out.printf(Locale.ROOT,"height,speed");
192 out.printf(Locale.ROOT,",temperature");
194 out.printf(Locale.ROOT,",drogue_voltage,main_voltage");
197 double acceleration() { return series.value(AltosFlightSeries.accel_name, indices); }
198 double pressure() { return series.value(AltosFlightSeries.pressure_name, indices); }
199 double altitude() { return series.value(AltosFlightSeries.altitude_name, indices); }
200 double height() { return series.value(AltosFlightSeries.height_name, indices); }
201 double speed() { return series.value(AltosFlightSeries.speed_name, indices); }
202 double temperature() { return series.value(AltosFlightSeries.temperature_name, indices); }
203 double apogee_voltage() { return series.value(AltosFlightSeries.apogee_voltage_name, indices); }
204 double main_voltage() { return series.value(AltosFlightSeries.main_voltage_name, indices); }
208 out.printf(Locale.ROOT,"%8.2f,", acceleration());
210 out.printf(Locale.ROOT,"%10.2f,%8.2f,",
211 pressure(), altitude());
212 out.printf(Locale.ROOT,"%8.2f,%8.2f",
215 out.printf(Locale.ROOT,",%5.1f", temperature());
217 out.printf(Locale.ROOT,",%5.2f,%5.2f",
222 void write_battery_header() {
223 out.printf(Locale.ROOT,"battery_voltage");
226 double battery_voltage() { return series.value(AltosFlightSeries.battery_voltage_name, indices); }
228 void write_battery() {
229 out.printf(Locale.ROOT,"%5.2f", battery_voltage());
232 void write_motor_pressure_header() {
233 out.printf(Locale.ROOT,"motor_pressure");
236 double motor_pressure() { return series.value(AltosFlightSeries.motor_pressure_name, indices); }
238 void write_motor_pressure() {
239 out.printf(Locale.ROOT,"%10.1f", motor_pressure());
242 void write_3d_accel_header() {
243 out.printf(Locale.ROOT,"accel_x,accel_y,accel_z");
246 double accel_along() { return series.value(AltosFlightSeries.accel_along_name, indices); }
247 double accel_across() { return series.value(AltosFlightSeries.accel_across_name, indices); }
248 double accel_through() { return series.value(AltosFlightSeries.accel_through_name, indices); }
250 void write_3d_accel() {
251 out.printf(Locale.ROOT,"%7.2f,%7.2f,%7.2f",
252 accel_along(), accel_across(), accel_through());
255 void write_imu_header() {
256 out.printf(Locale.ROOT,"gyro_roll,gyro_pitch,gyro_yaw,mag_x,mag_y,mag_z,tilt");
259 double gyro_roll() { return series.value(AltosFlightSeries.gyro_roll_name, indices); }
260 double gyro_pitch() { return series.value(AltosFlightSeries.gyro_pitch_name, indices); }
261 double gyro_yaw() { return series.value(AltosFlightSeries.gyro_yaw_name, indices); }
263 double mag_along() { return series.value(AltosFlightSeries.mag_along_name, indices); }
264 double mag_across() { return series.value(AltosFlightSeries.mag_across_name, indices); }
265 double mag_through() { return series.value(AltosFlightSeries.mag_through_name, indices); }
267 double tilt() { return series.value(AltosFlightSeries.orient_name, indices); }
270 out.printf(Locale.ROOT,"%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f",
271 gyro_roll(), gyro_pitch(), gyro_yaw(),
272 mag_along(), mag_across(), mag_through(),
276 void write_igniter_header() {
277 out.printf(Locale.ROOT,"pyro");
278 for (int i = 0; i < series.igniter_voltage.length; i++)
279 out.printf(Locale.ROOT,",%s", AltosLib.igniter_short_name(i));
282 double pyro() { return series.value(AltosFlightSeries.pyro_voltage_name, indices); }
284 double igniter_value(int channel) { return series.value(series.igniter_voltage_name(channel), indices); }
286 void write_igniter() {
287 out.printf(Locale.ROOT,"%5.2f", pyro());
288 for (int i = 0; i < series.igniter_voltage.length; i++)
289 out.printf(Locale.ROOT,",%5.2f", igniter_value(i));
292 void write_gps_header() {
293 out.printf(Locale.ROOT,"connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,pdop,hdop,vdop");
297 AltosGPS gps = series.gps_before(series.time(indices));
299 AltosGreatCircle from_pad;
301 if (series.cal_data().gps_pad != null && gps != null)
302 from_pad = new AltosGreatCircle(series.cal_data().gps_pad, gps);
304 from_pad = new AltosGreatCircle();
307 gps = new AltosGPS();
309 out.printf(Locale.ROOT,"%2d,%2d,%3d,%12.7f,%12.7f,%8.1f,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f,%6.1f,%6.1f",
331 void write_gps_sat_header() {
332 for(int i = 1; i <= 32; i++) {
333 out.printf(Locale.ROOT,"sat%02d", i);
335 out.printf(Locale.ROOT,",");
339 void write_gps_sat() {
340 AltosGPS gps = series.gps_before(series.time(indices));
341 for(int i = 1; i <= 32; i++) {
343 if (gps != null && gps.cc_gps_sat != null) {
344 for(int j = 0; j < gps.cc_gps_sat.length; j++)
345 if (gps.cc_gps_sat[j].svid == i) {
346 c_n0 = gps.cc_gps_sat[j].c_n0;
350 out.printf ("%3d", c_n0);
352 out.printf(Locale.ROOT,",");
356 void write_companion_header() {
358 out.printf(Locale.ROOT,"companion_id,companion_time,companion_update,companion_channels");
359 for (int i = 0; i < 12; i++)
360 out.printf(Locale.ROOT,",companion_%02d", i);
364 void write_companion() {
366 AltosCompanion companion = state.companion;
368 int channels_written = 0;
369 if (companion == null) {
370 out.printf(Locale.ROOT,"0,0,0,0");
372 out.printf(Locale.ROOT,"%3d,%5.2f,%5.2f,%2d",
374 (companion.tick - boost_tick) / 100.0,
375 companion.update_period / 100.0,
377 for (; channels_written < companion.channels; channels_written++)
378 out.printf(Locale.ROOT,",%5d", companion.companion_data[channels_written]);
380 for (; channels_written < 12; channels_written++)
381 out.printf(Locale.ROOT,",0");
385 void write_header() {
386 out.printf(Locale.ROOT,"#"); write_general_header();
388 out.printf(Locale.ROOT,",");
389 write_radio_header();
391 if (has_flight_state) {
392 out.printf(Locale.ROOT,",");
393 write_flight_header();
396 out.printf(Locale.ROOT,",");
397 write_basic_header();
400 out.printf(Locale.ROOT,",");
401 write_battery_header();
403 if (has_motor_pressure) {
404 out.printf(Locale.ROOT,",");
405 write_motor_pressure_header();
408 out.printf(Locale.ROOT,",");
409 write_3d_accel_header();
412 out.printf(Locale.ROOT,",");
416 out.printf(Locale.ROOT,",");
417 write_igniter_header();
420 out.printf(Locale.ROOT,",");
424 out.printf(Locale.ROOT,",");
425 write_gps_sat_header();
428 out.printf(Locale.ROOT,",");
429 write_companion_header();
437 out.printf(Locale.ROOT,",");
440 if (has_flight_state) {
441 out.printf(Locale.ROOT,",");
445 out.printf(Locale.ROOT,",");
449 out.printf(Locale.ROOT,",");
452 if (has_motor_pressure) {
453 out.printf(Locale.ROOT,",");
454 write_motor_pressure();
457 out.printf(Locale.ROOT,",");
461 out.printf(Locale.ROOT,",");
465 out.printf(Locale.ROOT,",");
469 out.printf(Locale.ROOT,",");
473 out.printf(Locale.ROOT,",");
477 out.printf(Locale.ROOT,",");
483 private void write() {
484 if (state() == AltosLib.ao_flight_startup)
486 if (!header_written) {
488 header_written = true;
493 private PrintStream out() {
497 public void close() {
501 public void write(AltosFlightSeries series) {
502 // series.write_comments(out());
504 this.series = series;
509 has_flight_state = false;
515 has_motor_pressure = false;
516 has_3d_accel = false;
521 has_companion = false;
523 if (series.has_series(AltosFlightSeries.rssi_name))
525 if (series.has_series(AltosFlightSeries.state_name))
526 has_flight_state = true;
527 if (series.has_series(AltosFlightSeries.accel_name)) {
531 if (series.has_series(AltosFlightSeries.pressure_name)) {
535 if (series.has_series(AltosFlightSeries.apogee_voltage_name))
537 if (series.has_series(AltosFlightSeries.battery_voltage_name))
539 if (series.has_series(AltosFlightSeries.motor_pressure_name))
540 has_motor_pressure = true;
541 if (series.has_series(AltosFlightSeries.accel_across_name))
543 if (series.has_series(AltosFlightSeries.gyro_roll_name))
545 if (series.has_series(AltosFlightSeries.pyro_voltage_name))
548 if (series.gps_series != null)
550 if (series.sats_in_view != null)
553 if (state.companion != null)
554 has_companion = true;
557 indices = series.indices();
561 if (!series.step_indices(indices))
566 public AltosCSV(PrintStream in_out, File in_name) {
571 public AltosCSV(File in_name) throws FileNotFoundException {
572 this(new PrintStream(in_name), in_name);
575 public AltosCSV(String in_string) throws FileNotFoundException {
576 this(new File(in_string));