Add Mini logging format. Use in EasyMini lpc
authorKeith Packard <keithp@keithp.com>
Mon, 20 May 2013 06:07:54 +0000 (23:07 -0700)
committerKeith Packard <keithp@keithp.com>
Mon, 20 May 2013 06:07:54 +0000 (23:07 -0700)
This is a 16-byte record that includes all of the sensor data in each
sensor record, along with records for flight state changes.

Signed-off-by: Keith Packard <keithp@keithp.com>
14 files changed:
altoslib/AltosEepromMini.java [new file with mode: 0644]
altoslib/AltosEepromMiniIterable.java [new file with mode: 0644]
altoslib/AltosLib.java
altoslib/AltosOrderedMiniRecord.java [new file with mode: 0644]
altoslib/AltosRecordMini.java [new file with mode: 0644]
altoslib/Makefile.am
altosui/AltosDataChooser.java
altosui/AltosEepromDownload.java
altosui/AltosLanded.java
altosui/AltosUI.java
src/core/ao_log.h
src/core/ao_log_mini.c [new file with mode: 0644]
src/easymini-v0.1/Makefile
src/easymini-v0.1/ao_pins.h

diff --git a/altoslib/AltosEepromMini.java b/altoslib/AltosEepromMini.java
new file mode 100644 (file)
index 0000000..215cd3d
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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;
+
+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 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 data24(int i) {
+               return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 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_pres() { return data32(4); }
+
+       /* AO_LOG_STATE elements */
+       public int state() { return data16(0); }
+       public int reason() { return data16(2); }
+
+       /* AO_LOG_SENSOR elements */
+       public int pres() { return data24(0); }
+       public int temp() { return data24(3); }
+       public int sense_a() { return data16(6); }
+       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;
+               }
+
+               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 (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 AltosEepromMini(int in_cmd, int in_tick) {
+               cmd = in_cmd;
+               tick = in_tick;
+               valid = true;
+       }
+}
diff --git a/altoslib/AltosEepromMiniIterable.java b/altoslib/AltosEepromMiniIterable.java
new file mode 100644 (file)
index 0000000..1f22118
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * 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 AltosEepromMiniIterable extends AltosRecordIterable {
+
+       static final int        seen_flight = 1;
+       static final int        seen_sensor = 2;
+
+       static final int        seen_basic = seen_flight|seen_sensor;
+
+       boolean                 has_accel;
+       boolean                 has_gps;
+       boolean                 has_ignite;
+
+       AltosEepromMini flight_record;
+
+       TreeSet<AltosOrderedMiniRecord> records;
+
+       AltosMs5607             baro;
+
+       LinkedList<AltosRecord> list;
+
+       class EepromState {
+               int     seen;
+               int     n_pad_samples;
+               double  ground_pres;
+               int     boost_tick;
+               int     sensor_tick;
+
+               EepromState() {
+                       seen = 0;
+                       n_pad_samples = 0;
+                       ground_pres = 0.0;
+               }
+       }
+
+       void update_state(AltosRecordMini state, AltosEepromMini record, EepromState eeprom) {
+               state.tick = record.tick;
+               switch (record.cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       eeprom.seen |= seen_flight;
+                       state.ground_pres = record.ground_pres();
+                       state.flight_pres = state.ground_pres;
+                       state.flight = record.data16(0);
+                       eeprom.boost_tick = record.tick;
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       baro.set(record.pres(), record.temp());
+                       state.pres = baro.pa;
+                       state.temp = baro.cc;
+                       state.sense_m = record.sense_m();
+                       state.sense_a = record.sense_a();
+                       state.v_batt = record.v_batt();
+                       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;
+                       }
+                       if ((eeprom.seen & seen_sensor) == 0)
+                               eeprom.sensor_tick = record.tick - 1;
+                       eeprom.seen |= seen_sensor;
+                       eeprom.sensor_tick = record.tick;
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.state = record.state();
+                       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_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<AltosOrderedMiniRecord> iterator = records.iterator();
+               AltosOrderedMiniRecord          record = null;
+               AltosRecordMini                 state = new AltosRecordMini();
+               //boolean                       last_reported = false;
+               EepromState                     eeprom = new EepromState();
+
+               state.state = AltosLib.ao_flight_pad;
+
+               /* Pull in static data from the flight records */
+               if (flight_record != null)
+                       update_state(state, flight_record, eeprom);
+
+               while (iterator.hasNext()) {
+                       record = iterator.next();
+                       if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
+                               AltosRecordMini r = state.clone();
+                               r.time = (r.tick - eeprom.boost_tick) / 100.0;
+                               list.add(r);
+                       }
+                       update_state(state, record, eeprom);
+               }
+               AltosRecordMini 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<AltosOrderedMiniRecord>        iterator = records.iterator();
+               out.printf("# Comments\n");
+               while (iterator.hasNext()) {
+                       AltosOrderedMiniRecord  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
+        */
+       public AltosEepromMiniIterable (FileInputStream input) {
+               records = new TreeSet<AltosOrderedMiniRecord>();
+
+               AltosOrderedMiniRecord 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;
+                               AltosOrderedMiniRecord record = new AltosOrderedMiniRecord(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 25d17e726bf01727c2720d6aba01c1e6772eb722..a629260bb50d2e0fd844bf8361f31c2cfe43cd1a 100644 (file)
@@ -216,6 +216,7 @@ public class AltosLib {
        public static final int AO_LOG_FORMAT_TELEMETRY = 3;
        public static final int AO_LOG_FORMAT_TELESCIENCE = 4;
        public static final int AO_LOG_FORMAT_TELEMEGA = 5;
+       public static final int AO_LOG_FORMAT_MINI = 6;
        public static final int AO_LOG_FORMAT_NONE = 127;
 
        public static boolean isspace(int c) {
diff --git a/altoslib/AltosOrderedMiniRecord.java b/altoslib/AltosOrderedMiniRecord.java
new file mode 100644 (file)
index 0000000..9688894
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.ParseException;
+
+/*
+ * AltosRecords with an index field so they can be sorted by tick while preserving
+ * the original ordering for elements with matching ticks
+ */
+class AltosOrderedMiniRecord extends AltosEepromMini implements Comparable<AltosOrderedMiniRecord> {
+
+       public int      index;
+
+       public AltosOrderedMiniRecord(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(AltosOrderedMiniRecord o) {
+               int     tick_diff = tick - o.tick;
+               if (tick_diff != 0)
+                       return tick_diff;
+               return index - o.index;
+       }
+}
diff --git a/altoslib/AltosRecordMini.java b/altoslib/AltosRecordMini.java
new file mode 100644 (file)
index 0000000..253f380
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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 AltosRecordMini extends AltosRecord {
+
+       /* Sensor values */
+       public int      pres;
+       public int      temp;
+       
+       public int      sense_a;
+       public int      sense_m;
+       public int      v_batt;
+
+       public int      ground_pres;
+
+       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 temperature() {
+               if (temp != MISSING)
+                       return temp;
+               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 apogee_voltage() {
+               return pyro(sense_a);
+       }
+
+       public void copy (AltosRecordMini old) {
+               super.copy(old);
+
+               pres = old.pres;
+               temp = old.temp;
+
+               sense_a = old.sense_a;
+               sense_m = old.sense_m;
+               v_batt = old.v_batt;
+
+               ground_pres = old.ground_pres;
+               
+               flight_accel = old.flight_accel;
+               flight_vel = old.flight_vel;
+               flight_pres = old.flight_pres;
+       }
+
+
+
+       public AltosRecordMini clone() {
+               return new AltosRecordMini(this);
+       }
+
+       void make_missing() {
+
+               pres = MISSING;
+
+               sense_a = MISSING;
+               sense_m = MISSING;
+               v_batt = MISSING;
+
+               ground_pres = MISSING;
+
+               flight_accel = 0;
+               flight_vel = 0;
+               flight_pres = 0;
+       }
+
+       public AltosRecordMini(AltosRecord old) {
+               super.copy(old);
+               make_missing();
+       }
+
+       public AltosRecordMini(AltosRecordMini old) {
+               copy(old);
+       }
+
+       public AltosRecordMini() {
+               super();
+               make_missing();
+       }
+}
index 18b028d628776652ef2243e30ba8eb50ce22fc80..8c1cf2add83c615b6899d4a147a199ed797b559e 100644 (file)
@@ -24,6 +24,8 @@ altoslib_JAVA = \
        AltosEepromMegaIterable.java \
        AltosEepromRecord.java \
        AltosEepromTeleScience.java \
+       AltosEepromMini.java \
+       AltosEepromMiniIterable.java \
        AltosFile.java \
        AltosFlash.java \
        AltosFlashListener.java \
@@ -47,6 +49,7 @@ altoslib_JAVA = \
        AltosMs5607Query.java \
        AltosOrderedRecord.java \
        AltosOrderedMegaRecord.java \
+       AltosOrderedMiniRecord.java \
        AltosParse.java \
        AltosPreferences.java \
        AltosPreferencesBackend.java \
@@ -56,6 +59,7 @@ altoslib_JAVA = \
        AltosRecordNone.java \
        AltosRecordTM.java \
        AltosRecordMM.java \
+       AltosRecordMini.java \
        AltosReplayReader.java \
        AltosRomconfig.java \
        AltosSensorMM.java \
index f914f138f2fe7d2e2d116744a343910283ad8cc9..c7b561d5a809c5eda48f5045a1234c438fe02079 100644 (file)
@@ -55,6 +55,9 @@ public class AltosDataChooser extends JFileChooser {
                                } else if (filename.endsWith("mega")) {
                                        FileInputStream in = new FileInputStream(file);
                                        return new AltosEepromMegaIterable(in);
+                               } else if (filename.endsWith("mini")) {
+                                       FileInputStream in = new FileInputStream(file);
+                                       return new AltosEepromMiniIterable(in);
                                } else {
                                        throw new FileNotFoundException();
                                }
@@ -77,8 +80,10 @@ public class AltosDataChooser extends JFileChooser {
                                                          "telem"));
                setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file",
                                                          "mega"));
+               setFileFilter(new FileNameExtensionFilter("EasyMini eeprom file",
+                                                         "mini"));
                setFileFilter(new FileNameExtensionFilter("Flight data file",
-                                                         "telem", "eeprom", "mega"));
+                                                         "telem", "eeprom", "mega", "mini"));
                setCurrentDirectory(AltosUIPreferences.logdir());
        }
 }
index a0523b58a2c00ea8734c614479994a617ef6249d..53d5433f0146e45aa19756f4ae13b1a5ebe2526f 100644 (file)
@@ -302,6 +302,53 @@ public class AltosEepromDownload implements Runnable {
                CheckFile(false);
        }
        
+       void LogMini(AltosEepromMini r) throws IOException {
+               if (r.cmd != Altos.AO_LOG_INVALID) {
+                       String log_line = String.format("%c %4x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+                                                       r.cmd, r.tick,
+                                                       r.data8[0], r.data8[1], r.data8[2], r.data8[3],
+                                                       r.data8[4], r.data8[5], r.data8[6], r.data8[7],
+                                                       r.data8[8], r.data8[9], r.data8[10], r.data8[11]);
+                       if (eeprom_file != null)
+                               eeprom_file.write(log_line);
+                       else
+                               eeprom_pending.add(log_line);
+               }
+       }
+
+       void CaptureMini(AltosEepromChunk eechunk) throws IOException {
+               boolean any_valid = false;
+
+               extension = "mini";
+               set_serial(flights.config_data.serial);
+               for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromMini.record_length) {
+                       try {
+                               AltosEepromMini r = new AltosEepromMini(eechunk, i);
+                               if (r.cmd == Altos.AO_LOG_FLIGHT)
+                                       set_flight(r.data16(0));
+
+                               /* Monitor state transitions to update display */
+                               if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) <= Altos.ao_flight_landed) {
+                                       state = r.data16(0);
+                                       if (state > Altos.ao_flight_pad)
+                                               want_file = true;
+                               }
+
+                               if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) == Altos.ao_flight_landed)
+                                       done = true;
+                               any_valid = true;
+                               LogMini(r);
+                       } catch (ParseException pe) {
+                               if (parse_exception == null)
+                                       parse_exception = pe;
+                       }
+               }
+               if (!any_valid)
+                       done = true;
+
+               CheckFile(false);
+       }
+       
        void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException {
                
        }
