altosui: Split eeprom download code apart
authorKeith Packard <keithp@keithp.com>
Tue, 11 Jan 2011 23:39:24 +0000 (15:39 -0800)
committerKeith Packard <keithp@keithp.com>
Tue, 11 Jan 2011 23:39:24 +0000 (15:39 -0800)
Create separate 'download config data', 'read single record' and 'read
block' functions. This code will be shared with future multi-log
reading code for new firmware.

Signed-off-by: Keith Packard <keithp@keithp.com>
altosui/AltosConfigData.java [new file with mode: 0644]
altosui/AltosEepromBlock.java [new file with mode: 0644]
altosui/AltosEepromDownload.java
altosui/AltosEepromRecord.java
altosui/Makefile.am

diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java
new file mode 100644 (file)
index 0000000..8c32ed8
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.*;
+
+import libaltosJNI.*;
+
+public class AltosConfigData implements Iterable<String> {
+
+       /* Version information */
+       String  manufacturer;
+       String  product;
+       String  version;
+       int     serial;
+
+       /* Strings returned */
+       LinkedList<String>      lines;
+
+       /* Config information */
+       int     config_major;
+       int     config_minor;
+       int     main_deploy;
+       int     apogee_delay;
+       int     radio_channel;
+       String  callsign;
+       int     accel_cal_plus, accel_cal_minus;
+       int     radio_calibration;
+       int     flight_log_max;
+
+
+       static String get_string(String line, String label) throws  ParseException {
+               if (line.startsWith(label)) {
+                       String  quoted = line.substring(label.length()).trim();
+
+                       if (quoted.startsWith("\""))
+                               quoted = quoted.substring(1);
+                       if (quoted.endsWith("\""))
+                               quoted = quoted.substring(0,quoted.length()-1);
+                       return quoted;
+               }
+               throw new ParseException("mismatch", 0);
+       }
+
+       static int get_int(String line, String label) throws NumberFormatException, ParseException {
+               if (line.startsWith(label)) {
+                       String tail = line.substring(label.length()).trim();
+                       String[] tokens = tail.split("\\s+");
+                       if (tokens.length > 0)
+                               return  Integer.parseInt(tokens[0]);
+               }
+               throw new ParseException("mismatch", 0);
+       }
+
+       public Iterator<String> iterator() {
+               return lines.iterator();
+       }
+
+       public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException {
+               serial_line.printf("c s\nv\n");
+               lines = new LinkedList<String>();
+               for (;;) {
+                       String line = serial_line.get_reply(5000);
+                       if (line == null)
+                               throw new TimeoutException();
+                       if (line.contains("Syntax error"))
+                               continue;
+                       lines.add(line);
+                       try { serial = get_int(line, "serial-number"); } catch (Exception e) {}
+                       try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {}
+                       try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {}
+                       try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {}
+                       try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {}
+                       try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {}
+                       try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {}
+                       try { version = get_string(line,"software-version"); } catch (Exception e) {}
+                       try { product = get_string(line,"product"); } catch (Exception e) {}
+
+                       /* signals the end of the version info */
+                       if (line.startsWith("software-version"))
+                               break;
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/altosui/AltosEepromBlock.java b/altosui/AltosEepromBlock.java
new file mode 100644 (file)
index 0000000..0c1a4a9
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.*;
+import java.lang.reflect.Array;
+
+import libaltosJNI.*;
+
+public class AltosEepromBlock extends ArrayList<AltosEepromRecord> {
+       boolean has_flight;
+       int     flight;
+       boolean has_state;
+       int     state;
+       boolean has_date;
+       int     year, month, day;
+
+       public AltosEepromBlock (AltosSerial serial_line, int block) throws TimeoutException, InterruptedException {
+               int     addr;
+               boolean done = false;
+
+               has_flight = false;
+               has_state = false;
+               has_date = false;
+               serial_line.printf("e %x\n", block);
+               for (addr = 0; !done && addr < 0x100;) {
+                       try {
+                               AltosEepromRecord r = new AltosEepromRecord(serial_line, block * 256 + addr);
+
+                               if (r.cmd == Altos.AO_LOG_FLIGHT) {
+                                       flight = r.b;
+                                       has_flight = true;
+                               }
+
+                               /* Monitor state transitions to update display */
+                               if (r.cmd == Altos.AO_LOG_STATE && r.a <= Altos.ao_flight_landed) {
+                                       if (!has_state || r.a > state) {
+                                               state = r.a;
+                                               has_state = true;
+                                       }
+                               }
+
+                               if (r.cmd == Altos.AO_LOG_GPS_DATE) {
+                                       year = 2000 + (r.a & 0xff);
+                                       month = (r.a >> 8) & 0xff;
+                                       day = (r.b & 0xff);
+                                       has_date = true;
+                               }
+
+                               if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed)
+                                       done = true;
+                               add(addr / 8, r);
+                       } catch (ParseException pe) {
+                       }
+                       addr += 8;
+               }
+       }
+}
\ No newline at end of file
index e5ff766..9a74871 100644 (file)
@@ -32,182 +32,105 @@ import libaltosJNI.*;
 
 public class AltosEepromDownload implements Runnable {
 
-       static final String[] state_names = {
-               "startup",
-               "idle",
-               "pad",
-               "boost",
-               "fast",
-               "coast",
-               "drogue",
-               "main",
-               "landed",
-               "invalid",
-       };
-
-       int[] ParseHex(String line) {
-               String[] tokens = line.split("\\s+");
-               int[] array = new int[tokens.length];
-
-               for (int i = 0; i < tokens.length; i++)
-                       try {
-                               array[i] = Integer.parseInt(tokens[i], 16);
-                       } catch (NumberFormatException ne) {
-                               return null;
-                       }
-               return array;
-       }
-
-       int checksum(int[] line) {
-               int     csum = 0x5a;
-               for (int i = 1; i < line.length; i++)
-                       csum += line[i];
-               return csum & 0xff;
-       }
-
-       void FlushPending(FileWriter file, LinkedList<String> pending) throws IOException {
-               while (!pending.isEmpty()) {
-                       file.write(pending.remove());
-               }
-       }
-
        JFrame                  frame;
        AltosDevice             device;
        AltosSerial             serial_line;
        boolean                 remote;
        Thread                  eeprom_thread;
        AltosEepromMonitor      monitor;
+       int                     serial = 0;
+       int                     flight = 0;
+       int                     year = 0, month = 0, day = 0;
+       boolean                 want_file = false;
+       FileWriter              eeprom_file = null;
+       LinkedList<String>      eeprom_pending = new LinkedList<String>();
+       AltosConfigData         config_data;
+
+       private void FlushPending() throws IOException {
+               for (String s : config_data) {
+                       eeprom_file.write(s);
+                       eeprom_file.write('\n');
+               }
 
-       void CaptureLog() throws IOException, InterruptedException, TimeoutException {
-               int                     serial = 0;
-               int                     block, state_block = 0;
-               int                     addr;
-               int                     flight = 0;
-               int                     year = 0, month = 0, day = 0;
-               int                     state = 0;
-               boolean                 done = false;
-               boolean                 want_file = false;
-               boolean                 any_valid;
-               FileWriter              eeprom_file = null;
-               AltosFile               eeprom_name;
-               LinkedList<String>      eeprom_pending = new LinkedList<String>();
-
-               serial_line.printf("\nc s\nv\n");
-
-               /* Pull the serial number out of the version information */
+               for (String s : eeprom_pending)
+                       eeprom_file.write(s);
+       }
 
-               for (;;) {
-                       String  line = serial_line.get_reply(5000);
+       private void CheckFile(boolean force) throws IOException {
+               if (eeprom_file != null)
+                       return;
+               if (force || (flight != 0 && want_file)) {
+                       AltosFile               eeprom_name;
+                       if (year != 0 && month != 0 && day != 0)
+                               eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom");
+                       else
+                               eeprom_name = new AltosFile(serial, flight, "eeprom");
 
-                       if (line == null)
-                               throw new TimeoutException();
-                       if (line.startsWith("serial-number")) {
-                               try {
-                                       serial = Integer.parseInt(line.substring(13).trim());
-                               } catch (NumberFormatException ne) {
-                                       serial = 0;
-                               }
+                       eeprom_file = new FileWriter(eeprom_name);
+                       if (eeprom_file != null) {
+                               monitor.set_file(eeprom_name.getName());
+                               FlushPending();
+                               eeprom_pending = null;
                        }
+               }
+       }
 
-                       eeprom_pending.add(String.format("%s\n", line));
+       void CaptureLog(int start_block, int end_block) throws IOException, InterruptedException, TimeoutException {
+               int                     block, state_block = 0;
+               int                     state = 0;
+               boolean                 done = false;
+               int                     record;
 
-                       /* signals the end of the version info */
-                       if (line.startsWith("software-version"))
-                               break;
-               }
+               config_data = new AltosConfigData(serial_line);
+               serial = config_data.serial;
                if (serial == 0)
                        throw new IOException("no serial number found");
 
                monitor.set_serial(serial);
                /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
 
-               state = 0; state_block = 0;
-               for (block = 0; !done && block < 511; block++) {
-                       serial_line.printf("e %x\n", block);
-                       any_valid = false;
-                       monitor.set_value(state_names[state], state, block - state_block);
-                       for (addr = 0; addr < 0x100;) {
-                               String  line = serial_line.get_reply(5000);
-                               if (line == null)
-                                       throw new TimeoutException();
-                               int[] values = ParseHex(line);
-
-                               if (values == null) {
-                                       System.out.printf("invalid line: %s\n", line);
-                                       continue;
-                               } else if (values[0] != addr) {
-                                       System.out.printf("data address out of sync at 0x%x\n",
-                                                         block * 256 + values[0]);
-                               } else if (checksum(values) != 0) {
-                                       System.out.printf("invalid checksum at 0x%x\n",
-                                                         block * 256 + values[0]);
-                               } else {
-                                       any_valid = true;
-                                       int     cmd = values[1];
-                                       int     tick = values[3] + (values[4] << 8);
-                                       int     a = values[5] + (values[6] << 8);
-                                       int     b = values[7] + (values[8] << 8);
+               state = 0; state_block = start_block;
+               for (block = start_block; !done && block < end_block; block++) {
+                       monitor.set_value(Altos.state_to_string[state], state, block - state_block);
 
-                                       if (cmd == Altos.AO_LOG_FLIGHT) {
-                                               flight = b;
-                                               monitor.set_flight(flight);
-                                       }
-
-                                       /* Monitor state transitions to update display */
-                                       if (cmd == Altos.AO_LOG_STATE && a <= Altos.ao_flight_landed) {
-                                               if (a > Altos.ao_flight_pad)
-                                                       want_file = true;
-                                               if (a > state)
-                                                       state_block = block;
-                                               state = a;
-                                       }
+                       AltosEepromBlock        eeblock = new AltosEepromBlock(serial_line, block);
+                       if (eeblock.has_flight) {
+                               flight = eeblock.flight;
+                               monitor.set_flight(flight);
+                       }
+                       if (eeblock.has_date) {
+                               year = eeblock.year;
+                               month = eeblock.month;
+                               day = eeblock.day;
+                               want_file = true;
+                       }
 
-                                       if (cmd == Altos.AO_LOG_GPS_DATE) {
-                                               year = 2000 + (a & 0xff);
-                                               month = (a >> 8) & 0xff;
-                                               day = (b & 0xff);
-                                               want_file = true;
-                                       }
+                       if (eeblock.size() == 0 ||
+                           eeblock.has_state && eeblock.state == Altos.ao_flight_landed)
+                                       done = true;
 
-                                       if (eeprom_file == null) {
-                                               if (serial != 0 && flight != 0 && want_file) {
-                                                       if (year != 0 && month != 0 && day != 0)
-                                                               eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom");
-                                                       else
-                                                               eeprom_name = new AltosFile(serial, flight, "eeprom");
+                       /* Monitor state transitions to update display */
+                       if (eeblock.has_state) {
+                               if (eeblock.state > Altos.ao_flight_pad)
+                                       want_file = true;
+                               if (eeblock.state > state)
+                                       state = eeblock.state;
+                       }
 
-                                                       monitor.set_file(eeprom_name.getName());
-                                                       eeprom_file = new FileWriter(eeprom_name);
-                                                       if (eeprom_file != null) {
-                                                               FlushPending(eeprom_file, eeprom_pending);
-                                                               eeprom_pending = null;
-                                                       }
-                                               }
-                                       }
+                       CheckFile(true);
 
-                                       String log_line = String.format("%c %4x %4x %4x\n",
-                                                                       cmd, tick, a, b);
-                                       if (eeprom_file != null)
-                                               eeprom_file.write(log_line);
-                                       else
-                                               eeprom_pending.add(log_line);
+                       for (record = 0; record < eeblock.size(); record++) {
+                               AltosEepromRecord r = eeblock.get(record);
 
-                                       if (cmd == Altos.AO_LOG_STATE && a == Altos.ao_flight_landed) {
-                                               done = true;
-                                       }
-                               }
-                               addr += 8;
-                       }
-                       if (!any_valid)
-                               done = true;
-               }
-               if (eeprom_file == null) {
-                       eeprom_name = new AltosFile(serial,flight,"eeprom");
-                       eeprom_file = new FileWriter(eeprom_name);
-                       if (eeprom_file != null) {
-                               FlushPending(eeprom_file, eeprom_pending);
+                               String log_line = String.format("%c %4x %4x %4x\n",
+                                                               r.cmd, r.tick, r.a, r.b);
+                               if (eeprom_file != null)
+                                       eeprom_file.write(log_line);
+                               else
+                                       eeprom_pending.add(log_line);
                        }
                }
+               CheckFile(true);
                if (eeprom_file != null) {
                        eeprom_file.flush();
                        eeprom_file.close();
@@ -235,6 +158,8 @@ public class AltosEepromDownload implements Runnable {
                SwingUtilities.invokeLater(r);
        }
 
+       int     start_block, end_block;
+
        public void run () {
                if (remote) {
                        serial_line.set_radio();
@@ -243,7 +168,7 @@ public class AltosEepromDownload implements Runnable {
                }
 
                try {
-                       CaptureLog();
+                       CaptureLog(start_block, end_block);
                } catch (IOException ee) {
                        show_error (device.toShortString(),
                                    ee.getLocalizedMessage());
@@ -271,6 +196,7 @@ public class AltosEepromDownload implements Runnable {
                                serial_line = new AltosSerial(device);
                                if (!device.matchProduct(AltosDevice.product_telemetrum))
                                        remote = true;
+
                                monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed);
                                monitor.addActionListener(new ActionListener() {
                                                public void actionPerformed(ActionEvent e) {
@@ -280,6 +206,8 @@ public class AltosEepromDownload implements Runnable {
                                        });
 
                                eeprom_thread = new Thread(this);
+                               start_block = 0;
+                               end_block = 0xfff;
                                eeprom_thread.start();
                        } catch (FileNotFoundException ee) {
                                JOptionPane.showMessageDialog(frame,
index 5a67381..e61a715 100644 (file)
@@ -26,7 +26,9 @@ import java.io.*;
 import java.util.*;
 import java.text.*;
 import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.*;
+
+import libaltosJNI.*;
 
 public class AltosEepromRecord {
        public int      cmd;
@@ -36,6 +38,49 @@ public class AltosEepromRecord {
        public String   data;
        public boolean  tick_valid;
 
+       int[] ParseHex(String line) {
+               String[] tokens = line.split("\\s+");
+               int[] array = new int[tokens.length];
+
+               for (int i = 0; i < tokens.length; i++)
+                       try {
+                               array[i] = Integer.parseInt(tokens[i], 16);
+                       } catch (NumberFormatException ne) {
+                               return null;
+                       }
+               return array;
+       }
+
+       int checksum(int[] line) {
+               int     csum = 0x5a;
+               for (int i = 1; i < line.length; i++)
+                       csum += line[i];
+               return csum & 0xff;
+       }
+
+       public AltosEepromRecord (AltosSerial serial_line, int addr)
+               throws TimeoutException, ParseException, InterruptedException {
+               String  line = serial_line.get_reply(5000);
+               if (line == null)
+                       throw new TimeoutException();
+               int[] values = ParseHex(line);
+
+               if (values == null)
+                       throw new ParseException(String.format("invalid line %s", line), 0);
+               if (values[0] != (addr & 0xff))
+                       throw new ParseException(String.format("data address out of sync at 0x%x",
+                                                              addr), 0);
+               if (checksum(values) != 0)
+                       throw new ParseException(String.format("invalid checksum at 0x%x", addr), 0);
+
+               cmd = values[1];
+               tick = values[3] + (values[4] << 8);
+               a = values[5] + (values[6] << 8);
+               b = values[7] + (values[8] << 8);
+               data = null;
+               tick_valid = true;
+       }
+
        public AltosEepromRecord (String line) {
                tick_valid = false;
                tick = 0;
index e2ff55a..8cdd64c 100644 (file)
@@ -15,6 +15,7 @@ altosui_JAVA = \
        AltosAscent.java \
        AltosChannelMenu.java \
        AltosConfig.java \
+       AltosConfigData.java \
        AltosConfigUI.java \
        AltosConfigureUI.java \
        AltosConvert.java \
@@ -26,6 +27,7 @@ altosui_JAVA = \
        AltosDeviceDialog.java \
        AltosDevice.java \
        AltosDisplayThread.java \
+       AltosEepromBlock.java \
        AltosEepromDownload.java \
        AltosEepromMonitor.java \
        AltosEepromIterable.java \