altoslib: Start restructuring AltosState harder
authorKeith Packard <keithp@keithp.com>
Wed, 28 Aug 2013 03:28:07 +0000 (21:28 -0600)
committerKeith Packard <keithp@keithp.com>
Thu, 29 Aug 2013 12:47:37 +0000 (06:47 -0600)
Make per-packet code update state itself rather than having all state
updates done centrally. Will make adding new packet types easier.

Signed-off-by: Keith Packard <keithp@keithp.com>
29 files changed:
altoslib/AltosCompanion.java [new file with mode: 0644]
altoslib/AltosEeprom.java [new file with mode: 0644]
altoslib/AltosEepromBody.java [new file with mode: 0644]
altoslib/AltosEepromBodyIterable.java [new file with mode: 0644]
altoslib/AltosEepromFile.java [new file with mode: 0644]
altoslib/AltosEepromHeader.java [new file with mode: 0644]
altoslib/AltosEepromHeaderIterable.java [new file with mode: 0644]
altoslib/AltosEepromIterable.java
altoslib/AltosEepromMetrum.java [new file with mode: 0644]
altoslib/AltosEepromMetrumIterable.java [new file with mode: 0644]
altoslib/AltosEepromMini.java
altoslib/AltosEepromOldIterable.java [new file with mode: 0644]
altoslib/AltosEepromTM.java [new file with mode: 0644]
altoslib/AltosGPS.java
altoslib/AltosGreatCircle.java
altoslib/AltosIMU.java
altoslib/AltosMag.java
altoslib/AltosOrderedMetrumRecord.java [new file with mode: 0644]
altoslib/AltosRecordMini.java
altoslib/AltosRecordTM2.java [new file with mode: 0644]
altoslib/AltosSelfFlash.java [new file with mode: 0644]
altoslib/AltosSensorMetrum.java [new file with mode: 0644]
altoslib/AltosState.java
altoslib/AltosStateUpdate.java [new file with mode: 0644]
altoslib/AltosTelemetryRecord.java
altoslib/AltosTelemetryRecordMetrumData.java [new file with mode: 0644]
altoslib/AltosTelemetryRecordMetrumSensor.java [new file with mode: 0644]
altoslib/AltosTelemetryRecordMini.java [new file with mode: 0644]
altoslib/Makefile.am