@@ -369,6 +416,9 @@ public class AltosEepromDownload implements Runnable {
                        case AltosLib.AO_LOG_FORMAT_TELEMEGA:
                                extension = "mega";
                                CaptureMega(eechunk);
+                       case AltosLib.AO_LOG_FORMAT_MINI:
+                               extension = "mini";
+                               CaptureMini(eechunk);
                        }
                }
                CheckFile(true);
index 1d209bda8ccaa493371d104126efb2d1c6ca21c2..9dab52c436098b8ea0f2a8a90bd5a8829d9276d3 100644 (file)
@@ -253,6 +253,9 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
                                        } else if (filename.endsWith("mega")) {
                                                FileInputStream in = new FileInputStream(file);
                                                records = new AltosEepromMegaIterable(in);
+                                       } else if (filename.endsWith("mini")) {
+                                               FileInputStream in = new FileInputStream(file);
+                                               records = new AltosEepromMiniIterable(in);
                                        } else {
                                                throw new FileNotFoundException(filename);
                                        }
index 9f8f6ddac4285a0bee154d6267b52e429ec01d54..4362e36c88e1575ee5167790a0d3c26427dcfa09 100644 (file)
@@ -354,6 +354,8 @@ public class AltosUI extends AltosUIFrame {
                                return new AltosEepromIterable(in);
                        else if (file.getName().endsWith("mega"))
                                return new AltosEepromMegaIterable(in);
+                       else if (file.getName().endsWith("mini"))
+                               return new AltosEepromMiniIterable(in);
                        else
                                return new AltosTelemetryIterable(in);
                } catch (FileNotFoundException fe) {
@@ -441,6 +443,8 @@ public class AltosUI extends AltosUIFrame {
                        recs = new AltosEepromIterable(in);
                } else if (file.getName().endsWith("mega")) {
                        recs = new AltosEepromMegaIterable(in);
+               } else if (file.getName().endsWith("mini")) {
+                       recs = new AltosEepromMiniIterable(in);
                } else {
                        recs = new AltosTelemetryIterable(in);
                }
index a68a40dddc0f4f8370c7edc7cd109408a1579af6..95b3764991c47554669132244cc27b0c3a24a9e9 100644 (file)
@@ -44,6 +44,7 @@ extern __pdata enum ao_flight_state ao_log_state;
 #define AO_LOG_FORMAT_TELEMETRY                3       /* 32 byte ao_telemetry records */
 #define AO_LOG_FORMAT_TELESCIENCE      4       /* 32 byte typed telescience records */
 #define AO_LOG_FORMAT_TELEMEGA         5       /* 32 byte typed telemega records */
+#define AO_LOG_FORMAT_MINI             6       /* 16-byte MS5607 baro only */
 #define AO_LOG_FORMAT_NONE             127     /* No log at all */
 
 extern __code uint8_t ao_log_format;
@@ -261,6 +262,40 @@ struct ao_log_mega {
        } u;
 };
 
