From bd2480fd757b67557d9c7de42e402034002c3e37 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 11 Jan 2011 15:39:24 -0800 Subject: [PATCH] altosui: Split eeprom download code apart 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 --- altosui/AltosConfigData.java | 109 +++++++++++++++ altosui/AltosEepromBlock.java | 82 +++++++++++ altosui/AltosEepromDownload.java | 230 +++++++++++-------------------- altosui/AltosEepromRecord.java | 47 ++++++- altosui/Makefile.am | 2 + 5 files changed, 318 insertions(+), 152 deletions(-) create mode 100644 altosui/AltosConfigData.java create mode 100644 altosui/AltosEepromBlock.java diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java new file mode 100644 index 00000000..8c32ed86 --- /dev/null +++ b/altosui/AltosConfigData.java @@ -0,0 +1,109 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 { + + /* Version information */ + String manufacturer; + String product; + String version; + int serial; + + /* Strings returned */ + LinkedList 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 iterator() { + return lines.iterator(); + } + + public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { + serial_line.printf("c s\nv\n"); + lines = new LinkedList(); + 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 index 00000000..0c1a4a92 --- /dev/null +++ b/altosui/AltosEepromBlock.java @@ -0,0 +1,82 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 { + 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 diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index e5ff766c..9a748710 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -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 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 eeprom_pending = new LinkedList(); + 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 eeprom_pending = new LinkedList(); - - 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, diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index 5a673817..e61a7159 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -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; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index e2ff55af..8cdd64cc 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -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 \ -- 2.30.2