diff --git a/altoslib/AltosCompanion.java b/altoslib/AltosCompanion.java
new file mode 100644 (file)
index 0000000..1572fda
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 org.altusmetrum.altoslib_1;
+
+public class AltosCompanion {
+       public final static int board_id_telescience = 0x0a;
+       public final static int MAX_CHANNELS = 12;
+
+       public int      tick;
+       public int      board_id;
+       public int      update_period;
+       public int      channels;
+       public int[]    companion_data;
+
+       public AltosCompanion(int in_channels) {
+               channels = in_channels;
+               if (channels < 0)
+                       channels = 0;
+               if (channels > MAX_CHANNELS)
+                       channels = MAX_CHANNELS;
+               companion_data = new int[channels];
+       }
+}
diff --git a/altoslib/AltosEeprom.java b/altoslib/AltosEeprom.java
new file mode 100644 (file)
index 0000000..31646c7
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public abstract class AltosEeprom implements AltosStateUpdate {
+       public int      cmd;
+       public int      tick;
+       public int      data8[];
+       public boolean  valid;
+
+       public final static int header_length = 4;
+
+       public abstract void update_state(AltosState state);
+
+       public void write(PrintStream out) {
+               out.printf("%c %04x", cmd, tick);
+               if (data8 != null) {
+                       for (int i = 0; i < data8.length; i++)
+                               out.printf (" %02x", data8[i]);
+               }
+               out.printf ("\n");
+       }
+
+       void parse_chunk(AltosEepromChunk chunk, int start, int record_length) throws ParseException {
+               cmd = chunk.data(start);
+
+               int data_length = record_length - header_length;
+
+               valid = !chunk.erased(start, record_length);
+               if (valid) {
+                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
+                               throw new ParseException(String.format("invalid checksum at 0x%x",
+                                                                      chunk.address + start), 0);
+               } else {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               }
+
+               tick = chunk.data16(start+2);
+
+               data8 = new int[data_length];
+               for (int i = 0; i < data_length; i++)
+                       data8[i] = chunk.data(start + header_length + i);
+       }
+
+       void parse_string(String line, int record_length) {
+               valid = false;
+               tick = 0;
+               cmd = AltosLib.AO_LOG_INVALID;
+
+               int data_length = record_length - header_length;
+
+               if (line == null)
+                       return;
+               try {
+                       String[] tokens = line.split("\\s+");
+
+                       if (tokens[0].length() == 1) {
+                               if (tokens.length == 2 + data_length) {
+                                       cmd = tokens[0].codePointAt(0);
+                                       tick = Integer.parseInt(tokens[1],16);
+                                       valid = true;
+                                       data8 = new int[data_length];
+                                       for (int i = 0; i < data_length; i++)
+                                               data8[i] = Integer.parseInt(tokens[2 + i],16);
+                               }
+                       }
+               } catch (NumberFormatException ne) {
+               }
+       }
+}
diff --git a/altoslib/AltosEepromBody.java b/altoslib/AltosEepromBody.java
new file mode 100644 (file)
index 0000000..60aa888
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromBody implements AltosEeprom, AltosStateUpdate {
+
+       public void update_state(AltosState state) {
+       }
+
+       public void write(PrintStream out) {
+       }
+}
\ No newline at end of file
diff --git a/altoslib/AltosEepromBodyIterable.java b/altoslib/AltosEepromBodyIterable.java
new file mode 100644 (file)
index 0000000..33dc0ac
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromBodyIterable {
+       LinkedList<AltosEepromBody>     bodies;
+
+       
+}
\ No newline at end of file
diff --git a/altoslib/AltosEepromFile.java b/altoslib/AltosEepromFile.java
new file mode 100644 (file)
index 0000000..48d2543
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromFile {
+
+       AltosEepromIterable     headers;
+       AltosEepromIterable     body;
+
+       public void write(PrintStream out) {
+               headers.write(out);
+               body.write(out);
+       }
+
+       public AltosEepromFile(FileInputStream input) {
+               headers = new AltosEepromIterable(AltosEepromHeader.read(input));
+
+               AltosState      state = headers.state();
+
+               switch (state.log_format) {
+               case AltosLib.AO_LOG_FORMAT_FULL:
+               case AltosLib.AO_LOG_FORMAT_TINY:
+               case AltosLib.AO_LOG_FORMAT_TELEMETRY:
+               case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
+               case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+                       break;
+               case AltosLib.AO_LOG_FORMAT_MINI:
+                       body = new AltosEepromIterable(AltosEepromMini.read(input));
+                       break;
+               }
+       }
+}
\ No newline at end of file
diff --git a/altoslib/AltosEepromHeader.java b/altoslib/AltosEepromHeader.java
new file mode 100644 (file)
index 0000000..b2343dc
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromHeader extends AltosEeprom {
+
+       public int      cmd;
+       public String   data;
+       public int      config_a, config_b;
+       public boolean  last;
+       public boolean  valid;
+
+       public void update_state(AltosState state) {
+               switch (cmd) {
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       state.callsign = data;
+                       break;
+               case AltosLib.AO_LOG_ACCEL_CAL:
+                       state.accel_plus_g = config_a;
+                       state.accel_minus_g = config_b;
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       break;
+               case AltosLib.AO_LOG_LOG_FORMAT:
+                       state.log_format = config_a;
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       state.serial = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_RESERVED:
+                       state.baro.reserved = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_SENS:
+                       state.baro.sens = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_OFF:
+                       state.baro.off = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCS:
+                       state.baro.tcs = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCO:
+                       state.baro.tco = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TREF:
+                       state.baro.tref = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TEMPSENS:
+                       state.baro.tempsens = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_CRC:
+                       state.baro.crc = config_a;
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       break;
+               }
+       }
+
+       public void write(PrintStream out) {
+               switch (cmd) {
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       out.printf("# Config version: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       out.printf("# Main deploy: %s\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       out.printf("# Apogee delay: %s\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       out.printf("# Radio channel: %s\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       out.printf("# Callsign: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_ACCEL_CAL:
+                       out.printf ("# Accel cal: %d %d\n", config_a, config_b);
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       out.printf ("# Radio cal: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
+                       out.printf ("# Max flight log: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       out.printf ("# Manufacturer: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       out.printf ("# Product: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       out.printf ("# Serial number: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       out.printf ("# Software version: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_BARO_RESERVED:
+                       out.printf ("# Baro reserved: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_SENS:
+                       out.printf ("# Baro sens: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_OFF:
+                       out.printf ("# Baro off: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TCS:
+                       out.printf ("# Baro tcs: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TCO:
+                       out.printf ("# Baro tco: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TREF:
+                       out.printf ("# Baro tref: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TEMPSENS:
+                       out.printf ("# Baro tempsens: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_CRC:
+                       out.printf ("# Baro crc: %d\n", config_a);
+                       break;
+               }
+       }
+       
+       public AltosEepromHeader (String[] tokens) {
+               last = false;
+               valid = true;
+               try {
+                       if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+                               cmd = AltosLib.AO_LOG_CONFIG_VERSION;
+                               data = tokens[2];
+                       } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+                               cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+                               cmd = AltosLib.AO_LOG_APOGEE_DELAY;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+                               cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Callsign:")) {
+                               cmd = AltosLib.AO_LOG_CALLSIGN;
+                               data = tokens[1].replaceAll("\"","");
+                       } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+                               cmd = AltosLib.AO_LOG_ACCEL_CAL;
+                               config_a = Integer.parseInt(tokens[3]);
+                               config_b = Integer.parseInt(tokens[5]);
+                       } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+                               cmd = AltosLib.AO_LOG_RADIO_CAL;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
+                               cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
+                               config_a = Integer.parseInt(tokens[3]);
+                       } else if (tokens[0].equals("manufacturer")) {
+                               cmd = AltosLib.AO_LOG_MANUFACTURER;
+                               data = tokens[1];
+                       } else if (tokens[0].equals("product")) {
+                               cmd = AltosLib.AO_LOG_PRODUCT;
+                               data = tokens[1];
+                       } else if (tokens[0].equals("serial-number")) {
+                               cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
+                               config_a = Integer.parseInt(tokens[1]);
+                       } else if (tokens[0].equals("log-format")) {
+                               cmd = AltosLib.AO_LOG_LOG_FORMAT;
+                               config_a = Integer.parseInt(tokens[1]);
+                       } else if (tokens[0].equals("software-version")) {
+                               cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
+                               data = tokens[1];
+                               last = true;
+                       } else if (tokens[0].equals("ms5607")) {
+                               if (tokens[1].equals("reserved:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_RESERVED;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("sens:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_SENS;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("off:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_OFF;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tcs:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TCS;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tco:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TCO;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tref:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TREF;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tempsens:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("crc:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_CRC;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else {
+                                       cmd = AltosLib.AO_LOG_INVALID;
+                                       data = tokens[2];
+                               }
+                       } else
+                               valid = false;
+               } catch (Exception e) {
+                       valid = false;
+               }
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> headers = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosEepromHeader header = new AltosEepromHeader(line);
+                               headers.add(header);
+                               if (header.last)
+                                       break;
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return headers;
+       }
+
+       static public void write (PrintStream out, LinkedList<AltosEepromHeader> headers) {
+               out.printf("# Comments\n");
+               for (AltosEepromHeader header : headers) {
+                       header.write(out);
+               }
+               
+       }
+
+       public AltosEepromHeader (String line) {
+               this(line.split("\\s+"));
+       }
+}
diff --git a/altoslib/AltosEepromHeaderIterable.java b/altoslib/AltosEepromHeaderIterable.java
new file mode 100644 (file)
index 0000000..fe9e05d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromHeaderIterable implements Iterable<AltosEepromHeader> {
+       public LinkedList<AltosEepromHeader> headers;
+
+       public void write(PrintStream out) {
+               AltosEepromHeader.write(out, headers);
+       }
+
+       public AltosState state() {
+               AltosState      state = new AltosState(null);
+
+               for (AltosEepromHeader header : headers)
+                       header.update_state(state);
+               return state;
+       }
+
+       public AltosEepromHeaderIterable(FileInputStream input) {
+               headers = AltosEepromHeader.read(input);
+       }
+
+       public Iterator<AltosEepromHeader> iterator() {
+               if (headers == null)
+                       headers = new LinkedList<AltosEepromHeader>();
+               return headers.iterator();
+       }
+}
\ No newline at end of file
index b84574ef9647261ea724d9510f0946f03469f544..470a7a8adf98f5c65b6f347f7b714c2a4e6aaa59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ * Copyright © 2013 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
@@ -21,415 +21,29 @@ import java.io.*;
 import java.util.*;
 import java.text.*;
 
-public class AltosEepromIterable extends AltosRecordIterable {
+public class AltosEepromIterable implements Iterable<AltosEeprom> {
+       public LinkedList<AltosEeprom> eeproms;
 
-       static final int        seen_basic = AltosRecord.seen_flight|AltosRecord.seen_sensor;
-
-       boolean                 has_accel;
-       boolean                 has_gps;
-       boolean                 has_ignite;
-
-       AltosEepromRecord       flight_record;
-       AltosEepromRecord       gps_date_record;
-
-       TreeSet<AltosOrderedRecord>     records;
-
-       LinkedList<AltosRecord> list;
-
-       class EepromState {
-               int     seen;
-               int     n_pad_samples;
-               double  ground_pres;
-               int     gps_tick;
-               int     boost_tick;
-               int     sensor_tick;
-
-               EepromState() {
-                       seen = 0;
-                       n_pad_samples = 0;
-                       ground_pres = 0.0;
-                       gps_tick = 0;
-               }
-       }
-
-       void update_state(AltosRecordTM state, AltosEepromRecord record, EepromState eeprom) {
-               state.tick = record.tick;
-               switch (record.cmd) {
-               case AltosLib.AO_LOG_FLIGHT:
-                       eeprom.seen |= AltosRecord.seen_flight;
-                       state.ground_accel = record.a;
-                       state.flight_accel = record.a;
-                       state.flight = record.b;
-                       eeprom.boost_tick = record.tick;
-                       break;
-               case AltosLib.AO_LOG_SENSOR:
-                       state.accel = record.a;
-                       state.pres = record.b;
-                       if (state.state < AltosLib.ao_flight_boost) {
-                               eeprom.n_pad_samples++;
-                               eeprom.ground_pres += state.pres;
-                               state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
-                               state.flight_pres = state.ground_pres;
-                       } else {
-                               state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
-                       }
-                       state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
-                       if ((eeprom.seen & AltosRecord.seen_sensor) == 0)
-                               eeprom.sensor_tick = record.tick - 1;
-                       state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
-                       eeprom.seen |= AltosRecord.seen_sensor;
-                       eeprom.sensor_tick = record.tick;
-                       has_accel = true;
-                       break;
-               case AltosLib.AO_LOG_PRESSURE:
-                       state.pres = record.b;
-                       state.flight_pres = state.pres;
-                       if (eeprom.n_pad_samples == 0) {
-                               eeprom.n_pad_samples++;
-                               state.ground_pres = state.pres;
-                       }
-                       eeprom.seen |= AltosRecord.seen_sensor;
-                       break;
-               case AltosLib.AO_LOG_TEMP_VOLT:
-                       state.temp = record.a;
-                       state.batt = record.b;
-                       eeprom.seen |= AltosRecord.seen_temp_volt;
-                       break;
-               case AltosLib.AO_LOG_DEPLOY:
-                       state.drogue = record.a;
-                       state.main = record.b;
-                       eeprom.seen |= AltosRecord.seen_deploy;
-                       has_ignite = true;
-                       break;
-               case AltosLib.AO_LOG_STATE:
-                       state.state = record.a;
-                       break;
-               case AltosLib.AO_LOG_GPS_TIME:
-                       eeprom.gps_tick = state.tick;
-                       eeprom.seen |= AltosRecord.seen_gps_time;
-                       AltosGPS old = state.gps;
-                       state.gps = new AltosGPS();
-
-                       /* GPS date doesn't get repeated through the file */
-                       if (old != null) {
-                               state.gps.year = old.year;
-                               state.gps.month = old.month;
-                               state.gps.day = old.day;
-                       }
-                       state.gps.hour = (record.a & 0xff);
-                       state.gps.minute = (record.a >> 8);
-                       state.gps.second = (record.b & 0xff);
-
-                       int flags = (record.b >> 8);
-                       state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
-                       state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
-                       state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
-                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
-                       state.gps_sequence++;
-                       has_gps = true;
-                       break;
-               case AltosLib.AO_LOG_GPS_LAT:
-                       eeprom.seen |= AltosRecord.seen_gps_lat;
-                       int lat32 = record.a | (record.b << 16);
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.lat = (double) lat32 / 1e7;
-                       break;
-               case AltosLib.AO_LOG_GPS_LON:
-                       eeprom.seen |= AltosRecord.seen_gps_lon;
-                       int lon32 = record.a | (record.b << 16);
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.lon = (double) lon32 / 1e7;
-                       break;
-               case AltosLib.AO_LOG_GPS_ALT:
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.alt = record.a;
-                       break;
-               case AltosLib.AO_LOG_GPS_SAT:
-                       if (state.tick == eeprom.gps_tick) {
-                               int svid = record.a;
-                               int c_n0 = record.b >> 8;
-                               if (state.gps == null)
-                                       state.gps = new AltosGPS();
-                               state.gps.add_sat(svid, c_n0);
-                       }
-                       break;
-               case AltosLib.AO_LOG_GPS_DATE:
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.year = (record.a & 0xff) + 2000;
-                       state.gps.month = record.a >> 8;
-                       state.gps.day = record.b & 0xff;
-                       break;
-
-               case AltosLib.AO_LOG_CONFIG_VERSION:
-                       break;
-               case AltosLib.AO_LOG_MAIN_DEPLOY:
-                       break;
-               case AltosLib.AO_LOG_APOGEE_DELAY:
-                       break;
-               case AltosLib.AO_LOG_RADIO_CHANNEL:
-                       break;
-               case AltosLib.AO_LOG_CALLSIGN:
-                       state.callsign = record.data;
-                       break;
-               case AltosLib.AO_LOG_ACCEL_CAL:
-                       state.accel_plus_g = record.a;
-                       state.accel_minus_g = record.b;
-                       break;
-               case AltosLib.AO_LOG_RADIO_CAL:
-                       break;
-               case AltosLib.AO_LOG_MANUFACTURER:
-                       break;
-               case AltosLib.AO_LOG_PRODUCT:
-                       break;
-               case AltosLib.AO_LOG_SERIAL_NUMBER:
-                       state.serial = record.a;
-                       break;
-               case AltosLib.AO_LOG_SOFTWARE_VERSION:
-                       break;
-               }
-               state.seen |= eeprom.seen;
+       public void write(PrintStream out) {
+               for (AltosEeprom eeprom : eeproms)
+                       eeprom.write(out);
        }
 
-       LinkedList<AltosRecord> make_list() {
-               LinkedList<AltosRecord>         list = new LinkedList<AltosRecord>();
-               Iterator<AltosOrderedRecord>    iterator = records.iterator();
-               AltosOrderedRecord              record = null;
-               AltosRecordTM                   state = new AltosRecordTM();
-               //boolean                               last_reported = false;
-               EepromState                     eeprom = new EepromState();
-
-               state.state = AltosLib.ao_flight_pad;
-               state.accel_plus_g = 15758;
-               state.accel_minus_g = 16294;
-               state.flight_vel = 0;
+       public AltosState state() {
+               AltosState      state = new AltosState(null);
 
-               /* Pull in static data from the flight and gps_date records */
-               if (flight_record != null)
-                       update_state(state, flight_record, eeprom);
-               if (gps_date_record != null)
-                       update_state(state, gps_date_record, eeprom);
-
-               while (iterator.hasNext()) {
-                       record = iterator.next();
-                       if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
-                               AltosRecordTM r = state.clone();
-                               r.time = (r.tick - eeprom.boost_tick) / 100.0;
-                               list.add(r);
-                       }
-                       update_state(state, record, eeprom);
-               }
-               AltosRecordTM r = state.clone();
-               r.time = (r.tick - eeprom.boost_tick) / 100.0;
-               list.add(r);
-       return list;
-       }
-
-       public Iterator<AltosRecord> iterator() {
-               if (list == null)
-                       list = make_list();
-               return list.iterator();
+               for (AltosEeprom header : eeproms)
+                       header.update_state(state);
+               return state;
        }
 
-       public boolean has_gps() { return has_gps; }
-       public boolean has_accel() { return has_accel; }
-       public boolean has_ignite() { return has_ignite; }
-
-       public void write_comments(PrintStream out) {
-               Iterator<AltosOrderedRecord>    iterator = records.iterator();
-               out.printf("# Comments\n");
-               while (iterator.hasNext()) {
-                       AltosOrderedRecord      record = iterator.next();
-                       switch (record.cmd) {
-                       case AltosLib.AO_LOG_CONFIG_VERSION:
-                               out.printf("# Config version: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_MAIN_DEPLOY:
-                               out.printf("# Main deploy: %s\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_APOGEE_DELAY:
-                               out.printf("# Apogee delay: %s\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_RADIO_CHANNEL:
-                               out.printf("# Radio channel: %s\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_CALLSIGN:
-                               out.printf("# Callsign: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_ACCEL_CAL:
-                               out.printf ("# Accel cal: %d %d\n", record.a, record.b);
-                               break;
-                       case AltosLib.AO_LOG_RADIO_CAL:
-                               out.printf ("# Radio cal: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
-                               out.printf ("# Max flight log: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_MANUFACTURER:
-                               out.printf ("# Manufacturer: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_PRODUCT:
-                               out.printf ("# Product: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_SERIAL_NUMBER:
-                               out.printf ("# Serial number: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_SOFTWARE_VERSION:
-                               out.printf ("# Software version: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_BARO_RESERVED:
-                               out.printf ("# Baro reserved: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_SENS:
-                               out.printf ("# Baro sens: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_OFF:
-                               out.printf ("# Baro off: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TCS:
-                               out.printf ("# Baro tcs: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TCO:
-                               out.printf ("# Baro tco: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TREF:
-                               out.printf ("# Baro tref: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TEMPSENS:
-                               out.printf ("# Baro tempsens: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_CRC:
-                               out.printf ("# Baro crc: %d\n", record.a);
-                               break;
-                       }
-               }
+       public AltosEepromIterable(LinkedList<AltosEeprom> eeproms) {
+               this.eeproms = eeproms;
        }
 
-       /*
-        * Given an AO_LOG_GPS_TIME record with correct time, and one
-        * missing time, rewrite the missing time values with the good
-        * ones, assuming that the difference between them is 'diff' seconds
-        */
-       void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) {
-
-               int diff = (bad.tick - good.tick + 50) / 100;
-
-               int hour = (good.a & 0xff);
-               int minute = (good.a >> 8);
-               int second = (good.b & 0xff);
-               int flags = (good.b >> 8);
-               int seconds = hour * 3600 + minute * 60 + second;
-
-               /* Make sure this looks like a good GPS value */
-               if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4)
-                       flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT);
-               flags |= AltosLib.AO_GPS_RUNNING;
-               flags |= AltosLib.AO_GPS_VALID;
-
-               int new_seconds = seconds + diff;
-               if (new_seconds < 0)
-                       new_seconds += 24 * 3600;
-               int new_second = (new_seconds % 60);
-               int new_minutes = (new_seconds / 60);
-               int new_minute = (new_minutes % 60);
-               int new_hours = (new_minutes / 60);
-               int new_hour = (new_hours % 24);
-
-               bad.a = new_hour + (new_minute << 8);
-               bad.b = new_second + (flags << 8);
-       }
-
-       /*
-        * Read the whole file, dumping records into a RB tree so
-        * we can enumerate them in time order -- the eeprom data
-        * are sometimes out of order with GPS data getting timestamps
-        * matching the first packet out of the GPS unit but not
-        * written until the final GPS packet has been received.
-        */
-       public AltosEepromIterable (FileInputStream input) {
-               records = new TreeSet<AltosOrderedRecord>();
-
-               AltosOrderedRecord last_gps_time = null;
-
-               int index = 0;
-               int prev_tick = 0;
-               boolean prev_tick_valid = false;
-               boolean missing_time = false;
-
-               try {
-                       for (;;) {
-                               String line = AltosLib.gets(input);
-                               if (line == null)
-                                       break;
-                               AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid);
-                               if (record.cmd == AltosLib.AO_LOG_INVALID)
-                                       continue;
-                               prev_tick = record.tick;
-                               if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
-                                       prev_tick_valid = true;
-                               if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
-                                       flight_record = record;
-                                       continue;
-                               }
-
-                               /* Two firmware bugs caused the loss of some GPS data.
-                                * The flight date would never be recorded, and often
-                                * the flight time would get overwritten by another
-                                * record. Detect the loss of the GPS date and fix up the
-                                * missing time records
-                                */
-                               if (record.cmd == AltosLib.AO_LOG_GPS_DATE) {
-                                       gps_date_record = record;
-                                       continue;
-                               }
-
-                               /* go back and fix up any missing time values */
-                               if (record.cmd == AltosLib.AO_LOG_GPS_TIME) {
-                                       last_gps_time = record;
-                                       if (missing_time) {
-                                               Iterator<AltosOrderedRecord> iterator = records.iterator();
-                                               while (iterator.hasNext()) {
-                                                       AltosOrderedRecord old = iterator.next();
-                                                       if (old.cmd == AltosLib.AO_LOG_GPS_TIME &&
-                                                           old.a == -1 && old.b == -1)
-                                                       {
-                                                               update_time(record, old);
-                                                       }
-                                               }
-                                               missing_time = false;
-                                       }
-                               }
-
-                               if (record.cmd == AltosLib.AO_LOG_GPS_LAT) {
-                                       if (last_gps_time == null || last_gps_time.tick != record.tick) {
-                                               AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME,
-                                                                                                        record.tick,
-                                                                                                        -1, -1, index-1);
-                                               if (last_gps_time != null)
-                                                       update_time(last_gps_time, add_gps_time);
-                                               else
-                                                       missing_time = true;
-
-                                               records.add(add_gps_time);
-                                               record.index = index++;
-                                       }
-                               }
-                               records.add(record);
-
-                               /* Bail after reading the 'landed' record; we're all done */
-                               if (record.cmd == AltosLib.AO_LOG_STATE &&
-                                   record.a == AltosLib.ao_flight_landed)
-                                       break;
-                       }
-               } catch (IOException io) {
-               } catch (ParseException pe) {
-               }
-               try {
-                       input.close();
-               } catch (IOException ie) {
-               }
+       public Iterator<AltosEeprom> iterator() {
+               if (eeproms == null)
+                       eeproms = new LinkedList<AltosEeprom>();
+               return eeproms.iterator();
        }
-}
+}
\ No newline at end of file
diff --git a/altoslib/AltosEepromMetrum.java b/altoslib/AltosEepromMetrum.java
new file mode 100644 (file)
index 0000000..7288703
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.text.*;
+
+public class AltosEepromMetrum {
+       public int      cmd;
+       public int      tick;
+       public boolean  valid;
+       public String   data;
+       public int      config_a, config_b;
+
+       public int      data8[];
+
+       public static final int record_length = 16;
+       static final int        header_length = 4;
+       static final int        data_length = record_length - header_length;
+
+       public int data8(int i) {
+               return data8[i];
+       }
+
+       public int data16(int i) {
+               return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16;
+       }
+
+       public int data32(int i) {
+               return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
+       }
+
+       /* AO_LOG_FLIGHT elements */
+       public int flight() { return data16(0); }
+       public int ground_accel() { return data16(2); }
+       public int ground_pres() { return data32(4); }
+       public int ground_temp() { return data32(8); }
+
+       /* AO_LOG_STATE elements */
+       public int state() { return data16(0); }
+       public int reason() { return data16(2); }
+
+       /* AO_LOG_SENSOR elements */
+       public int pres() { return data32(0); }
+       public int temp() { return data32(4); }
+       public int accel() { return data16(8); }
+
+       /* AO_LOG_TEMP_VOLT elements */
+       public int v_batt() { return data16(0); }
+       public int sense_a() { return data16(2); }
+       public int sense_m() { return data16(4); }
+
+       /* AO_LOG_GPS_POS elements */
+       public int latitude() { return data32(0); }
+       public int longitude() { return data32(4); }
+       public int altitude() { return data16(8); }
+
+       /* AO_LOG_GPS_TIME elements */
+       public int hour() { return data8(0); }
+       public int minute() { return data8(1); }
+       public int second() { return data8(2); }
+       public int flags() { return data8(3); }
+       public int year() { return data8(4); }
+       public int month() { return data8(5); }
+       public int day() { return data8(6); }
+       
+       /* AO_LOG_GPS_SAT elements */
+       public int channels() { return data8(0); }
+       public int more() { return data8(1); }
+       public int svid(int n) { return data8(2 + n * 2); }
+       public int c_n(int n) { return data8(2 + n * 2 + 1); }
+
+       public AltosEepromMetrum (AltosEepromChunk chunk, int start) throws ParseException {
+               cmd = chunk.data(start);
+
+               valid = !chunk.erased(start, record_length);
+               if (valid) {
+                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
+                               throw new ParseException(String.format("invalid checksum at 0x%x",
+                                                                      chunk.address + start), 0);
+               } else {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               }
+
+               tick = chunk.data16(start+2);
+
+               data8 = new int[data_length];
+               for (int i = 0; i < data_length; i++)
+                       data8[i] = chunk.data(start + header_length + i);
+       }
+
+       public AltosEepromMetrum (String line) {
+               valid = false;
+               tick = 0;
+
+               if (line == null) {
+                       cmd = AltosLib.AO_LOG_INVALID;
+                       line = "";
+               } else {
+                       try {
+                               String[] tokens = line.split("\\s+");
+
+                               if (tokens[0].length() == 1) {
+                                       if (tokens.length != 2 + data_length) {
+                                               cmd = AltosLib.AO_LOG_INVALID;
+                                               data = line;
+                                       } else {
+                                               cmd = tokens[0].codePointAt(0);
+                                               tick = Integer.parseInt(tokens[1],16);
+                                               valid = true;
+                                               data8 = new int[data_length];
+                                               for (int i = 0; i < data_length; i++)
+                                                       data8[i] = Integer.parseInt(tokens[2 + i],16);
+                                       }
+                               } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+                                       cmd = AltosLib.AO_LOG_CONFIG_VERSION;
+                                       data = tokens[2];
+                               } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+                                       cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+                                       cmd = AltosLib.AO_LOG_APOGEE_DELAY;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+                                       cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Callsign:")) {
+                                       cmd = AltosLib.AO_LOG_CALLSIGN;
+                                       data = tokens[1].replaceAll("\"","");
+                               } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+                                       cmd = AltosLib.AO_LOG_ACCEL_CAL;
+                                       config_a = Integer.parseInt(tokens[3]);
+                                       config_b = Integer.parseInt(tokens[5]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+                                       cmd = AltosLib.AO_LOG_RADIO_CAL;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
+                                       cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
+                                       config_a = Integer.parseInt(tokens[3]);
+                               } else if (tokens[0].equals("manufacturer")) {
+                                       cmd = AltosLib.AO_LOG_MANUFACTURER;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("product")) {
+                                       cmd = AltosLib.AO_LOG_PRODUCT;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("serial-number")) {
+                                       cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
+                                       config_a = Integer.parseInt(tokens[1]);
+                               } else if (tokens[0].equals("log-format")) {
+                                       cmd = AltosLib.AO_LOG_LOG_FORMAT;
+                                       config_a = Integer.parseInt(tokens[1]);
+                               } else if (tokens[0].equals("software-version")) {
+                                       cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("ms5607")) {
+                                       if (tokens[1].equals("reserved:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_RESERVED;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("sens:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_SENS;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("off:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_OFF;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tcs:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TCS;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tco:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TCO;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tref:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TREF;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tempsens:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("crc:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_CRC;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else {
+                                               cmd = AltosLib.AO_LOG_INVALID;
+                                               data = line;
+                                       }
+                               } else {
+                                       cmd = AltosLib.AO_LOG_INVALID;
+                                       data = line;
+                               }
+                       } catch (NumberFormatException ne) {
+                               cmd = AltosLib.AO_LOG_INVALID;
+                               data = line;
+                       }
+               }
+       }
+
+       public AltosEepromMetrum(int in_cmd, int in_tick) {
+               cmd = in_cmd;
+               tick = in_tick;
+               valid = true;
+       }
+}
diff --git a/altoslib/AltosEepromMetrumIterable.java b/altoslib/AltosEepromMetrumIterable.java
new file mode 100644 (file)
index 0000000..0387319
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromMetrumIterable extends AltosRecordIterable {
+
+       static final int        seen_flight = 1;
+       static final int        seen_sensor = 2;
+       static final int        seen_temp_volt = 4;
+       static final int        seen_deploy = 8;
+       static final int        seen_gps_time = 16;
+       static final int        seen_gps_lat = 32;
+       static final int        seen_gps_lon = 64;
+
+       static final int        seen_basic = seen_flight|seen_sensor;
+
+       boolean                 has_accel;
+       boolean                 has_gps;
+       boolean                 has_ignite;
+
+       AltosEepromMetrum       flight_record;
+       AltosEepromMetrum       gps_date_record;
+
+       TreeSet<AltosOrderedMetrumRecord>       records;
+
+       AltosMs5607             baro;
+
+       LinkedList<AltosRecord> list;
+
+       class EepromState {
+               int     seen;
+               int     n_pad_samples;
+               double  ground_pres;
+               int     gps_tick;
+               int     boost_tick;
+               int     sensor_tick;
+
+               EepromState() {
+                       seen = 0;
+                       n_pad_samples = 0;
+                       ground_pres = 0.0;
+                       gps_tick = 0;
+               }
+       }
+
+       void update_state(AltosRecordTM2 state, AltosEepromMetrum record, EepromState eeprom) {
+               state.tick = record.tick;
+               switch (record.cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       eeprom.seen |= seen_flight;
+                       state.ground_accel = record.ground_accel();
+                       state.flight_accel = record.ground_accel();
+                       state.ground_pres = baro.set(record.ground_pres(), record.ground_temp());
+                       state.flight_pres = state.ground_pres;
+                       state.flight = record.data16(0);
+                       eeprom.boost_tick = record.tick;
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.state = record.state();
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       state.accel = record.accel();
+                       baro.set(record.pres(), record.temp());
+                       state.pres = baro.pa;
+                       state.temp = baro.cc;
+                       if (state.state < AltosLib.ao_flight_boost) {
+                               eeprom.n_pad_samples++;
+                               eeprom.ground_pres += state.pres;
+                               state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
+                               state.flight_pres = state.ground_pres;
+                       } else {
+                               state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
+                       }
+                       state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
+                       if ((eeprom.seen & seen_sensor) == 0)
+                               eeprom.sensor_tick = record.tick - 1;
+                       state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
+                       eeprom.seen |= seen_sensor;
+                       eeprom.sensor_tick = record.tick;
+                       has_accel = true;
+                       break;
+               case AltosLib.AO_LOG_TEMP_VOLT:
+                       state.v_batt = record.v_batt();
+                       state.sense_a = record.sense_a();
+                       state.sense_m = record.sense_m();
+                       eeprom.seen |= seen_temp_volt;
+                       break;
+               case AltosLib.AO_LOG_GPS_POS:
+                       eeprom.gps_tick = state.tick;
+                       state.gps = new AltosGPS();
+
+                       state.gps.lat = record.latitude() / 1e7;
+                       state.gps.lon = record.longitude() / 1e7;
+                       state.gps.alt = record.altitude();
+                       break;
+
+               case AltosLib.AO_LOG_GPS_TIME:
+                       state.gps.year = record.year() + 2000;
+                       state.gps.month = record.month();
+                       state.gps.day = record.day();
+
+                       state.gps.hour = record.hour();
+                       state.gps.minute = record.minute();
+                       state.gps.second = record.second();
+
+                       int flags = record.flags();
+                       state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+                       state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+                       state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
+                       state.gps_sequence++;
+                       has_gps = true;
+                       eeprom.seen |= seen_gps_time | seen_gps_lat | seen_gps_lon;
+                       break;
+               case AltosLib.AO_LOG_GPS_SAT:
+                       if (state.tick == eeprom.gps_tick) {
+                               int nsat = record.channels();
+                               for (int i = 0; i < nsat; i++)
+                                       state.gps.add_sat(record.svid(i), record.c_n(i));
+                       }
+                       break;
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       state.callsign = record.data;
+                       break;
+               case AltosLib.AO_LOG_ACCEL_CAL:
+                       state.accel_plus_g = record.config_a;
+                       state.accel_minus_g = record.config_b;
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       state.serial = record.config_a;
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       break;
+               case AltosLib.AO_LOG_BARO_RESERVED:
+                       baro.reserved = record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_SENS:
+                       baro.sens =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_OFF:
+                       baro.off =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCS:
+                       baro.tcs =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCO:
+                       baro.tco =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TREF:
+                       baro.tref =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TEMPSENS:
+                       baro.tempsens =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_CRC:
+                       baro.crc =record.config_a;
+                       break;
+               }
+               state.seen |= eeprom.seen;
+       }
+
+       LinkedList<AltosRecord> make_list() {
+               LinkedList<AltosRecord>                 list = new LinkedList<AltosRecord>();
+               Iterator<AltosOrderedMetrumRecord>      iterator = records.iterator();
+               AltosOrderedMetrumRecord                record = null;
+               AltosRecordTM2                          state = new AltosRecordTM2();
+               //boolean                               last_reported = false;
+               EepromState                             eeprom = new EepromState();
+
+               state.state = AltosLib.ao_flight_pad;
+               state.accel_plus_g = 15758;
+               state.accel_minus_g = 16294;
+
+               /* Pull in static data from the flight and gps_date records */
+               if (flight_record != null)
+                       update_state(state, flight_record, eeprom);
+               if (gps_date_record != null)
+                       update_state(state, gps_date_record, eeprom);
+
+               while (iterator.hasNext()) {
+                       record = iterator.next();
+                       if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
+                               AltosRecordTM2 r = state.clone();
+                               r.time = (r.tick - eeprom.boost_tick) / 100.0;
+                               list.add(r);
+                       }
+                       update_state(state, record, eeprom);
+               }
+               AltosRecordTM2 r = state.clone();
+               r.time = (r.tick - eeprom.boost_tick) / 100.0;
+               list.add(r);
+               return list;
+       }
+
+       public Iterator<AltosRecord> iterator() {
+               if (list == null)
+                       list = make_list();
+               return list.iterator();
+       }
+
+       public boolean has_gps() { return has_gps; }
+       public boolean has_accel() { return has_accel; }
+       public boolean has_ignite() { return has_ignite; }
+
+       public void write_comments(PrintStream out) {
+               Iterator<AltosOrderedMetrumRecord>      iterator = records.iterator();
+               out.printf("# Comments\n");
+               while (iterator.hasNext()) {
+                       AltosOrderedMetrumRecord        record = iterator.next();
+                       switch (record.cmd) {
+                       case AltosLib.AO_LOG_CONFIG_VERSION:
+                               out.printf("# Config version: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_MAIN_DEPLOY:
+                               out.printf("# Main deploy: %s\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_APOGEE_DELAY:
+                               out.printf("# Apogee delay: %s\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_RADIO_CHANNEL:
+                               out.printf("# Radio channel: %s\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_CALLSIGN:
+                               out.printf("# Callsign: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_ACCEL_CAL:
+                               out.printf ("# Accel cal: %d %d\n", record.config_a, record.config_b);
+                               break;
+                       case AltosLib.AO_LOG_RADIO_CAL:
+                               out.printf ("# Radio cal: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
+                               out.printf ("# Max flight log: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_MANUFACTURER:
+                               out.printf ("# Manufacturer: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_PRODUCT:
+                               out.printf ("# Product: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_SERIAL_NUMBER:
+                               out.printf ("# Serial number: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                               out.printf ("# Software version: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_BARO_RESERVED:
+                               out.printf ("# Baro reserved: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_SENS:
+                               out.printf ("# Baro sens: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_OFF:
+                               out.printf ("# Baro off: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TCS:
+                               out.printf ("# Baro tcs: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TCO:
+                               out.printf ("# Baro tco: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TREF:
+                               out.printf ("# Baro tref: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TEMPSENS:
+                               out.printf ("# Baro tempsens: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_CRC:
+                               out.printf ("# Baro crc: %d\n", record.config_a);
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * Read the whole file, dumping records into a RB tree so
+        * we can enumerate them in time order -- the eeprom data
+        * are sometimes out of order with GPS data getting timestamps
+        * matching the first packet out of the GPS unit but not
+        * written until the final GPS packet has been received.
+        */
+       public AltosEepromMetrumIterable (FileInputStream input) {
+               records = new TreeSet<AltosOrderedMetrumRecord>();
+
+               AltosOrderedMetrumRecord last_gps_time = null;
+
+               baro = new AltosMs5607();
+
+               int index = 0;
+               int prev_tick = 0;
+               boolean prev_tick_valid = false;
+               boolean missing_time = false;
+
+               try {
+                       for (;;) {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosOrderedMetrumRecord record = new AltosOrderedMetrumRecord(line, index++, prev_tick, prev_tick_valid);
+                               if (record.cmd == AltosLib.AO_LOG_INVALID)
+                                       continue;
+                               prev_tick = record.tick;
+                               if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
+                                       prev_tick_valid = true;
+                               if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
+                                       flight_record = record;
+                                       continue;
+                               }
+
+                               records.add(record);
+
+                               /* Bail after reading the 'landed' record; we're all done */
+                               if (record.cmd == AltosLib.AO_LOG_STATE &&
+                                   record.state() == AltosLib.ao_flight_landed)
+                                       break;
+                       }
+               } catch (IOException io) {
+               } catch (ParseException pe) {
+               }
+               try {
+                       input.close();
+               } catch (IOException ie) {
+               }
+       }
+}
index 215cd3d9a99eeb2461cbdf377a07890df55dfe9b..ced8768045b14168bdff54fdc76242335c57c749 100644 (file)
 
 package org.altusmetrum.altoslib_1;
 
+import java.io.*;
+import java.util.*;
 import java.text.*;
 
-public class AltosEepromMini {
-       public int      cmd;
-       public int      tick;
-       public boolean  valid;
-       public String   data;
-       public int      config_a, config_b;
-
-       public int      data8[];
-
+public class AltosEepromMini extends AltosEeprom {
        public static final int record_length = 16;
-       static final int        header_length = 4;
-       static final int        data_length = record_length - header_length;
 
        public int data8(int i) {
                return data8[i];
@@ -63,126 +55,23 @@ public class AltosEepromMini {
        public int sense_m() { return data16(8); }
        public int v_batt() { return data16(10); }
 
-       public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException {
-               cmd = chunk.data(start);
-
-               valid = !chunk.erased(start, record_length);
-               if (valid) {
-                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
-                               throw new ParseException(String.format("invalid checksum at 0x%x",
-                                                                      chunk.address + start), 0);
-               } else {
-                       cmd = AltosLib.AO_LOG_INVALID;
+       public void update_state(AltosState state) {
+               switch (cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       break;
                }
+       }
 
-               tick = chunk.data16(start+2);
-
-               data8 = new int[data_length];
-               for (int i = 0; i < data_length; i++)
-                       data8[i] = chunk.data(start + header_length + i);
+       public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException {
+               parse_chunk(chunk, start, record_length);
        }
 
        public AltosEepromMini (String line) {
-               valid = false;
-               tick = 0;
-
-               if (line == null) {
-                       cmd = AltosLib.AO_LOG_INVALID;
-                       line = "";
-               } else {
-                       try {
-                               String[] tokens = line.split("\\s+");
-
-                               if (tokens[0].length() == 1) {
-                                       if (tokens.length != 2 + data_length) {
-                                               cmd = AltosLib.AO_LOG_INVALID;
-                                               data = line;
-                                       } else {
-                                               cmd = tokens[0].codePointAt(0);
-                                               tick = Integer.parseInt(tokens[1],16);
-                                               valid = true;
-                                               data8 = new int[data_length];
-                                               for (int i = 0; i < data_length; i++)
-                                                       data8[i] = Integer.parseInt(tokens[2 + i],16);
-                                       }
-                               } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
-                                       cmd = AltosLib.AO_LOG_CONFIG_VERSION;
-                                       data = tokens[2];
-                               } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
-                                       cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
-                                       cmd = AltosLib.AO_LOG_APOGEE_DELAY;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
-                                       cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Callsign:")) {
-                                       cmd = AltosLib.AO_LOG_CALLSIGN;
-                                       data = tokens[1].replaceAll("\"","");
-                               } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
-                                       cmd = AltosLib.AO_LOG_ACCEL_CAL;
-                                       config_a = Integer.parseInt(tokens[3]);
-                                       config_b = Integer.parseInt(tokens[5]);
-                               } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
-                                       cmd = AltosLib.AO_LOG_RADIO_CAL;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
-                                       cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
-                                       config_a = Integer.parseInt(tokens[3]);
-                               } else if (tokens[0].equals("manufacturer")) {
-                                       cmd = AltosLib.AO_LOG_MANUFACTURER;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("product")) {
-                                       cmd = AltosLib.AO_LOG_PRODUCT;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("serial-number")) {
-                                       cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
-                                       config_a = Integer.parseInt(tokens[1]);
-                               } else if (tokens[0].equals("log-format")) {
-                                       cmd = AltosLib.AO_LOG_LOG_FORMAT;
-                                       config_a = Integer.parseInt(tokens[1]);
-                               } else if (tokens[0].equals("software-version")) {
-                                       cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("ms5607")) {
-                                       if (tokens[1].equals("reserved:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_RESERVED;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("sens:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_SENS;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("off:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_OFF;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tcs:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TCS;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tco:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TCO;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tref:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TREF;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tempsens:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("crc:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_CRC;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else {
-                                               cmd = AltosLib.AO_LOG_INVALID;
-                                               data = line;
-                                       }
-                               } else {
-                                       cmd = AltosLib.AO_LOG_INVALID;
-                                       data = line;
-                               }
-                       } catch (NumberFormatException ne) {
-                               cmd = AltosLib.AO_LOG_INVALID;
-                               data = line;
-                       }
-               }
+               parse_string(line, record_length);
        }
 
        public AltosEepromMini(int in_cmd, int in_tick) {
@@ -190,4 +79,22 @@ public class AltosEepromMini {
                tick = in_tick;
                valid = true;
        }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> minis = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosEepromMini mini = new AltosEepromMini(line);
+                               minis.add(mini);
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return minis;
+       }
 }
diff --git a/altoslib/AltosEepromOldIterable.java b/altoslib/AltosEepromOldIterable.java
new file mode 100644 (file)
index 0000000..ef82828
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright © 2010 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromOldIterable extends AltosRecordIterable {
+
+       static final int        seen_basic = AltosRecord.seen_flight|AltosRecord.seen_sensor;
+
+       boolean                 has_accel;
+       boolean                 has_gps;
+       boolean                 has_ignite;
+
+       AltosEepromRecord       flight_record;
+       AltosEepromRecord       gps_date_record;
+
+       TreeSet<AltosOrderedRecord>     records;
+
+       LinkedList<AltosRecord> list;
+
+       class EepromState {
+               int     seen;
+               int     n_pad_samples;
+               double  ground_pres;
+               int     gps_tick;
+               int     boost_tick;
+               int     sensor_tick;
+
+               EepromState() {
+                       seen = 0;
+                       n_pad_samples = 0;
+                       ground_pres = 0.0;
+                       gps_tick = 0;
+               }
+       }
+
+       void update_state(AltosRecordTM state, AltosEepromRecord record, EepromState eeprom) {
+               state.tick = record.tick;
+               switch (record.cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       eeprom.seen |= AltosRecord.seen_flight;
+                       state.ground_accel = record.a;
+                       state.flight_accel = record.a;
+                       state.flight = record.b;
+                       eeprom.boost_tick = record.tick;
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       state.accel = record.a;
+                       state.pres = record.b;
+                       if (state.state < AltosLib.ao_flight_boost) {
+                               eeprom.n_pad_samples++;
+                               eeprom.ground_pres += state.pres;
+                               state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
+                               state.flight_pres = state.ground_pres;
+                       } else {
+                               state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
+                       }
+                       state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
+                       if ((eeprom.seen & AltosRecord.seen_sensor) == 0)
+                               eeprom.sensor_tick = record.tick - 1;
+                       state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
+                       eeprom.seen |= AltosRecord.seen_sensor;
+                       eeprom.sensor_tick = record.tick;
+                       has_accel = true;
+                       break;
+               case AltosLib.AO_LOG_PRESSURE:
+                       state.pres = record.b;
+                       state.flight_pres = state.pres;
+                       if (eeprom.n_pad_samples == 0) {
+                               eeprom.n_pad_samples++;
+                               state.ground_pres = state.pres;
+                       }
+                       eeprom.seen |= AltosRecord.seen_sensor;
+                       break;
+               case AltosLib.AO_LOG_TEMP_VOLT:
+                       state.temp = record.a;
+                       state.batt = record.b;
+                       eeprom.seen |= AltosRecord.seen_temp_volt;
+                       break;
+               case AltosLib.AO_LOG_DEPLOY:
+                       state.drogue = record.a;
+                       state.main = record.b;
+                       eeprom.seen |= AltosRecord.seen_deploy;
+                       has_ignite = true;
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.state = record.a;
+                       break;
+               case AltosLib.AO_LOG_GPS_TIME:
+                       eeprom.gps_tick = state.tick;
+                       eeprom.seen |= AltosRecord.seen_gps_time;
+                       AltosGPS old = state.gps;
+                       state.gps = new AltosGPS();
+
+                       /* GPS date doesn't get repeated through the file */
+                       if (old != null) {
+                               state.gps.year = old.year;
+                               state.gps.month = old.month;
+                               state.gps.day = old.day;
+                       }
+                       state.gps.hour = (record.a & 0xff);
+                       state.gps.minute = (record.a >> 8);
+                       state.gps.second = (record.b & 0xff);
+
+                       int flags = (record.b >> 8);
+                       state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+                       state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+                       state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
+                       state.gps_sequence++;
+                       has_gps = true;
+                       break;
+               case AltosLib.AO_LOG_GPS_LAT:
+                       eeprom.seen |= AltosRecord.seen_gps_lat;
+                       int lat32 = record.a | (record.b << 16);
+                       if (state.gps == null)
+                               state.gps = new AltosGPS();
+                       state.gps.lat = (double) lat32 / 1e7;
+                       break;
+               case AltosLib.AO_LOG_GPS_LON:
+                       eeprom.seen |= AltosRecord.seen_gps_lon;
+                       int lon32 = record.a | (record.b << 16);
+                       if (state.gps == null)
+                               state.gps = new AltosGPS();
+                       state.gps.lon = (double) lon32 / 1e7;
+                       break;
+               case AltosLib.AO_LOG_GPS_ALT:
+                       if (state.gps == null)
+                               state.gps = new AltosGPS();
+                       state.gps.alt = record.a;
+                       break;
+               case AltosLib.AO_LOG_GPS_SAT:
+                       if (state.tick == eeprom.gps_tick) {
+                               int svid = record.a;
+                               int c_n0 = record.b >> 8;
+                               if (state.gps == null)
+                                       state.gps = new AltosGPS();
+                               state.gps.add_sat(svid, c_n0);
+                       }
+                       break;
+               case AltosLib.AO_LOG_GPS_DATE:
+                       if (state.gps == null)
+                               state.gps = new AltosGPS();
+                       state.gps.year = (record.a & 0xff) + 2000;
+                       state.gps.month = record.a >> 8;
+                       state.gps.day = record.b & 0xff;
+                       break;
+
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       state.callsign = record.data;
+                       break;
+               case AltosLib.AO_LOG_ACCEL_CAL:
+                       state.accel_plus_g = record.a;
+                       state.accel_minus_g = record.b;
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       state.serial = record.a;
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       break;
+               }
+               state.seen |= eeprom.seen;
+       }
+
+       LinkedList<AltosRecord> make_list() {
+               LinkedList<AltosRecord>         list = new LinkedList<AltosRecord>();
+               Iterator<AltosOrderedRecord>    iterator = records.iterator();
+               AltosOrderedRecord              record = null;
+               AltosRecordTM                   state = new AltosRecordTM();
+               //boolean                               last_reported = false;
+               EepromState                     eeprom = new EepromState();
+
+               state.state = AltosLib.ao_flight_pad;
+               state.accel_plus_g = 15758;
+               state.accel_minus_g = 16294;
+               state.flight_vel = 0;
+
+               /* Pull in static data from the flight and gps_date records */
+               if (flight_record != null)
+                       update_state(state, flight_record, eeprom);
+               if (gps_date_record != null)
+                       update_state(state, gps_date_record, eeprom);
+
+               while (iterator.hasNext()) {
+                       record = iterator.next();
+                       if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
+                               AltosRecordTM r = state.clone();
+                               r.time = (r.tick - eeprom.boost_tick) / 100.0;
+                               list.add(r);
+                       }
+                       update_state(state, record, eeprom);
+               }
+               AltosRecordTM r = state.clone();
+               r.time = (r.tick - eeprom.boost_tick) / 100.0;
+               list.add(r);
+       return list;
+       }
+
+       public Iterator<AltosRecord> iterator() {
+               if (list == null)
+                       list = make_list();
+               return list.iterator();
+       }
+
+       public boolean has_gps() { return has_gps; }
+       public boolean has_accel() { return has_accel; }
+       public boolean has_ignite() { return has_ignite; }
+
+       public void write_comments(PrintStream out) {
+               Iterator<AltosOrderedRecord>    iterator = records.iterator();
+               out.printf("# Comments\n");
+               while (iterator.hasNext()) {
+                       AltosOrderedRecord      record = iterator.next();
+                       switch (record.cmd) {
+                       case AltosLib.AO_LOG_CONFIG_VERSION:
+                               out.printf("# Config version: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_MAIN_DEPLOY:
+                               out.printf("# Main deploy: %s\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_APOGEE_DELAY:
+                               out.printf("# Apogee delay: %s\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_RADIO_CHANNEL:
+                               out.printf("# Radio channel: %s\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_CALLSIGN:
+                               out.printf("# Callsign: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_ACCEL_CAL:
+                               out.printf ("# Accel cal: %d %d\n", record.a, record.b);
+                               break;
+                       case AltosLib.AO_LOG_RADIO_CAL:
+                               out.printf ("# Radio cal: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
+                               out.printf ("# Max flight log: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_MANUFACTURER:
+                               out.printf ("# Manufacturer: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_PRODUCT:
+                               out.printf ("# Product: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_SERIAL_NUMBER:
+                               out.printf ("# Serial number: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                               out.printf ("# Software version: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_BARO_RESERVED:
+                               out.printf ("# Baro reserved: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_SENS:
+                               out.printf ("# Baro sens: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_OFF:
+                               out.printf ("# Baro off: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TCS:
+                               out.printf ("# Baro tcs: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TCO:
+                               out.printf ("# Baro tco: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TREF:
+                               out.printf ("# Baro tref: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TEMPSENS:
+                               out.printf ("# Baro tempsens: %d\n", record.a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_CRC:
+                               out.printf ("# Baro crc: %d\n", record.a);
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * Given an AO_LOG_GPS_TIME record with correct time, and one
+        * missing time, rewrite the missing time values with the good
+        * ones, assuming that the difference between them is 'diff' seconds
+        */
+       void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) {
+
+               int diff = (bad.tick - good.tick + 50) / 100;
+
+               int hour = (good.a & 0xff);
+               int minute = (good.a >> 8);
+               int second = (good.b & 0xff);
+               int flags = (good.b >> 8);
+               int seconds = hour * 3600 + minute * 60 + second;
+
+               /* Make sure this looks like a good GPS value */
+               if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4)
+                       flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT);
+               flags |= AltosLib.AO_GPS_RUNNING;
+               flags |= AltosLib.AO_GPS_VALID;
+
+               int new_seconds = seconds + diff;
+               if (new_seconds < 0)
+                       new_seconds += 24 * 3600;
+               int new_second = (new_seconds % 60);
+               int new_minutes = (new_seconds / 60);
+               int new_minute = (new_minutes % 60);
+               int new_hours = (new_minutes / 60);
+               int new_hour = (new_hours % 24);
+
+               bad.a = new_hour + (new_minute << 8);
+               bad.b = new_second + (flags << 8);
+       }
+
+       /*
+        * Read the whole file, dumping records into a RB tree so
+        * we can enumerate them in time order -- the eeprom data
+        * are sometimes out of order with GPS data getting timestamps
+        * matching the first packet out of the GPS unit but not
+        * written until the final GPS packet has been received.
+        */
+       public AltosEepromOldIterable (FileInputStream input) {
+               records = new TreeSet<AltosOrderedRecord>();
+
+               AltosOrderedRecord last_gps_time = null;
+
+               int index = 0;
+               int prev_tick = 0;
+               boolean prev_tick_valid = false;
+               boolean missing_time = false;
+
+               try {
+                       for (;;) {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid);
+                               if (record.cmd == AltosLib.AO_LOG_INVALID)
+                                       continue;
+                               prev_tick = record.tick;
+                               if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
+                                       prev_tick_valid = true;
+                               if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
+                                       flight_record = record;
+                                       continue;
+                               }
+
+                               /* Two firmware bugs caused the loss of some GPS data.
+                                * The flight date would never be recorded, and often
+                                * the flight time would get overwritten by another
+                                * record. Detect the loss of the GPS date and fix up the
+                                * missing time records
+                                */
+                               if (record.cmd == AltosLib.AO_LOG_GPS_DATE) {
+                                       gps_date_record = record;
+                                       continue;
+                               }
+
+                               /* go back and fix up any missing time values */
+                               if (record.cmd == AltosLib.AO_LOG_GPS_TIME) {
+                                       last_gps_time = record;
+                                       if (missing_time) {
+                                               Iterator<AltosOrderedRecord> iterator = records.iterator();
+                                               while (iterator.hasNext()) {
+                                                       AltosOrderedRecord old = iterator.next();
+                                                       if (old.cmd == AltosLib.AO_LOG_GPS_TIME &&
+                                                           old.a == -1 && old.b == -1)
+                                                       {
+                                                               update_time(record, old);
+                                                       }
+                                               }
+                                               missing_time = false;
+                                       }
+                               }
+
+                               if (record.cmd == AltosLib.AO_LOG_GPS_LAT) {
+                                       if (last_gps_time == null || last_gps_time.tick != record.tick) {
+                                               AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME,
+                                                                                                        record.tick,
+                                                                                                        -1, -1, index-1);
+                                               if (last_gps_time != null)
+                                                       update_time(last_gps_time, add_gps_time);
+                                               else
+                                                       missing_time = true;
+
+                                               records.add(add_gps_time);
+                                               record.index = index++;
+                                       }
+                               }
+                               records.add(record);
+
+                               /* Bail after reading the 'landed' record; we're all done */
+                               if (record.cmd == AltosLib.AO_LOG_STATE &&
+                                   record.a == AltosLib.ao_flight_landed)
+                                       break;
+                       }
+               } catch (IOException io) {
+               } catch (ParseException pe) {
+               }
+               try {
+                       input.close();
+               } catch (IOException ie) {
+               }
+       }
+}
diff --git a/altoslib/AltosEepromTM.java b/altoslib/AltosEepromTM.java
new file mode 100644 (file)
index 0000000..fc7ec32
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright © 2010 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 org.altusmetrum.altoslib_1;
+
+import java.text.*;
+
+public class AltosEepromTM implements AltosStateUpdate {
+       public int      cmd;
+       public int      tick;
+       public int      a;
+       public int      b;
+       public String   data;
+       public boolean  tick_valid;
+
+       public static final int record_length = 8;
+
+       public void update_state(AltosState state) {
+               state.set_tick(tick);
+               switch (cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       state.ground_accel = a;
+                       state.flight = b;
+                       state.set_boost_tick(tick);
+                       state.time = 0;
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       state.set_telemetrum(a, b);
+                       break;
+               case AltosLib.AO_LOG_PRESSURE:
+                       state.set_telemetrum(AltosState.MISSING, b);
+                       break;
+               case AltosLib.AO_LOG_TEMP_VOLT:
+/*
+                       
+                       record.temp = a;
+                       record.batt = b;
+                       eeprom_state.seen |= AltosRecord.seen_temp_volt;
+*/
+                       break;
+               case AltosLib.AO_LOG_DEPLOY:
+/*
+                       record.drogue = a;
+                       record.main = b;
+                       eeprom_state.seen |= AltosRecord.seen_deploy;
+                       has_ignite = true;
+*/
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.state = a;
+                       break;
+//             case AltosLib.AO_LOG_GPS_TIME:
+//                     eeprom_state.gps_tick = record.tick;
+//                     eeprom_state.seen |= AltosRecord.seen_gps_time;
+//                     AltosGPS old = state.gps;
+//                     AltosGPS gps = new AltosGPS();
+//
+//                     /* GPS date doesn't get repeated through the file */
+//                     if (old != null) {
+//                             gps.year = old.year;
+//                             gps.month = old.month;
+//                             gps.day = old.day;
+//                     }
+//                     gps.hour = (a & 0xff);
+//                     gps.minute = (a >> 8);
+//                     gps.second = (b & 0xff);
+//
+//                     int flags = (b >> 8);
+//                     gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+//                     gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+//                     gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+//                             AltosLib.AO_GPS_NUM_SAT_SHIFT;
+//                     state.temp_gps = gps;
+//                     break;
+//             case AltosLib.AO_LOG_GPS_LAT:
+//                     int lat32 = a | (b << 16);
+//                     if (state.temp_gps == null)
+//                             state.temp_gps = new AltosGPS();
+//                     state.temp_gps.lat = (double) lat32 / 1e7;
+//                     break;
+//             case AltosLib.AO_LOG_GPS_LON:
+//                     int lon32 = a | (b << 16);
+//                     if (state.temp_gps == null)
+//                             state.temp_gps = new AltosGPS();
+//                     state.temp_gps.lon = (double) lon32 / 1e7;
+//                     break;
+//             case AltosLib.AO_LOG_GPS_ALT:
+//                     if (state.temp_gps == null)
+//                             state.temp_gps = new AltosGPS();
+//                     state.temp_gps.alt = a;
+//                     break;
+//             case AltosLib.AO_LOG_GPS_SAT:
+//                     if (record.tick == eeprom_state.gps_tick) {
+//                             int svid = a;
+//                             int c_n0 = b >> 8;
+//                             if (record.gps == null)
+//                                     record.gps = new AltosGPS();
+//                             record.gps.add_sat(svid, c_n0);
+//                     }
+//                     break;
+//             case AltosLib.AO_LOG_GPS_DATE:
+//                     if (record.gps == null)
+//                             record.gps = new AltosGPS();
+//                     record.gps.year = (a & 0xff) + 2000;
+//                     record.gps.month = a >> 8;
+//                     record.gps.day = b & 0xff;
+//                     break;
+
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       state.callsign = data;
+                       break;
+               case AltosLib.AO_LOG_ACCEL_CAL:
+                       state.accel_plus_g = a;
+                       state.accel_minus_g = b;
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       state.serial = a;
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       break;
+               }
+       }
+
+       public AltosEepromTM (AltosEepromChunk chunk, int start) throws ParseException {
+
+               cmd = chunk.data(start);
+               tick_valid = true;
+
+               tick_valid = !chunk.erased(start, record_length);
+               if (tick_valid) {
+                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
+                               throw new ParseException(String.format("invalid checksum at 0x%x",
+                                                                      chunk.address + start), 0);
+               } else {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               }
+
+               tick = chunk.data16(start + 2);
+               a = chunk.data16(start + 4);
+               b = chunk.data16(start + 6);
+
+               data = null;
+       }
+
+       public AltosEepromTM (String line) {
+               tick_valid = false;
+               tick = 0;
+               a = 0;
+               b = 0;
+               data = null;
+               if (line == null) {
+                       cmd = AltosLib.AO_LOG_INVALID;
+                       data = "";
+               } else {
+                       try {
+                               String[] tokens = line.split("\\s+");
+
+                               if (tokens[0].length() == 1) {
+                                       if (tokens.length != 4) {
+                                               cmd = AltosLib.AO_LOG_INVALID;
+                                               data = line;
+                                       } else {
+                                               cmd = tokens[0].codePointAt(0);
+                                               tick = Integer.parseInt(tokens[1],16);
+                                               tick_valid = true;
+                                               a = Integer.parseInt(tokens[2],16);
+                                               b = Integer.parseInt(tokens[3],16);
+                                       }
+                               } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+                                       cmd = AltosLib.AO_LOG_CONFIG_VERSION;
+                                       data = tokens[2];
+                               } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+                                       cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+                                       cmd = AltosLib.AO_LOG_APOGEE_DELAY;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+                                       cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Callsign:")) {
+                                       cmd = AltosLib.AO_LOG_CALLSIGN;
+                                       data = tokens[1].replaceAll("\"","");
+                               } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+                                       cmd = AltosLib.AO_LOG_ACCEL_CAL;
+                                       a = Integer.parseInt(tokens[3]);
+                                       b = Integer.parseInt(tokens[5]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+                                       cmd = AltosLib.AO_LOG_RADIO_CAL;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
+                                       cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
+                                       a = Integer.parseInt(tokens[3]);
+                               } else if (tokens[0].equals("manufacturer")) {
+                                       cmd = AltosLib.AO_LOG_MANUFACTURER;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("product")) {
+                                       cmd = AltosLib.AO_LOG_PRODUCT;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("serial-number")) {
+                                       cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
+                                       a = Integer.parseInt(tokens[1]);
+                               } else if (tokens[0].equals("log-format")) {
+                                       cmd = AltosLib.AO_LOG_LOG_FORMAT;
+                                       a = Integer.parseInt(tokens[1]);
+                               } else if (tokens[0].equals("software-version")) {
+                                       cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
+                                       data = tokens[1];
+                               } else {
+                                       cmd = AltosLib.AO_LOG_INVALID;
+                                       data = line;
+                               }
+                       } catch (NumberFormatException ne) {
+v                              cmd = AltosLib.AO_LOG_INVALID;
+                               data = line;
+                       }
+               }
+       }
+
+       public AltosEepromTM(int in_cmd, int in_tick, int in_a, int in_b) {
+               tick_valid = true;
+               cmd = in_cmd;
+               tick = in_tick;
+               a = in_a;
+               b = in_b;
+       }
+}
index f23842f3d947c09b135bbfabef197111a1ab9a71..f7929a4ca032e22343c742f2a8f02e4e25fcfd3d 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.altoslib_1;
 
 import java.text.*;
 
-public class AltosGPS {
+public class AltosGPS implements Cloneable {
 
        public final static int MISSING = AltosRecord.MISSING;
 
@@ -216,6 +216,39 @@ public class AltosGPS {
                cc_gps_sat = null;
        }
 
+       public AltosGPS clone() {
+               AltosGPS        g = new AltosGPS();
+
+               g.nsat = nsat;
+               g.locked = locked;
+               g.connected = connected;
+               g.lat = lat;            g./* degrees (+N -S) */
+               g.lon = lon;            /* degrees (+E -W) */
+               g.alt = alt;            /* m */
+               g.year = year;
+               g.month = month;
+               g.day = day;
+               g.hour = hour;
+               g.minute = minute;
+               g.second = second;
+
+               g.ground_speed = ground_speed;  /* m/s */
+               g.course = course;              /* degrees */
+               g.climb_rate = climb_rate;      /* m/s */
+               g.hdop = hdop;          /* unitless? */
+               g.h_error = h_error;    /* m */
+               g.v_error = v_error;    /* m */
+
+               if (cc_gps_sat != null) {
+                       g.cc_gps_sat = new AltosGPSSat[cc_gps_sat.length];
+                       for (int i = 0; i < cc_gps_sat.length; i++) {
+                               g.cc_gps_sat[i] = new AltosGPSSat();
+                               g.cc_gps_sat[i].svid = cc_gps_sat[i].svid;
+                               g.cc_gps_sat[i].c_n0 = cc_gps_sat[i].c_n0;
+                       }
+               }
+       }
+
        public AltosGPS(AltosGPS old) {
                if (old != null) {
                        nsat = old.nsat;
index f1cf0ae9089173de180b9b0e39108379ed807a53..770c3c6c34ffabc288db27a04f322ac980a0104c 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.altoslib_1;
 
 import java.lang.Math;
 
-public class AltosGreatCircle {
+public class AltosGreatCircle implements Cloneable {
        public double   distance;
        public double   bearing;
        public double   range;
@@ -95,6 +95,16 @@ public class AltosGreatCircle {
                elevation = Math.atan2(height_diff, distance) * 180 / Math.PI;
        }
 
+       public AltosGreatCircle clone() {
+               AltosGreatCircle n = new AltosGreatCircle();
+
+               n.distance = distance;
+               n.bearing = bearing;
+               n.range = range;
+               n.elevation = elevation;
+               return n;
+       }
+
        public AltosGreatCircle (double start_lat, double start_lon,
                                 double end_lat, double end_lon) {
                this(start_lat, start_lon, 0, end_lat, end_lon, 0);
index 8f6731faa5a9bebbbbf1712d0502a4bf4d471042..46df35bf12c1428cfa7ac23f065dc0e4017ae052 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.altoslib_1;
 
-public class AltosIMU {
+public class AltosIMU implements Cloneable {
        public int              accel_x;
        public int              accel_y;
        public int              accel_z;
@@ -25,5 +25,17 @@ public class AltosIMU {
        public int              gyro_x;
        public int              gyro_y;
        public int              gyro_z;
+
+       public AltosIMU clone() {
+               AltosIMU        n = new AltosIMU();
+
+               n.accel_x = accel_x;
+               n.accel_y = accel_y;
+               n.accel_z = accel_z;
+
+               n.gyro_x = gyro_x;
+               n.gyro_y = gyro_y;
+               n.gyro_z = gyro_z;
+               return n;
 }
        
\ No newline at end of file
index b3bbd92fa9843acbcbdf633489e7c0c741357af2..cb6826f3412fd56fdca25c51c1710cdb9fef48c9 100644 (file)
 
 package org.altusmetrum.altoslib_1;
 
-public class AltosMag {
+public class AltosMag implements Cloneable {
        public int              x;
        public int              y;
        public int              z;
+
+       public AltosMag clone() {
+               AltosMag n = new AltosMag();
+
+               n.x = x;
+               n.y = y;
+               n.z = z;
+               return n;
+       }
 }
        
\ No newline at end of file
diff --git a/altoslib/AltosOrderedMetrumRecord.java b/altoslib/AltosOrderedMetrumRecord.java
new file mode 100644 (file)
index 0000000..02cdf1f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.text.ParseException;
+
+/*
+ * AltosRecords with an index field so they can be sorted by tick while preserving
+ * the original ordering for elements with matching ticks
+ */
+class AltosOrderedMetrumRecord extends AltosEepromMetrum implements Comparable<AltosOrderedMetrumRecord> {
+
+       public int      index;
+
+       public AltosOrderedMetrumRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
+               throws ParseException {
+               super(line);
+               if (prev_tick_valid) {
+                       tick |= (prev_tick & ~0xffff);
+                       if (tick < prev_tick) {
+                               if (prev_tick - tick > 0x8000)
+                                       tick += 0x10000;
+                       } else {
+                               if (tick - prev_tick > 0x8000)
+                                       tick -= 0x10000;
+                       }
+               }
+               index = in_index;
+       }
+
+       public int compareTo(AltosOrderedMetrumRecord o) {
+               int     tick_diff = tick - o.tick;
+               if (tick_diff != 0)
+                       return tick_diff;
+               return index - o.index;
+       }
+}
index 253f3804af06f93cb245a26cb8d4ccc2a2d97b44..dacd89b8ac56703e3b49806f300f5e1a4f04202a 100644 (file)
@@ -31,6 +31,8 @@ public class AltosRecordMini extends AltosRecord {
 
        public int      flight_accel;
        public int      flight_vel;
+       public int      flight_height;
+
        public int      flight_pres;
 
        static double adc(int raw) {
@@ -89,6 +91,7 @@ public class AltosRecordMini extends AltosRecord {
                
                flight_accel = old.flight_accel;
                flight_vel = old.flight_vel;
+               flight_height = old.flight_height;
                flight_pres = old.flight_pres;
        }
 
@@ -110,6 +113,7 @@ public class AltosRecordMini extends AltosRecord {
 
                flight_accel = 0;
                flight_vel = 0;
+               flight_height = 0;
                flight_pres = 0;
        }
 
diff --git a/altoslib/AltosRecordTM2.java b/altoslib/AltosRecordTM2.java
new file mode 100644 (file)
index 0000000..0cd54f2
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright © 2012 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 org.altusmetrum.altoslib_1;
+
+public class AltosRecordTM2 extends AltosRecord {
+
+       /* Sensor values */
+       public int      accel;
+       public int      pres;
+       public int      temp;
+       
+       public int      v_batt;
+       public int      sense_a;
+       public int      sense_m;
+
+       public int      ground_accel;
+       public int      ground_pres;
+       public int      accel_plus_g;
+       public int      accel_minus_g;
+
+       public int      flight_accel;
+       public int      flight_vel;
+       public int      flight_pres;
+
+       static double adc(int raw) {
+               return raw / 4095.0;
+       }
+
+       public double pressure() {
+               if (pres != MISSING)
+                       return pres;
+               return MISSING;
+       }
+
+       public double ground_pressure() {
+               if (ground_pres != MISSING)
+                       return ground_pres;
+               return MISSING;
+       }
+
+       public double battery_voltage() {
+               if (v_batt != MISSING)
+                       return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0;
+               return MISSING;
+       }
+
+       static double pyro(int raw) {
+               if (raw != MISSING)
+                       return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0;
+               return MISSING;
+       }
+
+       public double main_voltage() {
+               return pyro(sense_m);
+       }
+
+       public double drogue_voltage() {
+               return pyro(sense_a);
+       }
+
+       public double temperature() {
+               if (temp != MISSING)
+                       return temp / 100.0;
+               return MISSING;
+       }
+       
+       double accel_counts_per_mss() {
+               double  counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2;
+
+               return counts_per_g / 9.80665;
+       }
+
+       public double acceleration() {
+               if (ground_accel == MISSING || accel == MISSING)
+                       return MISSING;
+
+               if (accel_minus_g == MISSING || accel_plus_g == MISSING)
+                       return MISSING;
+
+               return (ground_accel - accel) / accel_counts_per_mss();
+       }
+
+       public void copy (AltosRecordTM2 old) {
+               super.copy(old);
+
+               accel = old.accel;
+               pres = old.pres;
+               temp = old.temp;
+
+               v_batt = old.v_batt;
+               sense_a = old.sense_a;
+               sense_m = old.sense_m;
+
+               ground_accel = old.ground_accel;
+               ground_pres = old.ground_pres;
+               accel_plus_g = old.accel_plus_g;
+               accel_minus_g = old.accel_minus_g;
+               
+               flight_accel = old.flight_accel;
+               flight_vel = old.flight_vel;
+               flight_pres = old.flight_pres;
+       }
+
+       public AltosRecordTM2 clone() {
+               return new AltosRecordTM2(this);
+       }
+
+       void make_missing() {
+
+               accel = MISSING;
+               pres = MISSING;
+               temp = MISSING;
+
+               v_batt = MISSING;
+               sense_a = MISSING;
+               sense_m = MISSING;
+
+               ground_accel = MISSING;
+               ground_pres = MISSING;
+               accel_plus_g = MISSING;
+               accel_minus_g = MISSING;
+
+               flight_accel = 0;
+               flight_vel = 0;
+               flight_pres = 0;
+       }
+
+       public AltosRecordTM2(AltosRecord old) {
+               super.copy(old);
+               make_missing();
+       }
+
+       public AltosRecordTM2(AltosRecordTM2 old) {
+               copy(old);
+       }
+
+       public AltosRecordTM2() {
+               super();
+               make_missing();
+       }
+}
diff --git a/altoslib/AltosSelfFlash.java b/altoslib/AltosSelfFlash.java
new file mode 100644 (file)
index 0000000..07917d5
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.io.*;
+
+public class AltosSelfFlash {
+       File                    file;
+       FileInputStream         input;
+       AltosHexfile            image;
+       AltosLink               link;
+       boolean                 aborted;
+       AltosFlashListener      listener;
+       byte[]                  read_block, write_block;
+
+       void action(String s, int percent) {
+               if (listener != null && !aborted)
+                       listener.position(s, percent);
+       }
+
+       void action(int part, int total) {
+               int percent = 100 * part / total;
+               action(String.format("%d/%d (%d%%)",
+                                    part, total, percent),
+                      percent);
+       }
+
+       void read_block(long addr) {
+               link.printf("R %x\n", addr);
+               
+       }
+
+       void read_memory(long addr, int len) {
+       }
+               
+       void write_memory(long addr, byte[] data, int start, int len) {
+               
+       }
+
+       void reboot() {
+       }
+
+       public void flash() {
+               try {
+                       int remain = image.data.length;
+                       long flash_addr = image.address;
+                       int image_start = 0;
+
+                       action("start", 0);
+                       action(0, image.data.length);
+                       while (remain > 0 && !aborted) {
+                               int this_time = remain;
+                               if (this_time > 0x100)
+                                       this_time = 0x100;
+
+                               if (link != null) {
+                                       /* write the data */
+                                       write_memory(flash_addr, image.data, image_start, this_time);
+
+                                       byte[] check = read_memory(flash_addr, this_time);
+                                       for (int i = 0; i < this_time; i++)
+                                               if (check[i] != image.data[image_start + i])
+                                                       throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
+                                                                                           image.address + image_start + i,
+                                                                                           check[i], image.data[image_start + i]));
+                               } else {
+                                       Thread.sleep(100);
+                               }
+
+                               remain -= this_time;
+                               flash_addr += this_time;
+                               image_start += this_time;
+
+                               action(image.data.length - remain, image.data.length);
+                       }
+                       if (!aborted) {
+                               action("done", 100);
+                               if (link != null) {
+                                       reboot();
+                               }
+                       }
+                       if (link != null)
+                               link.close();
+               } catch (IOException ie) {
+                       action(ie.getMessage(), -1);
+                       abort();
+               } catch (InterruptedException ie) {
+                       abort();
+               }
+       }
+
+       public void close() {
+               if (link != null)
+                       link.close();
+       }
+
+       synchronized public void abort() {
+               aborted = true;
+               close();
+       }
+
+       public boolean check_rom_config() {
+               if (link == null)
+                       return true;
+               if (rom_config == null)
+                       rom_config = debug.romconfig();
+               return rom_config != null && rom_config.valid();
+       }
+
+       public void set_romconfig (AltosRomconfig romconfig) {
+               rom_config = romconfig;
+       }
+
+       public AltosRomconfig romconfig() {
+               if (!check_rom_config())
+                       return null;
+               return rom_config;
+       }
+
+       public AltosFlash(File file, AltosLink link, AltosFlashListener listener)
+               throws IOException, FileNotFoundException, InterruptedException {
+               this.file = file;
+               this.link = link;
+               this.listener = listener;
+               this.read_block = new byte[256];
+               this.write_block = new byte[256];
+               input = new FileInputStream(file);
+               image = new AltosHexfile(input);
+               if (link != null) {
+                       debug.close();
+                       throw new IOException("Debug port not connected");
+               }
+       }
+}
\ No newline at end of file
diff --git a/altoslib/AltosSensorMetrum.java b/altoslib/AltosSensorMetrum.java
new file mode 100644 (file)
index 0000000..686c78a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+import java.util.concurrent.TimeoutException;
+
+class AltosSensorMetrum {
+       int             tick;
+       int             sense_a;
+       int             sense_m;
+       int             v_batt;
+
+       public AltosSensorMetrum(AltosLink link) throws InterruptedException, TimeoutException {
+               String[] items = link.adc();
+               for (int i = 0; i < items.length;) {
+                       if (items[i].equals("tick:")) {
+                               tick = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("drogue:")) {
+                               sense_a = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("main:")) {
+                               sense_m = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("batt:")) {
+                               v_batt = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       i++;
+               }
+       }
+}
+
index e0d9bb1fc394dc1cb42b495bc03e755d135968bb..b40b744fd7b5ae13894095aa2bf278758c309d62 100644 (file)
@@ -21,7 +21,7 @@
 
 package org.altusmetrum.altoslib_1;
 
-public class AltosState {
+public class AltosState implements Cloneable {
        public AltosRecord data;
 
        /* derived data */
@@ -35,24 +35,29 @@ public class AltosState {
        public int      state;
        public boolean  landed;
        public boolean  ascent; /* going up? */
-       public boolean boost;   /* under power */
+       public boolean  boost;  /* under power */
 
        public double   ground_altitude;
        public double   altitude;
        public double   height;
        public double   pressure;
        public double   acceleration;
-       public double   battery;
+       public double   battery_voltage;
+       public double   pyro_voltage;
        public double   temperature;
-       public double   main_sense;
-       public double   drogue_sense;
-       public double   accel_speed;
-       public double   baro_speed;
+       public double   apogee_voltage;
+       public double   main_voltage;
+       public double   speed;
+
+       public double   prev_height;
+       public double   prev_speed;
+       public double   prev_acceleration;
 
        public double   max_height;
        public double   max_acceleration;
-       public double   max_accel_speed;
-       public double   max_baro_speed;
+       public double   max_speed;
+
+       public double   kalman_height, kalman_speed, kalman_acceleration;
 
        public AltosGPS gps;
        public int gps_sequence;
@@ -63,10 +68,11 @@ public class AltosState {
        public static final int MIN_PAD_SAMPLES = 10;
 
        public int      npad;
-       public int      ngps;
        public int      gps_waiting;
        public boolean  gps_ready;
 
+       public int      ngps;
+
        public AltosGreatCircle from_pad;
        public double   elevation;      /* from pad */
        public double   range;          /* total distance */
@@ -78,80 +84,434 @@ public class AltosState {
        public int      speak_tick;
        public double   speak_altitude;
 
+       public String   callsign;
+       public double   accel_plus_g;
+       public double   accel_minus_g;
+       public double   accel;
+       public double   ground_accel;
+
+       public int      log_format;
+       public int      serial;
+
+       public AltosMs5607      baro;
+
        public double speed() {
-               if (ascent)
-                       return accel_speed;
-               else
-                       return baro_speed;
+               return speed;
        }
 
        public double max_speed() {
-               if (max_accel_speed != 0)
-                       return max_accel_speed;
-               return max_baro_speed;
+               return max_speed;
+       }
+
+       public void set_npad(int npad) {
+               this.npad = npad;
+               gps_waiting = MIN_PAD_SAMPLES - npad;
+               if (this.gps_waiting < 0)
+                       gps_waiting = 0;
+               gps_ready = gps_waiting == 0;
+       }
+
+       public void init() {
+               data = new AltosRecord();
+
+               report_time = System.currentTimeMillis();
+               time = AltosRecord.MISSING;
+               time_change = AltosRecord.MISSING;
+               tick = AltosRecord.MISSING;
+               state = AltosLib.ao_flight_invalid;
+               landed = false;
+               boost = false;
+
+               ground_altitude = AltosRecord.MISSING;
+               altitude = AltosRecord.MISSING;
+               height = AltosRecord.MISSING;
+               pressure = AltosRecord.MISSING;
+               acceleration = AltosRecord.MISSING;
+               temperature = AltosRecord.MISSING;
+
+               prev_height = AltosRecord.MISSING;
+               prev_speed = AltosRecord.MISSING;
+               prev_acceleration = AltosRecord.MISSING;
+
+               battery_voltage = AltosRecord.MISSING;
+               pyro_voltage = AltosRecord.MISSING;
+               apogee_voltage = AltosRecord.MISSING;
+               main_voltage = AltosRecord.MISSING;
+
+
+               accel_speed = AltosRecord.MISSING;
+               baro_speed = AltosRecord.MISSING;
+
+               kalman_height = AltosRecord.MISSING;
+               kalman_speed = AltosRecord.MISSING;
+               kalman_acceleration = AltosRecord.MISSING;
+
+               max_baro_speed = 0;
+               max_accel_speed = 0;
+               max_height = 0;
+               max_acceleration = 0;
+
+               gps = null;
+               gps_sequence = 0;
+
+               imu = null;
+               mag = null;
+
+               set_npad(0);
+               ngps = 0;
+
+               from_pad = null;
+               elevation = AltosRecord.MISSING;
+               range = AltosRecord.MISSING;
+               gps_height = AltosRecord.MISSING;
+
+               pat_lat = AltosRecord.MISSING;
+               pad_lon = AltosRecord.MISSING;
+               pad_alt = AltosRecord.MISSING;
+
+               speak_tick = AltosRecord.MISSING;
+               speak_altitude = AltosRecord.MISSING;
+
+               callsign = null;
+
+               accel_plus_g = AltosRecord.MISSING;
+               accel_minus_g = AltosRecord.MISSING;
+               log_format = AltosRecord.MISSING;
+               serial = AltosRecord.MISSING;
+
+               baro = null;
+       }
+
+       void copy(AltosState old) {
+
+               data = null;
+
+               if (old == null) {
+                       init();
+                       return;
+               }
+
+               report_time = old.report_time;
+               time = old.time;
+               time_change = old.time_change;
+               tick = old.tick;
+
+               state = old.state;
+               landed = old.landed;
+               ascent = old.ascent;
+               boost = old.boost;
+
+               ground_altitude = old.ground_altitude;
+               altitude = old.altitude;
+               height = old.height;
+               pressure = old.pressure;
+               acceleration = old.acceleration;
+               battery_voltage = old.battery_voltage;
+               pyro_voltage = old.pyro_voltage;
+               temperature = old.temperature;
+               apogee_voltage = old.apogee_voltage;
+               main_voltage = old.main_voltage;
+               accel_speed = old.accel_speed;
+               baro_speed = old.baro_speed;
+
+               prev_height = old.height;
+               prev_speed = old.speed;
+               prev_acceleration = old.acceleration;
+
+               max_height = old.max_height;
+               max_acceleration = old.max_acceleration;
+               max_accel_speed = old.max_accel_speed;
+               max_baro_speed = old.max_baro_speed;
+
+               kalman_height = old.kalman_height;
+               kalman_speed = old.kalman_speed;
+               kalman_acceleration = old.kalman_acceleration;
+
+               if (old.gps != null)
+                       gps = old.gps.clone();
+               else
+                       gps = null;
+               gps_sequence = old.gps_sequence;
+
+               if (old.imu != null)
+                       imu = old.imu.clone();
+               else
+                       imu = null;
+
+               if (old.mag != null)
+                       mag = old.mag.clone();
+               else
+                       mag = null;
+
+               npad = old.npad;
+               gps_waiting = old.gps_waiting;
+               gps_ready = old.gps_ready;
+               ngps = old.ngps;
+
+               if (old.from_pad != null)
+                       from_pad = old.from_pad.clone();
+               else
+                       from_pad = null;
+
+               elevation = old.elevation;
+               range = old.range;
+
+               gps_height = old.gps_height;
+               pad_lat = old.pad_lat;
+               pad_lon = old.pad_lon;
+               pad_alt = old.pad_alt;
+
+               speak_tick = old.speak_tick;
+               speak_altitude = old.speak_altitude;
+
+               callsign = old.callsign;
+
+               accel_plus_g = old.accel_plus_g;
+               accel_minus_g = old.accel_minus_g;
+               log_format = old.log_format;
+               serial = old.serial;
+
+               baro = old.baro;
+       }
+
+       double ground_altitude() {
+               
+       }
+
+       double altitude() {
+               if (altitude != AltosRecord.MISSING)
+                       return altitude;
+               if (gps != null)
+                       return gps.alt;
+               return AltosRecord.MISSING;
+       }
+
+       void update_vertical_pos() {
+
+               double  alt = altitude();
+               if (state == AltosLib.ao_flight_pad) {
+                       
+               }
+
+               if (kalman_height != AltosRecord.MISSING)
+                       height = kalman_height;
+               else if (altitude != AltosRecord.MISSING && ground_altitude != AltosRecord.MISSING)
+                       height = altitude - ground_altitude;
+               else
+                       height = AltosRecord.MISSING;
+
+               update_speed();
+       }
+
+       double motion_filter_value() {
+               return 1/ Math.exp(time_change/10.0);
+       }
+
+       void update_speed() {
+               if (kalman_speed != AltosRecord.MISSING)
+                       speed = kalman_speed;
+               else if (state != AltosLib.ao_flight_invalid &&
+                        time_change != AltosRecord.MISSING)
+               {
+                       if (ascent && acceleration != AltosRecord.MISSING)
+                       {
+                               if (prev_speed == AltosRecord.MISSING)
+                                       speed = acceleration * time_change;
+                               else
+                                       speed = prev_speed + acceleration * time_change;
+                       }
+                       else if (height != AltosRecord.MISSING &&
+                                prev_height != AltosRecord.MISSING &&
+                                time_change != 0)
+                       {
+                               double  new_speed = (height - prev_height) / time_change;
+
+                               if (prev_speed == AltosRecord.MISSING)
+                                       speed = new_speed;
+                               else {
+                                       double  filter = motion_filter_value();
+
+                                       speed = prev_speed * filter + new_speed * (1-filter);
+                               }
+                       }
+               }
+               if (acceleration == AltosRecord.MISSING) {
+                       if (prev_speed != AltosRecord.MISSING && time_change != 0) {
+                               double  new_acceleration = (speed - prev_speed) / time_change;
+
+                               if (prev_acceleration == AltosRecord.MISSING)
+                                       acceleration = new_acceleration;
+                               else {
+                                       double filter = motion_filter_value();
+
+                                       acceleration = prev_acceleration * filter + new_acceleration * (1-filter);
+                               }
+                       }
+               }
+       }
+       
+       void update_accel() {
+               if (accel == AltosRecord.MISSING)
+                       return;
+               if (ground_Accel == AltosRecord.MISSING)
+                       return;
+               if (accel_plus_g == AltosRecord.MISSING)
+                       return;
+               if (accel_minus_g == AltosRecord.MISSING)
+                       return;
+
+               double counts_per_g = (accel_minus_g - accel_plus_g) / 2.0;
+               double counts_per_mss = counts_per_g / 9.80665;
+
+               acceleration = (ground_accel - accel) / counts_per_mss;
+               update_speed();
+       }
+
+       public void set_tick(int tick) {
+               if (tick != AltosRecord.MISSING) {
+                       if (this.tick != AltosRecord.MISSING) {
+                               while (tick < this.tick)
+                                       tick += 65536;
+                               time_change = (tick - this.tick) / 100.0;
+                       } else
+                               time_change = 0;
+                       this.tick = tick;
+                       update_time();
+               }
+       }
+
+       public void set_state(int state) {
+               if (state != AltosLib.ao_flight_invalid) {
+                       this.state = state;
+                       ascent = (AltosLib.ao_flight_boost <= state &&
+                                 state <= AltosLib.ao_flight_coast);
+                       boost = (AltosLib.ao_flight_boost == state);
+               }
+
+       }
+
+       public void set_altitude(double altitude) {
+               if (altitude != AltosRecord.MISSING) {
+                       this.altitude = altitude;
+                       update_vertical_pos();
+               }
+       }
+
+       public void set_ground_altitude(double ground_altitude) {
+               if (ground_altitude != AltosRecord.MISSING) {
+                       this.ground_altitude = ground_altitude;
+                       update_vertical_pos();
+               }
+       }
+
+       public void set_gps(AltosGPS gps, int sequence) {
+               if (gps != null) {
+                       this.gps = gps.clone();
+                       gps_sequence = sequence;
+                       update_vertical_pos();
+               }
+       }
+
+       public void set_kalman(double height, double speed, double acceleration) {
+               if (height != AltosRecord.MISSING) {
+                       kalman_height = height;
+                       kalman_speed = speed;
+                       kalman_acceleration = acceleration;
+                       baro_speed = accel_speed = speed;
+                       update_vertical_pos();
+               }
+       }
+
+       public void set_pressure(double pressure) {
+               if (pressure != AltosRecord.MISSING) {
+                       this.pressure = pressure;
+                       set_altitude(AltosConvert.pressure_to_altitude(pressure));
+               }
+       }
+
+       public void set_accel_g(double accel_plus_g, double accel_minus_g) {
+               if (accel_plus_g != AltosRecord.MISSING) {
+                       this.accel_plus_g = accel_plus_g;
+                       this.accel_minus_g = accel_minus_g;
+                       update_accel();
+               }
+       }
+       public void set_ground_accel(double ground_accel) {
+               if (ground_accel != AltosRecord.MISSING) {
+                       this.ground_accel = ground_accel;
+                       update_accel();
+               }
+       }
+
+       public void set_accel(double accel) {
+               if (accel != AltosRecord.MISSING) {
+                       this.accel = accel;
+               }
+               update_accel();
+       }
+
+       public void set_temperature(double temperature) {
+               if (temperature != AltosRecord.MISSING)
+                       this.temperature = temperature;
+       }
+
+       public void set_battery_voltage(double battery_voltage) {
+               if (battery_voltage != AltosRecord.MISSING)
+                       this.battery_voltage = battery_voltage;
+       }
+
+       public void set_pyro_voltage(double pyro_voltage) {
+               if (pyro_voltage != AltosRecord.MISSING)
+                       this.pyro_voltage = pyro_voltage;
+       }
+
+       public void set_apogee_voltage(double apogee_voltage) {
+               if (apogee_voltage != AltosRecord.MISSING)
+                       this.apogee_voltage = apogee_voltage;
+       }
+
+       public void set_main_voltage(double main_voltage) {
+               if (main_voltage != AltosRecord.MISSING)
+                       this.main_voltage = main_voltage;
        }
 
        public void init (AltosRecord cur, AltosState prev_state) {
+
+               if (cur == null)
+                       cur = new AltosRecord();
+
                data = cur;
 
                /* Discard previous state if it was for a different board */
-               if (prev_state != null && prev_state.data.serial != data.serial)
+               if (prev_state != null && prev_state.serial != cur.serial)
                        prev_state = null;
-               ground_altitude = data.ground_altitude();
 
-               altitude = data.altitude();
-               if (altitude == AltosRecord.MISSING && data.gps != null)
-                       altitude = data.gps.alt;
+               copy(prev_state);
 
-               height = AltosRecord.MISSING;
-               if (data.kalman_height != AltosRecord.MISSING)
-                       height = data.kalman_height;
-               else {
-                       if (altitude != AltosRecord.MISSING && ground_altitude != AltosRecord.MISSING) {
-                               double  cur_height = altitude - ground_altitude;
-                               if (prev_state == null || prev_state.height == AltosRecord.MISSING)
-                                       height = cur_height;
-                               else
-                                       height = (prev_state.height * 15 + cur_height) / 16.0;
-                       }
-               }
+               set_ground_altitude(data.ground_altitude());
+               set_altitude(data.altitude());
+
+               set_kalman(data.kalman_height, data.kalman_speed, data.kalman_acceleration);
 
                report_time = System.currentTimeMillis();
 
-               if (data.kalman_acceleration != AltosRecord.MISSING)
-                       acceleration = data.kalman_acceleration;
-               else
-                       acceleration = data.acceleration();
-               temperature = data.temperature();
-               drogue_sense = data.drogue_voltage();
-               main_sense = data.main_voltage();
-               battery = data.battery_voltage();
-               pressure = data.pressure();
-               tick = data.tick;
-               state = data.state;
+               set_temperature(data.temperature());
+               set_apogee_voltage(data.drogue_voltage());
+               set_main_voltage(data.main_voltage());
+               set_battery_voltage(data.battery_voltage());
 
-               if (prev_state != null) {
+               set_pressure(data.pressure());
 
-                       /* Preserve any existing gps data */
-                       npad = prev_state.npad;
-                       ngps = prev_state.ngps;
-                       gps = prev_state.gps;
-                       gps_sequence = prev_state.gps_sequence;
-                       pad_lat = prev_state.pad_lat;
-                       pad_lon = prev_state.pad_lon;
-                       pad_alt = prev_state.pad_alt;
-                       max_height = prev_state.max_height;
-                       max_acceleration = prev_state.max_acceleration;
-                       max_accel_speed = prev_state.max_accel_speed;
-                       max_baro_speed = prev_state.max_baro_speed;
-                       imu = prev_state.imu;
-                       mag = prev_state.mag;
-
-                       /* make sure the clock is monotonic */
-                       while (tick < prev_state.tick)
-                               tick += 65536;
-
-                       time_change = (tick - prev_state.tick) / 100.0;
+               set_tick(data.tick);
+               set_state(data.state);
+
+               set_accel_g (data.accel_minus_g, data.accel_plus_g);
+               set_ground_accel(data.ground_accel);
+               set_accel (data.accel);
+
+               set_gps(data.gps, data.gps_sequence);
+
+               if (prev_state != null) {
 
                        if (data.kalman_speed != AltosRecord.MISSING) {
                                baro_speed = accel_speed = data.kalman_speed;
@@ -200,6 +560,12 @@ public class AltosState {
                        max_height = 0;
                        max_acceleration = 0;
                        time_change = 0;
+                       baro = new AltosMs5607();
+                       callsign = "";
+                       accel_plus_g = AltosRecord.MISSING;
+                       accel_minus_g = AltosRecord.MISSING;
+                       log_format = AltosRecord.MISSING;
+                       serial = AltosRecord.MISSING;
                }
 
                time = tick / 100.0;
@@ -208,9 +574,9 @@ public class AltosState {
 
                        /* Track consecutive 'good' gps reports, waiting for 10 of them */
                        if (data.gps != null && data.gps.locked && data.gps.nsat >= 4)
-                               npad++;
+                               set_npad(npad+1);
                        else
-                               npad = 0;
+                               set_npad(0);
 
                        /* Average GPS data while on the pad */
                        if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) {
@@ -233,16 +599,6 @@ public class AltosState {
 
                gps_sequence = data.gps_sequence;
 
-               gps_waiting = MIN_PAD_SAMPLES - npad;
-               if (gps_waiting < 0)
-                       gps_waiting = 0;
-
-               gps_ready = gps_waiting == 0;
-
-               ascent = (AltosLib.ao_flight_boost <= state &&
-                         state <= AltosLib.ao_flight_coast);
-               boost = (AltosLib.ao_flight_boost == state);
-
                /* Only look at accelerometer data under boost */
                if (boost && acceleration != AltosRecord.MISSING && (max_acceleration == AltosRecord.MISSING || acceleration > max_acceleration))
                        max_acceleration = acceleration;
@@ -270,6 +626,11 @@ public class AltosState {
                }
        }
 
+       public AltosState clone() {
+               AltosState s = new AltosState(data, this);
+               return s;
+       }
+
        public AltosState(AltosRecord cur) {
                init(cur, null);
        }
diff --git a/altoslib/AltosStateUpdate.java b/altoslib/AltosStateUpdate.java
new file mode 100644 (file)
index 0000000..50460e2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright © 2013 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 org.altusmetrum.altoslib_1;
+
+public interface AltosStateUpdate {
+       public void     update_state(AltosState state);
+}
\ No newline at end of file
index fdc3c88eb6d25b773c1dbad62a6fba17564f5ef9..a744e61a185ed7c384eb812c023e0d20694a1740 100644 (file)
@@ -44,6 +44,7 @@ public abstract class AltosTelemetryRecord {
        final static int packet_type_companion = 0x07;
        final static int packet_type_MM_sensor = 0x08;
        final static int packet_type_MM_data = 0x09;
+       final static int packet_type_Mini = 0x10;
        
        static AltosTelemetryRecord parse_hex(String hex)  throws ParseException, AltosCRCException {
                AltosTelemetryRecord    r;
diff --git a/altoslib/AltosTelemetryRecordMetrumData.java b/altoslib/AltosTelemetryRecordMetrumData.java
new file mode 100644 (file)
index 0000000..70179b2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 org.altusmetrum.altoslib_1;
+
+
+public class AltosTelemetryRecordMetrumData extends AltosTelemetryRecordRaw {
+
+       int     ground_pres;
+       int     ground_accel;
+       int     accel_plus_g;
+       int     accel_minus_g;
+
+       public AltosTelemetryRecordMetrumData(int[] in_bytes, int rssi) {
+               super(in_bytes, rssi);
+
+               ground_pres = int32(8);
+               ground_accel = int16(12);
+               accel_plus_g = int16(14);
+               accel_minus_g = int16(16);
+       }
+
+       public AltosRecord update_state(AltosRecord previous) {
+               AltosRecord     n = super.update_state(previous);
+
+               AltosRecordTM2  next;
+               if (!(n instanceof AltosRecordTM2)) {
+                       next = new AltosRecordTM2(n);
+               } else {
+                       next = (AltosRecordTM2) n;
+               }
+
+               next.ground_accel = ground_accel;
+               next.ground_pres = ground_pres;
+               next.accel_plus_g = accel_plus_g;
+               next.accel_minus_g = accel_minus_g;
+
+               return next;
+       }
+}
diff --git a/altoslib/AltosTelemetryRecordMetrumSensor.java b/altoslib/AltosTelemetryRecordMetrumSensor.java
new file mode 100644 (file)
index 0000000..e41242c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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 org.altusmetrum.altoslib_1;
+
+
+public class AltosTelemetryRecordMetrumSensor extends AltosTelemetryRecordRaw {
+       int     state;
+
+       int     accel;
+       int     pres;
+       int     temp;
+
+       int     acceleration;
+       int     speed;
+       int     height;
+
+       int     v_batt;
+       int     sense_a;
+       int     sense_m;
+
+       public AltosTelemetryRecordMetrumSensor(int[] in_bytes, int rssi) {
+               super(in_bytes, rssi);
+
+               state         = int8(5);
+               accel         = int16(6);
+               pres          = int32(8);
+               temp          = int16(12);
+
+               acceleration  = int16(14);
+               speed         = int16(16);
+               height        = int16(18);
+
+               v_batt        = int16(20);
+               sense_a       = int16(22);
+               sense_m       = int16(24);
+       }
+
+       public AltosRecord update_state(AltosRecord previous) {
+               AltosRecord     n = super.update_state(previous);
+
+               AltosRecordTM2  next;
+               if (!(n instanceof AltosRecordTM2)) {
+                       next = new AltosRecordTM2(n);
+               } else {
+                       next = (AltosRecordTM2) n;
+               }
+
+               next.state = state;
+
+               next.accel = accel;
+               next.pres = pres;
+               next.temp = temp;
+
+               next.kalman_acceleration = acceleration / 16.0;
+               next.kalman_speed = speed / 16.0;
+               next.kalman_height = height;
+
+               next.v_batt = v_batt;
+               next.sense_a = sense_a;
+               next.sense_m = sense_m;
+
+               next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;;
+
+               return next;
+       }
+}
diff --git a/altoslib/AltosTelemetryRecordMini.java b/altoslib/AltosTelemetryRecordMini.java
new file mode 100644 (file)
index 0000000..75a66c1
--- /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 org.altusmetrum.altoslib_1;
+
+
+public class AltosTelemetryRecordMini extends AltosTelemetryRecordRaw {
+       int     state;
+
+       int     accel;
+       int     pres;
+       int     temp;
+
+       int     v_batt;
+       int     sense_a;
+       int     sense_m;
+
+       int     acceleration;
+       int     speed;
+       int     height;
+
+       int     ground_pres;
+
+       public AltosTelemetryRecordMini(int[] in_bytes, int rssi) {
+               super(in_bytes, rssi);
+
+               state         = int8(5);
+               v_batt        = int16(6);
+               sense_a       = int16(8);
+               sense_m       = int16(10);
+
+               pres          = int32(12);
+               temp          = int16(16);
+
+               acceleration  = int16(18);
+               speed        = int16(20);
+               height        = int16(22);
+
+               ground_pres   = int32(24);
+       }
+
+       public AltosRecord update_state(AltosRecord previous) {
+               AltosRecord     n = super.update_state(previous);
+
+               AltosRecordMini next;
+               if (!(n instanceof AltosRecordMini)) {
+                       next = new AltosRecordMini(n);
+               } else {
+                       next = (AltosRecordMini) n;
+               }
+
+               next.pres = pres;
+               next.temp = temp;
+
+               next.sense_a = sense_a;
+               next.sense_m = sense_m;
+
+               next.ground_pres = ground_pres;
+               next.flight_accel = acceleration;
+               next.flight_vel = speed;
+               next.flight_height = height;
+               next.flight_pres = pres;
+
+               next.seen |= AltosRecord.seen_sensor;
+
+               return next;
+       }
+}
index 8c1cf2add83c615b6899d4a147a199ed797b559e..8a41b90c9c8b5136269440fc4298efc189b500bb 100644 (file)
@@ -17,7 +17,10 @@ altoslib_JAVA = \
        AltosConvert.java \
        AltosCRCException.java \
        AltosDebug.java \
+       AltosEeprom.java \
        AltosEepromChunk.java \
+       AltosEepromFile.java \
+       AltosEepromHeader.java \
        AltosEepromIterable.java \
        AltosEepromLog.java \
        AltosEepromMega.java \
@@ -26,6 +29,7 @@ altoslib_JAVA = \
        AltosEepromTeleScience.java \
        AltosEepromMini.java \
        AltosEepromMiniIterable.java \
+       AltosEepromOldIterable.java \
        AltosFile.java \
        AltosFlash.java \
        AltosFlashListener.java \
@@ -65,6 +69,7 @@ altoslib_JAVA = \
        AltosSensorMM.java \
        AltosSensorTM.java \
        AltosState.java \
+       AltosStateUpdate.java \
        AltosTelemetry.java \
        AltosTelemetryIterable.java \
        AltosTelemetryMap.java \
@@ -80,6 +85,7 @@ altoslib_JAVA = \
        AltosTelemetryRecordSensor.java \
        AltosTelemetryRecordMegaSensor.java \
        AltosTelemetryRecordMegaData.java \
+       AltosTelemetryRecordMini.java \
        AltosUnitsListener.java \
        AltosMs5607.java \
        AltosIMU.java \