+struct ao_log_mini {
+       char            type;                           /* 0 */
+       uint8_t         csum;                           /* 1 */
+       uint16_t        tick;                           /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       uint16_t        r6;
+                       uint32_t        ground_pres;    /* 8 */
+               } flight;
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint8_t         pres[3];        /* 4 */
+                       uint8_t         temp[3];        /* 7 */
+                       int16_t         sense_a;        /* 10 */
+                       int16_t         sense_m;        /* 12 */
+                       int16_t         v_batt;         /* 14 */
+               } sensor;                               /* 16 */
+       } u;                                            /* 16 */
+};                                                     /* 16 */
+
+static inline void
+ao_log_pack24(uint8_t *dst, uint32_t value) {
+       dst[0] = value;
+       dst[1] = value >> 8;
+       dst[2] = value >> 16;
+}
+
 /* Write a record to the eeprom log */
 uint8_t
 ao_log_data(__xdata struct ao_log_record *log) __reentrant;
@@ -268,6 +303,9 @@ ao_log_data(__xdata struct ao_log_record *log) __reentrant;
 uint8_t
 ao_log_mega(__xdata struct ao_log_mega *log) __reentrant;
 
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant;
+
 void
 ao_log_flush(void);
 
diff --git a/src/core/ao_log_mini.c b/src/core/ao_log_mini.c
new file mode 100644 (file)
index 0000000..1273b0e
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#include "ao.h"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_mini log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_MINI;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_mini); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (struct ao_log_mini));
+                       ao_log_current_pos += sizeof (struct ao_log_mini);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+static __data uint8_t  ao_log_data_pos;
+
+/* a hack to make sure that ao_log_minis fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mini))] ;
+
+#ifndef AO_SENSOR_INTERVAL_ASCENT
+#define AO_SENSOR_INTERVAL_ASCENT      1
+#define AO_SENSOR_INTERVAL_DESCENT     10
+#endif
+
+void
+ao_log(void)
+{
+       __pdata uint16_t        next_sensor, next_other;
+       uint8_t                 i;
+
+       ao_storage_setup();
+
+       ao_log_scan();
+
+       while (!ao_log_running)
+               ao_sleep(&ao_log_running);
+
+#if HAS_FLIGHT
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_sample_tick;
+       log.u.flight.flight = ao_flight_number;
+       log.u.flight.ground_pres = ao_ground_pres;
+       ao_log_mini(&log);
+#endif
+
+       /* Write the whole contents of the ring to the log
+        * when starting up.
+        */
+       ao_log_data_pos = ao_data_ring_next(ao_data_head);
+       next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick;
+       ao_log_state = ao_flight_startup;
+       for (;;) {
+               /* Write samples to EEPROM */
+               while (ao_log_data_pos != ao_data_head) {
+                       log.tick = ao_data_ring[ao_log_data_pos].tick;
+                       if ((int16_t) (log.tick - next_sensor) >= 0) {
+                               log.type = AO_LOG_SENSOR;
+                               ao_log_pack24(log.u.sensor.pres,
+                                             ao_data_ring[ao_log_data_pos].ms5607_raw.pres);
+                               ao_log_pack24(log.u.sensor.temp,
+                                             ao_data_ring[ao_log_data_pos].ms5607_raw.temp);
+                               log.u.sensor.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
+                               log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
+                               log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+                               ao_log_mini(&log);
+                               if (ao_log_state <= ao_flight_coast)
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+                               else
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+                       }
+                       ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+               }
+#if HAS_FLIGHT
+               /* Write state change to EEPROM */
+               if (ao_flight_state != ao_log_state) {
+                       ao_log_state = ao_flight_state;
+                       log.type = AO_LOG_STATE;
+                       log.tick = ao_time();
+                       log.u.state.state = ao_log_state;
+                       log.u.state.reason = 0;
+                       ao_log_mini(&log);
+
+                       if (ao_log_state == ao_flight_landed)
+                               ao_log_stop();
+               }
+#endif
+
+               ao_log_flush();
+
+               /* Wait for a while */
+               ao_delay(AO_MS_TO_TICKS(100));
+
+               /* Stop logging when told to */
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+       }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_mini)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
index c4e60ada8e58d17ce0776a8257631843ba5d0114..612cc47238dfe738c95ffd04de12c6d84e726986 100644 (file)
@@ -34,7 +34,7 @@ ALTOS_SRC = \
        ao_led_lpc.c \
        ao_task.c \
        ao_log.c \
-       ao_log_tiny.c \
+       ao_log_mini.c \
        ao_cmd.c \
        ao_config.c \
        ao_timer_lpc.c \
index 4102c21d196be8f3d439ce1cb3c9a4203f7465dd..d4fbe7a1e176e4e018e19f9c3b6d1b4f9a58bf12 100644 (file)
 #define AO_ADC_2               1
 
 struct ao_adc {
-       int16_t         sense_d;
+       int16_t         sense_a;
        int16_t         sense_m;
        int16_t         v_batt;
 };
@@ -126,6 +126,9 @@ struct ao_adc {
 #define AO_IGNITER_MAIN_PIN    3
 #define AO_IGNITER_SET_MAIN(v)         ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v)
 
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense_m)
+
 #define AO_ADC_DUMP(p) \
-       printf("tick: %5u drogue: %5d main: %5d batt: %5d\n", \
-              (p)->tick, (p)->adc.sense_d, (p)->adc.sense_m, (p)->adc.v_batt)
+       printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \
+              (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)