--- /dev/null
+/*
+ * 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];
+ }
+}
--- /dev/null
+/*
+ * 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) {
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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+"));
+ }
+}
--- /dev/null
+/*
+ * 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
/*
- * 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
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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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) {
+ }
+ }
+}
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];
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) {
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;
+ }
}
--- /dev/null
+/*
+ * 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) {
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
import java.text.*;
-public class AltosGPS {
+public class AltosGPS implements Cloneable {
public final static int MISSING = AltosRecord.MISSING;
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;
import java.lang.Math;
-public class AltosGreatCircle {
+public class AltosGreatCircle implements Cloneable {
public double distance;
public double bearing;
public double range;
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);
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;
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
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
--- /dev/null
+/*
+ * 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;
+ }
+}
public int flight_accel;
public int flight_vel;
+ public int flight_height;
+
public int flight_pres;
static double adc(int raw) {
flight_accel = old.flight_accel;
flight_vel = old.flight_vel;
+ flight_height = old.flight_height;
flight_pres = old.flight_pres;
}
flight_accel = 0;
flight_vel = 0;
+ flight_height = 0;
flight_pres = 0;
}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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++;
+ }
+ }
+}
+
package org.altusmetrum.altoslib_1;
-public class AltosState {
+public class AltosState implements Cloneable {
public AltosRecord data;
/* derived data */
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;
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 */
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;
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;
/* 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) {
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;
}
}
+ public AltosState clone() {
+ AltosState s = new AltosState(data, this);
+ return s;
+ }
+
public AltosState(AltosRecord cur) {
init(cur, null);
}
--- /dev/null
+/*
+ * 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
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;
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
AltosConvert.java \
AltosCRCException.java \
AltosDebug.java \
+ AltosEeprom.java \
AltosEepromChunk.java \
+ AltosEepromFile.java \
+ AltosEepromHeader.java \
AltosEepromIterable.java \
AltosEepromLog.java \
AltosEepromMega.java \
AltosEepromTeleScience.java \
AltosEepromMini.java \
AltosEepromMiniIterable.java \
+ AltosEepromOldIterable.java \
AltosFile.java \
AltosFlash.java \
AltosFlashListener.java \
AltosSensorMM.java \
AltosSensorTM.java \
AltosState.java \
+ AltosStateUpdate.java \
AltosTelemetry.java \
AltosTelemetryIterable.java \
AltosTelemetryMap.java \
AltosTelemetryRecordSensor.java \
AltosTelemetryRecordMegaSensor.java \
AltosTelemetryRecordMegaData.java \
+ AltosTelemetryRecordMini.java \
AltosUnitsListener.java \
AltosMs5607.java \
AltosIMU.java \