From 04d7d0f829ba953ffeca8ad9887a4b6b2b5d5087 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Aug 2013 21:28:07 -0600 Subject: [PATCH] altoslib: Start restructuring AltosState harder Make per-packet code update state itself rather than having all state updates done centrally. Will make adding new packet types easier. Signed-off-by: Keith Packard --- altoslib/AltosCompanion.java | 38 ++ altoslib/AltosEeprom.java | 89 +++ altoslib/AltosEepromBody.java | 31 ++ altoslib/AltosEepromBodyIterable.java | 28 + altoslib/AltosEepromFile.java | 51 ++ altoslib/AltosEepromHeader.java | 267 +++++++++ altoslib/AltosEepromHeaderIterable.java | 48 ++ altoslib/AltosEepromIterable.java | 422 +------------- altoslib/AltosEepromMetrum.java | 214 ++++++++ altoslib/AltosEepromMetrumIterable.java | 358 ++++++++++++ altoslib/AltosEepromMini.java | 159 ++---- altoslib/AltosEepromOldIterable.java | 435 +++++++++++++++ altoslib/AltosEepromTM.java | 255 +++++++++ altoslib/AltosGPS.java | 35 +- altoslib/AltosGreatCircle.java | 12 +- altoslib/AltosIMU.java | 14 +- altoslib/AltosMag.java | 11 +- altoslib/AltosOrderedMetrumRecord.java | 52 ++ altoslib/AltosRecordMini.java | 4 + altoslib/AltosRecordTM2.java | 156 ++++++ altoslib/AltosSelfFlash.java | 149 +++++ altoslib/AltosSensorMetrum.java | 55 ++ altoslib/AltosState.java | 517 +++++++++++++++--- altoslib/AltosStateUpdate.java | 22 + altoslib/AltosTelemetryRecord.java | 1 + altoslib/AltosTelemetryRecordMetrumData.java | 54 ++ .../AltosTelemetryRecordMetrumSensor.java | 81 +++ altoslib/AltosTelemetryRecordMini.java | 82 +++ altoslib/Makefile.am | 6 + 29 files changed, 3034 insertions(+), 612 deletions(-) create mode 100644 altoslib/AltosCompanion.java create mode 100644 altoslib/AltosEeprom.java create mode 100644 altoslib/AltosEepromBody.java create mode 100644 altoslib/AltosEepromBodyIterable.java create mode 100644 altoslib/AltosEepromFile.java create mode 100644 altoslib/AltosEepromHeader.java create mode 100644 altoslib/AltosEepromHeaderIterable.java create mode 100644 altoslib/AltosEepromMetrum.java create mode 100644 altoslib/AltosEepromMetrumIterable.java create mode 100644 altoslib/AltosEepromOldIterable.java create mode 100644 altoslib/AltosEepromTM.java create mode 100644 altoslib/AltosOrderedMetrumRecord.java create mode 100644 altoslib/AltosRecordTM2.java create mode 100644 altoslib/AltosSelfFlash.java create mode 100644 altoslib/AltosSensorMetrum.java create mode 100644 altoslib/AltosStateUpdate.java create mode 100644 altoslib/AltosTelemetryRecordMetrumData.java create mode 100644 altoslib/AltosTelemetryRecordMetrumSensor.java create mode 100644 altoslib/AltosTelemetryRecordMini.java diff --git a/altoslib/AltosCompanion.java b/altoslib/AltosCompanion.java new file mode 100644 index 00000000..1572fdae --- /dev/null +++ b/altoslib/AltosCompanion.java @@ -0,0 +1,38 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +public class AltosCompanion { + public final static int board_id_telescience = 0x0a; + public final static int MAX_CHANNELS = 12; + + public int tick; + public int board_id; + public int update_period; + public int channels; + public int[] companion_data; + + public AltosCompanion(int in_channels) { + channels = in_channels; + if (channels < 0) + channels = 0; + if (channels > MAX_CHANNELS) + channels = MAX_CHANNELS; + companion_data = new int[channels]; + } +} diff --git a/altoslib/AltosEeprom.java b/altoslib/AltosEeprom.java new file mode 100644 index 00000000..31646c7e --- /dev/null +++ b/altoslib/AltosEeprom.java @@ -0,0 +1,89 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +public abstract class AltosEeprom implements AltosStateUpdate { + public int cmd; + public int tick; + public int data8[]; + public boolean valid; + + public final static int header_length = 4; + + public abstract void update_state(AltosState state); + + public void write(PrintStream out) { + out.printf("%c %04x", cmd, tick); + if (data8 != null) { + for (int i = 0; i < data8.length; i++) + out.printf (" %02x", data8[i]); + } + out.printf ("\n"); + } + + void parse_chunk(AltosEepromChunk chunk, int start, int record_length) throws ParseException { + cmd = chunk.data(start); + + int data_length = record_length - header_length; + + valid = !chunk.erased(start, record_length); + if (valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + cmd = AltosLib.AO_LOG_INVALID; + } + + tick = chunk.data16(start+2); + + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = chunk.data(start + header_length + i); + } + + void parse_string(String line, int record_length) { + valid = false; + tick = 0; + cmd = AltosLib.AO_LOG_INVALID; + + int data_length = record_length - header_length; + + if (line == null) + return; + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length == 2 + data_length) { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + valid = true; + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = Integer.parseInt(tokens[2 + i],16); + } + } + } catch (NumberFormatException ne) { + } + } +} diff --git a/altoslib/AltosEepromBody.java b/altoslib/AltosEepromBody.java new file mode 100644 index 00000000..60aa8881 --- /dev/null +++ b/altoslib/AltosEepromBody.java @@ -0,0 +1,31 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromBody implements AltosEeprom, AltosStateUpdate { + + public void update_state(AltosState state) { + } + + public void write(PrintStream out) { + } +} \ No newline at end of file diff --git a/altoslib/AltosEepromBodyIterable.java b/altoslib/AltosEepromBodyIterable.java new file mode 100644 index 00000000..33dc0ac8 --- /dev/null +++ b/altoslib/AltosEepromBodyIterable.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromBodyIterable { + LinkedList bodies; + + +} \ No newline at end of file diff --git a/altoslib/AltosEepromFile.java b/altoslib/AltosEepromFile.java new file mode 100644 index 00000000..48d2543c --- /dev/null +++ b/altoslib/AltosEepromFile.java @@ -0,0 +1,51 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromFile { + + AltosEepromIterable headers; + AltosEepromIterable body; + + public void write(PrintStream out) { + headers.write(out); + body.write(out); + } + + public AltosEepromFile(FileInputStream input) { + headers = new AltosEepromIterable(AltosEepromHeader.read(input)); + + AltosState state = headers.state(); + + switch (state.log_format) { + case AltosLib.AO_LOG_FORMAT_FULL: + case AltosLib.AO_LOG_FORMAT_TINY: + case AltosLib.AO_LOG_FORMAT_TELEMETRY: + case AltosLib.AO_LOG_FORMAT_TELESCIENCE: + case AltosLib.AO_LOG_FORMAT_TELEMEGA: + break; + case AltosLib.AO_LOG_FORMAT_MINI: + body = new AltosEepromIterable(AltosEepromMini.read(input)); + break; + } + } +} \ No newline at end of file diff --git a/altoslib/AltosEepromHeader.java b/altoslib/AltosEepromHeader.java new file mode 100644 index 00000000..b2343dc6 --- /dev/null +++ b/altoslib/AltosEepromHeader.java @@ -0,0 +1,267 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package 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 read(FileInputStream input) { + LinkedList headers = new LinkedList(); + + 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 headers) { + out.printf("# Comments\n"); + for (AltosEepromHeader header : headers) { + header.write(out); + } + + } + + public AltosEepromHeader (String line) { + this(line.split("\\s+")); + } +} diff --git a/altoslib/AltosEepromHeaderIterable.java b/altoslib/AltosEepromHeaderIterable.java new file mode 100644 index 00000000..fe9e05d9 --- /dev/null +++ b/altoslib/AltosEepromHeaderIterable.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromHeaderIterable implements Iterable { + public LinkedList 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 iterator() { + if (headers == null) + headers = new LinkedList(); + return headers.iterator(); + } +} \ No newline at end of file diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index b84574ef..470a7a8a 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Keith Packard + * Copyright © 2013 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,415 +21,29 @@ import java.io.*; import java.util.*; import java.text.*; -public class AltosEepromIterable extends AltosRecordIterable { +public class AltosEepromIterable implements Iterable { + public LinkedList 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 records; - - LinkedList 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 make_list() { - LinkedList list = new LinkedList(); - Iterator 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 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 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 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 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 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 iterator() { + if (eeproms == null) + eeproms = new LinkedList(); + return eeproms.iterator(); } -} +} \ No newline at end of file diff --git a/altoslib/AltosEepromMetrum.java b/altoslib/AltosEepromMetrum.java new file mode 100644 index 00000000..72887032 --- /dev/null +++ b/altoslib/AltosEepromMetrum.java @@ -0,0 +1,214 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.text.*; + +public class AltosEepromMetrum { + public int cmd; + public int tick; + public boolean valid; + public String data; + public int config_a, config_b; + + public int data8[]; + + public static final int record_length = 16; + static final int header_length = 4; + static final int data_length = record_length - header_length; + + public int data8(int i) { + return data8[i]; + } + + public int data16(int i) { + return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16; + } + + public int data32(int i) { + return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24); + } + + /* AO_LOG_FLIGHT elements */ + public int flight() { return data16(0); } + public int ground_accel() { return data16(2); } + public int ground_pres() { return data32(4); } + public int ground_temp() { return data32(8); } + + /* AO_LOG_STATE elements */ + public int state() { return data16(0); } + public int reason() { return data16(2); } + + /* AO_LOG_SENSOR elements */ + public int pres() { return data32(0); } + public int temp() { return data32(4); } + public int accel() { return data16(8); } + + /* AO_LOG_TEMP_VOLT elements */ + public int v_batt() { return data16(0); } + public int sense_a() { return data16(2); } + public int sense_m() { return data16(4); } + + /* AO_LOG_GPS_POS elements */ + public int latitude() { return data32(0); } + public int longitude() { return data32(4); } + public int altitude() { return data16(8); } + + /* AO_LOG_GPS_TIME elements */ + public int hour() { return data8(0); } + public int minute() { return data8(1); } + public int second() { return data8(2); } + public int flags() { return data8(3); } + public int year() { return data8(4); } + public int month() { return data8(5); } + public int day() { return data8(6); } + + /* AO_LOG_GPS_SAT elements */ + public int channels() { return data8(0); } + public int more() { return data8(1); } + public int svid(int n) { return data8(2 + n * 2); } + public int c_n(int n) { return data8(2 + n * 2 + 1); } + + public AltosEepromMetrum (AltosEepromChunk chunk, int start) throws ParseException { + cmd = chunk.data(start); + + valid = !chunk.erased(start, record_length); + if (valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + cmd = AltosLib.AO_LOG_INVALID; + } + + tick = chunk.data16(start+2); + + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = chunk.data(start + header_length + i); + } + + public AltosEepromMetrum (String line) { + valid = false; + tick = 0; + + if (line == null) { + cmd = AltosLib.AO_LOG_INVALID; + line = ""; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 2 + data_length) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + valid = true; + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = Integer.parseInt(tokens[2 + i],16); + } + } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = AltosLib.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = AltosLib.AO_LOG_MAIN_DEPLOY; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { + cmd = AltosLib.AO_LOG_APOGEE_DELAY; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { + cmd = AltosLib.AO_LOG_RADIO_CHANNEL; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Callsign:")) { + cmd = AltosLib.AO_LOG_CALLSIGN; + data = tokens[1].replaceAll("\"",""); + } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { + cmd = AltosLib.AO_LOG_ACCEL_CAL; + config_a = Integer.parseInt(tokens[3]); + config_b = Integer.parseInt(tokens[5]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { + cmd = AltosLib.AO_LOG_RADIO_CAL; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { + cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; + config_a = Integer.parseInt(tokens[3]); + } else if (tokens[0].equals("manufacturer")) { + cmd = AltosLib.AO_LOG_MANUFACTURER; + data = tokens[1]; + } else if (tokens[0].equals("product")) { + cmd = AltosLib.AO_LOG_PRODUCT; + data = tokens[1]; + } else if (tokens[0].equals("serial-number")) { + cmd = AltosLib.AO_LOG_SERIAL_NUMBER; + config_a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("log-format")) { + cmd = AltosLib.AO_LOG_LOG_FORMAT; + config_a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("software-version")) { + cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; + data = tokens[1]; + } else if (tokens[0].equals("ms5607")) { + if (tokens[1].equals("reserved:")) { + cmd = AltosLib.AO_LOG_BARO_RESERVED; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("sens:")) { + cmd = AltosLib.AO_LOG_BARO_SENS; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("off:")) { + cmd = AltosLib.AO_LOG_BARO_OFF; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tcs:")) { + cmd = AltosLib.AO_LOG_BARO_TCS; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tco:")) { + cmd = AltosLib.AO_LOG_BARO_TCO; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tref:")) { + cmd = AltosLib.AO_LOG_BARO_TREF; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tempsens:")) { + cmd = AltosLib.AO_LOG_BARO_TEMPSENS; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("crc:")) { + cmd = AltosLib.AO_LOG_BARO_CRC; + config_a = Integer.parseInt(tokens[2]); + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } catch (NumberFormatException ne) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } + } + + public AltosEepromMetrum(int in_cmd, int in_tick) { + cmd = in_cmd; + tick = in_tick; + valid = true; + } +} diff --git a/altoslib/AltosEepromMetrumIterable.java b/altoslib/AltosEepromMetrumIterable.java new file mode 100644 index 00000000..0387319e --- /dev/null +++ b/altoslib/AltosEepromMetrumIterable.java @@ -0,0 +1,358 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package 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 records; + + AltosMs5607 baro; + + LinkedList 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 make_list() { + LinkedList list = new LinkedList(); + Iterator 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 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 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 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) { + } + } +} diff --git a/altoslib/AltosEepromMini.java b/altoslib/AltosEepromMini.java index 215cd3d9..ced87680 100644 --- a/altoslib/AltosEepromMini.java +++ b/altoslib/AltosEepromMini.java @@ -17,20 +17,12 @@ package org.altusmetrum.altoslib_1; +import java.io.*; +import java.util.*; import java.text.*; -public class AltosEepromMini { - public int cmd; - public int tick; - public boolean valid; - public String data; - public int config_a, config_b; - - public int data8[]; - +public class AltosEepromMini extends AltosEeprom { public static final int record_length = 16; - static final int header_length = 4; - static final int data_length = record_length - header_length; public int data8(int i) { return data8[i]; @@ -63,126 +55,23 @@ public class AltosEepromMini { public int sense_m() { return data16(8); } public int v_batt() { return data16(10); } - public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException { - cmd = chunk.data(start); - - valid = !chunk.erased(start, record_length); - if (valid) { - if (AltosConvert.checksum(chunk.data, start, record_length) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x", - chunk.address + start), 0); - } else { - cmd = AltosLib.AO_LOG_INVALID; + public void update_state(AltosState state) { + switch (cmd) { + case AltosLib.AO_LOG_FLIGHT: + break; + case AltosLib.AO_LOG_STATE: + break; + case AltosLib.AO_LOG_SENSOR: + break; } + } - tick = chunk.data16(start+2); - - data8 = new int[data_length]; - for (int i = 0; i < data_length; i++) - data8[i] = chunk.data(start + header_length + i); + public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException { + parse_chunk(chunk, start, record_length); } public AltosEepromMini (String line) { - valid = false; - tick = 0; - - if (line == null) { - cmd = AltosLib.AO_LOG_INVALID; - line = ""; - } else { - try { - String[] tokens = line.split("\\s+"); - - if (tokens[0].length() == 1) { - if (tokens.length != 2 + data_length) { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } else { - cmd = tokens[0].codePointAt(0); - tick = Integer.parseInt(tokens[1],16); - valid = true; - data8 = new int[data_length]; - for (int i = 0; i < data_length; i++) - data8[i] = Integer.parseInt(tokens[2 + i],16); - } - } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { - cmd = AltosLib.AO_LOG_CONFIG_VERSION; - data = tokens[2]; - } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { - cmd = AltosLib.AO_LOG_MAIN_DEPLOY; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { - cmd = AltosLib.AO_LOG_APOGEE_DELAY; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { - cmd = AltosLib.AO_LOG_RADIO_CHANNEL; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Callsign:")) { - cmd = AltosLib.AO_LOG_CALLSIGN; - data = tokens[1].replaceAll("\"",""); - } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { - cmd = AltosLib.AO_LOG_ACCEL_CAL; - config_a = Integer.parseInt(tokens[3]); - config_b = Integer.parseInt(tokens[5]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { - cmd = AltosLib.AO_LOG_RADIO_CAL; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { - cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; - config_a = Integer.parseInt(tokens[3]); - } else if (tokens[0].equals("manufacturer")) { - cmd = AltosLib.AO_LOG_MANUFACTURER; - data = tokens[1]; - } else if (tokens[0].equals("product")) { - cmd = AltosLib.AO_LOG_PRODUCT; - data = tokens[1]; - } else if (tokens[0].equals("serial-number")) { - cmd = AltosLib.AO_LOG_SERIAL_NUMBER; - config_a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("log-format")) { - cmd = AltosLib.AO_LOG_LOG_FORMAT; - config_a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("software-version")) { - cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; - data = tokens[1]; - } else if (tokens[0].equals("ms5607")) { - if (tokens[1].equals("reserved:")) { - cmd = AltosLib.AO_LOG_BARO_RESERVED; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("sens:")) { - cmd = AltosLib.AO_LOG_BARO_SENS; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("off:")) { - cmd = AltosLib.AO_LOG_BARO_OFF; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tcs:")) { - cmd = AltosLib.AO_LOG_BARO_TCS; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tco:")) { - cmd = AltosLib.AO_LOG_BARO_TCO; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tref:")) { - cmd = AltosLib.AO_LOG_BARO_TREF; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tempsens:")) { - cmd = AltosLib.AO_LOG_BARO_TEMPSENS; - config_a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("crc:")) { - cmd = AltosLib.AO_LOG_BARO_CRC; - config_a = Integer.parseInt(tokens[2]); - } else { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } - } else { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } - } catch (NumberFormatException ne) { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } - } + parse_string(line, record_length); } public AltosEepromMini(int in_cmd, int in_tick) { @@ -190,4 +79,22 @@ public class AltosEepromMini { tick = in_tick; valid = true; } + + static public LinkedList read(FileInputStream input) { + LinkedList minis = new LinkedList(); + + for (;;) { + try { + String line = AltosLib.gets(input); + if (line == null) + break; + AltosEepromMini mini = new AltosEepromMini(line); + minis.add(mini); + } catch (IOException ie) { + break; + } + } + + return minis; + } } diff --git a/altoslib/AltosEepromOldIterable.java b/altoslib/AltosEepromOldIterable.java new file mode 100644 index 00000000..ef82828b --- /dev/null +++ b/altoslib/AltosEepromOldIterable.java @@ -0,0 +1,435 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package 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 records; + + LinkedList 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 make_list() { + LinkedList list = new LinkedList(); + Iterator 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 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 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 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 iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedRecord old = iterator.next(); + if (old.cmd == AltosLib.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == AltosLib.AO_LOG_STATE && + record.a == AltosLib.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altoslib/AltosEepromTM.java b/altoslib/AltosEepromTM.java new file mode 100644 index 00000000..fc7ec321 --- /dev/null +++ b/altoslib/AltosEepromTM.java @@ -0,0 +1,255 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package 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; + } +} diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index f23842f3..f7929a4c 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -19,7 +19,7 @@ package org.altusmetrum.altoslib_1; import java.text.*; -public class AltosGPS { +public class AltosGPS implements Cloneable { public final static int MISSING = AltosRecord.MISSING; @@ -216,6 +216,39 @@ public class AltosGPS { cc_gps_sat = null; } + public AltosGPS clone() { + AltosGPS g = new AltosGPS(); + + g.nsat = nsat; + g.locked = locked; + g.connected = connected; + g.lat = lat; g./* degrees (+N -S) */ + g.lon = lon; /* degrees (+E -W) */ + g.alt = alt; /* m */ + g.year = year; + g.month = month; + g.day = day; + g.hour = hour; + g.minute = minute; + g.second = second; + + g.ground_speed = ground_speed; /* m/s */ + g.course = course; /* degrees */ + g.climb_rate = climb_rate; /* m/s */ + g.hdop = hdop; /* unitless? */ + g.h_error = h_error; /* m */ + g.v_error = v_error; /* m */ + + if (cc_gps_sat != null) { + g.cc_gps_sat = new AltosGPSSat[cc_gps_sat.length]; + for (int i = 0; i < cc_gps_sat.length; i++) { + g.cc_gps_sat[i] = new AltosGPSSat(); + g.cc_gps_sat[i].svid = cc_gps_sat[i].svid; + g.cc_gps_sat[i].c_n0 = cc_gps_sat[i].c_n0; + } + } + } + public AltosGPS(AltosGPS old) { if (old != null) { nsat = old.nsat; diff --git a/altoslib/AltosGreatCircle.java b/altoslib/AltosGreatCircle.java index f1cf0ae9..770c3c6c 100644 --- a/altoslib/AltosGreatCircle.java +++ b/altoslib/AltosGreatCircle.java @@ -19,7 +19,7 @@ package org.altusmetrum.altoslib_1; import java.lang.Math; -public class AltosGreatCircle { +public class AltosGreatCircle implements Cloneable { public double distance; public double bearing; public double range; @@ -95,6 +95,16 @@ public class AltosGreatCircle { elevation = Math.atan2(height_diff, distance) * 180 / Math.PI; } + public AltosGreatCircle clone() { + AltosGreatCircle n = new AltosGreatCircle(); + + n.distance = distance; + n.bearing = bearing; + n.range = range; + n.elevation = elevation; + return n; + } + public AltosGreatCircle (double start_lat, double start_lon, double end_lat, double end_lon) { this(start_lat, start_lon, 0, end_lat, end_lon, 0); diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index 8f6731fa..46df35bf 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -17,7 +17,7 @@ package org.altusmetrum.altoslib_1; -public class AltosIMU { +public class AltosIMU implements Cloneable { public int accel_x; public int accel_y; public int accel_z; @@ -25,5 +25,17 @@ public class AltosIMU { public int gyro_x; public int gyro_y; public int gyro_z; + + public AltosIMU clone() { + AltosIMU n = new AltosIMU(); + + n.accel_x = accel_x; + n.accel_y = accel_y; + n.accel_z = accel_z; + + n.gyro_x = gyro_x; + n.gyro_y = gyro_y; + n.gyro_z = gyro_z; + return n; } \ No newline at end of file diff --git a/altoslib/AltosMag.java b/altoslib/AltosMag.java index b3bbd92f..cb6826f3 100644 --- a/altoslib/AltosMag.java +++ b/altoslib/AltosMag.java @@ -17,9 +17,18 @@ package org.altusmetrum.altoslib_1; -public class AltosMag { +public class AltosMag implements Cloneable { public int x; public int y; public int z; + + public AltosMag clone() { + AltosMag n = new AltosMag(); + + n.x = x; + n.y = y; + n.z = z; + return n; + } } \ No newline at end of file diff --git a/altoslib/AltosOrderedMetrumRecord.java b/altoslib/AltosOrderedMetrumRecord.java new file mode 100644 index 00000000..02cdf1fe --- /dev/null +++ b/altoslib/AltosOrderedMetrumRecord.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package 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 { + + 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; + } +} diff --git a/altoslib/AltosRecordMini.java b/altoslib/AltosRecordMini.java index 253f3804..dacd89b8 100644 --- a/altoslib/AltosRecordMini.java +++ b/altoslib/AltosRecordMini.java @@ -31,6 +31,8 @@ public class AltosRecordMini extends AltosRecord { public int flight_accel; public int flight_vel; + public int flight_height; + public int flight_pres; static double adc(int raw) { @@ -89,6 +91,7 @@ public class AltosRecordMini extends AltosRecord { flight_accel = old.flight_accel; flight_vel = old.flight_vel; + flight_height = old.flight_height; flight_pres = old.flight_pres; } @@ -110,6 +113,7 @@ public class AltosRecordMini extends AltosRecord { flight_accel = 0; flight_vel = 0; + flight_height = 0; flight_pres = 0; } diff --git a/altoslib/AltosRecordTM2.java b/altoslib/AltosRecordTM2.java new file mode 100644 index 00000000..0cd54f2c --- /dev/null +++ b/altoslib/AltosRecordTM2.java @@ -0,0 +1,156 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +public class AltosRecordTM2 extends AltosRecord { + + /* Sensor values */ + public int accel; + public int pres; + public int temp; + + public int v_batt; + public int sense_a; + public int sense_m; + + public int ground_accel; + public int ground_pres; + public int accel_plus_g; + public int accel_minus_g; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + static double adc(int raw) { + return raw / 4095.0; + } + + public double pressure() { + if (pres != MISSING) + return pres; + return MISSING; + } + + public double ground_pressure() { + if (ground_pres != MISSING) + return ground_pres; + return MISSING; + } + + public double battery_voltage() { + if (v_batt != MISSING) + return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0; + return MISSING; + } + + static double pyro(int raw) { + if (raw != MISSING) + return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0; + return MISSING; + } + + public double main_voltage() { + return pyro(sense_m); + } + + public double drogue_voltage() { + return pyro(sense_a); + } + + public double temperature() { + if (temp != MISSING) + return temp / 100.0; + return MISSING; + } + + double accel_counts_per_mss() { + double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; + + return counts_per_g / 9.80665; + } + + public double acceleration() { + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + + if (accel_minus_g == MISSING || accel_plus_g == MISSING) + return MISSING; + + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public void copy (AltosRecordTM2 old) { + super.copy(old); + + accel = old.accel; + pres = old.pres; + temp = old.temp; + + v_batt = old.v_batt; + sense_a = old.sense_a; + sense_m = old.sense_m; + + ground_accel = old.ground_accel; + ground_pres = old.ground_pres; + accel_plus_g = old.accel_plus_g; + accel_minus_g = old.accel_minus_g; + + flight_accel = old.flight_accel; + flight_vel = old.flight_vel; + flight_pres = old.flight_pres; + } + + public AltosRecordTM2 clone() { + return new AltosRecordTM2(this); + } + + void make_missing() { + + accel = MISSING; + pres = MISSING; + temp = MISSING; + + v_batt = MISSING; + sense_a = MISSING; + sense_m = MISSING; + + ground_accel = MISSING; + ground_pres = MISSING; + accel_plus_g = MISSING; + accel_minus_g = MISSING; + + flight_accel = 0; + flight_vel = 0; + flight_pres = 0; + } + + public AltosRecordTM2(AltosRecord old) { + super.copy(old); + make_missing(); + } + + public AltosRecordTM2(AltosRecordTM2 old) { + copy(old); + } + + public AltosRecordTM2() { + super(); + make_missing(); + } +} diff --git a/altoslib/AltosSelfFlash.java b/altoslib/AltosSelfFlash.java new file mode 100644 index 00000000..07917d5d --- /dev/null +++ b/altoslib/AltosSelfFlash.java @@ -0,0 +1,149 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; + +public class AltosSelfFlash { + File file; + FileInputStream input; + AltosHexfile image; + AltosLink link; + boolean aborted; + AltosFlashListener listener; + byte[] read_block, write_block; + + void action(String s, int percent) { + if (listener != null && !aborted) + listener.position(s, percent); + } + + void action(int part, int total) { + int percent = 100 * part / total; + action(String.format("%d/%d (%d%%)", + part, total, percent), + percent); + } + + void read_block(long addr) { + link.printf("R %x\n", addr); + + } + + void read_memory(long addr, int len) { + } + + void write_memory(long addr, byte[] data, int start, int len) { + + } + + void reboot() { + } + + public void flash() { + try { + int remain = image.data.length; + long flash_addr = image.address; + int image_start = 0; + + action("start", 0); + action(0, image.data.length); + while (remain > 0 && !aborted) { + int this_time = remain; + if (this_time > 0x100) + this_time = 0x100; + + if (link != null) { + /* write the data */ + write_memory(flash_addr, image.data, image_start, this_time); + + byte[] check = read_memory(flash_addr, this_time); + for (int i = 0; i < this_time; i++) + if (check[i] != image.data[image_start + i]) + throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)", + image.address + image_start + i, + check[i], image.data[image_start + i])); + } else { + Thread.sleep(100); + } + + remain -= this_time; + flash_addr += this_time; + image_start += this_time; + + action(image.data.length - remain, image.data.length); + } + if (!aborted) { + action("done", 100); + if (link != null) { + reboot(); + } + } + if (link != null) + link.close(); + } catch (IOException ie) { + action(ie.getMessage(), -1); + abort(); + } catch (InterruptedException ie) { + abort(); + } + } + + public void close() { + if (link != null) + link.close(); + } + + synchronized public void abort() { + aborted = true; + close(); + } + + public boolean check_rom_config() { + if (link == null) + return true; + if (rom_config == null) + rom_config = debug.romconfig(); + return rom_config != null && rom_config.valid(); + } + + public void set_romconfig (AltosRomconfig romconfig) { + rom_config = romconfig; + } + + public AltosRomconfig romconfig() { + if (!check_rom_config()) + return null; + return rom_config; + } + + public AltosFlash(File file, AltosLink link, AltosFlashListener listener) + throws IOException, FileNotFoundException, InterruptedException { + this.file = file; + this.link = link; + this.listener = listener; + this.read_block = new byte[256]; + this.write_block = new byte[256]; + input = new FileInputStream(file); + image = new AltosHexfile(input); + if (link != null) { + debug.close(); + throw new IOException("Debug port not connected"); + } + } +} \ No newline at end of file diff --git a/altoslib/AltosSensorMetrum.java b/altoslib/AltosSensorMetrum.java new file mode 100644 index 00000000..686c78a8 --- /dev/null +++ b/altoslib/AltosSensorMetrum.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package 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++; + } + } +} + diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index e0d9bb1f..b40b744f 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -21,7 +21,7 @@ package org.altusmetrum.altoslib_1; -public class AltosState { +public class AltosState implements Cloneable { public AltosRecord data; /* derived data */ @@ -35,24 +35,29 @@ public class AltosState { public int state; public boolean landed; public boolean ascent; /* going up? */ - public boolean boost; /* under power */ + public boolean boost; /* under power */ public double ground_altitude; public double altitude; public double height; public double pressure; public double acceleration; - public double battery; + public double battery_voltage; + public double pyro_voltage; public double temperature; - public double main_sense; - public double drogue_sense; - public double accel_speed; - public double baro_speed; + public double apogee_voltage; + public double main_voltage; + public double speed; + + public double prev_height; + public double prev_speed; + public double prev_acceleration; public double max_height; public double max_acceleration; - public double max_accel_speed; - public double max_baro_speed; + public double max_speed; + + public double kalman_height, kalman_speed, kalman_acceleration; public AltosGPS gps; public int gps_sequence; @@ -63,10 +68,11 @@ public class AltosState { public static final int MIN_PAD_SAMPLES = 10; public int npad; - public int ngps; public int gps_waiting; public boolean gps_ready; + public int ngps; + public AltosGreatCircle from_pad; public double elevation; /* from pad */ public double range; /* total distance */ @@ -78,80 +84,434 @@ public class AltosState { public int speak_tick; public double speak_altitude; + public String callsign; + public double accel_plus_g; + public double accel_minus_g; + public double accel; + public double ground_accel; + + public int log_format; + public int serial; + + public AltosMs5607 baro; + public double speed() { - if (ascent) - return accel_speed; - else - return baro_speed; + return speed; } public double max_speed() { - if (max_accel_speed != 0) - return max_accel_speed; - return max_baro_speed; + return max_speed; + } + + public void set_npad(int npad) { + this.npad = npad; + gps_waiting = MIN_PAD_SAMPLES - npad; + if (this.gps_waiting < 0) + gps_waiting = 0; + gps_ready = gps_waiting == 0; + } + + public void init() { + data = new AltosRecord(); + + report_time = System.currentTimeMillis(); + time = AltosRecord.MISSING; + time_change = AltosRecord.MISSING; + tick = AltosRecord.MISSING; + state = AltosLib.ao_flight_invalid; + landed = false; + boost = false; + + ground_altitude = AltosRecord.MISSING; + altitude = AltosRecord.MISSING; + height = AltosRecord.MISSING; + pressure = AltosRecord.MISSING; + acceleration = AltosRecord.MISSING; + temperature = AltosRecord.MISSING; + + prev_height = AltosRecord.MISSING; + prev_speed = AltosRecord.MISSING; + prev_acceleration = AltosRecord.MISSING; + + battery_voltage = AltosRecord.MISSING; + pyro_voltage = AltosRecord.MISSING; + apogee_voltage = AltosRecord.MISSING; + main_voltage = AltosRecord.MISSING; + + + accel_speed = AltosRecord.MISSING; + baro_speed = AltosRecord.MISSING; + + kalman_height = AltosRecord.MISSING; + kalman_speed = AltosRecord.MISSING; + kalman_acceleration = AltosRecord.MISSING; + + max_baro_speed = 0; + max_accel_speed = 0; + max_height = 0; + max_acceleration = 0; + + gps = null; + gps_sequence = 0; + + imu = null; + mag = null; + + set_npad(0); + ngps = 0; + + from_pad = null; + elevation = AltosRecord.MISSING; + range = AltosRecord.MISSING; + gps_height = AltosRecord.MISSING; + + pat_lat = AltosRecord.MISSING; + pad_lon = AltosRecord.MISSING; + pad_alt = AltosRecord.MISSING; + + speak_tick = AltosRecord.MISSING; + speak_altitude = AltosRecord.MISSING; + + callsign = null; + + accel_plus_g = AltosRecord.MISSING; + accel_minus_g = AltosRecord.MISSING; + log_format = AltosRecord.MISSING; + serial = AltosRecord.MISSING; + + baro = null; + } + + void copy(AltosState old) { + + data = null; + + if (old == null) { + init(); + return; + } + + report_time = old.report_time; + time = old.time; + time_change = old.time_change; + tick = old.tick; + + state = old.state; + landed = old.landed; + ascent = old.ascent; + boost = old.boost; + + ground_altitude = old.ground_altitude; + altitude = old.altitude; + height = old.height; + pressure = old.pressure; + acceleration = old.acceleration; + battery_voltage = old.battery_voltage; + pyro_voltage = old.pyro_voltage; + temperature = old.temperature; + apogee_voltage = old.apogee_voltage; + main_voltage = old.main_voltage; + accel_speed = old.accel_speed; + baro_speed = old.baro_speed; + + prev_height = old.height; + prev_speed = old.speed; + prev_acceleration = old.acceleration; + + max_height = old.max_height; + max_acceleration = old.max_acceleration; + max_accel_speed = old.max_accel_speed; + max_baro_speed = old.max_baro_speed; + + kalman_height = old.kalman_height; + kalman_speed = old.kalman_speed; + kalman_acceleration = old.kalman_acceleration; + + if (old.gps != null) + gps = old.gps.clone(); + else + gps = null; + gps_sequence = old.gps_sequence; + + if (old.imu != null) + imu = old.imu.clone(); + else + imu = null; + + if (old.mag != null) + mag = old.mag.clone(); + else + mag = null; + + npad = old.npad; + gps_waiting = old.gps_waiting; + gps_ready = old.gps_ready; + ngps = old.ngps; + + if (old.from_pad != null) + from_pad = old.from_pad.clone(); + else + from_pad = null; + + elevation = old.elevation; + range = old.range; + + gps_height = old.gps_height; + pad_lat = old.pad_lat; + pad_lon = old.pad_lon; + pad_alt = old.pad_alt; + + speak_tick = old.speak_tick; + speak_altitude = old.speak_altitude; + + callsign = old.callsign; + + accel_plus_g = old.accel_plus_g; + accel_minus_g = old.accel_minus_g; + log_format = old.log_format; + serial = old.serial; + + baro = old.baro; + } + + double ground_altitude() { + + } + + double altitude() { + if (altitude != AltosRecord.MISSING) + return altitude; + if (gps != null) + return gps.alt; + return AltosRecord.MISSING; + } + + void update_vertical_pos() { + + double alt = altitude(); + if (state == AltosLib.ao_flight_pad) { + + } + + if (kalman_height != AltosRecord.MISSING) + height = kalman_height; + else if (altitude != AltosRecord.MISSING && ground_altitude != AltosRecord.MISSING) + height = altitude - ground_altitude; + else + height = AltosRecord.MISSING; + + update_speed(); + } + + double motion_filter_value() { + return 1/ Math.exp(time_change/10.0); + } + + void update_speed() { + if (kalman_speed != AltosRecord.MISSING) + speed = kalman_speed; + else if (state != AltosLib.ao_flight_invalid && + time_change != AltosRecord.MISSING) + { + if (ascent && acceleration != AltosRecord.MISSING) + { + if (prev_speed == AltosRecord.MISSING) + speed = acceleration * time_change; + else + speed = prev_speed + acceleration * time_change; + } + else if (height != AltosRecord.MISSING && + prev_height != AltosRecord.MISSING && + time_change != 0) + { + double new_speed = (height - prev_height) / time_change; + + if (prev_speed == AltosRecord.MISSING) + speed = new_speed; + else { + double filter = motion_filter_value(); + + speed = prev_speed * filter + new_speed * (1-filter); + } + } + } + if (acceleration == AltosRecord.MISSING) { + if (prev_speed != AltosRecord.MISSING && time_change != 0) { + double new_acceleration = (speed - prev_speed) / time_change; + + if (prev_acceleration == AltosRecord.MISSING) + acceleration = new_acceleration; + else { + double filter = motion_filter_value(); + + acceleration = prev_acceleration * filter + new_acceleration * (1-filter); + } + } + } + } + + void update_accel() { + if (accel == AltosRecord.MISSING) + return; + if (ground_Accel == AltosRecord.MISSING) + return; + if (accel_plus_g == AltosRecord.MISSING) + return; + if (accel_minus_g == AltosRecord.MISSING) + return; + + double counts_per_g = (accel_minus_g - accel_plus_g) / 2.0; + double counts_per_mss = counts_per_g / 9.80665; + + acceleration = (ground_accel - accel) / counts_per_mss; + update_speed(); + } + + public void set_tick(int tick) { + if (tick != AltosRecord.MISSING) { + if (this.tick != AltosRecord.MISSING) { + while (tick < this.tick) + tick += 65536; + time_change = (tick - this.tick) / 100.0; + } else + time_change = 0; + this.tick = tick; + update_time(); + } + } + + public void set_state(int state) { + if (state != AltosLib.ao_flight_invalid) { + this.state = state; + ascent = (AltosLib.ao_flight_boost <= state && + state <= AltosLib.ao_flight_coast); + boost = (AltosLib.ao_flight_boost == state); + } + + } + + public void set_altitude(double altitude) { + if (altitude != AltosRecord.MISSING) { + this.altitude = altitude; + update_vertical_pos(); + } + } + + public void set_ground_altitude(double ground_altitude) { + if (ground_altitude != AltosRecord.MISSING) { + this.ground_altitude = ground_altitude; + update_vertical_pos(); + } + } + + public void set_gps(AltosGPS gps, int sequence) { + if (gps != null) { + this.gps = gps.clone(); + gps_sequence = sequence; + update_vertical_pos(); + } + } + + public void set_kalman(double height, double speed, double acceleration) { + if (height != AltosRecord.MISSING) { + kalman_height = height; + kalman_speed = speed; + kalman_acceleration = acceleration; + baro_speed = accel_speed = speed; + update_vertical_pos(); + } + } + + public void set_pressure(double pressure) { + if (pressure != AltosRecord.MISSING) { + this.pressure = pressure; + set_altitude(AltosConvert.pressure_to_altitude(pressure)); + } + } + + public void set_accel_g(double accel_plus_g, double accel_minus_g) { + if (accel_plus_g != AltosRecord.MISSING) { + this.accel_plus_g = accel_plus_g; + this.accel_minus_g = accel_minus_g; + update_accel(); + } + } + public void set_ground_accel(double ground_accel) { + if (ground_accel != AltosRecord.MISSING) { + this.ground_accel = ground_accel; + update_accel(); + } + } + + public void set_accel(double accel) { + if (accel != AltosRecord.MISSING) { + this.accel = accel; + } + update_accel(); + } + + public void set_temperature(double temperature) { + if (temperature != AltosRecord.MISSING) + this.temperature = temperature; + } + + public void set_battery_voltage(double battery_voltage) { + if (battery_voltage != AltosRecord.MISSING) + this.battery_voltage = battery_voltage; + } + + public void set_pyro_voltage(double pyro_voltage) { + if (pyro_voltage != AltosRecord.MISSING) + this.pyro_voltage = pyro_voltage; + } + + public void set_apogee_voltage(double apogee_voltage) { + if (apogee_voltage != AltosRecord.MISSING) + this.apogee_voltage = apogee_voltage; + } + + public void set_main_voltage(double main_voltage) { + if (main_voltage != AltosRecord.MISSING) + this.main_voltage = main_voltage; } public void init (AltosRecord cur, AltosState prev_state) { + + if (cur == null) + cur = new AltosRecord(); + data = cur; /* Discard previous state if it was for a different board */ - if (prev_state != null && prev_state.data.serial != data.serial) + if (prev_state != null && prev_state.serial != cur.serial) prev_state = null; - ground_altitude = data.ground_altitude(); - altitude = data.altitude(); - if (altitude == AltosRecord.MISSING && data.gps != null) - altitude = data.gps.alt; + copy(prev_state); - height = AltosRecord.MISSING; - if (data.kalman_height != AltosRecord.MISSING) - height = data.kalman_height; - else { - if (altitude != AltosRecord.MISSING && ground_altitude != AltosRecord.MISSING) { - double cur_height = altitude - ground_altitude; - if (prev_state == null || prev_state.height == AltosRecord.MISSING) - height = cur_height; - else - height = (prev_state.height * 15 + cur_height) / 16.0; - } - } + set_ground_altitude(data.ground_altitude()); + set_altitude(data.altitude()); + + set_kalman(data.kalman_height, data.kalman_speed, data.kalman_acceleration); report_time = System.currentTimeMillis(); - if (data.kalman_acceleration != AltosRecord.MISSING) - acceleration = data.kalman_acceleration; - else - acceleration = data.acceleration(); - temperature = data.temperature(); - drogue_sense = data.drogue_voltage(); - main_sense = data.main_voltage(); - battery = data.battery_voltage(); - pressure = data.pressure(); - tick = data.tick; - state = data.state; + set_temperature(data.temperature()); + set_apogee_voltage(data.drogue_voltage()); + set_main_voltage(data.main_voltage()); + set_battery_voltage(data.battery_voltage()); - if (prev_state != null) { + set_pressure(data.pressure()); - /* Preserve any existing gps data */ - npad = prev_state.npad; - ngps = prev_state.ngps; - gps = prev_state.gps; - gps_sequence = prev_state.gps_sequence; - pad_lat = prev_state.pad_lat; - pad_lon = prev_state.pad_lon; - pad_alt = prev_state.pad_alt; - max_height = prev_state.max_height; - max_acceleration = prev_state.max_acceleration; - max_accel_speed = prev_state.max_accel_speed; - max_baro_speed = prev_state.max_baro_speed; - imu = prev_state.imu; - mag = prev_state.mag; - - /* make sure the clock is monotonic */ - while (tick < prev_state.tick) - tick += 65536; - - time_change = (tick - prev_state.tick) / 100.0; + set_tick(data.tick); + set_state(data.state); + + set_accel_g (data.accel_minus_g, data.accel_plus_g); + set_ground_accel(data.ground_accel); + set_accel (data.accel); + + set_gps(data.gps, data.gps_sequence); + + if (prev_state != null) { if (data.kalman_speed != AltosRecord.MISSING) { baro_speed = accel_speed = data.kalman_speed; @@ -200,6 +560,12 @@ public class AltosState { max_height = 0; max_acceleration = 0; time_change = 0; + baro = new AltosMs5607(); + callsign = ""; + accel_plus_g = AltosRecord.MISSING; + accel_minus_g = AltosRecord.MISSING; + log_format = AltosRecord.MISSING; + serial = AltosRecord.MISSING; } time = tick / 100.0; @@ -208,9 +574,9 @@ public class AltosState { /* Track consecutive 'good' gps reports, waiting for 10 of them */ if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) - npad++; + set_npad(npad+1); else - npad = 0; + set_npad(0); /* Average GPS data while on the pad */ if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { @@ -233,16 +599,6 @@ public class AltosState { gps_sequence = data.gps_sequence; - gps_waiting = MIN_PAD_SAMPLES - npad; - if (gps_waiting < 0) - gps_waiting = 0; - - gps_ready = gps_waiting == 0; - - ascent = (AltosLib.ao_flight_boost <= state && - state <= AltosLib.ao_flight_coast); - boost = (AltosLib.ao_flight_boost == state); - /* Only look at accelerometer data under boost */ if (boost && acceleration != AltosRecord.MISSING && (max_acceleration == AltosRecord.MISSING || acceleration > max_acceleration)) max_acceleration = acceleration; @@ -270,6 +626,11 @@ public class AltosState { } } + public AltosState clone() { + AltosState s = new AltosState(data, this); + return s; + } + public AltosState(AltosRecord cur) { init(cur, null); } diff --git a/altoslib/AltosStateUpdate.java b/altoslib/AltosStateUpdate.java new file mode 100644 index 00000000..50460e21 --- /dev/null +++ b/altoslib/AltosStateUpdate.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +public interface AltosStateUpdate { + public void update_state(AltosState state); +} \ No newline at end of file diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java index fdc3c88e..a744e61a 100644 --- a/altoslib/AltosTelemetryRecord.java +++ b/altoslib/AltosTelemetryRecord.java @@ -44,6 +44,7 @@ public abstract class AltosTelemetryRecord { final static int packet_type_companion = 0x07; final static int packet_type_MM_sensor = 0x08; final static int packet_type_MM_data = 0x09; + final static int packet_type_Mini = 0x10; static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { AltosTelemetryRecord r; diff --git a/altoslib/AltosTelemetryRecordMetrumData.java b/altoslib/AltosTelemetryRecordMetrumData.java new file mode 100644 index 00000000..70179b28 --- /dev/null +++ b/altoslib/AltosTelemetryRecordMetrumData.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + + +public class AltosTelemetryRecordMetrumData extends AltosTelemetryRecordRaw { + + int ground_pres; + int ground_accel; + int accel_plus_g; + int accel_minus_g; + + public AltosTelemetryRecordMetrumData(int[] in_bytes, int rssi) { + super(in_bytes, rssi); + + ground_pres = int32(8); + ground_accel = int16(12); + accel_plus_g = int16(14); + accel_minus_g = int16(16); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord n = super.update_state(previous); + + AltosRecordTM2 next; + if (!(n instanceof AltosRecordTM2)) { + next = new AltosRecordTM2(n); + } else { + next = (AltosRecordTM2) n; + } + + next.ground_accel = ground_accel; + next.ground_pres = ground_pres; + next.accel_plus_g = accel_plus_g; + next.accel_minus_g = accel_minus_g; + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordMetrumSensor.java b/altoslib/AltosTelemetryRecordMetrumSensor.java new file mode 100644 index 00000000..e41242c5 --- /dev/null +++ b/altoslib/AltosTelemetryRecordMetrumSensor.java @@ -0,0 +1,81 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + + +public class AltosTelemetryRecordMetrumSensor extends AltosTelemetryRecordRaw { + int state; + + int accel; + int pres; + int temp; + + int acceleration; + int speed; + int height; + + int v_batt; + int sense_a; + int sense_m; + + public AltosTelemetryRecordMetrumSensor(int[] in_bytes, int rssi) { + super(in_bytes, rssi); + + state = int8(5); + accel = int16(6); + pres = int32(8); + temp = int16(12); + + acceleration = int16(14); + speed = int16(16); + height = int16(18); + + v_batt = int16(20); + sense_a = int16(22); + sense_m = int16(24); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord n = super.update_state(previous); + + AltosRecordTM2 next; + if (!(n instanceof AltosRecordTM2)) { + next = new AltosRecordTM2(n); + } else { + next = (AltosRecordTM2) n; + } + + next.state = state; + + next.accel = accel; + next.pres = pres; + next.temp = temp; + + next.kalman_acceleration = acceleration / 16.0; + next.kalman_speed = speed / 16.0; + next.kalman_height = height; + + next.v_batt = v_batt; + next.sense_a = sense_a; + next.sense_m = sense_m; + + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;; + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordMini.java b/altoslib/AltosTelemetryRecordMini.java new file mode 100644 index 00000000..75a66c16 --- /dev/null +++ b/altoslib/AltosTelemetryRecordMini.java @@ -0,0 +1,82 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package 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; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 8c1cf2ad..8a41b90c 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -17,7 +17,10 @@ altoslib_JAVA = \ AltosConvert.java \ AltosCRCException.java \ AltosDebug.java \ + AltosEeprom.java \ AltosEepromChunk.java \ + AltosEepromFile.java \ + AltosEepromHeader.java \ AltosEepromIterable.java \ AltosEepromLog.java \ AltosEepromMega.java \ @@ -26,6 +29,7 @@ altoslib_JAVA = \ AltosEepromTeleScience.java \ AltosEepromMini.java \ AltosEepromMiniIterable.java \ + AltosEepromOldIterable.java \ AltosFile.java \ AltosFlash.java \ AltosFlashListener.java \ @@ -65,6 +69,7 @@ altoslib_JAVA = \ AltosSensorMM.java \ AltosSensorTM.java \ AltosState.java \ + AltosStateUpdate.java \ AltosTelemetry.java \ AltosTelemetryIterable.java \ AltosTelemetryMap.java \ @@ -80,6 +85,7 @@ altoslib_JAVA = \ AltosTelemetryRecordSensor.java \ AltosTelemetryRecordMegaSensor.java \ AltosTelemetryRecordMegaData.java \ + AltosTelemetryRecordMini.java \ AltosUnitsListener.java \ AltosMs5607.java \ AltosIMU.java \ -- 2.30.2