altosui: Add support for downloading TeleMini/TeleNano flight logs
authorKeith Packard <keithp@keithp.com>
Sat, 26 Mar 2011 04:34:31 +0000 (21:34 -0700)
committerKeith Packard <keithp@keithp.com>
Sat, 26 Mar 2011 04:35:44 +0000 (21:35 -0700)
Splits the eeprom downloading code into eeprom block downloading and
separate eeprom data parsing so that the new data logging format can
share the data downloading code.

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

index 9d5b2e02369d3eef870ac083be1fd881f2c31e04..3ef4d79994dcaee73d31b7d9657ebf8fe4b2e4d7 100644 (file)
@@ -34,6 +34,7 @@ public class Altos {
        static final int AO_LOG_GPS_ALT = 'H';
        static final int AO_LOG_GPS_SAT = 'V';
        static final int AO_LOG_GPS_DATE = 'Y';
        static final int AO_LOG_GPS_ALT = 'H';
        static final int AO_LOG_GPS_SAT = 'V';
        static final int AO_LOG_GPS_DATE = 'Y';
+       static final int AO_LOG_HEIGHT = 'h';
 
        /* Added for header fields in eeprom files */
        static final int AO_LOG_CONFIG_VERSION = 1000;
 
        /* Added for header fields in eeprom files */
        static final int AO_LOG_CONFIG_VERSION = 1000;
index d59fd39e2bdf9b67951dd67e2a3e3a924966a861..650920d1b353629c7cdf3d18ae6846997054832c 100644 (file)
@@ -46,7 +46,7 @@ public class AltosEepromBlock extends ArrayList<AltosEepromRecord> {
        int     hour, minute, second;
        ParseException  parse_exception = null;
 
        int     hour, minute, second;
        ParseException  parse_exception = null;
 
-       public AltosEepromBlock (AltosSerial serial_line, int block) throws TimeoutException, InterruptedException {
+       public AltosEepromBlock (AltosEepromChunk chunk) {
                int     addr;
                boolean done = false;
 
                int     addr;
                boolean done = false;
 
@@ -56,10 +56,9 @@ public class AltosEepromBlock extends ArrayList<AltosEepromRecord> {
                has_lat = false;
                has_lon = false;
                has_time = false;
                has_lat = false;
                has_lon = false;
                has_time = false;
-               serial_line.printf("e %x\n", block);
-               for (addr = 0; addr < 0x100;) {
+               for (addr = 0; addr < chunk.chunk_size;) {
                        try {
                        try {
-                               AltosEepromRecord r = new AltosEepromRecord(serial_line, block * 256 + addr);
+                               AltosEepromRecord r = new AltosEepromRecord(chunk, addr);
 
                                if (r.cmd == Altos.AO_LOG_FLIGHT) {
                                        flight = r.b;
 
                                if (r.cmd == Altos.AO_LOG_FLIGHT) {
                                        flight = r.b;
diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java
new file mode 100644 (file)
index 0000000..8eec407
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+public class AltosEepromChunk {
+
+       static final int        chunk_size = 256;
+       static final int        per_line = 8;
+
+       public int              data[];
+       public int              address;
+       public ParseException   parse_exception = null;
+
+       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 data(int offset) {
+               return data[offset];
+       }
+
+       int data16(int offset) {
+               return data[offset] | (data[offset + 1] << 8);
+       }
+
+       public AltosEepromChunk(AltosSerial serial_line, int block)
+               throws TimeoutException, InterruptedException {
+
+               int     offset;
+
+               data = new int[chunk_size];
+               address = block * chunk_size;
+               serial_line.printf("e %x\n", block);
+
+               for (offset = 0; offset < chunk_size; offset += per_line) {
+                       try {
+                               String  line = serial_line.get_reply(5000);
+
+                               if (line == null)
+                                       throw new TimeoutException();
+
+                               int[] values = ParseHex(line);
+
+                               if (values == null || values.length != per_line + 1)
+                                       throw new ParseException(String.format("invalid line %s", line), 0);
+                               if (values[0] != offset)
+                                       throw new ParseException(String.format("data address out of sync at 0x%x",
+                                                                              address + offset), 0);
+                               for (int i = 0; i < per_line; i++)
+                                       data[offset + i] = values[1 + i];
+                       } catch (ParseException pe) {
+                               for (int i = 0; i < per_line; i++)
+                                       data[offset + i] = 0xff;
+                               if (parse_exception == null)
+                                       parse_exception = pe;
+                       }
+               }
+       }
+}
\ No newline at end of file
index 1da94a6769ca191a0b5e6eefa0149003e44a307d..f96a3dc90527559b685d2c28b94a090a53ba9467 100644 (file)
@@ -78,11 +78,105 @@ public class AltosEepromDownload implements Runnable {
                }
        }
 
                }
        }
 
+       void Log(AltosEepromRecord r) throws IOException {
+               if (r.cmd != Altos.AO_LOG_INVALID) {
+                       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);
+               }
+       }
+
+       static final int        log_full = 1;
+       static final int        log_tiny = 2;
+
+       boolean                 done;
+       int                     state;
+
+       void CaptureFull(AltosEepromChunk eechunk) throws IOException {
+               AltosEepromBlock        eeblock = new AltosEepromBlock(eechunk);
+
+               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 (eeblock.size() == 0 ||
+                   eeblock.has_state && eeblock.state == Altos.ao_flight_landed)
+                       done = true;
+
+               /* 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;
+               }
+
+               if (parse_exception == null && eeblock.parse_exception != null)
+                       parse_exception = eeblock.parse_exception;
+
+               CheckFile(false);
+
+               for (int record = 0; record < eeblock.size(); record++)
+                       Log(eeblock.get(record));
+       }
+
+       boolean start;
+       int     tiny_tick;
+
+       void CaptureTiny (AltosEepromChunk eechunk) throws IOException {
+               boolean some_reasonable_data = false;
+
+               for (int i = 0; i < eechunk.data.length; i += 2) {
+                       int     v = eechunk.data16(i);
+
+                       if (i == 0 && start) {
+                               tiny_tick = 0;
+                               start = false;
+                               flight = v;
+                               Log(new AltosEepromRecord(Altos.AO_LOG_FLIGHT, tiny_tick, 0, v));
+                               some_reasonable_data = true;
+                       } else {
+                               int     s = v ^ 0x8000;
+                               if (Altos.ao_flight_startup <= s && s <= Altos.ao_flight_invalid) {
+                                       Log(new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, s, 0));
+                                       if (s == Altos.ao_flight_landed) {
+                                               done = true;
+                                               break;
+                                       }
+                                       some_reasonable_data = true;
+                               } else {
+                                       if (v != 0xffff)
+                                               some_reasonable_data = true;
+                                       Log(new AltosEepromRecord(Altos.AO_LOG_HEIGHT, tiny_tick, v, 0));
+                                       if (state < Altos.ao_flight_drogue)
+                                               tiny_tick += 10;
+                                       else
+                                               tiny_tick += 100;
+                               }
+                       }
+               }
+               CheckFile(false);
+               if (!some_reasonable_data)
+                       done = true;
+       }
+
        void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException {
                int                     block, state_block = 0;
        void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException {
                int                     block, state_block = 0;
-               int                     state = 0;
-               boolean                 done = false;
-               int                     record;
+               int                     log_style = 0;
+
+               state = 0;
+               done = false;
+               start = true;
 
                if (flights.config_data.serial == 0)
                        throw new IOException("no serial number found");
 
                if (flights.config_data.serial == 0)
                        throw new IOException("no serial number found");
@@ -104,47 +198,26 @@ public class AltosEepromDownload implements Runnable {
                for (block = log.start_block; !done && block < log.end_block; block++) {
                        monitor.set_value(Altos.state_to_string[state], state, block - state_block);
 
                for (block = log.start_block; !done && block < log.end_block; block++) {
                        monitor.set_value(Altos.state_to_string[state], state, block - state_block);
 
-                       AltosEepromBlock        eeblock = new AltosEepromBlock(serial_line, block);
+                       AltosEepromChunk        eechunk = new AltosEepromChunk(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;
-                       }
+                       /*
+                        * Figure out what kind of data is there
+                        */
 
 
-                       if (eeblock.size() == 0 ||
-                           eeblock.has_state && eeblock.state == Altos.ao_flight_landed)
-                                       done = true;
-
-                       /* 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;
+                       if (block == log.start_block) {
+                               if (eechunk.data(0) == Altos.AO_LOG_FLIGHT)
+                                       log_style = log_full;
+                               else
+                                       log_style = log_tiny;
                        }
 
                        }
 
-                       if (parse_exception == null && eeblock.parse_exception != null)
-                               parse_exception = eeblock.parse_exception;
-
-                       CheckFile(false);
-
-                       for (record = 0; record < eeblock.size(); record++) {
-                               AltosEepromRecord r = eeblock.get(record);
-
-                               if (r.cmd != Altos.AO_LOG_INVALID) {
-                                       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);
-                               }
+                       switch (log_style) {
+                       case log_full:
+                               CaptureFull(eechunk);
+                               break;
+                       case log_tiny:
+                               CaptureTiny(eechunk);
+                               break;
                        }
                }
                CheckFile(true);
                        }
                }
                CheckFile(true);
index f8e6d7e5a2e16126755d4d7568be479d42445074..bb7c7bef17d34384c5a8af3e4d03e020942ad78c 100644 (file)
@@ -124,6 +124,10 @@ public class AltosEepromIterable extends AltosRecordIterable {
                        }
                        eeprom.seen |= seen_sensor;
                        break;
                        }
                        eeprom.seen |= seen_sensor;
                        break;
+               case Altos.AO_LOG_HEIGHT:
+                       state.height = record.a;
+                       eeprom.seen |= seen_sensor;
+                       break;
                case Altos.AO_LOG_TEMP_VOLT:
                        state.temp = record.a;
                        state.batt = record.b;
                case Altos.AO_LOG_TEMP_VOLT:
                        state.temp = record.a;
                        state.batt = record.b;
@@ -155,7 +159,6 @@ public class AltosEepromIterable extends AltosRecordIterable {
                        int flags = (record.b >> 8);
                        state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0;
                        state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0;
                        int flags = (record.b >> 8);
                        state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0;
                        state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0;
-                       state.gps.date_valid = (flags & Altos.AO_GPS_DATE_VALID) != 0;
                        state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >>
                                Altos.AO_GPS_NUM_SAT_SHIFT;
                        break;
                        state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >>
                                Altos.AO_GPS_NUM_SAT_SHIFT;
                        break;
index 10befad49765b3ee61fb92c37a5d9cf6f5987d56..4c6deaa065f232dd09f63119e7297708e3d08cf2 100644 (file)
@@ -73,7 +73,16 @@ public class AltosEepromLog {
                        in_end_block = in_start_block + 2;
 
                for (block = in_start_block; block < in_end_block; block++) {
                        in_end_block = in_start_block + 2;
 
                for (block = in_start_block; block < in_end_block; block++) {
-                       AltosEepromBlock eeblock = new AltosEepromBlock(serial_line, block);
+                       AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block);
+
+                       if (block == in_start_block) {
+                               if (eechunk.data(0) != Altos.AO_LOG_FLIGHT) {
+                                       flight = eechunk.data16(0);
+                                       has_flight = true;
+                                       break;
+                               }
+                       }
+                       AltosEepromBlock eeblock = new AltosEepromBlock(eechunk);
                        if (eeblock.has_flight) {
                                flight = eeblock.flight;
                                has_flight = true;
                        if (eeblock.has_flight) {
                                flight = eeblock.flight;
                                has_flight = true;
index e5196c50039a69434d36bd661f612ad50bb3ae08..5787af86e6d53fc60640bc35f803c7d71be2c931 100644 (file)
@@ -38,6 +38,8 @@ public class AltosEepromRecord {
        public String   data;
        public boolean  tick_valid;
 
        public String   data;
        public boolean  tick_valid;
 
+       static final int        record_length = 8;
+
        int[] ParseHex(String line) {
                String[] tokens = line.split("\\s+");
                int[] array = new int[tokens.length];
        int[] ParseHex(String line) {
                String[] tokens = line.split("\\s+");
                int[] array = new int[tokens.length];
@@ -51,44 +53,35 @@ public class AltosEepromRecord {
                return array;
        }
 
                return array;
        }
 
-       int checksum(int[] line) {
+       int checksum(int[] data, int start) {
                int     csum = 0x5a;
                int     csum = 0x5a;
-               for (int i = 1; i < line.length; i++)
-                       csum += line[i];
+               for (int i = 0; i < record_length; i++)
+                       csum += data[i + start];
                return csum & 0xff;
        }
 
                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);
+       public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException {
+
+               cmd = chunk.data(start);
+               tick_valid = true;
 
 
-               if (values == null || values.length < 9) {
-                       System.out.printf("invalid line %s", line);
-                       throw new ParseException(String.format("inalid line %s", line), 0);
-               }
-               if (values[0] != (addr & 0xff))
-                       throw new ParseException(String.format("data address out of sync at 0x%x",
-                                                              addr), 0);
                int i;
                int i;
-               for (i = 1; i < values.length; i++)
-                       if (values[i] != 0xff)
+               for (i = 0; i < record_length; i++)
+                       if (chunk.data[start + i] != 0xff)
                                break;
                                break;
-               cmd = values[1];
-               tick_valid = true;
-               if (i != values.length) {
-                       if (checksum(values) != 0)
-                               throw new ParseException(String.format("invalid checksum at 0x%x in line %s", addr, line), 0);
+               if (i != 8) {
+                       if (checksum(chunk.data, start) != 0)
+                               throw new ParseException(String.format("invalid checksum at 0x%x",
+                                                                      chunk.address + start), 0);
                } else {
                        cmd = Altos.AO_LOG_INVALID;
                        tick_valid = false;
                }
 
                } else {
                        cmd = Altos.AO_LOG_INVALID;
                        tick_valid = false;
                }
 
-               tick = values[3] + (values[4] << 8);
-               a = values[5] + (values[6] << 8);
-               b = values[7] + (values[8] << 8);
+               tick = chunk.data16(start + 2);
+               a = chunk.data16(start + 4);
+               b = chunk.data16(start + 6);
+
                data = null;
        }
 
                data = null;
        }
 
index 49f34ce39ba4414b7bcefeb75802c6974e411af9..9a9d0d362f250a0b66a2c491e0f5b0538670fa79 100644 (file)
@@ -28,6 +28,7 @@ altosui_JAVA = \
        AltosDevice.java \
        AltosDisplayThread.java \
        AltosEepromBlock.java \
        AltosDevice.java \
        AltosDisplayThread.java \
        AltosEepromBlock.java \
+       AltosEepromChunk.java \
        AltosEepromDelete.java \
        AltosEepromDownload.java \
        AltosEepromList.java \
        AltosEepromDelete.java \
        AltosEepromDownload.java \
        AltosEepromList.java \