diff options
Diffstat (limited to 'altoslib')
100 files changed, 5683 insertions, 3397 deletions
diff --git a/altoslib/AltosAccel.java b/altoslib/AltosAccel.java index d02b3238..b838d30b 100644 --- a/altoslib/AltosAccel.java +++ b/altoslib/AltosAccel.java @@ -15,29 +15,35 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosAccel extends AltosUnits { - public double value(double v) { - if (AltosConvert.imperial_units) + public double value(double v, boolean imperial_units) { + if (imperial_units) return AltosConvert.meters_to_feet(v); return v; } - public String show_units() { - if (AltosConvert.imperial_units) + public double inverse(double v, boolean imperial_units) { + if (imperial_units) + return AltosConvert.feet_to_meters(v); + return v; + } + + public String show_units(boolean imperial_units) { + if (imperial_units) return "ft/s²"; return "m/s²"; } - public String say_units() { - if (AltosConvert.imperial_units) + public String say_units(boolean imperial_units) { + if (imperial_units) return "feet per second squared"; return "meters per second squared"; } - public int show_fraction(int width) { + public int show_fraction(int width, boolean imperial_units) { return width / 9; } }
\ No newline at end of file diff --git a/altoslib/AltosCRCException.java b/altoslib/AltosCRCException.java index 76e79add..be2ec4fe 100644 --- a/altoslib/AltosCRCException.java +++ b/altoslib/AltosCRCException.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosCRCException extends Exception { public int rssi; diff --git a/altoslib/AltosRecordCompanion.java b/altoslib/AltosCompanion.java index b153fb5b..57bb21af 100644 --- a/altoslib/AltosRecordCompanion.java +++ b/altoslib/AltosCompanion.java @@ -15,9 +15,9 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosRecordCompanion { +public class AltosCompanion { public final static int board_id_telescience = 0x0a; public final static int MAX_CHANNELS = 12; @@ -27,7 +27,7 @@ public class AltosRecordCompanion { public int channels; public int[] companion_data; - public AltosRecordCompanion(int in_channels) { + public AltosCompanion(int in_channels) { channels = in_channels; if (channels < 0) channels = 0; diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 2ca5a7a5..1c3085bd 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.util.*; import java.text.*; @@ -336,6 +336,10 @@ public class AltosConfigData implements Iterable<String> { public double frequency() { int channel = radio_channel; int setting = radio_setting; + + if (radio_frequency < 0 && channel < 0 && setting < 0) + return -1; + if (channel < 0) channel = 0; if (setting < 0) diff --git a/altoslib/AltosConfigValues.java b/altoslib/AltosConfigValues.java index 027d10f4..fd5584c2 100644 --- a/altoslib/AltosConfigValues.java +++ b/altoslib/AltosConfigValues.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public interface AltosConfigValues { /* set and get all of the dialog values */ diff --git a/altoslib/AltosConvert.java b/altoslib/AltosConvert.java index a42b36c4..8d0b74dd 100644 --- a/altoslib/AltosConvert.java +++ b/altoslib/AltosConvert.java @@ -18,7 +18,7 @@ /* * Sensor data conversion functions */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosConvert { /* @@ -190,6 +190,46 @@ public class AltosConvert { return ignite / 32767 * 15.0; } + public static double + barometer_to_pressure(double count) + { + return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; + } + + static double + thermometer_to_temperature(double thermo) + { + return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; + } + + static double mega_adc(int raw) { + return raw / 4095.0; + } + + static public double mega_battery_voltage(int v_batt) { + if (v_batt != AltosLib.MISSING) + return 3.3 * mega_adc(v_batt) * (15.0 + 27.0) / 27.0; + return AltosLib.MISSING; + } + + static double mega_pyro_voltage(int raw) { + if (raw != AltosLib.MISSING) + return 3.3 * mega_adc(raw) * (100.0 + 27.0) / 27.0; + return AltosLib.MISSING; + } + + static double tele_mini_voltage(int sensor) { + double supply = 3.3; + + return sensor / 32767.0 * supply * 127/27; + } + + static double easy_mini_voltage(int sensor) { + double supply = 3.0; + + return sensor / 32767.0 * supply * 127/27; + } + public static double radio_to_frequency(int freq, int setting, int cal, int channel) { double f; @@ -242,14 +282,26 @@ public class AltosConvert { return meters * (100 / (2.54 * 12)); } + public static double feet_to_meters(double feet) { + return feet * 12 * 2.54 / 100.0; + } + public static double meters_to_miles(double meters) { return meters_to_feet(meters) / 5280; } + public static double miles_to_meters(double miles) { + return feet_to_meters(miles * 5280); + } + public static double meters_to_mph(double mps) { return meters_to_miles(mps) * 3600; } + public static double mph_to_meters(double mps) { + return miles_to_meters(mps) / 3600; + } + public static double meters_to_mach(double meters) { return meters / 343; /* something close to mach at usual rocket sites */ } @@ -262,6 +314,10 @@ public class AltosConvert { return c * 9/5 + 32; } + public static double f_to_c(double c) { + return (c - 32) * 5/9; + } + public static boolean imperial_units = false; public static AltosDistance distance = new AltosDistance(); diff --git a/altoslib/AltosDebug.java b/altoslib/AltosDebug.java index 4d8e3ae7..fb11d39a 100644 --- a/altoslib/AltosDebug.java +++ b/altoslib/AltosDebug.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; @@ -56,13 +56,10 @@ public class AltosDebug { boolean debug_mode; - void ensure_debug_mode() { + void ensure_debug_mode() throws InterruptedException { if (!debug_mode) { link.printf("D\n"); - try { - link.flush_input(); - } catch (InterruptedException ie) { - } + link.flush_input(); debug_mode = true; } } @@ -81,13 +78,16 @@ public class AltosDebug { } public void close() { - link.close(); + try { + link.close(); + } catch (InterruptedException ie) { + } } /* * Write target memory */ - public void write_memory(int address, byte[] bytes, int start, int len) { + public void write_memory(int address, byte[] bytes, int start, int len) throws InterruptedException { ensure_debug_mode(); // dump_memory("write_memory", address, bytes, start, len); link.printf("O %x %x\n", len, address); @@ -95,7 +95,7 @@ public class AltosDebug { link.printf("%02x", bytes[start + i]); } - public void write_memory(int address, byte[] bytes) { + public void write_memory(int address, byte[] bytes) throws InterruptedException { write_memory(address, bytes, 0, bytes.length); } @@ -132,7 +132,7 @@ public class AltosDebug { /* * Write raw bytes to the debug link using the 'P' command */ - public void write_bytes(byte[] bytes) throws IOException { + public void write_bytes(byte[] bytes) throws IOException, InterruptedException { int i = 0; ensure_debug_mode(); while (i < bytes.length) { @@ -147,7 +147,7 @@ public class AltosDebug { } } - public void write_byte(byte b) throws IOException { + public void write_byte(byte b) throws IOException, InterruptedException { byte[] bytes = { b }; write_bytes(bytes); } @@ -257,12 +257,12 @@ public class AltosDebug { return true; } - public AltosRomconfig romconfig() { + public AltosRomconfig romconfig() throws InterruptedException { try { byte[] bytes = read_memory(0xa0, 10); - return new AltosRomconfig(bytes, 0); + AltosHexfile hexfile = new AltosHexfile (bytes, 0xa0); + return new AltosRomconfig(hexfile); } catch (IOException ie) { - } catch (InterruptedException ie) { } return new AltosRomconfig(); } diff --git a/altoslib/AltosDistance.java b/altoslib/AltosDistance.java index 25028ac7..8d359feb 100644 --- a/altoslib/AltosDistance.java +++ b/altoslib/AltosDistance.java @@ -15,36 +15,42 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosDistance extends AltosUnits { - public double value(double v) { - if (AltosConvert.imperial_units) + public double value(double v, boolean imperial_units) { + if (imperial_units) return AltosConvert.meters_to_miles(v); return v; } - public String show_units() { - if (AltosConvert.imperial_units) + public double inverse(double v, boolean imperial_units) { + if (imperial_units) + return AltosConvert.miles_to_meters(v); + return v; + } + + public String show_units(boolean imperial_units) { + if (imperial_units) return "miles"; return "m"; } - public String say_units() { - if (AltosConvert.imperial_units) + public String say_units(boolean imperial_units) { + if (imperial_units) return "miles"; return "meters"; } - public int show_fraction(int width) { - if (AltosConvert.imperial_units) + public int show_fraction(int width, boolean imperial_units) { + if (imperial_units) return width / 3; return width / 9; } - public int say_fraction() { - if (AltosConvert.imperial_units) + public int say_fraction(boolean imperial_units) { + if (imperial_units) return 1; return 0; } diff --git a/altoslib/AltosEeprom.java b/altoslib/AltosEeprom.java new file mode 100644 index 00000000..dd5993c7 --- /dev/null +++ b/altoslib/AltosEeprom.java @@ -0,0 +1,127 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +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 int data8(int i) { + return data8[i]; + } + + public int data16(int i) { + return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16; + } + + public int data24(int i) { + return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16); + } + + public int data32(int i) { + return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24); + } + + public final static int header_length = 4; + + public abstract int record_length(); + + public void update_state(AltosState state) { + if (cmd == AltosLib.AO_LOG_FLIGHT) + state.set_boost_tick(tick); + else + state.set_tick(tick); + } + + 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"); + } + + public String string() { + String s; + + s = String.format("%c %04x", cmd, tick); + if (data8 != null) { + for (int i = 0; i < data8.length; i++) { + String d = String.format(" %02x", data8[i]); + s = s.concat(d); + } + } + s = s.concat("\n"); + return s; + } + + void parse_chunk(AltosEepromChunk chunk, int start) 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) { + 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/AltosEepromChunk.java b/altoslib/AltosEepromChunk.java index b1bba3bb..c03fa931 100644 --- a/altoslib/AltosEepromChunk.java +++ b/altoslib/AltosEepromChunk.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; import java.util.concurrent.*; @@ -62,6 +62,34 @@ public class AltosEepromChunk { return true; } + public AltosEeprom eeprom(int offset, int log_format, AltosState state) throws ParseException { + AltosEeprom eeprom = null; + switch (log_format) { + case AltosLib.AO_LOG_FORMAT_FULL: + eeprom = new AltosEepromTM(this, offset); + break; + case AltosLib.AO_LOG_FORMAT_TINY: + eeprom = new AltosEepromTm(this, offset, state); + break; + case AltosLib.AO_LOG_FORMAT_TELEMETRY: + case AltosLib.AO_LOG_FORMAT_TELESCIENCE: + break; + case AltosLib.AO_LOG_FORMAT_TELEMEGA: + eeprom = new AltosEepromMega(this, offset); + break; + case AltosLib.AO_LOG_FORMAT_TELEMETRUM: + eeprom = new AltosEepromMetrum2(this, offset); + break; + case AltosLib.AO_LOG_FORMAT_TELEMINI: + case AltosLib.AO_LOG_FORMAT_EASYMINI: + eeprom = new AltosEepromMini(this, offset); + break; + default: + throw new ParseException("unknown eeprom format " + log_format, 0); + } + return eeprom; + } + public AltosEepromChunk(AltosLink link, int block, boolean flush) throws TimeoutException, InterruptedException { diff --git a/altoslib/AltosEepromDownload.java b/altoslib/AltosEepromDownload.java new file mode 100644 index 00000000..1b043167 --- /dev/null +++ b/altoslib/AltosEepromDownload.java @@ -0,0 +1,261 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public class AltosEepromDownload implements Runnable { + + AltosLink link; + boolean remote; + Thread eeprom_thread; + AltosEepromMonitor monitor; + + boolean want_file; + FileWriter eeprom_file; + LinkedList<String> eeprom_pending; + + AltosEepromList flights; + boolean success; + ParseException parse_exception; + AltosState state; + + private void FlushPending() throws IOException { + for (String s : flights.config_data) { + eeprom_file.write(s); + eeprom_file.write('\n'); + } + + for (String s : eeprom_pending) + eeprom_file.write(s); + } + + private void CheckFile(boolean force) throws IOException { + if (eeprom_file != null) + return; + if (force || (state.flight != 0 && want_file)) { + AltosFile eeprom_name; + AltosGPS gps = state.gps; + + if (gps != null && + gps.year != AltosLib.MISSING && + gps.month != AltosLib.MISSING && + gps.day != AltosLib.MISSING) + { + eeprom_name = new AltosFile(gps.year, gps.month, gps.day, + state.serial, state.flight, "eeprom"); + } else + eeprom_name = new AltosFile(state.serial, state.flight, "eeprom"); + + eeprom_file = new FileWriter(eeprom_name); + if (eeprom_file != null) { + monitor.set_filename(eeprom_name.getName()); + FlushPending(); + eeprom_pending = null; + } + } + } + + boolean done; + boolean start; + + void LogEeprom(AltosEeprom r) throws IOException { + if (r.cmd != AltosLib.AO_LOG_INVALID) { + String line = r.string(); + if (eeprom_file != null) + eeprom_file.write(line); + else + eeprom_pending.add(line); + } + } + + void CaptureEeprom(AltosEepromChunk eechunk, int log_format) throws IOException, ParseException { + boolean any_valid = false; + boolean got_flight = false; + + int record_length = 8; + + state.set_serial(flights.config_data.serial); + monitor.set_serial(flights.config_data.serial); + + for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += record_length) { + AltosEeprom r = eechunk.eeprom(i, log_format, state); + + if (r == null) + continue; + + record_length = r.record_length(); + + r.update_state(state); + + if (!got_flight && state.flight != AltosLib.MISSING) + monitor.set_flight(state.flight); + + /* Monitor state transitions to update display */ + if (state.state != AltosLib.ao_flight_invalid && + state.state <= AltosLib.ao_flight_landed) + { + if (state.state > AltosLib.ao_flight_pad) + want_file = true; + if (state.state == AltosLib.ao_flight_landed) + done = true; + } + + if (state.gps != null) + want_file = true; + + if (r.valid) { + any_valid = true; + LogEeprom(r); + } + } + if (!any_valid) + done = true; + + CheckFile(false); + } + + void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException, ParseException { + int block, state_block = 0; + int log_format = flights.config_data.log_format; + + state = new AltosState(); + + done = false; + start = true; + + if (flights.config_data.serial < 0) + throw new IOException("no serial number found"); + + /* Reset per-capture variables */ + want_file = false; + eeprom_file = null; + eeprom_pending = new LinkedList<String>(); + + /* Set serial number in the monitor dialog window */ + /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */ + + state_block = log.start_block; + for (block = log.start_block; !done && block < log.end_block; block++) { + monitor.set_value(state.state_name(), + state.state, + block - state_block, + block - log.start_block); + + AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == log.start_block); + + /* + * Guess what kind of data is there if the device + * didn't tell us + */ + + if (log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN) { + if (block == log.start_block) { + if (eechunk.data(0) == AltosLib.AO_LOG_FLIGHT) + log_format = AltosLib.AO_LOG_FORMAT_FULL; + else + log_format = AltosLib.AO_LOG_FORMAT_TINY; + } + } + + CaptureEeprom (eechunk, log_format); + } + CheckFile(true); + if (eeprom_file != null) { + eeprom_file.flush(); + eeprom_file.close(); + } + } + + public void run () { + try { + boolean failed = false; + if (remote) + link.start_remote(); + + for (AltosEepromLog log : flights) { + parse_exception = null; + if (log.selected) { + monitor.reset(); + try { + CaptureLog(log); + } catch (ParseException e) { + parse_exception = e; + } + } + if (parse_exception != null) { + failed = true; + monitor.show_message(String.format("Flight %d download error\n%s\nValid log data saved", + log.flight, + parse_exception.getMessage()), + link.name, + AltosEepromMonitor.WARNING_MESSAGE); + } + } + success = !failed; + } catch (IOException ee) { + monitor.show_message(ee.getLocalizedMessage(), + link.name, + AltosEepromMonitor.ERROR_MESSAGE); + } catch (InterruptedException ie) { + monitor.show_message(String.format("Connection to \"%s\" interrupted", + link.name), + "Connection Interrupted", + AltosEepromMonitor.ERROR_MESSAGE); + } catch (TimeoutException te) { + monitor.show_message(String.format("Connection to \"%s\" failed", + link.name), + "Connection Failed", + AltosEepromMonitor.ERROR_MESSAGE); + } finally { + if (remote) { + try { + link.stop_remote(); + } catch (InterruptedException ie) { + } + } + link.flush_output(); + } + monitor.done(success); + } + + public void start() { + eeprom_thread = new Thread(this); + monitor.set_thread(eeprom_thread); + eeprom_thread.start(); + } + + public AltosEepromDownload(AltosEepromMonitor given_monitor, + AltosLink given_link, + boolean given_remote, + AltosEepromList given_flights) { + + monitor = given_monitor; + link = given_link; + remote = given_remote; + flights = given_flights; + success = false; + + monitor.set_states(AltosLib.ao_flight_boost, AltosLib.ao_flight_landed); + + monitor.start(); + } +} diff --git a/altoslib/AltosEepromFile.java b/altoslib/AltosEepromFile.java new file mode 100644 index 00000000..60ab2573 --- /dev/null +++ b/altoslib/AltosEepromFile.java @@ -0,0 +1,123 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; + +class AltosEepromIterator implements Iterator<AltosState> { + AltosState state; + Iterator<AltosEeprom> body; + AltosEeprom next; + boolean seen; + + public boolean hasNext() { + return !seen || body.hasNext(); + } + + public AltosState next() { + if (seen) { + AltosState n = state.clone(); + AltosEeprom e = body.next(); + + e.update_state(n); + state = n; + } + seen = true; + return state; + } + + public void remove () { + } + + public AltosEepromIterator(AltosState start, Iterator<AltosEeprom> body) { + this.state = start; + this.body = body; + this.seen = false; + } +} + +public class AltosEepromFile extends AltosStateIterable { + + AltosEepromIterable headers; + AltosEepromIterable body; + AltosState start; + + public void write_comments(PrintStream out) { + headers.write(out); + } + + public void write(PrintStream out) { + headers.write(out); + body.write(out); + } + + public AltosEepromFile(FileInputStream input) { + headers = new AltosEepromIterable(AltosEepromHeader.read(input)); + + start = headers.state(); + start.set_state(AltosLib.ao_flight_pad); + + switch (start.log_format) { + case AltosLib.AO_LOG_FORMAT_FULL: + body = new AltosEepromIterable(AltosEepromTM.read(input)); + break; + case AltosLib.AO_LOG_FORMAT_TINY: + body = new AltosEepromIterable(AltosEepromTm.read(input)); + break; + case AltosLib.AO_LOG_FORMAT_TELEMETRY: + case AltosLib.AO_LOG_FORMAT_TELESCIENCE: + case AltosLib.AO_LOG_FORMAT_TELEMEGA: + body = new AltosEepromIterable(AltosEepromMega.read(input)); + break; + case AltosLib.AO_LOG_FORMAT_TELEMETRUM: + body = new AltosEepromIterable(AltosEepromMetrum2.read(input)); + break; + case AltosLib.AO_LOG_FORMAT_TELEMINI: + case AltosLib.AO_LOG_FORMAT_EASYMINI: + body = new AltosEepromIterable(AltosEepromMini.read(input)); + break; + default: + body = new AltosEepromIterable(new LinkedList<AltosEeprom>()); + break; + } + + /* Find boost tick */ + AltosState state = start.clone(); + for (AltosEeprom eeprom : body) { + eeprom.update_state(state); + state.finish_update(); + if (state.state >= AltosLib.ao_flight_boost) { + start.set_boost_tick(state.tick); + break; + } + } + } + + public Iterator<AltosState> iterator() { + AltosState state = start.clone(); + Iterator<AltosEeprom> i = body.iterator(); + + while (i.hasNext() && !state.valid()) { + i.next().update_state(state); + state.finish_update(); + } + return new AltosEepromIterator(state, i); + } +}
\ No newline at end of file diff --git a/altoslib/AltosEepromHeader.java b/altoslib/AltosEepromHeader.java new file mode 100644 index 00000000..0aeb78dd --- /dev/null +++ b/altoslib/AltosEepromHeader.java @@ -0,0 +1,278 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +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 int record_length () { return 0; } + + /* XXX pull rest of config data to state */ + 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.set_callsign(data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + state.set_accel_g(config_a, 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.set_serial(config_a); + break; + case AltosLib.AO_LOG_BARO_RESERVED: + state.make_baro(); + state.baro.reserved = config_a; + break; + case AltosLib.AO_LOG_BARO_SENS: + state.make_baro(); + state.baro.sens = config_a; + break; + case AltosLib.AO_LOG_BARO_OFF: + state.make_baro(); + state.baro.off = config_a; + break; + case AltosLib.AO_LOG_BARO_TCS: + state.make_baro(); + state.baro.tcs = config_a; + break; + case AltosLib.AO_LOG_BARO_TCO: + state.make_baro(); + state.baro.tco = config_a; + break; + case AltosLib.AO_LOG_BARO_TREF: + state.make_baro(); + state.baro.tref = config_a; + break; + case AltosLib.AO_LOG_BARO_TEMPSENS: + state.make_baro(); + state.baro.tempsens = config_a; + break; + case AltosLib.AO_LOG_BARO_CRC: + state.make_baro(); + state.baro.crc = config_a; + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + state.set_firmware_version(data); + break; + } + } + + public void write(PrintStream out) { + switch (cmd) { + case AltosLib.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", data); + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", config_a); + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", config_a); + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", config_a); + break; + case AltosLib.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", config_a, config_b); + break; + case AltosLib.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", config_a); + break; + case AltosLib.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", config_a); + break; + case AltosLib.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", data); + break; + case AltosLib.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", data); + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", config_a); + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", data); + break; + case AltosLib.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", config_a); + break; + case AltosLib.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", config_a); + break; + case AltosLib.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", config_a); + break; + case AltosLib.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", config_a); + break; + case AltosLib.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", config_a); + break; + case AltosLib.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", config_a); + break; + case AltosLib.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", config_a); + break; + case AltosLib.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", config_a); + break; + } + } + + public AltosEepromHeader (String[] tokens) { + last = false; + valid = true; + try { + if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = AltosLib.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = AltosLib.AO_LOG_MAIN_DEPLOY; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { + cmd = AltosLib.AO_LOG_APOGEE_DELAY; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { + cmd = AltosLib.AO_LOG_RADIO_CHANNEL; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Callsign:")) { + cmd = AltosLib.AO_LOG_CALLSIGN; + data = tokens[1].replaceAll("\"",""); + } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { + cmd = AltosLib.AO_LOG_ACCEL_CAL; + config_a = Integer.parseInt(tokens[3]); + config_b = Integer.parseInt(tokens[5]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { + cmd = AltosLib.AO_LOG_RADIO_CAL; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { + cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; + config_a = Integer.parseInt(tokens[3]); + } else if (tokens[0].equals("manufacturer")) { + cmd = AltosLib.AO_LOG_MANUFACTURER; + data = tokens[1]; + } else if (tokens[0].equals("product")) { + cmd = AltosLib.AO_LOG_PRODUCT; + data = tokens[1]; + } else if (tokens[0].equals("serial-number")) { + cmd = AltosLib.AO_LOG_SERIAL_NUMBER; + config_a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("log-format")) { + cmd = AltosLib.AO_LOG_LOG_FORMAT; + config_a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("software-version")) { + cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; + data = tokens[1]; + last = true; + } else if (tokens[0].equals("ms5607")) { + if (tokens[1].equals("reserved:")) { + cmd = AltosLib.AO_LOG_BARO_RESERVED; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("sens:")) { + cmd = AltosLib.AO_LOG_BARO_SENS; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("off:")) { + cmd = AltosLib.AO_LOG_BARO_OFF; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tcs:")) { + cmd = AltosLib.AO_LOG_BARO_TCS; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tco:")) { + cmd = AltosLib.AO_LOG_BARO_TCO; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tref:")) { + cmd = AltosLib.AO_LOG_BARO_TREF; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tempsens:")) { + cmd = AltosLib.AO_LOG_BARO_TEMPSENS; + config_a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("crc:")) { + cmd = AltosLib.AO_LOG_BARO_CRC; + config_a = Integer.parseInt(tokens[2]); + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = tokens[2]; + } + } else + valid = false; + } catch (Exception e) { + valid = false; + } + } + + static public LinkedList<AltosEeprom> read(FileInputStream input) { + LinkedList<AltosEeprom> headers = new LinkedList<AltosEeprom>(); + + for (;;) { + try { + String line = AltosLib.gets(input); + if (line == null) + break; + AltosEepromHeader header = new AltosEepromHeader(line); + headers.add(header); + if (header.last) + break; + } catch (IOException ie) { + break; + } + } + + return headers; + } + + static public void write (PrintStream out, LinkedList<AltosEepromHeader> headers) { + out.printf("# Comments\n"); + for (AltosEepromHeader header : headers) { + header.write(out); + } + + } + + public AltosEepromHeader (String line) { + this(line.split("\\s+")); + } +} diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index b84574ef..fc793579 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Keith Packard <keithp@keithp.com> + * Copyright © 2013 Keith Packard <keithp@keithp.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,421 +15,105 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.*; import java.text.*; -public class AltosEepromIterable extends AltosRecordIterable { +class AltosEepromOrdered implements Comparable<AltosEepromOrdered> { + AltosEeprom eeprom; + int index; + int tick; - static final int seen_basic = AltosRecord.seen_flight|AltosRecord.seen_sensor; - - boolean has_accel; - boolean has_gps; - boolean has_ignite; - - AltosEepromRecord flight_record; - AltosEepromRecord gps_date_record; - - TreeSet<AltosOrderedRecord> records; - - LinkedList<AltosRecord> list; - - class EepromState { - int seen; - int n_pad_samples; - double ground_pres; - int gps_tick; - int boost_tick; - int sensor_tick; - - EepromState() { - seen = 0; - n_pad_samples = 0; - ground_pres = 0.0; - gps_tick = 0; - } + int cmdi() { + if (eeprom.cmd == AltosLib.AO_LOG_FLIGHT) + return 0; + return 1; } - 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(); + public int compareTo(AltosEepromOrdered o) { + int cmd_diff = cmdi() - o.cmdi(); - /* 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); + if (cmd_diff != 0) + return cmd_diff; - 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; + int tick_diff = tick - o.tick; - 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; + if (tick_diff != 0) + return tick_diff; + return index - o.index; } - LinkedList<AltosRecord> make_list() { - LinkedList<AltosRecord> list = new LinkedList<AltosRecord>(); - Iterator<AltosOrderedRecord> iterator = records.iterator(); - AltosOrderedRecord record = null; - AltosRecordTM state = new AltosRecordTM(); - //boolean last_reported = false; - EepromState eeprom = new EepromState(); - - state.state = AltosLib.ao_flight_pad; - state.accel_plus_g = 15758; - state.accel_minus_g = 16294; - state.flight_vel = 0; - - /* Pull in static data from the flight and gps_date records */ - if (flight_record != null) - update_state(state, flight_record, eeprom); - if (gps_date_record != null) - update_state(state, gps_date_record, eeprom); + AltosEepromOrdered (AltosEeprom eeprom, int index, int tick) { + this.eeprom = eeprom; + this.index = index; + this.tick = tick; + } +} - 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); +class AltosEepromOrderedIterator implements Iterator<AltosEeprom> { + TreeSet<AltosEepromOrdered> olist; + Iterator<AltosEepromOrdered> oiterator; + + public AltosEepromOrderedIterator(Iterable<AltosEeprom> eeproms) { + olist = new TreeSet<AltosEepromOrdered>(); + + int tick = 0; + int index = 0; + boolean first = true; + + for (AltosEeprom e : eeproms) { + int t = e.tick; + if (first) + tick = t; + else { + while (t < tick - 32767) + t += 65536; + tick = t; } - update_state(state, record, eeprom); + olist.add(new AltosEepromOrdered(e, index++, tick)); + first = false; } - AltosRecordTM r = state.clone(); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - return list; - } - public Iterator<AltosRecord> iterator() { - if (list == null) - list = make_list(); - return list.iterator(); + oiterator = olist.iterator(); } - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; } - - public void write_comments(PrintStream out) { - Iterator<AltosOrderedRecord> iterator = records.iterator(); - out.printf("# Comments\n"); - while (iterator.hasNext()) { - AltosOrderedRecord record = iterator.next(); - switch (record.cmd) { - case AltosLib.AO_LOG_CONFIG_VERSION: - out.printf("# Config version: %s\n", record.data); - break; - case AltosLib.AO_LOG_MAIN_DEPLOY: - out.printf("# Main deploy: %s\n", record.a); - break; - case AltosLib.AO_LOG_APOGEE_DELAY: - out.printf("# Apogee delay: %s\n", record.a); - break; - case AltosLib.AO_LOG_RADIO_CHANNEL: - out.printf("# Radio channel: %s\n", record.a); - break; - case AltosLib.AO_LOG_CALLSIGN: - out.printf("# Callsign: %s\n", record.data); - break; - case AltosLib.AO_LOG_ACCEL_CAL: - out.printf ("# Accel cal: %d %d\n", record.a, record.b); - break; - case AltosLib.AO_LOG_RADIO_CAL: - out.printf ("# Radio cal: %d\n", record.a); - break; - case AltosLib.AO_LOG_MAX_FLIGHT_LOG: - out.printf ("# Max flight log: %d\n", record.a); - break; - case AltosLib.AO_LOG_MANUFACTURER: - out.printf ("# Manufacturer: %s\n", record.data); - break; - case AltosLib.AO_LOG_PRODUCT: - out.printf ("# Product: %s\n", record.data); - break; - case AltosLib.AO_LOG_SERIAL_NUMBER: - out.printf ("# Serial number: %d\n", record.a); - break; - case AltosLib.AO_LOG_SOFTWARE_VERSION: - out.printf ("# Software version: %s\n", record.data); - break; - case AltosLib.AO_LOG_BARO_RESERVED: - out.printf ("# Baro reserved: %d\n", record.a); - break; - case AltosLib.AO_LOG_BARO_SENS: - out.printf ("# Baro sens: %d\n", record.a); - break; - case AltosLib.AO_LOG_BARO_OFF: - out.printf ("# Baro off: %d\n", record.a); - break; - case AltosLib.AO_LOG_BARO_TCS: - out.printf ("# Baro tcs: %d\n", record.a); - break; - case AltosLib.AO_LOG_BARO_TCO: - out.printf ("# Baro tco: %d\n", record.a); - break; - case AltosLib.AO_LOG_BARO_TREF: - out.printf ("# Baro tref: %d\n", record.a); - break; - case AltosLib.AO_LOG_BARO_TEMPSENS: - out.printf ("# Baro tempsens: %d\n", record.a); - break; - case AltosLib.AO_LOG_BARO_CRC: - out.printf ("# Baro crc: %d\n", record.a); - break; - } - } + public boolean hasNext() { + return oiterator.hasNext(); } - /* - * 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); + public AltosEeprom next() { + return oiterator.next().eeprom; } - /* - * Read the whole file, dumping records into a RB tree so - * we can enumerate them in time order -- the eeprom data - * are sometimes out of order with GPS data getting timestamps - * matching the first packet out of the GPS unit but not - * written until the final GPS packet has been received. - */ - public AltosEepromIterable (FileInputStream input) { - records = new TreeSet<AltosOrderedRecord>(); - - AltosOrderedRecord last_gps_time = null; - - int index = 0; - int prev_tick = 0; - boolean prev_tick_valid = false; - boolean missing_time = false; + public void remove () { + } +} - 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; - } +public class AltosEepromIterable implements Iterable<AltosEeprom> { + public LinkedList<AltosEeprom> eeproms; - /* 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; - } + public void write(PrintStream out) { + for (AltosEeprom eeprom : eeproms) + eeprom.write(out); + } - /* go back and fix up any missing time values */ - if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { - last_gps_time = record; - if (missing_time) { - Iterator<AltosOrderedRecord> iterator = records.iterator(); - while (iterator.hasNext()) { - AltosOrderedRecord old = iterator.next(); - if (old.cmd == AltosLib.AO_LOG_GPS_TIME && - old.a == -1 && old.b == -1) - { - update_time(record, old); - } - } - missing_time = false; - } - } + public AltosState state() { + AltosState state = new AltosState(); - 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; + for (AltosEeprom header : eeproms) + header.update_state(state); + return state; + } - records.add(add_gps_time); - record.index = index++; - } - } - records.add(record); + public AltosEepromIterable(LinkedList<AltosEeprom> eeproms) { + this.eeproms = eeproms; + } - /* Bail after reading the 'landed' record; we're all done */ - if (record.cmd == AltosLib.AO_LOG_STATE && - record.a == AltosLib.ao_flight_landed) - break; - } - } catch (IOException io) { - } catch (ParseException pe) { - } - try { - input.close(); - } catch (IOException ie) { - } + public Iterator<AltosEeprom> iterator() { + if (eeproms == null) + eeproms = new LinkedList<AltosEeprom>(); + return new AltosEepromOrderedIterator(eeproms); } -} +}
\ No newline at end of file diff --git a/altoslib/AltosEepromList.java b/altoslib/AltosEepromList.java new file mode 100644 index 00000000..763bd1e2 --- /dev/null +++ b/altoslib/AltosEepromList.java @@ -0,0 +1,117 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +/* + * Temporary structure to hold the list of stored flights; + * each of these will be queried in turn to generate more + * complete information + */ + +class AltosEepromFlight { + int flight; + int start; + int end; + + public AltosEepromFlight(int in_flight, int in_start, int in_end) { + flight = in_flight; + start = in_start; + end = in_end; + } +} + +/* + * Construct a list of flights available in a connected device + */ + +public class AltosEepromList extends ArrayList<AltosEepromLog> { + public AltosConfigData config_data; + + public AltosEepromList (AltosLink link, boolean remote) + throws IOException, InterruptedException, TimeoutException + { + try { + if (remote) + link.start_remote(); + config_data = new AltosConfigData (link); +// if (config_data.serial == 0) +// throw new IOException("no serial number found"); + + ArrayList<AltosEepromFlight> flights = new ArrayList<AltosEepromFlight>(); + + if (config_data.flight_log_max != 0 || config_data.log_format != 0) { + + /* Devices with newer firmware will support the 'l' + * command which will list the region of storage + * occupied by each available flight + */ + link.printf("l\n"); + for (;;) { + String line = link.get_reply(5000); + if (line == null) + throw new TimeoutException(); + if (line.contains("done")) + break; + if (line.contains("Syntax")) + continue; + String[] tokens = line.split("\\s+"); + if (tokens.length < 6) + break; + + int flight = -1, start = -1, end = -1; + try { + if (tokens[0].equals("flight")) + flight = AltosParse.parse_int(tokens[1]); + if (tokens[2].equals("start")) + start = AltosParse.parse_hex(tokens[3]); + if (tokens[4].equals("end")) + end = AltosParse.parse_hex(tokens[5]); + if (flight > 0 && start >= 0 && end > 0) + flights.add(new AltosEepromFlight(flight, start, end)); + } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); } + } + } else { + + /* Older devices will hold only a single + * flight. This also assumes that any older + * device will have a 1MB flash device + */ + flights.add(new AltosEepromFlight(0, 0, 0xfff)); + } + + /* With the list of flights collected, collect more complete + * information on them by reading the first block or two of + * data. This will add GPS coordinates and a date. For older + * firmware, this will also extract the flight number. + */ + for (AltosEepromFlight flight : flights) { + add(new AltosEepromLog(config_data, link, + flight.flight, flight.start, flight.end)); + } + } finally { + if (remote) + link.stop_remote(); + link.flush_output(); + } + } +}
\ No newline at end of file diff --git a/altoslib/AltosEepromLog.java b/altoslib/AltosEepromLog.java index 20026c6d..95c0c3f6 100644 --- a/altoslib/AltosEepromLog.java +++ b/altoslib/AltosEepromLog.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; import java.util.concurrent.*; @@ -72,9 +72,9 @@ public class AltosEepromLog { for (block = in_start_block; block < in_end_block; block++) { AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == in_start_block); - for (int i = 0; i < AltosEepromChunk.chunk_size; i += AltosEepromRecord.record_length) { + for (int i = 0; i < AltosEepromChunk.chunk_size; i += AltosEepromTM.record_length) { try { - AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + AltosEepromTM r = new AltosEepromTM(eechunk, i); if (r.cmd == AltosLib.AO_LOG_FLIGHT) { flight = r.b; diff --git a/altoslib/AltosEepromMega.java b/altoslib/AltosEepromMega.java index b077e26c..7a4ee52d 100644 --- a/altoslib/AltosEepromMega.java +++ b/altoslib/AltosEepromMega.java @@ -15,34 +15,16 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; +import java.io.*; +import java.util.*; import java.text.*; -public class AltosEepromMega { - public int cmd; - public int tick; - public boolean valid; - public String data; - public int config_a, config_b; - - public int data8[]; - +public class AltosEepromMega extends AltosEeprom { public static final int record_length = 32; - 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); - } + public int record_length() { return record_length; } /* AO_LOG_FLIGHT elements */ public int flight() { return data16(0); } @@ -68,11 +50,12 @@ public class AltosEepromMega { public int mag_z() { return data16(24); } public int accel() { return data16(26); } - /* AO_LOG_VOLT elements */ + /* AO_LOG_TEMP_VOLT elements */ public int v_batt() { return data16(0); } public int v_pbatt() { return data16(2); } public int nsense() { return data16(4); } public int sense(int i) { return data16(6 + i * 2); } + public int pyro() { return data16(26); } /* AO_LOG_GPS_TIME elements */ public int latitude() { return data32(0); } @@ -90,131 +73,139 @@ public class AltosEepromMega { public int nsat() { return data16(0); } public int svid(int n) { return data8(2 + n * 2); } public int c_n(int n) { return data8(2 + n * 2 + 1); } + public AltosEepromMega (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; - } + parse_chunk(chunk, start); + } - tick = chunk.data16(start+2); + public void update_state(AltosState state) { + super.update_state(state); + + AltosGPS gps; + + /* Flush any pending GPS changes */ + if (state.gps_pending) { + switch (cmd) { + case AltosLib.AO_LOG_GPS_LAT: + case AltosLib.AO_LOG_GPS_LON: + case AltosLib.AO_LOG_GPS_ALT: + case AltosLib.AO_LOG_GPS_SAT: + case AltosLib.AO_LOG_GPS_DATE: + break; + default: + state.set_temp_gps(); + break; + } + } - data8 = new int[data_length]; - for (int i = 0; i < data_length; i++) - data8[i] = chunk.data(start + header_length + i); + switch (cmd) { + case AltosLib.AO_LOG_FLIGHT: + state.set_boost_tick(tick); + state.set_flight(flight()); + state.set_ground_accel(ground_accel()); + state.set_ground_pressure(ground_pres()); + state.set_temperature(ground_temp() / 100.0); + break; + case AltosLib.AO_LOG_STATE: + state.set_tick(tick); + state.set_state(state()); + break; + case AltosLib.AO_LOG_SENSOR: + state.set_tick(tick); + state.set_ms5607(pres(), temp()); + + AltosIMU imu = new AltosIMU(); + imu.accel_x = accel_x(); + imu.accel_y = accel_y(); + imu.accel_z = accel_z(); + + imu.gyro_x = gyro_x(); + imu.gyro_y = gyro_y(); + imu.gyro_z = gyro_z(); + state.imu = imu; + + AltosMag mag = new AltosMag(); + mag.x = mag_x(); + mag.y = mag_y(); + mag.z = mag_z(); + + state.mag = mag; + + state.set_accel(accel()); + + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt())); + state.set_pyro_voltage(AltosConvert.mega_pyro_voltage(v_pbatt())); + + int nsense = nsense(); + + state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense(nsense-2))); + state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense(nsense-1))); + + double voltages[] = new double[nsense-2]; + for (int i = 0; i < nsense-2; i++) + voltages[i] = AltosConvert.mega_pyro_voltage(sense(i)); + + state.set_ignitor_voltage(voltages); + break; + case AltosLib.AO_LOG_GPS_TIME: + state.set_tick(tick); + gps = state.make_temp_gps(false); + gps.lat = latitude() / 1e7; + gps.lon = longitude() / 1e7; + gps.alt = altitude(); + + gps.hour = hour(); + gps.minute = minute(); + gps.second = second(); + + int flags = flags(); + + 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; + + gps.year = 2000 + year(); + gps.month = month(); + gps.day = day(); + break; + case AltosLib.AO_LOG_GPS_SAT: + state.set_tick(tick); + gps = state.make_temp_gps(true); + + int n = nsat(); + for (int i = 0; i < n; i++) + gps.add_sat(svid(i), c_n(i)); + break; + } } public AltosEepromMega (String line) { - valid = false; - tick = 0; + parse_string(line); + } - if (line == null) { - cmd = AltosLib.AO_LOG_INVALID; - line = ""; - } else { + static public LinkedList<AltosEeprom> read(FileInputStream input) { + LinkedList<AltosEeprom> megas = new LinkedList<AltosEeprom>(); + + for (;;) { 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; + String line = AltosLib.gets(input); + if (line == null) + break; + try { + AltosEepromMega mega = new AltosEepromMega(line); + if (mega.cmd != AltosLib.AO_LOG_INVALID) + megas.add(mega); + } catch (Exception e) { + System.out.printf ("exception\n"); } - } catch (NumberFormatException ne) { - cmd = AltosLib.AO_LOG_INVALID; - data = line; + } catch (IOException ie) { + break; } } - } - public AltosEepromMega(int in_cmd, int in_tick) { - cmd = in_cmd; - tick = in_tick; - valid = true; + return megas; } } diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java deleted file mode 100644 index 5736f937..00000000 --- a/altoslib/AltosEepromMegaIterable.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright © 2010 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -import java.io.*; -import java.util.*; -import java.text.*; - -public class AltosEepromMegaIterable 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; - - AltosEepromMega flight_record; - AltosEepromMega gps_date_record; - - TreeSet<AltosOrderedMegaRecord> records; - - AltosMs5607 baro; - - LinkedList<AltosRecord> list; - - class EepromState { - int seen; - int n_pad_samples; - double ground_pres; - int gps_tick; - int boost_tick; - int sensor_tick; - - EepromState() { - seen = 0; - n_pad_samples = 0; - ground_pres = 0.0; - gps_tick = 0; - } - } - - void update_state(AltosRecordMM state, AltosEepromMega 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_SENSOR: - state.accel = record.accel(); - baro.set(record.pres(), record.temp()); - state.pres = baro.pa; - state.temp = baro.cc; - state.imu = new AltosIMU(); - state.imu.accel_x = record.accel_x(); - state.imu.accel_y = record.accel_y(); - state.imu.accel_z = record.accel_z(); - state.imu.gyro_x = record.gyro_x(); - state.imu.gyro_y = record.gyro_y(); - state.imu.gyro_z = record.gyro_z(); - state.mag = new AltosMag(); - state.mag.x = record.mag_x(); - state.mag.y = record.mag_y(); - state.mag.z = record.mag_z(); - 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.v_pyro = record.v_pbatt(); - for (int i = 0; i < record.nsense(); i++) - state.sense[i] = record.sense(i); - eeprom.seen |= seen_temp_volt; - break; - case AltosLib.AO_LOG_STATE: - state.state = record.state(); - break; - case AltosLib.AO_LOG_GPS_TIME: - 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(); - 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.nsat(); - for (int i = 0; i < nsat; i++) - state.gps.add_sat(record.svid(i), record.c_n(i)); - } - break; - case AltosLib.AO_LOG_CONFIG_VERSION: - break; - case AltosLib.AO_LOG_MAIN_DEPLOY: - break; - case AltosLib.AO_LOG_APOGEE_DELAY: - break; - case AltosLib.AO_LOG_RADIO_CHANNEL: - break; - case AltosLib.AO_LOG_CALLSIGN: - state.callsign = record.data; - break; - case AltosLib.AO_LOG_ACCEL_CAL: - state.accel_plus_g = record.config_a; - state.accel_minus_g = record.config_b; - break; - case AltosLib.AO_LOG_RADIO_CAL: - break; - case AltosLib.AO_LOG_MANUFACTURER: - break; - case AltosLib.AO_LOG_PRODUCT: - break; - case AltosLib.AO_LOG_SERIAL_NUMBER: - state.serial = record.config_a; - break; - case AltosLib.AO_LOG_SOFTWARE_VERSION: - break; - case AltosLib.AO_LOG_BARO_RESERVED: - baro.reserved = record.config_a; - break; - case AltosLib.AO_LOG_BARO_SENS: - baro.sens =record.config_a; - break; - case AltosLib.AO_LOG_BARO_OFF: - baro.off =record.config_a; - break; - case AltosLib.AO_LOG_BARO_TCS: - baro.tcs =record.config_a; - break; - case AltosLib.AO_LOG_BARO_TCO: - baro.tco =record.config_a; - break; - case AltosLib.AO_LOG_BARO_TREF: - baro.tref =record.config_a; - break; - case AltosLib.AO_LOG_BARO_TEMPSENS: - baro.tempsens =record.config_a; - break; - case AltosLib.AO_LOG_BARO_CRC: - baro.crc =record.config_a; - break; - } - state.seen |= eeprom.seen; - } - - LinkedList<AltosRecord> make_list() { - LinkedList<AltosRecord> list = new LinkedList<AltosRecord>(); - Iterator<AltosOrderedMegaRecord> iterator = records.iterator(); - AltosOrderedMegaRecord record = null; - AltosRecordMM state = new AltosRecordMM(); - //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) { - AltosRecordMM r = state.clone(); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - } - update_state(state, record, eeprom); - } - AltosRecordMM r = state.clone(); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - return list; - } - - public Iterator<AltosRecord> iterator() { - if (list == null) - list = make_list(); - return list.iterator(); - } - - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; } - - public void write_comments(PrintStream out) { - Iterator<AltosOrderedMegaRecord> iterator = records.iterator(); - out.printf("# Comments\n"); - while (iterator.hasNext()) { - AltosOrderedMegaRecord 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 AltosEepromMegaIterable (FileInputStream input) { - records = new TreeSet<AltosOrderedMegaRecord>(); - - AltosOrderedMegaRecord 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; - AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(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/AltosEepromMetrum2.java b/altoslib/AltosEepromMetrum2.java new file mode 100644 index 00000000..c1d62c0c --- /dev/null +++ b/altoslib/AltosEepromMetrum2.java @@ -0,0 +1,177 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromMetrum2 extends AltosEeprom { + public static final int record_length = 16; + + public int record_length() { return record_length; } + + /* 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 nsat() { 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 AltosEepromMetrum2 (AltosEepromChunk chunk, int start) throws ParseException { + parse_chunk(chunk, start); + } + + public void update_state(AltosState state) { + super.update_state(state); + + AltosGPS gps; + + /* Flush any pending GPS changes */ + if (state.gps_pending) { + switch (cmd) { + case AltosLib.AO_LOG_GPS_POS: + case AltosLib.AO_LOG_GPS_LAT: + case AltosLib.AO_LOG_GPS_LON: + case AltosLib.AO_LOG_GPS_ALT: + case AltosLib.AO_LOG_GPS_SAT: + case AltosLib.AO_LOG_GPS_DATE: + break; + default: + state.set_temp_gps(); + break; + } + } + + switch (cmd) { + case AltosLib.AO_LOG_FLIGHT: + state.set_flight(flight()); + state.set_ground_accel(ground_accel()); + state.set_ground_pressure(ground_pres()); +// state.set_temperature(ground_temp() / 100.0); + break; + case AltosLib.AO_LOG_STATE: + state.set_state(state()); + break; + case AltosLib.AO_LOG_SENSOR: + state.set_ms5607(pres(), temp()); + state.set_accel(accel()); + + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt())); + + state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense_a())); + state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m())); + + break; + case AltosLib.AO_LOG_GPS_POS: + gps = state.make_temp_gps(false); + gps.lat = latitude() / 1e7; + gps.lon = longitude() / 1e7; + gps.alt = altitude(); + break; + case AltosLib.AO_LOG_GPS_TIME: + gps = state.make_temp_gps(false); + + gps.hour = hour(); + gps.minute = minute(); + gps.second = second(); + + int flags = flags(); + + 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; + + gps.year = 2000 + year(); + gps.month = month(); + gps.day = day(); + break; + case AltosLib.AO_LOG_GPS_SAT: + gps = state.make_temp_gps(true); + + int n = nsat(); + for (int i = 0; i < n; i++) + gps.add_sat(svid(i), c_n(i)); + break; + } + } + + public AltosEepromMetrum2 (String line) { + parse_string(line); + } + + static public LinkedList<AltosEeprom> read(FileInputStream input) { + LinkedList<AltosEeprom> metrums = new LinkedList<AltosEeprom>(); + + for (;;) { + try { + String line = AltosLib.gets(input); + if (line == null) + break; + try { + AltosEepromMetrum2 metrum = new AltosEepromMetrum2(line); + + if (metrum.cmd != AltosLib.AO_LOG_INVALID) + metrums.add(metrum); + } catch (Exception e) { + System.out.printf ("exception\n"); + } + } catch (IOException ie) { + break; + } + } + + return metrums; + } +} diff --git a/altoslib/AltosEepromMini.java b/altoslib/AltosEepromMini.java new file mode 100644 index 00000000..a09a62ce --- /dev/null +++ b/altoslib/AltosEepromMini.java @@ -0,0 +1,102 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromMini extends AltosEeprom { + public static final int record_length = 16; + + public int record_length() { return record_length; } + + /* AO_LOG_FLIGHT elements */ + public int flight() { return data16(0); } + public int ground_pres() { return data32(4); } + + /* AO_LOG_STATE elements */ + public int state() { return data16(0); } + public int reason() { return data16(2); } + + /* AO_LOG_SENSOR elements */ + public int pres() { return data24(0); } + public int temp() { return data24(3); } + public int sense_a() { return data16(6); } + public int sense_m() { return data16(8); } + public int v_batt() { return data16(10); } + + double voltage(AltosState state, int sensor) { + if (state.log_format == AltosLib.AO_LOG_FORMAT_EASYMINI) + return AltosConvert.easy_mini_voltage(sensor); + else + return AltosConvert.tele_mini_voltage(sensor); + } + + public void update_state(AltosState state) { + super.update_state(state); + + switch (cmd) { + case AltosLib.AO_LOG_FLIGHT: + state.set_flight(flight()); + state.set_ground_pressure(ground_pres()); + break; + case AltosLib.AO_LOG_STATE: + state.set_state(state()); + break; + case AltosLib.AO_LOG_SENSOR: + state.set_ms5607(pres(), temp()); + state.set_apogee_voltage(voltage(state, sense_a())); + state.set_main_voltage(voltage(state, sense_m())); + state.set_battery_voltage(voltage(state, v_batt())); + break; + } + } + + public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException { + parse_chunk(chunk, start); + } + + public AltosEepromMini (String line) { + parse_string(line); + } + + public AltosEepromMini(int in_cmd, int in_tick) { + cmd = in_cmd; + tick = in_tick; + valid = true; + } + + static public LinkedList<AltosEeprom> read(FileInputStream input) { + LinkedList<AltosEeprom> minis = new LinkedList<AltosEeprom>(); + + for (;;) { + try { + String line = AltosLib.gets(input); + if (line == null) + break; + AltosEepromMini mini = new AltosEepromMini(line); + minis.add(mini); + } catch (IOException ie) { + break; + } + } + + return minis; + } +} diff --git a/altoslib/AltosEepromMonitor.java b/altoslib/AltosEepromMonitor.java new file mode 100644 index 00000000..eeef0678 --- /dev/null +++ b/altoslib/AltosEepromMonitor.java @@ -0,0 +1,45 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +public interface AltosEepromMonitor { + + public void set_states(int min_state, int max_state); + + public void set_value(String in_state_name, int in_state, int in_state_block, int in_block); + + public void set_serial(int in_serial); + + public void set_flight(int in_flight); + + public void set_filename(String in_file); + + public void set_thread(Thread eeprom_thread); + + final static int INFO_MESSAGE = 0; + final static int WARNING_MESSAGE = 1; + final static int ERROR_MESSAGE = 2; + + public void show_message(String message, String title, int message_type); + + public void start(); + + public void done(boolean success); + + public void reset(); +} diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java deleted file mode 100644 index 70ac1113..00000000 --- a/altoslib/AltosEepromRecord.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright © 2010 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -import java.text.*; - -public class AltosEepromRecord { - 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 AltosEepromRecord (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 AltosEepromRecord (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) { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } - } - } - - public AltosEepromRecord(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/AltosEepromTM.java b/altoslib/AltosEepromTM.java new file mode 100644 index 00000000..36803912 --- /dev/null +++ b/altoslib/AltosEepromTM.java @@ -0,0 +1,205 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromTM extends AltosEeprom { + public int a; + public int b; + + public static final int record_length = 8; + + public void write(PrintStream out) { + out.printf("%c %4x %4x %4x\n", cmd, tick, a, b); + } + + public int record_length() { return record_length; } + + public String string() { + return String.format("%c %4x %4x %4x\n", cmd, tick, a, b); + } + + public void update_state(AltosState state) { + super.update_state(state); + + AltosGPS gps; + + /* Flush any pending GPS changes */ + if (state.gps_pending) { + switch (cmd) { + case AltosLib.AO_LOG_GPS_LAT: + case AltosLib.AO_LOG_GPS_LON: + case AltosLib.AO_LOG_GPS_ALT: + case AltosLib.AO_LOG_GPS_SAT: + case AltosLib.AO_LOG_GPS_DATE: + break; + default: + state.set_temp_gps(); + break; + } + } + + switch (cmd) { + case AltosLib.AO_LOG_FLIGHT: + state.set_state(AltosLib.ao_flight_pad); + state.set_ground_accel(a); + state.set_flight(b); + state.set_boost_tick(tick); + break; + case AltosLib.AO_LOG_SENSOR: + state.set_accel(a); + state.set_pressure(AltosConvert.barometer_to_pressure(b)); + break; + case AltosLib.AO_LOG_PRESSURE: + state.set_pressure(AltosConvert.barometer_to_pressure(b)); + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.set_temperature(AltosConvert.thermometer_to_temperature(a)); + state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(b)); + break; + case AltosLib.AO_LOG_DEPLOY: + state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(a)); + state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(b)); + break; + case AltosLib.AO_LOG_STATE: + state.set_state(a); + break; + case AltosLib.AO_LOG_GPS_TIME: + gps = state.make_temp_gps(false); + + 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; + break; + case AltosLib.AO_LOG_GPS_LAT: + gps = state.make_temp_gps(false); + + int lat32 = a | (b << 16); + gps.lat = (double) lat32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_LON: + gps = state.make_temp_gps(false); + + int lon32 = a | (b << 16); + gps.lon = (double) lon32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_ALT: + gps = state.make_temp_gps(false); + gps.alt = a; + break; + case AltosLib.AO_LOG_GPS_SAT: + gps = state.make_temp_gps(true); + int svid = a; + int c_n0 = b >> 8; + gps.add_sat(svid, c_n0); + break; + case AltosLib.AO_LOG_GPS_DATE: + gps = state.make_temp_gps(false); + gps.year = (a & 0xff) + 2000; + gps.month = a >> 8; + gps.day = b & 0xff; + break; + } + } + + public AltosEepromTM (AltosEepromChunk chunk, int start) throws ParseException { + + cmd = chunk.data(start); + valid = true; + + 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); + a = chunk.data16(start + 4); + b = chunk.data16(start + 6); + } + + public AltosEepromTM (String line) { + valid = false; + tick = 0; + a = 0; + b = 0; + if (line == null) { + cmd = AltosLib.AO_LOG_INVALID; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 4) { + cmd = AltosLib.AO_LOG_INVALID; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + valid = true; + a = Integer.parseInt(tokens[2],16); + b = Integer.parseInt(tokens[3],16); + } + } else { + cmd = AltosLib.AO_LOG_INVALID; + } + } catch (NumberFormatException ne) { + cmd = AltosLib.AO_LOG_INVALID; + } + } + } + + public AltosEepromTM(int in_cmd, int in_tick, int in_a, int in_b) { + valid = true; + cmd = in_cmd; + tick = in_tick; + a = in_a; + b = in_b; + } + + static public LinkedList<AltosEeprom> read(FileInputStream input) { + LinkedList<AltosEeprom> tms = new LinkedList<AltosEeprom>(); + + for (;;) { + try { + String line = AltosLib.gets(input); + if (line == null) + break; + AltosEepromTM tm = new AltosEepromTM(line); + tms.add(tm); + } catch (IOException ie) { + break; + } + } + + return tms; + } + +} diff --git a/altoslib/AltosEepromTeleScience.java b/altoslib/AltosEepromTeleScience.java deleted file mode 100644 index 2a828cf3..00000000 --- a/altoslib/AltosEepromTeleScience.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright © 2011 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -import java.text.*; - -public class AltosEepromTeleScience { - public int type; - public int tick; - public int tm_state; - public int tm_tick; - public int[] data; - public boolean valid; - - public static final int AO_LOG_TELESCIENCE_START = 's'; - public static final int AO_LOG_TELESCIENCE_DATA = 'd'; - - static final int max_data = 12; - public static final int record_length = 32; - - public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException { - type = 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 { - type = AltosLib.AO_LOG_INVALID; - } - - tick = chunk.data16(start+2); - tm_tick = chunk.data16(start+4); - tm_state = chunk.data(start+6); - data = new int[max_data]; - for (int i = 0; i < max_data; i++) - data[i] = chunk.data16(start + 8 + i * 2); - } -} diff --git a/altoslib/AltosEepromTm.java b/altoslib/AltosEepromTm.java new file mode 100644 index 00000000..b8914131 --- /dev/null +++ b/altoslib/AltosEepromTm.java @@ -0,0 +1,159 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromTm extends AltosEeprom { + public int i; + public int a; + public int b; + + public static final int record_length = 2; + + public void write(PrintStream out) { + out.printf("%c %4x %4x %4x\n", cmd, tick, a, b); + } + + public int record_length() { return record_length; } + + public String string() { + return String.format("%c %4x %4x %4x\n", cmd, tick, a, b); + } + + public void update_state(AltosState state) { + super.update_state(state); + + switch (cmd) { + case AltosLib.AO_LOG_FLIGHT: + state.set_state(AltosLib.ao_flight_boost); + state.set_flight(b); + break; + case AltosLib.AO_LOG_PRESSURE: + if (tick == 0) + state.set_ground_pressure(AltosConvert.barometer_to_pressure(b)); + else + state.set_pressure(AltosConvert.barometer_to_pressure(b)); + break; + case AltosLib.AO_LOG_STATE: + state.set_state(a); + break; + } + } + + public AltosEepromTm (AltosEepromChunk chunk, int start, AltosState state) throws ParseException { + int value = chunk.data16(start); + + int i = (chunk.address + start) / record_length; + + cmd = chunk.data(start); + valid = true; + + valid = !chunk.erased(start, record_length); + + switch (i) { + case 0: + cmd = AltosLib.AO_LOG_FLIGHT; + tick = 0; + a = 0; + b = value; + break; + case 1: + cmd = AltosLib.AO_LOG_PRESSURE; + tick = 0; + a = 0; + b = value; + break; + default: + if ((value & 0x8000) != 0) { + cmd = AltosLib.AO_LOG_STATE; + tick = state.tick; + a = value & 0x7fff; + b = 0; + } else { + if (state.ascent) + tick = state.tick + 10; + else + tick = state.tick + 100; + cmd = AltosLib.AO_LOG_PRESSURE; + a = 0; + b = value; + } + break; + } + } + + public AltosEepromTm (String line) { + valid = false; + tick = 0; + a = 0; + b = 0; + if (line == null) { + cmd = AltosLib.AO_LOG_INVALID; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 4) { + cmd = AltosLib.AO_LOG_INVALID; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + valid = true; + a = Integer.parseInt(tokens[2],16); + b = Integer.parseInt(tokens[3],16); + } + } else { + cmd = AltosLib.AO_LOG_INVALID; + } + } catch (NumberFormatException ne) { + cmd = AltosLib.AO_LOG_INVALID; + } + } + } + + public AltosEepromTm(int in_cmd, int in_tick, int in_a, int in_b) { + valid = true; + cmd = in_cmd; + tick = in_tick; + a = in_a; + b = in_b; + } + + static public LinkedList<AltosEeprom> read(FileInputStream input) { + LinkedList<AltosEeprom> tms = new LinkedList<AltosEeprom>(); + + for (;;) { + try { + String line = AltosLib.gets(input); + if (line == null) + break; + AltosEepromTm tm = new AltosEepromTm(line); + tms.add(tm); + } catch (IOException ie) { + break; + } + } + + return tms; + } + +} diff --git a/altoslib/AltosFile.java b/altoslib/AltosFile.java index 90dbc6db..f39c3962 100644 --- a/altoslib/AltosFile.java +++ b/altoslib/AltosFile.java @@ -15,17 +15,44 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.File; import java.util.*; public class AltosFile extends File { - public AltosFile(int year, int month, int day, int serial, int flight, String extension) { + static String number(int n) { + if (n == AltosLib.MISSING) + return "unkn"; + else + return String.format("%04d", n); + } + + static String receiver(int receiver) { + if (receiver == AltosLib.MISSING) + return ""; + return String.format("-via-%04d", receiver); + } + + public AltosFile(int year, int month, int day, int serial, int flight, int receiver, String extension) { super (AltosPreferences.logdir(), - String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", - year, month, day, serial, flight, extension)); + String.format("%04d-%02d-%02d-serial-%s-flight-%s%s.%s", + year, month, day, number(serial), number(flight), receiver(receiver), extension)); + } + + public AltosFile(int year, int month, int day, int serial, int flight, String extension) { + this(year, month, day, serial, flight, AltosLib.MISSING, extension); + } + + public AltosFile(int serial, int flight, int receiver, String extension) { + this(Calendar.getInstance().get(Calendar.YEAR), + Calendar.getInstance().get(Calendar.MONTH) + 1, + Calendar.getInstance().get(Calendar.DAY_OF_MONTH), + serial, + flight, + receiver, + extension); } public AltosFile(int serial, int flight, String extension) { @@ -34,10 +61,11 @@ public class AltosFile extends File { Calendar.getInstance().get(Calendar.DAY_OF_MONTH), serial, flight, + AltosLib.MISSING, extension); } - public AltosFile(AltosRecord telem) { - this(telem.serial, telem.flight, "telem"); + public AltosFile(AltosState state) { + this(state.serial, state.flight, state.receiver_serial, "telem"); } } diff --git a/altoslib/AltosFlash.java b/altoslib/AltosFlash.java index 010274b9..0977070e 100644 --- a/altoslib/AltosFlash.java +++ b/altoslib/AltosFlash.java @@ -15,11 +15,11 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; -public class AltosFlash { +public class AltosFlash extends AltosProgrammer { File file; FileInputStream input; AltosHexfile image; @@ -318,7 +318,7 @@ public class AltosFlash { close(); } - public boolean check_rom_config() { + public boolean check_rom_config() throws InterruptedException { if (debug == null) return true; if (rom_config == null) @@ -330,7 +330,7 @@ public class AltosFlash { rom_config = romconfig; } - public AltosRomconfig romconfig() { + public AltosRomconfig romconfig() throws InterruptedException { if (!check_rom_config()) return null; return rom_config; diff --git a/altoslib/AltosFlashListener.java b/altoslib/AltosFlashListener.java index ab50b74a..777ae635 100644 --- a/altoslib/AltosFlashListener.java +++ b/altoslib/AltosFlashListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public interface AltosFlashListener { public void position(String label, int percent); diff --git a/altoslib/AltosFlightReader.java b/altoslib/AltosFlightReader.java index 34526658..b251e7cc 100644 --- a/altoslib/AltosFlightReader.java +++ b/altoslib/AltosFlightReader.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; import java.io.*; @@ -28,7 +28,7 @@ public class AltosFlightReader { public void init() { } - public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } + public AltosState read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } public void close(boolean interrupted) { } @@ -46,7 +46,7 @@ public class AltosFlightReader { public File backing_file() { return null; } - public boolean has_monitor_battery() { return false; } + public boolean has_monitor_battery() throws InterruptedException { return false; } - public double monitor_battery() { return AltosRecord.MISSING; } + public double monitor_battery() throws InterruptedException { return AltosLib.MISSING; } } diff --git a/altoslib/AltosFrequency.java b/altoslib/AltosFrequency.java index 484a2fd9..ece7525a 100644 --- a/altoslib/AltosFrequency.java +++ b/altoslib/AltosFrequency.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosFrequency { public double frequency; diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index f23842f3..f5162225 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -15,20 +15,21 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; +import java.util.concurrent.*; -public class AltosGPS { +public class AltosGPS implements Cloneable { - public final static int MISSING = AltosRecord.MISSING; + public final static int MISSING = AltosLib.MISSING; public int nsat; public boolean locked; public boolean connected; public double lat; /* degrees (+N -S) */ public double lon; /* degrees (+E -W) */ - public int alt; /* m */ + public double alt; /* m */ public int year; public int month; public int day; @@ -65,40 +66,40 @@ public class AltosGPS { } public void ClearGPSTime() { - year = month = day = 0; - hour = minute = second = 0; + year = month = day = AltosLib.MISSING; + hour = minute = second = AltosLib.MISSING; } public AltosGPS(AltosTelemetryMap map) throws ParseException { - String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, - AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); + String state = map.get_string(AltosTelemetryLegacy.AO_TELEM_GPS_STATE, + AltosTelemetryLegacy.AO_TELEM_GPS_STATE_ERROR); - nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); - if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { + nsat = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_NUM_SAT, 0); + if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_LOCKED)) { connected = true; locked = true; - lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); - lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); - alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); - year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); + lat = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); + lon = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); + alt = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_ALTITUDE, MISSING); + year = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_YEAR, MISSING); if (year != MISSING) year += 2000; - month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); - day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); - - hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0); - minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0); - second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0); - - ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, - AltosRecord.MISSING, 1/100.0); - course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, - AltosRecord.MISSING); - hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0); - vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0); - h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING); - v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING); - } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) { + month = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MONTH, MISSING); + day = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_DAY, MISSING); + + hour = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HOUR, 0); + minute = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MINUTE, 0); + second = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_SECOND, 0); + + ground_speed = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HORIZONTAL_SPEED, + AltosLib.MISSING, 1/100.0); + course = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_COURSE, + AltosLib.MISSING); + hdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HDOP, MISSING, 1.0); + vdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_VDOP, MISSING, 1.0); + h_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HERROR, MISSING); + v_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_VERROR, MISSING); + } else if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_UNLOCKED)) { connected = true; locked = false; } else { @@ -107,6 +108,62 @@ public class AltosGPS { } } + public boolean parse_string (String line, boolean says_done) { + String[] bits = line.split("\\s+"); + if (bits.length == 0) + return false; + if (line.startsWith("Date:")) { + if (bits.length < 2) + return false; + String[] d = bits[1].split("/"); + if (d.length < 3) + return false; + year = Integer.parseInt(d[0]) + 2000; + month = Integer.parseInt(d[1]); + day = Integer.parseInt(d[2]); + } else if (line.startsWith("Time:")) { + if (bits.length < 2) + return false; + String[] d = bits[1].split(":"); + if (d.length < 3) + return false; + hour = Integer.parseInt(d[0]); + minute = Integer.parseInt(d[1]); + second = Integer.parseInt(d[2]); + } else if (line.startsWith("Lat/Lon:")) { + if (bits.length < 3) + return false; + lat = Integer.parseInt(bits[1]) * 1.0e-7; + lon = Integer.parseInt(bits[2]) * 1.0e-7; + } else if (line.startsWith("Alt:")) { + if (bits.length < 2) + return false; + alt = Integer.parseInt(bits[1]); + } else if (line.startsWith("Flags:")) { + if (bits.length < 2) + return false; + int status = Integer.decode(bits[1]); + connected = (status & AltosLib.AO_GPS_RUNNING) != 0; + locked = (status & AltosLib.AO_GPS_VALID) != 0; + if (!says_done) + return false; + } else if (line.startsWith("Sats:")) { + if (bits.length < 2) + return false; + nsat = Integer.parseInt(bits[1]); + cc_gps_sat = new AltosGPSSat[nsat]; + for (int i = 0; i < nsat; i++) { + int svid = Integer.parseInt(bits[2+i*2]); + int cc_n0 = Integer.parseInt(bits[3+i*2]); + cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0); + } + } else if (line.startsWith("done")) { + return false; + } else + return false; + return true; + } + public AltosGPS(String[] words, int i, int version) throws ParseException { AltosParse.word(words[i++], "GPS"); nsat = AltosParse.parse_int(words[i++]); @@ -212,10 +269,46 @@ public class AltosGPS { } public AltosGPS() { + lat = AltosLib.MISSING; + lon = AltosLib.MISSING; + alt = AltosLib.MISSING; ClearGPSTime(); cc_gps_sat = null; } + public AltosGPS clone() { + AltosGPS g = new AltosGPS(); + + g.nsat = nsat; + g.locked = locked; + g.connected = connected; + g.lat = lat; /* 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(cc_gps_sat[i].svid, + cc_gps_sat[i].c_n0); + } + } + return g; + } + public AltosGPS(AltosGPS old) { if (old != null) { nsat = old.nsat; @@ -247,8 +340,36 @@ public class AltosGPS { } } } else { + lat = AltosLib.MISSING; + lon = AltosLib.MISSING; + alt = AltosLib.MISSING; ClearGPSTime(); cc_gps_sat = null; } } + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosGPS gps = new AltosGPS(link, config_data); + + if (gps != null) { + state.set_gps(gps, state.gps_sequence++); + return; + } + } catch (TimeoutException te) { + } + state.set_gps(null, 0); + } + + public AltosGPS (AltosLink link, AltosConfigData config_data) throws TimeoutException, InterruptedException { + boolean says_done = config_data.compare_version("1.0") >= 0; + link.printf("g\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + if (!parse_string(line, says_done)) + break; + } + } } diff --git a/altoslib/AltosGPSQuery.java b/altoslib/AltosGPSQuery.java deleted file mode 100644 index deb9d201..00000000 --- a/altoslib/AltosGPSQuery.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright © 2012 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -import java.util.concurrent.*; - -class AltosGPSQuery extends AltosGPS { - public AltosGPSQuery (AltosLink link, AltosConfigData config_data) - throws TimeoutException, InterruptedException { - boolean says_done = config_data.compare_version("1.0") >= 0; - link.printf("g\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) - throw new TimeoutException(); - String[] bits = line.split("\\s+"); - if (bits.length == 0) - continue; - if (line.startsWith("Date:")) { - if (bits.length < 2) - continue; - String[] d = bits[1].split(":"); - if (d.length < 3) - continue; - year = Integer.parseInt(d[0]) + 2000; - month = Integer.parseInt(d[1]); - day = Integer.parseInt(d[2]); - continue; - } - if (line.startsWith("Time:")) { - if (bits.length < 2) - continue; - String[] d = bits[1].split("/"); - if (d.length < 3) - continue; - hour = Integer.parseInt(d[0]); - minute = Integer.parseInt(d[1]); - second = Integer.parseInt(d[2]); - continue; - } - if (line.startsWith("Lat/Lon:")) { - if (bits.length < 3) - continue; - lat = Integer.parseInt(bits[1]) * 1.0e-7; - lon = Integer.parseInt(bits[2]) * 1.0e-7; - continue; - } - if (line.startsWith("Alt:")) { - if (bits.length < 2) - continue; - alt = Integer.parseInt(bits[1]); - continue; - } - if (line.startsWith("Flags:")) { - if (bits.length < 2) - continue; - int status = Integer.decode(bits[1]); - connected = (status & AltosLib.AO_GPS_RUNNING) != 0; - locked = (status & AltosLib.AO_GPS_VALID) != 0; - if (!says_done) - break; - continue; - } - if (line.startsWith("Sats:")) { - if (bits.length < 2) - continue; - nsat = Integer.parseInt(bits[1]); - cc_gps_sat = new AltosGPSSat[nsat]; - for (int i = 0; i < nsat; i++) { - int svid = Integer.parseInt(bits[2+i*2]); - int cc_n0 = Integer.parseInt(bits[3+i*2]); - cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0); - } - } - if (line.startsWith("done")) - break; - if (line.startsWith("Syntax error")) - break; - } - } -} - diff --git a/altoslib/AltosGPSSat.java b/altoslib/AltosGPSSat.java index 8714dd8a..0e17d7f2 100644 --- a/altoslib/AltosGPSSat.java +++ b/altoslib/AltosGPSSat.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosGPSSat { public int svid; diff --git a/altoslib/AltosGreatCircle.java b/altoslib/AltosGreatCircle.java index f1cf0ae9..2c84bf4a 100644 --- a/altoslib/AltosGreatCircle.java +++ b/altoslib/AltosGreatCircle.java @@ -15,11 +15,11 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; 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/AltosHeight.java b/altoslib/AltosHeight.java index ed590812..84bd42d9 100644 --- a/altoslib/AltosHeight.java +++ b/altoslib/AltosHeight.java @@ -15,29 +15,35 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosHeight extends AltosUnits { - public double value(double v) { - if (AltosConvert.imperial_units) + public double value(double v, boolean imperial_units) { + if (imperial_units) return AltosConvert.meters_to_feet(v); return v; } - public String show_units() { - if (AltosConvert.imperial_units) + public double inverse(double v, boolean imperial_units) { + if (imperial_units) + return AltosConvert.feet_to_meters(v); + return v; + } + + public String show_units(boolean imperial_units) { + if (imperial_units) return "ft"; return "m"; } - public String say_units() { - if (AltosConvert.imperial_units) + public String say_units(boolean imperial_units) { + if (imperial_units) return "feet"; return "meters"; } - public int show_fraction(int width) { + public int show_fraction(int width, boolean imperial_units) { return width / 9; } }
\ No newline at end of file diff --git a/altoslib/AltosHexfile.java b/altoslib/AltosHexfile.java index 2140228a..717c1c5d 100644 --- a/altoslib/AltosHexfile.java +++ b/altoslib/AltosHexfile.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.LinkedList; @@ -116,7 +116,7 @@ class HexRecord implements Comparable<Object> { return String.format("%04x: %02x (%d)", address, type, data.length); } - public HexRecord(HexFileInputStream input) throws IOException { + public HexRecord(HexFileInputStream input) throws IOException, EOFException { read_state state = read_state.marker; int nhexbytes = 0; int hex = 0; @@ -125,14 +125,16 @@ class HexRecord implements Comparable<Object> { while (state != read_state.done) { int c = input.read(); - if (c < 0 && state != read_state.white) + if (c < 0 && state != read_state.white && state != read_state.marker) throw new IOException(String.format("%d: Unexpected EOF", input.line)); if (c == ' ') continue; switch (state) { case marker: + if (c == EOF || c == -1) + throw new EOFException(); if (c != ':') - throw new IOException("Missing ':'"); + throw new IOException(String.format ("Missing ':' (got %x)", c)); state = read_state.length; nhexbytes = 2; hex = 0; @@ -208,25 +210,82 @@ class HexRecord implements Comparable<Object> { } public class AltosHexfile { - public int address; - public byte[] data; + public int address; + public byte[] data; + LinkedList<AltosHexsym> symlist = new LinkedList<AltosHexsym>(); public byte get_byte(int a) { return data[a - address]; } + /* CC1111-based products have the romconfig stuff located + * at a fixed address; when the file we load has no symbols, + * assume it is one of those and set the symbols appropriately + */ + final static int ao_romconfig_version_addr = 0xa0; + final static int ao_romconfig_check_addr = 0xa2; + final static int ao_serial_number_addr = 0xa4; + final static int ao_radio_cal_addr = 0xa6; + final static int ao_usb_descriptors_addr = 0xaa; + + static AltosHexsym[] cc_symbols = { + new AltosHexsym("ao_romconfig_version", ao_romconfig_version_addr), + new AltosHexsym("ao_romconfig_check", ao_romconfig_check_addr), + new AltosHexsym("ao_serial_number", ao_serial_number_addr), + new AltosHexsym("ao_radio_cal", ao_radio_cal_addr), + new AltosHexsym("ao_usb_descriptors", ao_usb_descriptors_addr) + }; + + private void add_cc_symbols() { + for (int i = 0; i < cc_symbols.length; i++) + symlist.add(cc_symbols[i]); + } + + public void add_symbol(AltosHexsym symbol) { + symlist.add(symbol); + } + + /* Take symbols from another hexfile and duplicate them here */ + public void add_symbols(AltosHexfile other) { + for (AltosHexsym symbol : other.symlist) + symlist.add(symbol); + } + + public AltosHexsym lookup_symbol(String name) { + if (symlist.isEmpty()) + add_cc_symbols(); + + for (AltosHexsym symbol : symlist) + if (name.equals(symbol.name)) + return symbol; + return null; + } + + private String make_string(byte[] data, int start, int length) { + String s = ""; + for (int i = 0; i < length; i++) + s += (char) data[start + i]; + return s; + } + + public AltosHexfile(byte[] bytes, int offset) { + data = bytes; + address = offset; + } + public AltosHexfile(FileInputStream file) throws IOException { HexFileInputStream input = new HexFileInputStream(file); LinkedList<HexRecord> record_list = new LinkedList<HexRecord>(); boolean done = false; while (!done) { - HexRecord record = new HexRecord(input); + try { + HexRecord record = new HexRecord(input); - if (record.type == HexRecord.EOF) - done = true; - else record_list.add(record); + } catch (EOFException eof) { + done = true; + } } long extended_addr = 0; @@ -234,9 +293,10 @@ public class AltosHexfile { long bound = 0; boolean set = false; for (HexRecord record : record_list) { + long addr; switch (record.type) { case 0: - long addr = extended_addr + record.address; + addr = extended_addr + record.address; long r_bound = addr + record.data.length; if (!set || addr < base) base = addr; @@ -256,6 +316,12 @@ public class AltosHexfile { throw new IOException("invalid extended segment address record"); extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; break; + case 0xfe: + String name = make_string(record.data, 0, record.data.length); + addr = extended_addr + record.address; + AltosHexsym s = new AltosHexsym(name, addr); + symlist.add(s); + break; default: throw new IOException ("invalid hex record type"); } @@ -292,6 +358,8 @@ public class AltosHexfile { throw new IOException("invalid extended segment address record"); extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; break; + case 0xfe: + break; default: throw new IOException ("invalid hex record type"); } diff --git a/altoslib/AltosRecordNone.java b/altoslib/AltosHexsym.java index a95b6a9c..810a4803 100644 --- a/altoslib/AltosRecordNone.java +++ b/altoslib/AltosHexsym.java @@ -1,5 +1,5 @@ /* - * Copyright © 2012 Keith Packard <keithp@keithp.com> + * Copyright © 2013 Keith Packard <keithp@keithp.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,24 +15,16 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosRecordNone extends AltosRecord { +public class AltosHexsym { + String name; + long address; - public double pressure() { return MISSING; } - public double ground_pressure() { return MISSING; } - public double temperature() { return MISSING; } - public double acceleration() { return MISSING; } + final static long invalid_addr = 0xffffffff; - public AltosRecordNone(AltosRecord old) { - super.copy(old); + public AltosHexsym(String name, long address) { + this.name = name; + this.address = address; } - - public AltosRecordNone clone() { - return new AltosRecordNone(this); - } - - public AltosRecordNone() { - super(); - } -} +}
\ No newline at end of file diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index 8f6731fa..6d88ccae 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -15,9 +15,11 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosIMU { +import java.util.concurrent.*; + +public class AltosIMU implements Cloneable { public int accel_x; public int accel_y; public int accel_z; @@ -25,5 +27,67 @@ public class AltosIMU { public int gyro_x; public int gyro_y; public int gyro_z; + + public boolean parse_string(String line) { + if (!line.startsWith("Accel:")) + return false; + + String[] items = line.split("\\s+"); + + if (items.length >= 8) { + accel_x = Integer.parseInt(items[1]); + accel_y = Integer.parseInt(items[2]); + accel_z = Integer.parseInt(items[3]); + gyro_x = Integer.parseInt(items[5]); + gyro_y = Integer.parseInt(items[6]); + gyro_z = Integer.parseInt(items[7]); + } + return true; + } + + 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; + } + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosIMU imu = new AltosIMU(link); + + if (imu != null) + state.set_imu(imu); + } catch (TimeoutException te) { + } + } + + public AltosIMU() { + accel_x = AltosLib.MISSING; + accel_y = AltosLib.MISSING; + accel_z = AltosLib.MISSING; + + gyro_x = AltosLib.MISSING; + gyro_y = AltosLib.MISSING; + gyro_z = AltosLib.MISSING; + } + + public AltosIMU(AltosLink link) throws InterruptedException, TimeoutException { + this(); + link.printf("I\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (parse_string(line)) + break; + } + } } -
\ No newline at end of file diff --git a/altoslib/AltosIMUQuery.java b/altoslib/AltosIMUQuery.java deleted file mode 100644 index 4ea5d963..00000000 --- a/altoslib/AltosIMUQuery.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2012 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -import java.util.concurrent.TimeoutException; - -class AltosIMUQuery extends AltosIMU { - - public AltosIMUQuery (AltosLink link) throws InterruptedException, TimeoutException { - link.printf("I\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!line.startsWith("Accel:")) - continue; - String[] items = line.split("\\s+"); - if (items.length >= 8) { - accel_x = Integer.parseInt(items[1]); - accel_y = Integer.parseInt(items[2]); - accel_z = Integer.parseInt(items[3]); - gyro_x = Integer.parseInt(items[5]); - gyro_y = Integer.parseInt(items[6]); - gyro_z = Integer.parseInt(items[7]); - } - break; - } - } -} - diff --git a/altoslib/AltosIdle.java b/altoslib/AltosIdle.java new file mode 100644 index 00000000..456a9247 --- /dev/null +++ b/altoslib/AltosIdle.java @@ -0,0 +1,39 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public abstract class AltosIdle { + AltosLink link; + AltosConfigData config_data; + + public void printf(String format, Object ... arguments) { + link.printf(format, arguments); + } + + public abstract void update_state(AltosState state) throws InterruptedException, TimeoutException; + + public AltosIdle(AltosLink link, AltosConfigData config_data) { + this.link = link; + this.config_data = config_data; + } +} diff --git a/altoslib/AltosIdleFetch.java b/altoslib/AltosIdleFetch.java new file mode 100644 index 00000000..4adc6c41 --- /dev/null +++ b/altoslib/AltosIdleFetch.java @@ -0,0 +1,151 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +class AltosIdler { + String prefix; + int[] idlers; + + static final int idle_gps = 0; + static final int idle_imu = 1; + static final int idle_mag = 2; + static final int idle_ms5607 = 3; + static final int idle_mma655x = 4; + + + static final int idle_sensor_tm = 10; + static final int idle_sensor_metrum = 11; + static final int idle_sensor_mega = 12; + static final int idle_sensor_emini = 13; + static final int idle_sensor_tmini = 14; + + public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException { + for (int idler : idlers) { + AltosIdle idle = null; + switch (idler) { + case idle_gps: + AltosGPS.update_state(state, link, config_data); + break; + case idle_imu: + AltosIMU.update_state(state, link, config_data); + break; + case idle_mag: + AltosMag.update_state(state, link, config_data); + break; + case idle_ms5607: + AltosMs5607.update_state(state, link, config_data); + break; + case idle_mma655x: + AltosMma655x.update_state(state, link, config_data); + break; + case idle_sensor_tm: + AltosSensorTM.update_state(state, link, config_data); + break; + case idle_sensor_metrum: + AltosSensorMetrum.update_state(state, link, config_data); + break; + case idle_sensor_mega: + AltosSensorMega.update_state(state, link, config_data); + break; + case idle_sensor_emini: + AltosSensorEMini.update_state(state, link, config_data); + break; + case idle_sensor_tmini: + AltosSensorTMini.update_state(state, link, config_data); + } + if (idle != null) + idle.update_state(state); + } + } + + public boolean matches(AltosConfigData config_data) { + return config_data.product.startsWith(prefix); + } + + public AltosIdler(String prefix, int ... idlers) { + this.prefix = prefix; + this.idlers = idlers; + } +} + + +public class AltosIdleFetch implements AltosStateUpdate { + + static final AltosIdler[] idlers = { + + new AltosIdler("EasyMini", + AltosIdler.idle_ms5607, + AltosIdler.idle_sensor_emini), + + new AltosIdler("TeleMini-v1", + AltosIdler.idle_sensor_tm), + + new AltosIdler("TeleMini-v2", + AltosIdler.idle_ms5607, + AltosIdler.idle_sensor_tmini), + + new AltosIdler("TeleMetrum-v1", + AltosIdler.idle_gps, + AltosIdler.idle_sensor_tm), + + new AltosIdler("TeleMetrum-v2", + AltosIdler.idle_gps, + AltosIdler.idle_ms5607, AltosIdler.idle_mma655x, + AltosIdler.idle_sensor_metrum), + + new AltosIdler("TeleMega", + AltosIdler.idle_gps, + AltosIdler.idle_ms5607, AltosIdler.idle_mma655x, + AltosIdler.idle_imu, AltosIdler.idle_mag, + AltosIdler.idle_sensor_mega), + }; + + AltosLink link; + + double frequency; + String callsign; + + public void update_state(AltosState state) throws InterruptedException { + try { + AltosConfigData config_data = new AltosConfigData(link); + state.set_state(AltosLib.ao_flight_startup); + state.set_serial(config_data.serial); + state.set_callsign(config_data.callsign); + state.set_ground_accel(config_data.accel_cal_plus); + state.set_accel_g(config_data.accel_cal_plus, config_data.accel_cal_minus); + for (AltosIdler idler : idlers) { + if (idler.matches(config_data)) { + idler.update_state(state, link, config_data); + break; + } + } + state.set_received_time(System.currentTimeMillis()); + } catch (TimeoutException te) { + } + + } + + public AltosIdleFetch(AltosLink link) { + this.link = link; + } +} diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index b3ce5b20..d9d71143 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.concurrent.*; @@ -24,11 +24,13 @@ import java.util.concurrent.*; public class AltosIdleMonitor extends Thread { AltosLink link; AltosIdleMonitorListener listener; - AltosState state; + + AltosIdleFetch fetch; + boolean remote; double frequency; String callsign; - AltosState previous_state; + AltosListenerState listener_state; AltosConfigData config_data; AltosGPS gps; @@ -47,86 +49,35 @@ public class AltosIdleMonitor extends Thread { return rssi; } - boolean has_sensor_tm(AltosConfigData config_data) { - return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("TeleMini"); - } - - boolean has_sensor_mm(AltosConfigData config_data) { - return config_data.product.startsWith("TeleMega"); + void start_link() throws InterruptedException, TimeoutException { + if (remote) { + link.set_radio_frequency(frequency); + link.set_callsign(callsign); + link.start_remote(); + } else + link.flush_input(); } - boolean has_gps(AltosConfigData config_data) { - return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("TeleMega"); - } - - AltosRecord sensor_mm(AltosConfigData config_data) throws InterruptedException, TimeoutException { - AltosRecordMM record_mm = new AltosRecordMM(); - AltosSensorMM sensor = new AltosSensorMM(link); - AltosMs5607 ms5607 = new AltosMs5607Query(link); - AltosIMU imu = new AltosIMUQuery(link); - - record_mm.accel_plus_g = config_data.accel_cal_plus; - record_mm.accel_minus_g = config_data.accel_cal_minus; - - record_mm.ground_accel = sensor.accel; - record_mm.accel = sensor.accel; - record_mm.ground_pres = ms5607.pa; - record_mm.pres = ms5607.pa; - record_mm.temp = ms5607.cc; - - record_mm.v_batt = sensor.v_batt; - record_mm.v_pyro = sensor.v_pyro; - record_mm.sense = sensor.sense; - - record_mm.imu = imu; - - return record_mm; + void stop_link() throws InterruptedException, TimeoutException { + if (remote) + link.stop_remote(); } - void update_state() throws InterruptedException, TimeoutException { - AltosRecord record = null; + void update_state(AltosState state) throws InterruptedException, TimeoutException { + boolean worked = false; try { - if (remote) { - link.set_radio_frequency(frequency); - link.set_callsign(callsign); - link.start_remote(); - } else - link.flush_input(); - config_data = new AltosConfigData(link); - - if (has_sensor_tm(config_data)) - record = new AltosSensorTM(link, config_data); - else if (has_sensor_mm(config_data)) - record = sensor_mm(config_data); - else - record = new AltosRecordNone(); - - if (has_gps(config_data)) - gps = new AltosGPSQuery(link, config_data); - - record.version = 0; - record.callsign = config_data.callsign; - record.serial = config_data.serial; - record.flight = config_data.log_available() > 0 ? 255 : 0; - record.status = 0; - record.state = AltosLib.ao_flight_idle; - record.gps = gps; - record.gps_sequence++; - state = new AltosState (record, state); + start_link(); + fetch.update_state(state); + worked = true; } finally { - if (remote) { - link.stop_remote(); - if (record != null) { - record.rssi = link.rssi(); - listener_state.battery = link.monitor_battery(); - } - } else { - if (record != null) - record.rssi = 0; + stop_link(); + if (worked) { + if (remote) + state.set_rssi(link.rssi(), 0); + listener_state.battery = link.monitor_battery(); } } - } public void set_frequency(double in_frequency) { @@ -139,33 +90,32 @@ public class AltosIdleMonitor extends Thread { link.abort_reply(); } - public void post_state() { - listener.update(state, listener_state); - } - - public void abort() { - if (isAlive()) { + public void abort() throws InterruptedException { + while (isAlive()) { interrupt(); link.abort_reply(); - try { - join(); - } catch (InterruptedException ie) { - } + Thread.sleep(100); } + join(); } public void run() { + AltosState state = new AltosState(); try { - for (;;) { + while (!link.has_error) { try { - update_state(); - post_state(); + link.config_data(); + update_state(state); + listener.update(state, listener_state); } catch (TimeoutException te) { } Thread.sleep(1000); } } catch (InterruptedException ie) { + } + try { link.close(); + } catch (InterruptedException ie) { } } @@ -174,7 +124,7 @@ public class AltosIdleMonitor extends Thread { listener = in_listener; link = in_link; remote = in_remote; - state = null; listener_state = new AltosListenerState(); + fetch = new AltosIdleFetch(link); } } diff --git a/altoslib/AltosIdleMonitorListener.java b/altoslib/AltosIdleMonitorListener.java index 27e36dea..0b03b897 100644 --- a/altoslib/AltosIdleMonitorListener.java +++ b/altoslib/AltosIdleMonitorListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public interface AltosIdleMonitorListener { public void update(AltosState state, AltosListenerState listener_state); diff --git a/altoslib/AltosIgnite.java b/altoslib/AltosIgnite.java index 85905900..fc9599b6 100644 --- a/altoslib/AltosIgnite.java +++ b/altoslib/AltosIgnite.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.concurrent.*; @@ -141,7 +141,7 @@ public class AltosIgnite { } } - public void fire(int igniter) { + public void fire(int igniter) throws InterruptedException { if (link == null) return; try { @@ -154,21 +154,14 @@ public class AltosIgnite { link.printf("i DoIt drogue\n"); break; } - } catch (InterruptedException ie) { } catch (TimeoutException te) { } finally { - try { - stop_link(); - } catch (InterruptedException ie) { - } + stop_link(); } } - public void close() { - try { - stop_link(); - } catch (InterruptedException ie) { - } + public void close() throws InterruptedException { + stop_link(); link.close(); link = null; } diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 25d17e72..efbc3ddb 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.util.*; import java.io.*; @@ -28,6 +28,7 @@ public class AltosLib { public static final int AO_LOG_TEMP_VOLT = 'T'; public static final int AO_LOG_DEPLOY = 'D'; public static final int AO_LOG_STATE = 'S'; + public static final int AO_LOG_GPS_POS = 'P'; public static final int AO_LOG_GPS_TIME = 'G'; public static final int AO_LOG_GPS_LAT = 'N'; public static final int AO_LOG_GPS_LON = 'W'; @@ -62,6 +63,8 @@ public class AltosLib { public static final int AO_LOG_SOFTWARE_VERSION = 9999; + public final static int MISSING = 0x7fffffff; + /* Added to flag invalid records */ public static final int AO_LOG_INVALID = -1; @@ -92,16 +95,59 @@ public class AltosLib { public final static int product_telemega = 0x0023; public final static int product_megadongle = 0x0024; public final static int product_telegps = 0x0025; + public final static int product_easymini = 0x0026; + public final static int product_telemini = 0x0027; public final static int product_altusmetrum_min = 0x000a; - public final static int product_altusmetrum_max = 0x0025; + public final static int product_altusmetrum_max = 0x002c; public final static int product_any = 0x10000; public final static int product_basestation = 0x10000 + 1; public final static int product_altimeter = 0x10000 + 2; + private static class Product { + final String name; + final int product; + + Product (String name, int product) { + this.name = name; + this.product = product; + } + } + + private static Product[] products = { + new Product("telemetrum", product_telemetrum), + new Product("teleballoon", product_telemetrum), + new Product("teledongle", product_teledongle), + new Product("teleterra", product_teledongle), + new Product("telebt", product_telebt), + new Product("telelaunch", product_telelaunch), + new Product("telelco", product_telelco), + new Product("telescience", product_telescience), + new Product("telepyro", product_telepyro), + new Product("telemega", product_telemega), + new Product("megadongle", product_megadongle), + new Product("telegps", product_telegps), + new Product("easymini", product_easymini), + new Product("telemini", product_telemini) + }; + + public static int name_to_product(String name) { + String low = name.toLowerCase(); + + for (int i = 0; i < products.length; i++) + if (low.startsWith(products[i].name)) + return products[i].product; + return product_any; + } + /* Bluetooth "identifier" (bluetooth sucks) */ public final static String bt_product_telebt = "TeleBT"; + /* "good" voltages */ + + public final static double ao_battery_good = 3.8; + public final static double ao_igniter_good = 3.5; + /* Telemetry modes */ public static final int ao_telemetry_off = 0; public static final int ao_telemetry_min = 1; @@ -216,6 +262,9 @@ public class AltosLib { public static final int AO_LOG_FORMAT_TELEMETRY = 3; public static final int AO_LOG_FORMAT_TELESCIENCE = 4; public static final int AO_LOG_FORMAT_TELEMEGA = 5; + public static final int AO_LOG_FORMAT_EASYMINI = 6; + public static final int AO_LOG_FORMAT_TELEMETRUM = 7; + public static final int AO_LOG_FORMAT_TELEMINI = 8; public static final int AO_LOG_FORMAT_NONE = 127; public static boolean isspace(int c) { @@ -410,4 +459,24 @@ public class AltosLib { public static File replace_extension(File input, String extension) { return new File(replace_extension(input.getPath(), extension)); } + + public static String product_name(int product_id) { + switch (product_id) { + case product_altusmetrum: return "AltusMetrum"; + case product_telemetrum: return "TeleMetrum"; + case product_teledongle: return "TeleDongle"; + case product_teleterra: return "TeleTerra"; + case product_telebt: return "TeleBT"; + case product_telelaunch: return "TeleLaunch"; + case product_telelco: return "TeleLco"; + case product_telescience: return "Telescience"; + case product_telepyro: return "TelePyro"; + case product_telemega: return "TeleMega"; + case product_megadongle: return "MegaDongle"; + case product_telegps: return "TeleGPS"; + case product_easymini: return "EasyMini"; + case product_telemini: return "TeleMini"; + default: return "unknown"; + } + } } diff --git a/altoslib/AltosLine.java b/altoslib/AltosLine.java index b3bd20f9..e5dd13fc 100644 --- a/altoslib/AltosLine.java +++ b/altoslib/AltosLine.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosLine { public String line; diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 159ebfe1..ee1f9785 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.concurrent.*; @@ -26,23 +26,28 @@ public abstract class AltosLink implements Runnable { public final static int ERROR = -1; public final static int TIMEOUT = -2; - public abstract int getchar(); - public abstract void print(String data); - public abstract void close(); + public abstract int getchar() throws InterruptedException; + public abstract void print(String data) throws InterruptedException; + public abstract void putchar(byte c); + public abstract void close() throws InterruptedException; public static boolean debug = false; public static void set_debug(boolean in_debug) { debug = in_debug; } + + public boolean has_error; + LinkedList<String> pending_output = new LinkedList<String>(); public LinkedList<LinkedBlockingQueue<AltosLine>> monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();; public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>(); + public LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>(); - public void add_monitor(LinkedBlockingQueue<AltosLine> q) { + public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) { set_monitor(true); monitors.add(q); } - public void remove_monitor(LinkedBlockingQueue<AltosLine> q) { + public synchronized void remove_monitor(LinkedBlockingQueue<AltosLine> q) { monitors.remove(q); if (monitors.isEmpty()) set_monitor(false); @@ -52,7 +57,11 @@ public abstract class AltosLink implements Runnable { String line = String.format(format, arguments); if (debug) pending_output.add(line); - print(line); + try { + print(line); + } catch (InterruptedException ie) { + + } } public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { @@ -90,6 +99,7 @@ public abstract class AltosLink implements Runnable { } } + private int len_read = 0; public void run () { int c; @@ -100,13 +110,12 @@ public abstract class AltosLink implements Runnable { for (;;) { c = getchar(); if (Thread.interrupted()) { - if (debug) - System.out.printf("INTERRUPTED\n"); break; } if (c == ERROR) { if (debug) System.out.printf("ERROR\n"); + has_error = true; add_telem (new AltosLine()); add_reply (new AltosLine()); break; @@ -116,10 +125,10 @@ public abstract class AltosLink implements Runnable { System.out.printf("TIMEOUT\n"); continue; } - if (c == '\r') + if (c == '\r' && len_read == 0) continue; synchronized(this) { - if (c == '\n') { + if (c == '\n' && len_read == 0) { if (line_count != 0) { add_bytes(line_bytes, line_count); line_count = 0; @@ -134,6 +143,11 @@ public abstract class AltosLink implements Runnable { } line_bytes[line_count] = (byte) c; line_count++; + if (len_read !=0 && line_count == len_read) { + add_binary(line_bytes, line_count); + line_count = 0; + len_read = 0; + } } } } @@ -141,6 +155,7 @@ public abstract class AltosLink implements Runnable { } } + public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = can_cancel_reply(); String reply = null; @@ -175,6 +190,38 @@ public abstract class AltosLink implements Runnable { return reply; } + public byte[] get_binary_reply(int timeout, int len) throws InterruptedException { + boolean can_cancel = can_cancel_reply(); + byte[] bytes = null; + + synchronized(this) { + len_read = len; + } + try { + ++in_reply; + + flush_output(); + + reply_abort = false; + reply_timeout_shown = false; + for (;;) { + bytes = binary_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (bytes != null) { + cleanup_reply_timeout(); + break; + } + if (!remote || !can_cancel || check_reply_timeout()) { + bytes = null; + break; + } + } + + } finally { + --in_reply; + } + return bytes; + } + public void add_telem(AltosLine line) throws InterruptedException { for (int e = 0; e < monitors.size(); e++) { LinkedBlockingQueue<AltosLine> q = monitors.get(e); @@ -190,7 +237,7 @@ public abstract class AltosLink implements Runnable { try { add_telem (new AltosLine()); add_reply (new AltosLine()); - } catch (InterruptedException e) { + } catch (InterruptedException ie) { } } @@ -216,6 +263,22 @@ public abstract class AltosLink implements Runnable { add_string(line); } + public void add_binary(byte[] bytes, int len) throws InterruptedException { + byte[] dup = new byte[len]; + + if (debug) + System.out.printf ("\t\t\t\t\t%d:", len); + for(int i = 0; i < len; i++) { + dup[i] = bytes[i]; + if (debug) + System.out.printf(" %02x", dup[i]); + } + if (debug) + System.out.printf("\n"); + + binary_queue.put(dup); + } + public void flush_output() { for (String s : pending_output) System.out.print(s); @@ -252,6 +315,8 @@ public abstract class AltosLink implements Runnable { public String callsign; AltosConfigData config_data; + private Object config_data_lock = new Object(); + private int telemetry_len() { return AltosLib.telemetry_len(telemetry); } @@ -325,9 +390,11 @@ public abstract class AltosLink implements Runnable { } public AltosConfigData config_data() throws InterruptedException, TimeoutException { - if (config_data == null) - config_data = new AltosConfigData(this); - return config_data; + synchronized(config_data_lock) { + if (config_data == null) + config_data = new AltosConfigData(this); + return config_data; + } } public void set_callsign(String callsign) { @@ -336,6 +403,29 @@ public abstract class AltosLink implements Runnable { flush_output(); } + public boolean is_loader() throws InterruptedException { + boolean ret = false; + printf("v\n"); + for (;;) { + String line = get_reply(); + + if (line == null) + return false; + if (line.startsWith("software-version")) + break; + if (line.startsWith("altos-loader")) + ret = true; + } + return ret; + } + + public void to_loader() throws InterruptedException { + printf("X\n"); + flush_output(); + close(); + Thread.sleep(1000); + } + public boolean remote; public int serial; public String name; @@ -398,8 +488,8 @@ public abstract class AltosLink implements Runnable { return config_data.has_monitor_battery(); } - public double monitor_battery() { - int monitor_batt = AltosRecord.MISSING; + public double monitor_battery() throws InterruptedException { + int monitor_batt = AltosLib.MISSING; if (config_data.has_monitor_battery()) { try { @@ -412,16 +502,16 @@ public abstract class AltosLink implements Runnable { } i++; } - } catch (InterruptedException ie) { } catch (TimeoutException te) { } } - if (monitor_batt == AltosRecord.MISSING) - return AltosRecord.MISSING; + if (monitor_batt == AltosLib.MISSING) + return AltosLib.MISSING; return AltosConvert.cc_battery_to_voltage(monitor_batt); } public AltosLink() { callsign = ""; + has_error = false; } } diff --git a/altoslib/AltosListenerState.java b/altoslib/AltosListenerState.java index 2fb4673e..01dd7afb 100644 --- a/altoslib/AltosListenerState.java +++ b/altoslib/AltosListenerState.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosListenerState { public int crc_errors; @@ -23,6 +23,6 @@ public class AltosListenerState { public AltosListenerState() { crc_errors = 0; - battery = AltosRecord.MISSING; + battery = AltosLib.MISSING; } } diff --git a/altoslib/AltosLog.java b/altoslib/AltosLog.java index 974c9f0f..d4fbee97 100644 --- a/altoslib/AltosLog.java +++ b/altoslib/AltosLog.java @@ -15,11 +15,11 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; -import java.text.ParseException; -import java.util.concurrent.LinkedBlockingQueue; +import java.text.*; +import java.util.concurrent.*; /* * This creates a thread to capture telemetry data and write it to @@ -31,9 +31,11 @@ public class AltosLog implements Runnable { LinkedBlockingQueue<String> pending_queue; int serial; int flight; + int receiver_serial; FileWriter log_file; Thread log_thread; AltosFile file; + AltosLink link; private void close_log_file() { if (log_file != null) { @@ -57,18 +59,15 @@ public class AltosLog implements Runnable { return file; } - boolean open (AltosRecord telem) throws IOException { - AltosFile a = new AltosFile(telem); + boolean open (AltosState state) throws IOException, InterruptedException { + AltosFile a = new AltosFile(state); log_file = new FileWriter(a, true); if (log_file != null) { while (!pending_queue.isEmpty()) { - try { - String s = pending_queue.take(); - log_file.write(s); - log_file.write('\n'); - } catch (InterruptedException ie) { - } + String s = pending_queue.take(); + log_file.write(s); + log_file.write('\n'); } log_file.flush(); file = a; @@ -78,22 +77,25 @@ public class AltosLog implements Runnable { public void run () { try { - AltosRecord previous = null; + AltosState state = new AltosState(); + AltosConfigData receiver_config = link.config_data(); + state.set_receiver_serial(receiver_config.serial); for (;;) { AltosLine line = input_queue.take(); if (line.line == null) continue; try { - AltosRecord telem = AltosTelemetry.parse(line.line, previous); - if ((telem.seen & AltosRecord.seen_flight) != 0 && - (telem.serial != serial || telem.flight != flight || log_file == null)) + AltosTelemetry telem = AltosTelemetry.parse(line.line); + state = state.clone(); + telem.update_state(state); + if (state.serial != serial || state.flight != flight || log_file == null) { close_log_file(); - serial = telem.serial; - flight = telem.flight; - open(telem); + serial = state.serial; + flight = state.flight; + if (state.serial != AltosLib.MISSING && state.flight != AltosLib.MISSING) + open(state); } - previous = telem; } catch (ParseException pe) { } catch (AltosCRCException ce) { } @@ -105,6 +107,7 @@ public class AltosLog implements Runnable { pending_queue.put(line.line); } } catch (InterruptedException ie) { + } catch (TimeoutException te) { } catch (IOException ie) { } close(); @@ -116,6 +119,7 @@ public class AltosLog implements Runnable { link.add_monitor(input_queue); serial = -1; flight = -1; + this.link = link; log_file = null; log_thread = new Thread(this); log_thread.start(); diff --git a/altoslib/AltosMag.java b/altoslib/AltosMag.java index b3bbd92f..89e72bd6 100644 --- a/altoslib/AltosMag.java +++ b/altoslib/AltosMag.java @@ -15,11 +15,70 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosMag { +import java.util.concurrent.*; + +public class AltosMag implements Cloneable { public int x; public int y; public int z; + + public boolean parse_string(String line) { +// if (line.startsWith("Syntax error")) { +// x = y = z = 0; +// return true; +// } + + if (!line.startsWith("X:")) + return false; + + String[] items = line.split("\\s+"); + + if (items.length >= 6) { + x = Integer.parseInt(items[1]); + y = Integer.parseInt(items[3]); + z = Integer.parseInt(items[5]); + } + return true; + } + + public AltosMag clone() { + AltosMag n = new AltosMag(); + + n.x = x; + n.y = y; + n.z = z; + return n; + } + + public AltosMag() { + x = AltosLib.MISSING; + y = AltosLib.MISSING; + z = AltosLib.MISSING; + } + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosMag mag = new AltosMag(link); + + if (mag != null) + state.set_mag(mag); + } catch (TimeoutException te) { + } + } + + public AltosMag(AltosLink link) throws InterruptedException, TimeoutException { + this(); + link.printf("M\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (parse_string(line)) + break; + } + } }
\ No newline at end of file diff --git a/altoslib/AltosMma655x.java b/altoslib/AltosMma655x.java new file mode 100644 index 00000000..f8256190 --- /dev/null +++ b/altoslib/AltosMma655x.java @@ -0,0 +1,68 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.util.concurrent.*; + +public class AltosMma655x implements Cloneable { + + int accel; + + public boolean parse_line(String line) { + String[] items = line.split("\\s+"); + if (line.startsWith("MMA655X value:")) { + if (items.length >= 3) + accel = Integer.parseInt(items[1]); + } else + return false; + return true; + } + + public AltosMma655x() { + accel = AltosLib.MISSING; + } + + public AltosMma655x clone() { + AltosMma655x n = new AltosMma655x(); + + n.accel = accel; + return n; + } + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosMma655x mma655x = new AltosMma655x(link); + + if (mma655x != null) + state.set_accel(mma655x.accel); + } catch (TimeoutException te) { + } + } + + public AltosMma655x(AltosLink link) throws InterruptedException, TimeoutException { + this(); + link.printf("A\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + if (!parse_line(line)) + break; + } + } +} diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index 606916b7..2319d5b8 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -15,7 +15,9 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; + +import java.util.concurrent.*; public class AltosMs5607 { public int reserved; @@ -85,8 +87,9 @@ public class AltosMs5607 { public boolean parse_line(String line) { String[] items = line.split("\\s+"); if (line.startsWith("Pressure:")) { - if (items.length >= 2) + if (items.length >= 2) { raw_pres = Integer.parseInt(items[1]); + } } else if (line.startsWith("Temperature:")) { if (items.length >= 2) raw_temp = Integer.parseInt(items[1]); @@ -94,8 +97,9 @@ public class AltosMs5607 { if (items.length >= 3) reserved = Integer.parseInt(items[2]); } else if (line.startsWith("ms5607 sens:")) { - if (items.length >= 3) + if (items.length >= 3) { sens = Integer.parseInt(items[2]); + } } else if (line.startsWith("ms5607 off:")) { if (items.length >= 3) off = Integer.parseInt(items[2]); @@ -114,15 +118,43 @@ public class AltosMs5607 { } else if (line.startsWith("ms5607 crc:")) { if (items.length >= 3) crc = Integer.parseInt(items[2]); - } else if (line.startsWith("Altitude")) + } else if (line.startsWith("Altitude:")) { return false; + } return true; } + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosMs5607 ms5607 = new AltosMs5607(link); + + if (ms5607 != null) { + state.set_ms5607(ms5607); + return; + } + } catch (TimeoutException te) { + } + } + public AltosMs5607() { - raw_pres = AltosRecord.MISSING; - raw_temp = AltosRecord.MISSING; - pa = AltosRecord.MISSING; - cc = AltosRecord.MISSING; + raw_pres = AltosLib.MISSING; + raw_temp = AltosLib.MISSING; + pa = AltosLib.MISSING; + cc = AltosLib.MISSING; + } + + public AltosMs5607 (AltosLink link) throws InterruptedException, TimeoutException { + this(); + link.printf("c s\nB\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!parse_line(line)) { + break; + } + } + convert(); } } diff --git a/altoslib/AltosNoSymbol.java b/altoslib/AltosNoSymbol.java new file mode 100644 index 00000000..e94687cd --- /dev/null +++ b/altoslib/AltosNoSymbol.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +public class AltosNoSymbol extends Exception { + public AltosNoSymbol(String name) { + super(String.format("No such symbol \"%s\"", name)); + } +} diff --git a/altoslib/AltosOrderedMegaRecord.java b/altoslib/AltosOrderedMegaRecord.java deleted file mode 100644 index b20a5bbd..00000000 --- a/altoslib/AltosOrderedMegaRecord.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2010 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -import java.text.ParseException; - -/* - * AltosRecords with an index field so they can be sorted by tick while preserving - * the original ordering for elements with matching ticks - */ -class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable<AltosOrderedMegaRecord> { - - public int index; - - public AltosOrderedMegaRecord(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(AltosOrderedMegaRecord o) { - int tick_diff = tick - o.tick; - if (tick_diff != 0) - return tick_diff; - return index - o.index; - } -} diff --git a/altoslib/AltosOrderedRecord.java b/altoslib/AltosOrderedRecord.java deleted file mode 100644 index 63507d39..00000000 --- a/altoslib/AltosOrderedRecord.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright © 2010 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -import java.text.ParseException; - -/* - * AltosRecords with an index field so they can be sorted by tick while preserving - * the original ordering for elements with matching ticks - */ -class AltosOrderedRecord extends AltosEepromRecord implements Comparable<AltosOrderedRecord> { - - public int index; - - public AltosOrderedRecord(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 AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { - super(in_cmd, in_tick, in_a, in_b); - index = in_index; - } - - public String toString() { - return String.format("%d.%d %04x %04x %04x", - cmd, index, tick, a, b); - } - - public int compareTo(AltosOrderedRecord o) { - int tick_diff = tick - o.tick; - if (tick_diff != 0) - return tick_diff; - return index - o.index; - } -} - diff --git a/altoslib/AltosParse.java b/altoslib/AltosParse.java index 66bbeed5..ca96a8f9 100644 --- a/altoslib/AltosParse.java +++ b/altoslib/AltosParse.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 088ca3d7..c4051f9b 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.*; diff --git a/altoslib/AltosPreferencesBackend.java b/altoslib/AltosPreferencesBackend.java index fb8a235a..1ea28b01 100644 --- a/altoslib/AltosPreferencesBackend.java +++ b/altoslib/AltosPreferencesBackend.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.File; diff --git a/altoslib/AltosProgrammer.java b/altoslib/AltosProgrammer.java new file mode 100644 index 00000000..b010d564 --- /dev/null +++ b/altoslib/AltosProgrammer.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; + +public abstract class AltosProgrammer { + + abstract public void flash(); + + abstract public void close(); + + abstract public void abort(); + + abstract public AltosRomconfig romconfig() throws InterruptedException; + + abstract public void set_romconfig(AltosRomconfig config); +}
\ No newline at end of file diff --git a/altoslib/AltosPyro.java b/altoslib/AltosPyro.java index 4dbb4223..a219468c 100644 --- a/altoslib/AltosPyro.java +++ b/altoslib/AltosPyro.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.util.*; import java.text.*; @@ -28,24 +28,24 @@ public class AltosPyro { public static final int pyro_accel_greater = 0x00000002; public static final String pyro_accel_less_string = "a<"; public static final String pyro_accel_greater_string = "a>"; - public static final String pyro_accel_less_name = "Acceleration less than (m/s²)"; - public static final String pyro_accel_greater_name = "Acceleration greater than (m/s²)"; + public static final String pyro_accel_less_name = "Acceleration less than"; + public static final String pyro_accel_greater_name = "Acceleration greater than"; public static final double pyro_accel_scale = 16.0; public static final int pyro_speed_less = 0x00000004; public static final int pyro_speed_greater = 0x00000008; public static final String pyro_speed_less_string = "s<"; public static final String pyro_speed_greater_string = "s>"; - public static final String pyro_speed_less_name = "Speed less than (m/s)"; - public static final String pyro_speed_greater_name = "Speed greater than (m/s)"; + public static final String pyro_speed_less_name = "Speed less than"; + public static final String pyro_speed_greater_name = "Speed greater than"; public static final double pyro_speed_scale = 16.0; public static final int pyro_height_less = 0x00000010; public static final int pyro_height_greater = 0x00000020; public static final String pyro_height_less_string = "h<"; public static final String pyro_height_greater_string = "h>"; - public static final String pyro_height_less_name = "Height less than (m)"; - public static final String pyro_height_greater_name = "Height greater than (m)"; + public static final String pyro_height_less_name = "Height less than"; + public static final String pyro_height_greater_name = "Height greater than"; public static final double pyro_height_scale = 1.0; public static final int pyro_orient_less = 0x00000040; @@ -102,12 +102,16 @@ public class AltosPyro { private static HashMap<Integer,String> pyro_to_name = new HashMap<Integer,String>(); + private static HashMap<Integer,AltosUnits> pyro_to_units = new HashMap<Integer,AltosUnits>(); + private static HashMap<Integer,Double> pyro_to_scale = new HashMap<Integer,Double>(); - private static void insert_map(int flag, String string, String name, double scale) { + private static void insert_map(int flag, String string, String name, AltosUnits units, double scale) { string_to_pyro.put(string, flag); pyro_to_string.put(flag, string); pyro_to_name.put(flag, name); + if (units != null) + pyro_to_units.put(flag, units); pyro_to_scale.put(flag, scale); } @@ -124,8 +128,22 @@ public class AltosPyro { } public static String pyro_to_name(int flag) { - if (pyro_to_name.containsKey(flag)) - return pyro_to_name.get(flag); + String name; + AltosUnits units = null; + if (!pyro_to_name.containsKey(flag)) + return null; + + name = pyro_to_name.get(flag); + if (pyro_to_units.containsKey(flag)) + units = pyro_to_units.get(flag); + if (units == null) + return name; + return String.format ("%s (%s)", name, units.show_units()); + } + + public static AltosUnits pyro_to_units(int flag) { + if (pyro_to_units.containsKey(flag)) + return pyro_to_units.get(flag); return null; } @@ -136,29 +154,29 @@ public class AltosPyro { } private static void initialize_maps() { - insert_map(pyro_accel_less, pyro_accel_less_string, pyro_accel_less_name, pyro_accel_scale); - insert_map(pyro_accel_greater, pyro_accel_greater_string, pyro_accel_greater_name, pyro_accel_scale); + insert_map(pyro_accel_less, pyro_accel_less_string, pyro_accel_less_name, AltosConvert.accel, pyro_accel_scale); + insert_map(pyro_accel_greater, pyro_accel_greater_string, pyro_accel_greater_name, AltosConvert.accel, pyro_accel_scale); - insert_map(pyro_speed_less, pyro_speed_less_string, pyro_speed_less_name, pyro_speed_scale); - insert_map(pyro_speed_greater, pyro_speed_greater_string, pyro_speed_greater_name, pyro_speed_scale); + insert_map(pyro_speed_less, pyro_speed_less_string, pyro_speed_less_name, AltosConvert.speed, pyro_speed_scale); + insert_map(pyro_speed_greater, pyro_speed_greater_string, pyro_speed_greater_name, AltosConvert.speed, pyro_speed_scale); - insert_map(pyro_height_less, pyro_height_less_string, pyro_height_less_name, pyro_height_scale); - insert_map(pyro_height_greater, pyro_height_greater_string, pyro_height_greater_name, pyro_height_scale); + insert_map(pyro_height_less, pyro_height_less_string, pyro_height_less_name, AltosConvert.height, pyro_height_scale); + insert_map(pyro_height_greater, pyro_height_greater_string, pyro_height_greater_name, AltosConvert.height, pyro_height_scale); - insert_map(pyro_orient_less, pyro_orient_less_string, pyro_orient_less_name, pyro_orient_scale); - insert_map(pyro_orient_greater, pyro_orient_greater_string, pyro_orient_greater_name, pyro_orient_scale); + insert_map(pyro_orient_less, pyro_orient_less_string, pyro_orient_less_name, null, pyro_orient_scale); + insert_map(pyro_orient_greater, pyro_orient_greater_string, pyro_orient_greater_name, null, pyro_orient_scale); - insert_map(pyro_time_less, pyro_time_less_string, pyro_time_less_name, pyro_time_scale); - insert_map(pyro_time_greater, pyro_time_greater_string, pyro_time_greater_name, pyro_time_scale); + insert_map(pyro_time_less, pyro_time_less_string, pyro_time_less_name, null, pyro_time_scale); + insert_map(pyro_time_greater, pyro_time_greater_string, pyro_time_greater_name, null, pyro_time_scale); - insert_map(pyro_ascending, pyro_ascending_string, pyro_ascending_name, 1.0); - insert_map(pyro_descending, pyro_descending_string, pyro_descending_name, 1.0); + insert_map(pyro_ascending, pyro_ascending_string, pyro_ascending_name, null, 1.0); + insert_map(pyro_descending, pyro_descending_string, pyro_descending_name, null, 1.0); - insert_map(pyro_after_motor, pyro_after_motor_string, pyro_after_motor_name, 1.0); - insert_map(pyro_delay, pyro_delay_string, pyro_delay_name, pyro_delay_scale); + insert_map(pyro_after_motor, pyro_after_motor_string, pyro_after_motor_name, null, 1.0); + insert_map(pyro_delay, pyro_delay_string, pyro_delay_name, null, pyro_delay_scale); - insert_map(pyro_state_less, pyro_state_less_string, pyro_state_less_name, 1.0); - insert_map(pyro_state_greater_or_equal, pyro_state_greater_or_equal_string, pyro_state_greater_or_equal_name, 1.0); + insert_map(pyro_state_less, pyro_state_less_string, pyro_state_less_name, null, 1.0); + insert_map(pyro_state_greater_or_equal, pyro_state_greater_or_equal_string, pyro_state_greater_or_equal_name, null, 1.0); } { diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java deleted file mode 100644 index 5e4ed927..00000000 --- a/altoslib/AltosRecord.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright © 2010 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -public class AltosRecord implements Comparable <AltosRecord>, Cloneable { - - public static final int seen_flight = 1; - public static final int seen_sensor = 2; - public static final int seen_temp_volt = 4; - public static final int seen_deploy = 8; - public static final int seen_gps_time = 16; - public static final int seen_gps_lat = 32; - public static final int seen_gps_lon = 64; - public static final int seen_companion = 128; - - public int seen; - - public final static int MISSING = 0x7fffffff; - - /* Every AltosRecord implementation provides these fields */ - - public int version; - public String callsign; - public int serial; - public int flight; - public int rssi; - public int status; - public int state; - public int tick; - - public AltosGPS gps; - public int gps_sequence; - - public double time; /* seconds since boost */ - - public int device_type; - public int config_major; - public int config_minor; - public int apogee_delay; - public int main_deploy; - public int flight_log_max; - public String firmware_version; - - public AltosRecordCompanion companion; - - /* Telemetry sources have these values recorded from the flight computer */ - public double kalman_height; - public double kalman_speed; - public double kalman_acceleration; - - /* - * Abstract methods that convert record data - * to standard units: - * - * pressure: Pa - * voltage: V - * acceleration: m/s² - * speed: m/s - * height: m - * temperature: °C - */ - - public double pressure() { return MISSING; } - public double ground_pressure() { return MISSING; } - public double acceleration() { return MISSING; } - - public double altitude() { - double p = pressure(); - - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double ground_altitude() { - double p = ground_pressure(); - - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double height() { - double g = ground_altitude(); - double a = altitude(); - - if (g == MISSING) - return MISSING; - if (a == MISSING) - return MISSING; - return a - g; - } - - public double battery_voltage() { return MISSING; } - - public double main_voltage() { return MISSING; } - - public double drogue_voltage() { return MISSING; } - - public double temperature() { return MISSING; } - - public AltosIMU imu() { return null; } - - public AltosMag mag() { return null; } - - public String state() { - return AltosLib.state_name(state); - } - - public int compareTo(AltosRecord o) { - return tick - o.tick; - } - - public AltosRecord clone() { - AltosRecord n = new AltosRecord(); - n.copy(this); - return n; - } - - public void copy(AltosRecord old) { - seen = old.seen; - version = old.version; - callsign = old.callsign; - serial = old.serial; - flight = old.flight; - rssi = old.rssi; - status = old.status; - state = old.state; - tick = old.tick; - gps = new AltosGPS(old.gps); - gps_sequence = old.gps_sequence; - companion = old.companion; - kalman_acceleration = old.kalman_acceleration; - kalman_speed = old.kalman_speed; - kalman_height = old.kalman_height; - } - - public AltosRecord() { - seen = 0; - version = 0; - callsign = "N0CALL"; - serial = MISSING; - flight = MISSING; - rssi = 0; - status = 0; - state = AltosLib.ao_flight_startup; - tick = 0; - gps = null; - gps_sequence = 0; - companion = null; - - kalman_acceleration = MISSING; - kalman_speed = MISSING; - kalman_height = MISSING; - } -} diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java deleted file mode 100644 index d697111c..00000000 --- a/altoslib/AltosRecordMM.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright © 2012 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -public class AltosRecordMM extends AltosRecord { - - /* Sensor values */ - public int accel; - public int pres; - public int temp; - - public int v_batt; - public int v_pyro; - public int sense[]; - - 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; - - public final static int num_sense = 6; - - public AltosIMU imu; - public AltosMag mag; - - 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[5]); - } - - public double drogue_voltage() { - return pyro(sense[4]); - } - - public double temperature() { - if (temp != MISSING) - return temp / 100.0; - return MISSING; - } - - public AltosIMU imu() { return imu; } - - public AltosMag mag() { return mag; } - - 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 (AltosRecordMM old) { - super.copy(old); - - accel = old.accel; - pres = old.pres; - temp = old.temp; - - v_batt = old.v_batt; - v_pyro = old.v_pyro; - sense = new int[num_sense]; - - for (int i = 0; i < num_sense; i++) - sense[i] = old.sense[i]; - - 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; - - imu = old.imu; - mag = old.mag; - } - - - - public AltosRecordMM clone() { - return new AltosRecordMM(this); - } - - void make_missing() { - - accel = MISSING; - pres = MISSING; - temp = MISSING; - - v_batt = MISSING; - v_pyro = MISSING; - sense = new int[num_sense]; - for (int i = 0; i < num_sense; i++) - sense[i] = MISSING; - - ground_accel = MISSING; - ground_pres = MISSING; - accel_plus_g = MISSING; - accel_minus_g = MISSING; - - flight_accel = 0; - flight_vel = 0; - flight_pres = 0; - - imu = new AltosIMU(); - mag = new AltosMag(); - } - - public AltosRecordMM(AltosRecord old) { - super.copy(old); - make_missing(); - } - - public AltosRecordMM(AltosRecordMM old) { - copy(old); - } - - public AltosRecordMM() { - super(); - make_missing(); - } -} diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java deleted file mode 100644 index c6cf3646..00000000 --- a/altoslib/AltosRecordTM.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright © 2012 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -public class AltosRecordTM extends AltosRecord { - - /* Sensor values */ - public int accel; - public int pres; - public int temp; - public int batt; - public int drogue; - public int main; - - 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; - - /* - * Values for our MP3H6115A pressure sensor - * - * From the data sheet: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * - * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa - * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa - */ - - static final double counts_per_kPa = 27 * 2047 / 3300; - static final double counts_at_101_3kPa = 1674.0; - - static double - barometer_to_pressure(double count) - { - return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; - } - - public double pressure() { - if (pres == MISSING) - return MISSING; - return barometer_to_pressure(pres); - } - - public double ground_pressure() { - if (ground_pres == MISSING) - return MISSING; - return barometer_to_pressure(ground_pres); - } - - public double battery_voltage() { - if (batt == MISSING) - return MISSING; - return AltosConvert.cc_battery_to_voltage(batt); - } - - public double main_voltage() { - if (main == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(main); - } - - public double drogue_voltage() { - if (drogue == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(drogue); - } - - /* Value for the CC1111 built-in temperature sensor - * Output voltage at 0°C = 0.755V - * Coefficient = 0.00247V/°C - * Reference voltage = 1.25V - * - * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 - * = (value - 19791.268) / 32768 * 1.25 / 0.00247 - */ - - static double - thermometer_to_temperature(double thermo) - { - return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; - } - - public double temperature() { - if (temp == MISSING) - return MISSING; - return thermometer_to_temperature(temp); - } - - 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; - return (ground_accel - accel) / accel_counts_per_mss(); - } - - public void copy(AltosRecordTM old) { - super.copy(old); - - version = old.version; - callsign = old.callsign; - serial = old.serial; - flight = old.flight; - rssi = old.rssi; - status = old.status; - state = old.state; - tick = old.tick; - accel = old.accel; - pres = old.pres; - temp = old.temp; - batt = old.batt; - drogue = old.drogue; - main = old.main; - flight_accel = old.flight_accel; - ground_accel = old.ground_accel; - flight_vel = old.flight_vel; - flight_pres = old.flight_pres; - ground_pres = old.ground_pres; - accel_plus_g = old.accel_plus_g; - accel_minus_g = old.accel_minus_g; - } - - public AltosRecordTM clone() { - return new AltosRecordTM(this); - } - - void make_missing() { - accel = MISSING; - pres = MISSING; - temp = MISSING; - batt = MISSING; - drogue = MISSING; - main = MISSING; - - flight_accel = MISSING; - flight_vel = MISSING; - flight_pres = MISSING; - - ground_accel = MISSING; - ground_pres = MISSING; - accel_plus_g = MISSING; - accel_minus_g = MISSING; - } - - public AltosRecordTM(AltosRecord old) { - super.copy(old); - make_missing(); - } - - public AltosRecordTM(AltosRecordTM old) { - copy(old); - } - - public AltosRecordTM() { - super(); - make_missing(); - } -} diff --git a/altoslib/AltosReplayReader.java b/altoslib/AltosReplayReader.java index a7e30370..19091d3d 100644 --- a/altoslib/AltosReplayReader.java +++ b/altoslib/AltosReplayReader.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.*; @@ -25,10 +25,10 @@ import java.util.*; */ public class AltosReplayReader extends AltosFlightReader { - Iterator<AltosRecord> iterator; + Iterator<AltosState> iterator; File file; - public AltosRecord read() { + public AltosState read() { if (iterator.hasNext()) return iterator.next(); return null; @@ -41,11 +41,12 @@ public class AltosReplayReader extends AltosFlightReader { /* Make it run in realtime after the rocket leaves the pad */ if (state.state > AltosLib.ao_flight_pad) Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); + state.set_received_time(System.currentTimeMillis()); } public File backing_file() { return file; } - public AltosReplayReader(Iterator<AltosRecord> in_iterator, File in_file) { + public AltosReplayReader(Iterator<AltosState> in_iterator, File in_file) { iterator = in_iterator; file = in_file; name = file.getName(); diff --git a/altoslib/AltosRomconfig.java b/altoslib/AltosRomconfig.java index 0800a2c4..2f106deb 100644 --- a/altoslib/AltosRomconfig.java +++ b/altoslib/AltosRomconfig.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; @@ -26,7 +26,20 @@ public class AltosRomconfig { public int serial_number; public int radio_calibration; - static int get_int(byte[] bytes, int start, int len) { + static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol { + AltosHexsym symbol = hexfile.lookup_symbol(name); + if (symbol == null) + throw new AltosNoSymbol(name); + int offset = (int) symbol.address - hexfile.address; + if (offset < 0 || hexfile.data.length < offset + len) + throw new AltosNoSymbol(name); + return offset; + } + + static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol { + byte[] bytes = hexfile.data; + int start = find_offset(hexfile, name, len); + int v = 0; int o = 0; while (len > 0) { @@ -38,7 +51,10 @@ public class AltosRomconfig { return v; } - static void put_int(int value, byte[] bytes, int start, int len) { + static void put_int(int value, AltosHexfile hexfile, String name, int len) throws AltosNoSymbol, IOException { + byte[] bytes = hexfile.data; + int start = find_offset(hexfile, name, len); + while (len > 0) { bytes[start] = (byte) (value & 0xff); start++; @@ -47,86 +63,155 @@ public class AltosRomconfig { } } - static void put_string(String value, byte[] bytes, int start) { + static void put_string(String value, AltosHexfile hexfile, String name) throws AltosNoSymbol { + byte[] bytes = hexfile.data; + int start = find_offset(hexfile, name, value.length()); + for (int i = 0; i < value.length(); i++) bytes[start + i] = (byte) value.charAt(i); } static final int AO_USB_DESC_STRING = 3; - static void put_usb_serial(int value, byte[] bytes, int start) { - int offset = start + 0xa; + static void put_usb_serial(int value, AltosHexfile hexfile, String name) throws AltosNoSymbol { + byte[] bytes = hexfile.data; + int start = find_offset(hexfile, name, 2); + int string_num = 0; - while (offset < bytes.length && bytes[offset] != 0) { - if (bytes[offset + 1] == AO_USB_DESC_STRING) { + while (start < bytes.length && bytes[start] != 0) { + if (bytes[start + 1] == AO_USB_DESC_STRING) { ++string_num; if (string_num == 4) break; } - offset += ((int) bytes[offset]) & 0xff; + start += ((int) bytes[start]) & 0xff; } - if (offset >= bytes.length || bytes[offset] == 0) - return; - int len = ((((int) bytes[offset]) & 0xff) - 2) / 2; + if (start >= bytes.length || bytes[start] == 0) + throw new AltosNoSymbol(name); + + int len = ((((int) bytes[start]) & 0xff) - 2) / 2; String fmt = String.format("%%0%dd", len); String s = String.format(fmt, value); - if (s.length() != len) { - System.out.printf("weird usb length issue %s isn't %d\n", - s, len); - return; - } + if (s.length() != len) + throw new AltosNoSymbol(String.format("weird usb length issue %s isn't %d\n", s, len)); + for (int i = 0; i < len; i++) { - bytes[offset + 2 + i*2] = (byte) s.charAt(i); - bytes[offset + 2 + i*2+1] = 0; + bytes[start + 2 + i*2] = (byte) s.charAt(i); + bytes[start + 2 + i*2+1] = 0; } } - public AltosRomconfig(byte[] bytes, int offset) { - version = get_int(bytes, offset + 0, 2); - check = get_int(bytes, offset + 2, 2); - if (check == (~version & 0xffff)) { - switch (version) { - case 2: - case 1: - serial_number = get_int(bytes, offset + 4, 2); - radio_calibration = get_int(bytes, offset + 6, 4); - valid = true; - break; + final static String ao_romconfig_version = "ao_romconfig_version"; + final static String ao_romconfig_check = "ao_romconfig_check"; + final static String ao_serial_number = "ao_serial_number"; + final static String ao_radio_cal = "ao_radio_cal"; + final static String ao_usb_descriptors = "ao_usb_descriptors"; + + public AltosRomconfig(AltosHexfile hexfile) { + try { + version = get_int(hexfile, ao_romconfig_version, 2); + check = get_int(hexfile, ao_romconfig_check, 2); + if (check == (~version & 0xffff)) { + switch (version) { + case 2: + case 1: + serial_number = get_int(hexfile, ao_serial_number, 2); + try { + radio_calibration = get_int(hexfile, ao_radio_cal, 4); + } catch (AltosNoSymbol missing) { + radio_calibration = 0; + } + valid = true; + break; + } } + } catch (AltosNoSymbol missing) { + valid = false; } } - public AltosRomconfig(AltosHexfile hexfile) { - this(hexfile.data, 0xa0 - hexfile.address); + private final static String[] fetch_names = { + ao_romconfig_version, + ao_romconfig_check, + ao_serial_number, + ao_radio_cal + }; + + private final static String[] required_names = { + ao_romconfig_version, + ao_romconfig_check, + ao_serial_number + }; + + private static boolean name_required(String name) { + for (String required : required_names) + if (name.equals(required)) + return true; + return false; } - public void write(byte[] bytes, int offset) throws IOException { + public static int fetch_base(AltosHexfile hexfile) throws AltosNoSymbol { + int base = 0x7fffffff; + for (String name : fetch_names) { + try { + int addr = find_offset(hexfile, name, 2) + hexfile.address; + if (addr < base) + base = addr; + } catch (AltosNoSymbol ns) { + if (name_required(name)) + throw (ns); + } + } + return base; + } + + public static int fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol { + int bounds = 0; + for (String name : fetch_names) { + try { + int addr = find_offset(hexfile, name, 2) + hexfile.address; + if (addr > bounds) + bounds = addr; + } catch (AltosNoSymbol ns) { + if (name_required(name)) + throw (ns); + } + } + return bounds + 2; + } + + public void write (AltosHexfile hexfile) throws IOException { if (!valid) throw new IOException("rom configuration invalid"); - if (offset < 0 || bytes.length < offset + 10) - throw new IOException("image cannot contain rom config"); - - AltosRomconfig existing = new AltosRomconfig(bytes, offset); + AltosRomconfig existing = new AltosRomconfig(hexfile); if (!existing.valid) throw new IOException("image does not contain existing rom config"); - switch (existing.version) { - case 2: - put_usb_serial(serial_number, bytes, offset); - case 1: - put_int(serial_number, bytes, offset + 4, 2); - put_int(radio_calibration, bytes, offset + 6, 4); - break; + try { + switch (existing.version) { + case 2: + try { + put_usb_serial(serial_number, hexfile, ao_usb_descriptors); + } catch (AltosNoSymbol missing) { + } + /* fall through ... */ + case 1: + put_int(serial_number, hexfile, ao_serial_number, 2); + try { + put_int(radio_calibration, hexfile, ao_radio_cal, 4); + } catch (AltosNoSymbol missing) { + } + break; + } + } catch (AltosNoSymbol missing) { + throw new IOException(missing.getMessage()); } - } - public void write (AltosHexfile hexfile) throws IOException { - write(hexfile.data, 0xa0 - hexfile.address); AltosRomconfig check = new AltosRomconfig(hexfile); - if (!check.valid()) + if (!check.valid) throw new IOException("writing new rom config failed\n"); } diff --git a/altoslib/AltosSelfFlash.java b/altoslib/AltosSelfFlash.java new file mode 100644 index 00000000..3bf7ce41 --- /dev/null +++ b/altoslib/AltosSelfFlash.java @@ -0,0 +1,189 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; + +public class AltosSelfFlash extends AltosProgrammer { + File file; + FileInputStream input; + AltosHexfile image; + AltosLink link; + boolean aborted; + AltosFlashListener listener; + AltosRomconfig rom_config; + + 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); + } + + byte[] read_memory(long addr, int len) throws InterruptedException, IOException { + int b; + byte[] data = new byte[len]; + + for (int offset = 0; offset < len; offset += 0x100) { + link.printf("R %x\n", addr + offset); + byte[] reply = link.get_binary_reply(5000, 0x100); + + if (reply == null) + throw new IOException("Read device memory timeout"); + for (b = 0; b < len; b++) + data[b+offset] = reply[b]; + } + return data; + } + + void write_memory(long addr, byte[] data, int start, int len) { + int b; + link.printf("W %x\n", addr); + link.flush_output(); + for (b = 0; b < len; b++) + link.putchar(data[start + b]); + for (; b < 0x100; b++) + link.putchar((byte) 0xff); + } + + void reboot() { + link.printf("a\n"); + link.flush_output(); + } + + public void flash() { + try { + if (!check_rom_config()) + throw new IOException("Invalid rom config settings"); + + /* + * Store desired config values into image + */ + rom_config.write(image); + + 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); + } + close(); + } catch (IOException ie) { + action(ie.getMessage(), -1); + abort(); + } catch (InterruptedException ie) { + abort(); + } + } + + public void close() { + if (link != null) { + reboot(); + try { + link.close(); + } catch (InterruptedException ie) { + } + link = null; + } + } + + synchronized public void abort() { + aborted = true; + close(); + } + + private AltosHexfile get_rom() throws InterruptedException { + try { + int base = AltosRomconfig.fetch_base(image); + int bounds = AltosRomconfig.fetch_bounds(image); + byte[] data = read_memory(base, bounds - base); + AltosHexfile hexfile = new AltosHexfile(data, base); + hexfile.add_symbols(image); + return hexfile; + } catch (AltosNoSymbol none) { + return null; + } catch (IOException ie) { + return null; + } + + } + + public boolean check_rom_config() throws InterruptedException { + if (link == null) { + return true; + } + if (rom_config == null) { + AltosHexfile hexfile = get_rom(); + if (hexfile != null) + rom_config = new AltosRomconfig(hexfile); + } + return rom_config != null && rom_config.valid(); + } + + public void set_romconfig (AltosRomconfig romconfig) { + rom_config = romconfig; + } + + public AltosRomconfig romconfig() throws InterruptedException { + if (!check_rom_config()) + return null; + return rom_config; + } + + public AltosSelfFlash(File file, AltosLink link, AltosFlashListener listener) + throws IOException, FileNotFoundException, InterruptedException { + this.file = file; + this.link = link; + this.listener = listener; + input = new FileInputStream(file); + image = new AltosHexfile(input); + } +}
\ No newline at end of file diff --git a/altoslib/AltosSensorEMini.java b/altoslib/AltosSensorEMini.java new file mode 100644 index 00000000..5f9eed55 --- /dev/null +++ b/altoslib/AltosSensorEMini.java @@ -0,0 +1,69 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.util.concurrent.TimeoutException; + +public class AltosSensorEMini { + public int tick; + public int apogee; + public int main; + public int batt; + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosSensorEMini sensor_emini = new AltosSensorEMini(link); + + if (sensor_emini == null) + return; + state.set_battery_voltage(AltosConvert.easy_mini_voltage(sensor_emini.batt)); + state.set_apogee_voltage(AltosConvert.easy_mini_voltage(sensor_emini.apogee)); + state.set_main_voltage(AltosConvert.easy_mini_voltage(sensor_emini.main)); + + } catch (TimeoutException te) { + } + } + + public AltosSensorEMini(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("apogee:")) { + apogee = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + } +} + diff --git a/altoslib/AltosSensorMM.java b/altoslib/AltosSensorMM.java index 6d1b61c0..0ef42cf6 100644 --- a/altoslib/AltosSensorMM.java +++ b/altoslib/AltosSensorMM.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.util.concurrent.TimeoutException; diff --git a/altoslib/AltosSensorMega.java b/altoslib/AltosSensorMega.java new file mode 100644 index 00000000..e715242a --- /dev/null +++ b/altoslib/AltosSensorMega.java @@ -0,0 +1,108 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.util.concurrent.TimeoutException; + +class AltosSensorMega { + int tick; + int[] sense; + int v_batt; + int v_pbatt; + int temp; + + public AltosSensorMega() { + sense = new int[6]; + } + + public AltosSensorMega(AltosLink link) throws InterruptedException, TimeoutException { + this(); + 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("A:")) { + sense[0] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("B:")) { + sense[1] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("C:")) { + sense[2] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("D:")) { + sense[3] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + sense[4] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + sense[5] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + v_batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pbatt:")) { + v_pbatt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + } + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosSensorMega sensor_mega = new AltosSensorMega(link); + + state.set_battery_voltage(AltosConvert.mega_battery_voltage(sensor_mega.v_batt)); + state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sensor_mega.sense[4])); + state.set_main_voltage(AltosConvert.mega_pyro_voltage(sensor_mega.sense[5])); + + double[] ignitor_voltage = new double[4]; + for (int i = 0; i < 4; i++) + ignitor_voltage[i] = AltosConvert.mega_pyro_voltage(sensor_mega.sense[i]); + state.set_ignitor_voltage(ignitor_voltage); + + } catch (TimeoutException te) { + } + } +} + diff --git a/altoslib/AltosSensorMetrum.java b/altoslib/AltosSensorMetrum.java new file mode 100644 index 00000000..c30eaebd --- /dev/null +++ b/altoslib/AltosSensorMetrum.java @@ -0,0 +1,65 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +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++; + } + } + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosSensorMetrum sensor_metrum = new AltosSensorMetrum(link); + state.set_battery_voltage(AltosConvert.mega_battery_voltage(sensor_metrum.v_batt)); + state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sensor_metrum.sense_a)); + state.set_main_voltage(AltosConvert.mega_pyro_voltage(sensor_metrum.sense_m)); + } catch (TimeoutException te) { + } + } +} + diff --git a/altoslib/AltosSensorTM.java b/altoslib/AltosSensorTM.java index 754dc5bb..f867de4b 100644 --- a/altoslib/AltosSensorTM.java +++ b/altoslib/AltosSensorTM.java @@ -15,14 +15,37 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.util.concurrent.TimeoutException; -class AltosSensorTM extends AltosRecordTM { +public class AltosSensorTM { + public int tick; + public int accel; + public int pres; + public int temp; + public int batt; + public int drogue; + public int main; - public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException { - super(); + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosSensorTM sensor_tm = new AltosSensorTM(link); + + if (sensor_tm == null) + return; + state.set_accel(sensor_tm.accel); + state.set_pressure(AltosConvert.barometer_to_pressure(sensor_tm.pres)); + state.set_temperature(AltosConvert.thermometer_to_temperature(sensor_tm.temp)); + state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(sensor_tm.batt)); + state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(sensor_tm.drogue)); + state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(sensor_tm.main)); + + } catch (TimeoutException te) { + } + } + + public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException { String[] items = link.adc(); for (int i = 0; i < items.length;) { if (items[i].equals("tick:")) { @@ -62,10 +85,6 @@ class AltosSensorTM extends AltosRecordTM { } i++; } - ground_accel = config_data.accel_cal_plus; - ground_pres = pres; - accel_plus_g = config_data.accel_cal_plus; - accel_minus_g = config_data.accel_cal_minus; } } diff --git a/altoslib/AltosSensorTMini.java b/altoslib/AltosSensorTMini.java new file mode 100644 index 00000000..ee030910 --- /dev/null +++ b/altoslib/AltosSensorTMini.java @@ -0,0 +1,69 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.util.concurrent.TimeoutException; + +public class AltosSensorTMini { + public int tick; + public int apogee; + public int main; + public int batt; + + static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException { + try { + AltosSensorTMini sensor_tmini = new AltosSensorTMini(link); + + if (sensor_tmini == null) + return; + state.set_battery_voltage(AltosConvert.easy_mini_voltage(sensor_tmini.batt)); + state.set_apogee_voltage(AltosConvert.easy_mini_voltage(sensor_tmini.apogee)); + state.set_main_voltage(AltosConvert.easy_mini_voltage(sensor_tmini.main)); + + } catch (TimeoutException te) { + } + } + + public AltosSensorTMini(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("apogee:")) { + apogee = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + } +} + diff --git a/altoslib/AltosSpeed.java b/altoslib/AltosSpeed.java index 6fb624fb..6618c539 100644 --- a/altoslib/AltosSpeed.java +++ b/altoslib/AltosSpeed.java @@ -15,29 +15,35 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosSpeed extends AltosUnits { - public double value(double v) { - if (AltosConvert.imperial_units) + public double value(double v, boolean imperial_units) { + if (imperial_units) return AltosConvert.meters_to_mph(v); return v; } - public String show_units() { - if (AltosConvert.imperial_units) + public double inverse(double v, boolean imperial_units) { + if (imperial_units) + return AltosConvert.mph_to_meters(v); + return v; + } + + public String show_units(boolean imperial_units) { + if (imperial_units) return "mph"; return "m/s"; } - public String say_units() { - if (AltosConvert.imperial_units) + public String say_units(boolean imperial_units) { + if (imperial_units) return "miles per hour"; return "meters per second"; } - public int show_fraction(int width) { + public int show_fraction(int width, boolean imperial_units) { return width / 9; } }
\ No newline at end of file diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 825306be..6d55b833 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -19,41 +19,471 @@ * Track flight state from telemetry or eeprom data stream */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosState { - public AltosRecord data; +public class AltosState implements Cloneable { + + public static final int set_position = 1; + public static final int set_gps = 2; + public static final int set_data = 4; + + public int set; + + static final double ascent_filter_len = 0.5; + static final double descent_filter_len = 0.5; /* derived data */ - public long report_time; + public long received_time; public double time; + public double prev_time; public double time_change; public int tick; + private int prev_tick; + public int boost_tick; + + class AltosValue { + private double value; + private double prev_value; + private double max_value; + private double set_time; + private double prev_set_time; + + void set(double new_value, double time) { + if (new_value != AltosLib.MISSING) { + value = new_value; + if (max_value == AltosLib.MISSING || value > max_value) { + max_value = value; + } + set_time = time; + } + } + + void set_filtered(double new_value, double time) { + if (prev_value != AltosLib.MISSING) + new_value = (prev_value * 15.0 + new_value) / 16.0; + set(new_value, time); + } + + double value() { + return value; + } + + double max() { + return max_value; + } + + double prev() { + return prev_value; + } + + double change() { + if (value != AltosLib.MISSING && prev_value != AltosLib.MISSING) + return value - prev_value; + return AltosLib.MISSING; + } + + double rate() { + double c = change(); + double t = set_time - prev_set_time; + + if (c != AltosLib.MISSING && t != 0) + return c / t; + return AltosLib.MISSING; + } + + double integrate() { + if (value == AltosLib.MISSING) + return AltosLib.MISSING; + if (prev_value == AltosLib.MISSING) + return AltosLib.MISSING; + + return (value + prev_value) / 2 * (set_time - prev_set_time); + } + + double time() { + return set_time; + } + + void set_derivative(AltosValue in) { + double n = in.rate(); + + if (n == AltosLib.MISSING) + return; + + double p = prev_value; + double pt = prev_set_time; + + if (p == AltosLib.MISSING) { + p = 0; + pt = in.time() - 0.01; + } + + /* Clip changes to reduce noise */ + double ddt = in.time() - pt; + double ddv = (n - p) / ddt; + + final double max = 100000; + + /* 100gs */ + if (Math.abs(ddv) > max) { + if (n > p) + n = p + ddt * max; + else + n = p - ddt * max; + } + + double filter_len; + + if (ascent) + filter_len = ascent_filter_len; + else + filter_len = descent_filter_len; + + double f = 1/Math.exp(ddt/ filter_len); + n = p * f + n * (1-f); + + set(n, in.time()); + } + + void set_integral(AltosValue in) { + double change = in.integrate(); + + if (change != AltosLib.MISSING) { + double prev = prev_value; + if (prev == AltosLib.MISSING) + prev = 0; + set(prev + change, in.time()); + } + } + + void copy(AltosValue old) { + value = old.value; + set_time = old.set_time; + prev_value = old.value; + prev_set_time = old.set_time; + max_value = old.max_value; + } + + void finish_update() { + prev_value = value; + prev_set_time = set_time; + } + + AltosValue() { + value = AltosLib.MISSING; + prev_value = AltosLib.MISSING; + max_value = AltosLib.MISSING; + } + } + + class AltosCValue { + AltosValue measured; + AltosValue computed; + + double value() { + double v = measured.value(); + if (v != AltosLib.MISSING) + return v; + return computed.value(); + } + + boolean is_measured() { + return measured.value() != AltosLib.MISSING; + } + + double max() { + double m = measured.max(); + + if (m != AltosLib.MISSING) + return m; + return computed.max(); + } + + double prev_value() { + if (measured.value != AltosLib.MISSING && measured.prev_value != AltosLib.MISSING) + return measured.prev_value; + return computed.prev_value; + } + + AltosValue altos_value() { + if (measured.value() != AltosLib.MISSING) + return measured; + return computed; + } + + double change() { + double c = measured.change(); + if (c == AltosLib.MISSING) + c = computed.change(); + return c; + } + + double rate() { + double r = measured.rate(); + if (r == AltosLib.MISSING) + r = computed.rate(); + return r; + } + + void set_measured(double new_value, double time) { + measured.set(new_value, time); + } + + void set_computed(double new_value, double time) { + computed.set(new_value, time); + } + + void set_derivative(AltosValue in) { + computed.set_derivative(in); + } + + void set_derivative(AltosCValue in) { + set_derivative(in.altos_value()); + } + + void set_integral(AltosValue in) { + computed.set_integral(in); + } + + void set_integral(AltosCValue in) { + set_integral(in.altos_value()); + } + + void copy(AltosCValue old) { + measured.copy(old.measured); + computed.copy(old.computed); + } + + void finish_update() { + measured.finish_update(); + computed.finish_update(); + } + + AltosCValue() { + measured = new AltosValue(); + computed = new AltosValue(); + } + } public int state; + public int flight; + public int serial; + public int receiver_serial; public boolean landed; public boolean ascent; /* going up? */ - public boolean boost; /* under power */ + public boolean boost; /* under power */ + public int rssi; + public int status; + public int device_type; + public int config_major; + public int config_minor; + public int apogee_delay; + public int main_deploy; + public int flight_log_max; + + private double pressure_to_altitude(double p) { + if (p == AltosLib.MISSING) + return AltosLib.MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + private AltosCValue ground_altitude; - public double ground_altitude; - public double altitude; - public double height; - public double acceleration; - public double battery; + public double ground_altitude() { + return ground_altitude.value(); + } + + public void set_ground_altitude(double a) { + ground_altitude.set_measured(a, time); + } + + class AltosGroundPressure extends AltosCValue { + void set_filtered(double p, double time) { + computed.set_filtered(p, time); + if (!is_measured()) + ground_altitude.set_computed(pressure_to_altitude(computed.value()), time); + } + + void set_measured(double p, double time) { + super.set_measured(p, time); + ground_altitude.set_computed(pressure_to_altitude(p), time); + } + } + + private AltosGroundPressure ground_pressure; + + public double ground_pressure() { + return ground_pressure.value(); + } + + public void set_ground_pressure (double pressure) { + ground_pressure.set_measured(pressure, time); + } + + class AltosAltitude extends AltosCValue { + + private void set_speed(AltosValue v) { + if (!acceleration.is_measured() || !ascent) + speed.set_derivative(this); + } + + void set_computed(double a, double time) { + super.set_computed(a,time); + set_speed(computed); + set |= set_position; + } + + void set_measured(double a, double time) { + super.set_measured(a,time); + set_speed(measured); + set |= set_position; + } + } + + private AltosAltitude altitude; + + public double altitude() { + double a = altitude.value(); + if (a != AltosLib.MISSING) + return a; + if (gps != null) + return gps.alt; + return AltosLib.MISSING; + } + + public double max_altitude() { + double a = altitude.max(); + if (a != AltosLib.MISSING) + return a; + return AltosLib.MISSING; + } + + public void set_altitude(double new_altitude) { + altitude.set_measured(new_altitude, time); + } + + class AltosPressure extends AltosValue { + void set(double p, double time) { + super.set(p, time); + if (state == AltosLib.ao_flight_pad) + ground_pressure.set_filtered(p, time); + double a = pressure_to_altitude(p); + altitude.set_computed(a, time); + } + } + + private AltosPressure pressure; + + public double pressure() { + return pressure.value(); + } + + public void set_pressure(double p) { + pressure.set(p, time); + } + + public double height() { + double k = kalman_height.value(); + if (k != AltosLib.MISSING) + return k; + + double a = altitude(); + double g = ground_altitude(); + if (a != AltosLib.MISSING && g != AltosLib.MISSING) + return a - g; + return AltosLib.MISSING; + } + + public double max_height() { + double k = kalman_height.max(); + if (k != AltosLib.MISSING) + return k; + + double a = altitude.max(); + double g = ground_altitude(); + if (a != AltosLib.MISSING && g != AltosLib.MISSING) + return a - g; + return AltosLib.MISSING; + } + + class AltosSpeed extends AltosCValue { + + void set_accel() { + acceleration.set_derivative(this); + } + + void set_derivative(AltosCValue in) { + super.set_derivative(in); + set_accel(); + } + + void set_computed(double new_value, double time) { + super.set_computed(new_value, time); + set_accel(); + } + + void set_measured(double new_value, double time) { + super.set_measured(new_value, time); + set_accel(); + } + } + + private AltosSpeed speed; + + public double speed() { + double v = kalman_speed.value(); + if (v != AltosLib.MISSING) + return v; + return speed.value(); + } + + public double max_speed() { + double v = kalman_speed.max(); + if (v != AltosLib.MISSING) + return v; + return speed.max(); + } + + class AltosAccel extends AltosCValue { + void set_measured(double a, double time) { + super.set_measured(a, time); + if (ascent) + speed.set_integral(this.measured); + } + } + + AltosAccel acceleration; + + public double acceleration() { + return acceleration.value(); + } + + public double max_acceleration() { + return acceleration.max(); + } + + public AltosValue kalman_height, kalman_speed, kalman_acceleration; + + public void set_kalman(double height, double speed, double acceleration) { + kalman_height.set(height, time); + kalman_speed.set(speed, time); + kalman_acceleration.set(acceleration, time); + } + + 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 max_height; - public double max_acceleration; - public double max_accel_speed; - public double max_baro_speed; + public double ignitor_voltage[]; public AltosGPS gps; + public AltosGPS temp_gps; + public int temp_gps_sat_tick; + public boolean gps_pending; public int gps_sequence; public AltosIMU imu; @@ -62,10 +492,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 */ @@ -77,202 +508,554 @@ public class AltosState { public int speak_tick; public double speak_altitude; - public double speed() { - if (ascent) - return accel_speed; - else - return baro_speed; + public String callsign; + public String firmware_version; + + public double accel_plus_g; + public double accel_minus_g; + public double accel; + public double ground_accel; + public double ground_accel_avg; + + public int log_format; + + public AltosMs5607 baro; + + public AltosCompanion companion; + + 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 double max_speed() { - if (max_accel_speed != 0) - return max_accel_speed; - return max_baro_speed; - } - - public void init (AltosRecord cur, AltosState prev_state) { - data = cur; - - /* Discard previous state if it was for a different board */ - if (prev_state != null && prev_state.data.serial != data.serial) - prev_state = null; - ground_altitude = data.ground_altitude(); - - altitude = data.altitude(); - if (altitude == AltosRecord.MISSING && data.gps != null) - altitude = data.gps.alt; - - 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; - } + public void init() { + set = 0; + + received_time = System.currentTimeMillis(); + time = AltosLib.MISSING; + time_change = AltosLib.MISSING; + prev_time = AltosLib.MISSING; + tick = AltosLib.MISSING; + prev_tick = AltosLib.MISSING; + boost_tick = AltosLib.MISSING; + state = AltosLib.ao_flight_invalid; + flight = AltosLib.MISSING; + landed = false; + boost = false; + rssi = AltosLib.MISSING; + status = 0; + device_type = AltosLib.MISSING; + config_major = AltosLib.MISSING; + config_minor = AltosLib.MISSING; + apogee_delay = AltosLib.MISSING; + main_deploy = AltosLib.MISSING; + flight_log_max = AltosLib.MISSING; + + ground_altitude = new AltosCValue(); + ground_pressure = new AltosGroundPressure(); + altitude = new AltosAltitude(); + pressure = new AltosPressure(); + speed = new AltosSpeed(); + acceleration = new AltosAccel(); + + temperature = AltosLib.MISSING; + battery_voltage = AltosLib.MISSING; + pyro_voltage = AltosLib.MISSING; + apogee_voltage = AltosLib.MISSING; + main_voltage = AltosLib.MISSING; + ignitor_voltage = null; + + kalman_height = new AltosValue(); + kalman_speed = new AltosValue(); + kalman_acceleration = new AltosValue(); + + gps = null; + temp_gps = null; + temp_gps_sat_tick = 0; + gps_sequence = 0; + gps_pending = false; + + imu = null; + mag = null; + + set_npad(0); + ngps = 0; + + from_pad = null; + elevation = AltosLib.MISSING; + range = AltosLib.MISSING; + gps_height = AltosLib.MISSING; + + pad_lat = AltosLib.MISSING; + pad_lon = AltosLib.MISSING; + pad_alt = AltosLib.MISSING; + + speak_tick = AltosLib.MISSING; + speak_altitude = AltosLib.MISSING; + + callsign = null; + + accel_plus_g = AltosLib.MISSING; + accel_minus_g = AltosLib.MISSING; + accel = AltosLib.MISSING; + + ground_accel = AltosLib.MISSING; + ground_accel_avg = AltosLib.MISSING; + + log_format = AltosLib.MISSING; + serial = AltosLib.MISSING; + receiver_serial = AltosLib.MISSING; + + baro = null; + companion = null; + } + + void finish_update() { + prev_tick = tick; + + ground_altitude.finish_update(); + altitude.finish_update(); + pressure.finish_update(); + speed.finish_update(); + acceleration.finish_update(); + + kalman_height.finish_update(); + kalman_speed.finish_update(); + kalman_acceleration.finish_update(); + } + + void copy(AltosState old) { + + if (old == null) { + init(); + return; } - report_time = System.currentTimeMillis(); + received_time = old.received_time; + time = old.time; + time_change = old.time_change; + prev_time = old.time; + + tick = old.tick; + prev_tick = old.tick; + boost_tick = old.boost_tick; + + state = old.state; + flight = old.flight; + landed = old.landed; + ascent = old.ascent; + boost = old.boost; + rssi = old.rssi; + status = old.status; + device_type = old.device_type; + config_major = old.config_major; + config_minor = old.config_minor; + apogee_delay = old.apogee_delay; + main_deploy = old.main_deploy; + flight_log_max = old.flight_log_max; + + set = 0; + + ground_pressure.copy(old.ground_pressure); + ground_altitude.copy(old.ground_altitude); + altitude.copy(old.altitude); + pressure.copy(old.pressure); + speed.copy(old.speed); + acceleration.copy(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; + ignitor_voltage = old.ignitor_voltage; + + kalman_height.copy(old.kalman_height); + kalman_speed.copy(old.kalman_speed); + kalman_acceleration.copy(old.kalman_acceleration); - if (data.kalman_acceleration != AltosRecord.MISSING) - acceleration = data.kalman_acceleration; + if (old.gps != null) + gps = old.gps.clone(); else - acceleration = data.acceleration(); - temperature = data.temperature(); - drogue_sense = data.drogue_voltage(); - main_sense = data.main_voltage(); - battery = data.battery_voltage(); - tick = data.tick; - state = data.state; - - if (prev_state != null) { - - /* 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; - - if (data.kalman_speed != AltosRecord.MISSING) { - baro_speed = accel_speed = data.kalman_speed; - } else { - /* compute barometric speed */ - - double height_change = height - prev_state.height; - - double prev_baro_speed = prev_state.baro_speed; - if (prev_baro_speed == AltosRecord.MISSING) - prev_baro_speed = 0; - - if (time_change > 0) - baro_speed = (prev_baro_speed * 3 + (height_change / time_change)) / 4.0; - else - baro_speed = prev_state.baro_speed; + gps = null; + if (old.temp_gps != null) + temp_gps = old.temp_gps.clone(); + else + temp_gps = null; + temp_gps_sat_tick = old.temp_gps_sat_tick; + gps_sequence = old.gps_sequence; + gps_pending = old.gps_pending; - double prev_accel_speed = prev_state.accel_speed; + if (old.imu != null) + imu = old.imu.clone(); + else + imu = null; - if (prev_accel_speed == AltosRecord.MISSING) - prev_accel_speed = 0; + if (old.mag != null) + mag = old.mag.clone(); + else + mag = null; - if (acceleration == AltosRecord.MISSING) { - /* Fill in mising acceleration value */ - accel_speed = baro_speed; + npad = old.npad; + gps_waiting = old.gps_waiting; + gps_ready = old.gps_ready; + ngps = old.ngps; - if (time_change > 0 && accel_speed != AltosRecord.MISSING) - acceleration = (accel_speed - prev_accel_speed) / time_change; - else - acceleration = prev_state.acceleration; - } else { - /* compute accelerometer speed */ - accel_speed = prev_accel_speed + acceleration * time_change; + 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; + accel = old.accel; + ground_accel = old.ground_accel; + ground_accel_avg = old.ground_accel_avg; + + log_format = old.log_format; + serial = old.serial; + receiver_serial = old.receiver_serial; + + baro = old.baro; + companion = old.companion; + } + + void update_time() { + } + + void update_gps() { + elevation = 0; + range = -1; + gps_height = 0; + + if (gps == null) + return; + + if (gps.locked && gps.nsat >= 4) { + /* Track consecutive 'good' gps reports, waiting for 10 of them */ + if (state == AltosLib.ao_flight_pad) { + set_npad(npad+1); + if (pad_lat != AltosLib.MISSING) { + pad_lat = (pad_lat * 31 + gps.lat) / 32; + pad_lon = (pad_lon * 31 + gps.lon) / 32; + pad_alt = (pad_alt * 31 + gps.alt) / 32; } } - } else { - npad = 0; - ngps = 0; - gps = null; - gps_sequence = 0; - baro_speed = AltosRecord.MISSING; - accel_speed = AltosRecord.MISSING; - pad_alt = AltosRecord.MISSING; - max_baro_speed = 0; - max_accel_speed = 0; - max_height = 0; - max_acceleration = 0; - time_change = 0; + if (pad_lat == AltosLib.MISSING) { + pad_lat = gps.lat; + pad_lon = gps.lon; + pad_alt = gps.alt; + } } + if (gps.lat != 0 && gps.lon != 0 && + pad_lat != AltosLib.MISSING && + pad_lon != AltosLib.MISSING) + { + double h = height(); - time = tick / 100.0; - - if (data.gps != null && data.gps_sequence != gps_sequence && (state < AltosLib.ao_flight_boost)) { + if (h == AltosLib.MISSING) + h = 0; + from_pad = new AltosGreatCircle(pad_lat, pad_lon, 0, gps.lat, gps.lon, h); + elevation = from_pad.elevation; + range = from_pad.range; + gps_height = gps.alt - pad_alt; + } + } - /* Track consecutive 'good' gps reports, waiting for 10 of them */ - if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) - npad++; - else - npad = 0; - - /* Average GPS data while on the pad */ - if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { - if (ngps > 1 && state == AltosLib.ao_flight_pad) { - /* filter pad position */ - pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0; - pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0; - pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0; - } else { - pad_lat = data.gps.lat; - pad_lon = data.gps.lon; - pad_alt = data.gps.alt; + public void set_tick(int new_tick) { + if (new_tick != AltosLib.MISSING) { + if (prev_tick != AltosLib.MISSING) { + while (new_tick < prev_tick - 1000) { + new_tick += 65536; } - ngps++; } - } else { - if (ngps == 0 && ground_altitude != AltosRecord.MISSING) - pad_alt = ground_altitude; + tick = new_tick; + time = tick / 100.0; + time_change = time - prev_time; } + } - gps_sequence = data.gps_sequence; + public void set_boost_tick(int boost_tick) { + if (boost_tick != AltosLib.MISSING) + this.boost_tick = boost_tick; + } - gps_waiting = MIN_PAD_SAMPLES - npad; - if (gps_waiting < 0) - gps_waiting = 0; + public String state_name() { + return AltosLib.state_name(state); + } - gps_ready = gps_waiting == 0; + 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); + } - 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; - if (boost && accel_speed != AltosRecord.MISSING && accel_speed > max_accel_speed) - max_accel_speed = accel_speed; - if (boost && baro_speed != AltosRecord.MISSING && baro_speed > max_baro_speed) - max_baro_speed = baro_speed; + public void set_device_type(int device_type) { + this.device_type = device_type; + } - if (height != AltosRecord.MISSING && height > max_height) - max_height = height; - elevation = 0; - range = -1; - gps_height = 0; - if (data.gps != null) { - gps = data.gps; - if (ngps > 0 && gps.locked) { - double h = height; - - if (h == AltosRecord.MISSING) h = 0; - from_pad = new AltosGreatCircle(pad_lat, pad_lon, 0, gps.lat, gps.lon, h); - elevation = from_pad.elevation; - range = from_pad.range; - gps_height = gps.alt - pad_alt; + public void set_config(int major, int minor, int apogee_delay, int main_deploy, int flight_log_max) { + config_major = major; + config_minor = minor; + this.apogee_delay = apogee_delay; + this.main_deploy = main_deploy; + this.flight_log_max = flight_log_max; + } + + public void set_callsign(String callsign) { + this.callsign = callsign; + } + + public void set_firmware_version(String version) { + firmware_version = version; + } + + public void set_flight(int flight) { + + /* When the flight changes, reset the state */ + if (flight != AltosLib.MISSING && flight != 0) { + if (this.flight != AltosLib.MISSING && + this.flight != flight) { + int bt = boost_tick; + init(); + boost_tick = bt; + } + this.flight = flight; + } + } + + public void set_serial(int serial) { + /* When the serial changes, reset the state */ + if (serial != AltosLib.MISSING) { + if (this.serial != AltosLib.MISSING && + this.serial != serial) { + int bt = boost_tick; + init(); + boost_tick = bt; + } + this.serial = serial; + } + } + + public void set_receiver_serial(int serial) { + if (serial != AltosLib.MISSING) + receiver_serial = serial; + } + + public int rssi() { + if (rssi == AltosLib.MISSING) + return 0; + return rssi; + } + + public void set_rssi(int rssi, int status) { + if (rssi != AltosLib.MISSING) { + this.rssi = rssi; + this.status = status; + } + } + + public void set_received_time(long ms) { + received_time = ms; + } + + public void set_gps(AltosGPS gps, int sequence) { + if (gps != null) { + this.gps = gps.clone(); + gps_sequence = sequence; + update_gps(); + set |= set_gps; + } + } + + public void set_imu(AltosIMU imu) { + if (imu != null) + imu = imu.clone(); + this.imu = imu; + } + + public void set_mag(AltosMag mag) { + this.mag = mag.clone(); + } + + public AltosMs5607 make_baro() { + if (baro == null) + baro = new AltosMs5607(); + return baro; + } + + public void set_ms5607(AltosMs5607 ms5607) { + baro = ms5607; + + if (baro != null) { + set_pressure(baro.pa); + set_temperature(baro.cc / 100.0); + } + } + + public void set_ms5607(int pres, int temp) { + if (baro != null) { + baro.set(pres, temp); + + set_pressure(baro.pa); + set_temperature(baro.cc / 100.0); + } + } + + public void make_companion (int nchannels) { + if (companion == null) + companion = new AltosCompanion(nchannels); + } + + public void set_companion(AltosCompanion companion) { + this.companion = companion; + } + + void update_accel() { + double ground = ground_accel; + + if (ground == AltosLib.MISSING) + ground = ground_accel_avg; + if (accel == AltosLib.MISSING) + return; + if (ground == AltosLib.MISSING) + return; + if (accel_plus_g == AltosLib.MISSING) + return; + if (accel_minus_g == AltosLib.MISSING) + return; + + double counts_per_g = (accel_minus_g - accel_plus_g) / 2.0; + double counts_per_mss = counts_per_g / 9.80665; + acceleration.set_measured((ground - accel) / counts_per_mss, time); + } + + public void set_accel_g(double accel_plus_g, double accel_minus_g) { + if (accel_plus_g != AltosLib.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 != AltosLib.MISSING) { + this.ground_accel = ground_accel; + update_accel(); + } + } + + public void set_accel(double accel) { + if (accel != AltosLib.MISSING) { + this.accel = accel; + if (state == AltosLib.ao_flight_pad) { + if (ground_accel_avg == AltosLib.MISSING) + ground_accel_avg = accel; + else + ground_accel_avg = (ground_accel_avg * 7 + accel) / 8; } } + update_accel(); + } + + public void set_temperature(double temperature) { + if (temperature != AltosLib.MISSING) { + this.temperature = temperature; + set |= set_data; + } + } + + public void set_battery_voltage(double battery_voltage) { + if (battery_voltage != AltosLib.MISSING) { + this.battery_voltage = battery_voltage; + set |= set_data; + } + } + + public void set_pyro_voltage(double pyro_voltage) { + if (pyro_voltage != AltosLib.MISSING) { + this.pyro_voltage = pyro_voltage; + set |= set_data; + } + } + + public void set_apogee_voltage(double apogee_voltage) { + if (apogee_voltage != AltosLib.MISSING) { + this.apogee_voltage = apogee_voltage; + set |= set_data; + } + } + + public void set_main_voltage(double main_voltage) { + if (main_voltage != AltosLib.MISSING) { + this.main_voltage = main_voltage; + set |= set_data; + } + } + + public void set_ignitor_voltage(double[] voltage) { + this.ignitor_voltage = voltage; + } + + public double time_since_boost() { + if (tick == AltosLib.MISSING) + return 0.0; + + if (boost_tick == AltosLib.MISSING) + return tick / 100.0; + return (tick - boost_tick) / 100.0; + } + + public boolean valid() { + return tick != AltosLib.MISSING && serial != AltosLib.MISSING; + } + + public AltosGPS make_temp_gps(boolean sats) { + if (temp_gps == null) { + temp_gps = new AltosGPS(gps); + } + gps_pending = true; + if (sats) { + if (tick != temp_gps_sat_tick) + temp_gps.cc_gps_sat = null; + temp_gps_sat_tick = tick; + } + return temp_gps; + } + + public void set_temp_gps() { + set_gps(temp_gps, gps_sequence + 1); + gps_pending = false; + temp_gps = null; } - public AltosState(AltosRecord cur) { - init(cur, null); + public AltosState clone() { + AltosState s = new AltosState(); + s.copy(this); + return s; } - public AltosState (AltosRecord cur, AltosState prev) { - init(cur, prev); + public AltosState () { + init(); } } diff --git a/altoslib/AltosRecordIterable.java b/altoslib/AltosStateIterable.java index 62dbdfe3..6d637419 100644 --- a/altoslib/AltosRecordIterable.java +++ b/altoslib/AltosStateIterable.java @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Keith Packard <keithp@keithp.com> + * Copyright © 2013 Keith Packard <keithp@keithp.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,15 +15,15 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.*; -public abstract class AltosRecordIterable implements Iterable<AltosRecord> { - public abstract Iterator<AltosRecord> iterator(); - public void write_comments(PrintStream out) { } - public boolean has_accel() { return false; } - public boolean has_gps() { return false; } - public boolean has_ignite() { return false; }; +public abstract class AltosStateIterable implements Iterable<AltosState> { + + public void write_comments (PrintStream out) { + } + + public abstract void write(PrintStream out); } diff --git a/altoslib/AltosStateUpdate.java b/altoslib/AltosStateUpdate.java new file mode 100644 index 00000000..97a5dfe2 --- /dev/null +++ b/altoslib/AltosStateUpdate.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +public interface AltosStateUpdate { + public void update_state(AltosState state) throws InterruptedException; +}
\ No newline at end of file diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index e7322349..03ca9f80 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; @@ -23,217 +23,114 @@ import java.text.*; * Telemetry data contents */ +public abstract class AltosTelemetry implements AltosStateUpdate { -/* - * The packet format is a simple hex dump of the raw telemetry frame. - * It starts with 'TELEM', then contains hex digits with a checksum as the last - * byte on the line. - * - * Version 4 is a replacement with consistent syntax. Each telemetry line - * contains a sequence of space-separated names and values, the values are - * either integers or strings. The names are all unique. All values are - * optional - * - * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 - * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 - * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 - * - * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 - * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 - * - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - * - * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports - * in 1/2dB increments while this protocol provides only integers. So, - * the syntax didn't change just the interpretation of the RSSI - * values. - * - * Version 2 of the telemetry data stream is a bit of a mess, with no - * consistent formatting. In particular, the GPS data is formatted for - * viewing instead of parsing. However, the key feature is that every - * telemetry line contains all of the information necessary to - * describe the current rocket state, including the calibration values - * for accelerometer and barometer. - * - * GPS unlocked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ - * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ - * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 - * - * GPS locked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ - * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ - * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ - * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ - * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ - * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 - * - */ + /* All telemetry packets have these fields */ + public int tick; + public int serial; + public int rssi; + public int status; + + /* Mark when we received the packet */ + long received_time; + + static boolean cksum(int[] bytes) { + int sum = 0x5a; + for (int i = 1; i < bytes.length - 1; i++) + sum += bytes[i]; + sum &= 0xff; + return sum == bytes[bytes.length - 1]; + } + + public void update_state(AltosState state) { + if (state.state == AltosLib.ao_flight_invalid) + state.set_state(AltosLib.ao_flight_startup); + state.set_serial(serial); + state.set_tick(tick); + state.set_rssi(rssi, status); + state.set_received_time(received_time); + } + + final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); + final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); + final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; + + final static int packet_type_TM_sensor = 0x01; + final static int packet_type_Tm_sensor = 0x02; + final static int packet_type_Tn_sensor = 0x03; + final static int packet_type_configuration = 0x04; + final static int packet_type_location = 0x05; + final static int packet_type_satellite = 0x06; + final static int packet_type_companion = 0x07; + final static int packet_type_mega_sensor = 0x08; + final static int packet_type_mega_data = 0x09; + final static int packet_type_metrum_sensor = 0x0a; + final static int packet_type_metrum_data = 0x0b; + final static int packet_type_mini = 0x10; + + static AltosTelemetry parse_hex(String hex) throws ParseException, AltosCRCException { + AltosTelemetry telem = null; + + int[] bytes; + try { + bytes = AltosLib.hexbytes(hex); + } catch (NumberFormatException ne) { + throw new ParseException(ne.getMessage(), 0); + } + + /* one for length, one for checksum */ + if (bytes[0] != bytes.length - 2) + throw new ParseException(String.format("invalid length %d != %d\n", + bytes[0], + bytes.length - 2), 0); + if (!cksum(bytes)) + throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + + int rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74; + int status = AltosLib.uint8(bytes, bytes.length - 2); + + if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) + throw new AltosCRCException(rssi); + + /* length, data ..., rssi, status, checksum -- 4 bytes extra */ + switch (bytes.length) { + case AltosLib.ao_telemetry_standard_len + 4: + telem = AltosTelemetryStandard.parse_hex(bytes); + break; + case AltosLib.ao_telemetry_0_9_len + 4: + telem = new AltosTelemetryLegacy(bytes); + break; + case AltosLib.ao_telemetry_0_8_len + 4: + telem = new AltosTelemetryLegacy(bytes); + break; + default: + throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); + } + if (telem != null) { + telem.received_time = System.currentTimeMillis(); + telem.rssi = rssi; + telem.status = status; + } + return telem; + } + + public static AltosTelemetry parse(String line) throws ParseException, AltosCRCException { + String[] word = line.split("\\s+"); + int i =0; + + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + AltosTelemetry telem; -public abstract class AltosTelemetry extends AltosRecord { - - /* - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - */ - - final static String AO_TELEM_VERSION = "VERSION"; - final static String AO_TELEM_CALL = "c"; - final static String AO_TELEM_SERIAL = "n"; - final static String AO_TELEM_FLIGHT = "f"; - final static String AO_TELEM_RSSI = "r"; - final static String AO_TELEM_STATE = "s"; - final static String AO_TELEM_TICK = "t"; - - /* - * Raw sensor values - * - * Name Value - * r_a Accelerometer reading (integer) - * r_b Barometer reading (integer) - * r_t Thermometer reading (integer) - * r_v Battery reading (integer) - * r_d Drogue continuity (integer) - * r_m Main continuity (integer) - */ - - final static String AO_TELEM_RAW_ACCEL = "r_a"; - final static String AO_TELEM_RAW_BARO = "r_b"; - final static String AO_TELEM_RAW_THERMO = "r_t"; - final static String AO_TELEM_RAW_BATT = "r_v"; - final static String AO_TELEM_RAW_DROGUE = "r_d"; - final static String AO_TELEM_RAW_MAIN = "r_m"; - - /* - * Sensor calibration values - * - * Name Value - * c_a Ground accelerometer reading (integer) - * c_b Ground barometer reading (integer) - * c_p Accelerometer reading for +1g - * c_m Accelerometer reading for -1g - */ - - final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; - final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; - final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; - final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; - - /* - * Kalman state values - * - * Name Value - * k_h Height above pad (integer, meters) - * k_s Vertical speeed (integer, m/s * 16) - * k_a Vertical acceleration (integer, m/s² * 16) - */ - - final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; - final static String AO_TELEM_KALMAN_SPEED = "k_s"; - final static String AO_TELEM_KALMAN_ACCEL = "k_a"; - - /* - * Ad-hoc flight values - * - * Name Value - * a_a Acceleration (integer, sensor units) - * a_s Speed (integer, integrated acceleration value) - * a_b Barometer reading (integer, sensor units) - */ - - final static String AO_TELEM_ADHOC_ACCEL = "a_a"; - final static String AO_TELEM_ADHOC_SPEED = "a_s"; - final static String AO_TELEM_ADHOC_BARO = "a_b"; - - /* - * GPS values - * - * Name Value - * g_s GPS state (string): - * l locked - * u unlocked - * e error (missing or broken) - * g_n Number of sats used in solution - * g_ns Latitude (degrees * 10e7) - * g_ew Longitude (degrees * 10e7) - * g_a Altitude (integer meters) - * g_Y GPS year (integer) - * g_M GPS month (integer - 1-12) - * g_D GPS day (integer - 1-31) - * g_h GPS hour (integer - 0-23) - * g_m GPS minute (integer - 0-59) - * g_s GPS second (integer - 0-59) - * g_v GPS vertical speed (integer, cm/sec) - * g_s GPS horizontal speed (integer, cm/sec) - * g_c GPS course (integer, 0-359) - * g_hd GPS hdop (integer * 10) - * g_vd GPS vdop (integer * 10) - * g_he GPS h error (integer) - * g_ve GPS v error (integer) - */ - - final static String AO_TELEM_GPS_STATE = "g"; - final static String AO_TELEM_GPS_STATE_LOCKED = "l"; - final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; - final static String AO_TELEM_GPS_STATE_ERROR = "e"; - final static String AO_TELEM_GPS_NUM_SAT = "g_n"; - final static String AO_TELEM_GPS_LATITUDE = "g_ns"; - final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; - final static String AO_TELEM_GPS_ALTITUDE = "g_a"; - final static String AO_TELEM_GPS_YEAR = "g_Y"; - final static String AO_TELEM_GPS_MONTH = "g_M"; - final static String AO_TELEM_GPS_DAY = "g_D"; - final static String AO_TELEM_GPS_HOUR = "g_h"; - final static String AO_TELEM_GPS_MINUTE = "g_m"; - final static String AO_TELEM_GPS_SECOND = "g_s"; - final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; - final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; - final static String AO_TELEM_GPS_COURSE = "g_c"; - final static String AO_TELEM_GPS_HDOP = "g_hd"; - final static String AO_TELEM_GPS_VDOP = "g_vd"; - final static String AO_TELEM_GPS_HERROR = "g_he"; - final static String AO_TELEM_GPS_VERROR = "g_ve"; - - /* - * GPS satellite values - * - * Name Value - * s_n Number of satellites reported (integer) - * s_v0 Space vehicle ID (integer) for report 0 - * s_c0 C/N0 number (integer) for report 0 - * s_v1 Space vehicle ID (integer) for report 1 - * s_c1 C/N0 number (integer) for report 1 - * ... - */ - - final static String AO_TELEM_SAT_NUM = "s_n"; - final static String AO_TELEM_SAT_SVID = "s_v"; - final static String AO_TELEM_SAT_C_N_0 = "s_c"; - - static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { - AltosTelemetryRecord r = AltosTelemetryRecord.parse(line); - - return r.update_state(previous); + if (word[i].equals("TELEM")) { + telem = parse_hex(word[i+1]); + } else { + telem = new AltosTelemetryLegacy(line); + } + return telem; } } diff --git a/altoslib/AltosTelemetryRecordConfiguration.java b/altoslib/AltosTelemetryConfiguration.java index 47fc3488..e5d444dd 100644 --- a/altoslib/AltosTelemetryRecordConfiguration.java +++ b/altoslib/AltosTelemetryConfiguration.java @@ -15,10 +15,10 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { +public class AltosTelemetryConfiguration extends AltosTelemetryStandard { int device_type; int flight; int config_major; @@ -29,8 +29,8 @@ public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { String callsign; String version; - public AltosTelemetryRecordConfiguration(int[] in_bytes, int rssi) { - super(in_bytes, rssi); + public AltosTelemetryConfiguration(int[] bytes) { + super(bytes); device_type = uint8(5); flight = uint16(6); @@ -43,22 +43,13 @@ public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { version = string(24, 8); } - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); + public void update_state(AltosState state) { + super.update_state(state); + state.set_device_type(device_type); + state.set_flight(flight); + state.set_config(config_major, config_minor, apogee_delay, main_deploy, flight_log_max); - next.device_type = device_type; - next.flight = flight; - next.config_major = config_major; - next.config_minor = config_minor; - next.apogee_delay = apogee_delay; - next.main_deploy = main_deploy; - next.flight_log_max = flight_log_max; - - next.callsign = callsign; - next.firmware_version = version; - - next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight; - - return next; + state.set_callsign(callsign); + state.set_firmware_version(version); } } diff --git a/altoslib/AltosTelemetryFile.java b/altoslib/AltosTelemetryFile.java new file mode 100644 index 00000000..7566d946 --- /dev/null +++ b/altoslib/AltosTelemetryFile.java @@ -0,0 +1,96 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +import java.io.*; +import java.util.*; +import java.text.*; + +class AltosTelemetryIterator implements Iterator<AltosState> { + AltosState state; + Iterator<AltosTelemetry> telems; + AltosTelemetry next; + boolean seen; + + public boolean hasNext() { + return !seen || telems.hasNext(); + } + + public AltosState next() { + if (seen) { + AltosState n = state.clone(); + AltosTelemetry t = telems.next(); + + t.update_state(n); + state = n; + } + seen = true; + return state; + } + + public void remove () { + } + + public AltosTelemetryIterator(AltosState start, Iterator<AltosTelemetry> telems) { + this.state = start; + this.telems = telems; + this.seen = false; + } +} + +public class AltosTelemetryFile extends AltosStateIterable { + + AltosTelemetryIterable telems; + AltosState start; + + public void write_comments(PrintStream out) { + } + + public void write(PrintStream out) { + + } + + public AltosTelemetryFile(FileInputStream input) { + telems = new AltosTelemetryIterable(input); + start = new AltosState(); + + /* Find boost tick */ + AltosState state = start.clone(); + + for (AltosTelemetry telem : telems) { + telem.update_state(state); + state.finish_update(); + if (state.state != AltosLib.ao_flight_invalid && state.state >= AltosLib.ao_flight_boost) { + start.set_boost_tick(state.tick); + break; + } + } + } + + public Iterator<AltosState> iterator() { + AltosState state = start.clone(); + Iterator<AltosTelemetry> i = telems.iterator(); + + while (i.hasNext() && !state.valid()) { + AltosTelemetry t = i.next(); + t.update_state(state); + state.finish_update(); + } + return new AltosTelemetryIterator(state, i); + } +}
\ No newline at end of file diff --git a/altoslib/AltosTelemetryIterable.java b/altoslib/AltosTelemetryIterable.java index 57033638..bf30b4c8 100644 --- a/altoslib/AltosTelemetryIterable.java +++ b/altoslib/AltosTelemetryIterable.java @@ -15,33 +15,74 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.io.*; import java.util.*; import java.text.*; -public class AltosTelemetryIterable extends AltosRecordIterable { - TreeSet<AltosRecord> records; +class AltosTelemetryOrdered implements Comparable<AltosTelemetryOrdered> { + AltosTelemetry telem; + int index; + int tick; - public Iterator<AltosRecord> iterator () { - return records.iterator(); + public int compareTo(AltosTelemetryOrdered o) { + int tick_diff = tick - o.tick; + + if (tick_diff != 0) + return tick_diff; + return index - o.index; } - boolean has_gps = false; - boolean has_accel = false; - boolean has_ignite = false; - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; }; + AltosTelemetryOrdered (AltosTelemetry telem, int index, int tick) { + this.telem = telem; + this.index = index; + this.tick = tick; + } +} - public AltosTelemetryIterable (FileInputStream input) { - boolean saw_boost = false; - int current_tick = 0; - int boost_tick = 0; +class AltosTelemetryOrderedIterator implements Iterator<AltosTelemetry> { + Iterator<AltosTelemetryOrdered> iterator; + + public AltosTelemetryOrderedIterator(TreeSet<AltosTelemetryOrdered> telems) { + iterator = telems.iterator(); + } + + public boolean hasNext() { + return iterator.hasNext(); + } - AltosRecord previous = null; - records = new TreeSet<AltosRecord> (); + public AltosTelemetry next() { + return iterator.next().telem; + } + + public void remove () { + } +} + +public class AltosTelemetryIterable implements Iterable<AltosTelemetry> { + TreeSet<AltosTelemetryOrdered> telems; + int tick; + int index; + + public void add (AltosTelemetry telem) { + int t = telem.tick; + if (!telems.isEmpty()) { + while (t < tick - 1000) + t += 65536; + } + tick = t; + telems.add(new AltosTelemetryOrdered(telem, index++, tick)); + } + + public Iterator<AltosTelemetry> iterator () { + return new AltosTelemetryOrderedIterator(telems); + } + + public AltosTelemetryIterable (FileInputStream input) { + telems = new TreeSet<AltosTelemetryOrdered> (); + tick = 0; + index = 0; try { for (;;) { @@ -50,32 +91,10 @@ public class AltosTelemetryIterable extends AltosRecordIterable { break; } try { - AltosRecord record = AltosTelemetry.parse(line, previous); - if (record == null) + AltosTelemetry telem = AltosTelemetry.parse(line); + if (telem == null) break; - if (records.isEmpty()) { - current_tick = record.tick; - } else { - int tick = record.tick; - while (tick < current_tick - 0x1000) - tick += 0x10000; - current_tick = tick; - record.tick = current_tick; - } - if (!saw_boost && record.state >= AltosLib.ao_flight_boost) - { - saw_boost = true; - boost_tick = record.tick; - } - if (record.acceleration() != AltosRecord.MISSING) - has_accel = true; - if (record.gps != null) - has_gps = true; - if (record.main_voltage() != AltosRecord.MISSING) - has_ignite = true; - if (previous != null && previous.tick != record.tick) - records.add(previous); - previous = record; + add(telem); } catch (ParseException pe) { System.out.printf("parse exception %s\n", pe.getMessage()); } catch (AltosCRCException ce) { @@ -84,26 +103,5 @@ public class AltosTelemetryIterable extends AltosRecordIterable { } catch (IOException io) { System.out.printf("io exception\n"); } - - if (previous != null) - records.add(previous); - - /* Adjust all tick counts to match expected eeprom values, - * which starts with a 16-bit tick count 16 samples before boost - */ - - int tick_adjust = (boost_tick - 16) & 0xffff0000; - for (AltosRecord r : this) - r.tick -= tick_adjust; - boost_tick -= tick_adjust; - - /* adjust all tick counts to be relative to boost time */ - for (AltosRecord r : this) - r.time = (r.tick - boost_tick) / 100.0; - - try { - input.close(); - } catch (IOException ie) { - } } } diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryLegacy.java index f2d3f868..132b9e80 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryLegacy.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; @@ -82,7 +82,7 @@ import java.text.*; * */ -public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { +public class AltosTelemetryLegacy extends AltosTelemetry { /* * General header fields * @@ -230,156 +230,184 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { final static String AO_TELEM_SAT_SVID = "s_v"; final static String AO_TELEM_SAT_C_N_0 = "s_c"; - AltosRecordTM record; + public int version; + public String callsign; + public int flight; + public int state; + + public AltosGPS gps; + public int gps_sequence; + + /* Telemetry sources have these values recorded from the flight computer */ + public double kalman_height; + public double kalman_speed; + public double kalman_acceleration; + + /* Sensor values */ + public int accel; + public int pres; + public int temp; + public int batt; + public int apogee; + public int main; + + 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; private void parse_v4(String[] words, int i) throws ParseException { AltosTelemetryMap map = new AltosTelemetryMap(words, i); - record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); - record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); - record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); - record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); - record.state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid")); - record.tick = map.get_int(AO_TELEM_TICK, 0); + callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); + serial = map.get_int(AO_TELEM_SERIAL, AltosLib.MISSING); + flight = map.get_int(AO_TELEM_FLIGHT, AltosLib.MISSING); + rssi = map.get_int(AO_TELEM_RSSI, AltosLib.MISSING); + state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid")); + tick = map.get_int(AO_TELEM_TICK, 0); /* raw sensor values */ - record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING); - record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); - record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); - record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); - record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); - record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); + accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosLib.MISSING); + pres = map.get_int(AO_TELEM_RAW_BARO, AltosLib.MISSING); + temp = map.get_int(AO_TELEM_RAW_THERMO, AltosLib.MISSING); + batt = map.get_int(AO_TELEM_RAW_BATT, AltosLib.MISSING); + apogee = map.get_int(AO_TELEM_RAW_DROGUE, AltosLib.MISSING); + main = map.get_int(AO_TELEM_RAW_MAIN, AltosLib.MISSING); /* sensor calibration information */ - record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); - record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); - record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); - record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); + ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosLib.MISSING); + ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosLib.MISSING); + accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosLib.MISSING); + accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosLib.MISSING); /* flight computer values */ - record.kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); - record.kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); - record.kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); + kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosLib.MISSING, 1/16.0); + kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosLib.MISSING, 1/16.0); + kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosLib.MISSING); - record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); - record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); - record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING); + flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosLib.MISSING); + flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosLib.MISSING); + flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosLib.MISSING); - if (map.has(AO_TELEM_GPS_STATE)) { - record.gps = new AltosGPS(map); - record.gps_sequence++; - } + if (map.has(AO_TELEM_GPS_STATE)) + gps = new AltosGPS(map); else - record.gps = null; + gps = null; } private void parse_legacy(String[] words, int i) throws ParseException { AltosParse.word (words[i++], "CALL"); - record.callsign = words[i++]; + callsign = words[i++]; AltosParse.word (words[i++], "SERIAL"); - record.serial = AltosParse.parse_int(words[i++]); + serial = AltosParse.parse_int(words[i++]); - if (record.version >= 2) { + if (version >= 2) { AltosParse.word (words[i++], "FLIGHT"); - record.flight = AltosParse.parse_int(words[i++]); + flight = AltosParse.parse_int(words[i++]); } else - record.flight = 0; + flight = 0; AltosParse.word(words[i++], "RSSI"); - record.rssi = AltosParse.parse_int(words[i++]); + rssi = AltosParse.parse_int(words[i++]); /* Older telemetry data had mis-computed RSSI value */ - if (record.version <= 2) - record.rssi = (record.rssi + 74) / 2 - 74; + if (version <= 2) + rssi = (rssi + 74) / 2 - 74; AltosParse.word(words[i++], "STATUS"); - record.status = AltosParse.parse_hex(words[i++]); + status = AltosParse.parse_hex(words[i++]); AltosParse.word(words[i++], "STATE"); - record.state = AltosLib.state(words[i++]); + state = AltosLib.state(words[i++]); - record.tick = AltosParse.parse_int(words[i++]); + tick = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "a:"); - record.accel = AltosParse.parse_int(words[i++]); + accel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "p:"); - record.pres = AltosParse.parse_int(words[i++]); + pres = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "t:"); - record.temp = AltosParse.parse_int(words[i++]); + temp = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "v:"); - record.batt = AltosParse.parse_int(words[i++]); + batt = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "d:"); - record.drogue = AltosParse.parse_int(words[i++]); + apogee = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "m:"); - record.main = AltosParse.parse_int(words[i++]); + main = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "fa:"); - record.flight_accel = AltosParse.parse_int(words[i++]); + flight_accel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "ga:"); - record.ground_accel = AltosParse.parse_int(words[i++]); + ground_accel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "fv:"); - record.flight_vel = AltosParse.parse_int(words[i++]); + flight_vel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "fp:"); - record.flight_pres = AltosParse.parse_int(words[i++]); + flight_pres = AltosParse.parse_int(words[i++]); /* Old TeleDongle code with kalman-reporting TeleMetrum code */ - if ((record.flight_vel & 0xffff0000) == 0x80000000) { - record.kalman_speed = ((short) record.flight_vel) / 16.0; - record.kalman_acceleration = record.flight_accel / 16.0; - record.kalman_height = record.flight_pres; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; - record.flight_accel = AltosRecord.MISSING; + if ((flight_vel & 0xffff0000) == 0x80000000) { + kalman_speed = ((short) flight_vel) / 16.0; + kalman_acceleration = flight_accel / 16.0; + kalman_height = flight_pres; + flight_vel = AltosLib.MISSING; + flight_pres = AltosLib.MISSING; + flight_accel = AltosLib.MISSING; + } else { + kalman_speed = AltosLib.MISSING; + kalman_acceleration = AltosLib.MISSING; + kalman_height = AltosLib.MISSING; } AltosParse.word(words[i++], "gp:"); - record.ground_pres = AltosParse.parse_int(words[i++]); + ground_pres = AltosParse.parse_int(words[i++]); - if (record.version >= 1) { + if (version >= 1) { AltosParse.word(words[i++], "a+:"); - record.accel_plus_g = AltosParse.parse_int(words[i++]); + accel_plus_g = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "a-:"); - record.accel_minus_g = AltosParse.parse_int(words[i++]); + accel_minus_g = AltosParse.parse_int(words[i++]); } else { - record.accel_plus_g = record.ground_accel; - record.accel_minus_g = record.ground_accel + 530; + accel_plus_g = ground_accel; + accel_minus_g = ground_accel + 530; } - record.gps = new AltosGPS(words, i, record.version); - record.gps_sequence++; + gps = new AltosGPS(words, i, version); + gps_sequence++; } - public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { + public AltosTelemetryLegacy(String line) throws ParseException, AltosCRCException { String[] words = line.split("\\s+"); int i = 0; - record = new AltosRecordTM(); - if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { i += 2; AltosParse.word(words[i++], "RSSI"); - record.rssi = AltosParse.parse_int(words[i++]); - throw new AltosCRCException(record.rssi); + rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(rssi); } if (words[i].equals("CALL")) { - record.version = 0; + version = 0; } else { AltosParse.word (words[i++], "VERSION"); - record.version = AltosParse.parse_int(words[i++]); + version = AltosParse.parse_int(words[i++]); } - if (record.version < 4) + if (version < 4) parse_legacy(words, i); else parse_v4(words, i); @@ -421,75 +449,68 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { static final int AO_GPS_DATE_VALID = (1 << 6); static final int AO_GPS_COURSE_VALID = (1 << 7); - public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { - record = new AltosRecordTM(); - + public AltosTelemetryLegacy(int[] in_bytes) { bytes = in_bytes; - record.version = 4; + version = 4; adjust = 0; if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { - record.serial = uint8(0); + serial = uint8(0); adjust = -1; } else - record.serial = uint16(0); - - record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy; - - record.callsign = string(62, 8); - record.flight = uint16(2); - record.rssi = in_rssi; - record.status = in_status; - record.state = uint8(4); - record.tick = uint16(21); - record.accel = int16(23); - record.pres = int16(25); - record.temp = int16(27); - record.batt = int16(29); - record.drogue = int16(31); - record.main = int16(33); + serial = uint16(0); + + callsign = string(62, 8); + flight = uint16(2); + state = uint8(4); + tick = uint16(21); + accel = int16(23); + pres = int16(25); + temp = int16(27); + batt = int16(29); + apogee = int16(31); + main = int16(33); - record.ground_accel = int16(7); - record.ground_pres = int16(15); - record.accel_plus_g = int16(17); - record.accel_minus_g = int16(19); + ground_accel = int16(7); + ground_pres = int16(15); + accel_plus_g = int16(17); + accel_minus_g = int16(19); if (uint16(11) == 0x8000) { - record.kalman_acceleration = int16(5); - record.kalman_speed = int16(9); - record.kalman_height = int16(13); - record.flight_accel = AltosRecord.MISSING; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; + kalman_acceleration = int16(5); + kalman_speed = int16(9); + kalman_height = int16(13); + flight_accel = AltosLib.MISSING; + flight_vel = AltosLib.MISSING; + flight_pres = AltosLib.MISSING; } else { - record.flight_accel = int16(5); - record.flight_vel = uint32(9); - record.flight_pres = int16(13); - record.kalman_acceleration = AltosRecord.MISSING; - record.kalman_speed = AltosRecord.MISSING; - record.kalman_height = AltosRecord.MISSING; + flight_accel = int16(5); + flight_vel = uint32(9); + flight_pres = int16(13); + kalman_acceleration = AltosLib.MISSING; + kalman_speed = AltosLib.MISSING; + kalman_height = AltosLib.MISSING; } - record.gps = null; + gps = null; int gps_flags = uint8(41); if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { - record.gps = new AltosGPS(); - record.gps_sequence++; - - record.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; - record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); - record.gps.locked = (gps_flags & AO_GPS_VALID) != 0; - record.gps.connected = true; - record.gps.lat = uint32(42) / 1.0e7; - record.gps.lon = uint32(46) / 1.0e7; - record.gps.alt = int16(50); - record.gps.ground_speed = uint16(52) / 100.0; - record.gps.course = uint8(54) * 2; - record.gps.hdop = uint8(55) / 5.0; - record.gps.h_error = uint16(58); - record.gps.v_error = uint16(60); + gps = new AltosGPS(); + gps_sequence++; + + gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); + gps.locked = (gps_flags & AO_GPS_VALID) != 0; + gps.connected = true; + gps.lat = uint32(42) / 1.0e7; + gps.lon = uint32(46) / 1.0e7; + gps.alt = int16(50); + gps.ground_speed = uint16(52) / 100.0; + gps.course = uint8(54) * 2; + gps.hdop = uint8(55) / 5.0; + gps.h_error = uint16(58); + gps.v_error = uint16(60); int n_tracking_reported = uint8(70); if (n_tracking_reported > 12) @@ -500,22 +521,36 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { n_tracking_actual++; } if (n_tracking_actual > 0) { - record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; + gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; n_tracking_actual = 0; for (int i = 0; i < n_tracking_reported; i++) { int svid = uint8(71 + i*2); int c_n0 = uint8(72 + i*2); if (svid != 0) - record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); + gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); } } } - - record.time = 0.0; } - public AltosRecord update_state(AltosRecord previous) { - return record; + public void update_state(AltosState state) { + state.set_tick(tick); + state.set_state(this.state); + state.set_flight(flight); + state.set_serial(serial); + state.set_rssi(rssi, status); + + state.set_pressure(AltosConvert.barometer_to_pressure(pres)); + state.set_accel_g(accel_plus_g, accel_minus_g); + state.set_accel(accel); + if (kalman_height != AltosLib.MISSING) + state.set_kalman(kalman_height, kalman_speed, kalman_acceleration); + state.set_temperature(AltosConvert.thermometer_to_temperature(temp)); + state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(batt)); + state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(apogee)); + state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(main)); + if (gps != null) + state.set_gps(gps, gps_sequence); } } diff --git a/altoslib/AltosTelemetryRecordLocation.java b/altoslib/AltosTelemetryLocation.java index 0236d291..6e880914 100644 --- a/altoslib/AltosTelemetryRecordLocation.java +++ b/altoslib/AltosTelemetryLocation.java @@ -15,10 +15,10 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { +public class AltosTelemetryLocation extends AltosTelemetryStandard { int flags; int altitude; int latitude; @@ -37,8 +37,8 @@ public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { int climb_rate; int course; - public AltosTelemetryRecordLocation(int[] in_bytes, int rssi) { - super(in_bytes, rssi); + public AltosTelemetryLocation(int[] bytes) { + super(bytes); flags = uint8(5); altitude = int16(6); @@ -59,35 +59,30 @@ public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { course = uint8(30); } - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); + public void update_state(AltosState state) { + super.update_state(state); + AltosGPS gps = state.make_temp_gps(false); - if (next.gps == null) - next.gps = new AltosGPS(); + gps.nsat = flags & 0xf; + gps.locked = (flags & (1 << 4)) != 0; + gps.connected = (flags & (1 << 5)) != 0; - next.gps.nsat = flags & 0xf; - next.gps.locked = (flags & (1 << 4)) != 0; - next.gps.connected = (flags & (1 << 5)) != 0; - - if (next.gps.locked) { - next.gps.lat = latitude * 1.0e-7; - next.gps.lon = longitude * 1.0e-7; - next.gps.alt = altitude; - next.gps.year = 2000 + year; - next.gps.month = month; - next.gps.day = day; - next.gps.hour = hour; - next.gps.minute = minute; - next.gps.second = second; - next.gps.ground_speed = ground_speed * 1.0e-2; - next.gps.course = course * 2; - next.gps.climb_rate = climb_rate * 1.0e-2; - next.gps.hdop = hdop; - next.gps.vdop = vdop; - next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; - next.gps_sequence++; + if (gps.locked) { + gps.lat = latitude * 1.0e-7; + gps.lon = longitude * 1.0e-7; + gps.alt = altitude; + gps.year = 2000 + year; + gps.month = month; + gps.day = day; + gps.hour = hour; + gps.minute = minute; + gps.second = second; + gps.ground_speed = ground_speed * 1.0e-2; + gps.course = course * 2; + gps.climb_rate = climb_rate * 1.0e-2; + gps.hdop = hdop; + gps.vdop = vdop; } - - return next; + state.set_temp_gps(); } } diff --git a/altoslib/AltosTelemetryMap.java b/altoslib/AltosTelemetryMap.java index 7cca98b0..37883a1c 100644 --- a/altoslib/AltosTelemetryMap.java +++ b/altoslib/AltosTelemetryMap.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; import java.util.HashMap; diff --git a/altoslib/AltosTelemetryRecordMegaData.java b/altoslib/AltosTelemetryMegaData.java index a484ef4e..f5cc01d0 100644 --- a/altoslib/AltosTelemetryRecordMegaData.java +++ b/altoslib/AltosTelemetryMegaData.java @@ -15,11 +15,9 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; - - -public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw { +package org.altusmetrum.altoslib_2; +public class AltosTelemetryMegaData extends AltosTelemetryStandard { int state; int v_batt; @@ -35,8 +33,8 @@ public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw { int speed; int height; - public AltosTelemetryRecordMegaData(int[] in_bytes, int rssi) { - super(in_bytes, rssi); + public AltosTelemetryMegaData(int[] bytes) { + super(bytes); state = int8(5); @@ -60,35 +58,28 @@ public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw { height = int16(30); } - public AltosRecord update_state(AltosRecord previous) { - AltosRecord n = super.update_state(previous); - - AltosRecordMM next; - if (!(n instanceof AltosRecordMM)) { - next = new AltosRecordMM(n); - } else { - next = (AltosRecordMM) n; - } - - next.state = state; + public void update_state(AltosState state) { + super.update_state(state); - next.v_batt = v_batt; - next.v_pyro = v_pyro; + state.set_state(this.state); + + state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt)); + state.set_pyro_voltage(AltosConvert.mega_pyro_voltage(v_pyro)); - for (int i = 0; i < 6; i++) - next.sense[i] = sense[i]; + state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense[4])); + state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense[5])); - next.ground_accel = ground_accel; - next.ground_pres = ground_pres; - next.accel_plus_g = accel_plus_g; - next.accel_minus_g = accel_minus_g; + double voltages[] = new double[4]; + for (int i = 0; i < 4; i++) + voltages[i] = AltosConvert.mega_pyro_voltage(sense[i]); - next.kalman_acceleration = acceleration / 16.0; - next.kalman_speed = speed / 16.0; - next.kalman_height = height; + state.set_ignitor_voltage(voltages); - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + state.set_ground_accel(ground_accel); + state.set_ground_pressure(ground_pres); + state.set_accel_g(accel_plus_g, accel_minus_g); - return next; + state.set_kalman(height, speed/16.0, acceleration / 16.0); } } + diff --git a/altoslib/AltosTelemetryRecordMegaSensor.java b/altoslib/AltosTelemetryMegaSensor.java index 2a4b17a4..23b67af8 100644 --- a/altoslib/AltosTelemetryRecordMegaSensor.java +++ b/altoslib/AltosTelemetryMegaSensor.java @@ -15,10 +15,9 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; - -public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { +public class AltosTelemetryMegaSensor extends AltosTelemetryStandard { int accel; int pres; int temp; @@ -35,8 +34,8 @@ public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { int mag_y; int mag_z; - public AltosTelemetryRecordMegaSensor(int[] in_bytes, int rssi) { - super(in_bytes, rssi); + public AltosTelemetryMegaSensor(int[] bytes) { + super(bytes); accel = int16(6); pres = int32(8); @@ -55,34 +54,31 @@ public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { mag_z = int16(30); } - public AltosRecord update_state(AltosRecord previous) { - AltosRecord n = super.update_state(previous); + public void update_state(AltosState state) { + super.update_state(state); - AltosRecordMM next; - if (!(n instanceof AltosRecordMM)) { - next = new AltosRecordMM(n); - } else { - next = (AltosRecordMM) n; - } + state.set_accel(accel); + state.set_pressure(pres); + state.set_temperature(temp / 100.0); - next.accel = accel; - next.pres = pres; - next.temp = temp; + AltosIMU imu = new AltosIMU(); + + imu.accel_x = accel_x; + imu.accel_y = accel_y; + imu.accel_z = accel_z; - next.imu.accel_x = accel_x; - next.imu.accel_y = accel_y; - next.imu.accel_z = accel_z; + imu.gyro_x = gyro_x; + imu.gyro_y = gyro_y; + imu.gyro_z = gyro_z; - next.imu.gyro_x = gyro_x; - next.imu.gyro_y = gyro_y; - next.imu.gyro_z = gyro_z; + state.imu = imu; - next.mag.x = mag_x; - next.mag.y = mag_y; - next.mag.z = mag_z; + AltosMag mag = new AltosMag(); - next.seen |= AltosRecord.seen_sensor; + mag.x = mag_x; + mag.y = mag_y; + mag.z = mag_z; - return next; + state.mag = mag; } } diff --git a/altoslib/AltosTelemetryRecordGeneral.java b/altoslib/AltosTelemetryMetrumData.java index 08cd6065..b6239971 100644 --- a/altoslib/AltosTelemetryRecordGeneral.java +++ b/altoslib/AltosTelemetryMetrumData.java @@ -15,27 +15,28 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -import java.text.*; -public class AltosTelemetryRecordGeneral { +public class AltosTelemetryMetrumData extends AltosTelemetryStandard { - static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; + int ground_pres; + int ground_accel; + int accel_plus_g; + int accel_minus_g; - String[] word = line.split("\\s+"); - int i =0; - if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(word[i++], "RSSI"); - throw new AltosCRCException(AltosParse.parse_int(word[i++])); - } + public AltosTelemetryMetrumData(int[] bytes) { + super(bytes); - if (word[i].equals("TELEM")) - r = AltosTelemetryRecordRaw.parse(word[i+1]); - else - r = new AltosTelemetryRecordLegacy(line); - return r; + ground_pres = int32(8); + ground_accel = int16(12); + accel_plus_g = int16(14); + accel_minus_g = int16(16); + } + + public void update_state(AltosState state) { + state.set_ground_accel(ground_accel); + state.set_accel_g(accel_plus_g, accel_minus_g); + state.set_ground_pressure(ground_pres); } } diff --git a/altoslib/AltosTelemetryMetrumSensor.java b/altoslib/AltosTelemetryMetrumSensor.java new file mode 100644 index 00000000..fc047afd --- /dev/null +++ b/altoslib/AltosTelemetryMetrumSensor.java @@ -0,0 +1,69 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + + +public class AltosTelemetryMetrumSensor extends AltosTelemetryStandard { + int state; + + int accel; + int pres; + int temp; + + int acceleration; + int speed; + int height; + + int v_batt; + int sense_a; + int sense_m; + + public AltosTelemetryMetrumSensor(int[] bytes) { + super(bytes); + + 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 void update_state(AltosState state) { + super.update_state(state); + + state.set_state(this.state); + + state.set_accel(accel); + state.set_pressure(pres); + state.set_temperature(temp/100.0); + + state.set_kalman(height, speed/16.0, acceleration/16.0); + + state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt)); + + state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense_a)); + state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m)); + } +} diff --git a/altoslib/AltosTelemetryMini.java b/altoslib/AltosTelemetryMini.java new file mode 100644 index 00000000..e7109460 --- /dev/null +++ b/altoslib/AltosTelemetryMini.java @@ -0,0 +1,72 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + + +public class AltosTelemetryMini extends AltosTelemetryStandard { + int state; + + int v_batt; + int sense_a; + int sense_m; + + int pres; + int temp; + + int acceleration; + int speed; + int height; + + int ground_pres; + + public AltosTelemetryMini(int[] bytes) { + super(bytes); + + 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 void update_state(AltosState state) { + super.update_state(state); + + state.set_state(this.state); + + state.set_battery_voltage(AltosConvert.tele_mini_voltage(v_batt)); + state.set_apogee_voltage(AltosConvert.tele_mini_voltage(sense_a)); + state.set_main_voltage(AltosConvert.tele_mini_voltage(sense_m)); + + state.set_ground_pressure(ground_pres); + + state.set_pressure(pres); + state.set_temperature(temp/100.0); + + state.set_kalman(height, speed/16.0, acceleration/16.0); + } +} diff --git a/altoslib/AltosMs5607Query.java b/altoslib/AltosTelemetryRaw.java index d39dbf26..dbe70fe9 100644 --- a/altoslib/AltosMs5607Query.java +++ b/altoslib/AltosTelemetryRaw.java @@ -1,5 +1,5 @@ /* - * Copyright © 2012 Keith Packard <keithp@keithp.com> + * Copyright © 2011 Keith Packard <keithp@keithp.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,22 +15,14 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -import java.util.concurrent.TimeoutException; +public class AltosTelemetryRaw extends AltosTelemetryStandard { + public AltosTelemetryRaw(int[] bytes) { + super(bytes); + } -class AltosMs5607Query extends AltosMs5607 { - public AltosMs5607Query (AltosLink link) throws InterruptedException, TimeoutException { - link.printf("v\nB\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!parse_line(line)) - break; - } - convert(); + public void update_state(AltosState state) { + super.update_state(state); } } - diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index b4293c73..eeb35cb5 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; import java.text.*; import java.io.*; @@ -24,19 +24,23 @@ import java.util.concurrent.*; public class AltosTelemetryReader extends AltosFlightReader { AltosLink link; AltosLog log; - AltosRecord previous; double frequency; int telemetry; + AltosState state = null; LinkedBlockingQueue<AltosLine> telem; - public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { + public AltosState read() throws InterruptedException, ParseException, AltosCRCException, IOException { AltosLine l = telem.take(); if (l.line == null) throw new IOException("IO error"); - AltosRecord next = AltosTelemetry.parse(l.line, previous); - previous = next; - return next; + AltosTelemetry telem = AltosTelemetry.parse(l.line); + if (state == null) + state = new AltosState(); + else + state = state.clone(); + telem.update_state(state); + return state; } public void flush() { @@ -44,14 +48,16 @@ public class AltosTelemetryReader extends AltosFlightReader { } public void reset() { - previous = null; flush(); } public void close(boolean interrupted) { link.remove_monitor(telem); log.close(); - link.close(); + try { + link.close(); + } catch (InterruptedException ie) { + } } public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { @@ -80,7 +86,7 @@ public class AltosTelemetryReader extends AltosFlightReader { else return false; } catch (InterruptedException ie) { - return true; + return false; } catch (TimeoutException te) { return true; } @@ -111,29 +117,27 @@ public class AltosTelemetryReader extends AltosFlightReader { return link.has_monitor_battery(); } - public double monitor_battery() { + public double monitor_battery() throws InterruptedException { return link.monitor_battery(); } public AltosTelemetryReader (AltosLink in_link) throws IOException, InterruptedException, TimeoutException { link = in_link; + boolean success = false; try { log = new AltosLog(link); name = link.name; - previous = null; telem = new LinkedBlockingQueue<AltosLine>(); frequency = AltosPreferences.frequency(link.serial); set_frequency(frequency); telemetry = AltosPreferences.telemetry(link.serial); set_telemetry(telemetry); link.add_monitor(telem); - } catch (TimeoutException e) { - close(true); - throw(e); - } catch (InterruptedException e) { - close(true); - throw(e); + success = true; + } finally { + if (!success) + close(true); } } } diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java deleted file mode 100644 index fdc3c88e..00000000 --- a/altoslib/AltosTelemetryRecord.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright © 2011 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; -import java.text.*; - -public abstract class AltosTelemetryRecord { - - long received_time; - abstract public AltosRecord update_state(AltosRecord previous); - - static boolean cksum(int[] bytes) { - int sum = 0x5a; - for (int i = 1; i < bytes.length - 1; i++) - sum += bytes[i]; - sum &= 0xff; - return sum == bytes[bytes.length - 1]; - } - - final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); - final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); - final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; - - final static int packet_type_TM_sensor = 0x01; - final static int packet_type_Tm_sensor = 0x02; - final static int packet_type_Tn_sensor = 0x03; - final static int packet_type_configuration = 0x04; - final static int packet_type_location = 0x05; - final static int packet_type_satellite = 0x06; - final static int packet_type_companion = 0x07; - final static int packet_type_MM_sensor = 0x08; - final static int packet_type_MM_data = 0x09; - - static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - int[] bytes; - try { - bytes = AltosLib.hexbytes(hex); - } catch (NumberFormatException ne) { - throw new ParseException(ne.getMessage(), 0); - } - - /* one for length, one for checksum */ - if (bytes[0] != bytes.length - 2) - throw new ParseException(String.format("invalid length %d != %d\n", - bytes[0], - bytes.length - 2), 0); - if (!cksum(bytes)) - throw new ParseException(String.format("invalid line \"%s\"", hex), 0); - - int rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74; - int status = AltosLib.uint8(bytes, bytes.length - 2); - - if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) - throw new AltosCRCException(rssi); - - /* length, data ..., rssi, status, checksum -- 4 bytes extra */ - switch (bytes.length) { - case AltosLib.ao_telemetry_standard_len + 4: - int type = AltosLib.uint8(bytes, 4 + 1); - switch (type) { - case packet_type_TM_sensor: - case packet_type_Tm_sensor: - case packet_type_Tn_sensor: - r = new AltosTelemetryRecordSensor(bytes, rssi); - break; - case packet_type_configuration: - r = new AltosTelemetryRecordConfiguration(bytes, rssi); - break; - case packet_type_location: - r = new AltosTelemetryRecordLocation(bytes, rssi); - break; - case packet_type_satellite: - r = new AltosTelemetryRecordSatellite(bytes, rssi); - break; - case packet_type_companion: - r = new AltosTelemetryRecordCompanion(bytes, rssi); - break; - case packet_type_MM_sensor: - r = new AltosTelemetryRecordMegaSensor(bytes, rssi); - break; - case packet_type_MM_data: - r = new AltosTelemetryRecordMegaData(bytes, rssi); - break; - default: - r = new AltosTelemetryRecordRaw(bytes, rssi); - break; - } - break; - case AltosLib.ao_telemetry_0_9_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - case AltosLib.ao_telemetry_0_8_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - default: - throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); - } - r.received_time = System.currentTimeMillis(); - return r; - } - - public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - String[] word = line.split("\\s+"); - int i =0; - if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(word[i++], "RSSI"); - throw new AltosCRCException(AltosParse.parse_int(word[i++])); - } - - if (word[i].equals("TELEM")) - r = parse_hex(word[i+1]); - else - r = new AltosTelemetryRecordLegacy(line); - return r; - } -} diff --git a/altoslib/AltosTelemetryRecordCompanion.java b/altoslib/AltosTelemetryRecordCompanion.java deleted file mode 100644 index 2231df13..00000000 --- a/altoslib/AltosTelemetryRecordCompanion.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2011 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { - - AltosRecordCompanion companion; - - public AltosTelemetryRecordCompanion(int[] in_bytes, int rssi) { - super(in_bytes, rssi); - - int off = 0; - if (uint8(6) == 0) - off = 1; - int channels = uint8(7+off); - - if (off != 0 && channels >= 12) - channels = 11; - - companion = new AltosRecordCompanion(channels); - companion.tick = tick; - companion.board_id = uint8(5); - companion.update_period = uint8(6+off); - for (int i = 0; i < companion.companion_data.length; i++) - companion.companion_data[i] = uint16(8 + off + i * 2); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - next.companion = companion; - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - - companion.tick = tick; - return next; - } -} diff --git a/altoslib/AltosTelemetryRecordRaw.java b/altoslib/AltosTelemetryRecordRaw.java deleted file mode 100644 index f94789bb..00000000 --- a/altoslib/AltosTelemetryRecordRaw.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright © 2011 Keith Packard <keithp@keithp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.altoslib_1; - -public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { - int[] bytes; - int serial; - int tick; - int type; - int rssi; - - long received_time; - - public int int8(int off) { - return AltosLib.int8(bytes, off + 1); - } - - public int uint8(int off) { - return AltosLib.uint8(bytes, off + 1); - } - - public int int16(int off) { - return AltosLib.int16(bytes, off + 1); - } - - public int uint16(int off) { - return AltosLib.uint16(bytes, off + 1); - } - - public int uint32(int off) { - return AltosLib.uint32(bytes, off + 1); - } - - public int int32(int off) { - return AltosLib.int32(bytes, off + 1); - } - - public String string(int off, int l) { - return AltosLib.string(bytes, off + 1, l); - } - - public AltosTelemetryRecordRaw(int[] in_bytes, int in_rssi) { - bytes = in_bytes; - serial = uint16(0); - tick = uint16(2); - type = uint8(4); - rssi = in_rssi; - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next; - - if (previous != null && previous.serial == serial) - next = previous.clone(); - else - next = new AltosRecordNone(); - next.serial = serial; - next.tick = tick; - next.rssi = rssi; - return next; - } - - public long received_time() { - return received_time; - } -} diff --git a/altoslib/AltosTelemetryRecordSatellite.java b/altoslib/AltosTelemetrySatellite.java index 9835389b..fde3d86d 100644 --- a/altoslib/AltosTelemetryRecordSatellite.java +++ b/altoslib/AltosTelemetrySatellite.java @@ -15,14 +15,14 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { +public class AltosTelemetrySatellite extends AltosTelemetryStandard { int channels; AltosGPSSat[] sats; - public AltosTelemetryRecordSatellite(int[] in_bytes, int rssi) { - super(in_bytes, rssi); + public AltosTelemetrySatellite(int[] bytes) { + super(bytes); channels = uint8(5); if (channels > 12) @@ -39,14 +39,12 @@ public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { } } - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); + public void update_state(AltosState state) { + super.update_state(state); - if (next.gps == null) - next.gps = new AltosGPS(); - - next.gps.cc_gps_sat = sats; - - return next; + AltosGPS gps = state.make_temp_gps(true); + + gps.cc_gps_sat = sats; + state.set_temp_gps(); } } diff --git a/altoslib/AltosTelemetryRecordSensor.java b/altoslib/AltosTelemetrySensor.java index e0e92c13..e1106440 100644 --- a/altoslib/AltosTelemetryRecordSensor.java +++ b/altoslib/AltosTelemetrySensor.java @@ -15,10 +15,10 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; -public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { +public class AltosTelemetrySensor extends AltosTelemetryStandard { int state; int accel; int pres; @@ -36,8 +36,8 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { int accel_plus_g; int accel_minus_g; - public AltosTelemetryRecordSensor(int[] in_bytes, int rssi) { - super(in_bytes, rssi); + public AltosTelemetrySensor(int[] bytes) { + super(bytes); state = uint8(5); accel = int16(6); @@ -57,48 +57,24 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { accel_minus_g = int16(30); } - public AltosRecord update_state(AltosRecord prev) { - AltosRecord n = super.update_state(prev); + public void update_state(AltosState state) { + super.update_state(state); - AltosRecordTM next; - if (!(n instanceof AltosRecordTM)) - next = new AltosRecordTM(n); - else - next = (AltosRecordTM) n; - - next.state = state; - if (type == packet_type_TM_sensor) - next.accel = accel; - else - next.accel = AltosRecord.MISSING; - next.pres = pres; - next.temp = temp; - next.batt = v_batt; - if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) { - next.drogue = sense_d; - next.main = sense_m; - } else { - next.drogue = AltosRecord.MISSING; - next.main = AltosRecord.MISSING; - } - - next.kalman_acceleration = acceleration / 16.0; - next.kalman_speed = speed / 16.0; - next.kalman_height = height; - - next.ground_pres = ground_pres; + state.set_state(this.state); if (type == packet_type_TM_sensor) { - next.ground_accel = ground_accel; - next.accel_plus_g = accel_plus_g; - next.accel_minus_g = accel_minus_g; - } else { - next.ground_accel = AltosRecord.MISSING; - next.accel_plus_g = AltosRecord.MISSING; - next.accel_minus_g = AltosRecord.MISSING; + state.set_ground_accel(ground_accel); + state.set_accel_g(accel_plus_g, accel_minus_g); + state.set_accel(accel); + } + state.set_ground_pressure(AltosConvert.barometer_to_pressure(ground_pres)); + state.set_pressure(AltosConvert.barometer_to_pressure(pres)); + state.set_temperature(AltosConvert.thermometer_to_temperature(temp)); + state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(v_batt)); + if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) { + state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(sense_d)); + state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(sense_m)); } - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - - return next; + state.set_kalman(height, speed/16.0, acceleration / 16.0); } } diff --git a/altoslib/AltosTelemetryStandard.java b/altoslib/AltosTelemetryStandard.java new file mode 100644 index 00000000..3186ae09 --- /dev/null +++ b/altoslib/AltosTelemetryStandard.java @@ -0,0 +1,109 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_2; + +public abstract class AltosTelemetryStandard extends AltosTelemetry { + int[] bytes; + int type; + + public int int8(int off) { + return AltosLib.int8(bytes, off + 1); + } + + public int uint8(int off) { + return AltosLib.uint8(bytes, off + 1); + } + + public int int16(int off) { + return AltosLib.int16(bytes, off + 1); + } + + public int uint16(int off) { + return AltosLib.uint16(bytes, off + 1); + } + + public int uint32(int off) { + return AltosLib.uint32(bytes, off + 1); + } + + public int int32(int off) { + return AltosLib.int32(bytes, off + 1); + } + + public String string(int off, int l) { + return AltosLib.string(bytes, off + 1, l); + } + + public static AltosTelemetry parse_hex(int[] bytes) { + int type = AltosLib.uint8(bytes, 4 + 1); + + AltosTelemetry telem; + switch (type) { + case packet_type_TM_sensor: + case packet_type_Tm_sensor: + case packet_type_Tn_sensor: + telem = new AltosTelemetrySensor(bytes); + break; + case packet_type_configuration: + telem = new AltosTelemetryConfiguration(bytes); + break; + case packet_type_location: + telem = new AltosTelemetryLocation(bytes); + break; + case packet_type_satellite: + telem = new AltosTelemetrySatellite(bytes); + break; +/* + case packet_type_companion: + telem = new AltosTelemetryCompanion(bytes); + break; +*/ + case packet_type_mega_sensor: + telem = new AltosTelemetryMegaSensor(bytes); + break; + case packet_type_mega_data: + telem = new AltosTelemetryMegaData(bytes); + break; + case packet_type_metrum_sensor: + telem = new AltosTelemetryMetrumSensor(bytes); + break; + case packet_type_metrum_data: + telem = new AltosTelemetryMetrumData(bytes); + break; + case packet_type_mini: + telem = new AltosTelemetryMini(bytes); + break; + default: + telem = new AltosTelemetryRaw(bytes); + break; + } + return telem; + } + + public AltosTelemetryStandard(int[] bytes) { + this.bytes = bytes; + + serial = uint16(0); + tick = uint16(2); + type = uint8(4); + } + + public void update_state(AltosState state) { + super.update_state(state); + } +} diff --git a/altoslib/AltosTemperature.java b/altoslib/AltosTemperature.java index 2749eac0..a636533f 100644 --- a/altoslib/AltosTemperature.java +++ b/altoslib/AltosTemperature.java @@ -15,29 +15,35 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public class AltosTemperature extends AltosUnits { - public double value(double v) { - if (AltosConvert.imperial_units) + public double value(double v, boolean imperial_units) { + if (imperial_units) return AltosConvert.c_to_f(v); return v; } - public String show_units() { - if (AltosConvert.imperial_units) + public double inverse(double v, boolean imperial_units) { + if (imperial_units) + return AltosConvert.f_to_c(v); + return v; + } + + public String show_units(boolean imperial_units) { + if (imperial_units) return "°F"; return "°C"; } - public String say_units() { - if (AltosConvert.imperial_units) + public String say_units(boolean imperial_units) { + if (imperial_units) return "degrees farenheit"; return "degrees celsius"; } - public int show_fraction(int width) { + public int show_fraction(int width, boolean imperial_units) { return width / 3; } } diff --git a/altoslib/AltosUnits.java b/altoslib/AltosUnits.java index b8b3254c..8f9ccded 100644 --- a/altoslib/AltosUnits.java +++ b/altoslib/AltosUnits.java @@ -15,47 +15,94 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public abstract class AltosUnits { - public abstract double value(double v); + public abstract double value(double v, boolean imperial_units); - public abstract String show_units(); + public abstract double inverse(double v, boolean imperial_units); - public abstract String say_units(); + public abstract String show_units(boolean imperial_units); - public abstract int show_fraction(int width); + public abstract String say_units(boolean imperial_units); - int say_fraction() { + public abstract int show_fraction(int width, boolean imperial_units); + + public double parse(String s, boolean imperial_units) throws NumberFormatException { + double v = Double.parseDouble(s); + return inverse(v, imperial_units); + } + + public double parse(String s) throws NumberFormatException { + return parse(s, AltosConvert.imperial_units); + } + + public double value(double v) { + return value(v, AltosConvert.imperial_units); + } + + public double inverse(double v) { + return inverse(v, AltosConvert.imperial_units); + } + + public String show_units() { + return show_units(AltosConvert.imperial_units); + } + + public String say_units() { + return say_units(AltosConvert.imperial_units); + } + + public int show_fraction(int width) { + return show_fraction(width, AltosConvert.imperial_units); + } + + int say_fraction(boolean imperial_units) { return 0; } - private String show_format(int width) { - return String.format("%%%d.%df %s", width, show_fraction(width), show_units()); + private String show_format(int width, boolean imperial_units) { + return String.format("%%%d.%df %s", width, show_fraction(width, imperial_units), show_units(imperial_units)); + } + + private String say_format(boolean imperial_units) { + return String.format("%%1.%df", say_fraction(imperial_units)); } - private String say_format() { - return String.format("%%1.%df", say_fraction()); + private String say_units_format(boolean imperial_units) { + return String.format("%%1.%df %s", say_fraction(imperial_units), say_units(imperial_units)); } - private String say_units_format() { - return String.format("%%1.%df %s", say_fraction(), say_units()); + public String graph_format(int width, boolean imperial_units) { + return String.format(String.format("%%%d.%df", width, show_fraction(width, imperial_units)), 0.0); } public String graph_format(int width) { - return String.format(String.format("%%%d.%df", width, show_fraction(width)), 0.0); + return graph_format(width, AltosConvert.imperial_units); + } + + public String show(int width, double v, boolean imperial_units) { + return String.format(show_format(width, imperial_units), value(v, imperial_units)); } public String show(int width, double v) { - return String.format(show_format(width), value(v)); + return show(width, v, AltosConvert.imperial_units); + } + + public String say(double v, boolean imperial_units) { + return String.format(say_format(imperial_units), value(v, imperial_units)); } public String say(double v) { - return String.format(say_format(), value(v)); + return say(v, AltosConvert.imperial_units); + } + + public String say_units(double v, boolean imperial_units) { + return String.format(say_units_format(imperial_units), value(v, imperial_units)); } public String say_units(double v) { - return String.format(say_units_format(), value(v)); + return say_units(v, AltosConvert.imperial_units); } }
\ No newline at end of file diff --git a/altoslib/AltosUnitsListener.java b/altoslib/AltosUnitsListener.java index 61a181a4..1e3ad655 100644 --- a/altoslib/AltosUnitsListener.java +++ b/altoslib/AltosUnitsListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altoslib_1; +package org.altusmetrum.altoslib_2; public interface AltosUnitsListener { public void units_changed(boolean imperial_units); diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 18b028d6..6d396635 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -1,4 +1,4 @@ -AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation +AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6 JAVAROOT=bin @@ -9,73 +9,100 @@ CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/ SRC=. altoslibdir = $(datadir)/java +record_files = \ + AltosEepromRecord.java \ + AltosEepromTeleScience.java \ + AltosRecordCompanion.java \ + AltosRecordIterable.java \ + AltosOrderedRecord.java \ + AltosOrderedMegaRecord.java \ + AltosOrderedMiniRecord.java \ + AltosRecord.java \ + AltosRecordNone.java \ + AltosRecordTM.java \ + AltosRecordMM.java \ + AltosRecordMini.java + altoslib_JAVA = \ AltosLib.java \ + AltosCompanion.java \ AltosConfigData.java \ AltosConfigValues.java \ AltosConvert.java \ AltosCRCException.java \ AltosDebug.java \ + AltosEeprom.java \ AltosEepromChunk.java \ + AltosEepromDownload.java \ + AltosEepromFile.java \ + AltosEepromTM.java \ + AltosEepromTm.java \ + AltosEepromHeader.java \ AltosEepromIterable.java \ + AltosEepromList.java \ AltosEepromLog.java \ AltosEepromMega.java \ - AltosEepromMegaIterable.java \ - AltosEepromRecord.java \ - AltosEepromTeleScience.java \ + AltosEepromMetrum2.java \ + AltosEepromMini.java \ + AltosEepromMonitor.java \ AltosFile.java \ AltosFlash.java \ AltosFlashListener.java \ AltosFlightReader.java \ AltosFrequency.java \ AltosGPS.java \ - AltosGPSQuery.java \ AltosGPSSat.java \ AltosGreatCircle.java \ AltosHexfile.java \ + AltosHexsym.java \ + AltosIdle.java \ + AltosIdleFetch.java \ AltosIdleMonitor.java \ AltosIdleMonitorListener.java \ AltosIgnite.java \ AltosIMU.java \ - AltosIMUQuery.java \ AltosLine.java \ AltosLink.java \ AltosListenerState.java \ AltosLog.java \ + AltosMag.java \ + AltosMma655x.java \ AltosMs5607.java \ - AltosMs5607Query.java \ - AltosOrderedRecord.java \ - AltosOrderedMegaRecord.java \ + AltosNoSymbol.java \ AltosParse.java \ AltosPreferences.java \ AltosPreferencesBackend.java \ - AltosRecordCompanion.java \ - AltosRecordIterable.java \ - AltosRecord.java \ - AltosRecordNone.java \ - AltosRecordTM.java \ - AltosRecordMM.java \ + AltosProgrammer.java \ AltosReplayReader.java \ AltosRomconfig.java \ + AltosSelfFlash.java \ AltosSensorMM.java \ + AltosSensorEMini.java \ AltosSensorTM.java \ + AltosSensorTMini.java \ + AltosSensorMega.java \ + AltosSensorMetrum.java \ AltosState.java \ + AltosStateIterable.java \ + AltosStateUpdate.java \ AltosTelemetry.java \ + AltosTelemetryConfiguration.java \ + AltosTelemetryFile.java \ AltosTelemetryIterable.java \ + AltosTelemetryLegacy.java \ + AltosTelemetryLocation.java \ AltosTelemetryMap.java \ + AltosTelemetryMegaSensor.java \ + AltosTelemetryMegaData.java \ + AltosTelemetryMini.java \ + AltosTelemetryMetrumSensor.java \ + AltosTelemetryMetrumData.java \ AltosTelemetryReader.java \ - AltosTelemetryRecordCompanion.java \ - AltosTelemetryRecordConfiguration.java \ - AltosTelemetryRecordGeneral.java \ - AltosTelemetryRecord.java \ - AltosTelemetryRecordLegacy.java \ - AltosTelemetryRecordLocation.java \ - AltosTelemetryRecordRaw.java \ - AltosTelemetryRecordSatellite.java \ - AltosTelemetryRecordSensor.java \ - AltosTelemetryRecordMegaSensor.java \ - AltosTelemetryRecordMegaData.java \ + AltosTelemetryRaw.java \ + AltosTelemetrySensor.java \ + AltosTelemetrySatellite.java \ + AltosTelemetryStandard.java \ AltosUnitsListener.java \ AltosMs5607.java \ AltosIMU.java \ |