altosui: Remove unused files
[fw/altos] / altosui / AltosEepromMegaIterable.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.awt.*;
21 import java.awt.event.*;
22 import javax.swing.*;
23 import javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
25 import java.io.*;
26 import java.util.*;
27 import java.text.*;
28 import java.util.prefs.*;
29 import java.util.concurrent.LinkedBlockingQueue;
30
31 /*
32  * AltosRecords with an index field so they can be sorted by tick while preserving
33  * the original ordering for elements with matching ticks
34  */
35 class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable<AltosOrderedMegaRecord> {
36
37         public int      index;
38
39         public AltosOrderedMegaRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
40                 throws ParseException {
41                 super(line);
42                 if (prev_tick_valid) {
43                         tick |= (prev_tick & ~0xffff);
44                         if (tick < prev_tick) {
45                                 if (prev_tick - tick > 0x8000)
46                                         tick += 0x10000;
47                         } else {
48                                 if (tick - prev_tick > 0x8000)
49                                         tick -= 0x10000;
50                         }
51                 }
52                 index = in_index;
53         }
54
55         public AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) {
56                 super(in_cmd, in_tick);
57                 a = in_a;
58                 b = in_b;
59                 index = in_index;
60         }
61
62         public String toString() {
63                 return String.format("%d.%d %04x %04x %04x",
64                                      cmd, index, tick, a, b);
65         }
66
67         public int compareTo(AltosOrderedMegaRecord o) {
68                 int     tick_diff = tick - o.tick;
69                 if (tick_diff != 0)
70                         return tick_diff;
71                 return index - o.index;
72         }
73 }
74
75 public class AltosEepromMegaIterable extends AltosRecordIterable {
76
77         static final int        seen_flight = 1;
78         static final int        seen_sensor = 2;
79         static final int        seen_temp_volt = 4;
80         static final int        seen_deploy = 8;
81         static final int        seen_gps_time = 16;
82         static final int        seen_gps_lat = 32;
83         static final int        seen_gps_lon = 64;
84
85         static final int        seen_basic = seen_flight|seen_sensor;
86
87         boolean                 has_accel;
88         boolean                 has_gps;
89         boolean                 has_ignite;
90
91         AltosEepromMega flight_record;
92         AltosEepromMega gps_date_record;
93
94         TreeSet<AltosOrderedMegaRecord> records;
95
96         AltosMs5607             baro;
97
98         LinkedList<AltosRecord> list;
99
100         class EepromState {
101                 int     seen;
102                 int     n_pad_samples;
103                 double  ground_pres;
104                 int     gps_tick;
105                 int     boost_tick;
106                 int     sensor_tick;
107
108                 EepromState() {
109                         seen = 0;
110                         n_pad_samples = 0;
111                         ground_pres = 0.0;
112                         gps_tick = 0;
113                 }
114         }
115
116         void update_state(AltosRecord state, AltosEepromMega record, EepromState eeprom) {
117                 state.tick = record.tick;
118                 switch (record.cmd) {
119                 case Altos.AO_LOG_FLIGHT:
120                         eeprom.seen |= seen_flight;
121                         state.ground_accel = record.ground_accel();
122                         state.flight_accel = record.ground_accel();
123                         state.ground_pres = baro.set(record.ground_pres(), record.ground_temp());
124                         state.flight_pres = state.ground_pres;
125                         state.flight = record.data16(0);
126                         eeprom.boost_tick = record.tick;
127                         break;
128                 case Altos.AO_LOG_SENSOR:
129                         state.accel = record.accel();
130                         state.pres = baro.set(record.pres(), record.temp());
131                         state.temp = baro.cc;
132                         state.imu = new AltosIMU();
133                         state.imu.accel_x = record.accel_x();
134                         state.imu.accel_y = record.accel_y();
135                         state.imu.accel_z = record.accel_z();
136                         state.imu.gyro_x = record.gyro_x();
137                         state.imu.gyro_y = record.gyro_y();
138                         state.imu.gyro_z = record.gyro_z();
139                         state.mag = new AltosMag();
140                         state.mag.x = record.mag_x();
141                         state.mag.y = record.mag_y();
142                         state.mag.z = record.mag_z();
143                         if (state.state < Altos.ao_flight_boost) {
144                                 eeprom.n_pad_samples++;
145                                 eeprom.ground_pres += state.pres;
146                                 state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
147                                 state.flight_pres = state.ground_pres;
148                         } else {
149                                 state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
150                         }
151                         state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
152                         if ((eeprom.seen & seen_sensor) == 0)
153                                 eeprom.sensor_tick = record.tick - 1;
154                         state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
155                         eeprom.seen |= seen_sensor;
156                         eeprom.sensor_tick = record.tick;
157                         has_accel = true;
158                         break;
159                 case Altos.AO_LOG_PRESSURE:
160                         state.pres = record.b;
161                         state.flight_pres = state.pres;
162                         if (eeprom.n_pad_samples == 0) {
163                                 eeprom.n_pad_samples++;
164                                 state.ground_pres = state.pres;
165                         }
166                         eeprom.seen |= seen_sensor;
167                         break;
168                 case Altos.AO_LOG_TEMP_VOLT:
169                         state.batt = record.v_batt();
170                         eeprom.seen |= seen_temp_volt;
171                         break;
172                 case Altos.AO_LOG_DEPLOY:
173                         state.drogue = record.a;
174                         state.main = record.b;
175                         eeprom.seen |= seen_deploy;
176                         has_ignite = true;
177                         break;
178                 case Altos.AO_LOG_STATE:
179                         state.state = record.state();
180                         break;
181                 case Altos.AO_LOG_GPS_TIME:
182                         eeprom.gps_tick = state.tick;
183                         AltosGPS old = state.gps;
184                         state.gps = new AltosGPS();
185
186                         /* GPS date doesn't get repeated through the file */
187                         if (old != null) {
188                                 state.gps.year = old.year;
189                                 state.gps.month = old.month;
190                                 state.gps.day = old.day;
191                         }
192                         state.gps.hour = (record.a & 0xff);
193                         state.gps.minute = (record.a >> 8);
194                         state.gps.second = (record.b & 0xff);
195
196                         int flags = (record.b >> 8);
197                         state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0;
198                         state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0;
199                         state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >>
200                                 Altos.AO_GPS_NUM_SAT_SHIFT;
201                         state.new_gps = true;
202                         has_gps = true;
203                         break;
204                 case Altos.AO_LOG_GPS_LAT:
205                         int lat32 = record.a | (record.b << 16);
206                         state.gps.lat = (double) lat32 / 1e7;
207                         break;
208                 case Altos.AO_LOG_GPS_LON:
209                         int lon32 = record.a | (record.b << 16);
210                         state.gps.lon = (double) lon32 / 1e7;
211                         break;
212                 case Altos.AO_LOG_GPS_ALT:
213                         state.gps.alt = record.a;
214                         break;
215                 case Altos.AO_LOG_GPS_SAT:
216                         if (state.tick == eeprom.gps_tick) {
217                                 int svid = record.a;
218                                 int c_n0 = record.b >> 8;
219                                 state.gps.add_sat(svid, c_n0);
220                         }
221                         break;
222                 case Altos.AO_LOG_GPS_DATE:
223                         state.gps.year = (record.a & 0xff) + 2000;
224                         state.gps.month = record.a >> 8;
225                         state.gps.day = record.b & 0xff;
226                         break;
227
228                 case Altos.AO_LOG_CONFIG_VERSION:
229                         break;
230                 case Altos.AO_LOG_MAIN_DEPLOY:
231                         break;
232                 case Altos.AO_LOG_APOGEE_DELAY:
233                         break;
234                 case Altos.AO_LOG_RADIO_CHANNEL:
235                         break;
236                 case Altos.AO_LOG_CALLSIGN:
237                         state.callsign = record.data;
238                         break;
239                 case Altos.AO_LOG_ACCEL_CAL:
240                         state.accel_plus_g = record.a;
241                         state.accel_minus_g = record.b;
242                         break;
243                 case Altos.AO_LOG_RADIO_CAL:
244                         break;
245                 case Altos.AO_LOG_MANUFACTURER:
246                         break;
247                 case Altos.AO_LOG_PRODUCT:
248                         break;
249                 case Altos.AO_LOG_SERIAL_NUMBER:
250                         state.serial = record.a;
251                         break;
252                 case Altos.AO_LOG_SOFTWARE_VERSION:
253                         break;
254                 case Altos.AO_LOG_BARO_RESERVED:
255                         baro.reserved = record.a;
256                         break;
257                 case Altos.AO_LOG_BARO_SENS:
258                         baro.sens =record.a;
259                         break;
260                 case Altos.AO_LOG_BARO_OFF:
261                         baro.off =record.a;
262                         break;
263                 case Altos.AO_LOG_BARO_TCS:
264                         baro.tcs =record.a;
265                         break;
266                 case Altos.AO_LOG_BARO_TCO:
267                         baro.tco =record.a;
268                         break;
269                 case Altos.AO_LOG_BARO_TREF:
270                         baro.tref =record.a;
271                         break;
272                 case Altos.AO_LOG_BARO_TEMPSENS:
273                         baro.tempsens =record.a;
274                         break;
275                 case Altos.AO_LOG_BARO_CRC:
276                         baro.crc =record.a;
277                         break;
278                 }
279                 state.seen |= eeprom.seen;
280         }
281
282         LinkedList<AltosRecord> make_list() {
283                 LinkedList<AltosRecord>         list = new LinkedList<AltosRecord>();
284                 Iterator<AltosOrderedMegaRecord>        iterator = records.iterator();
285                 AltosOrderedMegaRecord          record = null;
286                 AltosRecord                     state = new AltosRecord();
287                 boolean                         last_reported = false;
288                 EepromState                     eeprom = new EepromState();
289
290                 state.state = Altos.ao_flight_pad;
291                 state.accel_plus_g = 15758;
292                 state.accel_minus_g = 16294;
293
294                 /* Pull in static data from the flight and gps_date records */
295                 if (flight_record != null)
296                         update_state(state, flight_record, eeprom);
297                 if (gps_date_record != null)
298                         update_state(state, gps_date_record, eeprom);
299
300                 while (iterator.hasNext()) {
301                         record = iterator.next();
302                         if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
303                                 AltosRecord r = new AltosRecord(state);
304                                 r.time = (r.tick - eeprom.boost_tick) / 100.0;
305                                 list.add(r);
306                         }
307                         update_state(state, record, eeprom);
308                 }
309                 AltosRecord r = new AltosRecord(state);
310                 r.time = (r.tick - eeprom.boost_tick) / 100.0;
311                 list.add(r);
312                 return list;
313         }
314
315         public Iterator<AltosRecord> iterator() {
316                 if (list == null)
317                         list = make_list();
318                 return list.iterator();
319         }
320
321         public boolean has_gps() { return has_gps; }
322         public boolean has_accel() { return has_accel; }
323         public boolean has_ignite() { return has_ignite; }
324
325         public void write_comments(PrintStream out) {
326                 Iterator<AltosOrderedMegaRecord>        iterator = records.iterator();
327                 out.printf("# Comments\n");
328                 while (iterator.hasNext()) {
329                         AltosOrderedMegaRecord  record = iterator.next();
330                         switch (record.cmd) {
331                         case Altos.AO_LOG_CONFIG_VERSION:
332                                 out.printf("# Config version: %s\n", record.data);
333                                 break;
334                         case Altos.AO_LOG_MAIN_DEPLOY:
335                                 out.printf("# Main deploy: %s\n", record.a);
336                                 break;
337                         case Altos.AO_LOG_APOGEE_DELAY:
338                                 out.printf("# Apogee delay: %s\n", record.a);
339                                 break;
340                         case Altos.AO_LOG_RADIO_CHANNEL:
341                                 out.printf("# Radio channel: %s\n", record.a);
342                                 break;
343                         case Altos.AO_LOG_CALLSIGN:
344                                 out.printf("# Callsign: %s\n", record.data);
345                                 break;
346                         case Altos.AO_LOG_ACCEL_CAL:
347                                 out.printf ("# Accel cal: %d %d\n", record.a, record.b);
348                                 break;
349                         case Altos.AO_LOG_RADIO_CAL:
350                                 out.printf ("# Radio cal: %d\n", record.a);
351                                 break;
352                         case Altos.AO_LOG_MAX_FLIGHT_LOG:
353                                 out.printf ("# Max flight log: %d\n", record.a);
354                                 break;
355                         case Altos.AO_LOG_MANUFACTURER:
356                                 out.printf ("# Manufacturer: %s\n", record.data);
357                                 break;
358                         case Altos.AO_LOG_PRODUCT:
359                                 out.printf ("# Product: %s\n", record.data);
360                                 break;
361                         case Altos.AO_LOG_SERIAL_NUMBER:
362                                 out.printf ("# Serial number: %d\n", record.a);
363                                 break;
364                         case Altos.AO_LOG_SOFTWARE_VERSION:
365                                 out.printf ("# Software version: %s\n", record.data);
366                                 break;
367                         case Altos.AO_LOG_BARO_RESERVED:
368                                 out.printf ("# Baro reserved: %d\n", record.a);
369                                 break;
370                         case Altos.AO_LOG_BARO_SENS:
371                                 out.printf ("# Baro sens: %d\n", record.a);
372                                 break;
373                         case Altos.AO_LOG_BARO_OFF:
374                                 out.printf ("# Baro off: %d\n", record.a);
375                                 break;
376                         case Altos.AO_LOG_BARO_TCS:
377                                 out.printf ("# Baro tcs: %d\n", record.a);
378                                 break;
379                         case Altos.AO_LOG_BARO_TCO:
380                                 out.printf ("# Baro tco: %d\n", record.a);
381                                 break;
382                         case Altos.AO_LOG_BARO_TREF:
383                                 out.printf ("# Baro tref: %d\n", record.a);
384                                 break;
385                         case Altos.AO_LOG_BARO_TEMPSENS:
386                                 out.printf ("# Baro tempsens: %d\n", record.a);
387                                 break;
388                         case Altos.AO_LOG_BARO_CRC:
389                                 out.printf ("# Baro crc: %d\n", record.a);
390                                 break;
391                         }
392                 }
393         }
394
395         /*
396          * Given an AO_LOG_GPS_TIME record with correct time, and one
397          * missing time, rewrite the missing time values with the good
398          * ones, assuming that the difference between them is 'diff' seconds
399          */
400         void update_time(AltosOrderedMegaRecord good, AltosOrderedMegaRecord bad) {
401
402                 int diff = (bad.tick - good.tick + 50) / 100;
403
404                 int hour = (good.a & 0xff);
405                 int minute = (good.a >> 8);
406                 int second = (good.b & 0xff);
407                 int flags = (good.b >> 8);
408                 int seconds = hour * 3600 + minute * 60 + second;
409
410                 /* Make sure this looks like a good GPS value */
411                 if ((flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4)
412                         flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT);
413                 flags |= Altos.AO_GPS_RUNNING;
414                 flags |= Altos.AO_GPS_VALID;
415
416                 int new_seconds = seconds + diff;
417                 if (new_seconds < 0)
418                         new_seconds += 24 * 3600;
419                 int new_second = (new_seconds % 60);
420                 int new_minutes = (new_seconds / 60);
421                 int new_minute = (new_minutes % 60);
422                 int new_hours = (new_minutes / 60);
423                 int new_hour = (new_hours % 24);
424
425                 bad.a = new_hour + (new_minute << 8);
426                 bad.b = new_second + (flags << 8);
427         }
428
429         /*
430          * Read the whole file, dumping records into a RB tree so
431          * we can enumerate them in time order -- the eeprom data
432          * are sometimes out of order with GPS data getting timestamps
433          * matching the first packet out of the GPS unit but not
434          * written until the final GPS packet has been received.
435          */
436         public AltosEepromMegaIterable (FileInputStream input) {
437                 records = new TreeSet<AltosOrderedMegaRecord>();
438
439                 AltosOrderedMegaRecord last_gps_time = null;
440
441                 baro = new AltosMs5607();
442
443                 int index = 0;
444                 int prev_tick = 0;
445                 boolean prev_tick_valid = false;
446                 boolean missing_time = false;
447
448                 try {
449                         for (;;) {
450                                 String line = AltosRecord.gets(input);
451                                 if (line == null)
452                                         break;
453                                 AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid);
454                                 if (record == null)
455                                         break;
456                                 if (record.cmd == Altos.AO_LOG_INVALID)
457                                         continue;
458                                 prev_tick = record.tick;
459                                 if (record.cmd < Altos.AO_LOG_CONFIG_VERSION)
460                                         prev_tick_valid = true;
461                                 if (record.cmd == Altos.AO_LOG_FLIGHT) {
462                                         flight_record = record;
463                                         continue;
464                                 }
465
466                                 /* Two firmware bugs caused the loss of some GPS data.
467                                  * The flight date would never be recorded, and often
468                                  * the flight time would get overwritten by another
469                                  * record. Detect the loss of the GPS date and fix up the
470                                  * missing time records
471                                  */
472                                 if (record.cmd == Altos.AO_LOG_GPS_DATE) {
473                                         gps_date_record = record;
474                                         continue;
475                                 }
476
477                                 /* go back and fix up any missing time values */
478                                 if (record.cmd == Altos.AO_LOG_GPS_TIME) {
479                                         last_gps_time = record;
480                                         if (missing_time) {
481                                                 Iterator<AltosOrderedMegaRecord> iterator = records.iterator();
482                                                 while (iterator.hasNext()) {
483                                                         AltosOrderedMegaRecord old = iterator.next();
484                                                         if (old.cmd == Altos.AO_LOG_GPS_TIME &&
485                                                             old.a == -1 && old.b == -1)
486                                                         {
487                                                                 update_time(record, old);
488                                                         }
489                                                 }
490                                                 missing_time = false;
491                                         }
492                                 }
493
494                                 if (record.cmd == Altos.AO_LOG_GPS_LAT) {
495                                         if (last_gps_time == null || last_gps_time.tick != record.tick) {
496                                                 AltosOrderedMegaRecord add_gps_time = new AltosOrderedMegaRecord(Altos.AO_LOG_GPS_TIME,
497                                                                                                          record.tick,
498                                                                                                          -1, -1, index-1);
499                                                 if (last_gps_time != null)
500                                                         update_time(last_gps_time, add_gps_time);
501                                                 else
502                                                         missing_time = true;
503
504                                                 records.add(add_gps_time);
505                                                 record.index = index++;
506                                         }
507                                 }
508                                 records.add(record);
509
510                                 /* Bail after reading the 'landed' record; we're all done */
511                                 if (record.cmd == Altos.AO_LOG_STATE &&
512                                     record.a == Altos.ao_flight_landed)
513                                         break;
514                         }
515                 } catch (IOException io) {
516                 } catch (ParseException pe) {
517                 }
518                 try {
519                         input.close();
520                 } catch (IOException ie) {
521                 }
522         }
523 }