altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / altoslib / AltosEepromDownload.java
index 9598bd93e88456cc5f946ad6a3496f2a0103f424..a3c15112318c7cae3c4503ba3ce1d50849190c95 100644 (file)
@@ -3,7 +3,8 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_6;
+package org.altusmetrum.altoslib_14;
 
 import java.io.*;
 import java.util.*;
 import java.text.*;
 import java.util.concurrent.*;
 
+class AltosEepromNameData extends AltosDataListener {
+       AltosGPS        gps = null;
+
+       boolean avoid_duplicate_files = false;
+
+       public void set_rssi(int rssi, int status) { }
+       public void set_received_time(long received_time) { }
+
+       public void set_acceleration(double accel) { }
+       public void set_pressure(double pa) { }
+       public void set_thrust(double N) { }
+
+       public void set_temperature(double deg_c) { }
+       public void set_battery_voltage(double volts) { }
+
+       public void set_apogee_voltage(double volts) { }
+       public void set_main_voltage(double volts) { }
+
+       public void set_avoid_duplicate_files() {
+               avoid_duplicate_files = true;
+       }
+
+       public void set_gps(AltosGPS gps, boolean set_location, boolean set_sats) {
+               super.set_gps(gps, set_location, set_sats);
+               if (gps != null &&
+                   gps.year != AltosLib.MISSING &&
+                   gps.month != AltosLib.MISSING &&
+                   gps.day != AltosLib.MISSING) {
+                       this.gps = gps;
+               }
+       }
+
+       public boolean done() {
+               if (gps == null)
+                       return false;
+               return true;
+       }
+
+       public void set_gyro(double roll, double pitch, double yaw) { }
+       public void set_accel_ground(double along, double across, double through) { }
+       public void set_accel(double along, double across, double through) { }
+       public void set_mag(double along, double across, double through) { }
+       public void set_pyro_voltage(double volts) { }
+       public void set_igniter_voltage(double[] voltage) { }
+       public void set_pyro_fired(int pyro_mask) { }
+       public void set_companion(AltosCompanion companion) { }
+       public void set_kalman(double height, double speed, double acceleration) { }
+       public void set_orient(double new_orient) { }
+       public void set_motor_pressure(double motor_pressure) { }
+
+       public AltosEepromNameData(AltosCalData cal_data) {
+               super(cal_data);
+       }
+}
+
 public class AltosEepromDownload implements Runnable {
 
        AltosLink               link;
@@ -29,194 +85,193 @@ public class AltosEepromDownload implements Runnable {
        Thread                  eeprom_thread;
        AltosEepromMonitor      monitor;
 
-       boolean                 want_file;
-       FileWriter              eeprom_file;
-       LinkedList<String>      eeprom_pending;
-
        AltosEepromList         flights;
-       boolean                 success;
-       ParseException          parse_exception;
-       AltosState              state;
-
-       private void FlushPending() throws IOException {
-               for (String s : flights.config_data) {
-                       eeprom_file.write(s);
-                       eeprom_file.write('\n');
-               }
+       String                  parse_errors;
+
+       private boolean has_gps_date(AltosState state) {
+               if (state == null)
+                       return false;
 
-               for (String s : eeprom_pending)
-                       eeprom_file.write(s);
+               AltosGPS gps = state.gps;
+
+               return gps != null &&
+                       gps.year != AltosLib.MISSING &&
+                       gps.month != AltosLib.MISSING &&
+                       gps.day != AltosLib.MISSING;
        }
 
-       private void CheckFile(boolean force) throws IOException {
-               if (eeprom_file != null)
-                       return;
-               if (force || (state.flight != 0 && want_file)) {
-                       AltosFile               eeprom_name;
-                       AltosGPS                gps = state.gps;
-
-                       if (gps != null &&
-                           gps.year != AltosLib.MISSING &&
-                           gps.month != AltosLib.MISSING &&
-                           gps.day != AltosLib.MISSING)
-                       {
+       private AltosFile MakeFile(int serial, int flight, AltosEepromNameData name_data) throws IOException {
+               AltosFile               eeprom_name;
+
+               for (;;) {
+                       if (name_data.gps != null) {
+                               AltosGPS                gps = name_data.gps;
                                eeprom_name = new AltosFile(gps.year, gps.month, gps.day,
-                                                           state.serial, state.flight, "eeprom");
+                                                           serial, flight, "eeprom");
                        } else
-                               eeprom_name = new AltosFile(state.serial, state.flight, "eeprom");
-
-                       eeprom_file = new FileWriter(eeprom_name);
-                       if (eeprom_file != null) {
-                               monitor.set_filename(eeprom_name.getName());
-                               FlushPending();
-                               eeprom_pending = null;
-                       }
+                               eeprom_name = new AltosFile(serial, flight, "eeprom");
+                       if (!name_data.avoid_duplicate_files)
+                               break;
+                       if (!eeprom_name.exists())
+                               break;
+                       flight++;
                }
+
+               return eeprom_name;
        }
 
        boolean                 done;
        int                     prev_state;
        int                     state_block;
 
-       void LogEeprom(AltosEeprom r) throws IOException {
-               if (r.cmd != AltosLib.AO_LOG_INVALID) {
-                       String line = r.string();
-                       if (eeprom_file != null)
-                               eeprom_file.write(line);
-                       else
-                               eeprom_pending.add(line);
-               }
+       void LogError(String error) {
+               if (parse_errors != null)
+                       parse_errors.concat(error.concat("\n"));
+               else
+                       parse_errors = error;
        }
 
-       void CaptureEeprom(AltosEepromChunk eechunk, int log_format) throws IOException, ParseException {
-               boolean any_valid = false;
-               boolean got_flight = false;
-
-               int record_length = 8;
-
-               state.set_serial(flights.config_data.serial);
-               monitor.set_serial(flights.config_data.serial);
+       class BlockCache extends Hashtable<Integer,AltosEepromChunk> {
+               AltosEepromLog  log;
 
-               for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += record_length) {
-                       AltosEeprom r = eechunk.eeprom(i, log_format, state);
-
-                       if (r == null)
-                               continue;
-
-                       record_length = r.record_length();
-
-                       r.update_state(state);
+               AltosEepromChunk get(int start, boolean add) throws TimeoutException, InterruptedException {
+                       if (contains(start))
+                               return super.get(start);
+                       AltosEepromChunk eechunk = new AltosEepromChunk(link, start, start == log.start_block);
+                       if (add)
+                               put(start, eechunk);
+                       return eechunk;
+               }
 
-                       if (!got_flight && state.flight != AltosLib.MISSING)
-                               monitor.set_flight(state.flight);
+               public BlockCache(AltosEepromLog log) {
+                       this.log = log;
+               }
+       }
 
-                       /* Monitor state transitions to update display */
-                       if (state.state != AltosLib.ao_flight_invalid &&
-                           state.state <= AltosLib.ao_flight_landed)
-                       {
-                               if (state.state > AltosLib.ao_flight_pad)
-                                       want_file = true;
-                               if (state.state == AltosLib.ao_flight_landed)
-                                       done = true;
-                       }
+       int FindLastLog(AltosEepromLog log, BlockCache cache) throws TimeoutException, InterruptedException {
+               int     low = log.start_block;
+               int     high = log.end_block - 1;
 
-                       if (state.gps != null)
-                               want_file = true;
+               while (low <= high) {
+                       int mid = (high + low) / 2;
 
-                       if (r.valid) {
-                               any_valid = true;
-                               LogEeprom(r);
-                       }
+                       if (!cache.get(mid, true).erased())
+                               low = mid + 1;
+                       else
+                               high = mid - 1;
                }
-               if (!any_valid)
-                       done = true;
-
-               CheckFile(false);
+               return low;
        }
 
        void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException, ParseException {
                int                     block, state_block = 0;
                int                     log_format = flights.config_data.log_format;
-
-               state = new AltosState();
+               BlockCache              cache = new BlockCache(log);
 
                done = false;
 
                if (flights.config_data.serial < 0)
                        throw new IOException("no serial number found");
 
-               /* Reset per-capture variables */
-               want_file = false;
-               eeprom_file = null;
-               eeprom_pending = new LinkedList<String>();
-
                /* Set serial number in the monitor dialog window */
-               /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
-
-               state_block = log.start_block;
-               prev_state = AltosLib.ao_flight_startup;
-               for (block = log.start_block; !done && block < log.end_block; block++) {
-                       AltosEepromChunk        eechunk = new AltosEepromChunk(link, block, block == log.start_block);
-
-                       /*
-                        * Guess what kind of data is there if the device
-                        * didn't tell us
-                        */
-
-                       if (log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN) {
-                               if (block == log.start_block) {
-                                       if (eechunk.data(0) == AltosLib.AO_LOG_FLIGHT)
-                                               log_format = AltosLib.AO_LOG_FORMAT_FULL;
-                                       else
-                                               log_format = AltosLib.AO_LOG_FORMAT_TINY;
-                               }
-                       }
+               monitor.set_serial(log.serial);
+               monitor.set_flight(log.flight);
 
-                       CaptureEeprom (eechunk, log_format);
+               int     start_block = log.start_block;
+               int     end_block = FindLastLog(log, cache);
 
-                       if (state.state != prev_state && state.state != AltosLib.ao_flight_invalid) {
-                               state_block = block;
-                               prev_state = state.state;
-                       }
+               monitor.set_max(end_block - start_block - 1);
+
+               ArrayList<Byte> data = new ArrayList<Byte>();
+
+               /* Now scan the eeprom, reading blocks of data to create a byte array of data */
+
+               for (block = start_block; block < end_block; block++) {
+                       monitor.set_block(block - start_block);
+
+                       AltosEepromChunk        eechunk = cache.get(block, false);
+
+                       for (int i = 0; i < eechunk.data.length; i++)
+                               data.add((byte) eechunk.data[i]);
+               }
 
-                       monitor.set_value(state.state_name(),
-                                         state.state,
-                                         block - state_block,
-                                         block - log.start_block);
+               /* Construct our internal representation of the eeprom data */
+               AltosEeprom     eeprom = new AltosEeprom(flights.config_data, data);
+
+               /* Now see if we can't actually parse the resulting
+                * file to generate a better filename. Note that this
+                * doesn't need to work; we'll still save the data using
+                * a less accurate name.
+                */
+               AltosEepromRecordSet            set = new AltosEepromRecordSet(eeprom);
+               AltosEepromNameData name_data = new AltosEepromNameData(set.cal_data());
+
+               for (AltosEepromRecord record : set.ordered) {
+                       record.provide_data(name_data, set.cal_data());
+                       if (name_data.done())
+                               break;
                }
-               CheckFile(true);
-               if (eeprom_file != null) {
-                       eeprom_file.flush();
-                       eeprom_file.close();
+
+               AltosFile f = MakeFile(flights.config_data.serial, log.flight, name_data);
+
+               log.set_file(f);
+
+               boolean do_write = true;
+
+               if (f.exists())
+                       do_write = monitor.check_overwrite(f);
+
+               if (do_write) {
+                       FileWriter w = new FileWriter(f);
+
+                       eeprom.write(w);
+                       w.close();
                }
+
+               if (eeprom.errors != 0)
+                       throw new ParseException(String.format("%d CRC Errors", eeprom.errors), 0);
+       }
+
+       static String label(int flight) {
+               if (flight < 0)
+                       return "Corrupt";
+               else
+                       return "Flight";
+       }
+
+       static int flight(int flight) {
+               if (flight < 0)
+                       return -flight;
+               return flight;
        }
 
        public void run () {
+               boolean success = false;
+
                try {
-                       boolean failed = false;
                        if (remote)
                                link.start_remote();
 
                        for (AltosEepromLog log : flights) {
-                               parse_exception = null;
-                               if (log.selected) {
+                               parse_errors = null;
+                               if (log.download_selected) {
                                        monitor.reset();
                                        try {
                                                CaptureLog(log);
                                        } catch (ParseException e) {
-                                               parse_exception = e;
+                                               LogError(e.getMessage());
                                        }
                                }
-                               if (parse_exception != null) {
-                                       failed = true;
-                                       monitor.show_message(String.format("Flight %d download error\n%s\nValid log data saved",
-                                                                          log.flight,
-                                                                          parse_exception.getMessage()),
+                               success = true;
+                               if (parse_errors != null) {
+                                       monitor.show_message(String.format("%s %d download error. Valid log data saved\n%s",
+                                                                          label(log.flight),
+                                                                          flight(log.flight),
+                                                                          parse_errors),
                                                             link.name,
                                                             AltosEepromMonitor.WARNING_MESSAGE);
                                }
                        }
-                       success = !failed;
                } catch (IOException ee) {
                        monitor.show_message(ee.getLocalizedMessage(),
                                             link.name,
@@ -258,12 +313,6 @@ public class AltosEepromDownload implements Runnable {
                link = given_link;
                remote = given_remote;
                flights = given_flights;
-               success = false;
-
-               if (flights.config_data.log_has_state())
-                       monitor.set_states(AltosLib.ao_flight_boost, AltosLib.ao_flight_landed);
-               else
-                       monitor.set_states(AltosLib.ao_flight_invalid, AltosLib.ao_flight_invalid);
 
                monitor.start();
        }