altosui: Fetch RF calibration value for TBT v4.0 units from web
[fw/altos] / altoslib / AltosCSV.java
1 /*
2  * Copyright © 2010 Keith Packard <keithp@keithp.com>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 package org.altusmetrum.altoslib_13;
20
21 import java.io.*;
22 import java.util.*;
23
24 public class AltosCSV implements AltosWriter {
25         File                    name;
26         PrintStream             out;
27         boolean                 header_written;
28         boolean                 seen_boost;
29         int                     boost_tick;
30
31         boolean                 has_basic;
32         boolean                 has_radio;
33         boolean                 has_battery;
34         boolean                 has_flight_state;
35         boolean                 has_advanced;
36         boolean                 has_igniter;
37         boolean                 has_gps;
38         boolean                 has_gps_sat;
39         boolean                 has_companion;
40
41         AltosFlightSeries       series;
42         int[]                   indices;
43
44         static final int ALTOS_CSV_VERSION = 6;
45
46         /* Version 4 format:
47          *
48          * General info
49          *      version number
50          *      serial number
51          *      flight number
52          *      callsign
53          *      time (seconds since boost)
54          *
55          * Radio info (if available)
56          *      rssi
57          *      link quality
58          *
59          * Flight status
60          *      state
61          *      state name
62          *
63          * Basic sensors
64          *      acceleration (m/s²)
65          *      pressure (mBar)
66          *      altitude (m)
67          *      height (m)
68          *      accelerometer speed (m/s)
69          *      barometer speed (m/s)
70          *      temp (°C)
71          *      drogue (V)
72          *      main (V)
73          *
74          * Battery
75          *      battery (V)
76          *
77          * Advanced sensors (if available)
78          *      accel_x (m/s²)
79          *      accel_y (m/s²)
80          *      accel_z (m/s²)
81          *      gyro_x (d/s)
82          *      gyro_y (d/s)
83          *      gyro_z (d/s)
84          *      mag_x (g)
85          *      mag_y (g)
86          *      mag_z (g)
87          *      tilt (d)
88          *
89          * Extra igniter voltages (if available)
90          *      pyro (V)
91          *      igniter_a (V)
92          *      igniter_b (V)
93          *      igniter_c (V)
94          *      igniter_d (V)
95          *
96          * GPS data (if available)
97          *      connected (1/0)
98          *      locked (1/0)
99          *      nsat (used for solution)
100          *      latitude (°)
101          *      longitude (°)
102          *      altitude (m)
103          *      year (e.g. 2010)
104          *      month (1-12)
105          *      day (1-31)
106          *      hour (0-23)
107          *      minute (0-59)
108          *      second (0-59)
109          *      from_pad_dist (m)
110          *      from_pad_azimuth (deg true)
111          *      from_pad_range (m)
112          *      from_pad_elevation (deg from horizon)
113          *      pdop
114          *      hdop
115          *      vdop
116          *
117          * GPS Sat data
118          *      C/N0 data for all 32 valid SDIDs
119          *
120          * Companion data
121          *      companion_id (1-255. 10 is TeleScience)
122          *      time of last companion data (seconds since boost)
123          *      update_period (0.1-2.55 minimum telemetry interval)
124          *      channels (0-12)
125          *      channel data for all 12 possible channels
126          */
127
128         void write_general_header() {
129                 out.printf("version,serial,flight,call,time");
130         }
131
132         double time() {
133                 return series.time(indices);
134         }
135
136         void write_general() {
137                 out.printf("%s, %d, %d, %s, %8.2f",
138                            ALTOS_CSV_VERSION,
139                            series.cal_data().serial,
140                            series.cal_data().flight,
141                            series.cal_data().callsign,
142                            time());
143         }
144
145         void write_radio_header() {
146                 out.printf("rssi,lqi");
147         }
148
149         int rssi() {
150                 return (int) series.value(AltosFlightSeries.rssi_name, indices);
151         }
152
153         int status() {
154                 return (int) series.value(AltosFlightSeries.status_name, indices);
155         }
156
157         void write_radio() {
158                 out.printf("%4d, %3d",
159                            rssi(), status() & 0x7f);
160         }
161
162         void write_flight_header() {
163                 out.printf("state,state_name");
164         }
165
166         int state() {
167                 return (int) series.value(AltosFlightSeries.state_name, indices);
168         }
169
170         void write_flight() {
171                 int state = state();
172                 out.printf("%2d,%8s", state, AltosLib.state_name(state));
173         }
174
175         void write_basic_header() {
176                 out.printf("acceleration,pressure,altitude,height,accel_speed,baro_speed,temperature,drogue_voltage,main_voltage");
177         }
178
179         double acceleration() { return series.value(AltosFlightSeries.accel_name, indices); }
180         double pressure() { return series.value(AltosFlightSeries.pressure_name, indices); }
181         double altitude() { return series.value(AltosFlightSeries.altitude_name, indices); }
182         double height() { return series.value(AltosFlightSeries.height_name, indices); }
183         double speed() { return series.value(AltosFlightSeries.speed_name, indices); }
184         double temperature() { return series.value(AltosFlightSeries.temperature_name, indices); }
185         double apogee_voltage() { return series.value(AltosFlightSeries.apogee_voltage_name, indices); }
186         double main_voltage() { return series.value(AltosFlightSeries.main_voltage_name, indices); }
187
188         void write_basic() {
189                 out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f",
190                            acceleration(),
191                            pressure(),
192                            altitude(),
193                            height(),
194                            speed(),
195                            speed(),
196                            temperature(),
197                            apogee_voltage(),
198                            main_voltage());
199         }
200
201         void write_battery_header() {
202                 out.printf("battery_voltage");
203         }
204
205         double battery_voltage() { return series.value(AltosFlightSeries.battery_voltage_name, indices); }
206
207         void write_battery() {
208                 out.printf("%5.2f", battery_voltage());
209         }
210
211         void write_advanced_header() {
212                 out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z,tilt");
213         }
214
215         double accel_along() { return series.value(AltosFlightSeries.accel_along_name, indices); }
216         double accel_across() { return series.value(AltosFlightSeries.accel_across_name, indices); }
217         double accel_through() { return series.value(AltosFlightSeries.accel_through_name, indices); }
218
219         double gyro_roll() { return series.value(AltosFlightSeries.gyro_roll_name, indices); }
220         double gyro_pitch() { return series.value(AltosFlightSeries.gyro_pitch_name, indices); }
221         double gyro_yaw() { return series.value(AltosFlightSeries.gyro_yaw_name, indices); }
222
223         double mag_along() { return series.value(AltosFlightSeries.mag_along_name, indices); }
224         double mag_across() { return series.value(AltosFlightSeries.mag_across_name, indices); }
225         double mag_through() { return series.value(AltosFlightSeries.mag_through_name, indices); }
226
227         double tilt() { return series.value(AltosFlightSeries.orient_name, indices); }
228
229         void write_advanced() {
230                 out.printf("%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f",
231                            accel_along(), accel_across(), accel_through(),
232                            gyro_roll(), gyro_pitch(), gyro_yaw(),
233                            mag_along(), mag_across(), mag_through(),
234                            tilt());
235         }
236
237         void write_igniter_header() {
238                 out.printf("pyro");
239                 for (int i = 0; i < series.igniter_voltage.length; i++)
240                         out.printf(",%s", AltosLib.igniter_short_name(i));
241         }
242
243         double pyro() { return series.value(AltosFlightSeries.pyro_voltage_name, indices); }
244
245         double igniter_value(int channel) { return series.value(series.igniter_voltage_name(channel), indices); }
246
247         void write_igniter() {
248                 out.printf("%5.2f", pyro());
249                 for (int i = 0; i < series.igniter_voltage.length; i++)
250                         out.printf(",%5.2f", igniter_value(i));
251         }
252
253         void write_gps_header() {
254                 out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,pdop,hdop,vdop");
255         }
256
257         void write_gps() {
258                 AltosGPS        gps = series.gps_before(series.time(indices));
259
260                 AltosGreatCircle from_pad;
261
262                 if (series.cal_data().gps_pad != null && gps != null)
263                         from_pad = new AltosGreatCircle(series.cal_data().gps_pad, gps);
264                 else
265                         from_pad = new AltosGreatCircle();
266
267                 if (gps == null)
268                         gps = new AltosGPS();
269
270                 out.printf("%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",
271                            gps.connected?1:0,
272                            gps.locked?1:0,
273                            gps.nsat,
274                            gps.lat,
275                            gps.lon,
276                            gps.alt,
277                            gps.year,
278                            gps.month,
279                            gps.day,
280                            gps.hour,
281                            gps.minute,
282                            gps.second,
283                            from_pad.distance,
284                            from_pad.range,
285                            from_pad.bearing,
286                            from_pad.elevation,
287                            gps.pdop,
288                            gps.hdop,
289                            gps.vdop);
290         }
291
292         void write_gps_sat_header() {
293                 for(int i = 1; i <= 32; i++) {
294                         out.printf("sat%02d", i);
295                         if (i != 32)
296                                 out.printf(",");
297                 }
298         }
299
300         void write_gps_sat() {
301                 AltosGPS        gps = series.gps_before(series.time(indices));
302                 for(int i = 1; i <= 32; i++) {
303                         int     c_n0 = 0;
304                         if (gps != null && gps.cc_gps_sat != null) {
305                                 for(int j = 0; j < gps.cc_gps_sat.length; j++)
306                                         if (gps.cc_gps_sat[j].svid == i) {
307                                                 c_n0 = gps.cc_gps_sat[j].c_n0;
308                                                 break;
309                                         }
310                         }
311                         out.printf ("%3d", c_n0);
312                         if (i != 32)
313                                 out.printf(",");
314                 }
315         }
316
317         void write_companion_header() {
318 /*
319                 out.printf("companion_id,companion_time,companion_update,companion_channels");
320                 for (int i = 0; i < 12; i++)
321                         out.printf(",companion_%02d", i);
322 */
323         }
324
325         void write_companion() {
326 /*
327                 AltosCompanion companion = state.companion;
328
329                 int     channels_written = 0;
330                 if (companion == null) {
331                         out.printf("0,0,0,0");
332                 } else {
333                         out.printf("%3d,%5.2f,%5.2f,%2d",
334                                    companion.board_id,
335                                    (companion.tick - boost_tick) / 100.0,
336                                    companion.update_period / 100.0,
337                                    companion.channels);
338                         for (; channels_written < companion.channels; channels_written++)
339                                 out.printf(",%5d", companion.companion_data[channels_written]);
340                 }
341                 for (; channels_written < 12; channels_written++)
342                         out.printf(",0");
343 */
344         }
345
346         void write_header() {
347                 out.printf("#"); write_general_header();
348                 if (has_radio) {
349                         out.printf(",");
350                         write_radio_header();
351                 }
352                 if (has_flight_state) {
353                         out.printf(",");
354                         write_flight_header();
355                 }
356                 if (has_basic) {
357                         out.printf(",");
358                         write_basic_header();
359                 }
360                 if (has_battery) {
361                         out.printf(",");
362                         write_battery_header();
363                 }
364                 if (has_advanced) {
365                         out.printf(",");
366                         write_advanced_header();
367                 }
368                 if (has_igniter) {
369                         out.printf(",");
370                         write_igniter_header();
371                 }
372                 if (has_gps) {
373                         out.printf(",");
374                         write_gps_header();
375                 }
376                 if (has_gps_sat) {
377                         out.printf(",");
378                         write_gps_sat_header();
379                 }
380                 if (has_companion) {
381                         out.printf(",");
382                         write_companion_header();
383                 }
384                 out.printf ("\n");
385         }
386
387         void write_one() {
388                 write_general();
389                 if (has_radio) {
390                         out.printf(",");
391                         write_radio();
392                 }
393                 if (has_flight_state) {
394                         out.printf(",");
395                         write_flight();
396                 }
397                 if (has_basic) {
398                         out.printf(",");
399                         write_basic();
400                 }
401                 if (has_battery) {
402                         out.printf(",");
403                         write_battery();
404                 }
405                 if (has_advanced) {
406                         out.printf(",");
407                         write_advanced();
408                 }
409                 if (has_igniter) {
410                         out.printf(",");
411                         write_igniter();
412                 }
413                 if (has_gps) {
414                         out.printf(",");
415                         write_gps();
416                 }
417                 if (has_gps_sat) {
418                         out.printf(",");
419                         write_gps_sat();
420                 }
421                 if (has_companion) {
422                         out.printf(",");
423                         write_companion();
424                 }
425                 out.printf ("\n");
426         }
427
428         private void write() {
429                 if (state() == AltosLib.ao_flight_startup)
430                         return;
431                 if (!header_written) {
432                         write_header();
433                         header_written = true;
434                 }
435                 write_one();
436         }
437
438         private PrintStream out() {
439                 return out;
440         }
441
442         public void close() {
443                 out.close();
444         }
445
446         public void write(AltosFlightSeries series) {
447 //              series.write_comments(out());
448
449                 this.series = series;
450
451                 series.finish();
452
453                 has_radio = false;
454                 has_flight_state = false;
455                 has_basic = false;
456                 has_battery = false;
457                 has_advanced = false;
458                 has_igniter = false;
459                 has_gps = false;
460                 has_gps_sat = false;
461                 has_companion = false;
462
463                 if (series.has_series(AltosFlightSeries.rssi_name))
464                         has_radio = true;
465                 if (series.has_series(AltosFlightSeries.state_name))
466                         has_flight_state = true;
467                 if (series.has_series(AltosFlightSeries.accel_name) || series.has_series(AltosFlightSeries.pressure_name))
468                         has_basic = true;
469                 if (series.has_series(AltosFlightSeries.battery_voltage_name))
470                         has_battery = true;
471                 if (series.has_series(AltosFlightSeries.accel_across_name))
472                         has_advanced = true;
473                 if (series.has_series(AltosFlightSeries.pyro_voltage_name))
474                         has_igniter = true;
475
476                 if (series.gps_series != null)
477                         has_gps = true;
478                 if (series.sats_in_view != null)
479                         has_gps_sat = true;
480                 /*
481                 if (state.companion != null)
482                         has_companion = true;
483                 */
484
485                 indices = series.indices();
486
487                 for (;;) {
488                         write();
489                         if (!series.step_indices(indices))
490                                 break;
491                 }
492         }
493
494         public AltosCSV(PrintStream in_out, File in_name) {
495                 name = in_name;
496                 out = in_out;
497         }
498
499         public AltosCSV(File in_name) throws FileNotFoundException {
500                 this(new PrintStream(in_name), in_name);
501         }
502
503         public AltosCSV(String in_string) throws FileNotFoundException {
504                 this(new File(in_string));
505         }
506 }