libaltos: fix test harness main type
[fw/altos] / altosui / 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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package altosui;
19
20 import java.io.*;
21 import java.util.*;
22 import org.altusmetrum.altoslib_2.*;
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         LinkedList<AltosState>  pad_states;
31         AltosState              state;
32
33         static final int ALTOS_CSV_VERSION = 5;
34
35         /* Version 4 format:
36          *
37          * General info
38          *      version number
39          *      serial number
40          *      flight number
41          *      callsign
42          *      time (seconds since boost)
43          *      clock (tick count / 100)
44          *      rssi
45          *      link quality
46          *
47          * Flight status
48          *      state
49          *      state name
50          *
51          * Basic sensors
52          *      acceleration (m/s²)
53          *      pressure (mBar)
54          *      altitude (m)
55          *      height (m)
56          *      accelerometer speed (m/s)
57          *      barometer speed (m/s)
58          *      temp (°C)
59          *      battery (V)
60          *      drogue (V)
61          *      main (V)
62          *
63          * Advanced sensors (if available)
64          *      accel_x (m/s²)
65          *      accel_y (m/s²)
66          *      accel_z (m/s²)
67          *      gyro_x (d/s)
68          *      gyro_y (d/s)
69          *      gyro_z (d/s)
70          *      mag_x (g)
71          *      mag_y (g)
72          *      mag_z (g)
73          *
74          * GPS data (if available)
75          *      connected (1/0)
76          *      locked (1/0)
77          *      nsat (used for solution)
78          *      latitude (°)
79          *      longitude (°)
80          *      altitude (m)
81          *      year (e.g. 2010)
82          *      month (1-12)
83          *      day (1-31)
84          *      hour (0-23)
85          *      minute (0-59)
86          *      second (0-59)
87          *      from_pad_dist (m)
88          *      from_pad_azimuth (deg true)
89          *      from_pad_range (m)
90          *      from_pad_elevation (deg from horizon)
91          *      hdop
92          *
93          * GPS Sat data
94          *      C/N0 data for all 32 valid SDIDs
95          *
96          * Companion data
97          *      companion_id (1-255. 10 is TeleScience)
98          *      time of last companion data (seconds since boost)
99          *      update_period (0.1-2.55 minimum telemetry interval)
100          *      channels (0-12)
101          *      channel data for all 12 possible channels
102          */
103
104         void write_general_header() {
105                 out.printf("version,serial,flight,call,time,clock,rssi,lqi");
106         }
107
108         void write_general(AltosState state) {
109                 out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d",
110                            ALTOS_CSV_VERSION, state.serial, state.flight, state.callsign,
111                            (double) state.time, (double) state.tick / 100.0,
112                            state.rssi,
113                            state.status & 0x7f);
114         }
115
116         void write_flight_header() {
117                 out.printf("state,state_name");
118         }
119
120         void write_flight(AltosState state) {
121                 out.printf("%d,%8s", state.state, state.state_name());
122         }
123
124         void write_basic_header() {
125                 out.printf("acceleration,pressure,altitude,height,accel_speed,baro_speed,temperature,battery_voltage,drogue_voltage,main_voltage");
126         }
127
128         void write_basic(AltosState state) {
129                 out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",
130                            state.acceleration(),
131                            state.pressure(),
132                            state.altitude(),
133                            state.height(),
134                            state.speed(),
135                            state.speed(),
136                            state.temperature,
137                            state.battery_voltage,
138                            state.apogee_voltage,
139                            state.main_voltage);
140         }
141
142         void write_advanced_header() {
143                 out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z");
144         }
145
146         void write_advanced(AltosState state) {
147                 AltosIMU        imu = state.imu;
148                 AltosMag        mag = state.mag;
149
150                 if (imu == null)
151                         imu = new AltosIMU();
152                 if (mag == null)
153                         mag = new AltosMag();
154                 out.printf("%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d",
155                            imu.accel_x, imu.accel_y, imu.accel_z,
156                            imu.gyro_x, imu.gyro_y, imu.gyro_z,
157                            mag.x, mag.y, mag.z);
158         }
159
160         void write_gps_header() {
161                 out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,hdop");
162         }
163
164         void write_gps(AltosState state) {
165                 AltosGPS        gps = state.gps;
166                 if (gps == null)
167                         gps = new AltosGPS();
168
169                 AltosGreatCircle from_pad = state.from_pad;
170                 if (from_pad == null)
171                         from_pad = new AltosGreatCircle();
172
173                 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",
174                            gps.connected?1:0,
175                            gps.locked?1:0,
176                            gps.nsat,
177                            gps.lat,
178                            gps.lon,
179                            gps.alt,
180                            gps.year,
181                            gps.month,
182                            gps.day,
183                            gps.hour,
184                            gps.minute,
185                            gps.second,
186                            from_pad.distance,
187                            state.range,
188                            from_pad.bearing,
189                            state.elevation,
190                            gps.hdop);
191         }
192
193         void write_gps_sat_header() {
194                 for(int i = 1; i <= 32; i++) {
195                         out.printf("sat%02d", i);
196                         if (i != 32)
197                                 out.printf(",");
198                 }
199         }
200
201         void write_gps_sat(AltosState state) {
202                 AltosGPS        gps = state.gps;
203                 for(int i = 1; i <= 32; i++) {
204                         int     c_n0 = 0;
205                         if (gps != null && gps.cc_gps_sat != null) {
206                                 for(int j = 0; j < gps.cc_gps_sat.length; j++)
207                                         if (gps.cc_gps_sat[j].svid == i) {
208                                                 c_n0 = gps.cc_gps_sat[j].c_n0;
209                                                 break;
210                                         }
211                         }
212                         out.printf ("%3d", c_n0);
213                         if (i != 32)
214                                 out.printf(",");
215                 }
216         }
217
218         void write_companion_header() {
219                 out.printf("companion_id,companion_time,companion_update,companion_channels");
220                 for (int i = 0; i < 12; i++)
221                         out.printf(",companion_%02d", i);
222         }
223
224         void write_companion(AltosState state) {
225                 AltosCompanion companion = state.companion;
226
227                 int     channels_written = 0;
228                 if (companion == null) {
229                         out.printf("0,0,0,0");
230                 } else {
231                         out.printf("%3d,%5.2f,%5.2f,%2d",
232                                    companion.board_id,
233                                    (companion.tick - boost_tick) / 100.0,
234                                    companion.update_period / 100.0,
235                                    companion.channels);
236                         for (; channels_written < companion.channels; channels_written++)
237                                 out.printf(",%5d", companion.companion_data[channels_written]);
238                 }
239                 for (; channels_written < 12; channels_written++)
240                         out.printf(",0");
241         }
242
243         void write_header(boolean advanced, boolean gps, boolean companion) {
244                 out.printf("#"); write_general_header();
245                 out.printf(","); write_flight_header();
246                 out.printf(","); write_basic_header();
247                 if (advanced)
248                         out.printf(","); write_advanced_header();
249                 if (gps) {
250                         out.printf(","); write_gps_header();
251                         out.printf(","); write_gps_sat_header();
252                 }
253                 if (companion) {
254                         out.printf(","); write_companion_header();
255                 }
256                 out.printf ("\n");
257         }
258
259         void write_one(AltosState state) {
260                 write_general(state); out.printf(",");
261                 write_flight(state); out.printf(",");
262                 write_basic(state); out.printf(",");
263                 if (state.imu != null || state.mag != null)
264                         write_advanced(state);
265                 if (state.gps != null) {
266                         out.printf(",");
267                         write_gps(state); out.printf(",");
268                         write_gps_sat(state);
269                 }
270                 if (state.companion != null) {
271                         out.printf(",");
272                         write_companion(state);
273                 }
274                 out.printf ("\n");
275         }
276
277         void flush_pad() {
278                 while (!pad_states.isEmpty()) {
279                         write_one (pad_states.remove());
280                 }
281         }
282
283         public void write(AltosState state) {
284                 if (state.state == Altos.ao_flight_startup)
285                         return;
286                 if (!header_written) {
287                         write_header(state.imu != null || state.mag != null,
288                                      state.gps != null, state.companion != null);
289                         header_written = true;
290                 }
291                 if (!seen_boost) {
292                         if (state.state >= Altos.ao_flight_boost) {
293                                 seen_boost = true;
294                                 boost_tick = state.tick;
295                                 flush_pad();
296                         }
297                 }
298                 if (seen_boost)
299                         write_one(state);
300                 else
301                         pad_states.add(state);
302         }
303
304         public PrintStream out() {
305                 return out;
306         }
307
308         public void close() {
309                 if (!pad_states.isEmpty()) {
310                         boost_tick = pad_states.element().tick;
311                         flush_pad();
312                 }
313                 out.close();
314         }
315
316         public void write(AltosStateIterable states) {
317                 states.write_comments(out());
318                 for (AltosState state : states)
319                         write(state);
320         }
321
322         public AltosCSV(PrintStream in_out, File in_name) {
323                 name = in_name;
324                 out = in_out;
325                 pad_states = new LinkedList<AltosState>();
326         }
327
328         public AltosCSV(File in_name) throws FileNotFoundException {
329                 this(new PrintStream(in_name), in_name);
330         }
331
332         public AltosCSV(String in_string) throws FileNotFoundException {
333                 this(new File(in_string));
334         }
335 }