From 81465a20049da40cd8d3cda920d6585ffe87bfe3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 4 Jan 2012 20:28:42 -0800 Subject: altosui: Move java altoslib to top level This will be shared with other (android) java code. Signed-off-by: Keith Packard --- altoslib/.gitignore | 1 + altoslib/Makefile.am | 69 +++ .../altusmetrum/AltosLib/AltosCRCException.java | 26 + .../org/altusmetrum/AltosLib/AltosConfigData.java | 184 ++++++++ .../src/org/altusmetrum/AltosLib/AltosConvert.java | 259 ++++++++++ .../org/altusmetrum/AltosLib/AltosEepromChunk.java | 102 ++++ .../altusmetrum/AltosLib/AltosEepromIterable.java | 475 +++++++++++++++++++ .../org/altusmetrum/AltosLib/AltosEepromLog.java | 100 ++++ .../altusmetrum/AltosLib/AltosEepromRecord.java | 139 ++++++ .../AltosLib/AltosEepromTeleScience.java | 59 +++ .../src/org/altusmetrum/AltosLib/AltosFile.java | 44 ++ .../altusmetrum/AltosLib/AltosFlightReader.java | 49 ++ .../org/altusmetrum/AltosLib/AltosFrequency.java | 48 ++ .../src/org/altusmetrum/AltosLib/AltosGPS.java | 248 ++++++++++ .../src/org/altusmetrum/AltosLib/AltosGPSSat.java | 32 ++ .../org/altusmetrum/AltosLib/AltosGreatCircle.java | 101 ++++ .../src/org/altusmetrum/AltosLib/AltosLib.java | 348 ++++++++++++++ .../src/org/altusmetrum/AltosLib/AltosLine.java | 30 ++ .../src/org/altusmetrum/AltosLib/AltosLink.java | 238 ++++++++++ .../src/org/altusmetrum/AltosLib/AltosLog.java | 126 +++++ .../src/org/altusmetrum/AltosLib/AltosParse.java | 79 ++++ .../org/altusmetrum/AltosLib/AltosPreferences.java | 365 +++++++++++++++ .../src/org/altusmetrum/AltosLib/AltosRecord.java | 319 +++++++++++++ .../altusmetrum/AltosLib/AltosRecordCompanion.java | 38 ++ .../altusmetrum/AltosLib/AltosRecordIterable.java | 29 ++ .../altusmetrum/AltosLib/AltosReplayReader.java | 56 +++ .../src/org/altusmetrum/AltosLib/AltosState.java | 210 +++++++++ .../org/altusmetrum/AltosLib/AltosTelemetry.java | 241 ++++++++++ .../AltosLib/AltosTelemetryIterable.java | 109 +++++ .../altusmetrum/AltosLib/AltosTelemetryMap.java | 63 +++ .../altusmetrum/AltosLib/AltosTelemetryReader.java | 119 +++++ .../altusmetrum/AltosLib/AltosTelemetryRecord.java | 126 +++++ .../AltosLib/AltosTelemetryRecordCompanion.java | 52 ++ .../AltosTelemetryRecordConfiguration.java | 64 +++ .../AltosLib/AltosTelemetryRecordGeneral.java | 43 ++ .../AltosLib/AltosTelemetryRecordLegacy.java | 521 +++++++++++++++++++++ .../AltosLib/AltosTelemetryRecordLocation.java | 93 ++++ .../AltosLib/AltosTelemetryRecordRaw.java | 77 +++ .../AltosLib/AltosTelemetryRecordSatellite.java | 52 ++ .../AltosLib/AltosTelemetryRecordSensor.java | 104 ++++ 40 files changed, 5438 insertions(+) create mode 100644 altoslib/.gitignore create mode 100644 altoslib/Makefile.am create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFile.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLib.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLine.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLink.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLog.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosParse.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosState.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java (limited to 'altoslib') diff --git a/altoslib/.gitignore b/altoslib/.gitignore new file mode 100644 index 00000000..ad2f8cbf --- /dev/null +++ b/altoslib/.gitignore @@ -0,0 +1 @@ +classAltosLib.stamp diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am new file mode 100644 index 00000000..2ddd24e6 --- /dev/null +++ b/altoslib/Makefile.am @@ -0,0 +1,69 @@ +AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation + +JAVAROOT=bin + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/*" + +SRC=src/org/altusmetrum/AltosLib +BIN=bin/org/altusmetrum/AltosLib + +AltosLibdir = $(datadir)/java + +AltosLib_JAVA = \ + $(SRC)/AltosLib.java \ + $(SRC)/AltosConfigData.java \ + $(SRC)/AltosConvert.java \ + $(SRC)/AltosCRCException.java \ + $(SRC)/AltosEepromChunk.java \ + $(SRC)/AltosEepromIterable.java \ + $(SRC)/AltosEepromLog.java \ + $(SRC)/AltosEepromRecord.java \ + $(SRC)/AltosEepromTeleScience.java \ + $(SRC)/AltosFile.java \ + $(SRC)/AltosFlightReader.java \ + $(SRC)/AltosFrequency.java \ + $(SRC)/AltosGPS.java \ + $(SRC)/AltosGPSSat.java \ + $(SRC)/AltosGreatCircle.java \ + $(SRC)/AltosLine.java \ + $(SRC)/AltosLink.java \ + $(SRC)/AltosLog.java \ + $(SRC)/AltosParse.java \ + $(SRC)/AltosPreferences.java \ + $(SRC)/AltosRecordCompanion.java \ + $(SRC)/AltosRecordIterable.java \ + $(SRC)/AltosRecord.java \ + $(SRC)/AltosReplayReader.java \ + $(SRC)/AltosState.java \ + $(SRC)/AltosTelemetry.java \ + $(SRC)/AltosTelemetryIterable.java \ + $(SRC)/AltosTelemetryMap.java \ + $(SRC)/AltosTelemetryReader.java \ + $(SRC)/AltosTelemetryRecordCompanion.java \ + $(SRC)/AltosTelemetryRecordConfiguration.java \ + $(SRC)/AltosTelemetryRecordGeneral.java \ + $(SRC)/AltosTelemetryRecord.java \ + $(SRC)/AltosTelemetryRecordLegacy.java \ + $(SRC)/AltosTelemetryRecordLocation.java \ + $(SRC)/AltosTelemetryRecordRaw.java \ + $(SRC)/AltosTelemetryRecordSatellite.java \ + $(SRC)/AltosTelemetryRecordSensor.java + +JAR=AltosLib.jar + +all-local: $(JAR) + +clean-local: + -rm -rf bin $(JAR) + +install-AltosLibJAVA: $(JAR) + @$(NORMAL_INSTALL) + test -z "$(AltosLibdir)" || $(MKDIR_P) "$(DESTDIR)$(AltosLibdir)" + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(AltosLibdir)/$(JAR)"; \ + $(INSTALL_DATA) "$<" "$(DESTDIR)$(AltosLibdir)" + +bin: + mkdir -p bin + +$(JAR): classAltosLib.stamp + jar cf $@ -C bin org diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java b/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java new file mode 100644 index 00000000..101c5363 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosCRCException extends Exception { + public int rssi; + + public AltosCRCException (int in_rssi) { + rssi = in_rssi; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java new file mode 100644 index 00000000..4ad4e58a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java @@ -0,0 +1,184 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; + +public class AltosConfigData implements Iterable { + + /* Version information */ + public String manufacturer; + public String product; + public String version; + public int log_format; + public int serial; + + /* Strings returned */ + public LinkedList lines; + + /* Config information */ + public int config_major; + public int config_minor; + public int main_deploy; + public int apogee_delay; + public int radio_channel; + public int radio_setting; + public int radio_frequency; + public String callsign; + public int accel_cal_plus, accel_cal_minus; + public int radio_calibration; + public int flight_log_max; + public int ignite_mode; + public int stored_flight; + public int storage_size; + public int storage_erase_unit; + + public static String get_string(String line, String label) throws ParseException { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + return quoted; + } + throw new ParseException("mismatch", 0); + } + + public static int get_int(String line, String label) throws NumberFormatException, ParseException { + if (line.startsWith(label)) { + String tail = line.substring(label.length()).trim(); + String[] tokens = tail.split("\\s+"); + if (tokens.length > 0) + return Integer.parseInt(tokens[0]); + } + throw new ParseException("mismatch", 0); + } + + public Iterator iterator() { + return lines.iterator(); + } + + public int log_available() { + switch (log_format) { + case AltosLib.AO_LOG_FORMAT_TINY: + if (stored_flight == 0) + return 1; + return 0; + default: + if (flight_log_max <= 0) + return 1; + int log_space = storage_size - storage_erase_unit; + int log_used = stored_flight * flight_log_max; + + if (log_used >= log_space) + return 0; + return (log_space - log_used) / flight_log_max; + } + } + + int[] parse_version(String v) { + String[] parts = v.split("\\."); + int r[] = new int[parts.length]; + + for (int i = 0; i < parts.length; i++) { + try { + r[i] = Altos.fromdec(parts[i]); + } catch (NumberFormatException n) { + r[i] = 0; + } + } + + return r; + } + + public int compare_version(String other) { + int[] me = parse_version(version); + int[] them = parse_version(other); + + int l = Math.min(me.length, them.length); + + for (int i = 0; i < l; i++) { + int d = me[i] - them[i]; + if (d != 0) + return d; + } + if (me.length > l) + return 1; + if (them.length > l) + return -1; + return 0; + } + + public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("c s\np\nf\nl\nv\n"); + lines = new LinkedList(); + radio_setting = 0; + radio_frequency = 0; + stored_flight = 0; + for (;;) { + String line = link.get_reply(); + if (line == null) + throw new TimeoutException(); + if (line.contains("Syntax error")) + continue; + lines.add(line); + try { serial = get_int(line, "serial-number"); } catch (Exception e) {} + try { log_format = get_int(line, "log-format"); } catch (Exception e) {} + try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} + try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} + try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} + try { + radio_frequency = get_int(line, "Frequency:"); + if (radio_frequency < 0) + radio_frequency = 434550; + } catch (Exception e) {} + try { + if (line.startsWith("Accel cal")) { + String[] bits = line.split("\\s+"); + if (bits.length >= 6) { + accel_cal_plus = Integer.parseInt(bits[3]); + accel_cal_minus = Integer.parseInt(bits[5]); + } + } + } catch (Exception e) {} + try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} + try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} + try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} + try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} + try { version = get_string(line,"software-version"); } catch (Exception e) {} + try { product = get_string(line,"product"); } catch (Exception e) {} + + try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} + try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} + try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} + + /* signals the end of the version info */ + if (line.startsWith("software-version")) + break; + } + } + +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java b/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java new file mode 100644 index 00000000..3527b575 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java @@ -0,0 +1,259 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* + * Sensor data conversion functions + */ +package org.altusmetrum.AltosLib; + +public class AltosConvert { + /* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= Math.pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * Math.pow(base, exponent); + } + + return pressure; + } + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ + public static double + pressure_to_altitude(double pressure) + { + + double next_base_temperature = LAYER0_BASE_TEMPERATURE; + double next_base_pressure = LAYER0_BASE_PRESSURE; + + double altitude; + double base_pressure; + double base_temperature; + double base; /* base for function to determine base pressure of next layer */ + double exponent; /* exponent for function to determine base pressure + of next layer */ + double coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= Math.pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * Math.log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (Math.pow(base, exponent) - 1); + } + + return altitude; + } + + public static double + cc_battery_to_voltage(double battery) + { + return battery / 32767.0 * 5.0; + } + + public static double + cc_ignitor_to_voltage(double ignite) + { + return ignite / 32767 * 15.0; + } + + public static double radio_to_frequency(int freq, int setting, int cal, int channel) { + double f; + + if (freq > 0) + f = freq / 1000.0; + else { + if (setting <= 0) + setting = cal; + f = 434.550 * setting / cal; + /* Round to nearest 50KHz */ + f = Math.floor (20.0 * f + 0.5) / 20.0; + } + return f + channel * 0.100; + } + + public static int radio_frequency_to_setting(double frequency, int cal) { + double set = frequency / 434.550 * cal; + + return (int) Math.floor (set + 0.5); + } + + public static int radio_frequency_to_channel(double frequency) { + int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); + + if (channel < 0) + channel = 0; + if (channel > 9) + channel = 9; + return channel; + } + + public static double radio_channel_to_frequency(int channel) { + return 434.550 + channel * 0.100; + } + + public static int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + public static double meters_to_feet(double meters) { + return meters * (100 / (2.54 * 12)); + } + + public static double meters_to_mach(double meters) { + return meters / 343; /* something close to mach at usual rocket sites */ + } + + public static double meters_to_g(double meters) { + return meters / 9.80665; + } + + public static int checksum(int[] data, int start, int length) { + int csum = 0x5a; + for (int i = 0; i < length; i++) + csum += data[i + start]; + return csum & 0xff; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java new file mode 100644 index 00000000..6d889723 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java @@ -0,0 +1,102 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public class AltosEepromChunk { + + public static final int chunk_size = 256; + public static final int per_line = 8; + + public int data[]; + public int address; + public ParseException parse_exception = null; + + int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + public int data(int offset) { + return data[offset]; + } + + public int data16(int offset) { + return data[offset] | (data[offset + 1] << 8); + } + + public int data32(int offset) { + return data[offset] | (data[offset + 1] << 8) | + (data[offset+2] << 16) | (data[offset+3] << 24); + } + + public boolean erased(int start, int len) { + for (int i = 0; i < len; i++) + if (data[start+i] != 0xff) + return false; + return true; + } + + public AltosEepromChunk(AltosLink link, int block, boolean flush) + throws TimeoutException, InterruptedException { + + int offset; + + data = new int[chunk_size]; + address = block * chunk_size; + if (flush) + link.flush_input(); + link.printf("e %x\n", block); + + for (offset = 0; offset < chunk_size; offset += per_line) { + try { + String line = link.get_reply(5000); + + if (line == null) + throw new TimeoutException(); + + int[] values = ParseHex(line); + + if (values == null || values.length != per_line + 1) + throw new ParseException(String.format("invalid line %s", line), 0); + if (values[0] != offset) + throw new ParseException(String.format("data address out of sync at 0x%x", + address + offset), 0); + for (int i = 0; i < per_line; i++) + data[offset + i] = values[1 + i]; + } catch (ParseException pe) { + for (int i = 0; i < per_line; i++) + data[offset + i] = 0xff; + if (parse_exception == null) + parse_exception = pe; + } + } + } +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java new file mode 100644 index 00000000..f1397c7b --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java @@ -0,0 +1,475 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * 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 { + + 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; + } +} + +public class AltosEepromIterable 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; + + AltosEepromRecord flight_record; + AltosEepromRecord gps_date_record; + + TreeSet records; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + int sensor_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { + state.tick = record.tick; + switch (record.cmd) { + case AltosLib.AO_LOG_FLIGHT: + eeprom.seen |= 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 & 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_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 |= seen_sensor; + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.temp = record.a; + state.batt = record.b; + eeprom.seen |= seen_temp_volt; + break; + case AltosLib.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= 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; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; + state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> + AltosLib.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; + has_gps = true; + break; + case AltosLib.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_ALT: + 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; + state.gps.add_sat(svid, c_n0); + } + break; + case AltosLib.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case AltosLib.AO_LOG_CONFIG_VERSION: + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + break; + case AltosLib.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case AltosLib.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case AltosLib.AO_LOG_RADIO_CAL: + break; + case AltosLib.AO_LOG_MANUFACTURER: + break; + case AltosLib.AO_LOG_PRODUCT: + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + break; + } + state.seen |= eeprom.seen; + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedRecord record = null; + AltosRecord state = new AltosRecord(); + 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) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + AltosOrderedRecord record = iterator.next(); + switch (record.cmd) { + case AltosLib.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", record.data); + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", record.a); + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case AltosLib.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case AltosLib.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case AltosLib.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; + case AltosLib.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case AltosLib.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + case Altos.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); + flags |= AltosLib.AO_GPS_RUNNING; + flags |= AltosLib.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromIterable (FileInputStream input) { + records = new TreeSet(); + + AltosOrderedRecord last_gps_time = null; + + int index = 0; + int prev_tick = 0; + boolean prev_tick_valid = false; + boolean missing_time = false; + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == AltosLib.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == AltosLib.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedRecord old = iterator.next(); + if (old.cmd == AltosLib.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == AltosLib.AO_LOG_STATE && + record.a == AltosLib.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java new file mode 100644 index 00000000..7fca4bd9 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java @@ -0,0 +1,100 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +/* + * Extract a bit of information from an eeprom-stored flight log. + */ + +public class AltosEepromLog { + public int serial; + public boolean has_flight; + public int flight; + public int start_block; + public int end_block; + + public int year, month, day; + + public boolean selected; + + public AltosEepromLog(AltosConfigData config_data, + AltosLink link, + int in_flight, int in_start_block, + int in_end_block) + throws InterruptedException, TimeoutException { + + int block; + boolean has_date = false; + + flight = in_flight; + if (flight != 0) + has_flight = true; + start_block = in_start_block; + end_block = in_end_block; + serial = config_data.serial; + + /* + * Select all flights for download + */ + selected = true; + + /* + * Look in TeleMetrum log data for date + */ + if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN || + config_data.log_format == AltosLib.AO_LOG_FORMAT_FULL) + { + /* + * Only look in the first two blocks so that this + * process doesn't take a long time + */ + if (in_end_block > in_start_block + 2) + in_end_block = in_start_block + 2; + + 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 < eechunk.chunk_size; i += AltosEepromRecord.record_length) { + try { + AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + + if (r.cmd == AltosLib.AO_LOG_FLIGHT) { + flight = r.b; + has_flight = true; + } + if (r.cmd == AltosLib.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + has_date = true; + } + } catch (ParseException pe) { + } + } + if (has_date && has_flight) + break; + } + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java new file mode 100644 index 00000000..1e845f46 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java @@ -0,0 +1,139 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +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/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java new file mode 100644 index 00000000..1758fa34 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +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/src/org/altusmetrum/AltosLib/AltosFile.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java new file mode 100644 index 00000000..d2e4f2f7 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +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) { + super (AltosPreferences.logdir(), + String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", + year, month, day, serial, flight, extension)); + } + + public AltosFile(int serial, int flight, String extension) { + this(Calendar.getInstance().get(Calendar.YEAR), + Calendar.getInstance().get(Calendar.MONTH) + 1, + Calendar.getInstance().get(Calendar.DAY_OF_MONTH), + serial, + flight, + extension); + } + + public AltosFile(AltosRecord telem) { + this(telem.serial, telem.flight, "telem"); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java new file mode 100644 index 00000000..3fdea469 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosFlightReader { + public String name; + + public int serial; + + public void init() { } + + public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } + + public void close(boolean interrupted) { } + + public void set_frequency(double frequency) throws InterruptedException, TimeoutException { } + + public void save_frequency() { } + + public void set_telemetry(int telemetry) { } + + public void save_telemetry() { } + + public void update(AltosState state) throws InterruptedException { } + + public boolean supports_telemetry(int telemetry) { return false; } + + public File backing_file() { return null; } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java new file mode 100644 index 00000000..f08ff116 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosFrequency { + public double frequency; + public String description; + + public String toString() { + return String.format("%7.3f MHz %-20s", + frequency, description); + } + + public String toShortString() { + return String.format("%7.3f MHz %s", + frequency, description); + } + + public boolean close(double f) { + double diff = Math.abs(frequency - f); + + return diff < 0.010; + } + + public AltosFrequency(double f, String d) { + frequency = f; + description = d; + } +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java new file mode 100644 index 00000000..f078a469 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java @@ -0,0 +1,248 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; + +public class AltosGPS { + + public final static int MISSING = AltosRecord.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 int year; + public int month; + public int day; + public int hour; + public int minute; + public int second; + + public double ground_speed; /* m/s */ + public int course; /* degrees */ + public double climb_rate; /* m/s */ + public double hdop; /* unitless */ + public double vdop; /* unitless */ + public int h_error; /* m */ + public int v_error; /* m */ + + public AltosGPSSat[] cc_gps_sat; /* tracking data */ + + public void ParseGPSDate(String date) throws ParseException { + String[] ymd = date.split("-"); + if (ymd.length != 3) + throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); + year = AltosParse.parse_int(ymd[0]); + month = AltosParse.parse_int(ymd[1]); + day = AltosParse.parse_int(ymd[2]); + } + + public void ParseGPSTime(String time) throws ParseException { + String[] hms = time.split(":"); + if (hms.length != 3) + throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); + hour = AltosParse.parse_int(hms[0]); + minute = AltosParse.parse_int(hms[1]); + second = AltosParse.parse_int(hms[2]); + } + + public void ClearGPSTime() { + year = month = day = 0; + hour = minute = second = 0; + } + + public AltosGPS(AltosTelemetryMap map) throws ParseException { + String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, + AltosTelemetry.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)) { + 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); + 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)) { + connected = true; + locked = false; + } else { + connected = false; + locked = false; + } + } + + public AltosGPS(String[] words, int i, int version) throws ParseException { + AltosParse.word(words[i++], "GPS"); + nsat = AltosParse.parse_int(words[i++]); + AltosParse.word(words[i++], "sat"); + + connected = false; + locked = false; + lat = lon = 0; + alt = 0; + ClearGPSTime(); + if ((words[i]).equals("unlocked")) { + connected = true; + i++; + } else if ((words[i]).equals("not-connected")) { + i++; + } else if (words.length >= 40) { + locked = true; + connected = true; + + if (version > 1) + ParseGPSDate(words[i++]); + else + year = month = day = 0; + ParseGPSTime(words[i++]); + lat = AltosParse.parse_coord(words[i++]); + lon = AltosParse.parse_coord(words[i++]); + alt = AltosParse.parse_int(words[i++]); + if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { + ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); + course = AltosParse.parse_int(words[i++]); + climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); + hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); + h_error = AltosParse.parse_int(words[i++]); + v_error = AltosParse.parse_int(words[i++]); + } + } else { + i++; + } + if (i < words.length) { + AltosParse.word(words[i++], "SAT"); + int tracking_channels = 0; + if (words[i].equals("not-connected")) + tracking_channels = 0; + else + tracking_channels = AltosParse.parse_int(words[i]); + i++; + cc_gps_sat = new AltosGPSSat[tracking_channels]; + for (int chan = 0; chan < tracking_channels; chan++) { + cc_gps_sat[chan] = new AltosGPSSat(); + cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); + /* Older versions included SiRF status bits */ + if (version < 2) + i++; + cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); + } + } else + cc_gps_sat = new AltosGPSSat[0]; + } + + public void set_latitude(int in_lat) { + lat = in_lat / 10.0e7; + } + + public void set_longitude(int in_lon) { + lon = in_lon / 10.0e7; + } + + public void set_time(int hour, int minute, int second) { + hour = hour; + minute = minute; + second = second; + } + + public void set_date(int year, int month, int day) { + year = year; + month = month; + day = day; + } + + public void set_flags(int flags) { + flags = flags; + } + + public void set_altitude(int altitude) { + altitude = altitude; + } + + public void add_sat(int svid, int c_n0) { + if (cc_gps_sat == null) { + cc_gps_sat = new AltosGPSSat[1]; + } else { + AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; + for (int i = 0; i < cc_gps_sat.length; i++) + new_gps_sat[i] = cc_gps_sat[i]; + cc_gps_sat = new_gps_sat; + } + AltosGPSSat sat = new AltosGPSSat(); + sat.svid = svid; + sat.c_n0 = c_n0; + cc_gps_sat[cc_gps_sat.length - 1] = sat; + } + + public AltosGPS() { + ClearGPSTime(); + cc_gps_sat = null; + } + + public AltosGPS(AltosGPS old) { + nsat = old.nsat; + locked = old.locked; + connected = old.connected; + lat = old.lat; /* degrees (+N -S) */ + lon = old.lon; /* degrees (+E -W) */ + alt = old.alt; /* m */ + year = old.year; + month = old.month; + day = old.day; + hour = old.hour; + minute = old.minute; + second = old.second; + + ground_speed = old.ground_speed; /* m/s */ + course = old.course; /* degrees */ + climb_rate = old.climb_rate; /* m/s */ + hdop = old.hdop; /* unitless? */ + h_error = old.h_error; /* m */ + v_error = old.v_error; /* m */ + + if (old.cc_gps_sat != null) { + cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; + for (int i = 0; i < old.cc_gps_sat.length; i++) { + cc_gps_sat[i] = new AltosGPSSat(); + cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; + cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; + } + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java new file mode 100644 index 00000000..faa1ec8d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java @@ -0,0 +1,32 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosGPSSat { + public int svid; + public int c_n0; + + public AltosGPSSat(int s, int c) { + svid = s; + c_n0= c; + } + + public AltosGPSSat() { + } +} + diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java new file mode 100644 index 00000000..76b71859 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java @@ -0,0 +1,101 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.Math; + +public class AltosGreatCircle { + public double distance; + public double bearing; + + double sqr(double a) { return a * a; } + + static final double rad = Math.PI / 180; + static final double earth_radius = 6371.2 * 1000; /* in meters */ + + public static final int BEARING_LONG = 0; + public static final int BEARING_SHORT = 1; + public static final int BEARING_VOICE = 2; + + public String bearing_words(int length) { + String [][] bearing_string = { + { + "North", "North North East", "North East", "East North East", + "East", "East South East", "South East", "South South East", + "South", "South South West", "South West", "West South West", + "West", "West North West", "North West", "North North West" + }, { + "N", "NNE", "NE", "ENE", + "E", "ESE", "SE", "SSE", + "S", "SSW", "SW", "WSW", + "W", "WNW", "NW", "NNW" + }, { + "north", "nor nor east", "north east", "east nor east", + "east", "east sow east", "south east", "sow sow east", + "south", "sow sow west", "south west", "west sow west", + "west", "west nor west", "north west", "nor nor west " + } + }; + return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; + } + + public AltosGreatCircle (double start_lat, double start_lon, + double end_lat, double end_lon) + { + double lat1 = rad * start_lat; + double lon1 = rad * -start_lon; + double lat2 = rad * end_lat; + double lon2 = rad * -end_lon; + + double d_lon = lon2 - lon1; + + /* From http://en.wikipedia.org/wiki/Great-circle_distance */ + double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + + sqr(Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); + double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); + double d = Math.atan2(vdn,vdd); + double course; + + if (Math.cos(lat1) < 1e-20) { + if (lat1 > 0) + course = Math.PI; + else + course = -Math.PI; + } else { + if (d < 1e-10) + course = 0; + else + course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / + (Math.sin(d)*Math.cos(lat1))); + if (Math.sin(lon2-lon1) > 0) + course = 2 * Math.PI-course; + } + distance = d * earth_radius; + bearing = course * 180/Math.PI; + } + + public AltosGreatCircle(AltosGPS start, AltosGPS end) { + this(start.lat, start.lon, end.lat, end.lon); + } + + public AltosGreatCircle() { + distance = 0; + bearing = 0; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java new file mode 100644 index 00000000..2921d040 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java @@ -0,0 +1,348 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.awt.*; +import java.util.*; +import java.text.*; +import java.nio.charset.Charset; + +public class AltosLib { + /* EEProm command letters */ + public static final int AO_LOG_FLIGHT = 'F'; + public static final int AO_LOG_SENSOR = 'A'; + 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_TIME = 'G'; + public static final int AO_LOG_GPS_LAT = 'N'; + public static final int AO_LOG_GPS_LON = 'W'; + public static final int AO_LOG_GPS_ALT = 'H'; + public static final int AO_LOG_GPS_SAT = 'V'; + public static final int AO_LOG_GPS_DATE = 'Y'; + public static final int AO_LOG_PRESSURE = 'P'; + + /* Added for header fields in eeprom files */ + public static final int AO_LOG_CONFIG_VERSION = 1000; + public static final int AO_LOG_MAIN_DEPLOY = 1001; + public static final int AO_LOG_APOGEE_DELAY = 1002; + public static final int AO_LOG_RADIO_CHANNEL = 1003; + public static final int AO_LOG_CALLSIGN = 1004; + public static final int AO_LOG_ACCEL_CAL = 1005; + public static final int AO_LOG_RADIO_CAL = 1006; + public static final int AO_LOG_MAX_FLIGHT_LOG = 1007; + public static final int AO_LOG_MANUFACTURER = 2000; + public static final int AO_LOG_PRODUCT = 2001; + public static final int AO_LOG_SERIAL_NUMBER = 2002; + public static final int AO_LOG_LOG_FORMAT = 2003; + public static final int AO_LOG_SOFTWARE_VERSION = 9999; + + /* Added to flag invalid records */ + public static final int AO_LOG_INVALID = -1; + + /* Flight state numbers and names */ + public static final int ao_flight_startup = 0; + public static final int ao_flight_idle = 1; + public static final int ao_flight_pad = 2; + public static final int ao_flight_boost = 3; + public static final int ao_flight_fast = 4; + public static final int ao_flight_coast = 5; + public static final int ao_flight_drogue = 6; + public static final int ao_flight_main = 7; + public static final int ao_flight_landed = 8; + public static final int ao_flight_invalid = 9; + + /* Telemetry modes */ + public static final int ao_telemetry_off = 0; + public static final int ao_telemetry_min = 1; + public static final int ao_telemetry_standard = 1; + public static final int ao_telemetry_0_9 = 2; + public static final int ao_telemetry_0_8 = 3; + public static final int ao_telemetry_max = 3; + + public static final String[] ao_telemetry_name = { + "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" + }; + + public static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; + + public static final int ao_telemetry_standard_len = 32; + public static final int ao_telemetry_0_9_len = 95; + public static final int ao_telemetry_0_8_len = 94; + + public static final int[] ao_telemetry_len = { + 0, 32, 95, 94 + }; + + public static HashMap string_to_state = new HashMap(); + + public static boolean map_initialized = false; + + public static void initialize_map() + { + string_to_state.put("startup", ao_flight_startup); + string_to_state.put("idle", ao_flight_idle); + string_to_state.put("pad", ao_flight_pad); + string_to_state.put("boost", ao_flight_boost); + string_to_state.put("fast", ao_flight_fast); + string_to_state.put("coast", ao_flight_coast); + string_to_state.put("drogue", ao_flight_drogue); + string_to_state.put("apogee", ao_flight_coast); + string_to_state.put("main", ao_flight_main); + string_to_state.put("landed", ao_flight_landed); + string_to_state.put("invalid", ao_flight_invalid); + map_initialized = true; + } + + public static int telemetry_len(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_len[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String telemetry_name(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_name[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String[] state_to_string = { + "startup", + "idle", + "pad", + "boost", + "fast", + "coast", + "drogue", + "main", + "landed", + "invalid", + }; + + public static String[] state_to_string_capital = { + "Startup", + "Idle", + "Pad", + "Boost", + "Fast", + "Coast", + "Drogue", + "Main", + "Landed", + "Invalid", + }; + + public static int state(String state) { + if (!map_initialized) + initialize_map(); + if (string_to_state.containsKey(state)) + return string_to_state.get(state); + return ao_flight_invalid; + } + + public static String state_name(int state) { + if (state < 0 || state_to_string.length <= state) + return "invalid"; + return state_to_string[state]; + } + + public static final int AO_GPS_VALID = (1 << 4); + public static final int AO_GPS_RUNNING = (1 << 5); + public static final int AO_GPS_DATE_VALID = (1 << 6); + public static final int AO_GPS_NUM_SAT_SHIFT = 0; + public static final int AO_GPS_NUM_SAT_MASK = 0xf; + + public static final int AO_LOG_FORMAT_UNKNOWN = 0; + public static final int AO_LOG_FORMAT_FULL = 1; + public static final int AO_LOG_FORMAT_TINY = 2; + 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_NONE = 127; + + public static boolean isspace(int c) { + switch (c) { + case ' ': + case '\t': + return true; + } + return false; + } + + public static boolean ishex(int c) { + if ('0' <= c && c <= '9') + return true; + if ('a' <= c && c <= 'f') + return true; + if ('A' <= c && c <= 'F') + return true; + return false; + } + + public static boolean ishex(String s) { + for (int i = 0; i < s.length(); i++) + if (!ishex(s.charAt(i))) + return false; + return true; + } + + public static int fromhex(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return c - 'a' + 10; + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + return -1; + } + + public static int fromhex(String s) throws NumberFormatException { + int c, v = 0; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (!ishex(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + return v; + } + v = v * 16 + fromhex(c); + } + return v; + } + + public static boolean isdec(int c) { + if ('0' <= c && c <= '9') + return true; + return false; + } + + public static boolean isdec(String s) { + for (int i = 0; i < s.length(); i++) + if (!isdec(s.charAt(i))) + return false; + return true; + } + + public static int fromdec(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + return -1; + } + + public static int int8(int[] bytes, int i) { + return (int) (byte) bytes[i]; + } + + public static int uint8(int[] bytes, int i) { + return bytes[i]; + } + + public static int int16(int[] bytes, int i) { + return (int) (short) (bytes[i] + (bytes[i+1] << 8)); + } + + public static int uint16(int[] bytes, int i) { + return bytes[i] + (bytes[i+1] << 8); + } + + public static int uint32(int[] bytes, int i) { + return bytes[i] + + (bytes[i+1] << 8) + + (bytes[i+2] << 16) + + (bytes[i+3] << 24); + } + + public static final Charset unicode_set = Charset.forName("UTF-8"); + + public static String string(int[] bytes, int s, int l) { + if (s + l > bytes.length) { + if (s > bytes.length) { + s = bytes.length; + l = 0; + } else { + l = bytes.length - s; + } + } + + int i; + for (i = l - 1; i >= 0; i--) + if (bytes[s+i] != 0) + break; + + l = i + 1; + byte[] b = new byte[l]; + + for (i = 0; i < l; i++) + b[i] = (byte) bytes[s+i]; + String n = new String(b, unicode_set); + return n; + } + + public static int hexbyte(String s, int i) { + int c0, c1; + + if (s.length() < i + 2) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + c0 = s.charAt(i); + if (!ishex(c0)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); + c1 = s.charAt(i+1); + if (!ishex(c1)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); + return fromhex(c0) * 16 + fromhex(c1); + } + + public static int[] hexbytes(String s) { + int n; + int[] r; + int i; + + if ((s.length() & 1) != 0) + throw new NumberFormatException(String.format("invalid line \"%s\"", s)); + n = s.length() / 2; + r = new int[n]; + for (i = 0; i < n; i++) + r[i] = hexbyte(s, i * 2); + return r; + } + + public static int fromdec(String s) throws NumberFormatException { + int c, v = 0; + int sign = 1; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (i == 0 && c == '-') { + sign = -1; + } else if (!isdec(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid number \"%s\"", s)); + return v; + } else + v = v * 10 + fromdec(c); + } + return v * sign; + } + + public static String replace_extension(String input, String extension) { + int dot = input.lastIndexOf("."); + if (dot > 0) + input = input.substring(0,dot); + return input.concat(extension); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java new file mode 100644 index 00000000..5627795a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosLine { + public String line; + + public AltosLine() { + line = null; + } + + public AltosLine(String s) { + line = s; + } +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java new file mode 100644 index 00000000..9b80e916 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java @@ -0,0 +1,238 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import java.text.*; + +public abstract class AltosLink { + public abstract void print(String data); + public abstract void close(); + + public static boolean debug = false; + public static void set_debug(boolean in_debug) { debug = in_debug; } + LinkedList pending_output = new LinkedList(); + + public LinkedList> monitors = new LinkedList> ();; + public LinkedBlockingQueue reply_queue = new LinkedBlockingQueue(); + + public void add_monitor(LinkedBlockingQueue q) { + set_monitor(true); + monitors.add(q); + } + + public void remove_monitor(LinkedBlockingQueue q) { + monitors.remove(q); + if (monitors.isEmpty()) + set_monitor(false); + } + + public void printf(String format, Object ... arguments) { + String line = String.format(format, arguments); + if (debug) + pending_output.add(line); + print(line); + } + + public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { + flush_output(); + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) + return line.line; + return null; + } + + public String get_reply(int timeout) throws InterruptedException { + try { + return get_reply_no_dialog(timeout); + } catch (TimeoutException te) { + return null; + } + } + + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + + public void add_telem(AltosLine line) throws InterruptedException { + for (int e = 0; e < monitors.size(); e++) { + LinkedBlockingQueue q = monitors.get(e); + q.put(line); + } + } + + public void add_reply(AltosLine line) throws InterruptedException { + reply_queue.put (line); + } + + public void add_string(String line) throws InterruptedException { + if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { + add_telem(new AltosLine(line)); + } else { + add_reply(new AltosLine(line)); + } + } + + public void add_bytes(byte[] bytes, int len) throws InterruptedException { + String line; + try { + line = new String(bytes, 0, len, "UTF-8"); + } catch (UnsupportedEncodingException ue) { + line = ""; + for (int i = 0; i < len; i++) + line = line + bytes[i]; + } + if (debug) + System.out.printf("\t\t\t\t\t%s\n", line); + add_string(line); + } + + public void flush_output() { + for (String s : pending_output) + System.out.print(s); + pending_output.clear(); + } + + public void flush_input(int timeout) throws InterruptedException { + flush_output(); + boolean got_some; + + do { + Thread.sleep(timeout); + got_some = !reply_queue.isEmpty(); + reply_queue.clear(); + } while (got_some); + } + + + public void flush_input() throws InterruptedException { + flush_input(100); + } + + + /* + * Various command-level operations on + * the link + */ + public boolean monitor_mode = false; + public int telemetry = AltosLib.ao_telemetry_standard; + public double frequency; + AltosConfigData config_data; + + private int telemetry_len() { + return AltosLib.telemetry_len(telemetry); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + if (monitor_mode) + printf("m 0\nm %x\n", telemetry_len()); + flush_output(); + } + + public void set_monitor(boolean monitor) { + monitor_mode = monitor; + if (monitor) + printf("m %x\n", telemetry_len()); + else + printf("m 0\n"); + flush_output(); + } + + private void set_channel(int channel) { + if (monitor_mode) + printf("m 0\nc r %d\nm %x\n", + channel, telemetry_len()); + else + printf("c r %d\n", channel); + flush_output(); + } + + private void set_radio_setting(int setting) { + if (monitor_mode) + printf("m 0\nc R %d\nm %x\n", + setting, telemetry_len()); + else + printf("c R %d\n", setting); + flush_output(); + } + + public void set_radio_frequency(double frequency, + boolean has_setting, + int cal) { + if (debug) + System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); + if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + + public AltosConfigData config_data() throws InterruptedException, TimeoutException { + if (config_data == null) + config_data = new AltosConfigData(this); + return config_data; + } + + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + + public void set_callsign(String callsign) { + printf ("c c %s\n", callsign); + flush_output(); + } + + public boolean remote; + public int serial; + public String name; + + public void start_remote() throws TimeoutException, InterruptedException { + if (debug) + System.out.printf("start remote %7.3f\n", frequency); + if (frequency == 0.0) + frequency = AltosPreferences.frequency(serial); + set_radio_frequency(frequency); + set_callsign(AltosPreferences.callsign()); + printf("p\nE 0\n"); + flush_input(); + remote = true; + } + + public void stop_remote() throws InterruptedException { + if (debug) + System.out.printf("stop remote\n"); + try { + flush_input(); + } finally { + printf ("~\n"); + flush_output(); + } + remote = false; + } + + public AltosLink() { + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java new file mode 100644 index 00000000..08c45ca8 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.text.ParseException; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * This creates a thread to capture telemetry data and write it to + * a log file + */ +class AltosLog implements Runnable { + + LinkedBlockingQueue input_queue; + LinkedBlockingQueue pending_queue; + int serial; + int flight; + FileWriter log_file; + Thread log_thread; + AltosFile file; + + private void close_log_file() { + if (log_file != null) { + try { + log_file.close(); + } catch (IOException io) { + } + log_file = null; + } + } + + void close() { + close_log_file(); + if (log_thread != null) { + log_thread.interrupt(); + log_thread = null; + } + } + + File file() { + return file; + } + + boolean open (AltosRecord telem) throws IOException { + AltosFile a = new AltosFile(telem); + + System.out.printf("open %s\n", a.toString()); + 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) { + } + } + log_file.flush(); + file = a; + } + return log_file != null; + } + + public void run () { + try { + AltosRecord previous = null; + for (;;) { + AltosLine line = input_queue.take(); + if (line.line == null) + continue; + try { + AltosRecord telem = AltosTelemetry.parse(line.line, previous); + if (telem.serial != 0 && telem.flight != 0 && + (telem.serial != serial || telem.flight != flight || log_file == null)) + { + close_log_file(); + serial = telem.serial; + flight = telem.flight; + open(telem); + } + previous = telem; + } catch (ParseException pe) { + } catch (AltosCRCException ce) { + } + if (log_file != null) { + log_file.write(line.line); + log_file.write('\n'); + log_file.flush(); + } else + pending_queue.put(line.line); + } + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + close(); + } + + public AltosLog (AltosLink link) { + pending_queue = new LinkedBlockingQueue (); + input_queue = new LinkedBlockingQueue (); + link.add_monitor(input_queue); + serial = -1; + flight = -1; + log_file = null; + log_thread = new Thread(this); + log_thread.start(); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java b/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java new file mode 100644 index 00000000..7d832f1a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java @@ -0,0 +1,79 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.text.*; +import java.lang.*; + +public class AltosParse { + public static boolean isdigit(char c) { + return '0' <= c && c <= '9'; + } + + public static int parse_int(String v) throws ParseException { + try { + return AltosLib.fromdec(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing int " + v, 0); + } + } + + public static int parse_hex(String v) throws ParseException { + try { + return AltosLib.fromhex(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing hex " + v, 0); + } + } + + public static double parse_double(String v) throws ParseException { + try { + return Double.parseDouble(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing double " + v, 0); + } + } + + public static double parse_coord(String coord) throws ParseException { + String[] dsf = coord.split("\\D+"); + + if (dsf.length != 3) { + throw new ParseException("error parsing coord " + coord, 0); + } + int deg = parse_int(dsf[0]); + int min = parse_int(dsf[1]); + int frac = parse_int(dsf[2]); + + double r = deg + (min + frac / 10000.0) / 60.0; + if (coord.endsWith("S") || coord.endsWith("W")) + r = -r; + return r; + } + + public static String strip_suffix(String v, String suffix) { + if (v.endsWith(suffix)) + return v.substring(0, v.length() - suffix.length()); + return v; + } + + public static void word(String v, String m) throws ParseException { + if (!v.equals(m)) { + throw new ParseException("error matching '" + v + "' '" + m + "'", 0); + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java b/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java new file mode 100644 index 00000000..43c7088d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java @@ -0,0 +1,365 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.awt.Component; +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; + +public class AltosPreferences { + public static Preferences preferences; + + /* logdir preference name */ + public final static String logdirPreference = "LOGDIR"; + + /* channel preference name */ + public final static String channelPreferenceFormat = "CHANNEL-%d"; + + /* frequency preference name */ + public final static String frequencyPreferenceFormat = "FREQUENCY-%d"; + + /* telemetry format preference name */ + public final static String telemetryPreferenceFormat = "TELEMETRY-%d"; + + /* voice preference name */ + public final static String voicePreference = "VOICE"; + + /* callsign preference name */ + public final static String callsignPreference = "CALLSIGN"; + + /* firmware directory preference name */ + public final static String firmwaredirPreference = "FIRMWARE"; + + /* serial debug preference name */ + public final static String serialDebugPreference = "SERIAL-DEBUG"; + + /* scanning telemetry preferences name */ + public final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; + + /* Launcher serial preference name */ + public final static String launcherSerialPreference = "LAUNCHER-SERIAL"; + + /* Launcher channel preference name */ + public final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; + + /* Default logdir is ~/TeleMetrum */ + public final static String logdirName = "TeleMetrum"; + + /* Log directory */ + public static File logdir; + + /* Map directory -- hangs of logdir */ + public static File mapdir; + + /* Frequency (map serial to frequency) */ + public static Hashtable frequencies; + + /* Telemetry (map serial to telemetry format) */ + public static Hashtable telemetries; + + /* Voice preference */ + public static boolean voice; + + /* Callsign preference */ + public static String callsign; + + /* Firmware directory */ + public static File firmwaredir; + + /* Scanning telemetry */ + public static int scanning_telemetry; + + /* List of frequencies */ + public final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; + public static AltosFrequency[] common_frequencies; + + public final static String frequency_count = "COUNT"; + public final static String frequency_format = "FREQUENCY-%d"; + public final static String description_format = "DESCRIPTION-%d"; + + public static AltosFrequency[] load_common_frequencies() { + AltosFrequency[] frequencies = null; + boolean existing = false; + try { + existing = preferences.nodeExists(common_frequencies_node_name); + } catch (BackingStoreException be) { + existing = false; + } + if (existing) { + Preferences node = preferences.node(common_frequencies_node_name); + int count = node.getInt(frequency_count, 0); + + frequencies = new AltosFrequency[count]; + for (int i = 0; i < count; i++) { + double frequency; + String description; + + frequency = node.getDouble(String.format(frequency_format, i), 0.0); + description = node.get(String.format(description_format, i), null); + frequencies[i] = new AltosFrequency(frequency, description); + } + } else { + frequencies = new AltosFrequency[10]; + for (int i = 0; i < 10; i++) { + frequencies[i] = new AltosFrequency(434.550 + i * .1, + String.format("Channel %d", i)); + } + } + return frequencies; + } + + public static void save_common_frequencies(AltosFrequency[] frequencies) { + Preferences node = preferences.node(common_frequencies_node_name); + + node.putInt(frequency_count, frequencies.length); + for (int i = 0; i < frequencies.length; i++) { + node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); + node.put(String.format(description_format, i), frequencies[i].description); + } + } + public static int launcher_serial; + + public static int launcher_channel; + + public static void init() { + preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); + + /* Initialize logdir from preferences */ + String logdir_string = preferences.get(logdirPreference, null); + if (logdir_string != null) + logdir = new File(logdir_string); + else { + /* Use the file system view default directory */ + logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); + if (!logdir.exists()) + logdir.mkdirs(); + } + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + + frequencies = new Hashtable(); + + telemetries = new Hashtable(); + + voice = preferences.getBoolean(voicePreference, true); + + callsign = preferences.get(callsignPreference,"N0CALL"); + + scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << AltosLib.ao_telemetry_standard)); + + launcher_serial = preferences.getInt(launcherSerialPreference, 0); + + launcher_channel = preferences.getInt(launcherChannelPreference, 0); + + String firmwaredir_string = preferences.get(firmwaredirPreference, null); + if (firmwaredir_string != null) + firmwaredir = new File(firmwaredir_string); + else + firmwaredir = null; + + common_frequencies = load_common_frequencies(); + + } + + static { init(); } + + public static void flush_preferences() { + try { + preferences.flush(); + } catch (BackingStoreException ee) { +/* + if (component != null) + JOptionPane.showMessageDialog(component, + preferences.absolutePath(), + "Cannot save prefernces", + JOptionPane.ERROR_MESSAGE); + else +*/ + System.err.printf("Cannot save preferences\n"); + } + } + + public static void set_logdir(File new_logdir) { + logdir = new_logdir; + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + synchronized (preferences) { + preferences.put(logdirPreference, logdir.getPath()); + flush_preferences(); + } + } + + public static File logdir() { + return logdir; + } + + public static File mapdir() { + return mapdir; + } + + public static void set_frequency(int serial, double new_frequency) { + frequencies.put(serial, new_frequency); + synchronized (preferences) { + preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); + flush_preferences(); + } + } + + public static double frequency(int serial) { + if (frequencies.containsKey(serial)) + return frequencies.get(serial); + double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); + if (frequency == 0.0) { + int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); + frequency = AltosConvert.radio_channel_to_frequency(channel); + } + frequencies.put(serial, frequency); + return frequency; + } + + public static void set_telemetry(int serial, int new_telemetry) { + telemetries.put(serial, new_telemetry); + synchronized (preferences) { + preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); + flush_preferences(); + } + } + + public static int telemetry(int serial) { + if (telemetries.containsKey(serial)) + return telemetries.get(serial); + int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), + AltosLib.ao_telemetry_standard); + telemetries.put(serial, telemetry); + return telemetry; + } + + public static void set_scanning_telemetry(int new_scanning_telemetry) { + scanning_telemetry = new_scanning_telemetry; + synchronized (preferences) { + preferences.putInt(scanningTelemetryPreference, scanning_telemetry); + flush_preferences(); + } + } + + public static int scanning_telemetry() { + return scanning_telemetry; + } + + public static void set_voice(boolean new_voice) { + voice = new_voice; + synchronized (preferences) { + preferences.putBoolean(voicePreference, voice); + flush_preferences(); + } + } + + public static boolean voice() { + return voice; + } + + public static void set_callsign(String new_callsign) { + callsign = new_callsign; + synchronized(preferences) { + preferences.put(callsignPreference, callsign); + flush_preferences(); + } + } + + public static String callsign() { + return callsign; + } + + public static void set_firmwaredir(File new_firmwaredir) { + firmwaredir = new_firmwaredir; + synchronized (preferences) { + preferences.put(firmwaredirPreference, firmwaredir.getPath()); + flush_preferences(); + } + } + + public static File firmwaredir() { + return firmwaredir; + } + + public static void set_launcher_serial(int new_launcher_serial) { + launcher_serial = new_launcher_serial; + System.out.printf("set launcher serial to %d\n", new_launcher_serial); + synchronized (preferences) { + preferences.putInt(launcherSerialPreference, launcher_serial); + flush_preferences(); + } + } + + public static int launcher_serial() { + return launcher_serial; + } + + public static void set_launcher_channel(int new_launcher_channel) { + launcher_channel = new_launcher_channel; + System.out.printf("set launcher channel to %d\n", new_launcher_channel); + synchronized (preferences) { + preferences.putInt(launcherChannelPreference, launcher_channel); + flush_preferences(); + } + } + + public static int launcher_channel() { + return launcher_channel; + } + + public static Preferences bt_devices() { + return preferences.node("bt_devices"); + } + + public static AltosFrequency[] common_frequencies() { + return common_frequencies; + } + + public static void set_common_frequencies(AltosFrequency[] frequencies) { + common_frequencies = frequencies; + synchronized(preferences) { + save_common_frequencies(frequencies); + flush_preferences(); + } + } + + public static void add_common_frequency(AltosFrequency frequency) { + AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; + int i; + + for (i = 0; i < common_frequencies.length; i++) { + if (frequency.frequency == common_frequencies[i].frequency) + return; + if (frequency.frequency < common_frequencies[i].frequency) + break; + new_frequencies[i] = common_frequencies[i]; + } + new_frequencies[i] = frequency; + for (; i < common_frequencies.length; i++) + new_frequencies[i+1] = common_frequencies[i]; + set_common_frequencies(new_frequencies); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java new file mode 100644 index 00000000..e4915af0 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java @@ -0,0 +1,319 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; +import java.io.*; + +public class AltosRecord implements Comparable { + public final static int MISSING = 0x7fffffff; + + 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 int version; + public String callsign; + public int serial; + public int flight; + public int rssi; + public int status; + public int state; + public int tick; + + 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 double acceleration; + public double speed; + public double height; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + public AltosGPS gps; + public boolean new_gps; + + public AltosIMU imu; + public AltosMag mag; + + 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; + +>>>>>>> 5a249bc... altosui: Complete split out of separate java library + /* + * 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 + */ + + public static final double counts_per_kPa = 27 * 2047 / 3300; + public static final double counts_at_101_3kPa = 1674.0; + + public static double + barometer_to_pressure(double count) + { + return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; + } + + public double raw_pressure() { + if (pres == MISSING) + return MISSING; + return barometer_to_pressure(pres); + } + + public double filtered_pressure() { + if (flight_pres == MISSING) + return MISSING; + return barometer_to_pressure(flight_pres); + } + + public double ground_pressure() { + if (ground_pres == MISSING) + return MISSING; + return barometer_to_pressure(ground_pres); + } + + public double raw_altitude() { + double p = raw_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 filtered_altitude() { + if (height != MISSING && ground_pres != MISSING) + return height + ground_altitude(); + + double p = filtered_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double filtered_height() { + if (height != MISSING) + return height; + + double f = filtered_altitude(); + double g = ground_altitude(); + if (f == MISSING || g == MISSING) + return MISSING; + return f - g; + } + + public double raw_height() { + double r = raw_altitude(); + double g = ground_altitude(); + + if (r == MISSING || g == MISSING) + return height; + return r - g; + } + + 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 + */ + + public 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); + } + + public 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 (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + if (speed != MISSING) + return speed; + if (flight_vel == MISSING) + return MISSING; + return flight_vel / (accel_counts_per_mss() * 100.0); + } + + public String state() { + return AltosLib.state_name(state); + } + + public static String gets(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') { + return line; + } + line = line + (char) c; + } + return null; + } + + public int compareTo(AltosRecord o) { + return tick - o.tick; + } + + public AltosRecord(AltosRecord old) { + version = old.version; + seen = old.seen; + 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; + acceleration = old.acceleration; + speed = old.speed; + height = old.height; + gps = new AltosGPS(old.gps); + new_gps = false; + companion = old.companion; + imu = old.imu; + mag = old.mag; + } + + public AltosRecord() { + version = 0; + seen = 0; + callsign = "N0CALL"; + serial = 0; + flight = 0; + rssi = 0; + status = 0; + state = AltosLib.ao_flight_startup; + tick = 0; + accel = MISSING; + pres = MISSING; + temp = MISSING; + batt = MISSING; + drogue = MISSING; + main = MISSING; + flight_accel = 0; + ground_accel = 0; + flight_vel = 0; + flight_pres = 0; + ground_pres = 0; + accel_plus_g = 0; + accel_minus_g = 0; + acceleration = MISSING; + speed = MISSING; + height = MISSING; + gps = new AltosGPS(); + new_gps = false; + companion = null; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java new file mode 100644 index 00000000..c8cc6cac --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java @@ -0,0 +1,38 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosRecordCompanion { + public final static int board_id_telescience = 0x0a; + public final static int MAX_CHANNELS = 12; + + public int tick; + public int board_id; + public int update_period; + public int channels; + public int[] companion_data; + + public AltosRecordCompanion(int in_channels) { + channels = in_channels; + if (channels < 0) + channels = 0; + if (channels > MAX_CHANNELS) + channels = MAX_CHANNELS; + companion_data = new int[channels]; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java new file mode 100644 index 00000000..ed1787ed --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; + +public abstract class AltosRecordIterable implements Iterable { + public abstract Iterator 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; }; +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java new file mode 100644 index 00000000..1585f9eb --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * Open an existing telemetry file and replay it in realtime + */ + +public class AltosReplayReader extends AltosFlightReader { + Iterator iterator; + File file; + + public AltosRecord read() { + if (iterator.hasNext()) + return iterator.next(); + return null; + } + + public void close (boolean interrupted) { + } + + public void update(AltosState state) throws InterruptedException { + /* 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)); + } + + public File backing_file() { return file; } + + public AltosReplayReader(Iterator in_iterator, File in_file) { + iterator = in_iterator; + file = in_file; + name = file.getName(); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosState.java b/altoslib/src/org/altusmetrum/AltosLib/AltosState.java new file mode 100644 index 00000000..0645e448 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosState.java @@ -0,0 +1,210 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* + * Track flight state from telemetry or eeprom data stream + */ + +package org.altusmetrum.AltosLib; + +public class AltosState { + public AltosRecord data; + + /* derived data */ + + public long report_time; + + public double time; + public double time_change; + public int tick; + + public int state; + public boolean landed; + public boolean ascent; /* going up? */ + public boolean boost; /* under power */ + + public double ground_altitude; + public double height; + public double speed; + public double acceleration; + public double battery; + public double temperature; + public double main_sense; + public double drogue_sense; + public double baro_speed; + + public double max_height; + public double max_acceleration; + public double max_speed; + public double max_baro_speed; + + public AltosGPS gps; + + public AltosIMU imu; + public AltosMag mag; + + public static final int MIN_PAD_SAMPLES = 10; + + public int npad; + public int ngps; + public int gps_waiting; + public boolean gps_ready; + + public AltosGreatCircle from_pad; + public double elevation; /* from pad */ + public double range; /* total distance */ + + public double gps_height; + + public int speak_tick; + public double speak_altitude; + + public void init (AltosRecord cur, AltosState prev_state) { + int i; + AltosRecord prev; + + data = cur; + + ground_altitude = data.ground_altitude(); + height = data.filtered_height(); + + report_time = System.currentTimeMillis(); + + acceleration = data.acceleration(); + speed = data.accel_speed(); + 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; + 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_speed = prev_state.max_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; + + /* compute barometric speed */ + + double height_change = height - prev_state.height; + if (data.speed != AltosRecord.MISSING) + baro_speed = data.speed; + else { + if (time_change > 0) + baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; + else + baro_speed = prev_state.baro_speed; + } + } else { + npad = 0; + ngps = 0; + gps = null; + baro_speed = 0; + time_change = 0; + } + + time = tick / 100.0; + + if (cur.new_gps && (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_idle)) { + + /* 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) { + /* 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; + } + ngps++; + } + } + + gps_waiting = MIN_PAD_SAMPLES - npad; + if (gps_waiting < 0) + gps_waiting = 0; + + gps_ready = gps_waiting == 0; + + ascent = (AltosLib.ao_flight_boost <= state && + state <= AltosLib.ao_flight_coast); + boost = (AltosLib.ao_flight_boost == state); + + /* Only look at accelerometer data under boost */ + if (boost && acceleration > max_acceleration) + max_acceleration = acceleration; + if (boost && speed > max_speed) + max_speed = speed; + if (boost && baro_speed > max_baro_speed) + max_baro_speed = baro_speed; + + if (height > max_height) + max_height = height; + if (data.gps != null) { + if (gps == null || !gps.locked || data.gps.locked) + gps = data.gps; + if (ngps > 0 && gps.locked) { + from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); + } + } + elevation = 0; + range = -1; + if (ngps > 0) { + gps_height = gps.alt - pad_alt; + if (from_pad != null) { + elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; + range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); + } + } else { + gps_height = 0; + } + } + + public AltosState(AltosRecord cur) { + init(cur, null); + } + + public AltosState (AltosRecord cur, AltosState prev) { + init(cur, prev); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java new file mode 100644 index 00000000..04abb1f3 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java @@ -0,0 +1,241 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * 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 + * + */ + +public 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); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java new file mode 100644 index 00000000..f4b4029f --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java @@ -0,0 +1,109 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosTelemetryIterable extends AltosRecordIterable { + TreeSet records; + + public Iterator iterator () { + return records.iterator(); + } + + 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; }; + + public AltosTelemetryIterable (FileInputStream input) { + boolean saw_boost = false; + int current_tick = 0; + int boost_tick = 0; + + AltosRecord previous = null; + records = new TreeSet (); + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) { + break; + } + try { + AltosRecord record = AltosTelemetry.parse(line, previous); + if (record == 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.accel != AltosRecord.MISSING) + has_accel = true; + if (record.gps != null) + has_gps = true; + if (record.main != AltosRecord.MISSING) + has_ignite = true; + if (previous != null && previous.tick != record.tick) + records.add(previous); + previous = record; + } catch (ParseException pe) { + System.out.printf("parse exception %s\n", pe.getMessage()); + } catch (AltosCRCException ce) { + } + } + } 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/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java new file mode 100644 index 00000000..003cb6a9 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryMap extends HashMap { + public boolean has(String key) { + return containsKey(key); + } + + public String get_string(String key) throws ParseException { + if (!has(key)) + throw new ParseException ("missing " + key, 0); + return (String) get(key); + } + + public String get_string(String key, String def) { + if (has(key)) + return get(key); + else + return def; + } + + public int get_int(String key) throws ParseException { + return AltosParse.parse_int(get_string(key)); + } + + public int get_int(String key, int def) throws ParseException { + if (has(key)) + return get_int(key); + else + return def; + } + + public double get_double(String key, double def, double scale) throws ParseException { + if (has(key)) + return get_int(key) * scale; + else + return def; + } + + public AltosTelemetryMap(String[] words, int start) { + for (int i = start; i < words.length - 1; i += 2) + put(words[i], words[i+1]); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java new file mode 100644 index 00000000..67ac1b65 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java @@ -0,0 +1,119 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosTelemetryReader extends AltosFlightReader { + AltosLink link; + AltosLog log; + AltosRecord previous; + double frequency; + int telemetry; + + LinkedBlockingQueue telem; + + public AltosRecord 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; + } + + public void flush() { + telem.clear(); + } + + public void close(boolean interrupted) { + link.remove_monitor(telem); + log.close(); + link.close(); + } + + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + link.set_radio_frequency(frequency); + } + + public boolean supports_telemetry(int telemetry) { + + try { + /* Version 1.0 or later firmware supports all telemetry formats */ + if (serial.config_data().compare_version("1.0") >= 0) + return true; + + /* Version 0.9 firmware only supports 0.9 telemetry */ + if (serial.config_data().compare_version("0.9") >= 0) { + if (telemetry == Altos.ao_telemetry_0_9) + return true; + else + return false; + } + + /* Version 0.8 firmware only supports 0.8 telemetry */ + if (telemetry == Altos.ao_telemetry_0_8) + return true; + else + return false; + } catch (InterruptedException ie) { + return true; + } catch (TimeoutException te) { + return true; + } + } + + public void save_frequency() { + AltosPreferences.set_frequency(link.serial, frequency); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + link.set_telemetry(telemetry); + } + + public void save_telemetry() { + AltosPreferences.set_telemetry(link.serial, telemetry); + } + + public void set_monitor(boolean monitor) { + link.set_monitor(monitor); + } + + public File backing_file() { + return log.file(); + } + + public AltosTelemetryReader (AltosLink in_link) + throws IOException, InterruptedException, TimeoutException { + link = in_link; + log = new AltosLog(link); + name = link.name; + previous = null; + telem = new LinkedBlockingQueue(); + frequency = AltosPreferences.frequency(link.serial); + set_frequency(frequency); + telemetry = AltosPreferences.telemetry(link.serial); + set_telemetry(telemetry); + link.add_monitor(telem); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java new file mode 100644 index 00000000..367c148d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +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; + + static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + int[] bytes; + try { + bytes = Altos.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 = Altos.int8(bytes, bytes.length - 3) / 2 - 74; + int status = Altos.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 Altos.ao_telemetry_standard_len + 4: + int type = Altos.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); + break; + case packet_type_location: + r = new AltosTelemetryRecordLocation(bytes); + break; + case packet_type_satellite: + r = new AltosTelemetryRecordSatellite(bytes); + break; + case packet_type_companion: + r = new AltosTelemetryRecordCompanion(bytes); + break; + default: + r = new AltosTelemetryRecordRaw(bytes); + break; + } + break; + case Altos.ao_telemetry_0_9_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + case Altos.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/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java new file mode 100644 index 00000000..6ad17244 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { + + AltosRecordCompanion companion; + + public AltosTelemetryRecordCompanion(int[] in_bytes) { + super(in_bytes); + + 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/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java new file mode 100644 index 00000000..25242edc --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { + int device_type; + int flight; + int config_major; + int config_minor; + int apogee_delay; + int main_deploy; + int flight_log_max; + String callsign; + String version; + + public AltosTelemetryRecordConfiguration(int[] in_bytes) { + super(in_bytes); + + device_type = uint8(5); + flight = uint16(6); + config_major = uint8(8); + config_minor = uint8(9); + apogee_delay = uint16(10); + main_deploy = uint16(12); + flight_log_max = uint16(14); + callsign = string(16, 8); + version = string(24, 8); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + 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; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java new file mode 100644 index 00000000..5e157a54 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordGeneral { + + 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 = AltosTelemetryRecordRaw.parse(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java new file mode 100644 index 00000000..8e3713cc --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java @@ -0,0 +1,521 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * 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 + * + */ + +public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { + /* + * 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"; + + AltosRecord record; + + 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 = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + record.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); + + /* 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); + + /* flight computer values */ + record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); + record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); + record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.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); + + if (map.has(AO_TELEM_GPS_STATE)) { + record.gps = new AltosGPS(map); + record.new_gps = true; + } + else + record.gps = null; + } + + private void parse_legacy(String[] words, int i) throws ParseException { + + AltosParse.word (words[i++], "CALL"); + record.callsign = words[i++]; + + AltosParse.word (words[i++], "SERIAL"); + record.serial = AltosParse.parse_int(words[i++]); + + if (record.version >= 2) { + AltosParse.word (words[i++], "FLIGHT"); + record.flight = AltosParse.parse_int(words[i++]); + } else + record.flight = 0; + + AltosParse.word(words[i++], "RSSI"); + record.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; + + AltosParse.word(words[i++], "STATUS"); + record.status = AltosParse.parse_hex(words[i++]); + + AltosParse.word(words[i++], "STATE"); + record.state = Altos.state(words[i++]); + + record.tick = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a:"); + record.accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "p:"); + record.pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "t:"); + record.temp = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "v:"); + record.batt = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "d:"); + record.drogue = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "m:"); + record.main = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fa:"); + record.flight_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "ga:"); + record.ground_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fv:"); + record.flight_vel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fp:"); + record.flight_pres = AltosParse.parse_int(words[i++]); + + /* Old TeleDongle code with kalman-reporting TeleMetrum code */ + if ((record.flight_vel & 0xffff0000) == 0x80000000) { + record.speed = ((short) record.flight_vel) / 16.0; + record.acceleration = record.flight_accel / 16.0; + record.height = record.flight_pres; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + record.flight_accel = AltosRecord.MISSING; + } + + AltosParse.word(words[i++], "gp:"); + record.ground_pres = AltosParse.parse_int(words[i++]); + + if (record.version >= 1) { + AltosParse.word(words[i++], "a+:"); + record.accel_plus_g = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a-:"); + record.accel_minus_g = AltosParse.parse_int(words[i++]); + } else { + record.accel_plus_g = record.ground_accel; + record.accel_minus_g = record.ground_accel + 530; + } + + record.gps = new AltosGPS(words, i, record.version); + record.new_gps = true; + } + + public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + record = new AltosRecord(); + + 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); + } + if (words[i].equals("CALL")) { + record.version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + record.version = AltosParse.parse_int(words[i++]); + } + + if (record.version < 4) + parse_legacy(words, i); + else + parse_v4(words, i); + } + + /* + * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that + */ + + int[] bytes; + int adjust; + + private int int8(int i) { + return AltosLib.int8(bytes, i + 1 + adjust); + } + private int uint8(int i) { + return AltosLib.uint8(bytes, i + 1 + adjust); + } + private int int16(int i) { + return AltosLib.int16(bytes, i + 1 + adjust); + } + private int uint16(int i) { + return AltosLib.uint16(bytes, i + 1 + adjust); + } + private int uint32(int i) { + return AltosLib.uint32(bytes, i + 1 + adjust); + } + private String string(int i, int l) { + return AltosLib.string(bytes, i + 1 + adjust, l); + } + + static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); + static final int AO_GPS_NUM_SAT_SHIFT = (0); + + static final int AO_GPS_VALID = (1 << 4); + static final int AO_GPS_RUNNING = (1 << 5); + 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 AltosRecord(); + + bytes = in_bytes; + record.version = 4; + adjust = 0; + + if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { + record.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); + + record.ground_accel = int16(7); + record.ground_pres = int16(15); + record.accel_plus_g = int16(17); + record.accel_minus_g = int16(19); + + if (uint16(11) == 0x8000) { + record.acceleration = int16(5); + record.speed = int16(9); + record.height = int16(13); + record.flight_accel = AltosRecord.MISSING; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + } else { + record.flight_accel = int16(5); + record.flight_vel = uint32(9); + record.flight_pres = int16(13); + record.acceleration = AltosRecord.MISSING; + record.speed = AltosRecord.MISSING; + record.height = AltosRecord.MISSING; + } + + record.gps = null; + + int gps_flags = uint8(41); + + if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { + record.gps = new AltosGPS(); + record.new_gps = true; + + record.seen |= record.seen_gps_time | record.seen_gps_lat | record.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); + + int n_tracking_reported = uint8(70); + if (n_tracking_reported > 12) + n_tracking_reported = 12; + int n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + if (uint8(71 + i*2) != 0) + n_tracking_actual++; + } + if (n_tracking_actual > 0) { + record.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); + } + } + } + + record.time = 0.0; + } + + public AltosRecord update_state(AltosRecord previous) { + return record; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java new file mode 100644 index 00000000..cddb773d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java @@ -0,0 +1,93 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { + int flags; + int altitude; + int latitude; + int longitude; + int year; + int month; + int day; + int hour; + int minute; + int second; + int pdop; + int hdop; + int vdop; + int mode; + int ground_speed; + int climb_rate; + int course; + + public AltosTelemetryRecordLocation(int[] in_bytes) { + super(in_bytes); + + flags = uint8(5); + altitude = int16(6); + latitude = uint32(8); + longitude = uint32(12); + year = uint8(16); + month = uint8(17); + day = uint8(18); + hour = uint8(19); + minute = uint8(20); + second = uint8(21); + pdop = uint8(22); + hdop = uint8(23); + vdop = uint8(24); + mode = uint8(25); + ground_speed = uint16(26); + climb_rate = int16(28); + course = uint8(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + 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.new_gps = true; + } + + return next; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java new file mode 100644 index 00000000..43d0f17a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java @@ -0,0 +1,77 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { + int[] bytes; + int serial; + int tick; + int type; + + 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 String string(int off, int l) { + return AltosLib.string(bytes, off + 1, l); + } + + public AltosTelemetryRecordRaw(int[] in_bytes) { + bytes = in_bytes; + serial = uint16(0); + tick = uint16(2); + type = uint8(4); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next; + if (previous != null) + next = new AltosRecord(previous); + else + next = new AltosRecord(); + next.serial = serial; + next.tick = tick; + return next; + } + + public long received_time() { + return received_time; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java new file mode 100644 index 00000000..2526afb6 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { + int channels; + AltosGPSSat[] sats; + + public AltosTelemetryRecordSatellite(int[] in_bytes) { + super(in_bytes); + + channels = uint8(5); + if (channels > 12) + channels = 12; + if (channels == 0) + sats = null; + else { + sats = new AltosGPSSat[channels]; + for (int i = 0; i < channels; i++) { + int svid = uint8(6 + i * 2 + 0); + int c_n_1 = uint8(6 + i * 2 + 1); + sats[i] = new AltosGPSSat(svid, c_n_1); + } + } + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.cc_gps_sat = sats; + + return next; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java new file mode 100644 index 00000000..cfaf90b0 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java @@ -0,0 +1,104 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { + int state; + int accel; + int pres; + int temp; + int v_batt; + int sense_d; + int sense_m; + + int acceleration; + int speed; + int height; + + int ground_accel; + int ground_pres; + int accel_plus_g; + int accel_minus_g; + + int rssi; + + public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { + super(in_bytes); + state = uint8(5); + + accel = int16(6); + pres = int16(8); + temp = int16(10); + v_batt = int16(12); + sense_d = int16(14); + sense_m = int16(16); + + acceleration = int16(18); + speed = int16(20); + height = int16(22); + + ground_pres = int16(24); + ground_accel = int16(26); + accel_plus_g = int16(28); + accel_minus_g = int16(30); + + rssi = in_rssi; + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + 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.acceleration = acceleration / 16.0; + next.speed = speed / 16.0; + next.height = height; + + next.ground_pres = ground_pres; + 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; + } + + next.rssi = rssi; + + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + return next; + } +} -- cgit v1.2.3 From a018724e40f2a4c0bae8b3d5c77bb90328ad4314 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 23 Feb 2012 11:15:23 +1300 Subject: Ignore generated altoslib files Signed-off-by: Keith Packard --- altosdroid/.gitignore | 3 +++ altoslib/.gitignore | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 altosdroid/.gitignore (limited to 'altoslib') diff --git a/altosdroid/.gitignore b/altosdroid/.gitignore new file mode 100644 index 00000000..1a6498b3 --- /dev/null +++ b/altosdroid/.gitignore @@ -0,0 +1,3 @@ +bin +gen +local.properties diff --git a/altoslib/.gitignore b/altoslib/.gitignore index ad2f8cbf..a71d076c 100644 --- a/altoslib/.gitignore +++ b/altoslib/.gitignore @@ -1 +1,3 @@ +bin classAltosLib.stamp +AltosLib.jar -- cgit v1.2.3 From 69e6df07976a56b49e07c242cd6e5b2cbd2a578d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 23 Feb 2012 17:00:48 +1300 Subject: Move altoslib sources to top dir No sense having them live deep in the file system. Signed-off-by: Keith Packard --- altoslib/AltosCRCException.java | 26 + altoslib/AltosConfigData.java | 184 ++++++++ altoslib/AltosConvert.java | 259 ++++++++++ altoslib/AltosEepromChunk.java | 102 ++++ altoslib/AltosEepromIterable.java | 475 +++++++++++++++++++ altoslib/AltosEepromLog.java | 100 ++++ altoslib/AltosEepromRecord.java | 139 ++++++ altoslib/AltosEepromTeleScience.java | 59 +++ altoslib/AltosFile.java | 44 ++ altoslib/AltosFlightReader.java | 49 ++ altoslib/AltosFrequency.java | 48 ++ altoslib/AltosGPS.java | 248 ++++++++++ altoslib/AltosGPSSat.java | 32 ++ altoslib/AltosGreatCircle.java | 101 ++++ altoslib/AltosLib.java | 348 ++++++++++++++ altoslib/AltosLine.java | 30 ++ altoslib/AltosLink.java | 238 ++++++++++ altoslib/AltosLog.java | 126 +++++ altoslib/AltosParse.java | 79 ++++ altoslib/AltosPreferences.java | 365 +++++++++++++++ altoslib/AltosRecord.java | 319 +++++++++++++ altoslib/AltosRecordCompanion.java | 38 ++ altoslib/AltosRecordIterable.java | 29 ++ altoslib/AltosReplayReader.java | 56 +++ altoslib/AltosState.java | 210 +++++++++ altoslib/AltosTelemetry.java | 241 ++++++++++ altoslib/AltosTelemetryIterable.java | 109 +++++ altoslib/AltosTelemetryMap.java | 63 +++ altoslib/AltosTelemetryReader.java | 119 +++++ altoslib/AltosTelemetryRecord.java | 126 +++++ altoslib/AltosTelemetryRecordCompanion.java | 52 ++ altoslib/AltosTelemetryRecordConfiguration.java | 64 +++ altoslib/AltosTelemetryRecordGeneral.java | 43 ++ altoslib/AltosTelemetryRecordLegacy.java | 521 +++++++++++++++++++++ altoslib/AltosTelemetryRecordLocation.java | 93 ++++ altoslib/AltosTelemetryRecordRaw.java | 77 +++ altoslib/AltosTelemetryRecordSatellite.java | 52 ++ altoslib/AltosTelemetryRecordSensor.java | 104 ++++ altoslib/Makefile.am | 2 +- .../altusmetrum/AltosLib/AltosCRCException.java | 26 - .../org/altusmetrum/AltosLib/AltosConfigData.java | 184 -------- .../src/org/altusmetrum/AltosLib/AltosConvert.java | 259 ---------- .../org/altusmetrum/AltosLib/AltosEepromChunk.java | 102 ---- .../altusmetrum/AltosLib/AltosEepromIterable.java | 475 ------------------- .../org/altusmetrum/AltosLib/AltosEepromLog.java | 100 ---- .../altusmetrum/AltosLib/AltosEepromRecord.java | 139 ------ .../AltosLib/AltosEepromTeleScience.java | 59 --- .../src/org/altusmetrum/AltosLib/AltosFile.java | 44 -- .../altusmetrum/AltosLib/AltosFlightReader.java | 49 -- .../org/altusmetrum/AltosLib/AltosFrequency.java | 48 -- .../src/org/altusmetrum/AltosLib/AltosGPS.java | 248 ---------- .../src/org/altusmetrum/AltosLib/AltosGPSSat.java | 32 -- .../org/altusmetrum/AltosLib/AltosGreatCircle.java | 101 ---- .../src/org/altusmetrum/AltosLib/AltosLib.java | 348 -------------- .../src/org/altusmetrum/AltosLib/AltosLine.java | 30 -- .../src/org/altusmetrum/AltosLib/AltosLink.java | 238 ---------- .../src/org/altusmetrum/AltosLib/AltosLog.java | 126 ----- .../src/org/altusmetrum/AltosLib/AltosParse.java | 79 ---- .../org/altusmetrum/AltosLib/AltosPreferences.java | 365 --------------- .../src/org/altusmetrum/AltosLib/AltosRecord.java | 319 ------------- .../altusmetrum/AltosLib/AltosRecordCompanion.java | 38 -- .../altusmetrum/AltosLib/AltosRecordIterable.java | 29 -- .../altusmetrum/AltosLib/AltosReplayReader.java | 56 --- .../src/org/altusmetrum/AltosLib/AltosState.java | 210 --------- .../org/altusmetrum/AltosLib/AltosTelemetry.java | 241 ---------- .../AltosLib/AltosTelemetryIterable.java | 109 ----- .../altusmetrum/AltosLib/AltosTelemetryMap.java | 63 --- .../altusmetrum/AltosLib/AltosTelemetryReader.java | 119 ----- .../altusmetrum/AltosLib/AltosTelemetryRecord.java | 126 ----- .../AltosLib/AltosTelemetryRecordCompanion.java | 52 -- .../AltosTelemetryRecordConfiguration.java | 64 --- .../AltosLib/AltosTelemetryRecordGeneral.java | 43 -- .../AltosLib/AltosTelemetryRecordLegacy.java | 521 --------------------- .../AltosLib/AltosTelemetryRecordLocation.java | 93 ---- .../AltosLib/AltosTelemetryRecordRaw.java | 77 --- .../AltosLib/AltosTelemetryRecordSatellite.java | 52 -- .../AltosLib/AltosTelemetryRecordSensor.java | 104 ---- 77 files changed, 5369 insertions(+), 5369 deletions(-) create mode 100644 altoslib/AltosCRCException.java create mode 100644 altoslib/AltosConfigData.java create mode 100644 altoslib/AltosConvert.java create mode 100644 altoslib/AltosEepromChunk.java create mode 100644 altoslib/AltosEepromIterable.java create mode 100644 altoslib/AltosEepromLog.java create mode 100644 altoslib/AltosEepromRecord.java create mode 100644 altoslib/AltosEepromTeleScience.java create mode 100644 altoslib/AltosFile.java create mode 100644 altoslib/AltosFlightReader.java create mode 100644 altoslib/AltosFrequency.java create mode 100644 altoslib/AltosGPS.java create mode 100644 altoslib/AltosGPSSat.java create mode 100644 altoslib/AltosGreatCircle.java create mode 100644 altoslib/AltosLib.java create mode 100644 altoslib/AltosLine.java create mode 100644 altoslib/AltosLink.java create mode 100644 altoslib/AltosLog.java create mode 100644 altoslib/AltosParse.java create mode 100644 altoslib/AltosPreferences.java create mode 100644 altoslib/AltosRecord.java create mode 100644 altoslib/AltosRecordCompanion.java create mode 100644 altoslib/AltosRecordIterable.java create mode 100644 altoslib/AltosReplayReader.java create mode 100644 altoslib/AltosState.java create mode 100644 altoslib/AltosTelemetry.java create mode 100644 altoslib/AltosTelemetryIterable.java create mode 100644 altoslib/AltosTelemetryMap.java create mode 100644 altoslib/AltosTelemetryReader.java create mode 100644 altoslib/AltosTelemetryRecord.java create mode 100644 altoslib/AltosTelemetryRecordCompanion.java create mode 100644 altoslib/AltosTelemetryRecordConfiguration.java create mode 100644 altoslib/AltosTelemetryRecordGeneral.java create mode 100644 altoslib/AltosTelemetryRecordLegacy.java create mode 100644 altoslib/AltosTelemetryRecordLocation.java create mode 100644 altoslib/AltosTelemetryRecordRaw.java create mode 100644 altoslib/AltosTelemetryRecordSatellite.java create mode 100644 altoslib/AltosTelemetryRecordSensor.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFile.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLib.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLine.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLink.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLog.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosParse.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosState.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java delete mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java (limited to 'altoslib') diff --git a/altoslib/AltosCRCException.java b/altoslib/AltosCRCException.java new file mode 100644 index 00000000..101c5363 --- /dev/null +++ b/altoslib/AltosCRCException.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosCRCException extends Exception { + public int rssi; + + public AltosCRCException (int in_rssi) { + rssi = in_rssi; + } +} diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java new file mode 100644 index 00000000..4ad4e58a --- /dev/null +++ b/altoslib/AltosConfigData.java @@ -0,0 +1,184 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; + +public class AltosConfigData implements Iterable { + + /* Version information */ + public String manufacturer; + public String product; + public String version; + public int log_format; + public int serial; + + /* Strings returned */ + public LinkedList lines; + + /* Config information */ + public int config_major; + public int config_minor; + public int main_deploy; + public int apogee_delay; + public int radio_channel; + public int radio_setting; + public int radio_frequency; + public String callsign; + public int accel_cal_plus, accel_cal_minus; + public int radio_calibration; + public int flight_log_max; + public int ignite_mode; + public int stored_flight; + public int storage_size; + public int storage_erase_unit; + + public static String get_string(String line, String label) throws ParseException { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + return quoted; + } + throw new ParseException("mismatch", 0); + } + + public static int get_int(String line, String label) throws NumberFormatException, ParseException { + if (line.startsWith(label)) { + String tail = line.substring(label.length()).trim(); + String[] tokens = tail.split("\\s+"); + if (tokens.length > 0) + return Integer.parseInt(tokens[0]); + } + throw new ParseException("mismatch", 0); + } + + public Iterator iterator() { + return lines.iterator(); + } + + public int log_available() { + switch (log_format) { + case AltosLib.AO_LOG_FORMAT_TINY: + if (stored_flight == 0) + return 1; + return 0; + default: + if (flight_log_max <= 0) + return 1; + int log_space = storage_size - storage_erase_unit; + int log_used = stored_flight * flight_log_max; + + if (log_used >= log_space) + return 0; + return (log_space - log_used) / flight_log_max; + } + } + + int[] parse_version(String v) { + String[] parts = v.split("\\."); + int r[] = new int[parts.length]; + + for (int i = 0; i < parts.length; i++) { + try { + r[i] = Altos.fromdec(parts[i]); + } catch (NumberFormatException n) { + r[i] = 0; + } + } + + return r; + } + + public int compare_version(String other) { + int[] me = parse_version(version); + int[] them = parse_version(other); + + int l = Math.min(me.length, them.length); + + for (int i = 0; i < l; i++) { + int d = me[i] - them[i]; + if (d != 0) + return d; + } + if (me.length > l) + return 1; + if (them.length > l) + return -1; + return 0; + } + + public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("c s\np\nf\nl\nv\n"); + lines = new LinkedList(); + radio_setting = 0; + radio_frequency = 0; + stored_flight = 0; + for (;;) { + String line = link.get_reply(); + if (line == null) + throw new TimeoutException(); + if (line.contains("Syntax error")) + continue; + lines.add(line); + try { serial = get_int(line, "serial-number"); } catch (Exception e) {} + try { log_format = get_int(line, "log-format"); } catch (Exception e) {} + try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} + try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} + try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} + try { + radio_frequency = get_int(line, "Frequency:"); + if (radio_frequency < 0) + radio_frequency = 434550; + } catch (Exception e) {} + try { + if (line.startsWith("Accel cal")) { + String[] bits = line.split("\\s+"); + if (bits.length >= 6) { + accel_cal_plus = Integer.parseInt(bits[3]); + accel_cal_minus = Integer.parseInt(bits[5]); + } + } + } catch (Exception e) {} + try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} + try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} + try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} + try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} + try { version = get_string(line,"software-version"); } catch (Exception e) {} + try { product = get_string(line,"product"); } catch (Exception e) {} + + try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} + try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} + try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} + + /* signals the end of the version info */ + if (line.startsWith("software-version")) + break; + } + } + +} \ No newline at end of file diff --git a/altoslib/AltosConvert.java b/altoslib/AltosConvert.java new file mode 100644 index 00000000..3527b575 --- /dev/null +++ b/altoslib/AltosConvert.java @@ -0,0 +1,259 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* + * Sensor data conversion functions + */ +package org.altusmetrum.AltosLib; + +public class AltosConvert { + /* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= Math.pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * Math.pow(base, exponent); + } + + return pressure; + } + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ + public static double + pressure_to_altitude(double pressure) + { + + double next_base_temperature = LAYER0_BASE_TEMPERATURE; + double next_base_pressure = LAYER0_BASE_PRESSURE; + + double altitude; + double base_pressure; + double base_temperature; + double base; /* base for function to determine base pressure of next layer */ + double exponent; /* exponent for function to determine base pressure + of next layer */ + double coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= Math.pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * Math.log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (Math.pow(base, exponent) - 1); + } + + return altitude; + } + + public static double + cc_battery_to_voltage(double battery) + { + return battery / 32767.0 * 5.0; + } + + public static double + cc_ignitor_to_voltage(double ignite) + { + return ignite / 32767 * 15.0; + } + + public static double radio_to_frequency(int freq, int setting, int cal, int channel) { + double f; + + if (freq > 0) + f = freq / 1000.0; + else { + if (setting <= 0) + setting = cal; + f = 434.550 * setting / cal; + /* Round to nearest 50KHz */ + f = Math.floor (20.0 * f + 0.5) / 20.0; + } + return f + channel * 0.100; + } + + public static int radio_frequency_to_setting(double frequency, int cal) { + double set = frequency / 434.550 * cal; + + return (int) Math.floor (set + 0.5); + } + + public static int radio_frequency_to_channel(double frequency) { + int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); + + if (channel < 0) + channel = 0; + if (channel > 9) + channel = 9; + return channel; + } + + public static double radio_channel_to_frequency(int channel) { + return 434.550 + channel * 0.100; + } + + public static int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + public static double meters_to_feet(double meters) { + return meters * (100 / (2.54 * 12)); + } + + public static double meters_to_mach(double meters) { + return meters / 343; /* something close to mach at usual rocket sites */ + } + + public static double meters_to_g(double meters) { + return meters / 9.80665; + } + + public static int checksum(int[] data, int start, int length) { + int csum = 0x5a; + for (int i = 0; i < length; i++) + csum += data[i + start]; + return csum & 0xff; + } +} diff --git a/altoslib/AltosEepromChunk.java b/altoslib/AltosEepromChunk.java new file mode 100644 index 00000000..6d889723 --- /dev/null +++ b/altoslib/AltosEepromChunk.java @@ -0,0 +1,102 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public class AltosEepromChunk { + + public static final int chunk_size = 256; + public static final int per_line = 8; + + public int data[]; + public int address; + public ParseException parse_exception = null; + + int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + public int data(int offset) { + return data[offset]; + } + + public int data16(int offset) { + return data[offset] | (data[offset + 1] << 8); + } + + public int data32(int offset) { + return data[offset] | (data[offset + 1] << 8) | + (data[offset+2] << 16) | (data[offset+3] << 24); + } + + public boolean erased(int start, int len) { + for (int i = 0; i < len; i++) + if (data[start+i] != 0xff) + return false; + return true; + } + + public AltosEepromChunk(AltosLink link, int block, boolean flush) + throws TimeoutException, InterruptedException { + + int offset; + + data = new int[chunk_size]; + address = block * chunk_size; + if (flush) + link.flush_input(); + link.printf("e %x\n", block); + + for (offset = 0; offset < chunk_size; offset += per_line) { + try { + String line = link.get_reply(5000); + + if (line == null) + throw new TimeoutException(); + + int[] values = ParseHex(line); + + if (values == null || values.length != per_line + 1) + throw new ParseException(String.format("invalid line %s", line), 0); + if (values[0] != offset) + throw new ParseException(String.format("data address out of sync at 0x%x", + address + offset), 0); + for (int i = 0; i < per_line; i++) + data[offset + i] = values[1 + i]; + } catch (ParseException pe) { + for (int i = 0; i < per_line; i++) + data[offset + i] = 0xff; + if (parse_exception == null) + parse_exception = pe; + } + } + } +} \ No newline at end of file diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java new file mode 100644 index 00000000..f1397c7b --- /dev/null +++ b/altoslib/AltosEepromIterable.java @@ -0,0 +1,475 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * 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 { + + 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; + } +} + +public class AltosEepromIterable 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; + + AltosEepromRecord flight_record; + AltosEepromRecord gps_date_record; + + TreeSet records; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + int sensor_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { + state.tick = record.tick; + switch (record.cmd) { + case AltosLib.AO_LOG_FLIGHT: + eeprom.seen |= 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 & 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_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 |= seen_sensor; + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.temp = record.a; + state.batt = record.b; + eeprom.seen |= seen_temp_volt; + break; + case AltosLib.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= 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; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; + state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> + AltosLib.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; + has_gps = true; + break; + case AltosLib.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_ALT: + 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; + state.gps.add_sat(svid, c_n0); + } + break; + case AltosLib.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case AltosLib.AO_LOG_CONFIG_VERSION: + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + break; + case AltosLib.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case AltosLib.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case AltosLib.AO_LOG_RADIO_CAL: + break; + case AltosLib.AO_LOG_MANUFACTURER: + break; + case AltosLib.AO_LOG_PRODUCT: + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + break; + } + state.seen |= eeprom.seen; + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedRecord record = null; + AltosRecord state = new AltosRecord(); + 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) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + AltosOrderedRecord record = iterator.next(); + switch (record.cmd) { + case AltosLib.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", record.data); + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", record.a); + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case AltosLib.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case AltosLib.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case AltosLib.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; + case AltosLib.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case AltosLib.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + case Altos.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); + flags |= AltosLib.AO_GPS_RUNNING; + flags |= AltosLib.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromIterable (FileInputStream input) { + records = new TreeSet(); + + AltosOrderedRecord last_gps_time = null; + + int index = 0; + int prev_tick = 0; + boolean prev_tick_valid = false; + boolean missing_time = false; + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == AltosLib.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == AltosLib.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedRecord old = iterator.next(); + if (old.cmd == AltosLib.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == AltosLib.AO_LOG_STATE && + record.a == AltosLib.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altoslib/AltosEepromLog.java b/altoslib/AltosEepromLog.java new file mode 100644 index 00000000..7fca4bd9 --- /dev/null +++ b/altoslib/AltosEepromLog.java @@ -0,0 +1,100 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +/* + * Extract a bit of information from an eeprom-stored flight log. + */ + +public class AltosEepromLog { + public int serial; + public boolean has_flight; + public int flight; + public int start_block; + public int end_block; + + public int year, month, day; + + public boolean selected; + + public AltosEepromLog(AltosConfigData config_data, + AltosLink link, + int in_flight, int in_start_block, + int in_end_block) + throws InterruptedException, TimeoutException { + + int block; + boolean has_date = false; + + flight = in_flight; + if (flight != 0) + has_flight = true; + start_block = in_start_block; + end_block = in_end_block; + serial = config_data.serial; + + /* + * Select all flights for download + */ + selected = true; + + /* + * Look in TeleMetrum log data for date + */ + if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN || + config_data.log_format == AltosLib.AO_LOG_FORMAT_FULL) + { + /* + * Only look in the first two blocks so that this + * process doesn't take a long time + */ + if (in_end_block > in_start_block + 2) + in_end_block = in_start_block + 2; + + 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 < eechunk.chunk_size; i += AltosEepromRecord.record_length) { + try { + AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + + if (r.cmd == AltosLib.AO_LOG_FLIGHT) { + flight = r.b; + has_flight = true; + } + if (r.cmd == AltosLib.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + has_date = true; + } + } catch (ParseException pe) { + } + } + if (has_date && has_flight) + break; + } + } + } +} diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java new file mode 100644 index 00000000..1e845f46 --- /dev/null +++ b/altoslib/AltosEepromRecord.java @@ -0,0 +1,139 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +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/AltosEepromTeleScience.java b/altoslib/AltosEepromTeleScience.java new file mode 100644 index 00000000..1758fa34 --- /dev/null +++ b/altoslib/AltosEepromTeleScience.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +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/AltosFile.java b/altoslib/AltosFile.java new file mode 100644 index 00000000..d2e4f2f7 --- /dev/null +++ b/altoslib/AltosFile.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +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) { + super (AltosPreferences.logdir(), + String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", + year, month, day, serial, flight, extension)); + } + + public AltosFile(int serial, int flight, String extension) { + this(Calendar.getInstance().get(Calendar.YEAR), + Calendar.getInstance().get(Calendar.MONTH) + 1, + Calendar.getInstance().get(Calendar.DAY_OF_MONTH), + serial, + flight, + extension); + } + + public AltosFile(AltosRecord telem) { + this(telem.serial, telem.flight, "telem"); + } +} diff --git a/altoslib/AltosFlightReader.java b/altoslib/AltosFlightReader.java new file mode 100644 index 00000000..3fdea469 --- /dev/null +++ b/altoslib/AltosFlightReader.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosFlightReader { + public String name; + + public int serial; + + public void init() { } + + public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } + + public void close(boolean interrupted) { } + + public void set_frequency(double frequency) throws InterruptedException, TimeoutException { } + + public void save_frequency() { } + + public void set_telemetry(int telemetry) { } + + public void save_telemetry() { } + + public void update(AltosState state) throws InterruptedException { } + + public boolean supports_telemetry(int telemetry) { return false; } + + public File backing_file() { return null; } +} diff --git a/altoslib/AltosFrequency.java b/altoslib/AltosFrequency.java new file mode 100644 index 00000000..f08ff116 --- /dev/null +++ b/altoslib/AltosFrequency.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosFrequency { + public double frequency; + public String description; + + public String toString() { + return String.format("%7.3f MHz %-20s", + frequency, description); + } + + public String toShortString() { + return String.format("%7.3f MHz %s", + frequency, description); + } + + public boolean close(double f) { + double diff = Math.abs(frequency - f); + + return diff < 0.010; + } + + public AltosFrequency(double f, String d) { + frequency = f; + description = d; + } +} \ No newline at end of file diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java new file mode 100644 index 00000000..f078a469 --- /dev/null +++ b/altoslib/AltosGPS.java @@ -0,0 +1,248 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; + +public class AltosGPS { + + public final static int MISSING = AltosRecord.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 int year; + public int month; + public int day; + public int hour; + public int minute; + public int second; + + public double ground_speed; /* m/s */ + public int course; /* degrees */ + public double climb_rate; /* m/s */ + public double hdop; /* unitless */ + public double vdop; /* unitless */ + public int h_error; /* m */ + public int v_error; /* m */ + + public AltosGPSSat[] cc_gps_sat; /* tracking data */ + + public void ParseGPSDate(String date) throws ParseException { + String[] ymd = date.split("-"); + if (ymd.length != 3) + throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); + year = AltosParse.parse_int(ymd[0]); + month = AltosParse.parse_int(ymd[1]); + day = AltosParse.parse_int(ymd[2]); + } + + public void ParseGPSTime(String time) throws ParseException { + String[] hms = time.split(":"); + if (hms.length != 3) + throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); + hour = AltosParse.parse_int(hms[0]); + minute = AltosParse.parse_int(hms[1]); + second = AltosParse.parse_int(hms[2]); + } + + public void ClearGPSTime() { + year = month = day = 0; + hour = minute = second = 0; + } + + public AltosGPS(AltosTelemetryMap map) throws ParseException { + String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, + AltosTelemetry.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)) { + 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); + 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)) { + connected = true; + locked = false; + } else { + connected = false; + locked = false; + } + } + + public AltosGPS(String[] words, int i, int version) throws ParseException { + AltosParse.word(words[i++], "GPS"); + nsat = AltosParse.parse_int(words[i++]); + AltosParse.word(words[i++], "sat"); + + connected = false; + locked = false; + lat = lon = 0; + alt = 0; + ClearGPSTime(); + if ((words[i]).equals("unlocked")) { + connected = true; + i++; + } else if ((words[i]).equals("not-connected")) { + i++; + } else if (words.length >= 40) { + locked = true; + connected = true; + + if (version > 1) + ParseGPSDate(words[i++]); + else + year = month = day = 0; + ParseGPSTime(words[i++]); + lat = AltosParse.parse_coord(words[i++]); + lon = AltosParse.parse_coord(words[i++]); + alt = AltosParse.parse_int(words[i++]); + if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { + ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); + course = AltosParse.parse_int(words[i++]); + climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); + hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); + h_error = AltosParse.parse_int(words[i++]); + v_error = AltosParse.parse_int(words[i++]); + } + } else { + i++; + } + if (i < words.length) { + AltosParse.word(words[i++], "SAT"); + int tracking_channels = 0; + if (words[i].equals("not-connected")) + tracking_channels = 0; + else + tracking_channels = AltosParse.parse_int(words[i]); + i++; + cc_gps_sat = new AltosGPSSat[tracking_channels]; + for (int chan = 0; chan < tracking_channels; chan++) { + cc_gps_sat[chan] = new AltosGPSSat(); + cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); + /* Older versions included SiRF status bits */ + if (version < 2) + i++; + cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); + } + } else + cc_gps_sat = new AltosGPSSat[0]; + } + + public void set_latitude(int in_lat) { + lat = in_lat / 10.0e7; + } + + public void set_longitude(int in_lon) { + lon = in_lon / 10.0e7; + } + + public void set_time(int hour, int minute, int second) { + hour = hour; + minute = minute; + second = second; + } + + public void set_date(int year, int month, int day) { + year = year; + month = month; + day = day; + } + + public void set_flags(int flags) { + flags = flags; + } + + public void set_altitude(int altitude) { + altitude = altitude; + } + + public void add_sat(int svid, int c_n0) { + if (cc_gps_sat == null) { + cc_gps_sat = new AltosGPSSat[1]; + } else { + AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; + for (int i = 0; i < cc_gps_sat.length; i++) + new_gps_sat[i] = cc_gps_sat[i]; + cc_gps_sat = new_gps_sat; + } + AltosGPSSat sat = new AltosGPSSat(); + sat.svid = svid; + sat.c_n0 = c_n0; + cc_gps_sat[cc_gps_sat.length - 1] = sat; + } + + public AltosGPS() { + ClearGPSTime(); + cc_gps_sat = null; + } + + public AltosGPS(AltosGPS old) { + nsat = old.nsat; + locked = old.locked; + connected = old.connected; + lat = old.lat; /* degrees (+N -S) */ + lon = old.lon; /* degrees (+E -W) */ + alt = old.alt; /* m */ + year = old.year; + month = old.month; + day = old.day; + hour = old.hour; + minute = old.minute; + second = old.second; + + ground_speed = old.ground_speed; /* m/s */ + course = old.course; /* degrees */ + climb_rate = old.climb_rate; /* m/s */ + hdop = old.hdop; /* unitless? */ + h_error = old.h_error; /* m */ + v_error = old.v_error; /* m */ + + if (old.cc_gps_sat != null) { + cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; + for (int i = 0; i < old.cc_gps_sat.length; i++) { + cc_gps_sat[i] = new AltosGPSSat(); + cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; + cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; + } + } + } +} diff --git a/altoslib/AltosGPSSat.java b/altoslib/AltosGPSSat.java new file mode 100644 index 00000000..faa1ec8d --- /dev/null +++ b/altoslib/AltosGPSSat.java @@ -0,0 +1,32 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosGPSSat { + public int svid; + public int c_n0; + + public AltosGPSSat(int s, int c) { + svid = s; + c_n0= c; + } + + public AltosGPSSat() { + } +} + diff --git a/altoslib/AltosGreatCircle.java b/altoslib/AltosGreatCircle.java new file mode 100644 index 00000000..76b71859 --- /dev/null +++ b/altoslib/AltosGreatCircle.java @@ -0,0 +1,101 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.Math; + +public class AltosGreatCircle { + public double distance; + public double bearing; + + double sqr(double a) { return a * a; } + + static final double rad = Math.PI / 180; + static final double earth_radius = 6371.2 * 1000; /* in meters */ + + public static final int BEARING_LONG = 0; + public static final int BEARING_SHORT = 1; + public static final int BEARING_VOICE = 2; + + public String bearing_words(int length) { + String [][] bearing_string = { + { + "North", "North North East", "North East", "East North East", + "East", "East South East", "South East", "South South East", + "South", "South South West", "South West", "West South West", + "West", "West North West", "North West", "North North West" + }, { + "N", "NNE", "NE", "ENE", + "E", "ESE", "SE", "SSE", + "S", "SSW", "SW", "WSW", + "W", "WNW", "NW", "NNW" + }, { + "north", "nor nor east", "north east", "east nor east", + "east", "east sow east", "south east", "sow sow east", + "south", "sow sow west", "south west", "west sow west", + "west", "west nor west", "north west", "nor nor west " + } + }; + return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; + } + + public AltosGreatCircle (double start_lat, double start_lon, + double end_lat, double end_lon) + { + double lat1 = rad * start_lat; + double lon1 = rad * -start_lon; + double lat2 = rad * end_lat; + double lon2 = rad * -end_lon; + + double d_lon = lon2 - lon1; + + /* From http://en.wikipedia.org/wiki/Great-circle_distance */ + double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + + sqr(Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); + double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); + double d = Math.atan2(vdn,vdd); + double course; + + if (Math.cos(lat1) < 1e-20) { + if (lat1 > 0) + course = Math.PI; + else + course = -Math.PI; + } else { + if (d < 1e-10) + course = 0; + else + course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / + (Math.sin(d)*Math.cos(lat1))); + if (Math.sin(lon2-lon1) > 0) + course = 2 * Math.PI-course; + } + distance = d * earth_radius; + bearing = course * 180/Math.PI; + } + + public AltosGreatCircle(AltosGPS start, AltosGPS end) { + this(start.lat, start.lon, end.lat, end.lon); + } + + public AltosGreatCircle() { + distance = 0; + bearing = 0; + } +} diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java new file mode 100644 index 00000000..2921d040 --- /dev/null +++ b/altoslib/AltosLib.java @@ -0,0 +1,348 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.awt.*; +import java.util.*; +import java.text.*; +import java.nio.charset.Charset; + +public class AltosLib { + /* EEProm command letters */ + public static final int AO_LOG_FLIGHT = 'F'; + public static final int AO_LOG_SENSOR = 'A'; + 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_TIME = 'G'; + public static final int AO_LOG_GPS_LAT = 'N'; + public static final int AO_LOG_GPS_LON = 'W'; + public static final int AO_LOG_GPS_ALT = 'H'; + public static final int AO_LOG_GPS_SAT = 'V'; + public static final int AO_LOG_GPS_DATE = 'Y'; + public static final int AO_LOG_PRESSURE = 'P'; + + /* Added for header fields in eeprom files */ + public static final int AO_LOG_CONFIG_VERSION = 1000; + public static final int AO_LOG_MAIN_DEPLOY = 1001; + public static final int AO_LOG_APOGEE_DELAY = 1002; + public static final int AO_LOG_RADIO_CHANNEL = 1003; + public static final int AO_LOG_CALLSIGN = 1004; + public static final int AO_LOG_ACCEL_CAL = 1005; + public static final int AO_LOG_RADIO_CAL = 1006; + public static final int AO_LOG_MAX_FLIGHT_LOG = 1007; + public static final int AO_LOG_MANUFACTURER = 2000; + public static final int AO_LOG_PRODUCT = 2001; + public static final int AO_LOG_SERIAL_NUMBER = 2002; + public static final int AO_LOG_LOG_FORMAT = 2003; + public static final int AO_LOG_SOFTWARE_VERSION = 9999; + + /* Added to flag invalid records */ + public static final int AO_LOG_INVALID = -1; + + /* Flight state numbers and names */ + public static final int ao_flight_startup = 0; + public static final int ao_flight_idle = 1; + public static final int ao_flight_pad = 2; + public static final int ao_flight_boost = 3; + public static final int ao_flight_fast = 4; + public static final int ao_flight_coast = 5; + public static final int ao_flight_drogue = 6; + public static final int ao_flight_main = 7; + public static final int ao_flight_landed = 8; + public static final int ao_flight_invalid = 9; + + /* Telemetry modes */ + public static final int ao_telemetry_off = 0; + public static final int ao_telemetry_min = 1; + public static final int ao_telemetry_standard = 1; + public static final int ao_telemetry_0_9 = 2; + public static final int ao_telemetry_0_8 = 3; + public static final int ao_telemetry_max = 3; + + public static final String[] ao_telemetry_name = { + "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" + }; + + public static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; + + public static final int ao_telemetry_standard_len = 32; + public static final int ao_telemetry_0_9_len = 95; + public static final int ao_telemetry_0_8_len = 94; + + public static final int[] ao_telemetry_len = { + 0, 32, 95, 94 + }; + + public static HashMap string_to_state = new HashMap(); + + public static boolean map_initialized = false; + + public static void initialize_map() + { + string_to_state.put("startup", ao_flight_startup); + string_to_state.put("idle", ao_flight_idle); + string_to_state.put("pad", ao_flight_pad); + string_to_state.put("boost", ao_flight_boost); + string_to_state.put("fast", ao_flight_fast); + string_to_state.put("coast", ao_flight_coast); + string_to_state.put("drogue", ao_flight_drogue); + string_to_state.put("apogee", ao_flight_coast); + string_to_state.put("main", ao_flight_main); + string_to_state.put("landed", ao_flight_landed); + string_to_state.put("invalid", ao_flight_invalid); + map_initialized = true; + } + + public static int telemetry_len(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_len[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String telemetry_name(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_name[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String[] state_to_string = { + "startup", + "idle", + "pad", + "boost", + "fast", + "coast", + "drogue", + "main", + "landed", + "invalid", + }; + + public static String[] state_to_string_capital = { + "Startup", + "Idle", + "Pad", + "Boost", + "Fast", + "Coast", + "Drogue", + "Main", + "Landed", + "Invalid", + }; + + public static int state(String state) { + if (!map_initialized) + initialize_map(); + if (string_to_state.containsKey(state)) + return string_to_state.get(state); + return ao_flight_invalid; + } + + public static String state_name(int state) { + if (state < 0 || state_to_string.length <= state) + return "invalid"; + return state_to_string[state]; + } + + public static final int AO_GPS_VALID = (1 << 4); + public static final int AO_GPS_RUNNING = (1 << 5); + public static final int AO_GPS_DATE_VALID = (1 << 6); + public static final int AO_GPS_NUM_SAT_SHIFT = 0; + public static final int AO_GPS_NUM_SAT_MASK = 0xf; + + public static final int AO_LOG_FORMAT_UNKNOWN = 0; + public static final int AO_LOG_FORMAT_FULL = 1; + public static final int AO_LOG_FORMAT_TINY = 2; + 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_NONE = 127; + + public static boolean isspace(int c) { + switch (c) { + case ' ': + case '\t': + return true; + } + return false; + } + + public static boolean ishex(int c) { + if ('0' <= c && c <= '9') + return true; + if ('a' <= c && c <= 'f') + return true; + if ('A' <= c && c <= 'F') + return true; + return false; + } + + public static boolean ishex(String s) { + for (int i = 0; i < s.length(); i++) + if (!ishex(s.charAt(i))) + return false; + return true; + } + + public static int fromhex(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return c - 'a' + 10; + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + return -1; + } + + public static int fromhex(String s) throws NumberFormatException { + int c, v = 0; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (!ishex(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + return v; + } + v = v * 16 + fromhex(c); + } + return v; + } + + public static boolean isdec(int c) { + if ('0' <= c && c <= '9') + return true; + return false; + } + + public static boolean isdec(String s) { + for (int i = 0; i < s.length(); i++) + if (!isdec(s.charAt(i))) + return false; + return true; + } + + public static int fromdec(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + return -1; + } + + public static int int8(int[] bytes, int i) { + return (int) (byte) bytes[i]; + } + + public static int uint8(int[] bytes, int i) { + return bytes[i]; + } + + public static int int16(int[] bytes, int i) { + return (int) (short) (bytes[i] + (bytes[i+1] << 8)); + } + + public static int uint16(int[] bytes, int i) { + return bytes[i] + (bytes[i+1] << 8); + } + + public static int uint32(int[] bytes, int i) { + return bytes[i] + + (bytes[i+1] << 8) + + (bytes[i+2] << 16) + + (bytes[i+3] << 24); + } + + public static final Charset unicode_set = Charset.forName("UTF-8"); + + public static String string(int[] bytes, int s, int l) { + if (s + l > bytes.length) { + if (s > bytes.length) { + s = bytes.length; + l = 0; + } else { + l = bytes.length - s; + } + } + + int i; + for (i = l - 1; i >= 0; i--) + if (bytes[s+i] != 0) + break; + + l = i + 1; + byte[] b = new byte[l]; + + for (i = 0; i < l; i++) + b[i] = (byte) bytes[s+i]; + String n = new String(b, unicode_set); + return n; + } + + public static int hexbyte(String s, int i) { + int c0, c1; + + if (s.length() < i + 2) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + c0 = s.charAt(i); + if (!ishex(c0)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); + c1 = s.charAt(i+1); + if (!ishex(c1)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); + return fromhex(c0) * 16 + fromhex(c1); + } + + public static int[] hexbytes(String s) { + int n; + int[] r; + int i; + + if ((s.length() & 1) != 0) + throw new NumberFormatException(String.format("invalid line \"%s\"", s)); + n = s.length() / 2; + r = new int[n]; + for (i = 0; i < n; i++) + r[i] = hexbyte(s, i * 2); + return r; + } + + public static int fromdec(String s) throws NumberFormatException { + int c, v = 0; + int sign = 1; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (i == 0 && c == '-') { + sign = -1; + } else if (!isdec(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid number \"%s\"", s)); + return v; + } else + v = v * 10 + fromdec(c); + } + return v * sign; + } + + public static String replace_extension(String input, String extension) { + int dot = input.lastIndexOf("."); + if (dot > 0) + input = input.substring(0,dot); + return input.concat(extension); + } +} diff --git a/altoslib/AltosLine.java b/altoslib/AltosLine.java new file mode 100644 index 00000000..5627795a --- /dev/null +++ b/altoslib/AltosLine.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosLine { + public String line; + + public AltosLine() { + line = null; + } + + public AltosLine(String s) { + line = s; + } +} \ No newline at end of file diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java new file mode 100644 index 00000000..9b80e916 --- /dev/null +++ b/altoslib/AltosLink.java @@ -0,0 +1,238 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import java.text.*; + +public abstract class AltosLink { + public abstract void print(String data); + public abstract void close(); + + public static boolean debug = false; + public static void set_debug(boolean in_debug) { debug = in_debug; } + LinkedList pending_output = new LinkedList(); + + public LinkedList> monitors = new LinkedList> ();; + public LinkedBlockingQueue reply_queue = new LinkedBlockingQueue(); + + public void add_monitor(LinkedBlockingQueue q) { + set_monitor(true); + monitors.add(q); + } + + public void remove_monitor(LinkedBlockingQueue q) { + monitors.remove(q); + if (monitors.isEmpty()) + set_monitor(false); + } + + public void printf(String format, Object ... arguments) { + String line = String.format(format, arguments); + if (debug) + pending_output.add(line); + print(line); + } + + public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { + flush_output(); + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) + return line.line; + return null; + } + + public String get_reply(int timeout) throws InterruptedException { + try { + return get_reply_no_dialog(timeout); + } catch (TimeoutException te) { + return null; + } + } + + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + + public void add_telem(AltosLine line) throws InterruptedException { + for (int e = 0; e < monitors.size(); e++) { + LinkedBlockingQueue q = monitors.get(e); + q.put(line); + } + } + + public void add_reply(AltosLine line) throws InterruptedException { + reply_queue.put (line); + } + + public void add_string(String line) throws InterruptedException { + if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { + add_telem(new AltosLine(line)); + } else { + add_reply(new AltosLine(line)); + } + } + + public void add_bytes(byte[] bytes, int len) throws InterruptedException { + String line; + try { + line = new String(bytes, 0, len, "UTF-8"); + } catch (UnsupportedEncodingException ue) { + line = ""; + for (int i = 0; i < len; i++) + line = line + bytes[i]; + } + if (debug) + System.out.printf("\t\t\t\t\t%s\n", line); + add_string(line); + } + + public void flush_output() { + for (String s : pending_output) + System.out.print(s); + pending_output.clear(); + } + + public void flush_input(int timeout) throws InterruptedException { + flush_output(); + boolean got_some; + + do { + Thread.sleep(timeout); + got_some = !reply_queue.isEmpty(); + reply_queue.clear(); + } while (got_some); + } + + + public void flush_input() throws InterruptedException { + flush_input(100); + } + + + /* + * Various command-level operations on + * the link + */ + public boolean monitor_mode = false; + public int telemetry = AltosLib.ao_telemetry_standard; + public double frequency; + AltosConfigData config_data; + + private int telemetry_len() { + return AltosLib.telemetry_len(telemetry); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + if (monitor_mode) + printf("m 0\nm %x\n", telemetry_len()); + flush_output(); + } + + public void set_monitor(boolean monitor) { + monitor_mode = monitor; + if (monitor) + printf("m %x\n", telemetry_len()); + else + printf("m 0\n"); + flush_output(); + } + + private void set_channel(int channel) { + if (monitor_mode) + printf("m 0\nc r %d\nm %x\n", + channel, telemetry_len()); + else + printf("c r %d\n", channel); + flush_output(); + } + + private void set_radio_setting(int setting) { + if (monitor_mode) + printf("m 0\nc R %d\nm %x\n", + setting, telemetry_len()); + else + printf("c R %d\n", setting); + flush_output(); + } + + public void set_radio_frequency(double frequency, + boolean has_setting, + int cal) { + if (debug) + System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); + if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + + public AltosConfigData config_data() throws InterruptedException, TimeoutException { + if (config_data == null) + config_data = new AltosConfigData(this); + return config_data; + } + + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + + public void set_callsign(String callsign) { + printf ("c c %s\n", callsign); + flush_output(); + } + + public boolean remote; + public int serial; + public String name; + + public void start_remote() throws TimeoutException, InterruptedException { + if (debug) + System.out.printf("start remote %7.3f\n", frequency); + if (frequency == 0.0) + frequency = AltosPreferences.frequency(serial); + set_radio_frequency(frequency); + set_callsign(AltosPreferences.callsign()); + printf("p\nE 0\n"); + flush_input(); + remote = true; + } + + public void stop_remote() throws InterruptedException { + if (debug) + System.out.printf("stop remote\n"); + try { + flush_input(); + } finally { + printf ("~\n"); + flush_output(); + } + remote = false; + } + + public AltosLink() { + } +} diff --git a/altoslib/AltosLog.java b/altoslib/AltosLog.java new file mode 100644 index 00000000..08c45ca8 --- /dev/null +++ b/altoslib/AltosLog.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.text.ParseException; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * This creates a thread to capture telemetry data and write it to + * a log file + */ +class AltosLog implements Runnable { + + LinkedBlockingQueue input_queue; + LinkedBlockingQueue pending_queue; + int serial; + int flight; + FileWriter log_file; + Thread log_thread; + AltosFile file; + + private void close_log_file() { + if (log_file != null) { + try { + log_file.close(); + } catch (IOException io) { + } + log_file = null; + } + } + + void close() { + close_log_file(); + if (log_thread != null) { + log_thread.interrupt(); + log_thread = null; + } + } + + File file() { + return file; + } + + boolean open (AltosRecord telem) throws IOException { + AltosFile a = new AltosFile(telem); + + System.out.printf("open %s\n", a.toString()); + 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) { + } + } + log_file.flush(); + file = a; + } + return log_file != null; + } + + public void run () { + try { + AltosRecord previous = null; + for (;;) { + AltosLine line = input_queue.take(); + if (line.line == null) + continue; + try { + AltosRecord telem = AltosTelemetry.parse(line.line, previous); + if (telem.serial != 0 && telem.flight != 0 && + (telem.serial != serial || telem.flight != flight || log_file == null)) + { + close_log_file(); + serial = telem.serial; + flight = telem.flight; + open(telem); + } + previous = telem; + } catch (ParseException pe) { + } catch (AltosCRCException ce) { + } + if (log_file != null) { + log_file.write(line.line); + log_file.write('\n'); + log_file.flush(); + } else + pending_queue.put(line.line); + } + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + close(); + } + + public AltosLog (AltosLink link) { + pending_queue = new LinkedBlockingQueue (); + input_queue = new LinkedBlockingQueue (); + link.add_monitor(input_queue); + serial = -1; + flight = -1; + log_file = null; + log_thread = new Thread(this); + log_thread.start(); + } +} diff --git a/altoslib/AltosParse.java b/altoslib/AltosParse.java new file mode 100644 index 00000000..7d832f1a --- /dev/null +++ b/altoslib/AltosParse.java @@ -0,0 +1,79 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.text.*; +import java.lang.*; + +public class AltosParse { + public static boolean isdigit(char c) { + return '0' <= c && c <= '9'; + } + + public static int parse_int(String v) throws ParseException { + try { + return AltosLib.fromdec(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing int " + v, 0); + } + } + + public static int parse_hex(String v) throws ParseException { + try { + return AltosLib.fromhex(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing hex " + v, 0); + } + } + + public static double parse_double(String v) throws ParseException { + try { + return Double.parseDouble(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing double " + v, 0); + } + } + + public static double parse_coord(String coord) throws ParseException { + String[] dsf = coord.split("\\D+"); + + if (dsf.length != 3) { + throw new ParseException("error parsing coord " + coord, 0); + } + int deg = parse_int(dsf[0]); + int min = parse_int(dsf[1]); + int frac = parse_int(dsf[2]); + + double r = deg + (min + frac / 10000.0) / 60.0; + if (coord.endsWith("S") || coord.endsWith("W")) + r = -r; + return r; + } + + public static String strip_suffix(String v, String suffix) { + if (v.endsWith(suffix)) + return v.substring(0, v.length() - suffix.length()); + return v; + } + + public static void word(String v, String m) throws ParseException { + if (!v.equals(m)) { + throw new ParseException("error matching '" + v + "' '" + m + "'", 0); + } + } +} diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java new file mode 100644 index 00000000..43c7088d --- /dev/null +++ b/altoslib/AltosPreferences.java @@ -0,0 +1,365 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.awt.Component; +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; + +public class AltosPreferences { + public static Preferences preferences; + + /* logdir preference name */ + public final static String logdirPreference = "LOGDIR"; + + /* channel preference name */ + public final static String channelPreferenceFormat = "CHANNEL-%d"; + + /* frequency preference name */ + public final static String frequencyPreferenceFormat = "FREQUENCY-%d"; + + /* telemetry format preference name */ + public final static String telemetryPreferenceFormat = "TELEMETRY-%d"; + + /* voice preference name */ + public final static String voicePreference = "VOICE"; + + /* callsign preference name */ + public final static String callsignPreference = "CALLSIGN"; + + /* firmware directory preference name */ + public final static String firmwaredirPreference = "FIRMWARE"; + + /* serial debug preference name */ + public final static String serialDebugPreference = "SERIAL-DEBUG"; + + /* scanning telemetry preferences name */ + public final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; + + /* Launcher serial preference name */ + public final static String launcherSerialPreference = "LAUNCHER-SERIAL"; + + /* Launcher channel preference name */ + public final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; + + /* Default logdir is ~/TeleMetrum */ + public final static String logdirName = "TeleMetrum"; + + /* Log directory */ + public static File logdir; + + /* Map directory -- hangs of logdir */ + public static File mapdir; + + /* Frequency (map serial to frequency) */ + public static Hashtable frequencies; + + /* Telemetry (map serial to telemetry format) */ + public static Hashtable telemetries; + + /* Voice preference */ + public static boolean voice; + + /* Callsign preference */ + public static String callsign; + + /* Firmware directory */ + public static File firmwaredir; + + /* Scanning telemetry */ + public static int scanning_telemetry; + + /* List of frequencies */ + public final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; + public static AltosFrequency[] common_frequencies; + + public final static String frequency_count = "COUNT"; + public final static String frequency_format = "FREQUENCY-%d"; + public final static String description_format = "DESCRIPTION-%d"; + + public static AltosFrequency[] load_common_frequencies() { + AltosFrequency[] frequencies = null; + boolean existing = false; + try { + existing = preferences.nodeExists(common_frequencies_node_name); + } catch (BackingStoreException be) { + existing = false; + } + if (existing) { + Preferences node = preferences.node(common_frequencies_node_name); + int count = node.getInt(frequency_count, 0); + + frequencies = new AltosFrequency[count]; + for (int i = 0; i < count; i++) { + double frequency; + String description; + + frequency = node.getDouble(String.format(frequency_format, i), 0.0); + description = node.get(String.format(description_format, i), null); + frequencies[i] = new AltosFrequency(frequency, description); + } + } else { + frequencies = new AltosFrequency[10]; + for (int i = 0; i < 10; i++) { + frequencies[i] = new AltosFrequency(434.550 + i * .1, + String.format("Channel %d", i)); + } + } + return frequencies; + } + + public static void save_common_frequencies(AltosFrequency[] frequencies) { + Preferences node = preferences.node(common_frequencies_node_name); + + node.putInt(frequency_count, frequencies.length); + for (int i = 0; i < frequencies.length; i++) { + node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); + node.put(String.format(description_format, i), frequencies[i].description); + } + } + public static int launcher_serial; + + public static int launcher_channel; + + public static void init() { + preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); + + /* Initialize logdir from preferences */ + String logdir_string = preferences.get(logdirPreference, null); + if (logdir_string != null) + logdir = new File(logdir_string); + else { + /* Use the file system view default directory */ + logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); + if (!logdir.exists()) + logdir.mkdirs(); + } + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + + frequencies = new Hashtable(); + + telemetries = new Hashtable(); + + voice = preferences.getBoolean(voicePreference, true); + + callsign = preferences.get(callsignPreference,"N0CALL"); + + scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << AltosLib.ao_telemetry_standard)); + + launcher_serial = preferences.getInt(launcherSerialPreference, 0); + + launcher_channel = preferences.getInt(launcherChannelPreference, 0); + + String firmwaredir_string = preferences.get(firmwaredirPreference, null); + if (firmwaredir_string != null) + firmwaredir = new File(firmwaredir_string); + else + firmwaredir = null; + + common_frequencies = load_common_frequencies(); + + } + + static { init(); } + + public static void flush_preferences() { + try { + preferences.flush(); + } catch (BackingStoreException ee) { +/* + if (component != null) + JOptionPane.showMessageDialog(component, + preferences.absolutePath(), + "Cannot save prefernces", + JOptionPane.ERROR_MESSAGE); + else +*/ + System.err.printf("Cannot save preferences\n"); + } + } + + public static void set_logdir(File new_logdir) { + logdir = new_logdir; + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + synchronized (preferences) { + preferences.put(logdirPreference, logdir.getPath()); + flush_preferences(); + } + } + + public static File logdir() { + return logdir; + } + + public static File mapdir() { + return mapdir; + } + + public static void set_frequency(int serial, double new_frequency) { + frequencies.put(serial, new_frequency); + synchronized (preferences) { + preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); + flush_preferences(); + } + } + + public static double frequency(int serial) { + if (frequencies.containsKey(serial)) + return frequencies.get(serial); + double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); + if (frequency == 0.0) { + int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); + frequency = AltosConvert.radio_channel_to_frequency(channel); + } + frequencies.put(serial, frequency); + return frequency; + } + + public static void set_telemetry(int serial, int new_telemetry) { + telemetries.put(serial, new_telemetry); + synchronized (preferences) { + preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); + flush_preferences(); + } + } + + public static int telemetry(int serial) { + if (telemetries.containsKey(serial)) + return telemetries.get(serial); + int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), + AltosLib.ao_telemetry_standard); + telemetries.put(serial, telemetry); + return telemetry; + } + + public static void set_scanning_telemetry(int new_scanning_telemetry) { + scanning_telemetry = new_scanning_telemetry; + synchronized (preferences) { + preferences.putInt(scanningTelemetryPreference, scanning_telemetry); + flush_preferences(); + } + } + + public static int scanning_telemetry() { + return scanning_telemetry; + } + + public static void set_voice(boolean new_voice) { + voice = new_voice; + synchronized (preferences) { + preferences.putBoolean(voicePreference, voice); + flush_preferences(); + } + } + + public static boolean voice() { + return voice; + } + + public static void set_callsign(String new_callsign) { + callsign = new_callsign; + synchronized(preferences) { + preferences.put(callsignPreference, callsign); + flush_preferences(); + } + } + + public static String callsign() { + return callsign; + } + + public static void set_firmwaredir(File new_firmwaredir) { + firmwaredir = new_firmwaredir; + synchronized (preferences) { + preferences.put(firmwaredirPreference, firmwaredir.getPath()); + flush_preferences(); + } + } + + public static File firmwaredir() { + return firmwaredir; + } + + public static void set_launcher_serial(int new_launcher_serial) { + launcher_serial = new_launcher_serial; + System.out.printf("set launcher serial to %d\n", new_launcher_serial); + synchronized (preferences) { + preferences.putInt(launcherSerialPreference, launcher_serial); + flush_preferences(); + } + } + + public static int launcher_serial() { + return launcher_serial; + } + + public static void set_launcher_channel(int new_launcher_channel) { + launcher_channel = new_launcher_channel; + System.out.printf("set launcher channel to %d\n", new_launcher_channel); + synchronized (preferences) { + preferences.putInt(launcherChannelPreference, launcher_channel); + flush_preferences(); + } + } + + public static int launcher_channel() { + return launcher_channel; + } + + public static Preferences bt_devices() { + return preferences.node("bt_devices"); + } + + public static AltosFrequency[] common_frequencies() { + return common_frequencies; + } + + public static void set_common_frequencies(AltosFrequency[] frequencies) { + common_frequencies = frequencies; + synchronized(preferences) { + save_common_frequencies(frequencies); + flush_preferences(); + } + } + + public static void add_common_frequency(AltosFrequency frequency) { + AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; + int i; + + for (i = 0; i < common_frequencies.length; i++) { + if (frequency.frequency == common_frequencies[i].frequency) + return; + if (frequency.frequency < common_frequencies[i].frequency) + break; + new_frequencies[i] = common_frequencies[i]; + } + new_frequencies[i] = frequency; + for (; i < common_frequencies.length; i++) + new_frequencies[i+1] = common_frequencies[i]; + set_common_frequencies(new_frequencies); + } +} diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java new file mode 100644 index 00000000..e4915af0 --- /dev/null +++ b/altoslib/AltosRecord.java @@ -0,0 +1,319 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; +import java.io.*; + +public class AltosRecord implements Comparable { + public final static int MISSING = 0x7fffffff; + + 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 int version; + public String callsign; + public int serial; + public int flight; + public int rssi; + public int status; + public int state; + public int tick; + + 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 double acceleration; + public double speed; + public double height; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + public AltosGPS gps; + public boolean new_gps; + + public AltosIMU imu; + public AltosMag mag; + + 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; + +>>>>>>> 5a249bc... altosui: Complete split out of separate java library + /* + * 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 + */ + + public static final double counts_per_kPa = 27 * 2047 / 3300; + public static final double counts_at_101_3kPa = 1674.0; + + public static double + barometer_to_pressure(double count) + { + return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; + } + + public double raw_pressure() { + if (pres == MISSING) + return MISSING; + return barometer_to_pressure(pres); + } + + public double filtered_pressure() { + if (flight_pres == MISSING) + return MISSING; + return barometer_to_pressure(flight_pres); + } + + public double ground_pressure() { + if (ground_pres == MISSING) + return MISSING; + return barometer_to_pressure(ground_pres); + } + + public double raw_altitude() { + double p = raw_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 filtered_altitude() { + if (height != MISSING && ground_pres != MISSING) + return height + ground_altitude(); + + double p = filtered_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double filtered_height() { + if (height != MISSING) + return height; + + double f = filtered_altitude(); + double g = ground_altitude(); + if (f == MISSING || g == MISSING) + return MISSING; + return f - g; + } + + public double raw_height() { + double r = raw_altitude(); + double g = ground_altitude(); + + if (r == MISSING || g == MISSING) + return height; + return r - g; + } + + 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 + */ + + public 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); + } + + public 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 (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + if (speed != MISSING) + return speed; + if (flight_vel == MISSING) + return MISSING; + return flight_vel / (accel_counts_per_mss() * 100.0); + } + + public String state() { + return AltosLib.state_name(state); + } + + public static String gets(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') { + return line; + } + line = line + (char) c; + } + return null; + } + + public int compareTo(AltosRecord o) { + return tick - o.tick; + } + + public AltosRecord(AltosRecord old) { + version = old.version; + seen = old.seen; + 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; + acceleration = old.acceleration; + speed = old.speed; + height = old.height; + gps = new AltosGPS(old.gps); + new_gps = false; + companion = old.companion; + imu = old.imu; + mag = old.mag; + } + + public AltosRecord() { + version = 0; + seen = 0; + callsign = "N0CALL"; + serial = 0; + flight = 0; + rssi = 0; + status = 0; + state = AltosLib.ao_flight_startup; + tick = 0; + accel = MISSING; + pres = MISSING; + temp = MISSING; + batt = MISSING; + drogue = MISSING; + main = MISSING; + flight_accel = 0; + ground_accel = 0; + flight_vel = 0; + flight_pres = 0; + ground_pres = 0; + accel_plus_g = 0; + accel_minus_g = 0; + acceleration = MISSING; + speed = MISSING; + height = MISSING; + gps = new AltosGPS(); + new_gps = false; + companion = null; + } +} diff --git a/altoslib/AltosRecordCompanion.java b/altoslib/AltosRecordCompanion.java new file mode 100644 index 00000000..c8cc6cac --- /dev/null +++ b/altoslib/AltosRecordCompanion.java @@ -0,0 +1,38 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosRecordCompanion { + public final static int board_id_telescience = 0x0a; + public final static int MAX_CHANNELS = 12; + + public int tick; + public int board_id; + public int update_period; + public int channels; + public int[] companion_data; + + public AltosRecordCompanion(int in_channels) { + channels = in_channels; + if (channels < 0) + channels = 0; + if (channels > MAX_CHANNELS) + channels = MAX_CHANNELS; + companion_data = new int[channels]; + } +} diff --git a/altoslib/AltosRecordIterable.java b/altoslib/AltosRecordIterable.java new file mode 100644 index 00000000..ed1787ed --- /dev/null +++ b/altoslib/AltosRecordIterable.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; + +public abstract class AltosRecordIterable implements Iterable { + public abstract Iterator 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; }; +} diff --git a/altoslib/AltosReplayReader.java b/altoslib/AltosReplayReader.java new file mode 100644 index 00000000..1585f9eb --- /dev/null +++ b/altoslib/AltosReplayReader.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * Open an existing telemetry file and replay it in realtime + */ + +public class AltosReplayReader extends AltosFlightReader { + Iterator iterator; + File file; + + public AltosRecord read() { + if (iterator.hasNext()) + return iterator.next(); + return null; + } + + public void close (boolean interrupted) { + } + + public void update(AltosState state) throws InterruptedException { + /* 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)); + } + + public File backing_file() { return file; } + + public AltosReplayReader(Iterator in_iterator, File in_file) { + iterator = in_iterator; + file = in_file; + name = file.getName(); + } +} diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java new file mode 100644 index 00000000..0645e448 --- /dev/null +++ b/altoslib/AltosState.java @@ -0,0 +1,210 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* + * Track flight state from telemetry or eeprom data stream + */ + +package org.altusmetrum.AltosLib; + +public class AltosState { + public AltosRecord data; + + /* derived data */ + + public long report_time; + + public double time; + public double time_change; + public int tick; + + public int state; + public boolean landed; + public boolean ascent; /* going up? */ + public boolean boost; /* under power */ + + public double ground_altitude; + public double height; + public double speed; + public double acceleration; + public double battery; + public double temperature; + public double main_sense; + public double drogue_sense; + public double baro_speed; + + public double max_height; + public double max_acceleration; + public double max_speed; + public double max_baro_speed; + + public AltosGPS gps; + + public AltosIMU imu; + public AltosMag mag; + + public static final int MIN_PAD_SAMPLES = 10; + + public int npad; + public int ngps; + public int gps_waiting; + public boolean gps_ready; + + public AltosGreatCircle from_pad; + public double elevation; /* from pad */ + public double range; /* total distance */ + + public double gps_height; + + public int speak_tick; + public double speak_altitude; + + public void init (AltosRecord cur, AltosState prev_state) { + int i; + AltosRecord prev; + + data = cur; + + ground_altitude = data.ground_altitude(); + height = data.filtered_height(); + + report_time = System.currentTimeMillis(); + + acceleration = data.acceleration(); + speed = data.accel_speed(); + 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; + 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_speed = prev_state.max_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; + + /* compute barometric speed */ + + double height_change = height - prev_state.height; + if (data.speed != AltosRecord.MISSING) + baro_speed = data.speed; + else { + if (time_change > 0) + baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; + else + baro_speed = prev_state.baro_speed; + } + } else { + npad = 0; + ngps = 0; + gps = null; + baro_speed = 0; + time_change = 0; + } + + time = tick / 100.0; + + if (cur.new_gps && (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_idle)) { + + /* 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) { + /* 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; + } + ngps++; + } + } + + gps_waiting = MIN_PAD_SAMPLES - npad; + if (gps_waiting < 0) + gps_waiting = 0; + + gps_ready = gps_waiting == 0; + + ascent = (AltosLib.ao_flight_boost <= state && + state <= AltosLib.ao_flight_coast); + boost = (AltosLib.ao_flight_boost == state); + + /* Only look at accelerometer data under boost */ + if (boost && acceleration > max_acceleration) + max_acceleration = acceleration; + if (boost && speed > max_speed) + max_speed = speed; + if (boost && baro_speed > max_baro_speed) + max_baro_speed = baro_speed; + + if (height > max_height) + max_height = height; + if (data.gps != null) { + if (gps == null || !gps.locked || data.gps.locked) + gps = data.gps; + if (ngps > 0 && gps.locked) { + from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); + } + } + elevation = 0; + range = -1; + if (ngps > 0) { + gps_height = gps.alt - pad_alt; + if (from_pad != null) { + elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; + range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); + } + } else { + gps_height = 0; + } + } + + public AltosState(AltosRecord cur) { + init(cur, null); + } + + public AltosState (AltosRecord cur, AltosState prev) { + init(cur, prev); + } +} diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java new file mode 100644 index 00000000..04abb1f3 --- /dev/null +++ b/altoslib/AltosTelemetry.java @@ -0,0 +1,241 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * 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 + * + */ + +public 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); + } +} diff --git a/altoslib/AltosTelemetryIterable.java b/altoslib/AltosTelemetryIterable.java new file mode 100644 index 00000000..f4b4029f --- /dev/null +++ b/altoslib/AltosTelemetryIterable.java @@ -0,0 +1,109 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosTelemetryIterable extends AltosRecordIterable { + TreeSet records; + + public Iterator iterator () { + return records.iterator(); + } + + 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; }; + + public AltosTelemetryIterable (FileInputStream input) { + boolean saw_boost = false; + int current_tick = 0; + int boost_tick = 0; + + AltosRecord previous = null; + records = new TreeSet (); + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) { + break; + } + try { + AltosRecord record = AltosTelemetry.parse(line, previous); + if (record == 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.accel != AltosRecord.MISSING) + has_accel = true; + if (record.gps != null) + has_gps = true; + if (record.main != AltosRecord.MISSING) + has_ignite = true; + if (previous != null && previous.tick != record.tick) + records.add(previous); + previous = record; + } catch (ParseException pe) { + System.out.printf("parse exception %s\n", pe.getMessage()); + } catch (AltosCRCException ce) { + } + } + } 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/AltosTelemetryMap.java b/altoslib/AltosTelemetryMap.java new file mode 100644 index 00000000..003cb6a9 --- /dev/null +++ b/altoslib/AltosTelemetryMap.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryMap extends HashMap { + public boolean has(String key) { + return containsKey(key); + } + + public String get_string(String key) throws ParseException { + if (!has(key)) + throw new ParseException ("missing " + key, 0); + return (String) get(key); + } + + public String get_string(String key, String def) { + if (has(key)) + return get(key); + else + return def; + } + + public int get_int(String key) throws ParseException { + return AltosParse.parse_int(get_string(key)); + } + + public int get_int(String key, int def) throws ParseException { + if (has(key)) + return get_int(key); + else + return def; + } + + public double get_double(String key, double def, double scale) throws ParseException { + if (has(key)) + return get_int(key) * scale; + else + return def; + } + + public AltosTelemetryMap(String[] words, int start) { + for (int i = start; i < words.length - 1; i += 2) + put(words[i], words[i+1]); + } +} diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java new file mode 100644 index 00000000..67ac1b65 --- /dev/null +++ b/altoslib/AltosTelemetryReader.java @@ -0,0 +1,119 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosTelemetryReader extends AltosFlightReader { + AltosLink link; + AltosLog log; + AltosRecord previous; + double frequency; + int telemetry; + + LinkedBlockingQueue telem; + + public AltosRecord 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; + } + + public void flush() { + telem.clear(); + } + + public void close(boolean interrupted) { + link.remove_monitor(telem); + log.close(); + link.close(); + } + + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + link.set_radio_frequency(frequency); + } + + public boolean supports_telemetry(int telemetry) { + + try { + /* Version 1.0 or later firmware supports all telemetry formats */ + if (serial.config_data().compare_version("1.0") >= 0) + return true; + + /* Version 0.9 firmware only supports 0.9 telemetry */ + if (serial.config_data().compare_version("0.9") >= 0) { + if (telemetry == Altos.ao_telemetry_0_9) + return true; + else + return false; + } + + /* Version 0.8 firmware only supports 0.8 telemetry */ + if (telemetry == Altos.ao_telemetry_0_8) + return true; + else + return false; + } catch (InterruptedException ie) { + return true; + } catch (TimeoutException te) { + return true; + } + } + + public void save_frequency() { + AltosPreferences.set_frequency(link.serial, frequency); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + link.set_telemetry(telemetry); + } + + public void save_telemetry() { + AltosPreferences.set_telemetry(link.serial, telemetry); + } + + public void set_monitor(boolean monitor) { + link.set_monitor(monitor); + } + + public File backing_file() { + return log.file(); + } + + public AltosTelemetryReader (AltosLink in_link) + throws IOException, InterruptedException, TimeoutException { + link = in_link; + log = new AltosLog(link); + name = link.name; + previous = null; + telem = new LinkedBlockingQueue(); + frequency = AltosPreferences.frequency(link.serial); + set_frequency(frequency); + telemetry = AltosPreferences.telemetry(link.serial); + set_telemetry(telemetry); + link.add_monitor(telem); + } +} diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java new file mode 100644 index 00000000..367c148d --- /dev/null +++ b/altoslib/AltosTelemetryRecord.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +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; + + static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + int[] bytes; + try { + bytes = Altos.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 = Altos.int8(bytes, bytes.length - 3) / 2 - 74; + int status = Altos.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 Altos.ao_telemetry_standard_len + 4: + int type = Altos.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); + break; + case packet_type_location: + r = new AltosTelemetryRecordLocation(bytes); + break; + case packet_type_satellite: + r = new AltosTelemetryRecordSatellite(bytes); + break; + case packet_type_companion: + r = new AltosTelemetryRecordCompanion(bytes); + break; + default: + r = new AltosTelemetryRecordRaw(bytes); + break; + } + break; + case Altos.ao_telemetry_0_9_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + case Altos.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 new file mode 100644 index 00000000..6ad17244 --- /dev/null +++ b/altoslib/AltosTelemetryRecordCompanion.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { + + AltosRecordCompanion companion; + + public AltosTelemetryRecordCompanion(int[] in_bytes) { + super(in_bytes); + + 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/AltosTelemetryRecordConfiguration.java b/altoslib/AltosTelemetryRecordConfiguration.java new file mode 100644 index 00000000..25242edc --- /dev/null +++ b/altoslib/AltosTelemetryRecordConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { + int device_type; + int flight; + int config_major; + int config_minor; + int apogee_delay; + int main_deploy; + int flight_log_max; + String callsign; + String version; + + public AltosTelemetryRecordConfiguration(int[] in_bytes) { + super(in_bytes); + + device_type = uint8(5); + flight = uint16(6); + config_major = uint8(8); + config_minor = uint8(9); + apogee_delay = uint16(10); + main_deploy = uint16(12); + flight_log_max = uint16(14); + callsign = string(16, 8); + version = string(24, 8); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + 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; + } +} diff --git a/altoslib/AltosTelemetryRecordGeneral.java b/altoslib/AltosTelemetryRecordGeneral.java new file mode 100644 index 00000000..5e157a54 --- /dev/null +++ b/altoslib/AltosTelemetryRecordGeneral.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordGeneral { + + 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 = AltosTelemetryRecordRaw.parse(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } +} diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java new file mode 100644 index 00000000..8e3713cc --- /dev/null +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -0,0 +1,521 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * 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 + * + */ + +public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { + /* + * 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"; + + AltosRecord record; + + 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 = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + record.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); + + /* 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); + + /* flight computer values */ + record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); + record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); + record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.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); + + if (map.has(AO_TELEM_GPS_STATE)) { + record.gps = new AltosGPS(map); + record.new_gps = true; + } + else + record.gps = null; + } + + private void parse_legacy(String[] words, int i) throws ParseException { + + AltosParse.word (words[i++], "CALL"); + record.callsign = words[i++]; + + AltosParse.word (words[i++], "SERIAL"); + record.serial = AltosParse.parse_int(words[i++]); + + if (record.version >= 2) { + AltosParse.word (words[i++], "FLIGHT"); + record.flight = AltosParse.parse_int(words[i++]); + } else + record.flight = 0; + + AltosParse.word(words[i++], "RSSI"); + record.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; + + AltosParse.word(words[i++], "STATUS"); + record.status = AltosParse.parse_hex(words[i++]); + + AltosParse.word(words[i++], "STATE"); + record.state = Altos.state(words[i++]); + + record.tick = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a:"); + record.accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "p:"); + record.pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "t:"); + record.temp = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "v:"); + record.batt = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "d:"); + record.drogue = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "m:"); + record.main = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fa:"); + record.flight_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "ga:"); + record.ground_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fv:"); + record.flight_vel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fp:"); + record.flight_pres = AltosParse.parse_int(words[i++]); + + /* Old TeleDongle code with kalman-reporting TeleMetrum code */ + if ((record.flight_vel & 0xffff0000) == 0x80000000) { + record.speed = ((short) record.flight_vel) / 16.0; + record.acceleration = record.flight_accel / 16.0; + record.height = record.flight_pres; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + record.flight_accel = AltosRecord.MISSING; + } + + AltosParse.word(words[i++], "gp:"); + record.ground_pres = AltosParse.parse_int(words[i++]); + + if (record.version >= 1) { + AltosParse.word(words[i++], "a+:"); + record.accel_plus_g = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a-:"); + record.accel_minus_g = AltosParse.parse_int(words[i++]); + } else { + record.accel_plus_g = record.ground_accel; + record.accel_minus_g = record.ground_accel + 530; + } + + record.gps = new AltosGPS(words, i, record.version); + record.new_gps = true; + } + + public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + record = new AltosRecord(); + + 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); + } + if (words[i].equals("CALL")) { + record.version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + record.version = AltosParse.parse_int(words[i++]); + } + + if (record.version < 4) + parse_legacy(words, i); + else + parse_v4(words, i); + } + + /* + * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that + */ + + int[] bytes; + int adjust; + + private int int8(int i) { + return AltosLib.int8(bytes, i + 1 + adjust); + } + private int uint8(int i) { + return AltosLib.uint8(bytes, i + 1 + adjust); + } + private int int16(int i) { + return AltosLib.int16(bytes, i + 1 + adjust); + } + private int uint16(int i) { + return AltosLib.uint16(bytes, i + 1 + adjust); + } + private int uint32(int i) { + return AltosLib.uint32(bytes, i + 1 + adjust); + } + private String string(int i, int l) { + return AltosLib.string(bytes, i + 1 + adjust, l); + } + + static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); + static final int AO_GPS_NUM_SAT_SHIFT = (0); + + static final int AO_GPS_VALID = (1 << 4); + static final int AO_GPS_RUNNING = (1 << 5); + 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 AltosRecord(); + + bytes = in_bytes; + record.version = 4; + adjust = 0; + + if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { + record.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); + + record.ground_accel = int16(7); + record.ground_pres = int16(15); + record.accel_plus_g = int16(17); + record.accel_minus_g = int16(19); + + if (uint16(11) == 0x8000) { + record.acceleration = int16(5); + record.speed = int16(9); + record.height = int16(13); + record.flight_accel = AltosRecord.MISSING; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + } else { + record.flight_accel = int16(5); + record.flight_vel = uint32(9); + record.flight_pres = int16(13); + record.acceleration = AltosRecord.MISSING; + record.speed = AltosRecord.MISSING; + record.height = AltosRecord.MISSING; + } + + record.gps = null; + + int gps_flags = uint8(41); + + if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { + record.gps = new AltosGPS(); + record.new_gps = true; + + record.seen |= record.seen_gps_time | record.seen_gps_lat | record.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); + + int n_tracking_reported = uint8(70); + if (n_tracking_reported > 12) + n_tracking_reported = 12; + int n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + if (uint8(71 + i*2) != 0) + n_tracking_actual++; + } + if (n_tracking_actual > 0) { + record.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); + } + } + } + + record.time = 0.0; + } + + public AltosRecord update_state(AltosRecord previous) { + return record; + } +} diff --git a/altoslib/AltosTelemetryRecordLocation.java b/altoslib/AltosTelemetryRecordLocation.java new file mode 100644 index 00000000..cddb773d --- /dev/null +++ b/altoslib/AltosTelemetryRecordLocation.java @@ -0,0 +1,93 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { + int flags; + int altitude; + int latitude; + int longitude; + int year; + int month; + int day; + int hour; + int minute; + int second; + int pdop; + int hdop; + int vdop; + int mode; + int ground_speed; + int climb_rate; + int course; + + public AltosTelemetryRecordLocation(int[] in_bytes) { + super(in_bytes); + + flags = uint8(5); + altitude = int16(6); + latitude = uint32(8); + longitude = uint32(12); + year = uint8(16); + month = uint8(17); + day = uint8(18); + hour = uint8(19); + minute = uint8(20); + second = uint8(21); + pdop = uint8(22); + hdop = uint8(23); + vdop = uint8(24); + mode = uint8(25); + ground_speed = uint16(26); + climb_rate = int16(28); + course = uint8(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + 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.new_gps = true; + } + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordRaw.java b/altoslib/AltosTelemetryRecordRaw.java new file mode 100644 index 00000000..43d0f17a --- /dev/null +++ b/altoslib/AltosTelemetryRecordRaw.java @@ -0,0 +1,77 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { + int[] bytes; + int serial; + int tick; + int type; + + 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 String string(int off, int l) { + return AltosLib.string(bytes, off + 1, l); + } + + public AltosTelemetryRecordRaw(int[] in_bytes) { + bytes = in_bytes; + serial = uint16(0); + tick = uint16(2); + type = uint8(4); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next; + if (previous != null) + next = new AltosRecord(previous); + else + next = new AltosRecord(); + next.serial = serial; + next.tick = tick; + return next; + } + + public long received_time() { + return received_time; + } +} diff --git a/altoslib/AltosTelemetryRecordSatellite.java b/altoslib/AltosTelemetryRecordSatellite.java new file mode 100644 index 00000000..2526afb6 --- /dev/null +++ b/altoslib/AltosTelemetryRecordSatellite.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { + int channels; + AltosGPSSat[] sats; + + public AltosTelemetryRecordSatellite(int[] in_bytes) { + super(in_bytes); + + channels = uint8(5); + if (channels > 12) + channels = 12; + if (channels == 0) + sats = null; + else { + sats = new AltosGPSSat[channels]; + for (int i = 0; i < channels; i++) { + int svid = uint8(6 + i * 2 + 0); + int c_n_1 = uint8(6 + i * 2 + 1); + sats[i] = new AltosGPSSat(svid, c_n_1); + } + } + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.cc_gps_sat = sats; + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordSensor.java b/altoslib/AltosTelemetryRecordSensor.java new file mode 100644 index 00000000..cfaf90b0 --- /dev/null +++ b/altoslib/AltosTelemetryRecordSensor.java @@ -0,0 +1,104 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { + int state; + int accel; + int pres; + int temp; + int v_batt; + int sense_d; + int sense_m; + + int acceleration; + int speed; + int height; + + int ground_accel; + int ground_pres; + int accel_plus_g; + int accel_minus_g; + + int rssi; + + public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { + super(in_bytes); + state = uint8(5); + + accel = int16(6); + pres = int16(8); + temp = int16(10); + v_batt = int16(12); + sense_d = int16(14); + sense_m = int16(16); + + acceleration = int16(18); + speed = int16(20); + height = int16(22); + + ground_pres = int16(24); + ground_accel = int16(26); + accel_plus_g = int16(28); + accel_minus_g = int16(30); + + rssi = in_rssi; + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + 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.acceleration = acceleration / 16.0; + next.speed = speed / 16.0; + next.height = height; + + next.ground_pres = ground_pres; + 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; + } + + next.rssi = rssi; + + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + return next; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 2ddd24e6..4262daca 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -4,7 +4,7 @@ JAVAROOT=bin CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/*" -SRC=src/org/altusmetrum/AltosLib +SRC=. BIN=bin/org/altusmetrum/AltosLib AltosLibdir = $(datadir)/java diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java b/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java deleted file mode 100644 index 101c5363..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -public class AltosCRCException extends Exception { - public int rssi; - - public AltosCRCException (int in_rssi) { - rssi = in_rssi; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java deleted file mode 100644 index 4ad4e58a..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -public class AltosConfigData implements Iterable { - - /* Version information */ - public String manufacturer; - public String product; - public String version; - public int log_format; - public int serial; - - /* Strings returned */ - public LinkedList lines; - - /* Config information */ - public int config_major; - public int config_minor; - public int main_deploy; - public int apogee_delay; - public int radio_channel; - public int radio_setting; - public int radio_frequency; - public String callsign; - public int accel_cal_plus, accel_cal_minus; - public int radio_calibration; - public int flight_log_max; - public int ignite_mode; - public int stored_flight; - public int storage_size; - public int storage_erase_unit; - - public static String get_string(String line, String label) throws ParseException { - if (line.startsWith(label)) { - String quoted = line.substring(label.length()).trim(); - - if (quoted.startsWith("\"")) - quoted = quoted.substring(1); - if (quoted.endsWith("\"")) - quoted = quoted.substring(0,quoted.length()-1); - return quoted; - } - throw new ParseException("mismatch", 0); - } - - public static int get_int(String line, String label) throws NumberFormatException, ParseException { - if (line.startsWith(label)) { - String tail = line.substring(label.length()).trim(); - String[] tokens = tail.split("\\s+"); - if (tokens.length > 0) - return Integer.parseInt(tokens[0]); - } - throw new ParseException("mismatch", 0); - } - - public Iterator iterator() { - return lines.iterator(); - } - - public int log_available() { - switch (log_format) { - case AltosLib.AO_LOG_FORMAT_TINY: - if (stored_flight == 0) - return 1; - return 0; - default: - if (flight_log_max <= 0) - return 1; - int log_space = storage_size - storage_erase_unit; - int log_used = stored_flight * flight_log_max; - - if (log_used >= log_space) - return 0; - return (log_space - log_used) / flight_log_max; - } - } - - int[] parse_version(String v) { - String[] parts = v.split("\\."); - int r[] = new int[parts.length]; - - for (int i = 0; i < parts.length; i++) { - try { - r[i] = Altos.fromdec(parts[i]); - } catch (NumberFormatException n) { - r[i] = 0; - } - } - - return r; - } - - public int compare_version(String other) { - int[] me = parse_version(version); - int[] them = parse_version(other); - - int l = Math.min(me.length, them.length); - - for (int i = 0; i < l; i++) { - int d = me[i] - them[i]; - if (d != 0) - return d; - } - if (me.length > l) - return 1; - if (them.length > l) - return -1; - return 0; - } - - public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { - link.printf("c s\np\nf\nl\nv\n"); - lines = new LinkedList(); - radio_setting = 0; - radio_frequency = 0; - stored_flight = 0; - for (;;) { - String line = link.get_reply(); - if (line == null) - throw new TimeoutException(); - if (line.contains("Syntax error")) - continue; - lines.add(line); - try { serial = get_int(line, "serial-number"); } catch (Exception e) {} - try { log_format = get_int(line, "log-format"); } catch (Exception e) {} - try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} - try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} - try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} - try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} - try { - radio_frequency = get_int(line, "Frequency:"); - if (radio_frequency < 0) - radio_frequency = 434550; - } catch (Exception e) {} - try { - if (line.startsWith("Accel cal")) { - String[] bits = line.split("\\s+"); - if (bits.length >= 6) { - accel_cal_plus = Integer.parseInt(bits[3]); - accel_cal_minus = Integer.parseInt(bits[5]); - } - } - } catch (Exception e) {} - try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} - try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} - try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} - try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} - try { version = get_string(line,"software-version"); } catch (Exception e) {} - try { product = get_string(line,"product"); } catch (Exception e) {} - - try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} - try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} - try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} - - /* signals the end of the version info */ - if (line.startsWith("software-version")) - break; - } - } - -} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java b/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java deleted file mode 100644 index 3527b575..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -/* - * Sensor data conversion functions - */ -package org.altusmetrum.AltosLib; - -public class AltosConvert { - /* - * Pressure Sensor Model, version 1.1 - * - * written by Holly Grimes - * - * Uses the International Standard Atmosphere as described in - * "A Quick Derivation relating altitude to air pressure" (version 1.03) - * from the Portland State Aerospace Society, except that the atmosphere - * is divided into layers with each layer having a different lapse rate. - * - * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 - * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ - return 0; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted altitude */ - for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - base_pressure *= Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - base_pressure *= Math.pow(base, exponent); - } - base_temperature += delta_z * lapse_rate[layer_number]; - } - - /* calculate the pressure at the inputted altitude */ - delta_z = altitude - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - pressure = base_pressure * Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - pressure = base_pressure * Math.pow(base, exponent); - } - - return pressure; - } - - -/* outputs the altitude associated with the given pressure. the altitude - returned is measured with respect to the mean sea level */ - public static double - pressure_to_altitude(double pressure) - { - - double next_base_temperature = LAYER0_BASE_TEMPERATURE; - double next_base_pressure = LAYER0_BASE_PRESSURE; - - double altitude; - double base_pressure; - double base_temperature; - double base; /* base for function to determine base pressure of next layer */ - double exponent; /* exponent for function to determine base pressure - of next layer */ - double coefficient; - int layer_number; /* identifies layer in the atmosphere */ - int delta_z; /* difference between two altitudes */ - - if (pressure < 0) /* illegal pressure */ - return -1; - if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ - return MAXIMUM_ALTITUDE; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted pressure. */ - layer_number = -1; - do { - layer_number++; - base_pressure = next_base_pressure; - base_temperature = next_base_temperature; - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - next_base_pressure *= Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - next_base_pressure *= Math.pow(base, exponent); - } - next_base_temperature += delta_z * lapse_rate[layer_number]; - } - while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); - - /* calculate the altitude associated with the inputted pressure */ - if (lapse_rate[layer_number] == 0.0) { - coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) - * base_temperature; - altitude = base_altitude[layer_number] - + coefficient * Math.log(pressure / base_pressure); - } - else { - base = pressure / base_pressure; - exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] - / GRAVITATIONAL_ACCELERATION; - coefficient = base_temperature / lapse_rate[layer_number]; - altitude = base_altitude[layer_number] - + coefficient * (Math.pow(base, exponent) - 1); - } - - return altitude; - } - - public static double - cc_battery_to_voltage(double battery) - { - return battery / 32767.0 * 5.0; - } - - public static double - cc_ignitor_to_voltage(double ignite) - { - return ignite / 32767 * 15.0; - } - - public static double radio_to_frequency(int freq, int setting, int cal, int channel) { - double f; - - if (freq > 0) - f = freq / 1000.0; - else { - if (setting <= 0) - setting = cal; - f = 434.550 * setting / cal; - /* Round to nearest 50KHz */ - f = Math.floor (20.0 * f + 0.5) / 20.0; - } - return f + channel * 0.100; - } - - public static int radio_frequency_to_setting(double frequency, int cal) { - double set = frequency / 434.550 * cal; - - return (int) Math.floor (set + 0.5); - } - - public static int radio_frequency_to_channel(double frequency) { - int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); - - if (channel < 0) - channel = 0; - if (channel > 9) - channel = 9; - return channel; - } - - public static double radio_channel_to_frequency(int channel) { - return 434.550 + channel * 0.100; - } - - public static int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - public static double meters_to_feet(double meters) { - return meters * (100 / (2.54 * 12)); - } - - public static double meters_to_mach(double meters) { - return meters / 343; /* something close to mach at usual rocket sites */ - } - - public static double meters_to_g(double meters) { - return meters / 9.80665; - } - - public static int checksum(int[] data, int start, int length) { - int csum = 0x5a; - for (int i = 0; i < length; i++) - csum += data[i + start]; - return csum & 0xff; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java deleted file mode 100644 index 6d889723..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.concurrent.*; - -public class AltosEepromChunk { - - public static final int chunk_size = 256; - public static final int per_line = 8; - - public int data[]; - public int address; - public ParseException parse_exception = null; - - int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - public int data(int offset) { - return data[offset]; - } - - public int data16(int offset) { - return data[offset] | (data[offset + 1] << 8); - } - - public int data32(int offset) { - return data[offset] | (data[offset + 1] << 8) | - (data[offset+2] << 16) | (data[offset+3] << 24); - } - - public boolean erased(int start, int len) { - for (int i = 0; i < len; i++) - if (data[start+i] != 0xff) - return false; - return true; - } - - public AltosEepromChunk(AltosLink link, int block, boolean flush) - throws TimeoutException, InterruptedException { - - int offset; - - data = new int[chunk_size]; - address = block * chunk_size; - if (flush) - link.flush_input(); - link.printf("e %x\n", block); - - for (offset = 0; offset < chunk_size; offset += per_line) { - try { - String line = link.get_reply(5000); - - if (line == null) - throw new TimeoutException(); - - int[] values = ParseHex(line); - - if (values == null || values.length != per_line + 1) - throw new ParseException(String.format("invalid line %s", line), 0); - if (values[0] != offset) - throw new ParseException(String.format("data address out of sync at 0x%x", - address + offset), 0); - for (int i = 0; i < per_line; i++) - data[offset + i] = values[1 + i]; - } catch (ParseException pe) { - for (int i = 0; i < per_line; i++) - data[offset + i] = 0xff; - if (parse_exception == null) - parse_exception = pe; - } - } - } -} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java deleted file mode 100644 index f1397c7b..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * 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 { - - 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; - } -} - -public class AltosEepromIterable 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; - - AltosEepromRecord flight_record; - AltosEepromRecord gps_date_record; - - TreeSet records; - - LinkedList list; - - class EepromState { - int seen; - int n_pad_samples; - double ground_pres; - int gps_tick; - int boost_tick; - int sensor_tick; - - EepromState() { - seen = 0; - n_pad_samples = 0; - ground_pres = 0.0; - gps_tick = 0; - } - } - - void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { - state.tick = record.tick; - switch (record.cmd) { - case AltosLib.AO_LOG_FLIGHT: - eeprom.seen |= 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 & 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_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 |= seen_sensor; - break; - case AltosLib.AO_LOG_TEMP_VOLT: - state.temp = record.a; - state.batt = record.b; - eeprom.seen |= seen_temp_volt; - break; - case AltosLib.AO_LOG_DEPLOY: - state.drogue = record.a; - state.main = record.b; - eeprom.seen |= 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; - AltosGPS old = state.gps; - state.gps = new AltosGPS(); - - /* GPS date doesn't get repeated through the file */ - if (old != null) { - state.gps.year = old.year; - state.gps.month = old.month; - state.gps.day = old.day; - } - state.gps.hour = (record.a & 0xff); - state.gps.minute = (record.a >> 8); - state.gps.second = (record.b & 0xff); - - int flags = (record.b >> 8); - state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; - state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; - state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> - AltosLib.AO_GPS_NUM_SAT_SHIFT; - state.new_gps = true; - has_gps = true; - break; - case AltosLib.AO_LOG_GPS_LAT: - int lat32 = record.a | (record.b << 16); - state.gps.lat = (double) lat32 / 1e7; - break; - case AltosLib.AO_LOG_GPS_LON: - int lon32 = record.a | (record.b << 16); - state.gps.lon = (double) lon32 / 1e7; - break; - case AltosLib.AO_LOG_GPS_ALT: - 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; - state.gps.add_sat(svid, c_n0); - } - break; - case AltosLib.AO_LOG_GPS_DATE: - state.gps.year = (record.a & 0xff) + 2000; - state.gps.month = record.a >> 8; - state.gps.day = record.b & 0xff; - break; - - case AltosLib.AO_LOG_CONFIG_VERSION: - break; - case AltosLib.AO_LOG_MAIN_DEPLOY: - break; - case AltosLib.AO_LOG_APOGEE_DELAY: - break; - case AltosLib.AO_LOG_RADIO_CHANNEL: - break; - case AltosLib.AO_LOG_CALLSIGN: - state.callsign = record.data; - break; - case AltosLib.AO_LOG_ACCEL_CAL: - state.accel_plus_g = record.a; - state.accel_minus_g = record.b; - break; - case AltosLib.AO_LOG_RADIO_CAL: - break; - case AltosLib.AO_LOG_MANUFACTURER: - break; - case AltosLib.AO_LOG_PRODUCT: - break; - case AltosLib.AO_LOG_SERIAL_NUMBER: - state.serial = record.a; - break; - case AltosLib.AO_LOG_SOFTWARE_VERSION: - break; - } - state.seen |= eeprom.seen; - } - - LinkedList make_list() { - LinkedList list = new LinkedList(); - Iterator iterator = records.iterator(); - AltosOrderedRecord record = null; - AltosRecord state = new AltosRecord(); - 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) { - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - } - update_state(state, record, eeprom); - } - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - return list; - } - - public Iterator iterator() { - if (list == null) - list = make_list(); - return list.iterator(); - } - - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; } - - public void write_comments(PrintStream out) { - Iterator iterator = records.iterator(); - out.printf("# Comments\n"); - while (iterator.hasNext()) { - AltosOrderedRecord record = iterator.next(); - switch (record.cmd) { - case AltosLib.AO_LOG_CONFIG_VERSION: - out.printf("# Config version: %s\n", record.data); - break; - case AltosLib.AO_LOG_MAIN_DEPLOY: - out.printf("# Main deploy: %s\n", record.a); - break; - case AltosLib.AO_LOG_APOGEE_DELAY: - out.printf("# Apogee delay: %s\n", record.a); - break; - case AltosLib.AO_LOG_RADIO_CHANNEL: - out.printf("# Radio channel: %s\n", record.a); - break; - case AltosLib.AO_LOG_CALLSIGN: - out.printf("# Callsign: %s\n", record.data); - break; - case AltosLib.AO_LOG_ACCEL_CAL: - out.printf ("# Accel cal: %d %d\n", record.a, record.b); - break; - case AltosLib.AO_LOG_RADIO_CAL: - out.printf ("# Radio cal: %d\n", record.a); - break; - case AltosLib.AO_LOG_MAX_FLIGHT_LOG: - out.printf ("# Max flight log: %d\n", record.a); - break; - case AltosLib.AO_LOG_MANUFACTURER: - out.printf ("# Manufacturer: %s\n", record.data); - break; - case AltosLib.AO_LOG_PRODUCT: - out.printf ("# Product: %s\n", record.data); - break; - case AltosLib.AO_LOG_SERIAL_NUMBER: - out.printf ("# Serial number: %d\n", record.a); - break; - case AltosLib.AO_LOG_SOFTWARE_VERSION: - out.printf ("# Software version: %s\n", record.data); - break; - case Altos.AO_LOG_BARO_RESERVED: - out.printf ("# Baro reserved: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_SENS: - out.printf ("# Baro sens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_OFF: - out.printf ("# Baro off: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCS: - out.printf ("# Baro tcs: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCO: - out.printf ("# Baro tco: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TREF: - out.printf ("# Baro tref: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TEMPSENS: - out.printf ("# Baro tempsens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_CRC: - out.printf ("# Baro crc: %d\n", record.a); - break; - } - } - } - - /* - * Given an AO_LOG_GPS_TIME record with correct time, and one - * missing time, rewrite the missing time values with the good - * ones, assuming that the difference between them is 'diff' seconds - */ - void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { - - int diff = (bad.tick - good.tick + 50) / 100; - - int hour = (good.a & 0xff); - int minute = (good.a >> 8); - int second = (good.b & 0xff); - int flags = (good.b >> 8); - int seconds = hour * 3600 + minute * 60 + second; - - /* Make sure this looks like a good GPS value */ - if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) - flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); - flags |= AltosLib.AO_GPS_RUNNING; - flags |= AltosLib.AO_GPS_VALID; - - int new_seconds = seconds + diff; - if (new_seconds < 0) - new_seconds += 24 * 3600; - int new_second = (new_seconds % 60); - int new_minutes = (new_seconds / 60); - int new_minute = (new_minutes % 60); - int new_hours = (new_minutes / 60); - int new_hour = (new_hours % 24); - - bad.a = new_hour + (new_minute << 8); - bad.b = new_second + (flags << 8); - } - - /* - * Read the whole file, dumping records into a RB tree so - * we can enumerate them in time order -- the eeprom data - * are sometimes out of order with GPS data getting timestamps - * matching the first packet out of the GPS unit but not - * written until the final GPS packet has been received. - */ - public AltosEepromIterable (FileInputStream input) { - records = new TreeSet(); - - AltosOrderedRecord last_gps_time = null; - - int index = 0; - int prev_tick = 0; - boolean prev_tick_valid = false; - boolean missing_time = false; - - try { - for (;;) { - String line = AltosRecord.gets(input); - if (line == null) - break; - AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); - if (record == null) - break; - if (record.cmd == AltosLib.AO_LOG_INVALID) - continue; - prev_tick = record.tick; - if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) - prev_tick_valid = true; - if (record.cmd == AltosLib.AO_LOG_FLIGHT) { - flight_record = record; - continue; - } - - /* Two firmware bugs caused the loss of some GPS data. - * The flight date would never be recorded, and often - * the flight time would get overwritten by another - * record. Detect the loss of the GPS date and fix up the - * missing time records - */ - if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { - gps_date_record = record; - continue; - } - - /* go back and fix up any missing time values */ - if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { - last_gps_time = record; - if (missing_time) { - Iterator iterator = records.iterator(); - while (iterator.hasNext()) { - AltosOrderedRecord old = iterator.next(); - if (old.cmd == AltosLib.AO_LOG_GPS_TIME && - old.a == -1 && old.b == -1) - { - update_time(record, old); - } - } - missing_time = false; - } - } - - if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { - if (last_gps_time == null || last_gps_time.tick != record.tick) { - AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME, - record.tick, - -1, -1, index-1); - if (last_gps_time != null) - update_time(last_gps_time, add_gps_time); - else - missing_time = true; - - records.add(add_gps_time); - record.index = index++; - } - } - records.add(record); - - /* Bail after reading the 'landed' record; we're all done */ - if (record.cmd == AltosLib.AO_LOG_STATE && - record.a == AltosLib.ao_flight_landed) - break; - } - } catch (IOException io) { - } catch (ParseException pe) { - } - try { - input.close(); - } catch (IOException ie) { - } - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java deleted file mode 100644 index 7fca4bd9..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -/* - * Extract a bit of information from an eeprom-stored flight log. - */ - -public class AltosEepromLog { - public int serial; - public boolean has_flight; - public int flight; - public int start_block; - public int end_block; - - public int year, month, day; - - public boolean selected; - - public AltosEepromLog(AltosConfigData config_data, - AltosLink link, - int in_flight, int in_start_block, - int in_end_block) - throws InterruptedException, TimeoutException { - - int block; - boolean has_date = false; - - flight = in_flight; - if (flight != 0) - has_flight = true; - start_block = in_start_block; - end_block = in_end_block; - serial = config_data.serial; - - /* - * Select all flights for download - */ - selected = true; - - /* - * Look in TeleMetrum log data for date - */ - if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN || - config_data.log_format == AltosLib.AO_LOG_FORMAT_FULL) - { - /* - * Only look in the first two blocks so that this - * process doesn't take a long time - */ - if (in_end_block > in_start_block + 2) - in_end_block = in_start_block + 2; - - 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 < eechunk.chunk_size; i += AltosEepromRecord.record_length) { - try { - AltosEepromRecord r = new AltosEepromRecord(eechunk, i); - - if (r.cmd == AltosLib.AO_LOG_FLIGHT) { - flight = r.b; - has_flight = true; - } - if (r.cmd == AltosLib.AO_LOG_GPS_DATE) { - year = 2000 + (r.a & 0xff); - month = (r.a >> 8) & 0xff; - day = (r.b & 0xff); - has_date = true; - } - } catch (ParseException pe) { - } - } - if (has_date && has_flight) - break; - } - } - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java deleted file mode 100644 index 1e845f46..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -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/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java deleted file mode 100644 index 1758fa34..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -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/src/org/altusmetrum/AltosLib/AltosFile.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java deleted file mode 100644 index d2e4f2f7..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -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) { - super (AltosPreferences.logdir(), - String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", - year, month, day, serial, flight, extension)); - } - - public AltosFile(int serial, int flight, String extension) { - this(Calendar.getInstance().get(Calendar.YEAR), - Calendar.getInstance().get(Calendar.MONTH) + 1, - Calendar.getInstance().get(Calendar.DAY_OF_MONTH), - serial, - flight, - extension); - } - - public AltosFile(AltosRecord telem) { - this(telem.serial, telem.flight, "telem"); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java deleted file mode 100644 index 3fdea469..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; - -public class AltosFlightReader { - public String name; - - public int serial; - - public void init() { } - - public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } - - public void close(boolean interrupted) { } - - public void set_frequency(double frequency) throws InterruptedException, TimeoutException { } - - public void save_frequency() { } - - public void set_telemetry(int telemetry) { } - - public void save_telemetry() { } - - public void update(AltosState state) throws InterruptedException { } - - public boolean supports_telemetry(int telemetry) { return false; } - - public File backing_file() { return null; } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java deleted file mode 100644 index f08ff116..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; - -public class AltosFrequency { - public double frequency; - public String description; - - public String toString() { - return String.format("%7.3f MHz %-20s", - frequency, description); - } - - public String toShortString() { - return String.format("%7.3f MHz %s", - frequency, description); - } - - public boolean close(double f) { - double diff = Math.abs(frequency - f); - - return diff < 0.010; - } - - public AltosFrequency(double f, String d) { - frequency = f; - description = d; - } -} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java deleted file mode 100644 index f078a469..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; - -public class AltosGPS { - - public final static int MISSING = AltosRecord.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 int year; - public int month; - public int day; - public int hour; - public int minute; - public int second; - - public double ground_speed; /* m/s */ - public int course; /* degrees */ - public double climb_rate; /* m/s */ - public double hdop; /* unitless */ - public double vdop; /* unitless */ - public int h_error; /* m */ - public int v_error; /* m */ - - public AltosGPSSat[] cc_gps_sat; /* tracking data */ - - public void ParseGPSDate(String date) throws ParseException { - String[] ymd = date.split("-"); - if (ymd.length != 3) - throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); - year = AltosParse.parse_int(ymd[0]); - month = AltosParse.parse_int(ymd[1]); - day = AltosParse.parse_int(ymd[2]); - } - - public void ParseGPSTime(String time) throws ParseException { - String[] hms = time.split(":"); - if (hms.length != 3) - throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); - hour = AltosParse.parse_int(hms[0]); - minute = AltosParse.parse_int(hms[1]); - second = AltosParse.parse_int(hms[2]); - } - - public void ClearGPSTime() { - year = month = day = 0; - hour = minute = second = 0; - } - - public AltosGPS(AltosTelemetryMap map) throws ParseException { - String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, - AltosTelemetry.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)) { - 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); - 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)) { - connected = true; - locked = false; - } else { - connected = false; - locked = false; - } - } - - public AltosGPS(String[] words, int i, int version) throws ParseException { - AltosParse.word(words[i++], "GPS"); - nsat = AltosParse.parse_int(words[i++]); - AltosParse.word(words[i++], "sat"); - - connected = false; - locked = false; - lat = lon = 0; - alt = 0; - ClearGPSTime(); - if ((words[i]).equals("unlocked")) { - connected = true; - i++; - } else if ((words[i]).equals("not-connected")) { - i++; - } else if (words.length >= 40) { - locked = true; - connected = true; - - if (version > 1) - ParseGPSDate(words[i++]); - else - year = month = day = 0; - ParseGPSTime(words[i++]); - lat = AltosParse.parse_coord(words[i++]); - lon = AltosParse.parse_coord(words[i++]); - alt = AltosParse.parse_int(words[i++]); - if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { - ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); - course = AltosParse.parse_int(words[i++]); - climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); - hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); - h_error = AltosParse.parse_int(words[i++]); - v_error = AltosParse.parse_int(words[i++]); - } - } else { - i++; - } - if (i < words.length) { - AltosParse.word(words[i++], "SAT"); - int tracking_channels = 0; - if (words[i].equals("not-connected")) - tracking_channels = 0; - else - tracking_channels = AltosParse.parse_int(words[i]); - i++; - cc_gps_sat = new AltosGPSSat[tracking_channels]; - for (int chan = 0; chan < tracking_channels; chan++) { - cc_gps_sat[chan] = new AltosGPSSat(); - cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); - /* Older versions included SiRF status bits */ - if (version < 2) - i++; - cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); - } - } else - cc_gps_sat = new AltosGPSSat[0]; - } - - public void set_latitude(int in_lat) { - lat = in_lat / 10.0e7; - } - - public void set_longitude(int in_lon) { - lon = in_lon / 10.0e7; - } - - public void set_time(int hour, int minute, int second) { - hour = hour; - minute = minute; - second = second; - } - - public void set_date(int year, int month, int day) { - year = year; - month = month; - day = day; - } - - public void set_flags(int flags) { - flags = flags; - } - - public void set_altitude(int altitude) { - altitude = altitude; - } - - public void add_sat(int svid, int c_n0) { - if (cc_gps_sat == null) { - cc_gps_sat = new AltosGPSSat[1]; - } else { - AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; - for (int i = 0; i < cc_gps_sat.length; i++) - new_gps_sat[i] = cc_gps_sat[i]; - cc_gps_sat = new_gps_sat; - } - AltosGPSSat sat = new AltosGPSSat(); - sat.svid = svid; - sat.c_n0 = c_n0; - cc_gps_sat[cc_gps_sat.length - 1] = sat; - } - - public AltosGPS() { - ClearGPSTime(); - cc_gps_sat = null; - } - - public AltosGPS(AltosGPS old) { - nsat = old.nsat; - locked = old.locked; - connected = old.connected; - lat = old.lat; /* degrees (+N -S) */ - lon = old.lon; /* degrees (+E -W) */ - alt = old.alt; /* m */ - year = old.year; - month = old.month; - day = old.day; - hour = old.hour; - minute = old.minute; - second = old.second; - - ground_speed = old.ground_speed; /* m/s */ - course = old.course; /* degrees */ - climb_rate = old.climb_rate; /* m/s */ - hdop = old.hdop; /* unitless? */ - h_error = old.h_error; /* m */ - v_error = old.v_error; /* m */ - - if (old.cc_gps_sat != null) { - cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; - for (int i = 0; i < old.cc_gps_sat.length; i++) { - cc_gps_sat[i] = new AltosGPSSat(); - cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; - cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; - } - } - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java deleted file mode 100644 index faa1ec8d..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -public class AltosGPSSat { - public int svid; - public int c_n0; - - public AltosGPSSat(int s, int c) { - svid = s; - c_n0= c; - } - - public AltosGPSSat() { - } -} - diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java deleted file mode 100644 index 76b71859..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.Math; - -public class AltosGreatCircle { - public double distance; - public double bearing; - - double sqr(double a) { return a * a; } - - static final double rad = Math.PI / 180; - static final double earth_radius = 6371.2 * 1000; /* in meters */ - - public static final int BEARING_LONG = 0; - public static final int BEARING_SHORT = 1; - public static final int BEARING_VOICE = 2; - - public String bearing_words(int length) { - String [][] bearing_string = { - { - "North", "North North East", "North East", "East North East", - "East", "East South East", "South East", "South South East", - "South", "South South West", "South West", "West South West", - "West", "West North West", "North West", "North North West" - }, { - "N", "NNE", "NE", "ENE", - "E", "ESE", "SE", "SSE", - "S", "SSW", "SW", "WSW", - "W", "WNW", "NW", "NNW" - }, { - "north", "nor nor east", "north east", "east nor east", - "east", "east sow east", "south east", "sow sow east", - "south", "sow sow west", "south west", "west sow west", - "west", "west nor west", "north west", "nor nor west " - } - }; - return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; - } - - public AltosGreatCircle (double start_lat, double start_lon, - double end_lat, double end_lon) - { - double lat1 = rad * start_lat; - double lon1 = rad * -start_lon; - double lat2 = rad * end_lat; - double lon2 = rad * -end_lon; - - double d_lon = lon2 - lon1; - - /* From http://en.wikipedia.org/wiki/Great-circle_distance */ - double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + - sqr(Math.cos(lat1) * Math.sin(lat2) - - Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); - double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); - double d = Math.atan2(vdn,vdd); - double course; - - if (Math.cos(lat1) < 1e-20) { - if (lat1 > 0) - course = Math.PI; - else - course = -Math.PI; - } else { - if (d < 1e-10) - course = 0; - else - course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / - (Math.sin(d)*Math.cos(lat1))); - if (Math.sin(lon2-lon1) > 0) - course = 2 * Math.PI-course; - } - distance = d * earth_radius; - bearing = course * 180/Math.PI; - } - - public AltosGreatCircle(AltosGPS start, AltosGPS end) { - this(start.lat, start.lon, end.lat, end.lon); - } - - public AltosGreatCircle() { - distance = 0; - bearing = 0; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java deleted file mode 100644 index 2921d040..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.awt.*; -import java.util.*; -import java.text.*; -import java.nio.charset.Charset; - -public class AltosLib { - /* EEProm command letters */ - public static final int AO_LOG_FLIGHT = 'F'; - public static final int AO_LOG_SENSOR = 'A'; - 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_TIME = 'G'; - public static final int AO_LOG_GPS_LAT = 'N'; - public static final int AO_LOG_GPS_LON = 'W'; - public static final int AO_LOG_GPS_ALT = 'H'; - public static final int AO_LOG_GPS_SAT = 'V'; - public static final int AO_LOG_GPS_DATE = 'Y'; - public static final int AO_LOG_PRESSURE = 'P'; - - /* Added for header fields in eeprom files */ - public static final int AO_LOG_CONFIG_VERSION = 1000; - public static final int AO_LOG_MAIN_DEPLOY = 1001; - public static final int AO_LOG_APOGEE_DELAY = 1002; - public static final int AO_LOG_RADIO_CHANNEL = 1003; - public static final int AO_LOG_CALLSIGN = 1004; - public static final int AO_LOG_ACCEL_CAL = 1005; - public static final int AO_LOG_RADIO_CAL = 1006; - public static final int AO_LOG_MAX_FLIGHT_LOG = 1007; - public static final int AO_LOG_MANUFACTURER = 2000; - public static final int AO_LOG_PRODUCT = 2001; - public static final int AO_LOG_SERIAL_NUMBER = 2002; - public static final int AO_LOG_LOG_FORMAT = 2003; - public static final int AO_LOG_SOFTWARE_VERSION = 9999; - - /* Added to flag invalid records */ - public static final int AO_LOG_INVALID = -1; - - /* Flight state numbers and names */ - public static final int ao_flight_startup = 0; - public static final int ao_flight_idle = 1; - public static final int ao_flight_pad = 2; - public static final int ao_flight_boost = 3; - public static final int ao_flight_fast = 4; - public static final int ao_flight_coast = 5; - public static final int ao_flight_drogue = 6; - public static final int ao_flight_main = 7; - public static final int ao_flight_landed = 8; - public static final int ao_flight_invalid = 9; - - /* Telemetry modes */ - public static final int ao_telemetry_off = 0; - public static final int ao_telemetry_min = 1; - public static final int ao_telemetry_standard = 1; - public static final int ao_telemetry_0_9 = 2; - public static final int ao_telemetry_0_8 = 3; - public static final int ao_telemetry_max = 3; - - public static final String[] ao_telemetry_name = { - "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" - }; - - public static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; - - public static final int ao_telemetry_standard_len = 32; - public static final int ao_telemetry_0_9_len = 95; - public static final int ao_telemetry_0_8_len = 94; - - public static final int[] ao_telemetry_len = { - 0, 32, 95, 94 - }; - - public static HashMap string_to_state = new HashMap(); - - public static boolean map_initialized = false; - - public static void initialize_map() - { - string_to_state.put("startup", ao_flight_startup); - string_to_state.put("idle", ao_flight_idle); - string_to_state.put("pad", ao_flight_pad); - string_to_state.put("boost", ao_flight_boost); - string_to_state.put("fast", ao_flight_fast); - string_to_state.put("coast", ao_flight_coast); - string_to_state.put("drogue", ao_flight_drogue); - string_to_state.put("apogee", ao_flight_coast); - string_to_state.put("main", ao_flight_main); - string_to_state.put("landed", ao_flight_landed); - string_to_state.put("invalid", ao_flight_invalid); - map_initialized = true; - } - - public static int telemetry_len(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_len[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - public static String telemetry_name(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_name[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - public static String[] state_to_string = { - "startup", - "idle", - "pad", - "boost", - "fast", - "coast", - "drogue", - "main", - "landed", - "invalid", - }; - - public static String[] state_to_string_capital = { - "Startup", - "Idle", - "Pad", - "Boost", - "Fast", - "Coast", - "Drogue", - "Main", - "Landed", - "Invalid", - }; - - public static int state(String state) { - if (!map_initialized) - initialize_map(); - if (string_to_state.containsKey(state)) - return string_to_state.get(state); - return ao_flight_invalid; - } - - public static String state_name(int state) { - if (state < 0 || state_to_string.length <= state) - return "invalid"; - return state_to_string[state]; - } - - public static final int AO_GPS_VALID = (1 << 4); - public static final int AO_GPS_RUNNING = (1 << 5); - public static final int AO_GPS_DATE_VALID = (1 << 6); - public static final int AO_GPS_NUM_SAT_SHIFT = 0; - public static final int AO_GPS_NUM_SAT_MASK = 0xf; - - public static final int AO_LOG_FORMAT_UNKNOWN = 0; - public static final int AO_LOG_FORMAT_FULL = 1; - public static final int AO_LOG_FORMAT_TINY = 2; - 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_NONE = 127; - - public static boolean isspace(int c) { - switch (c) { - case ' ': - case '\t': - return true; - } - return false; - } - - public static boolean ishex(int c) { - if ('0' <= c && c <= '9') - return true; - if ('a' <= c && c <= 'f') - return true; - if ('A' <= c && c <= 'F') - return true; - return false; - } - - public static boolean ishex(String s) { - for (int i = 0; i < s.length(); i++) - if (!ishex(s.charAt(i))) - return false; - return true; - } - - public static int fromhex(int c) { - if ('0' <= c && c <= '9') - return c - '0'; - if ('a' <= c && c <= 'f') - return c - 'a' + 10; - if ('A' <= c && c <= 'F') - return c - 'A' + 10; - return -1; - } - - public static int fromhex(String s) throws NumberFormatException { - int c, v = 0; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (!ishex(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - return v; - } - v = v * 16 + fromhex(c); - } - return v; - } - - public static boolean isdec(int c) { - if ('0' <= c && c <= '9') - return true; - return false; - } - - public static boolean isdec(String s) { - for (int i = 0; i < s.length(); i++) - if (!isdec(s.charAt(i))) - return false; - return true; - } - - public static int fromdec(int c) { - if ('0' <= c && c <= '9') - return c - '0'; - return -1; - } - - public static int int8(int[] bytes, int i) { - return (int) (byte) bytes[i]; - } - - public static int uint8(int[] bytes, int i) { - return bytes[i]; - } - - public static int int16(int[] bytes, int i) { - return (int) (short) (bytes[i] + (bytes[i+1] << 8)); - } - - public static int uint16(int[] bytes, int i) { - return bytes[i] + (bytes[i+1] << 8); - } - - public static int uint32(int[] bytes, int i) { - return bytes[i] + - (bytes[i+1] << 8) + - (bytes[i+2] << 16) + - (bytes[i+3] << 24); - } - - public static final Charset unicode_set = Charset.forName("UTF-8"); - - public static String string(int[] bytes, int s, int l) { - if (s + l > bytes.length) { - if (s > bytes.length) { - s = bytes.length; - l = 0; - } else { - l = bytes.length - s; - } - } - - int i; - for (i = l - 1; i >= 0; i--) - if (bytes[s+i] != 0) - break; - - l = i + 1; - byte[] b = new byte[l]; - - for (i = 0; i < l; i++) - b[i] = (byte) bytes[s+i]; - String n = new String(b, unicode_set); - return n; - } - - public static int hexbyte(String s, int i) { - int c0, c1; - - if (s.length() < i + 2) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - c0 = s.charAt(i); - if (!ishex(c0)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); - c1 = s.charAt(i+1); - if (!ishex(c1)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); - return fromhex(c0) * 16 + fromhex(c1); - } - - public static int[] hexbytes(String s) { - int n; - int[] r; - int i; - - if ((s.length() & 1) != 0) - throw new NumberFormatException(String.format("invalid line \"%s\"", s)); - n = s.length() / 2; - r = new int[n]; - for (i = 0; i < n; i++) - r[i] = hexbyte(s, i * 2); - return r; - } - - public static int fromdec(String s) throws NumberFormatException { - int c, v = 0; - int sign = 1; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (i == 0 && c == '-') { - sign = -1; - } else if (!isdec(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid number \"%s\"", s)); - return v; - } else - v = v * 10 + fromdec(c); - } - return v * sign; - } - - public static String replace_extension(String input, String extension) { - int dot = input.lastIndexOf("."); - if (dot > 0) - input = input.substring(0,dot); - return input.concat(extension); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java deleted file mode 100644 index 5627795a..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -public class AltosLine { - public String line; - - public AltosLine() { - line = null; - } - - public AltosLine(String s) { - line = s; - } -} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java deleted file mode 100644 index 9b80e916..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.io.*; -import java.util.concurrent.*; -import java.util.*; -import java.text.*; - -public abstract class AltosLink { - public abstract void print(String data); - public abstract void close(); - - public static boolean debug = false; - public static void set_debug(boolean in_debug) { debug = in_debug; } - LinkedList pending_output = new LinkedList(); - - public LinkedList> monitors = new LinkedList> ();; - public LinkedBlockingQueue reply_queue = new LinkedBlockingQueue(); - - public void add_monitor(LinkedBlockingQueue q) { - set_monitor(true); - monitors.add(q); - } - - public void remove_monitor(LinkedBlockingQueue q) { - monitors.remove(q); - if (monitors.isEmpty()) - set_monitor(false); - } - - public void printf(String format, Object ... arguments) { - String line = String.format(format, arguments); - if (debug) - pending_output.add(line); - print(line); - } - - public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { - flush_output(); - AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); - if (line != null) - return line.line; - return null; - } - - public String get_reply(int timeout) throws InterruptedException { - try { - return get_reply_no_dialog(timeout); - } catch (TimeoutException te) { - return null; - } - } - - public String get_reply() throws InterruptedException { - return get_reply(5000); - } - - public void add_telem(AltosLine line) throws InterruptedException { - for (int e = 0; e < monitors.size(); e++) { - LinkedBlockingQueue q = monitors.get(e); - q.put(line); - } - } - - public void add_reply(AltosLine line) throws InterruptedException { - reply_queue.put (line); - } - - public void add_string(String line) throws InterruptedException { - if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { - add_telem(new AltosLine(line)); - } else { - add_reply(new AltosLine(line)); - } - } - - public void add_bytes(byte[] bytes, int len) throws InterruptedException { - String line; - try { - line = new String(bytes, 0, len, "UTF-8"); - } catch (UnsupportedEncodingException ue) { - line = ""; - for (int i = 0; i < len; i++) - line = line + bytes[i]; - } - if (debug) - System.out.printf("\t\t\t\t\t%s\n", line); - add_string(line); - } - - public void flush_output() { - for (String s : pending_output) - System.out.print(s); - pending_output.clear(); - } - - public void flush_input(int timeout) throws InterruptedException { - flush_output(); - boolean got_some; - - do { - Thread.sleep(timeout); - got_some = !reply_queue.isEmpty(); - reply_queue.clear(); - } while (got_some); - } - - - public void flush_input() throws InterruptedException { - flush_input(100); - } - - - /* - * Various command-level operations on - * the link - */ - public boolean monitor_mode = false; - public int telemetry = AltosLib.ao_telemetry_standard; - public double frequency; - AltosConfigData config_data; - - private int telemetry_len() { - return AltosLib.telemetry_len(telemetry); - } - - public void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - if (monitor_mode) - printf("m 0\nm %x\n", telemetry_len()); - flush_output(); - } - - public void set_monitor(boolean monitor) { - monitor_mode = monitor; - if (monitor) - printf("m %x\n", telemetry_len()); - else - printf("m 0\n"); - flush_output(); - } - - private void set_channel(int channel) { - if (monitor_mode) - printf("m 0\nc r %d\nm %x\n", - channel, telemetry_len()); - else - printf("c r %d\n", channel); - flush_output(); - } - - private void set_radio_setting(int setting) { - if (monitor_mode) - printf("m 0\nc R %d\nm %x\n", - setting, telemetry_len()); - else - printf("c R %d\n", setting); - flush_output(); - } - - public void set_radio_frequency(double frequency, - boolean has_setting, - int cal) { - if (debug) - System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); - if (has_setting) - set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); - else - set_channel(AltosConvert.radio_frequency_to_channel(frequency)); - } - - public AltosConfigData config_data() throws InterruptedException, TimeoutException { - if (config_data == null) - config_data = new AltosConfigData(this); - return config_data; - } - - public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - config_data(); - set_radio_frequency(frequency, - config_data.radio_setting != 0, - config_data.radio_calibration); - } - - public void set_callsign(String callsign) { - printf ("c c %s\n", callsign); - flush_output(); - } - - public boolean remote; - public int serial; - public String name; - - public void start_remote() throws TimeoutException, InterruptedException { - if (debug) - System.out.printf("start remote %7.3f\n", frequency); - if (frequency == 0.0) - frequency = AltosPreferences.frequency(serial); - set_radio_frequency(frequency); - set_callsign(AltosPreferences.callsign()); - printf("p\nE 0\n"); - flush_input(); - remote = true; - } - - public void stop_remote() throws InterruptedException { - if (debug) - System.out.printf("stop remote\n"); - try { - flush_input(); - } finally { - printf ("~\n"); - flush_output(); - } - remote = false; - } - - public AltosLink() { - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java deleted file mode 100644 index 08c45ca8..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.lang.*; -import java.util.*; -import java.text.ParseException; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * This creates a thread to capture telemetry data and write it to - * a log file - */ -class AltosLog implements Runnable { - - LinkedBlockingQueue input_queue; - LinkedBlockingQueue pending_queue; - int serial; - int flight; - FileWriter log_file; - Thread log_thread; - AltosFile file; - - private void close_log_file() { - if (log_file != null) { - try { - log_file.close(); - } catch (IOException io) { - } - log_file = null; - } - } - - void close() { - close_log_file(); - if (log_thread != null) { - log_thread.interrupt(); - log_thread = null; - } - } - - File file() { - return file; - } - - boolean open (AltosRecord telem) throws IOException { - AltosFile a = new AltosFile(telem); - - System.out.printf("open %s\n", a.toString()); - 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) { - } - } - log_file.flush(); - file = a; - } - return log_file != null; - } - - public void run () { - try { - AltosRecord previous = null; - for (;;) { - AltosLine line = input_queue.take(); - if (line.line == null) - continue; - try { - AltosRecord telem = AltosTelemetry.parse(line.line, previous); - if (telem.serial != 0 && telem.flight != 0 && - (telem.serial != serial || telem.flight != flight || log_file == null)) - { - close_log_file(); - serial = telem.serial; - flight = telem.flight; - open(telem); - } - previous = telem; - } catch (ParseException pe) { - } catch (AltosCRCException ce) { - } - if (log_file != null) { - log_file.write(line.line); - log_file.write('\n'); - log_file.flush(); - } else - pending_queue.put(line.line); - } - } catch (InterruptedException ie) { - } catch (IOException ie) { - } - close(); - } - - public AltosLog (AltosLink link) { - pending_queue = new LinkedBlockingQueue (); - input_queue = new LinkedBlockingQueue (); - link.add_monitor(input_queue); - serial = -1; - flight = -1; - log_file = null; - log_thread = new Thread(this); - log_thread.start(); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java b/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java deleted file mode 100644 index 7d832f1a..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.text.*; -import java.lang.*; - -public class AltosParse { - public static boolean isdigit(char c) { - return '0' <= c && c <= '9'; - } - - public static int parse_int(String v) throws ParseException { - try { - return AltosLib.fromdec(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing int " + v, 0); - } - } - - public static int parse_hex(String v) throws ParseException { - try { - return AltosLib.fromhex(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing hex " + v, 0); - } - } - - public static double parse_double(String v) throws ParseException { - try { - return Double.parseDouble(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing double " + v, 0); - } - } - - public static double parse_coord(String coord) throws ParseException { - String[] dsf = coord.split("\\D+"); - - if (dsf.length != 3) { - throw new ParseException("error parsing coord " + coord, 0); - } - int deg = parse_int(dsf[0]); - int min = parse_int(dsf[1]); - int frac = parse_int(dsf[2]); - - double r = deg + (min + frac / 10000.0) / 60.0; - if (coord.endsWith("S") || coord.endsWith("W")) - r = -r; - return r; - } - - public static String strip_suffix(String v, String suffix) { - if (v.endsWith(suffix)) - return v.substring(0, v.length() - suffix.length()); - return v; - } - - public static void word(String v, String m) throws ParseException { - if (!v.equals(m)) { - throw new ParseException("error matching '" + v + "' '" + m + "'", 0); - } - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java b/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java deleted file mode 100644 index 43c7088d..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.awt.Component; -import javax.swing.*; -import javax.swing.filechooser.FileSystemView; - -public class AltosPreferences { - public static Preferences preferences; - - /* logdir preference name */ - public final static String logdirPreference = "LOGDIR"; - - /* channel preference name */ - public final static String channelPreferenceFormat = "CHANNEL-%d"; - - /* frequency preference name */ - public final static String frequencyPreferenceFormat = "FREQUENCY-%d"; - - /* telemetry format preference name */ - public final static String telemetryPreferenceFormat = "TELEMETRY-%d"; - - /* voice preference name */ - public final static String voicePreference = "VOICE"; - - /* callsign preference name */ - public final static String callsignPreference = "CALLSIGN"; - - /* firmware directory preference name */ - public final static String firmwaredirPreference = "FIRMWARE"; - - /* serial debug preference name */ - public final static String serialDebugPreference = "SERIAL-DEBUG"; - - /* scanning telemetry preferences name */ - public final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; - - /* Launcher serial preference name */ - public final static String launcherSerialPreference = "LAUNCHER-SERIAL"; - - /* Launcher channel preference name */ - public final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; - - /* Default logdir is ~/TeleMetrum */ - public final static String logdirName = "TeleMetrum"; - - /* Log directory */ - public static File logdir; - - /* Map directory -- hangs of logdir */ - public static File mapdir; - - /* Frequency (map serial to frequency) */ - public static Hashtable frequencies; - - /* Telemetry (map serial to telemetry format) */ - public static Hashtable telemetries; - - /* Voice preference */ - public static boolean voice; - - /* Callsign preference */ - public static String callsign; - - /* Firmware directory */ - public static File firmwaredir; - - /* Scanning telemetry */ - public static int scanning_telemetry; - - /* List of frequencies */ - public final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; - public static AltosFrequency[] common_frequencies; - - public final static String frequency_count = "COUNT"; - public final static String frequency_format = "FREQUENCY-%d"; - public final static String description_format = "DESCRIPTION-%d"; - - public static AltosFrequency[] load_common_frequencies() { - AltosFrequency[] frequencies = null; - boolean existing = false; - try { - existing = preferences.nodeExists(common_frequencies_node_name); - } catch (BackingStoreException be) { - existing = false; - } - if (existing) { - Preferences node = preferences.node(common_frequencies_node_name); - int count = node.getInt(frequency_count, 0); - - frequencies = new AltosFrequency[count]; - for (int i = 0; i < count; i++) { - double frequency; - String description; - - frequency = node.getDouble(String.format(frequency_format, i), 0.0); - description = node.get(String.format(description_format, i), null); - frequencies[i] = new AltosFrequency(frequency, description); - } - } else { - frequencies = new AltosFrequency[10]; - for (int i = 0; i < 10; i++) { - frequencies[i] = new AltosFrequency(434.550 + i * .1, - String.format("Channel %d", i)); - } - } - return frequencies; - } - - public static void save_common_frequencies(AltosFrequency[] frequencies) { - Preferences node = preferences.node(common_frequencies_node_name); - - node.putInt(frequency_count, frequencies.length); - for (int i = 0; i < frequencies.length; i++) { - node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); - node.put(String.format(description_format, i), frequencies[i].description); - } - } - public static int launcher_serial; - - public static int launcher_channel; - - public static void init() { - preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); - - /* Initialize logdir from preferences */ - String logdir_string = preferences.get(logdirPreference, null); - if (logdir_string != null) - logdir = new File(logdir_string); - else { - /* Use the file system view default directory */ - logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); - if (!logdir.exists()) - logdir.mkdirs(); - } - mapdir = new File(logdir, "maps"); - if (!mapdir.exists()) - mapdir.mkdirs(); - - frequencies = new Hashtable(); - - telemetries = new Hashtable(); - - voice = preferences.getBoolean(voicePreference, true); - - callsign = preferences.get(callsignPreference,"N0CALL"); - - scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << AltosLib.ao_telemetry_standard)); - - launcher_serial = preferences.getInt(launcherSerialPreference, 0); - - launcher_channel = preferences.getInt(launcherChannelPreference, 0); - - String firmwaredir_string = preferences.get(firmwaredirPreference, null); - if (firmwaredir_string != null) - firmwaredir = new File(firmwaredir_string); - else - firmwaredir = null; - - common_frequencies = load_common_frequencies(); - - } - - static { init(); } - - public static void flush_preferences() { - try { - preferences.flush(); - } catch (BackingStoreException ee) { -/* - if (component != null) - JOptionPane.showMessageDialog(component, - preferences.absolutePath(), - "Cannot save prefernces", - JOptionPane.ERROR_MESSAGE); - else -*/ - System.err.printf("Cannot save preferences\n"); - } - } - - public static void set_logdir(File new_logdir) { - logdir = new_logdir; - mapdir = new File(logdir, "maps"); - if (!mapdir.exists()) - mapdir.mkdirs(); - synchronized (preferences) { - preferences.put(logdirPreference, logdir.getPath()); - flush_preferences(); - } - } - - public static File logdir() { - return logdir; - } - - public static File mapdir() { - return mapdir; - } - - public static void set_frequency(int serial, double new_frequency) { - frequencies.put(serial, new_frequency); - synchronized (preferences) { - preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); - flush_preferences(); - } - } - - public static double frequency(int serial) { - if (frequencies.containsKey(serial)) - return frequencies.get(serial); - double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); - if (frequency == 0.0) { - int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); - frequency = AltosConvert.radio_channel_to_frequency(channel); - } - frequencies.put(serial, frequency); - return frequency; - } - - public static void set_telemetry(int serial, int new_telemetry) { - telemetries.put(serial, new_telemetry); - synchronized (preferences) { - preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); - flush_preferences(); - } - } - - public static int telemetry(int serial) { - if (telemetries.containsKey(serial)) - return telemetries.get(serial); - int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), - AltosLib.ao_telemetry_standard); - telemetries.put(serial, telemetry); - return telemetry; - } - - public static void set_scanning_telemetry(int new_scanning_telemetry) { - scanning_telemetry = new_scanning_telemetry; - synchronized (preferences) { - preferences.putInt(scanningTelemetryPreference, scanning_telemetry); - flush_preferences(); - } - } - - public static int scanning_telemetry() { - return scanning_telemetry; - } - - public static void set_voice(boolean new_voice) { - voice = new_voice; - synchronized (preferences) { - preferences.putBoolean(voicePreference, voice); - flush_preferences(); - } - } - - public static boolean voice() { - return voice; - } - - public static void set_callsign(String new_callsign) { - callsign = new_callsign; - synchronized(preferences) { - preferences.put(callsignPreference, callsign); - flush_preferences(); - } - } - - public static String callsign() { - return callsign; - } - - public static void set_firmwaredir(File new_firmwaredir) { - firmwaredir = new_firmwaredir; - synchronized (preferences) { - preferences.put(firmwaredirPreference, firmwaredir.getPath()); - flush_preferences(); - } - } - - public static File firmwaredir() { - return firmwaredir; - } - - public static void set_launcher_serial(int new_launcher_serial) { - launcher_serial = new_launcher_serial; - System.out.printf("set launcher serial to %d\n", new_launcher_serial); - synchronized (preferences) { - preferences.putInt(launcherSerialPreference, launcher_serial); - flush_preferences(); - } - } - - public static int launcher_serial() { - return launcher_serial; - } - - public static void set_launcher_channel(int new_launcher_channel) { - launcher_channel = new_launcher_channel; - System.out.printf("set launcher channel to %d\n", new_launcher_channel); - synchronized (preferences) { - preferences.putInt(launcherChannelPreference, launcher_channel); - flush_preferences(); - } - } - - public static int launcher_channel() { - return launcher_channel; - } - - public static Preferences bt_devices() { - return preferences.node("bt_devices"); - } - - public static AltosFrequency[] common_frequencies() { - return common_frequencies; - } - - public static void set_common_frequencies(AltosFrequency[] frequencies) { - common_frequencies = frequencies; - synchronized(preferences) { - save_common_frequencies(frequencies); - flush_preferences(); - } - } - - public static void add_common_frequency(AltosFrequency frequency) { - AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; - int i; - - for (i = 0; i < common_frequencies.length; i++) { - if (frequency.frequency == common_frequencies[i].frequency) - return; - if (frequency.frequency < common_frequencies[i].frequency) - break; - new_frequencies[i] = common_frequencies[i]; - } - new_frequencies[i] = frequency; - for (; i < common_frequencies.length; i++) - new_frequencies[i+1] = common_frequencies[i]; - set_common_frequencies(new_frequencies); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java deleted file mode 100644 index e4915af0..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; -import java.io.*; - -public class AltosRecord implements Comparable { - public final static int MISSING = 0x7fffffff; - - 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 int version; - public String callsign; - public int serial; - public int flight; - public int rssi; - public int status; - public int state; - public int tick; - - 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 double acceleration; - public double speed; - public double height; - - public int flight_accel; - public int flight_vel; - public int flight_pres; - - public AltosGPS gps; - public boolean new_gps; - - public AltosIMU imu; - public AltosMag mag; - - 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; - ->>>>>>> 5a249bc... altosui: Complete split out of separate java library - /* - * 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 - */ - - public static final double counts_per_kPa = 27 * 2047 / 3300; - public static final double counts_at_101_3kPa = 1674.0; - - public static double - barometer_to_pressure(double count) - { - return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; - } - - public double raw_pressure() { - if (pres == MISSING) - return MISSING; - return barometer_to_pressure(pres); - } - - public double filtered_pressure() { - if (flight_pres == MISSING) - return MISSING; - return barometer_to_pressure(flight_pres); - } - - public double ground_pressure() { - if (ground_pres == MISSING) - return MISSING; - return barometer_to_pressure(ground_pres); - } - - public double raw_altitude() { - double p = raw_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 filtered_altitude() { - if (height != MISSING && ground_pres != MISSING) - return height + ground_altitude(); - - double p = filtered_pressure(); - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double filtered_height() { - if (height != MISSING) - return height; - - double f = filtered_altitude(); - double g = ground_altitude(); - if (f == MISSING || g == MISSING) - return MISSING; - return f - g; - } - - public double raw_height() { - double r = raw_altitude(); - double g = ground_altitude(); - - if (r == MISSING || g == MISSING) - return height; - return r - g; - } - - 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 - */ - - public 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); - } - - public 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 (acceleration != MISSING) - return acceleration; - - if (ground_accel == MISSING || accel == MISSING) - return MISSING; - return (ground_accel - accel) / accel_counts_per_mss(); - } - - public double accel_speed() { - if (speed != MISSING) - return speed; - if (flight_vel == MISSING) - return MISSING; - return flight_vel / (accel_counts_per_mss() * 100.0); - } - - public String state() { - return AltosLib.state_name(state); - } - - public static String gets(FileInputStream s) throws IOException { - int c; - String line = ""; - - while ((c = s.read()) != -1) { - if (c == '\r') - continue; - if (c == '\n') { - return line; - } - line = line + (char) c; - } - return null; - } - - public int compareTo(AltosRecord o) { - return tick - o.tick; - } - - public AltosRecord(AltosRecord old) { - version = old.version; - seen = old.seen; - 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; - acceleration = old.acceleration; - speed = old.speed; - height = old.height; - gps = new AltosGPS(old.gps); - new_gps = false; - companion = old.companion; - imu = old.imu; - mag = old.mag; - } - - public AltosRecord() { - version = 0; - seen = 0; - callsign = "N0CALL"; - serial = 0; - flight = 0; - rssi = 0; - status = 0; - state = AltosLib.ao_flight_startup; - tick = 0; - accel = MISSING; - pres = MISSING; - temp = MISSING; - batt = MISSING; - drogue = MISSING; - main = MISSING; - flight_accel = 0; - ground_accel = 0; - flight_vel = 0; - flight_pres = 0; - ground_pres = 0; - accel_plus_g = 0; - accel_minus_g = 0; - acceleration = MISSING; - speed = MISSING; - height = MISSING; - gps = new AltosGPS(); - new_gps = false; - companion = null; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java deleted file mode 100644 index c8cc6cac..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -public class AltosRecordCompanion { - public final static int board_id_telescience = 0x0a; - public final static int MAX_CHANNELS = 12; - - public int tick; - public int board_id; - public int update_period; - public int channels; - public int[] companion_data; - - public AltosRecordCompanion(int in_channels) { - channels = in_channels; - if (channels < 0) - channels = 0; - if (channels > MAX_CHANNELS) - channels = MAX_CHANNELS; - companion_data = new int[channels]; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java deleted file mode 100644 index ed1787ed..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; - -public abstract class AltosRecordIterable implements Iterable { - public abstract Iterator 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; }; -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java deleted file mode 100644 index 1585f9eb..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * Open an existing telemetry file and replay it in realtime - */ - -public class AltosReplayReader extends AltosFlightReader { - Iterator iterator; - File file; - - public AltosRecord read() { - if (iterator.hasNext()) - return iterator.next(); - return null; - } - - public void close (boolean interrupted) { - } - - public void update(AltosState state) throws InterruptedException { - /* 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)); - } - - public File backing_file() { return file; } - - public AltosReplayReader(Iterator in_iterator, File in_file) { - iterator = in_iterator; - file = in_file; - name = file.getName(); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosState.java b/altoslib/src/org/altusmetrum/AltosLib/AltosState.java deleted file mode 100644 index 0645e448..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosState.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -/* - * Track flight state from telemetry or eeprom data stream - */ - -package org.altusmetrum.AltosLib; - -public class AltosState { - public AltosRecord data; - - /* derived data */ - - public long report_time; - - public double time; - public double time_change; - public int tick; - - public int state; - public boolean landed; - public boolean ascent; /* going up? */ - public boolean boost; /* under power */ - - public double ground_altitude; - public double height; - public double speed; - public double acceleration; - public double battery; - public double temperature; - public double main_sense; - public double drogue_sense; - public double baro_speed; - - public double max_height; - public double max_acceleration; - public double max_speed; - public double max_baro_speed; - - public AltosGPS gps; - - public AltosIMU imu; - public AltosMag mag; - - public static final int MIN_PAD_SAMPLES = 10; - - public int npad; - public int ngps; - public int gps_waiting; - public boolean gps_ready; - - public AltosGreatCircle from_pad; - public double elevation; /* from pad */ - public double range; /* total distance */ - - public double gps_height; - - public int speak_tick; - public double speak_altitude; - - public void init (AltosRecord cur, AltosState prev_state) { - int i; - AltosRecord prev; - - data = cur; - - ground_altitude = data.ground_altitude(); - height = data.filtered_height(); - - report_time = System.currentTimeMillis(); - - acceleration = data.acceleration(); - speed = data.accel_speed(); - 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; - 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_speed = prev_state.max_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; - - /* compute barometric speed */ - - double height_change = height - prev_state.height; - if (data.speed != AltosRecord.MISSING) - baro_speed = data.speed; - else { - if (time_change > 0) - baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; - else - baro_speed = prev_state.baro_speed; - } - } else { - npad = 0; - ngps = 0; - gps = null; - baro_speed = 0; - time_change = 0; - } - - time = tick / 100.0; - - if (cur.new_gps && (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_idle)) { - - /* 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) { - /* 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; - } - ngps++; - } - } - - gps_waiting = MIN_PAD_SAMPLES - npad; - if (gps_waiting < 0) - gps_waiting = 0; - - gps_ready = gps_waiting == 0; - - ascent = (AltosLib.ao_flight_boost <= state && - state <= AltosLib.ao_flight_coast); - boost = (AltosLib.ao_flight_boost == state); - - /* Only look at accelerometer data under boost */ - if (boost && acceleration > max_acceleration) - max_acceleration = acceleration; - if (boost && speed > max_speed) - max_speed = speed; - if (boost && baro_speed > max_baro_speed) - max_baro_speed = baro_speed; - - if (height > max_height) - max_height = height; - if (data.gps != null) { - if (gps == null || !gps.locked || data.gps.locked) - gps = data.gps; - if (ngps > 0 && gps.locked) { - from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); - } - } - elevation = 0; - range = -1; - if (ngps > 0) { - gps_height = gps.alt - pad_alt; - if (from_pad != null) { - elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; - range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); - } - } else { - gps_height = 0; - } - } - - public AltosState(AltosRecord cur) { - init(cur, null); - } - - public AltosState (AltosRecord cur, AltosState prev) { - init(cur, prev); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java deleted file mode 100644 index 04abb1f3..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -/* - * Telemetry data contents - */ - - -/* - * 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 - * - */ - -public 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); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java deleted file mode 100644 index f4b4029f..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; - -public class AltosTelemetryIterable extends AltosRecordIterable { - TreeSet records; - - public Iterator iterator () { - return records.iterator(); - } - - 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; }; - - public AltosTelemetryIterable (FileInputStream input) { - boolean saw_boost = false; - int current_tick = 0; - int boost_tick = 0; - - AltosRecord previous = null; - records = new TreeSet (); - - try { - for (;;) { - String line = AltosRecord.gets(input); - if (line == null) { - break; - } - try { - AltosRecord record = AltosTelemetry.parse(line, previous); - if (record == 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.accel != AltosRecord.MISSING) - has_accel = true; - if (record.gps != null) - has_gps = true; - if (record.main != AltosRecord.MISSING) - has_ignite = true; - if (previous != null && previous.tick != record.tick) - records.add(previous); - previous = record; - } catch (ParseException pe) { - System.out.printf("parse exception %s\n", pe.getMessage()); - } catch (AltosCRCException ce) { - } - } - } 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/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java deleted file mode 100644 index 003cb6a9..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryMap extends HashMap { - public boolean has(String key) { - return containsKey(key); - } - - public String get_string(String key) throws ParseException { - if (!has(key)) - throw new ParseException ("missing " + key, 0); - return (String) get(key); - } - - public String get_string(String key, String def) { - if (has(key)) - return get(key); - else - return def; - } - - public int get_int(String key) throws ParseException { - return AltosParse.parse_int(get_string(key)); - } - - public int get_int(String key, int def) throws ParseException { - if (has(key)) - return get_int(key); - else - return def; - } - - public double get_double(String key, double def, double scale) throws ParseException { - if (has(key)) - return get_int(key) * scale; - else - return def; - } - - public AltosTelemetryMap(String[] words, int start) { - for (int i = start; i < words.length - 1; i += 2) - put(words[i], words[i+1]); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java deleted file mode 100644 index 67ac1b65..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; - -public class AltosTelemetryReader extends AltosFlightReader { - AltosLink link; - AltosLog log; - AltosRecord previous; - double frequency; - int telemetry; - - LinkedBlockingQueue telem; - - public AltosRecord 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; - } - - public void flush() { - telem.clear(); - } - - public void close(boolean interrupted) { - link.remove_monitor(telem); - log.close(); - link.close(); - } - - public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - link.set_radio_frequency(frequency); - } - - public boolean supports_telemetry(int telemetry) { - - try { - /* Version 1.0 or later firmware supports all telemetry formats */ - if (serial.config_data().compare_version("1.0") >= 0) - return true; - - /* Version 0.9 firmware only supports 0.9 telemetry */ - if (serial.config_data().compare_version("0.9") >= 0) { - if (telemetry == Altos.ao_telemetry_0_9) - return true; - else - return false; - } - - /* Version 0.8 firmware only supports 0.8 telemetry */ - if (telemetry == Altos.ao_telemetry_0_8) - return true; - else - return false; - } catch (InterruptedException ie) { - return true; - } catch (TimeoutException te) { - return true; - } - } - - public void save_frequency() { - AltosPreferences.set_frequency(link.serial, frequency); - } - - public void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - link.set_telemetry(telemetry); - } - - public void save_telemetry() { - AltosPreferences.set_telemetry(link.serial, telemetry); - } - - public void set_monitor(boolean monitor) { - link.set_monitor(monitor); - } - - public File backing_file() { - return log.file(); - } - - public AltosTelemetryReader (AltosLink in_link) - throws IOException, InterruptedException, TimeoutException { - link = in_link; - log = new AltosLog(link); - name = link.name; - previous = null; - telem = new LinkedBlockingQueue(); - frequency = AltosPreferences.frequency(link.serial); - set_frequency(frequency); - telemetry = AltosPreferences.telemetry(link.serial); - set_telemetry(telemetry); - link.add_monitor(telem); - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java deleted file mode 100644 index 367c148d..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -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; - - static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - int[] bytes; - try { - bytes = Altos.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 = Altos.int8(bytes, bytes.length - 3) / 2 - 74; - int status = Altos.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 Altos.ao_telemetry_standard_len + 4: - int type = Altos.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); - break; - case packet_type_location: - r = new AltosTelemetryRecordLocation(bytes); - break; - case packet_type_satellite: - r = new AltosTelemetryRecordSatellite(bytes); - break; - case packet_type_companion: - r = new AltosTelemetryRecordCompanion(bytes); - break; - default: - r = new AltosTelemetryRecordRaw(bytes); - break; - } - break; - case Altos.ao_telemetry_0_9_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - case Altos.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/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java deleted file mode 100644 index 6ad17244..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { - - AltosRecordCompanion companion; - - public AltosTelemetryRecordCompanion(int[] in_bytes) { - super(in_bytes); - - 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/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java deleted file mode 100644 index 25242edc..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - - -public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { - int device_type; - int flight; - int config_major; - int config_minor; - int apogee_delay; - int main_deploy; - int flight_log_max; - String callsign; - String version; - - public AltosTelemetryRecordConfiguration(int[] in_bytes) { - super(in_bytes); - - device_type = uint8(5); - flight = uint16(6); - config_major = uint8(8); - config_minor = uint8(9); - apogee_delay = uint16(10); - main_deploy = uint16(12); - flight_log_max = uint16(14); - callsign = string(16, 8); - version = string(24, 8); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - 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; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java deleted file mode 100644 index 5e157a54..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryRecordGeneral { - - 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 = AltosTelemetryRecordRaw.parse(word[i+1]); - else - r = new AltosTelemetryRecordLegacy(line); - return r; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java deleted file mode 100644 index 8e3713cc..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -/* - * Telemetry data contents - */ - - -/* - * 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 - * - */ - -public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { - /* - * 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"; - - AltosRecord record; - - 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 = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); - record.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); - - /* 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); - - /* flight computer values */ - record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); - record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); - record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.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); - - if (map.has(AO_TELEM_GPS_STATE)) { - record.gps = new AltosGPS(map); - record.new_gps = true; - } - else - record.gps = null; - } - - private void parse_legacy(String[] words, int i) throws ParseException { - - AltosParse.word (words[i++], "CALL"); - record.callsign = words[i++]; - - AltosParse.word (words[i++], "SERIAL"); - record.serial = AltosParse.parse_int(words[i++]); - - if (record.version >= 2) { - AltosParse.word (words[i++], "FLIGHT"); - record.flight = AltosParse.parse_int(words[i++]); - } else - record.flight = 0; - - AltosParse.word(words[i++], "RSSI"); - record.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; - - AltosParse.word(words[i++], "STATUS"); - record.status = AltosParse.parse_hex(words[i++]); - - AltosParse.word(words[i++], "STATE"); - record.state = Altos.state(words[i++]); - - record.tick = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a:"); - record.accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "p:"); - record.pres = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "t:"); - record.temp = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "v:"); - record.batt = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "d:"); - record.drogue = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "m:"); - record.main = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fa:"); - record.flight_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "ga:"); - record.ground_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fv:"); - record.flight_vel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fp:"); - record.flight_pres = AltosParse.parse_int(words[i++]); - - /* Old TeleDongle code with kalman-reporting TeleMetrum code */ - if ((record.flight_vel & 0xffff0000) == 0x80000000) { - record.speed = ((short) record.flight_vel) / 16.0; - record.acceleration = record.flight_accel / 16.0; - record.height = record.flight_pres; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; - record.flight_accel = AltosRecord.MISSING; - } - - AltosParse.word(words[i++], "gp:"); - record.ground_pres = AltosParse.parse_int(words[i++]); - - if (record.version >= 1) { - AltosParse.word(words[i++], "a+:"); - record.accel_plus_g = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a-:"); - record.accel_minus_g = AltosParse.parse_int(words[i++]); - } else { - record.accel_plus_g = record.ground_accel; - record.accel_minus_g = record.ground_accel + 530; - } - - record.gps = new AltosGPS(words, i, record.version); - record.new_gps = true; - } - - public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { - String[] words = line.split("\\s+"); - int i = 0; - - record = new AltosRecord(); - - 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); - } - if (words[i].equals("CALL")) { - record.version = 0; - } else { - AltosParse.word (words[i++], "VERSION"); - record.version = AltosParse.parse_int(words[i++]); - } - - if (record.version < 4) - parse_legacy(words, i); - else - parse_v4(words, i); - } - - /* - * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that - */ - - int[] bytes; - int adjust; - - private int int8(int i) { - return AltosLib.int8(bytes, i + 1 + adjust); - } - private int uint8(int i) { - return AltosLib.uint8(bytes, i + 1 + adjust); - } - private int int16(int i) { - return AltosLib.int16(bytes, i + 1 + adjust); - } - private int uint16(int i) { - return AltosLib.uint16(bytes, i + 1 + adjust); - } - private int uint32(int i) { - return AltosLib.uint32(bytes, i + 1 + adjust); - } - private String string(int i, int l) { - return AltosLib.string(bytes, i + 1 + adjust, l); - } - - static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); - static final int AO_GPS_NUM_SAT_SHIFT = (0); - - static final int AO_GPS_VALID = (1 << 4); - static final int AO_GPS_RUNNING = (1 << 5); - 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 AltosRecord(); - - bytes = in_bytes; - record.version = 4; - adjust = 0; - - if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { - record.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); - - record.ground_accel = int16(7); - record.ground_pres = int16(15); - record.accel_plus_g = int16(17); - record.accel_minus_g = int16(19); - - if (uint16(11) == 0x8000) { - record.acceleration = int16(5); - record.speed = int16(9); - record.height = int16(13); - record.flight_accel = AltosRecord.MISSING; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; - } else { - record.flight_accel = int16(5); - record.flight_vel = uint32(9); - record.flight_pres = int16(13); - record.acceleration = AltosRecord.MISSING; - record.speed = AltosRecord.MISSING; - record.height = AltosRecord.MISSING; - } - - record.gps = null; - - int gps_flags = uint8(41); - - if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { - record.gps = new AltosGPS(); - record.new_gps = true; - - record.seen |= record.seen_gps_time | record.seen_gps_lat | record.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); - - int n_tracking_reported = uint8(70); - if (n_tracking_reported > 12) - n_tracking_reported = 12; - int n_tracking_actual = 0; - for (int i = 0; i < n_tracking_reported; i++) { - if (uint8(71 + i*2) != 0) - n_tracking_actual++; - } - if (n_tracking_actual > 0) { - record.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); - } - } - } - - record.time = 0.0; - } - - public AltosRecord update_state(AltosRecord previous) { - return record; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java deleted file mode 100644 index cddb773d..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - - -public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { - int flags; - int altitude; - int latitude; - int longitude; - int year; - int month; - int day; - int hour; - int minute; - int second; - int pdop; - int hdop; - int vdop; - int mode; - int ground_speed; - int climb_rate; - int course; - - public AltosTelemetryRecordLocation(int[] in_bytes) { - super(in_bytes); - - flags = uint8(5); - altitude = int16(6); - latitude = uint32(8); - longitude = uint32(12); - year = uint8(16); - month = uint8(17); - day = uint8(18); - hour = uint8(19); - minute = uint8(20); - second = uint8(21); - pdop = uint8(22); - hdop = uint8(23); - vdop = uint8(24); - mode = uint8(25); - ground_speed = uint16(26); - climb_rate = int16(28); - course = uint8(30); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - if (next.gps == null) - next.gps = new AltosGPS(); - - 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.new_gps = true; - } - - return next; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java deleted file mode 100644 index 43d0f17a..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { - int[] bytes; - int serial; - int tick; - int type; - - 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 String string(int off, int l) { - return AltosLib.string(bytes, off + 1, l); - } - - public AltosTelemetryRecordRaw(int[] in_bytes) { - bytes = in_bytes; - serial = uint16(0); - tick = uint16(2); - type = uint8(4); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next; - if (previous != null) - next = new AltosRecord(previous); - else - next = new AltosRecord(); - next.serial = serial; - next.tick = tick; - return next; - } - - public long received_time() { - return received_time; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java deleted file mode 100644 index 2526afb6..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { - int channels; - AltosGPSSat[] sats; - - public AltosTelemetryRecordSatellite(int[] in_bytes) { - super(in_bytes); - - channels = uint8(5); - if (channels > 12) - channels = 12; - if (channels == 0) - sats = null; - else { - sats = new AltosGPSSat[channels]; - for (int i = 0; i < channels; i++) { - int svid = uint8(6 + i * 2 + 0); - int c_n_1 = uint8(6 + i * 2 + 1); - sats[i] = new AltosGPSSat(svid, c_n_1); - } - } - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - if (next.gps == null) - next.gps = new AltosGPS(); - - next.gps.cc_gps_sat = sats; - - return next; - } -} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java deleted file mode 100644 index cfaf90b0..00000000 --- a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - - -public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { - int state; - int accel; - int pres; - int temp; - int v_batt; - int sense_d; - int sense_m; - - int acceleration; - int speed; - int height; - - int ground_accel; - int ground_pres; - int accel_plus_g; - int accel_minus_g; - - int rssi; - - public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { - super(in_bytes); - state = uint8(5); - - accel = int16(6); - pres = int16(8); - temp = int16(10); - v_batt = int16(12); - sense_d = int16(14); - sense_m = int16(16); - - acceleration = int16(18); - speed = int16(20); - height = int16(22); - - ground_pres = int16(24); - ground_accel = int16(26); - accel_plus_g = int16(28); - accel_minus_g = int16(30); - - rssi = in_rssi; - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - 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.acceleration = acceleration / 16.0; - next.speed = speed / 16.0; - next.height = height; - - next.ground_pres = ground_pres; - 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; - } - - next.rssi = rssi; - - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - - return next; - } -} -- cgit v1.2.3 From dd43a2ae7594f062a8980d1756a07488ee54b447 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Jun 2012 19:42:47 -0700 Subject: altoslib: Move new sensor library code into altoslib Signed-off-by: Keith Packard --- altoslib/AltosIMU.java | 29 ++++++++++++++++++ altoslib/AltosMag.java | 25 ++++++++++++++++ altoslib/AltosMs5607.java | 76 +++++++++++++++++++++++++++++++++++++++++++++++ altoslib/Makefile.am | 5 +++- altosui/AltosIMU.java | 29 ------------------ altosui/AltosMag.java | 25 ---------------- altosui/AltosMs5607.java | 76 ----------------------------------------------- altosui/Makefile.am | 3 -- 8 files changed, 134 insertions(+), 134 deletions(-) create mode 100644 altoslib/AltosIMU.java create mode 100644 altoslib/AltosMag.java create mode 100644 altoslib/AltosMs5607.java delete mode 100644 altosui/AltosIMU.java delete mode 100644 altosui/AltosMag.java delete mode 100644 altosui/AltosMs5607.java (limited to 'altoslib') diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java new file mode 100644 index 00000000..88e36544 --- /dev/null +++ b/altoslib/AltosIMU.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package altoslib; + +public class AltosIMU { + public int accel_x; + public int accel_y; + public int accel_z; + + public int gyro_x; + public int gyro_y; + public int gyro_z; +} + \ No newline at end of file diff --git a/altoslib/AltosMag.java b/altoslib/AltosMag.java new file mode 100644 index 00000000..45f1924c --- /dev/null +++ b/altoslib/AltosMag.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package altoslib; + +public class AltosMag { + public int x; + public int y; + public int z; +} + \ No newline at end of file diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java new file mode 100644 index 00000000..253e2f9b --- /dev/null +++ b/altoslib/AltosMs5607.java @@ -0,0 +1,76 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package altoslib; + +public class AltosMs5607 { + public int reserved; + public int sens; + public int off; + public int tcs; + public int tco; + public int tref; + public int tempsens; + public int crc; + + public int raw_pres; + public int raw_temp; + public int pa; + public int cc; + + void convert() { + int dT; + int TEMP; + long OFF; + long SENS; + int P; + + dT = raw_temp - ((int) tref << 8); + + TEMP = (int) (2000 + (((long) dT * tempsens) >> 23)); + + OFF = ((long) off << 17) + (((long) tco * dT) >> 6); + + SENS = ((long) sens << 16) + (((long) tcs * dT) >> 7); + + if (TEMP < 2000) { + int T2 = (int) (((long) dT * (long) dT) >> 31); + int TEMPM = TEMP - 2000; + long OFF2 = (61 * (long) TEMPM * (long) TEMPM) >> 4; + long SENS2 = 2 * (long) TEMPM * (long) TEMPM; + if (TEMP < 1500) { + int TEMPP = TEMP + 1500; + long TEMPP2 = TEMPP * TEMPP; + OFF2 = OFF2 + 15 * TEMPP2; + SENS2 = SENS2 + 8 * TEMPP2; + } + TEMP -= T2; + OFF -= OFF2; + SENS -= SENS2; + } + + pa = (int) (((((long) raw_pres * SENS) >> 21) - OFF) >> 15); + cc = TEMP; + } + + public int set(int in_pres, int in_temp) { + raw_pres = in_pres; + raw_temp = in_temp; + convert(); + return pa; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 4262daca..2e4a795a 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -47,7 +47,10 @@ AltosLib_JAVA = \ $(SRC)/AltosTelemetryRecordLocation.java \ $(SRC)/AltosTelemetryRecordRaw.java \ $(SRC)/AltosTelemetryRecordSatellite.java \ - $(SRC)/AltosTelemetryRecordSensor.java + $(SRC)/AltosTelemetryRecordSensor.java \ + $(SRC)/AltosMs5607.java \ + $(SRC)/AltosIMU.java \ + $(SRC)/AltosMag.java JAR=AltosLib.jar diff --git a/altosui/AltosIMU.java b/altosui/AltosIMU.java deleted file mode 100644 index 1f865a65..00000000 --- a/altosui/AltosIMU.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright © 2012 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -public class AltosIMU { - int accel_x; - int accel_y; - int accel_z; - - int gyro_x; - int gyro_y; - int gyro_z; -} - \ No newline at end of file diff --git a/altosui/AltosMag.java b/altosui/AltosMag.java deleted file mode 100644 index b3fc542b..00000000 --- a/altosui/AltosMag.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright © 2012 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -public class AltosMag { - int x; - int y; - int z; -} - \ No newline at end of file diff --git a/altosui/AltosMs5607.java b/altosui/AltosMs5607.java deleted file mode 100644 index 6f8bdbbe..00000000 --- a/altosui/AltosMs5607.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright © 2012 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -public class AltosMs5607 { - int reserved; - int sens; - int off; - int tcs; - int tco; - int tref; - int tempsens; - int crc; - - int raw_pres; - int raw_temp; - public int pa; - public int cc; - - void convert() { - int dT; - int TEMP; - long OFF; - long SENS; - int P; - - dT = raw_temp - ((int) tref << 8); - - TEMP = (int) (2000 + (((long) dT * tempsens) >> 23)); - - OFF = ((long) off << 17) + (((long) tco * dT) >> 6); - - SENS = ((long) sens << 16) + (((long) tcs * dT) >> 7); - - if (TEMP < 2000) { - int T2 = (int) (((long) dT * (long) dT) >> 31); - int TEMPM = TEMP - 2000; - long OFF2 = (61 * (long) TEMPM * (long) TEMPM) >> 4; - long SENS2 = 2 * (long) TEMPM * (long) TEMPM; - if (TEMP < 1500) { - int TEMPP = TEMP + 1500; - long TEMPP2 = TEMPP * TEMPP; - OFF2 = OFF2 + 15 * TEMPP2; - SENS2 = SENS2 + 8 * TEMPP2; - } - TEMP -= T2; - OFF -= OFF2; - SENS -= SENS2; - } - - pa = (int) (((((long) raw_pres * SENS) >> 21) - OFF) >> 15); - cc = TEMP; - } - - public int set(int in_pres, int in_temp) { - raw_pres = in_pres; - raw_temp = in_temp; - convert(); - return pa; - } -} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 1ec45c5f..0a6ae59e 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -45,9 +45,6 @@ altosui_JAVA = \ AltosEepromTeleScience.java \ AltosEepromMega.java \ AltosEepromMegaIterable.java \ - AltosMs5607.java \ - AltosIMU.java \ - AltosMag.java \ AltosEepromSelect.java \ AltosFlash.java \ AltosFlashUI.java \ -- cgit v1.2.3 From f86dac643081987c8994ab57a96640d5e91b342a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Jun 2012 19:59:40 -0700 Subject: altoslib: Clean up random rebase failures Signed-off-by: Keith Packard --- altoslib/AltosConfigData.java | 2 +- altoslib/AltosEepromIterable.java | 16 ++++---- altoslib/AltosIMU.java | 2 +- altoslib/AltosLib.java | 11 ++++++ altoslib/AltosMag.java | 2 +- altoslib/AltosMs5607.java | 2 +- altoslib/AltosRecord.java | 1 - altoslib/AltosState.java | 2 + altoslib/AltosTelemetryReader.java | 8 ++-- altoslib/AltosTelemetryRecord.java | 15 +++---- altoslib/AltosTelemetryRecordLegacy.java | 4 +- altosui/Altos.java | 67 -------------------------------- altosui/AltosSerial.java | 3 -- altosui/Makefile.am | 3 -- 14 files changed, 39 insertions(+), 99 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 4ad4e58a..fa6a72b5 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -104,7 +104,7 @@ public class AltosConfigData implements Iterable { for (int i = 0; i < parts.length; i++) { try { - r[i] = Altos.fromdec(parts[i]); + r[i] = AltosLib.fromdec(parts[i]); } catch (NumberFormatException n) { r[i] = 0; } diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index f1397c7b..a923d63b 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -318,28 +318,28 @@ public class AltosEepromIterable extends AltosRecordIterable { case AltosLib.AO_LOG_SOFTWARE_VERSION: out.printf ("# Software version: %s\n", record.data); break; - case Altos.AO_LOG_BARO_RESERVED: + case AltosLib.AO_LOG_BARO_RESERVED: out.printf ("# Baro reserved: %d\n", record.a); break; - case Altos.AO_LOG_BARO_SENS: + case AltosLib.AO_LOG_BARO_SENS: out.printf ("# Baro sens: %d\n", record.a); break; - case Altos.AO_LOG_BARO_OFF: + case AltosLib.AO_LOG_BARO_OFF: out.printf ("# Baro off: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TCS: + case AltosLib.AO_LOG_BARO_TCS: out.printf ("# Baro tcs: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TCO: + case AltosLib.AO_LOG_BARO_TCO: out.printf ("# Baro tco: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TREF: + case AltosLib.AO_LOG_BARO_TREF: out.printf ("# Baro tref: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TEMPSENS: + case AltosLib.AO_LOG_BARO_TEMPSENS: out.printf ("# Baro tempsens: %d\n", record.a); break; - case Altos.AO_LOG_BARO_CRC: + case AltosLib.AO_LOG_BARO_CRC: out.printf ("# Baro crc: %d\n", record.a); break; } diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index 88e36544..c0eaf139 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altoslib; +package org.altusmetrum.AltosLib; public class AltosIMU { public int accel_x; diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 2921d040..27d72079 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -50,6 +50,17 @@ public class AltosLib { public static final int AO_LOG_PRODUCT = 2001; public static final int AO_LOG_SERIAL_NUMBER = 2002; public static final int AO_LOG_LOG_FORMAT = 2003; + + /* Added for header fields in megametrum files */ + public static final int AO_LOG_BARO_RESERVED = 3000; + public static final int AO_LOG_BARO_SENS = 3001; + public static final int AO_LOG_BARO_OFF = 3002; + public static final int AO_LOG_BARO_TCS = 3004; + public static final int AO_LOG_BARO_TCO = 3005; + public static final int AO_LOG_BARO_TREF = 3006; + public static final int AO_LOG_BARO_TEMPSENS = 3007; + public static final int AO_LOG_BARO_CRC = 3008; + public static final int AO_LOG_SOFTWARE_VERSION = 9999; /* Added to flag invalid records */ diff --git a/altoslib/AltosMag.java b/altoslib/AltosMag.java index 45f1924c..0f8399ab 100644 --- a/altoslib/AltosMag.java +++ b/altoslib/AltosMag.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altoslib; +package org.altusmetrum.AltosLib; public class AltosMag { public int x; diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index 253e2f9b..a7b902e2 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altoslib; +package org.altusmetrum.AltosLib; public class AltosMs5607 { public int reserved; diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index e4915af0..10ef3061 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -82,7 +82,6 @@ public class AltosRecord implements Comparable { public AltosRecordCompanion companion; ->>>>>>> 5a249bc... altosui: Complete split out of separate java library /* * Values for our MP3H6115A pressure sensor * diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 0645e448..68c7611f 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -70,6 +70,8 @@ public class AltosState { public double gps_height; + public double pad_lat, pad_lon, pad_alt; + public int speak_tick; public double speak_altitude; diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 67ac1b65..112e008e 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -59,19 +59,19 @@ public class AltosTelemetryReader extends AltosFlightReader { try { /* Version 1.0 or later firmware supports all telemetry formats */ - if (serial.config_data().compare_version("1.0") >= 0) + if (link.config_data().compare_version("1.0") >= 0) return true; /* Version 0.9 firmware only supports 0.9 telemetry */ - if (serial.config_data().compare_version("0.9") >= 0) { - if (telemetry == Altos.ao_telemetry_0_9) + if (link.config_data().compare_version("0.9") >= 0) { + if (telemetry == AltosLib.ao_telemetry_0_9) return true; else return false; } /* Version 0.8 firmware only supports 0.8 telemetry */ - if (telemetry == Altos.ao_telemetry_0_8) + if (telemetry == AltosLib.ao_telemetry_0_8) return true; else return false; diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java index 367c148d..4292dae8 100644 --- a/altoslib/AltosTelemetryRecord.java +++ b/altoslib/AltosTelemetryRecord.java @@ -16,6 +16,7 @@ */ package org.altusmetrum.AltosLib; +import java.text.*; public abstract class AltosTelemetryRecord { @@ -47,7 +48,7 @@ public abstract class AltosTelemetryRecord { int[] bytes; try { - bytes = Altos.hexbytes(hex); + bytes = AltosLib.hexbytes(hex); } catch (NumberFormatException ne) { throw new ParseException(ne.getMessage(), 0); } @@ -60,16 +61,16 @@ public abstract class AltosTelemetryRecord { if (!cksum(bytes)) throw new ParseException(String.format("invalid line \"%s\"", hex), 0); - int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; - int status = Altos.uint8(bytes, bytes.length - 2); + 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 Altos.ao_telemetry_standard_len + 4: - int type = Altos.uint8(bytes, 4 + 1); + 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: @@ -93,10 +94,10 @@ public abstract class AltosTelemetryRecord { break; } break; - case Altos.ao_telemetry_0_9_len + 4: + case AltosLib.ao_telemetry_0_9_len + 4: r = new AltosTelemetryRecordLegacy(bytes, rssi, status); break; - case Altos.ao_telemetry_0_8_len + 4: + case AltosLib.ao_telemetry_0_8_len + 4: r = new AltosTelemetryRecordLegacy(bytes, rssi, status); break; default: diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index 8e3713cc..85071d9c 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -241,7 +241,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { 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 = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + record.state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid")); record.tick = map.get_int(AO_TELEM_TICK, 0); /* raw sensor values */ @@ -300,7 +300,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { record.status = AltosParse.parse_hex(words[i++]); AltosParse.word(words[i++], "STATE"); - record.state = Altos.state(words[i++]); + record.state = AltosLib.state(words[i++]); record.tick = AltosParse.parse_int(words[i++]); diff --git a/altosui/Altos.java b/altosui/Altos.java index 380796cc..334ddb07 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -28,73 +28,6 @@ import org.altusmetrum.AltosLib.*; public class Altos extends AltosLib { - /* Added for header fields in eeprom files */ - static final int AO_LOG_CONFIG_VERSION = 1000; - static final int AO_LOG_MAIN_DEPLOY = 1001; - static final int AO_LOG_APOGEE_DELAY = 1002; - static final int AO_LOG_RADIO_CHANNEL = 1003; - static final int AO_LOG_CALLSIGN = 1004; - static final int AO_LOG_ACCEL_CAL = 1005; - static final int AO_LOG_RADIO_CAL = 1006; - static final int AO_LOG_MAX_FLIGHT_LOG = 1007; - static final int AO_LOG_MANUFACTURER = 2000; - static final int AO_LOG_PRODUCT = 2001; - static final int AO_LOG_SERIAL_NUMBER = 2002; - static final int AO_LOG_LOG_FORMAT = 2003; - - /* Added for header fields in megametrum files */ - static final int AO_LOG_BARO_RESERVED = 3000; - static final int AO_LOG_BARO_SENS = 3001; - static final int AO_LOG_BARO_OFF = 3002; - static final int AO_LOG_BARO_TCS = 3004; - static final int AO_LOG_BARO_TCO = 3005; - static final int AO_LOG_BARO_TREF = 3006; - static final int AO_LOG_BARO_TEMPSENS = 3007; - static final int AO_LOG_BARO_CRC = 3008; - - static final int AO_LOG_SOFTWARE_VERSION = 9999; - - /* Added to flag invalid records */ - static final int AO_LOG_INVALID = -1; - - /* Flight state numbers and names */ - static final int ao_flight_startup = 0; - static final int ao_flight_idle = 1; - static final int ao_flight_pad = 2; - static final int ao_flight_boost = 3; - static final int ao_flight_fast = 4; - static final int ao_flight_coast = 5; - static final int ao_flight_drogue = 6; - static final int ao_flight_main = 7; - static final int ao_flight_landed = 8; - static final int ao_flight_invalid = 9; - - /* Telemetry modes */ - static final int ao_telemetry_off = 0; - static final int ao_telemetry_min = 1; - static final int ao_telemetry_standard = 1; - static final int ao_telemetry_0_9 = 2; - static final int ao_telemetry_0_8 = 3; - static final int ao_telemetry_max = 3; - - static final String[] ao_telemetry_name = { - "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" - }; - - static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; - - static final int ao_telemetry_standard_len = 32; - static final int ao_telemetry_0_9_len = 95; - static final int ao_telemetry_0_8_len = 94; - - static final int[] ao_telemetry_len = { - 0, 32, 95, 94 - }; - - static HashMap string_to_state = new HashMap(); - - static boolean map_initialized = false; - static final int tab_elt_pad = 5; static Font label_font; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 54cdcba7..3abdb645 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -264,7 +264,6 @@ public class AltosSerial extends AltosLink implements Runnable { flush_output(); } -<<<<<<< HEAD private int telemetry_len() { return Altos.telemetry_len(telemetry); } @@ -386,8 +385,6 @@ public class AltosSerial extends AltosLink implements Runnable { remote = false; } -======= ->>>>>>> bc5e669... altosui: Pull most of AltosSerial into AltosLink public void set_frame(Frame in_frame) { frame = in_frame; } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 0a6ae59e..9fc7b5b3 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -27,8 +27,6 @@ altosui_JAVA = \ AltosConfigureUI.java \ AltosConfigTD.java \ AltosConfigTDUI.java \ - AltosConvert.java \ - AltosCRCException.java \ AltosCSV.java \ AltosCSVUI.java \ AltosDebug.java \ @@ -42,7 +40,6 @@ altosui_JAVA = \ AltosEepromList.java \ AltosEepromManage.java \ AltosEepromMonitor.java \ - AltosEepromTeleScience.java \ AltosEepromMega.java \ AltosEepromMegaIterable.java \ AltosEepromSelect.java \ -- cgit v1.2.3 From 7a19d6790a9800f925c8de24aac71796351e2c04 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Jun 2012 19:28:58 -0700 Subject: altos: More cleanups for moving files to altoslib Signed-off-by: Keith Packard --- altoslib/AltosEepromMega.java | 213 ++++++++++++++ altoslib/AltosEepromMegaIterable.java | 518 +++++++++++++++++++++++++++++++++ altoslib/AltosLink.java | 25 ++ altoslib/Makefile.am | 2 + altosui/Altos.java | 56 ---- altosui/AltosConfigTD.java | 2 + altosui/AltosConfigTDUI.java | 2 + altosui/AltosEepromMega.java | 218 -------------- altosui/AltosEepromMegaIterable.java | 523 ---------------------------------- altosui/AltosFlightStatusUpdate.java | 1 + altosui/AltosSerial.java | 68 ----- altosui/Makefile.am | 2 - 12 files changed, 763 insertions(+), 867 deletions(-) create mode 100644 altoslib/AltosEepromMega.java create mode 100644 altoslib/AltosEepromMegaIterable.java delete mode 100644 altosui/AltosEepromMega.java delete mode 100644 altosui/AltosEepromMegaIterable.java (limited to 'altoslib') diff --git a/altoslib/AltosEepromMega.java b/altoslib/AltosEepromMega.java new file mode 100644 index 00000000..2628279e --- /dev/null +++ b/altoslib/AltosEepromMega.java @@ -0,0 +1,213 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromMega { + public int cmd; + public int tick; + public boolean valid; + public String data; + public int a, b; + + public int data8[]; + + 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); + } + + /* 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_x() { return data16(8); } + public int accel_y() { return data16(10); } + public int accel_z() { return data16(12); } + public int gyro_x() { return data16(14); } + public int gyro_y() { return data16(16); } + public int gyro_z() { return data16(18); } + public int mag_x() { return data16(20); } + public int mag_y() { return data16(22); } + public int mag_z() { return data16(24); } + public int accel() { + int a = data16(26); + if (a != 0xffff) + return a; + return accel_y(); + } + + /* AO_LOG_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 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; + } + + tick = chunk.data16(start+2); + + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = chunk.data(start + header_length + i); + } + + public AltosEepromMega (String line) { + valid = false; + tick = 0; + + if (line == null) { + cmd = AltosLib.AO_LOG_INVALID; + line = ""; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 2 + data_length) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + valid = true; + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = Integer.parseInt(tokens[2 + i],16); + } + } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = AltosLib.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = AltosLib.AO_LOG_MAIN_DEPLOY; + 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 if (tokens[0].equals("ms5607")) { + if (tokens[1].equals("reserved:")) { + cmd = AltosLib.AO_LOG_BARO_RESERVED; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("sens:")) { + cmd = AltosLib.AO_LOG_BARO_SENS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("off:")) { + cmd = AltosLib.AO_LOG_BARO_OFF; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tcs:")) { + cmd = AltosLib.AO_LOG_BARO_TCS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tco:")) { + cmd = AltosLib.AO_LOG_BARO_TCO; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tref:")) { + cmd = AltosLib.AO_LOG_BARO_TREF; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tempsens:")) { + cmd = AltosLib.AO_LOG_BARO_TEMPSENS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("crc:")) { + cmd = AltosLib.AO_LOG_BARO_CRC; + a = Integer.parseInt(tokens[2]); + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } catch (NumberFormatException ne) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } + } + + public AltosEepromMega(int in_cmd, int in_tick) { + cmd = in_cmd; + tick = in_tick; + valid = true; + } +} diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java new file mode 100644 index 00000000..28a298b3 --- /dev/null +++ b/altoslib/AltosEepromMegaIterable.java @@ -0,0 +1,518 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * 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 { + + 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 AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { + super(in_cmd, in_tick); + a = in_a; + b = in_b; + index = in_index; + } + + public String toString() { + return String.format("%d.%d %04x %04x %04x", + cmd, index, tick, a, b); + } + + public int compareTo(AltosOrderedMegaRecord o) { + int tick_diff = tick - o.tick; + if (tick_diff != 0) + return tick_diff; + return index - o.index; + } +} + +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 records; + + AltosMs5607 baro; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + int sensor_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord 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(); + state.pres = baro.set(record.pres(), record.temp()); + 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_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 |= seen_sensor; + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.batt = record.v_batt(); + eeprom.seen |= seen_temp_volt; + break; + case AltosLib.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= seen_deploy; + has_ignite = true; + break; + case AltosLib.AO_LOG_STATE: + state.state = record.state(); + break; + case AltosLib.AO_LOG_GPS_TIME: + eeprom.gps_tick = state.tick; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; + state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> + AltosLib.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; + has_gps = true; + break; + case AltosLib.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_ALT: + 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; + state.gps.add_sat(svid, c_n0); + } + break; + case AltosLib.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case AltosLib.AO_LOG_CONFIG_VERSION: + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + break; + case AltosLib.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case AltosLib.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case AltosLib.AO_LOG_RADIO_CAL: + break; + case AltosLib.AO_LOG_MANUFACTURER: + break; + case AltosLib.AO_LOG_PRODUCT: + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + break; + case AltosLib.AO_LOG_BARO_RESERVED: + baro.reserved = record.a; + break; + case AltosLib.AO_LOG_BARO_SENS: + baro.sens =record.a; + break; + case AltosLib.AO_LOG_BARO_OFF: + baro.off =record.a; + break; + case AltosLib.AO_LOG_BARO_TCS: + baro.tcs =record.a; + break; + case AltosLib.AO_LOG_BARO_TCO: + baro.tco =record.a; + break; + case AltosLib.AO_LOG_BARO_TREF: + baro.tref =record.a; + break; + case AltosLib.AO_LOG_BARO_TEMPSENS: + baro.tempsens =record.a; + break; + case AltosLib.AO_LOG_BARO_CRC: + baro.crc =record.a; + break; + } + state.seen |= eeprom.seen; + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedMegaRecord record = null; + AltosRecord state = new AltosRecord(); + 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) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + 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.a); + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case AltosLib.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case AltosLib.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case AltosLib.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; + case AltosLib.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case AltosLib.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + case AltosLib.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedMegaRecord good, AltosOrderedMegaRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); + flags |= AltosLib.AO_GPS_RUNNING; + flags |= AltosLib.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromMegaIterable (FileInputStream input) { + records = new TreeSet(); + + 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 = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == AltosLib.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == AltosLib.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedMegaRecord old = iterator.next(); + if (old.cmd == AltosLib.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedMegaRecord add_gps_time = new AltosOrderedMegaRecord(AltosLib.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == AltosLib.AO_LOG_STATE && + record.a == AltosLib.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 9b80e916..77b400fc 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -141,6 +141,31 @@ public abstract class AltosLink { return AltosLib.telemetry_len(telemetry); } + private void set_radio_freq(int frequency) { + if (monitor_mode) + printf("m 0\nc F %d\nm %x\n", + frequency, telemetry_len()); + else + printf("c F %d\n", frequency); + flush_output(); + } + + public void set_radio_frequency(double frequency, + boolean has_frequency, + boolean has_setting, + int cal) { + if (debug) + System.out.printf("set_radio_frequency %7.3f (freq %b) (set %b) %d\n", frequency, has_frequency, has_setting, cal); + if (frequency == 0) + return; + if (has_frequency) + set_radio_freq((int) Math.floor (frequency * 1000)); + else if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + public void set_telemetry(int in_telemetry) { telemetry = in_telemetry; if (monitor_mode) diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 2e4a795a..f644d46a 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -17,6 +17,8 @@ AltosLib_JAVA = \ $(SRC)/AltosEepromChunk.java \ $(SRC)/AltosEepromIterable.java \ $(SRC)/AltosEepromLog.java \ + $(SRC)/AltosEepromMega.java \ + $(SRC)/AltosEepromMegaIterable.java \ $(SRC)/AltosEepromRecord.java \ $(SRC)/AltosEepromTeleScience.java \ $(SRC)/AltosFile.java \ diff --git a/altosui/Altos.java b/altosui/Altos.java index 334ddb07..351927ee 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -72,62 +72,6 @@ public class Altos extends AltosLib { static final int text_width = 20; - static void initialize_map() - { - string_to_state.put("startup", ao_flight_startup); - string_to_state.put("idle", ao_flight_idle); - string_to_state.put("pad", ao_flight_pad); - string_to_state.put("boost", ao_flight_boost); - string_to_state.put("fast", ao_flight_fast); - string_to_state.put("coast", ao_flight_coast); - string_to_state.put("drogue", ao_flight_drogue); - string_to_state.put("apogee", ao_flight_coast); - string_to_state.put("main", ao_flight_main); - string_to_state.put("landed", ao_flight_landed); - string_to_state.put("invalid", ao_flight_invalid); - map_initialized = true; - } - - static int telemetry_len(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_len[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - static String telemetry_name(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_name[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - static String[] state_to_string = { - "startup", - "idle", - "pad", - "boost", - "fast", - "coast", - "drogue", - "main", - "landed", - "invalid", - }; - - static String[] state_to_string_capital = { - "Startup", - "Idle", - "Pad", - "Boost", - "Fast", - "Coast", - "Drogue", - "Main", - "Landed", - "Invalid", - }; - static public int state(String state) { if (!map_initialized) initialize_map(); diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index d3c452e1..4048166c 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -30,6 +30,8 @@ import java.util.concurrent.*; import libaltosJNI.*; +import org.altusmetrum.AltosLib.*; + public class AltosConfigTD implements ActionListener { class int_ref { diff --git a/altosui/AltosConfigTDUI.java b/altosui/AltosConfigTDUI.java index 9f6badc7..f2058f69 100644 --- a/altosui/AltosConfigTDUI.java +++ b/altosui/AltosConfigTDUI.java @@ -31,6 +31,8 @@ import java.util.concurrent.LinkedBlockingQueue; import libaltosJNI.*; +import org.altusmetrum.AltosLib.*; + public class AltosConfigTDUI extends AltosDialog implements ActionListener, ItemListener, DocumentListener diff --git a/altosui/AltosEepromMega.java b/altosui/AltosEepromMega.java deleted file mode 100644 index 8ae485cb..00000000 --- a/altosui/AltosEepromMega.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -public class AltosEepromMega { - public int cmd; - public int tick; - public boolean valid; - public String data; - int a, b; - - public int data8[]; - - 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); - } - - /* 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_x() { return data16(8); } - public int accel_y() { return data16(10); } - public int accel_z() { return data16(12); } - public int gyro_x() { return data16(14); } - public int gyro_y() { return data16(16); } - public int gyro_z() { return data16(18); } - public int mag_x() { return data16(20); } - public int mag_y() { return data16(22); } - public int mag_z() { return data16(24); } - public int accel() { - int a = data16(26); - if (a != 0xffff) - return a; - return accel_y(); - } - - /* AO_LOG_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 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 = Altos.AO_LOG_INVALID; - } - - tick = chunk.data16(start+2); - - data8 = new int[data_length]; - for (int i = 0; i < data_length; i++) - data8[i] = chunk.data(start + header_length + i); - } - - public AltosEepromMega (String line) { - valid = false; - tick = 0; - - if (line == null) { - cmd = Altos.AO_LOG_INVALID; - line = ""; - } else { - try { - String[] tokens = line.split("\\s+"); - - if (tokens[0].length() == 1) { - if (tokens.length != 2 + data_length) { - cmd = Altos.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 = Altos.AO_LOG_CONFIG_VERSION; - data = tokens[2]; - } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { - cmd = Altos.AO_LOG_MAIN_DEPLOY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { - cmd = Altos.AO_LOG_APOGEE_DELAY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { - cmd = Altos.AO_LOG_RADIO_CHANNEL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Callsign:")) { - cmd = Altos.AO_LOG_CALLSIGN; - data = tokens[1].replaceAll("\"",""); - } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { - cmd = Altos.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 = Altos.AO_LOG_RADIO_CAL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { - cmd = Altos.AO_LOG_MAX_FLIGHT_LOG; - a = Integer.parseInt(tokens[3]); - } else if (tokens[0].equals("manufacturer")) { - cmd = Altos.AO_LOG_MANUFACTURER; - data = tokens[1]; - } else if (tokens[0].equals("product")) { - cmd = Altos.AO_LOG_PRODUCT; - data = tokens[1]; - } else if (tokens[0].equals("serial-number")) { - cmd = Altos.AO_LOG_SERIAL_NUMBER; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("log-format")) { - cmd = Altos.AO_LOG_LOG_FORMAT; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("software-version")) { - cmd = Altos.AO_LOG_SOFTWARE_VERSION; - data = tokens[1]; - } else if (tokens[0].equals("ms5607")) { - if (tokens[1].equals("reserved:")) { - cmd = Altos.AO_LOG_BARO_RESERVED; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("sens:")) { - cmd = Altos.AO_LOG_BARO_SENS; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("off:")) { - cmd = Altos.AO_LOG_BARO_OFF; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tcs:")) { - cmd = Altos.AO_LOG_BARO_TCS; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tco:")) { - cmd = Altos.AO_LOG_BARO_TCO; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tref:")) { - cmd = Altos.AO_LOG_BARO_TREF; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tempsens:")) { - cmd = Altos.AO_LOG_BARO_TEMPSENS; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("crc:")) { - cmd = Altos.AO_LOG_BARO_CRC; - a = Integer.parseInt(tokens[2]); - } else { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } else { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } catch (NumberFormatException ne) { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } - } - - public AltosEepromMega(int in_cmd, int in_tick) { - cmd = in_cmd; - tick = in_tick; - valid = true; - } -} diff --git a/altosui/AltosEepromMegaIterable.java b/altosui/AltosEepromMegaIterable.java deleted file mode 100644 index e2cd2785..00000000 --- a/altosui/AltosEepromMegaIterable.java +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * 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 { - - 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 AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { - super(in_cmd, in_tick); - a = in_a; - b = in_b; - index = in_index; - } - - public String toString() { - return String.format("%d.%d %04x %04x %04x", - cmd, index, tick, a, b); - } - - public int compareTo(AltosOrderedMegaRecord o) { - int tick_diff = tick - o.tick; - if (tick_diff != 0) - return tick_diff; - return index - o.index; - } -} - -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 records; - - AltosMs5607 baro; - - LinkedList list; - - class EepromState { - int seen; - int n_pad_samples; - double ground_pres; - int gps_tick; - int boost_tick; - int sensor_tick; - - EepromState() { - seen = 0; - n_pad_samples = 0; - ground_pres = 0.0; - gps_tick = 0; - } - } - - void update_state(AltosRecord state, AltosEepromMega record, EepromState eeprom) { - state.tick = record.tick; - switch (record.cmd) { - case Altos.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 Altos.AO_LOG_SENSOR: - state.accel = record.accel(); - state.pres = baro.set(record.pres(), record.temp()); - 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 < Altos.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 Altos.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 |= seen_sensor; - break; - case Altos.AO_LOG_TEMP_VOLT: - state.batt = record.v_batt(); - eeprom.seen |= seen_temp_volt; - break; - case Altos.AO_LOG_DEPLOY: - state.drogue = record.a; - state.main = record.b; - eeprom.seen |= seen_deploy; - has_ignite = true; - break; - case Altos.AO_LOG_STATE: - state.state = record.state(); - break; - case Altos.AO_LOG_GPS_TIME: - eeprom.gps_tick = state.tick; - AltosGPS old = state.gps; - state.gps = new AltosGPS(); - - /* GPS date doesn't get repeated through the file */ - if (old != null) { - state.gps.year = old.year; - state.gps.month = old.month; - state.gps.day = old.day; - } - state.gps.hour = (record.a & 0xff); - state.gps.minute = (record.a >> 8); - state.gps.second = (record.b & 0xff); - - int flags = (record.b >> 8); - state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0; - state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0; - state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >> - Altos.AO_GPS_NUM_SAT_SHIFT; - state.new_gps = true; - has_gps = true; - break; - case Altos.AO_LOG_GPS_LAT: - int lat32 = record.a | (record.b << 16); - state.gps.lat = (double) lat32 / 1e7; - break; - case Altos.AO_LOG_GPS_LON: - int lon32 = record.a | (record.b << 16); - state.gps.lon = (double) lon32 / 1e7; - break; - case Altos.AO_LOG_GPS_ALT: - state.gps.alt = record.a; - break; - case Altos.AO_LOG_GPS_SAT: - if (state.tick == eeprom.gps_tick) { - int svid = record.a; - int c_n0 = record.b >> 8; - state.gps.add_sat(svid, c_n0); - } - break; - case Altos.AO_LOG_GPS_DATE: - state.gps.year = (record.a & 0xff) + 2000; - state.gps.month = record.a >> 8; - state.gps.day = record.b & 0xff; - break; - - case Altos.AO_LOG_CONFIG_VERSION: - break; - case Altos.AO_LOG_MAIN_DEPLOY: - break; - case Altos.AO_LOG_APOGEE_DELAY: - break; - case Altos.AO_LOG_RADIO_CHANNEL: - break; - case Altos.AO_LOG_CALLSIGN: - state.callsign = record.data; - break; - case Altos.AO_LOG_ACCEL_CAL: - state.accel_plus_g = record.a; - state.accel_minus_g = record.b; - break; - case Altos.AO_LOG_RADIO_CAL: - break; - case Altos.AO_LOG_MANUFACTURER: - break; - case Altos.AO_LOG_PRODUCT: - break; - case Altos.AO_LOG_SERIAL_NUMBER: - state.serial = record.a; - break; - case Altos.AO_LOG_SOFTWARE_VERSION: - break; - case Altos.AO_LOG_BARO_RESERVED: - baro.reserved = record.a; - break; - case Altos.AO_LOG_BARO_SENS: - baro.sens =record.a; - break; - case Altos.AO_LOG_BARO_OFF: - baro.off =record.a; - break; - case Altos.AO_LOG_BARO_TCS: - baro.tcs =record.a; - break; - case Altos.AO_LOG_BARO_TCO: - baro.tco =record.a; - break; - case Altos.AO_LOG_BARO_TREF: - baro.tref =record.a; - break; - case Altos.AO_LOG_BARO_TEMPSENS: - baro.tempsens =record.a; - break; - case Altos.AO_LOG_BARO_CRC: - baro.crc =record.a; - break; - } - state.seen |= eeprom.seen; - } - - LinkedList make_list() { - LinkedList list = new LinkedList(); - Iterator iterator = records.iterator(); - AltosOrderedMegaRecord record = null; - AltosRecord state = new AltosRecord(); - boolean last_reported = false; - EepromState eeprom = new EepromState(); - - state.state = Altos.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) { - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - } - update_state(state, record, eeprom); - } - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - return list; - } - - public Iterator iterator() { - if (list == null) - list = make_list(); - return list.iterator(); - } - - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; } - - public void write_comments(PrintStream out) { - Iterator iterator = records.iterator(); - out.printf("# Comments\n"); - while (iterator.hasNext()) { - AltosOrderedMegaRecord record = iterator.next(); - switch (record.cmd) { - case Altos.AO_LOG_CONFIG_VERSION: - out.printf("# Config version: %s\n", record.data); - break; - case Altos.AO_LOG_MAIN_DEPLOY: - out.printf("# Main deploy: %s\n", record.a); - break; - case Altos.AO_LOG_APOGEE_DELAY: - out.printf("# Apogee delay: %s\n", record.a); - break; - case Altos.AO_LOG_RADIO_CHANNEL: - out.printf("# Radio channel: %s\n", record.a); - break; - case Altos.AO_LOG_CALLSIGN: - out.printf("# Callsign: %s\n", record.data); - break; - case Altos.AO_LOG_ACCEL_CAL: - out.printf ("# Accel cal: %d %d\n", record.a, record.b); - break; - case Altos.AO_LOG_RADIO_CAL: - out.printf ("# Radio cal: %d\n", record.a); - break; - case Altos.AO_LOG_MAX_FLIGHT_LOG: - out.printf ("# Max flight log: %d\n", record.a); - break; - case Altos.AO_LOG_MANUFACTURER: - out.printf ("# Manufacturer: %s\n", record.data); - break; - case Altos.AO_LOG_PRODUCT: - out.printf ("# Product: %s\n", record.data); - break; - case Altos.AO_LOG_SERIAL_NUMBER: - out.printf ("# Serial number: %d\n", record.a); - break; - case Altos.AO_LOG_SOFTWARE_VERSION: - out.printf ("# Software version: %s\n", record.data); - break; - case Altos.AO_LOG_BARO_RESERVED: - out.printf ("# Baro reserved: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_SENS: - out.printf ("# Baro sens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_OFF: - out.printf ("# Baro off: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCS: - out.printf ("# Baro tcs: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCO: - out.printf ("# Baro tco: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TREF: - out.printf ("# Baro tref: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TEMPSENS: - out.printf ("# Baro tempsens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_CRC: - out.printf ("# Baro crc: %d\n", record.a); - break; - } - } - } - - /* - * Given an AO_LOG_GPS_TIME record with correct time, and one - * missing time, rewrite the missing time values with the good - * ones, assuming that the difference between them is 'diff' seconds - */ - void update_time(AltosOrderedMegaRecord good, AltosOrderedMegaRecord 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 & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4) - flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT); - flags |= Altos.AO_GPS_RUNNING; - flags |= Altos.AO_GPS_VALID; - - int new_seconds = seconds + diff; - if (new_seconds < 0) - new_seconds += 24 * 3600; - int new_second = (new_seconds % 60); - int new_minutes = (new_seconds / 60); - int new_minute = (new_minutes % 60); - int new_hours = (new_minutes / 60); - int new_hour = (new_hours % 24); - - bad.a = new_hour + (new_minute << 8); - bad.b = new_second + (flags << 8); - } - - /* - * Read the whole file, dumping records into a RB tree so - * we can enumerate them in time order -- the eeprom data - * are sometimes out of order with GPS data getting timestamps - * matching the first packet out of the GPS unit but not - * written until the final GPS packet has been received. - */ - public AltosEepromMegaIterable (FileInputStream input) { - records = new TreeSet(); - - 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 = AltosRecord.gets(input); - if (line == null) - break; - AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); - if (record == null) - break; - if (record.cmd == Altos.AO_LOG_INVALID) - continue; - prev_tick = record.tick; - if (record.cmd < Altos.AO_LOG_CONFIG_VERSION) - prev_tick_valid = true; - if (record.cmd == Altos.AO_LOG_FLIGHT) { - flight_record = record; - continue; - } - - /* Two firmware bugs caused the loss of some GPS data. - * The flight date would never be recorded, and often - * the flight time would get overwritten by another - * record. Detect the loss of the GPS date and fix up the - * missing time records - */ - if (record.cmd == Altos.AO_LOG_GPS_DATE) { - gps_date_record = record; - continue; - } - - /* go back and fix up any missing time values */ - if (record.cmd == Altos.AO_LOG_GPS_TIME) { - last_gps_time = record; - if (missing_time) { - Iterator iterator = records.iterator(); - while (iterator.hasNext()) { - AltosOrderedMegaRecord old = iterator.next(); - if (old.cmd == Altos.AO_LOG_GPS_TIME && - old.a == -1 && old.b == -1) - { - update_time(record, old); - } - } - missing_time = false; - } - } - - if (record.cmd == Altos.AO_LOG_GPS_LAT) { - if (last_gps_time == null || last_gps_time.tick != record.tick) { - AltosOrderedMegaRecord add_gps_time = new AltosOrderedMegaRecord(Altos.AO_LOG_GPS_TIME, - record.tick, - -1, -1, index-1); - if (last_gps_time != null) - update_time(last_gps_time, add_gps_time); - else - missing_time = true; - - records.add(add_gps_time); - record.index = index++; - } - } - records.add(record); - - /* Bail after reading the 'landed' record; we're all done */ - if (record.cmd == Altos.AO_LOG_STATE && - record.a == Altos.ao_flight_landed) - break; - } - } catch (IOException io) { - } catch (ParseException pe) { - } - try { - input.close(); - } catch (IOException ie) { - } - } -} diff --git a/altosui/AltosFlightStatusUpdate.java b/altosui/AltosFlightStatusUpdate.java index a600bd02..d70fc7f8 100644 --- a/altosui/AltosFlightStatusUpdate.java +++ b/altosui/AltosFlightStatusUpdate.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosFlightStatusUpdate implements ActionListener { diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 3abdb645..5768ba71 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -317,74 +317,6 @@ public class AltosSerial extends AltosLink implements Runnable { set_channel(AltosConvert.radio_frequency_to_channel(frequency)); } - public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - if (frequency == 0.0) - frequency = AltosPreferences.frequency(device.getSerial()); - config_data(); - set_radio_frequency(frequency, - config_data.radio_frequency != 0, - config_data.radio_setting != 0, - config_data.radio_calibration); - } - - public void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - if (altos != null) { - if (monitor_mode) - printf("m 0\nm %x\n", telemetry_len()); - flush_output(); - } - } - - void set_monitor(boolean monitor) { - monitor_mode = monitor; - if (altos != null) { - if (monitor) - printf("m %x\n", telemetry_len()); - else - printf("m 0\n"); - flush_output(); - } - } - - public void set_callsign(String callsign) { - if (altos != null) { - printf ("c c %s\n", callsign); - flush_output(); - } - } - - public AltosConfigData config_data() throws InterruptedException, TimeoutException { - if (config_data == null) - config_data = new AltosConfigData(this); - return config_data; - } - - public void start_remote() throws TimeoutException, InterruptedException { - if (debug) - System.out.printf("start remote %7.3f\n", frequency); - if (frequency == 0.0) - frequency = AltosUIPreferences.frequency(device.getSerial()); - set_radio_frequency(frequency); - set_callsign(AltosUIPreferences.callsign()); - printf("p\nE 0\n"); - flush_input(); - remote = true; - } - - public void stop_remote() throws InterruptedException { - if (debug) - System.out.printf("stop remote\n"); - try { - flush_input(); - } finally { - printf ("~\n"); - flush_output(); - } - remote = false; - } - public void set_frame(Frame in_frame) { frame = in_frame; } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 9fc7b5b3..feda00c7 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -40,8 +40,6 @@ altosui_JAVA = \ AltosEepromList.java \ AltosEepromManage.java \ AltosEepromMonitor.java \ - AltosEepromMega.java \ - AltosEepromMegaIterable.java \ AltosEepromSelect.java \ AltosFlash.java \ AltosFlashUI.java \ -- cgit v1.2.3 From 5634192a6036c6c7b47d224e2988e81bb71a4557 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Jun 2012 20:55:33 -0700 Subject: altosui: attempt to get ms5607 data into .mega files was misinformed The ms5607 'p' command also means 'go into packet mode', which nicely broke attempts to communicate with teledongle Signed-off-by: Keith Packard --- altoslib/AltosConfigData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altoslib') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index fa6a72b5..ecc2d0aa 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -132,7 +132,7 @@ public class AltosConfigData implements Iterable { } public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { - link.printf("c s\np\nf\nl\nv\n"); + link.printf("c s\nf\nl\nv\n"); lines = new LinkedList(); radio_setting = 0; radio_frequency = 0; -- cgit v1.2.3 From b8c363d9411fd5e79e3f806894dbc12bcc106b88 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Jun 2012 20:56:25 -0700 Subject: altosui: More changes to migrate code to altoslib Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 1 + altosui/Altos.java | 184 --------------------------------------- altosui/AltosEepromDownload.java | 10 +-- 3 files changed, 6 insertions(+), 189 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 27d72079..e74eaf99 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -185,6 +185,7 @@ public class AltosLib { public static final int AO_LOG_FORMAT_TINY = 2; 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_MEGAMETRUM = 5; public static final int AO_LOG_FORMAT_NONE = 127; public static boolean isspace(int c) { diff --git a/altosui/Altos.java b/altosui/Altos.java index 351927ee..78e56970 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -86,190 +86,6 @@ public class Altos extends AltosLib { return state_to_string[state]; } - static final int AO_GPS_VALID = (1 << 4); - static final int AO_GPS_RUNNING = (1 << 5); - static final int AO_GPS_DATE_VALID = (1 << 6); - static final int AO_GPS_NUM_SAT_SHIFT = 0; - static final int AO_GPS_NUM_SAT_MASK = 0xf; - - static final int AO_LOG_FORMAT_UNKNOWN = 0; - static final int AO_LOG_FORMAT_FULL = 1; - static final int AO_LOG_FORMAT_TINY = 2; - static final int AO_LOG_FORMAT_TELEMETRY = 3; - static final int AO_LOG_FORMAT_TELESCIENCE = 4; - static final int AO_LOG_FORMAT_MEGAMETRUM = 5; - static final int AO_LOG_FORMAT_NONE = 127; - - static boolean isspace(int c) { - switch (c) { - case ' ': - case '\t': - return true; - } - return false; - } - - static boolean ishex(int c) { - if ('0' <= c && c <= '9') - return true; - if ('a' <= c && c <= 'f') - return true; - if ('A' <= c && c <= 'F') - return true; - return false; - } - - static boolean ishex(String s) { - for (int i = 0; i < s.length(); i++) - if (!ishex(s.charAt(i))) - return false; - return true; - } - - static int fromhex(int c) { - if ('0' <= c && c <= '9') - return c - '0'; - if ('a' <= c && c <= 'f') - return c - 'a' + 10; - if ('A' <= c && c <= 'F') - return c - 'A' + 10; - return -1; - } - - static int fromhex(String s) throws NumberFormatException { - int c, v = 0; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (!ishex(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - return v; - } - v = v * 16 + fromhex(c); - } - return v; - } - - static boolean isdec(int c) { - if ('0' <= c && c <= '9') - return true; - return false; - } - - static boolean isdec(String s) { - for (int i = 0; i < s.length(); i++) - if (!isdec(s.charAt(i))) - return false; - return true; - } - - static int fromdec(int c) { - if ('0' <= c && c <= '9') - return c - '0'; - return -1; - } - - static int int8(int[] bytes, int i) { - return (int) (byte) bytes[i]; - } - - static int uint8(int[] bytes, int i) { - return bytes[i]; - } - - static int int16(int[] bytes, int i) { - return (int) (short) (bytes[i] + (bytes[i+1] << 8)); - } - - static int uint16(int[] bytes, int i) { - return bytes[i] + (bytes[i+1] << 8); - } - - static int uint32(int[] bytes, int i) { - return bytes[i] + - (bytes[i+1] << 8) + - (bytes[i+2] << 16) + - (bytes[i+3] << 24); - } - - static final Charset unicode_set = Charset.forName("UTF-8"); - - static String string(int[] bytes, int s, int l) { - if (s + l > bytes.length) { - if (s > bytes.length) { - s = bytes.length; - l = 0; - } else { - l = bytes.length - s; - } - } - - int i; - for (i = l - 1; i >= 0; i--) - if (bytes[s+i] != 0) - break; - - l = i + 1; - byte[] b = new byte[l]; - - for (i = 0; i < l; i++) - b[i] = (byte) bytes[s+i]; - String n = new String(b, unicode_set); - return n; - } - - static int hexbyte(String s, int i) { - int c0, c1; - - if (s.length() < i + 2) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - c0 = s.charAt(i); - if (!Altos.ishex(c0)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); - c1 = s.charAt(i+1); - if (!Altos.ishex(c1)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); - return Altos.fromhex(c0) * 16 + Altos.fromhex(c1); - } - - static int[] hexbytes(String s) { - int n; - int[] r; - int i; - - if ((s.length() & 1) != 0) - throw new NumberFormatException(String.format("invalid line \"%s\"", s)); - n = s.length() / 2; - r = new int[n]; - for (i = 0; i < n; i++) - r[i] = Altos.hexbyte(s, i * 2); - return r; - } - - static int fromdec(String s) throws NumberFormatException { - int c, v = 0; - int sign = 1; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (i == 0 && c == '-') { - sign = -1; - } else if (!isdec(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid number \"%s\"", s)); - return v; - } else - v = v * 10 + fromdec(c); - } - return v * sign; - } - - static String replace_extension(String input, String extension) { - int dot = input.lastIndexOf("."); - if (dot > 0) - input = input.substring(0,dot); - return input.concat(extension); - } - static public boolean initialized = false; static public boolean loaded_library = false; diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 080bfc99..d1e5fdf0 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -357,23 +357,23 @@ public class AltosEepromDownload implements Runnable { } switch (log_format) { - case Altos.AO_LOG_FORMAT_FULL: + case AltosLib.AO_LOG_FORMAT_FULL: extension = "eeprom"; CaptureFull(eechunk); break; - case Altos.AO_LOG_FORMAT_TINY: + case AltosLib.AO_LOG_FORMAT_TINY: extension = "eeprom"; CaptureTiny(eechunk); break; - case Altos.AO_LOG_FORMAT_TELEMETRY: + case AltosLib.AO_LOG_FORMAT_TELEMETRY: extension = "telem"; CaptureTelemetry(eechunk); break; - case Altos.AO_LOG_FORMAT_TELESCIENCE: + case AltosLib.AO_LOG_FORMAT_TELESCIENCE: extension = "science"; CaptureTeleScience(eechunk); break; - case Altos.AO_LOG_FORMAT_MEGAMETRUM: + case AltosLib.AO_LOG_FORMAT_MEGAMETRUM: extension = "mega"; CaptureMega(eechunk); } -- cgit v1.2.3 From ca310342d7b0bd1b78318cae38d920b8690dfd36 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 16:09:43 -0700 Subject: altosui: Catch timeout errors when setting up TD telem monitoring Close the port in this case so it can be used for other things. Signed-off-by: Keith Packard --- altoslib/AltosTelemetryReader.java | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 112e008e..911a099a 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -106,14 +106,22 @@ public class AltosTelemetryReader extends AltosFlightReader { public AltosTelemetryReader (AltosLink in_link) throws IOException, InterruptedException, TimeoutException { link = in_link; - log = new AltosLog(link); - name = link.name; - previous = null; - telem = new LinkedBlockingQueue(); - frequency = AltosPreferences.frequency(link.serial); - set_frequency(frequency); - telemetry = AltosPreferences.telemetry(link.serial); - set_telemetry(telemetry); - link.add_monitor(telem); + try { + log = new AltosLog(link); + name = link.name; + previous = null; + telem = new LinkedBlockingQueue(); + 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); + } } } -- cgit v1.2.3 From 55747ce210d7d80d5b4fdaaf9dc7ee0f7bc8b0a3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 18:58:56 -0700 Subject: altosui: Move product definitions from AltosUI to AltosLib Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 24 ++++++++++++ altosui/Altos.java | 85 ------------------------------------------ altosui/AltosBTDevice.java | 1 + altosui/AltosBTKnown.java | 10 ++++- altosui/AltosConfig.java | 2 +- altosui/AltosConfigureUI.java | 2 +- altosui/AltosDeviceDialog.java | 4 +- altosui/AltosUI.java | 1 + 8 files changed, 39 insertions(+), 90 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index e74eaf99..4a779c55 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -78,6 +78,30 @@ public class AltosLib { public static final int ao_flight_landed = 8; public static final int ao_flight_invalid = 9; + /* USB product IDs */ + public final static int vendor_altusmetrum = 0xfffe; + + public final static int product_altusmetrum = 0x000a; + public final static int product_telemetrum = 0x000b; + public final static int product_teledongle = 0x000c; + public final static int product_teleterra = 0x000d; + public final static int product_telebt = 0x000e; + public final static int product_telelaunch = 0x000f; + public final static int product_telelco = 0x0010; + public final static int product_telescience = 0x0011; + public final static int product_telepyro =0x0012; + public final static int product_megametrum = 0x0023; + public final static int product_megadongle = 0x0024; + public final static int product_altusmetrum_min = 0x000a; + public final static int product_altusmetrum_max = 0x0024; + + public final static int product_any = 0x10000; + public final static int product_basestation = 0x10000 + 1; + public final static int product_altimeter = 0x10000 + 2; + + /* Bluetooth "identifier" (bluetooth sucks) */ + public final static String bt_product_telebt = "TeleBT"; + /* Telemetry modes */ public static final int ao_telemetry_off = 0; public static final int ao_telemetry_min = 1; diff --git a/altosui/Altos.java b/altosui/Altos.java index 78e56970..e60b3aaa 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -108,89 +108,4 @@ public class Altos extends AltosLib { } return loaded_library; } - - static int usb_vendor_altusmetrum() { - load_library(); - return 0xfffe; - } - - static int usb_product_altusmetrum() { - load_library(); - return 0x000a; - } - - static int usb_product_altusmetrum_min() { - load_library(); - return 0x000a; - } - - static int usb_product_altusmetrum_max() { - load_library(); - return 0x0013; - } - - static int usb_product_telemetrum() { - load_library(); - return 0x000b; - } - - static int usb_product_teledongle() { - load_library(); - return 0x000c; - } - - static int usb_product_teleterra() { - load_library(); - return 0x000d; - } - - static int usb_product_telebt() { - load_library(); - return 0x000e; - } - - static int usb_product_telelaunch() { - load_library(); - return 0x000f; - } - - static int usb_product_telelco() { - load_library(); - return 0x0010; - } - - static int usb_product_telescience() { - load_library(); - return 0x0011; - } - - static int usb_product_telepyro() { - load_library(); - return 0x0012; - } - - public final static int vendor_altusmetrum = usb_vendor_altusmetrum(); - public final static int product_altusmetrum = usb_product_altusmetrum(); - public final static int product_telemetrum = usb_product_telemetrum(); - public final static int product_teledongle = usb_product_teledongle(); - public final static int product_teleterra = usb_product_teleterra(); - public final static int product_telebt = usb_product_telebt(); - public final static int product_telelaunch = usb_product_telelaunch(); - public final static int product_tele10 = usb_product_telelco(); - public final static int product_telescience = usb_product_telescience(); - public final static int product_telepyro = usb_product_telepyro(); - public final static int product_altusmetrum_min = usb_product_altusmetrum_min(); - public final static int product_altusmetrum_max = usb_product_altusmetrum_max(); - - public final static int product_any = 0x10000; - public final static int product_basestation = 0x10000 + 1; - - static String bt_product_telebt() { - load_library(); - return "TeleBT"; - } - - public final static String bt_product_telebt = bt_product_telebt(); - - public static AltosBTKnown bt_known = new AltosBTKnown(); } diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 55b8f8fc..f6926b10 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -116,6 +116,7 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { } public AltosBTDevice(String name, String addr) { + Altos.load_library(); libaltos.altos_bt_fill_in(name, addr,this); } diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index e30be057..021e4d0b 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -94,4 +94,12 @@ public class AltosBTKnown implements Iterable { bt_pref = AltosUIPreferences.bt_devices(); load(); } -} \ No newline at end of file + + static AltosBTKnown known; + + static public AltosBTKnown bt_known() { + if (known == null) + known = new AltosBTKnown(); + return known; + } +} diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 35fef080..cae41858 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -491,7 +491,7 @@ public class AltosConfig implements ActionListener { try { serial_line = new AltosSerial(device); try { - if (!device.matchProduct(Altos.product_telemetrum)) + if (!device.matchProduct(Altos.product_altimeter)) remote = true; init_ui(); } catch (InterruptedException ie) { diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index deb179d6..d0ed9325 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -344,7 +344,7 @@ public class AltosConfigureUI manage_bluetooth = new JButton("Manage Bluetooth"); manage_bluetooth.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - AltosBTManage.show(owner, Altos.bt_known); + AltosBTManage.show(owner, AltosBTKnown.bt_known()); } }); c.gridx = 0; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index e53e75c1..fa9d0013 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -41,7 +41,7 @@ public class AltosDeviceDialog extends AltosDialog implements ActionListener { private AltosDevice[] devices() { java.util.List usb_devices = AltosUSBDevice.list(product); int num_devices = usb_devices.size(); - java.util.List bt_devices = Altos.bt_known.list(product); + java.util.List bt_devices = AltosBTKnown.bt_known().list(product); num_devices += bt_devices.size(); AltosDevice[] devices = new AltosDevice[num_devices]; @@ -169,7 +169,7 @@ public class AltosDeviceDialog extends AltosDialog implements ActionListener { if ("select".equals(e.getActionCommand())) value = (AltosDevice)(list.getSelectedValue()); if ("manage".equals(e.getActionCommand())) { - AltosBTManage.show(frame, Altos.bt_known); + AltosBTManage.show(frame, AltosBTKnown.bt_known()); update_devices(); return; } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 538f8734..926d66f0 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -538,6 +538,7 @@ public class AltosUI extends AltosFrame { } public static void main(final String[] args) { + load_library(null); try { UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel()); } catch (Exception e) { -- cgit v1.2.3 From 4cb46b8a84a0dd5b8fcb479d7aa5157480e1bc67 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 19:01:24 -0700 Subject: altosui: Add rudimentary MM support to altosui Decoded the MM sensor packets as if they were TM packets. Add the USB ids. Add class of 'altimeter' devices and match those instead of just telemetrum as appropriate. Signed-off-by: Keith Packard --- altoslib/AltosTelemetryRecord.java | 2 ++ altosui/AltosIdleMonitorUI.java | 2 +- altosui/AltosIgnite.java | 2 +- altosui/AltosUSBDevice.java | 7 ++++++- 4 files changed, 10 insertions(+), 3 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java index 4292dae8..6b6a252d 100644 --- a/altoslib/AltosTelemetryRecord.java +++ b/altoslib/AltosTelemetryRecord.java @@ -42,6 +42,7 @@ public abstract class AltosTelemetryRecord { 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; static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { AltosTelemetryRecord r; @@ -75,6 +76,7 @@ public abstract class AltosTelemetryRecord { case packet_type_TM_sensor: case packet_type_Tm_sensor: case packet_type_Tn_sensor: + case packet_type_MM_sensor: r = new AltosTelemetryRecordSensor(bytes, rssi); break; case packet_type_configuration: diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 02295ea9..2ee90937 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -325,7 +325,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay device = AltosDeviceDialog.show(in_owner, Altos.product_any); remote = false; - if (!device.matchProduct(Altos.product_telemetrum)) + if (!device.matchProduct(Altos.product_altimeter)) remote = true; serial = device.getSerial(); diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index c0cd44f1..45d37d16 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -178,7 +178,7 @@ public class AltosIgnite { serial = new AltosSerial(device); remote = false; - if (!device.matchProduct(Altos.product_telemetrum)) + if (!device.matchProduct(Altos.product_altimeter)) remote = true; } } \ No newline at end of file diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java index b11a3934..ed5f8307 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosui/AltosUSBDevice.java @@ -71,7 +71,12 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { if (want_product == Altos.product_basestation) return matchProduct(Altos.product_teledongle) || matchProduct(Altos.product_teleterra) || - matchProduct(Altos.product_telebt); + matchProduct(Altos.product_telebt) || + matchProduct(Altos.product_megadongle); + + if (want_product == Altos.product_altimeter) + return matchProduct(Altos.product_telemetrum) || + matchProduct(Altos.product_megametrum); int have_product = getProduct(); -- cgit v1.2.3 From 6f421818fd7062f03bfaf9e606d6a4cfdcb13b49 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 21 Jun 2012 09:50:18 -0700 Subject: altosui: Support MM telemetry packets Required restructuring the whole telemetry system to provide abstract interfaces to flight data. Signed-off-by: Keith Packard --- altoslib/AltosEepromIterable.java | 10 +- altoslib/AltosEepromMegaIterable.java | 32 ++-- altoslib/AltosLib.java | 20 +++ altoslib/AltosMs5607.java | 7 + altoslib/AltosRecord.java | 225 +++++++-------------------- altoslib/AltosRecordMM.java | 186 ++++++++++++++++++++++ altoslib/AltosRecordTM.java | 199 +++++++++++++++++++++++ altoslib/AltosTelemetry.java | 2 +- altoslib/AltosTelemetryIterable.java | 6 +- altoslib/AltosTelemetryRecord.java | 8 +- altoslib/AltosTelemetryRecordLegacy.java | 8 +- altoslib/AltosTelemetryRecordMegaData.java | 96 ++++++++++++ altoslib/AltosTelemetryRecordMegaSensor.java | 98 ++++++++++++ altoslib/AltosTelemetryRecordRaw.java | 6 +- altoslib/AltosTelemetryRecordSensor.java | 10 +- altoslib/Makefile.am | 4 + altosui/AltosCSV.java | 8 +- altosui/AltosIdleMonitorUI.java | 23 +-- 18 files changed, 735 insertions(+), 213 deletions(-) create mode 100644 altoslib/AltosRecordMM.java create mode 100644 altoslib/AltosRecordTM.java create mode 100644 altoslib/AltosTelemetryRecordMegaData.java create mode 100644 altoslib/AltosTelemetryRecordMegaSensor.java (limited to 'altoslib') diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index a923d63b..f8acdc16 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -104,7 +104,7 @@ public class AltosEepromIterable extends AltosRecordIterable { } } - void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { + void update_state(AltosRecordTM state, AltosEepromRecord record, EepromState eeprom) { state.tick = record.tick; switch (record.cmd) { case AltosLib.AO_LOG_FLIGHT: @@ -237,7 +237,7 @@ public class AltosEepromIterable extends AltosRecordIterable { LinkedList list = new LinkedList(); Iterator iterator = records.iterator(); AltosOrderedRecord record = null; - AltosRecord state = new AltosRecord(); + AltosRecordTM state = new AltosRecordTM(); boolean last_reported = false; EepromState eeprom = new EepromState(); @@ -254,13 +254,13 @@ public class AltosEepromIterable extends AltosRecordIterable { while (iterator.hasNext()) { record = iterator.next(); if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { - AltosRecord r = new AltosRecord(state); + AltosRecordTM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); } update_state(state, record, eeprom); } - AltosRecord r = new AltosRecord(state); + AltosRecordTM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); return list; @@ -399,7 +399,7 @@ public class AltosEepromIterable extends AltosRecordIterable { try { for (;;) { - String line = AltosRecord.gets(input); + String line = AltosLib.gets(input); if (line == null) break; AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java index 28a298b3..f62cc45b 100644 --- a/altoslib/AltosEepromMegaIterable.java +++ b/altoslib/AltosEepromMegaIterable.java @@ -108,7 +108,7 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { } } - void update_state(AltosRecord state, AltosEepromMega record, EepromState eeprom) { + void update_state(AltosRecordMM state, AltosEepromMega record, EepromState eeprom) { state.tick = record.tick; switch (record.cmd) { case AltosLib.AO_LOG_FLIGHT: @@ -122,7 +122,8 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { break; case AltosLib.AO_LOG_SENSOR: state.accel = record.accel(); - state.pres = baro.set(record.pres(), record.temp()); + 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(); @@ -161,15 +162,20 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { eeprom.seen |= seen_sensor; break; case AltosLib.AO_LOG_TEMP_VOLT: - state.batt = record.v_batt(); + state.v_batt = record.v_batt(); + state.v_pyro = record.v_pbatt(); + for (int i = 0; i < AltosRecordMM.num_sense; i++) + state.sense[i] = record.sense(i); eeprom.seen |= seen_temp_volt; break; - case AltosLib.AO_LOG_DEPLOY: - state.drogue = record.a; - state.main = record.b; - eeprom.seen |= seen_deploy; - has_ignite = true; - break; +// +// case AltosLib.AO_LOG_DEPLOY: +// state.drogue = record.a; +// state.main = record.b; +// eeprom.seen |= seen_deploy; +// has_ignite = true; +// break; + case AltosLib.AO_LOG_STATE: state.state = record.state(); break; @@ -278,7 +284,7 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { LinkedList list = new LinkedList(); Iterator iterator = records.iterator(); AltosOrderedMegaRecord record = null; - AltosRecord state = new AltosRecord(); + AltosRecordMM state = new AltosRecordMM(); boolean last_reported = false; EepromState eeprom = new EepromState(); @@ -295,13 +301,13 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { while (iterator.hasNext()) { record = iterator.next(); if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { - AltosRecord r = new AltosRecord(state); + AltosRecordMM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); } update_state(state, record, eeprom); } - AltosRecord r = new AltosRecord(state); + AltosRecordMM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); return list; @@ -442,7 +448,7 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { try { for (;;) { - String line = AltosRecord.gets(input); + String line = AltosLib.gets(input); if (line == null) break; AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 4a779c55..2402331e 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -20,6 +20,7 @@ package org.altusmetrum.AltosLib; import java.awt.*; import java.util.*; import java.text.*; +import java.io.*; import java.nio.charset.Charset; public class AltosLib { @@ -304,6 +305,10 @@ public class AltosLib { (bytes[i+3] << 24); } + public static int int32(int[] bytes, int i) { + return (int) uint32(bytes, i); + } + public static final Charset unicode_set = Charset.forName("UTF-8"); public static String string(int[] bytes, int s, int l) { @@ -375,6 +380,21 @@ public class AltosLib { return v * sign; } + public static String gets(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') { + return line; + } + line = line + (char) c; + } + return null; + } + public static String replace_extension(String input, String extension) { int dot = input.lastIndexOf("."); if (dot > 0) diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index a7b902e2..5fd997d8 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -73,4 +73,11 @@ public class AltosMs5607 { convert(); return pa; } + + public AltosMs5607() { + raw_pres = AltosRecord.MISSING; + raw_temp = AltosRecord.MISSING; + pa = AltosRecord.MISSING; + cc = AltosRecord.MISSING; + } } diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index 10ef3061..e468f84b 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -22,8 +22,7 @@ import java.text.*; import java.util.HashMap; import java.io.*; -public class AltosRecord implements Comparable { - public final static int MISSING = 0x7fffffff; +public class AltosRecord implements Comparable , Cloneable { public static final int seen_flight = 1; public static final int seen_sensor = 2; @@ -33,8 +32,13 @@ public class AltosRecord implements Comparable { 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 int seen; + + public final static int MISSING = 0x7fffffff; + + /* Every AltosRecord implementation provides these fields */ + public int version; public String callsign; public int serial; @@ -44,31 +48,13 @@ public class AltosRecord implements Comparable { public int state; public int tick; - 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 double acceleration; - public double speed; - public double height; - - public int flight_accel; - public int flight_vel; - public int flight_pres; + /* Current flight dynamic state */ + public double acceleration; /* m/s² */ + public double speed; /* m/s */ + public double height; /* m */ public AltosGPS gps; - public boolean new_gps; - - public AltosIMU imu; - public AltosMag mag; + public boolean new_gps; public double time; /* seconds since boost */ @@ -83,45 +69,42 @@ public class AltosRecord implements Comparable { public AltosRecordCompanion companion; /* - * Values for our MP3H6115A pressure sensor - * - * From the data sheet: + * Abstract methods that convert record data + * to standard units: * - * 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 + * pressure: Pa + * voltage: V + * acceleration: m/s² + * speed: m/s + * height: m + * temperature: °C */ - public static final double counts_per_kPa = 27 * 2047 / 3300; - public static final double counts_at_101_3kPa = 1674.0; + public double raw_pressure() { return MISSING; } - public static double - barometer_to_pressure(double count) - { - return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; - } + public double filtered_pressure() { return MISSING; } - public double raw_pressure() { - if (pres == MISSING) - return MISSING; - return barometer_to_pressure(pres); - } + public double ground_pressure() { return MISSING; } - public double filtered_pressure() { - if (flight_pres == MISSING) - return MISSING; - return barometer_to_pressure(flight_pres); - } + public double battery_voltage() { return MISSING; } - public double ground_pressure() { - if (ground_pres == MISSING) - return MISSING; - return barometer_to_pressure(ground_pres); - } + public double main_voltage() { return MISSING; } + + public double drogue_voltage() { return MISSING; } + + public double temperature() { return MISSING; } + + public double acceleration() { return MISSING; } + + public double accel_speed() { return MISSING; } + + public AltosIMU imu() { return null; } + + public AltosMag mag() { return null; } + + /* + * Convert various pressure values to altitude + */ public double raw_altitude() { double p = raw_pressure(); @@ -138,8 +121,9 @@ public class AltosRecord implements Comparable { } public double filtered_altitude() { - if (height != MISSING && ground_pres != MISSING) - return height + ground_altitude(); + double ga = ground_altitude(); + if (height != MISSING && ga != MISSING) + return height + ga; double p = filtered_pressure(); if (p == MISSING) @@ -167,94 +151,17 @@ public class AltosRecord implements Comparable { return r - g; } - 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 - */ - - public 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); - } - - public 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 (acceleration != MISSING) - return acceleration; - - if (ground_accel == MISSING || accel == MISSING) - return MISSING; - return (ground_accel - accel) / accel_counts_per_mss(); - } - - public double accel_speed() { - if (speed != MISSING) - return speed; - if (flight_vel == MISSING) - return MISSING; - return flight_vel / (accel_counts_per_mss() * 100.0); - } - public String state() { return AltosLib.state_name(state); } - public static String gets(FileInputStream s) throws IOException { - int c; - String line = ""; - - while ((c = s.read()) != -1) { - if (c == '\r') - continue; - if (c == '\n') { - return line; - } - line = line + (char) c; - } - return null; - } - public int compareTo(AltosRecord o) { return tick - o.tick; } - public AltosRecord(AltosRecord old) { - version = old.version; + public void copy(AltosRecord old) { seen = old.seen; + version = old.version; callsign = old.callsign; serial = old.serial; flight = old.flight; @@ -262,32 +169,27 @@ public class AltosRecord implements Comparable { 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; acceleration = old.acceleration; speed = old.speed; height = old.height; gps = new AltosGPS(old.gps); new_gps = false; companion = old.companion; - imu = old.imu; - mag = old.mag; + } + + public AltosRecord clone() { + try { + AltosRecord n = (AltosRecord) super.clone(); + n.copy(this); + return n; + } catch (CloneNotSupportedException e) { + return null; + } } public AltosRecord() { - version = 0; seen = 0; + version = 0; callsign = "N0CALL"; serial = 0; flight = 0; @@ -295,19 +197,6 @@ public class AltosRecord implements Comparable { status = 0; state = AltosLib.ao_flight_startup; tick = 0; - accel = MISSING; - pres = MISSING; - temp = MISSING; - batt = MISSING; - drogue = MISSING; - main = MISSING; - flight_accel = 0; - ground_accel = 0; - flight_vel = 0; - flight_pres = 0; - ground_pres = 0; - accel_plus_g = 0; - accel_minus_g = 0; acceleration = MISSING; speed = MISSING; height = MISSING; diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java new file mode 100644 index 00000000..8b3d745a --- /dev/null +++ b/altoslib/AltosRecordMM.java @@ -0,0 +1,186 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosRecordMM extends AltosRecord { + + 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 raw_pressure() { + if (pres != MISSING) + return pres / 100.0; + return MISSING; + } + + public double filtered_pressure() { + return raw_pressure(); + } + + public double ground_pressure() { + if (ground_pres != MISSING) + return ground_pres / 100.0; + return MISSING; + } + + public double battery_voltage() { + if (v_batt != MISSING) + return 3.3 * adc(v_batt) * 27.0 / (15.0 + 27.0); + return MISSING; + } + + static double pyro(int raw) { + if (raw != MISSING) + return 3.3 * adc(raw) * 27.0 / (100.0 + 27.0); + return MISSING; + } + + public double main_voltage() { + return pyro(sense[1]); + } + + public double drogue_voltage() { + return pyro(sense[0]); + } + + 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() { + System.out.printf("MM record acceleration %g ground_accel %d accel %d accel_minus_g %d accel_plus_g %d\n", + acceleration, ground_accel, accel, accel_minus_g, accel_plus_g); + if (acceleration != MISSING) + return 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 double accel_speed() { + return speed; + } + + 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() { + AltosRecordMM n = (AltosRecordMM) super.clone(); + n.copy(this); + return n; + } + + 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() { + super(); + make_missing(); + } +} diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java new file mode 100644 index 00000000..afb70790 --- /dev/null +++ b/altoslib/AltosRecordTM.java @@ -0,0 +1,199 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosRecordTM extends AltosRecord { + 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 raw_pressure() { + if (pres == MISSING) + return MISSING; + return barometer_to_pressure(pres); + } + + public double filtered_pressure() { + if (flight_pres == MISSING) + return MISSING; + return barometer_to_pressure(flight_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 (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + if (speed != MISSING) + return speed; + if (flight_vel == MISSING) + return MISSING; + return flight_vel / (accel_counts_per_mss() * 100.0); + } + + 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() { + AltosRecordTM n = (AltosRecordTM) super.clone(); + n.copy(this); + return n; + } + + void make_missing() { + accel = MISSING; + pres = MISSING; + temp = MISSING; + batt = MISSING; + drogue = MISSING; + main = MISSING; + + flight_accel = 0; + flight_vel = 0; + flight_pres = 0; + + ground_accel = 0; + ground_pres = 0; + accel_plus_g = 0; + accel_minus_g = 0; + } + + public AltosRecordTM(AltosRecord old) { + super.copy(old); + make_missing(); + } + + public AltosRecordTM() { + super(); + make_missing(); + } +} diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index 04abb1f3..ee244824 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -84,7 +84,7 @@ import java.util.HashMap; * */ -public class AltosTelemetry extends AltosRecord { +public abstract class AltosTelemetry extends AltosRecord { /* * General header fields diff --git a/altoslib/AltosTelemetryIterable.java b/altoslib/AltosTelemetryIterable.java index f4b4029f..e95c15e0 100644 --- a/altoslib/AltosTelemetryIterable.java +++ b/altoslib/AltosTelemetryIterable.java @@ -45,7 +45,7 @@ public class AltosTelemetryIterable extends AltosRecordIterable { try { for (;;) { - String line = AltosRecord.gets(input); + String line = AltosLib.gets(input); if (line == null) { break; } @@ -67,11 +67,11 @@ public class AltosTelemetryIterable extends AltosRecordIterable { saw_boost = true; boost_tick = record.tick; } - if (record.accel != AltosRecord.MISSING) + if (record.acceleration() != AltosRecord.MISSING) has_accel = true; if (record.gps != null) has_gps = true; - if (record.main != AltosRecord.MISSING) + if (record.main_voltage() != AltosRecord.MISSING) has_ignite = true; if (previous != null && previous.tick != record.tick) records.add(previous); diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java index 6b6a252d..6a8cfd35 100644 --- a/altoslib/AltosTelemetryRecord.java +++ b/altoslib/AltosTelemetryRecord.java @@ -43,6 +43,7 @@ public abstract class AltosTelemetryRecord { 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; @@ -76,7 +77,6 @@ public abstract class AltosTelemetryRecord { case packet_type_TM_sensor: case packet_type_Tm_sensor: case packet_type_Tn_sensor: - case packet_type_MM_sensor: r = new AltosTelemetryRecordSensor(bytes, rssi); break; case packet_type_configuration: @@ -91,6 +91,12 @@ public abstract class AltosTelemetryRecord { case packet_type_companion: r = new AltosTelemetryRecordCompanion(bytes); break; + case packet_type_MM_sensor: + r = new AltosTelemetryRecordMegaSensor(bytes, rssi); + break; + case packet_type_MM_data: + r = new AltosTelemetryRecordMegaData(bytes); + break; default: r = new AltosTelemetryRecordRaw(bytes); break; diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index 85071d9c..3976a07a 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -232,7 +232,7 @@ 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"; - AltosRecord record; + AltosRecordTM record; private void parse_v4(String[] words, int i) throws ParseException { AltosTelemetryMap map = new AltosTelemetryMap(words, i); @@ -366,7 +366,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { String[] words = line.split("\\s+"); int i = 0; - record = new AltosRecord(); + record = new AltosRecordTM(); if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { i += 2; @@ -388,7 +388,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { } /* - * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that + * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM from that */ int[] bytes; @@ -422,7 +422,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { static final int AO_GPS_COURSE_VALID = (1 << 7); public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { - record = new AltosRecord(); + record = new AltosRecordTM(); bytes = in_bytes; record.version = 4; diff --git a/altoslib/AltosTelemetryRecordMegaData.java b/altoslib/AltosTelemetryRecordMegaData.java new file mode 100644 index 00000000..cc35cd83 --- /dev/null +++ b/altoslib/AltosTelemetryRecordMegaData.java @@ -0,0 +1,96 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw { + + int state; + + int v_batt; + int v_pyro; + int sense[]; + + int ground_pres; + int ground_accel; + int accel_plus_g; + int accel_minus_g; + + int acceleration; + int speed; + int height; + + public AltosTelemetryRecordMegaData(int[] in_bytes) { + super(in_bytes); + + state = int8(5); + + v_batt = int16(6); + v_pyro = int16(8); + + sense = new int[6]; + + for (int i = 0; i < 6; i++) { + sense[i] = int8(10 + i) << 4; + sense[i] |= sense[i] >> 8; + } + + ground_pres = int32(16); + ground_accel = int16(20); + accel_plus_g = int16(22); + accel_minus_g = int16(24); + + acceleration = int16(26); + speed = int16(28); + height = int16(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord n = super.update_state(previous); + + AltosRecordMM next; + if (!(n instanceof AltosRecordMM)) { + System.out.printf("data making record MM\n"); + next = new AltosRecordMM(n); + } else { + System.out.printf ("data already has MM\n"); + next = (AltosRecordMM) n; + } + + next.state = state; + + next.v_batt = v_batt; + next.v_pyro = v_pyro; + + for (int i = 0; i < 6; i++) + next.sense[i] = sense[i]; + + next.ground_accel = ground_accel; + next.ground_pres = ground_pres; + next.accel_plus_g = accel_plus_g; + next.accel_minus_g = accel_minus_g; + + next.acceleration = acceleration / 16.0; + next.speed = speed / 16.0; + next.height = height; + + next.seen |= AltosRecord.seen_flight | AltosRecord.seen_temp_volt; + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordMegaSensor.java b/altoslib/AltosTelemetryRecordMegaSensor.java new file mode 100644 index 00000000..85a32d12 --- /dev/null +++ b/altoslib/AltosTelemetryRecordMegaSensor.java @@ -0,0 +1,98 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + + +public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { + int accel; + int pres; + int temp; + + int accel_x; + int accel_y; + int accel_z; + + int gyro_x; + int gyro_y; + int gyro_z; + + int mag_x; + int mag_y; + int mag_z; + + int rssi; + + public AltosTelemetryRecordMegaSensor(int[] in_bytes, int in_rssi) { + super(in_bytes); + + accel = int16(6); + pres = int32(8); + temp = int16(12); + + accel_x = int16(14); + accel_y = int16(16); + accel_z = int16(18); + + gyro_x = int16(20); + gyro_y = int16(22); + gyro_z = int16(24); + + mag_x = int16(26); + mag_y = int16(28); + mag_z = int16(30); + + rssi = in_rssi; + System.out.printf ("telem record accel: %d\n", accel); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord n = super.update_state(previous); + + AltosRecordMM next; + if (!(n instanceof AltosRecordMM)) { + System.out.printf("sensor making MM\n"); + next = new AltosRecordMM(n); + } else { + System.out.printf("sensor has MM\n"); + next = (AltosRecordMM) n; + } + + System.out.printf("telem update_state accel: %d\n", accel); + next.accel = accel; + next.pres = pres; + next.temp = temp; + + next.imu.accel_x = accel_x; + next.imu.accel_y = accel_y; + next.imu.accel_z = accel_z; + + next.imu.gyro_x = gyro_x; + next.imu.gyro_y = gyro_y; + next.imu.gyro_z = gyro_z; + + next.mag.x = mag_x; + next.mag.y = mag_y; + next.mag.z = mag_z; + + next.rssi = rssi; + + next.seen |= AltosRecord.seen_sensor; + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordRaw.java b/altoslib/AltosTelemetryRecordRaw.java index 43d0f17a..dc1b8947 100644 --- a/altoslib/AltosTelemetryRecordRaw.java +++ b/altoslib/AltosTelemetryRecordRaw.java @@ -49,6 +49,10 @@ public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { 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); } @@ -63,7 +67,7 @@ public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { public AltosRecord update_state(AltosRecord previous) { AltosRecord next; if (previous != null) - next = new AltosRecord(previous); + next = previous.clone(); else next = new AltosRecord(); next.serial = serial; diff --git a/altoslib/AltosTelemetryRecordSensor.java b/altoslib/AltosTelemetryRecordSensor.java index cfaf90b0..319a91b3 100644 --- a/altoslib/AltosTelemetryRecordSensor.java +++ b/altoslib/AltosTelemetryRecordSensor.java @@ -61,8 +61,14 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { rssi = in_rssi; } - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); + public AltosRecord update_state(AltosRecord prev) { + AltosRecord n = super.update_state(prev); + + AltosRecordTM next; + if (!(n instanceof AltosRecordTM)) + next = new AltosRecordTM(n); + else + next = (AltosRecordTM) n; next.state = state; if (type == packet_type_TM_sensor) diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index f644d46a..ac97c9cb 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -35,6 +35,8 @@ AltosLib_JAVA = \ $(SRC)/AltosRecordCompanion.java \ $(SRC)/AltosRecordIterable.java \ $(SRC)/AltosRecord.java \ + $(SRC)/AltosRecordTM.java \ + $(SRC)/AltosRecordMM.java \ $(SRC)/AltosReplayReader.java \ $(SRC)/AltosState.java \ $(SRC)/AltosTelemetry.java \ @@ -50,6 +52,8 @@ AltosLib_JAVA = \ $(SRC)/AltosTelemetryRecordRaw.java \ $(SRC)/AltosTelemetryRecordSatellite.java \ $(SRC)/AltosTelemetryRecordSensor.java \ + $(SRC)/AltosTelemetryRecordMegaSensor.java \ + $(SRC)/AltosTelemetryRecordMegaData.java \ $(SRC)/AltosMs5607.java \ $(SRC)/AltosIMU.java \ $(SRC)/AltosMag.java diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index be86a454..c876d9ca 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -146,8 +146,8 @@ public class AltosCSV implements AltosWriter { } void write_advanced(AltosRecord record) { - AltosIMU imu = record.imu; - AltosMag mag = record.mag; + AltosIMU imu = record.imu(); + AltosMag mag = record.mag(); if (imu == null) imu = new AltosIMU(); @@ -263,7 +263,7 @@ public class AltosCSV implements AltosWriter { write_general(record); out.printf(","); write_flight(record); out.printf(","); write_basic(record); out.printf(","); - if (record.imu != null || record.mag != null) + if (record.imu() != null || record.mag() != null) write_advanced(record); if (record.gps != null) { out.printf(","); @@ -287,7 +287,7 @@ public class AltosCSV implements AltosWriter { if (record.state == Altos.ao_flight_startup) return; if (!header_written) { - write_header(record.imu != null || record.mag != null, + write_header(record.imu() != null || record.mag() != null, record.gps != null, record.companion != null); header_written = true; } diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 2ee90937..949e3926 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -204,17 +204,18 @@ class AltosIdleMonitor extends Thread { record.state = Altos.ao_flight_idle; record.tick = adc.tick; - record.accel = adc.accel; - record.pres = adc.pres; - record.batt = adc.batt; - record.temp = adc.temp; - record.drogue = adc.drogue; - record.main = adc.main; - - record.ground_accel = record.accel; - record.ground_pres = record.pres; - record.accel_plus_g = config_data.accel_cal_plus; - record.accel_minus_g = config_data.accel_cal_minus; + +// record.accel = adc.accel; +// record.pres = adc.pres; +// record.batt = adc.batt; +// record.temp = adc.temp; +// record.drogue = adc.drogue; +// record.main = adc.main; + +// record.ground_accel = record.accel; +// record.ground_pres = record.pres; +// record.accel_plus_g = config_data.accel_cal_plus; +// record.accel_minus_g = config_data.accel_cal_minus; record.acceleration = 0; record.speed = 0; record.height = 0; -- cgit v1.2.3 From 9dcb4e2ab60ecf0cc7371c1b1a620be952fa8776 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Jun 2012 22:19:01 -0700 Subject: altosui: AltosSerial and AltosLink both tried to provide frequency setting AltosLink owns all of the device configuration, so remove that from AltosSerial and make sure that AltosLink provides the right function signatures (wasn't using the new direct frequency setting command). Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 28 ++++++++----------------- altosui/AltosSerial.java | 53 ------------------------------------------------ 2 files changed, 9 insertions(+), 72 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 77b400fc..a39204ac 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -166,6 +166,15 @@ public abstract class AltosLink { set_channel(AltosConvert.radio_frequency_to_channel(frequency)); } + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_frequency != 0, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + public void set_telemetry(int in_telemetry) { telemetry = in_telemetry; if (monitor_mode) @@ -200,31 +209,12 @@ public abstract class AltosLink { flush_output(); } - public void set_radio_frequency(double frequency, - boolean has_setting, - int cal) { - if (debug) - System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); - if (has_setting) - set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); - else - set_channel(AltosConvert.radio_frequency_to_channel(frequency)); - } - public AltosConfigData config_data() throws InterruptedException, TimeoutException { if (config_data == null) config_data = new AltosConfigData(this); return config_data; } - public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - config_data(); - set_radio_frequency(frequency, - config_data.radio_setting != 0, - config_data.radio_calibration); - } - public void set_callsign(String callsign) { printf ("c c %s\n", callsign); flush_output(); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 5768ba71..8b60dd54 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -264,59 +264,6 @@ public class AltosSerial extends AltosLink implements Runnable { flush_output(); } - private int telemetry_len() { - return Altos.telemetry_len(telemetry); - } - - private void set_channel(int channel) { - if (altos != null) { - if (monitor_mode) - printf("m 0\nc r %d\nm %x\n", - channel, telemetry_len()); - else - printf("c r %d\n", channel); - flush_output(); - } - } - - private void set_radio_setting(int setting) { - if (altos != null) { - if (monitor_mode) - printf("m 0\nc R %d\nm %x\n", - setting, telemetry_len()); - else - printf("c R %d\n", setting); - flush_output(); - } - } - - private void set_radio_freq(int frequency) { - if (altos != null) { - if (monitor_mode) - printf("m 0\nc F %d\nm %x\n", - frequency, telemetry_len()); - else - printf("c F %d\n", frequency); - flush_output(); - } - } - - public void set_radio_frequency(double frequency, - boolean has_frequency, - boolean has_setting, - int cal) { - if (debug) - System.out.printf("set_radio_frequency %7.3f (freq %b) (set %b) %d\n", frequency, has_frequency, has_setting, cal); - if (frequency == 0) - return; - if (has_frequency) - set_radio_freq((int) Math.floor (frequency * 1000)); - else if (has_setting) - set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); - else - set_channel(AltosConvert.radio_frequency_to_channel(frequency)); - } - public void set_frame(Frame in_frame) { frame = in_frame; } -- cgit v1.2.3 From f078a591cf2fafe89bb1bb883f49d80750129d44 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 14:28:53 -0700 Subject: altosui: Remove a bunch of debugging printfs These aren't useful at this point. Signed-off-by: Keith Packard --- altoslib/AltosLog.java | 1 - altoslib/AltosPreferences.java | 2 -- altoslib/AltosRecordMM.java | 2 -- altoslib/AltosTelemetryRecordMegaData.java | 2 -- altoslib/AltosTelemetryRecordMegaSensor.java | 4 ---- altosui/AltosBTDevice.java | 2 -- altosui/AltosBTDeviceIterator.java | 2 -- altosui/AltosBTKnown.java | 2 -- altosui/AltosBTManage.java | 3 --- altosui/AltosConfigTD.java | 7 ++----- altosui/AltosConfigureUI.java | 1 - altosui/AltosFlashUI.java | 7 ------- altosui/AltosLaunchUI.java | 1 - 13 files changed, 2 insertions(+), 34 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLog.java b/altoslib/AltosLog.java index 08c45ca8..55a25bb4 100644 --- a/altoslib/AltosLog.java +++ b/altoslib/AltosLog.java @@ -62,7 +62,6 @@ class AltosLog implements Runnable { boolean open (AltosRecord telem) throws IOException { AltosFile a = new AltosFile(telem); - System.out.printf("open %s\n", a.toString()); log_file = new FileWriter(a, true); if (log_file != null) { while (!pending_queue.isEmpty()) { diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 43c7088d..9ab80cf5 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -306,7 +306,6 @@ public class AltosPreferences { public static void set_launcher_serial(int new_launcher_serial) { launcher_serial = new_launcher_serial; - System.out.printf("set launcher serial to %d\n", new_launcher_serial); synchronized (preferences) { preferences.putInt(launcherSerialPreference, launcher_serial); flush_preferences(); @@ -319,7 +318,6 @@ public class AltosPreferences { public static void set_launcher_channel(int new_launcher_channel) { launcher_channel = new_launcher_channel; - System.out.printf("set launcher channel to %d\n", new_launcher_channel); synchronized (preferences) { preferences.putInt(launcherChannelPreference, launcher_channel); flush_preferences(); diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java index 8b3d745a..055cf85f 100644 --- a/altoslib/AltosRecordMM.java +++ b/altoslib/AltosRecordMM.java @@ -98,8 +98,6 @@ public class AltosRecordMM extends AltosRecord { } public double acceleration() { - System.out.printf("MM record acceleration %g ground_accel %d accel %d accel_minus_g %d accel_plus_g %d\n", - acceleration, ground_accel, accel, accel_minus_g, accel_plus_g); if (acceleration != MISSING) return acceleration; diff --git a/altoslib/AltosTelemetryRecordMegaData.java b/altoslib/AltosTelemetryRecordMegaData.java index cc35cd83..8f55d238 100644 --- a/altoslib/AltosTelemetryRecordMegaData.java +++ b/altoslib/AltosTelemetryRecordMegaData.java @@ -65,10 +65,8 @@ public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw { AltosRecordMM next; if (!(n instanceof AltosRecordMM)) { - System.out.printf("data making record MM\n"); next = new AltosRecordMM(n); } else { - System.out.printf ("data already has MM\n"); next = (AltosRecordMM) n; } diff --git a/altoslib/AltosTelemetryRecordMegaSensor.java b/altoslib/AltosTelemetryRecordMegaSensor.java index 85a32d12..93c001de 100644 --- a/altoslib/AltosTelemetryRecordMegaSensor.java +++ b/altoslib/AltosTelemetryRecordMegaSensor.java @@ -57,7 +57,6 @@ public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { mag_z = int16(30); rssi = in_rssi; - System.out.printf ("telem record accel: %d\n", accel); } public AltosRecord update_state(AltosRecord previous) { @@ -65,14 +64,11 @@ public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { AltosRecordMM next; if (!(n instanceof AltosRecordMM)) { - System.out.printf("sensor making MM\n"); next = new AltosRecordMM(n); } else { - System.out.printf("sensor has MM\n"); next = (AltosRecordMM) n; } - System.out.printf("telem update_state accel: %d\n", accel); next.accel = accel; next.pres = pres; next.temp = temp; diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index f6926b10..5e353fdd 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -87,7 +87,6 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { public boolean matchProduct(int want_product) { - System.out.printf("matchProduct %s %d\n", toString(), want_product); // if (!isAltusMetrum()) // return false; @@ -107,7 +106,6 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { if (!(o instanceof AltosBTDevice)) return false; AltosBTDevice other = (AltosBTDevice) o; - System.out.printf("AltosBTDevice equals %s == %s\n", toString(), other.toString()); return getName().equals(other.getName()) && getAddr().equals(other.getAddr()); } diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java index 7c360705..58ed86d5 100644 --- a/altosui/AltosBTDeviceIterator.java +++ b/altosui/AltosBTDeviceIterator.java @@ -26,7 +26,6 @@ public class AltosBTDeviceIterator implements Iterator { SWIGTYPE_p_altos_bt_list list; public boolean hasNext() { - System.out.printf ("BT has next?\n"); if (list == null) return false; if (current != null) @@ -35,7 +34,6 @@ public class AltosBTDeviceIterator implements Iterator { return false; current = new AltosBTDevice(); while (libaltos.altos_bt_list_next(list, current) != 0) { - System.out.printf("Got BT device %s\n", current.toString()); // if (current.matchProduct(product)) return true; } diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index 021e4d0b..6a8e53cb 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -31,7 +31,6 @@ public class AltosBTKnown implements Iterable { private void set_address(String name, String addr) { bt_pref.put(name, addr); - System.out.printf("saving known %s %s\n", name, addr); } private void remove(String name) { @@ -44,7 +43,6 @@ public class AltosBTKnown implements Iterable { for (int i = 0; i < names.length; i++) { String name = names[i]; String addr = get_address(name); - System.out.printf("Known device %s %s\n", name, addr); devices.add(new AltosBTDevice(name, addr)); } } catch (BackingStoreException be) { diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index d2899d65..aeb964bb 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -126,7 +126,6 @@ public class AltosBTManage extends AltosDialog implements ActionListener, Iterab public void add_known() { for (AltosBTDevice device : visible_devices.selected_list()) { - System.out.printf("Add known %s\n", device.toString()); known_devices.add(device); visible_devices.remove(device); } @@ -134,7 +133,6 @@ public class AltosBTManage extends AltosDialog implements ActionListener, Iterab public void remove_known() { for (AltosBTDevice device : known_devices.selected_list()) { - System.out.printf("Remove known %s\n", device.toString()); known_devices.remove(device); visible_devices.add(device); } @@ -151,7 +149,6 @@ public class AltosBTManage extends AltosDialog implements ActionListener, Iterab public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); - System.out.printf("manage command %s\n", command); if ("ok".equals(command)) { bt_thread.interrupt(); commit(); diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index 4048166c..324a5988 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -144,10 +144,8 @@ public class AltosConfigTD implements ActionListener { get_string(line, "Config version", config_version); get_int(line, "serial-number", serial); get_int(line, "Radio channel:", radio_channel); - if (get_int(line, "Radio cal:", radio_calibration)) - System.out.printf("got radio cal %d\n", radio_calibration.get()); - if (get_int(line, "Frequency:", radio_frequency)) - System.out.printf("got radio freq %d\n", radio_frequency.get()); + get_int(line, "Radio cal:", radio_calibration); + get_int(line, "Frequency:", radio_frequency); get_int(line, "Radio setting:", radio_setting); get_string(line,"software-version", version); get_string(line,"product", product); @@ -205,7 +203,6 @@ public class AltosConfigTD implements ActionListener { break; } } - System.out.printf("config_version %s\n", config_version.get()); if (been_there) break; if (!config_version.get().equals("0.0")) diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index d0ed9325..ace245a0 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -291,7 +291,6 @@ public class AltosConfigureUI final UIManager.LookAndFeelInfo[] look_and_feels = UIManager.getInstalledLookAndFeels(); - System.out.printf("look_and_feels %d\n", look_and_feels.length); look_and_feel_value = new JComboBox(look_and_feels); DelegatingRenderer.install(look_and_feel_value); diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 4ab73a6d..66991d10 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -235,22 +235,17 @@ public class AltosFlashUI public void run() { ui.flash = flash; ui.update_rom_config_info(current_config); - System.out.printf("Done updating rom config info\n"); await_rom_config.release(); } }); - System.out.printf("Waiting for rom configuration updates\n"); await_rom_config.acquire(); - System.out.printf("Got rom config update\n"); if (ui.rom_config != null) { - System.out.printf("rom_config not null\n"); flash.set_romconfig(ui.rom_config); flash.flash(); } } catch (InterruptedException ee) { final Exception e = ee; - System.out.printf("exception %s\n", e.toString()); SwingUtilities.invokeLater(new Runnable() { public void run() { ui.exception(e); @@ -258,7 +253,6 @@ public class AltosFlashUI }); } catch (IOException ee) { final Exception e = ee; - System.out.printf("exception %s\n", e.toString()); SwingUtilities.invokeLater(new Runnable() { public void run() { ui.exception(e); @@ -266,7 +260,6 @@ public class AltosFlashUI }); } catch (AltosSerialInUseException ee) { final Exception e = ee; - System.out.printf("exception %s\n", e.toString()); SwingUtilities.invokeLater(new Runnable() { public void run() { ui.exception(e); diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index eb76243d..44481544 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -336,7 +336,6 @@ public class AltosLaunchUI public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); - System.out.printf("cmd %s\n", cmd); if (cmd.equals("armed") || cmd.equals("igniter")) { stop_arm_timer(); } -- cgit v1.2.3 From b5f6d4e5251a825395c93916afa3af659c678498 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 19:15:32 -0700 Subject: altosui: Abstract remote connection timeout stuff This moves some of the logic for managing when to present the 'cancel' dialog for remote operations to altoslib. Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 69 +++++++++++++++++++++++++++++++---- altosui/AltosSerial.java | 95 ++++++++++++++---------------------------------- 2 files changed, 88 insertions(+), 76 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index a39204ac..779c8496 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -60,16 +60,66 @@ public abstract class AltosLink { return null; } - public String get_reply(int timeout) throws InterruptedException { - try { - return get_reply_no_dialog(timeout); - } catch (TimeoutException te) { - return null; + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + + + public abstract boolean can_cancel_reply(); + public abstract boolean show_reply_timeout(); + public abstract void hide_reply_timeout(); + + public boolean reply_abort; + public int in_reply; + + boolean reply_timeout_shown = false; + + private boolean check_reply_timeout() { + if (!reply_timeout_shown) + reply_timeout_shown = show_reply_timeout(); + return reply_abort; + } + + private void cleanup_reply_timeout() { + if (reply_timeout_shown) { + reply_timeout_shown = false; + hide_reply_timeout(); } } - public String get_reply() throws InterruptedException { - return get_reply(5000); + + public String get_reply(int timeout) throws InterruptedException { + boolean can_cancel = can_cancel_reply(); + String reply = null; + + if (!can_cancel && remote) + System.out.printf("Uh-oh, reading remote serial device from swing thread\n"); + + if (remote && can_cancel) + timeout = 500; + try { + ++in_reply; + + flush_output(); + + reply_abort = false; + reply_timeout_shown = false; + for (;;) { + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) { + cleanup_reply_timeout(); + reply = line.line; + break; + } + if (!remote || !can_cancel || check_reply_timeout()) { + reply = null; + break; + } + } + } finally { + --in_reply; + } + return reply; } public void add_telem(AltosLine line) throws InterruptedException { @@ -124,7 +174,10 @@ public abstract class AltosLink { public void flush_input() throws InterruptedException { - flush_input(100); + if (remote) + flush_input(500); + else + flush_input(100); } diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 8b60dd54..35704d40 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -102,21 +102,7 @@ public class AltosSerial extends AltosLink implements Runnable { } } - boolean abort; JDialog timeout_dialog; - boolean timeout_started = false; - - private void stop_timeout_dialog() { - if (timeout_started) { - timeout_started = false; - Runnable r = new Runnable() { - public void run() { - timeout_dialog.setVisible(false); - } - }; - SwingUtilities.invokeLater(r); - } - } private void start_timeout_dialog_internal() { @@ -135,69 +121,42 @@ public class AltosSerial extends AltosLink implements Runnable { if (o == null) return; if (options[0].equals(o)) - abort = true; + reply_abort = true; timeout_dialog.dispose(); timeout_dialog = null; } - private boolean check_timeout() { - if (!timeout_started && frame != null) { - if (!SwingUtilities.isEventDispatchThread()) { - timeout_started = true; - Runnable r = new Runnable() { - public void run() { - start_timeout_dialog_internal(); - } - }; - SwingUtilities.invokeLater(r); - } - } - return abort; - } + /* + * These are required by the AltosLink implementation + */ - public void flush_input() throws InterruptedException { - if (remote) - flush_input(500); - else - flush_input(100); + public boolean can_cancel_reply() { + /* + * Can cancel any replies not called from the dispatch thread + */ + return !SwingUtilities.isEventDispatchThread(); } - int in_reply; - - public String get_reply(int timeout) throws InterruptedException { - boolean can_cancel = true; - String reply = null; - - try { - ++in_reply; + public boolean show_reply_timeout() { + if (!SwingUtilities.isEventDispatchThread() && frame != null) { + Runnable r = new Runnable() { + public void run() { + start_timeout_dialog_internal(); + } + }; + SwingUtilities.invokeLater(r); + return true; + } + return false; + } - if (SwingUtilities.isEventDispatchThread()) { - can_cancel = false; - if (remote) - System.out.printf("Uh-oh, reading remote serial device from swing thread\n"); - } - flush_output(); - if (remote && can_cancel) { - timeout = 500; - } - abort = false; - timeout_started = false; - for (;;) { - AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); - if (line != null) { - stop_timeout_dialog(); - reply = line.line; - break; + public void hide_reply_timeout() { + Runnable r = new Runnable() { + public void run() { + timeout_dialog.setVisible(false); } - if (!remote || !can_cancel || check_timeout()) { - reply = null; - break; - } - } - } finally { - --in_reply; - } - return reply; + }; + SwingUtilities.invokeLater(r); } public void close() { -- cgit v1.2.3 From 52196975c447851f14619213c1de5101d334eebc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 16 Jul 2012 15:35:11 -0700 Subject: altosui: Move serial datastream parser to altoslib instead of having it in altosui Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 47 +++++++++++++++++++++++++++++++++++++++++++++++ altosui/AltosSerial.java | 42 ++---------------------------------------- 2 files changed, 49 insertions(+), 40 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 779c8496..d59e73ba 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -24,6 +24,11 @@ import java.util.*; import java.text.*; public abstract class AltosLink { + + 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(); @@ -88,6 +93,48 @@ public abstract class AltosLink { } + public void run () { + int c; + byte[] line_bytes = null; + int line_count = 0; + + try { + for (;;) { + c = getchar(); + if (Thread.interrupted()) + break; + if (c == ERROR) { + add_telem (new AltosLine()); + add_reply (new AltosLine()); + break; + } + if (c == TIMEOUT) + continue; + if (c == '\r') + continue; + synchronized(this) { + if (c == '\n') { + if (line_count != 0) { + add_bytes(line_bytes, line_count); + line_count = 0; + } + } else { + if (line_bytes == null) { + line_bytes = new byte[256]; + } else if (line_count == line_bytes.length) { + byte[] new_line_bytes = new byte[line_count * 2]; + System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count); + line_bytes = new_line_bytes; + } + line_bytes[line_count] = (byte) c; + line_count++; + } + } + } + } catch (InterruptedException e) { + } + } + public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = can_cancel_reply(); String reply = null; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 35704d40..c4e9c697 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -53,46 +53,8 @@ public class AltosSerial extends AltosLink implements Runnable { int line_count; Frame frame; - public void run () { - int c; - byte[] line_bytes = null; - int line_count = 0; - - try { - for (;;) { - c = libaltos.altos_getchar(altos, 0); - if (Thread.interrupted()) - break; - if (c == libaltosConstants.LIBALTOS_ERROR) { - add_telem (new AltosLine()); - add_reply (new AltosLine()); - break; - } - if (c == libaltosConstants.LIBALTOS_TIMEOUT) - continue; - if (c == '\r') - continue; - synchronized(this) { - if (c == '\n') { - if (line_count != 0) { - add_bytes(line_bytes, line_count); - line_count = 0; - } - } else { - if (line_bytes == null) { - line_bytes = new byte[256]; - } else if (line_count == line_bytes.length) { - byte[] new_line_bytes = new byte[line_count * 2]; - System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count); - line_bytes = new_line_bytes; - } - line_bytes[line_count] = (byte) c; - line_count++; - } - } - } - } catch (InterruptedException e) { - } + public int getchar() { + return libaltos.altos_getchar(altos, 0); } public void flush_output() { -- cgit v1.2.3 From 99b7eaf8d1b312443b842d078fb8464032b3a39b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 17 Jul 2012 20:42:42 -0700 Subject: altoslib: Fix MM conversion functions Pressure is already reported in Pa, no need to convert that. Voltage divider computations were backwards. Signed-off-by: Keith Packard --- altoslib/AltosRecordMM.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java index 055cf85f..5f952f7a 100644 --- a/altoslib/AltosRecordMM.java +++ b/altoslib/AltosRecordMM.java @@ -47,7 +47,7 @@ public class AltosRecordMM extends AltosRecord { public double raw_pressure() { if (pres != MISSING) - return pres / 100.0; + return pres; return MISSING; } @@ -57,19 +57,19 @@ public class AltosRecordMM extends AltosRecord { public double ground_pressure() { if (ground_pres != MISSING) - return ground_pres / 100.0; + return ground_pres; return MISSING; } public double battery_voltage() { if (v_batt != MISSING) - return 3.3 * adc(v_batt) * 27.0 / (15.0 + 27.0); + 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) * 27.0 / (100.0 + 27.0); + return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0; return MISSING; } -- cgit v1.2.3 From 97c1cfee929a35dd1596dc02ce519b80132f3c5c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 17 Jul 2012 20:43:31 -0700 Subject: altoslib: Don't use MISSING values in max computations Early telemetry state may be missing critical data, don't use MISSING values in computing max ranges. Signed-off-by: Keith Packard --- altoslib/AltosState.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 68c7611f..e20ec9a7 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -160,7 +160,8 @@ public class AltosState { } ngps++; } - } + } else + pad_alt = ground_altitude; gps_waiting = MIN_PAD_SAMPLES - npad; if (gps_waiting < 0) @@ -173,14 +174,14 @@ public class AltosState { boost = (AltosLib.ao_flight_boost == state); /* Only look at accelerometer data under boost */ - if (boost && acceleration > max_acceleration) + if (boost && acceleration > max_acceleration && acceleration != AltosRecord.MISSING) max_acceleration = acceleration; - if (boost && speed > max_speed) + if (boost && speed > max_speed && speed != AltosRecord.MISSING) max_speed = speed; - if (boost && baro_speed > max_baro_speed) + if (boost && baro_speed > max_baro_speed && baro_speed != AltosRecord.MISSING) max_baro_speed = baro_speed; - if (height > max_height) + if (height > max_height && height != AltosRecord.MISSING) max_height = height; if (data.gps != null) { if (gps == null || !gps.locked || data.gps.locked) -- cgit v1.2.3 From f6921c9040b1f1fc4408d163532b0695a3611195 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 17 Jul 2012 21:04:23 -0700 Subject: altoslib: Move idle monitor managing code to altoslib More stuff to be shared (potentially) Signed-off-by: Keith Packard --- altoslib/AltosIdleMonitor.java | 445 +++++++++++++++++++++++++++++++++ altoslib/AltosIdleMonitorListener.java | 28 +++ altoslib/AltosIdleRecordTM.java | 268 ++++++++++++++++++++ altoslib/Makefile.am | 2 + altosui/AltosIdleMonitorUI.java | 266 +------------------- 5 files changed, 752 insertions(+), 257 deletions(-) create mode 100644 altoslib/AltosIdleMonitor.java create mode 100644 altoslib/AltosIdleMonitorListener.java create mode 100644 altoslib/AltosIdleRecordTM.java (limited to 'altoslib') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java new file mode 100644 index 00000000..cd518c28 --- /dev/null +++ b/altoslib/AltosIdleMonitor.java @@ -0,0 +1,445 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosSensorTM { + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + + public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + 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("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + break; + } + } +} + +class AltosSensorMM { + int tick; + int sense[]; + int v_batt; + int v_pyro; + int accel; + int accel_ref; + + public AltosSensorMM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + sense = new int[6]; + 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("0:")) { + sense[0] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("1:")) { + sense[1] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("2:")) { + sense[2] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("3:")) { + sense[3] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("4:")) { + sense[4] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("5:")) { + sense[5] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("6:")) { + v_batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("7:")) { + v_pyro = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("8:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("9:")) { + accel_ref = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + for (int i = 0; i < sense.length; i++) + System.out.printf("sense[%d]: %d\n", i, sense[i]); + break; + } + } +} + +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; + } + } +} + +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(); + } + String[] items = line.split("\\s+"); + if (line.startsWith("Pressure:")) { + 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]); + } else if (line.startsWith("ms5607 reserved:")) { + if (items.length >= 3) + reserved = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 sens:")) { + if (items.length >= 3) + sens = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 off:")) { + if (items.length >= 3) + off = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tcs:")) { + if (items.length >= 3) + tcs = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tco:")) { + if (items.length >= 3) + tco = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tref:")) { + if (items.length >= 3) + tref = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tempsens:")) { + if (items.length >= 3) + tempsens = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 crc:")) { + if (items.length >= 3) + crc = Integer.parseInt(items[2]); + } else if (line.startsWith("Altitude")) + break; + } + convert(); + } +} + +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; + } + } +} + +public class AltosIdleMonitor extends Thread { + AltosLink link; + AltosIdleMonitorListener listener; + AltosState state; + boolean remote; + double frequency; + AltosState previous_state; + AltosConfigData config_data; + AltosGPS gps; + + int AltosRSSI() throws TimeoutException, InterruptedException { + link.printf("s\n"); + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + if (items.length < 2) + return 0; + if (!items[0].equals("RSSI:")) + return 0; + int rssi = Integer.parseInt(items[1]); + return rssi; + } + + void update_state() throws InterruptedException, TimeoutException { + AltosRecord record; + int rssi; + + try { + if (remote) { + link.set_radio_frequency(frequency); + link.start_remote(); + } else + link.flush_input(); + config_data = new AltosConfigData(link); + if (config_data.product.startsWith("TeleMetrum")) { + AltosRecordTM record_tm = new AltosRecordTM(); + AltosSensorTM sensor = new AltosSensorTM(link); + record_tm.accel = sensor.accel; + record_tm.pres = sensor.pres; + record_tm.batt = sensor.batt; + record_tm.temp = sensor.temp; + record_tm.drogue = sensor.drogue; + record_tm.main = sensor.main; + record_tm.ground_accel = record_tm.accel; + record_tm.ground_pres = record_tm.pres; + record_tm.accel_plus_g = config_data.accel_cal_plus; + record_tm.accel_minus_g = config_data.accel_cal_minus; + record_tm.tick = sensor.tick; + record = record_tm; + } else if (config_data.product.startsWith("MegaMetrum")) { + 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; + + record = record_mm; + } else + record = new AltosRecord(); + + gps = new AltosGPSQuery(link, config_data); + } finally { + if (remote) { + link.stop_remote(); + rssi = AltosRSSI(); + } else + rssi = 0; + } + + record.version = 0; + record.callsign = config_data.callsign; + record.serial = config_data.serial; + record.flight = config_data.log_available() > 0 ? 255 : 0; + record.rssi = rssi; + record.status = 0; + record.state = AltosLib.ao_flight_idle; + + record.gps = gps; + state = new AltosState (record, state); + } + + public void set_frequency(double in_frequency) { + frequency = in_frequency; + } + + public void post_state() { + listener.update(state); + } + + public void run() { + try { + for (;;) { + try { + update_state(); + post_state(); + } catch (TimeoutException te) { + } + Thread.sleep(1000); + } + } catch (InterruptedException ie) { + link.close(); + } + } + + public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) + throws FileNotFoundException, InterruptedException, TimeoutException { + listener = in_listener; + link = in_link; + remote = in_remote; + state = null; + } +} diff --git a/altoslib/AltosIdleMonitorListener.java b/altoslib/AltosIdleMonitorListener.java new file mode 100644 index 00000000..3c18bfaa --- /dev/null +++ b/altoslib/AltosIdleMonitorListener.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public interface AltosIdleMonitorListener { + public void update(AltosState state); +} \ No newline at end of file diff --git a/altoslib/AltosIdleRecordTM.java b/altoslib/AltosIdleRecordTM.java new file mode 100644 index 00000000..112b847e --- /dev/null +++ b/altoslib/AltosIdleRecordTM.java @@ -0,0 +1,268 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosADCTM { + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + + public AltosADCTM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + 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("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + break; + } + } +} + +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; + } + } +} + +public class AltosIdleMonitor extends Thread { + AltosLink link; + AltosIdleMonitorListener listener; + AltosState state; + boolean remote; + double frequency; + AltosState previous_state; + AltosConfigData config_data; + AltosADC adc; + AltosGPS gps; + + int AltosRSSI() throws TimeoutException, InterruptedException { + link.printf("s\n"); + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + if (items.length < 2) + return 0; + if (!items[0].equals("RSSI:")) + return 0; + int rssi = Integer.parseInt(items[1]); + return rssi; + } + + void update_state() throws InterruptedException, TimeoutException { + AltosRecordTM record = new AltosRecordTM(); + int rssi; + + try { + if (remote) { + link.set_radio_frequency(frequency); + link.start_remote(); + } else + link.flush_input(); + config_data = new AltosConfigData(link); + adc = new AltosADC(link); + gps = new AltosGPSQuery(link, config_data); + } finally { + if (remote) { + link.stop_remote(); + rssi = AltosRSSI(); + } else + rssi = 0; + } + + record.version = 0; + record.callsign = config_data.callsign; + record.serial = config_data.serial; + record.flight = config_data.log_available() > 0 ? 255 : 0; + record.rssi = rssi; + record.status = 0; + record.state = AltosLib.ao_flight_idle; + + record.tick = adc.tick; + + record.accel = adc.accel; + record.pres = adc.pres; + record.batt = adc.batt; + record.temp = adc.temp; + record.drogue = adc.drogue; + record.main = adc.main; + + record.ground_accel = record.accel; + record.ground_pres = record.pres; + record.accel_plus_g = config_data.accel_cal_plus; + record.accel_minus_g = config_data.accel_cal_minus; + record.acceleration = 0; + record.speed = 0; + record.height = 0; + record.gps = gps; + state = new AltosState (record, state); + } + + public void set_frequency(double in_frequency) { + frequency = in_frequency; + } + + public void post_state() { + listener.update(state); + } + + public void run() { + try { + for (;;) { + try { + update_state(); + post_state(); + } catch (TimeoutException te) { + } + Thread.sleep(1000); + } + } catch (InterruptedException ie) { + link.close(); + } + } + + public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) + throws FileNotFoundException, InterruptedException, TimeoutException { + listener = in_listener; + link = in_link; + remote = in_remote; + state = null; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index ac97c9cb..a39623ee 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -27,6 +27,8 @@ AltosLib_JAVA = \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ $(SRC)/AltosGreatCircle.java \ + $(SRC)/AltosIdleMonitor.java \ + $(SRC)/AltosIdleMonitorListener.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosLink.java \ $(SRC)/AltosLog.java \ diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index ce608d2b..46ca3e5d 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -29,260 +29,7 @@ import java.util.prefs.*; import java.util.concurrent.*; import org.altusmetrum.AltosLib.*; -class AltosADC { - int tick; - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; - - public AltosADC(AltosSerial serial) throws InterruptedException, TimeoutException { - serial.printf("a\n"); - for (;;) { - String line = serial.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!line.startsWith("tick:")) - continue; - String[] items = line.split("\\s+"); - 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("accel:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("pres:")) { - pres = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("temp:")) { - temp = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("batt:")) { - batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("drogue:")) { - drogue = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("main:")) { - main = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; - } - break; - } - } -} - -class AltosGPSQuery extends AltosGPS { - public AltosGPSQuery (AltosSerial serial, AltosConfigData config_data) - throws TimeoutException, InterruptedException { - boolean says_done = config_data.compare_version("1.0") >= 0; - serial.printf("g\n"); - for (;;) { - String line = serial.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 & Altos.AO_GPS_RUNNING) != 0; - locked = (status & Altos.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; - } - } -} - -class AltosIdleMonitor extends Thread { - AltosDevice device; - AltosSerial serial; - AltosIdleMonitorUI ui; - AltosState state; - boolean remote; - double frequency; - AltosState previous_state; - AltosConfigData config_data; - AltosADC adc; - AltosGPS gps; - - int AltosRSSI() throws TimeoutException, InterruptedException { - serial.printf("s\n"); - String line = serial.get_reply_no_dialog(5000); - if (line == null) - throw new TimeoutException(); - String[] items = line.split("\\s+"); - if (items.length < 2) - return 0; - if (!items[0].equals("RSSI:")) - return 0; - int rssi = Integer.parseInt(items[1]); - return rssi; - } - - void update_state() throws InterruptedException, TimeoutException { - AltosRecordTM record = new AltosRecordTM(); - int rssi; - - try { - if (remote) { - serial.set_radio_frequency(frequency); - serial.start_remote(); - } else - serial.flush_input(); - config_data = new AltosConfigData(serial); - adc = new AltosADC(serial); - gps = new AltosGPSQuery(serial, config_data); - } finally { - if (remote) { - serial.stop_remote(); - rssi = AltosRSSI(); - } else - rssi = 0; - } - - record.version = 0; - record.callsign = config_data.callsign; - record.serial = config_data.serial; - record.flight = config_data.log_available() > 0 ? 255 : 0; - record.rssi = rssi; - record.status = 0; - record.state = Altos.ao_flight_idle; - - record.tick = adc.tick; - - record.accel = adc.accel; - record.pres = adc.pres; - record.batt = adc.batt; - record.temp = adc.temp; - record.drogue = adc.drogue; - record.main = adc.main; - - record.ground_accel = record.accel; - record.ground_pres = record.pres; - record.accel_plus_g = config_data.accel_cal_plus; - record.accel_minus_g = config_data.accel_cal_minus; - record.acceleration = 0; - record.speed = 0; - record.height = 0; - record.gps = gps; - state = new AltosState (record, state); - } - - void set_frequency(double in_frequency) { - frequency = in_frequency; - } - - public void post_state() { - Runnable r = new Runnable() { - public void run() { - ui.update(state); - } - }; - SwingUtilities.invokeLater(r); - } - - public void run() { - try { - for (;;) { - try { - update_state(); - post_state(); - } catch (TimeoutException te) { - if (AltosSerial.debug) - System.out.printf ("monitor idle data timeout\n"); - } - Thread.sleep(1000); - } - } catch (InterruptedException ie) { - serial.close(); - } - } - - public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote) - throws FileNotFoundException, AltosSerialInUseException, InterruptedException, TimeoutException { - device = in_device; - ui = in_ui; - serial = new AltosSerial(device); - remote = in_remote; - state = null; - } -} - -public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { +public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener { AltosDevice device; JTabbedPane pane; AltosPad pad; @@ -333,8 +80,13 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay } } - public void update(AltosState state) { - show (state, 0); + public void update(final AltosState state) { + Runnable r = new Runnable() { + public void run() { + show(state, 0); + } + }; + SwingUtilities.invokeLater(r); } Container bag; @@ -427,7 +179,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay pack(); setVisible(true); - thread = new AltosIdleMonitor(this, device, remote); + thread = new AltosIdleMonitor((AltosIdleMonitorListener) this, (AltosLink) new AltosSerial (device), (boolean) remote); status_update = new AltosFlightStatusUpdate(flightStatus); -- cgit v1.2.3 From f164e48cbeff521d45737794e2046a08322951d6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 18 Jul 2012 00:01:51 -0700 Subject: altosui: Make scan UI handle incremental telem data The new telem format doesn't send everything in each telem packet, so we need to handle updating information incrementally in the scan results. This involved clearing old scan data when switching frequencies and then updating existing entries with new data as it arrives. Signed-off-by: Keith Packard --- altoslib/AltosIdleMonitor.java | 2 -- altoslib/AltosTelemetryReader.java | 5 +++++ altosui/AltosScanUI.java | 42 +++++++++++++++++++++++++++++--------- 3 files changed, 37 insertions(+), 12 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index cd518c28..57c4da71 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -162,8 +162,6 @@ class AltosSensorMM { } i++; } - for (int i = 0; i < sense.length; i++) - System.out.printf("sense[%d]: %d\n", i, sense[i]); break; } } diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 911a099a..bdb44eef 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -44,6 +44,11 @@ public class AltosTelemetryReader extends AltosFlightReader { telem.clear(); } + public void reset() { + previous = null; + flush(); + } + public void close(boolean interrupted) { link.remove_monitor(telem); log.close(); diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 44eeda6d..ef6389b6 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -59,29 +59,50 @@ class AltosScanResult { } public boolean equals(AltosScanResult other) { - return (callsign.equals(other.callsign) && - serial == other.serial && - flight == other.flight && + return (serial == other.serial && frequency.frequency == other.frequency.frequency && telemetry == other.telemetry); } + + public boolean up_to_date(AltosScanResult other) { + if (flight == 0 && other.flight != 0) { + flight = other.flight; + return false; + } + if (callsign.equals("N0CALL") && !other.callsign.equals("N0CALL")) { + callsign = other.callsign; + return false; + } + return true; + } } class AltosScanResults extends LinkedList implements ListModel { LinkedList listeners = new LinkedList(); + void changed(ListDataEvent de) { + for (ListDataListener l : listeners) + l.contentsChanged(de); + } + public boolean add(AltosScanResult r) { - for (AltosScanResult old : this) - if (old.equals(r)) + int i = 0; + for (AltosScanResult old : this) { + if (old.equals(r)) { + if (!old.up_to_date(r)) + changed (new ListDataEvent(this, + ListDataEvent.CONTENTS_CHANGED, + i, i)); return true; + } + i++; + } super.add(r); - ListDataEvent de = new ListDataEvent(this, - ListDataEvent.INTERVAL_ADDED, - this.size() - 2, this.size() - 1); - for (ListDataListener l : listeners) - l.contentsChanged(de); + changed(new ListDataEvent(this, + ListDataEvent.INTERVAL_ADDED, + this.size() - 2, this.size() - 1)); return true; } @@ -205,6 +226,7 @@ public class AltosScanUI void set_frequency() throws InterruptedException, TimeoutException { reader.set_frequency(frequencies[frequency_index].frequency); + reader.reset(); } void next() throws InterruptedException, TimeoutException { -- cgit v1.2.3 From 233ab58df8ac8e1fdeab8d4c2f6c8c9d3f6e7be1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 22 Jul 2012 11:53:44 -0700 Subject: altosui: Move AltosIgnite.java to altoslib To be shared with altosdroid eventually Signed-off-by: Keith Packard --- altoslib/AltosIgnite.java | 180 +++++++++++++++++++++++++++++++++++++++++ altoslib/Makefile.am | 1 + altosui/AltosIgnite.java | 195 --------------------------------------------- altosui/AltosIgniteUI.java | 7 +- altosui/Makefile.am | 1 - 5 files changed, 186 insertions(+), 198 deletions(-) create mode 100644 altoslib/AltosIgnite.java delete mode 100644 altosui/AltosIgnite.java (limited to 'altoslib') diff --git a/altoslib/AltosIgnite.java b/altoslib/AltosIgnite.java new file mode 100644 index 00000000..cc814337 --- /dev/null +++ b/altoslib/AltosIgnite.java @@ -0,0 +1,180 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.concurrent.*; + +public class AltosIgnite { + AltosLink link; + boolean remote; + boolean link_started; + + public final static int None = 0; + public final static int Apogee = 1; + public final static int Main = 2; + + public final static int Unknown = 0; + public final static int Ready = 1; + public final static int Active = 2; + public final static int Open = 3; + + private void start_link() throws InterruptedException, TimeoutException { + link_started = true; + if (remote) + link.start_remote(); + } + + private void stop_link() throws InterruptedException { + if (!link_started) + return; + link_started = false; + if (link == null) + return; + if (remote) + link.stop_remote(); + } + + class string_ref { + String value; + + public String get() { + return value; + } + public void set(String i) { + value = i; + } + public string_ref() { + value = null; + } + } + + private boolean get_string(String line, String label, string_ref s) { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + s.set(quoted); + return true; + } else { + return false; + } + } + + private int status(String status_name) { + if (status_name.equals("unknown")) + return Unknown; + if (status_name.equals("ready")) + return Ready; + if (status_name.equals("active")) + return Active; + if (status_name.equals("open")) + return Open; + return Unknown; + } + + public int status(int igniter) throws InterruptedException, TimeoutException { + int status = Unknown; + if (link == null) + return status; + string_ref status_name = new string_ref(); + try { + start_link(); + link.printf("t\n"); + for (;;) { + String line = link.get_reply(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + + if (items.length < 4) + continue; + + if (!items[0].equals("Igniter:")) + continue; + + if (!items[2].equals("Status:")) + continue; + + if (items[1].equals("drogue")) { + if (igniter == Apogee) + status = status(items[3]); + } else if (items[1].equals("main")) { + if (igniter == Main) + status = status(items[3]); + break; + } + } + } finally { + stop_link(); + } + return status; + } + + public static String status_string(int status) { + switch (status) { + case Unknown: return "Unknown"; + case Ready: return "Ready"; + case Active: return "Active"; + case Open: return "Open"; + default: return "Unknown"; + } + } + + public void fire(int igniter) { + if (link == null) + return; + try { + start_link(); + switch (igniter) { + case Main: + link.printf("i DoIt main\n"); + break; + case Apogee: + link.printf("i DoIt drogue\n"); + break; + } + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + } finally { + try { + stop_link(); + } catch (InterruptedException ie) { + } + } + } + + public void close() { + try { + stop_link(); + } catch (InterruptedException ie) { + } + link.close(); + link = null; + } + + public AltosIgnite(AltosLink in_link, boolean in_remote) + throws FileNotFoundException, TimeoutException, InterruptedException { + + link = in_link; + remote = in_remote; + } +} \ No newline at end of file diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index a39623ee..1f42140b 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -29,6 +29,7 @@ AltosLib_JAVA = \ $(SRC)/AltosGreatCircle.java \ $(SRC)/AltosIdleMonitor.java \ $(SRC)/AltosIdleMonitorListener.java \ + $(SRC)/AltosIgnite.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosLink.java \ $(SRC)/AltosLog.java \ diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java deleted file mode 100644 index f84db0b9..00000000 --- a/altosui/AltosIgnite.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -import java.io.*; -import java.util.concurrent.*; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import javax.swing.event.*; -import org.altusmetrum.AltosLib.*; - -public class AltosIgnite { - AltosDevice device; - AltosSerial serial; - boolean remote; - boolean serial_started; - final static int None = 0; - final static int Apogee = 1; - final static int Main = 2; - - final static int Unknown = 0; - final static int Ready = 1; - final static int Active = 2; - final static int Open = 3; - - private void start_serial() throws InterruptedException, TimeoutException { - serial_started = true; - if (remote) - serial.start_remote(); - } - - private void stop_serial() throws InterruptedException { - if (!serial_started) - return; - serial_started = false; - if (serial == null) - return; - if (remote) - serial.stop_remote(); - } - - class string_ref { - String value; - - public String get() { - return value; - } - public void set(String i) { - value = i; - } - public string_ref() { - value = null; - } - } - - private boolean get_string(String line, String label, string_ref s) { - if (line.startsWith(label)) { - String quoted = line.substring(label.length()).trim(); - - if (quoted.startsWith("\"")) - quoted = quoted.substring(1); - if (quoted.endsWith("\"")) - quoted = quoted.substring(0,quoted.length()-1); - s.set(quoted); - return true; - } else { - return false; - } - } - - private int status(String status_name) { - if (status_name.equals("unknown")) - return Unknown; - if (status_name.equals("ready")) - return Ready; - if (status_name.equals("active")) - return Active; - if (status_name.equals("open")) - return Open; - return Unknown; - } - - public int status(int igniter) throws InterruptedException, TimeoutException { - int status = Unknown; - if (serial == null) - return status; - string_ref status_name = new string_ref(); - try { - start_serial(); - serial.printf("t\n"); - for (;;) { - String line = serial.get_reply(5000); - if (line == null) - throw new TimeoutException(); - String[] items = line.split("\\s+"); - - if (items.length < 4) - continue; - - if (!items[0].equals("Igniter:")) - continue; - - if (!items[2].equals("Status:")) - continue; - - if (items[1].equals("drogue")) { - if (igniter == Apogee) - status = status(items[3]); - } else if (items[1].equals("main")) { - if (igniter == Main) - status = status(items[3]); - break; - } - } - } finally { - stop_serial(); - } - return status; - } - - public static String status_string(int status) { - switch (status) { - case Unknown: return "Unknown"; - case Ready: return "Ready"; - case Active: return "Active"; - case Open: return "Open"; - default: return "Unknown"; - } - } - - public void fire(int igniter) { - if (serial == null) - return; - try { - start_serial(); - switch (igniter) { - case Main: - serial.printf("i DoIt main\n"); - break; - case Apogee: - serial.printf("i DoIt drogue\n"); - break; - } - } catch (InterruptedException ie) { - } catch (TimeoutException te) { - } finally { - try { - stop_serial(); - } catch (InterruptedException ie) { - } - } - } - - public void close() { - try { - stop_serial(); - } catch (InterruptedException ie) { - } - serial.close(); - serial = null; - } - - public void set_frame(Frame frame) { - serial.set_frame(frame); - } - - public AltosIgnite(AltosDevice in_device) - throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException { - - device = in_device; - serial = new AltosSerial(device); - remote = false; - - if (!device.matchProduct(Altos.product_altimeter)) - remote = true; - } -} \ No newline at end of file diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 076d99b2..78eba8e6 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -72,12 +72,15 @@ public class AltosIgniteUI public void run () { try { - ignite = new AltosIgnite(device); + AltosSerial serial = new AltosSerial(device); + serial.set_frame(owner); + ignite = new AltosIgnite(serial, + !device.matchProduct(Altos.product_altimeter)); + } catch (Exception e) { send_exception(e); return; } - ignite.set_frame(owner); for (;;) { Runnable r; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 1c8ea491..19db6698 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -55,7 +55,6 @@ altosui_JAVA = \ AltosHexfile.java \ Altos.java \ AltosIdleMonitorUI.java \ - AltosIgnite.java \ AltosIgniteUI.java \ AltosLaunch.java \ AltosLaunchUI.java \ -- cgit v1.2.3 From 0bf21399d3d47d58410df4c6ce89fc20fcd42c89 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 29 Jul 2012 19:34:00 -0700 Subject: altosui: Handle Monitor Idle errors better Deal with missing data by checking for MISSING in more places. Handle serial communication failures during send by reporting back from libaltos. Signed-off-by: Keith Packard --- altoslib/AltosIdleMonitor.java | 67 +++++++++++++++++------------------------- altoslib/AltosLink.java | 20 +++++++++++-- altoslib/AltosRecord.java | 2 +- altoslib/AltosRecordTM.java | 16 +++++----- altoslib/AltosState.java | 2 ++ altosui/AltosSerial.java | 14 +++++++-- altosui/libaltos/libaltos.c | 4 +-- 7 files changed, 70 insertions(+), 55 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index 57c4da71..27ea3a2b 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -23,16 +23,10 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; -class AltosSensorTM { - int tick; - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; +class AltosSensorTM extends AltosRecordTM { - public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException { + public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException { + super(); link.printf("a\n"); for (;;) { String line = link.get_reply_no_dialog(5000); @@ -82,6 +76,10 @@ class AltosSensorTM { } break; } + 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; } } @@ -253,7 +251,7 @@ class AltosGPSQuery extends AltosGPS { if (line.startsWith("Date:")) { if (bits.length < 2) continue; - String[] d = bits[1].split(":"); + String[] d = bits[1].split("/"); if (d.length < 3) continue; year = Integer.parseInt(d[0]) + 2000; @@ -264,7 +262,7 @@ class AltosGPSQuery extends AltosGPS { if (line.startsWith("Time:")) { if (bits.length < 2) continue; - String[] d = bits[1].split("/"); + String[] d = bits[1].split(":"); if (d.length < 3) continue; hour = Integer.parseInt(d[0]); @@ -339,8 +337,7 @@ public class AltosIdleMonitor extends Thread { } void update_state() throws InterruptedException, TimeoutException { - AltosRecord record; - int rssi; + AltosRecord record = null; try { if (remote) { @@ -350,20 +347,7 @@ public class AltosIdleMonitor extends Thread { link.flush_input(); config_data = new AltosConfigData(link); if (config_data.product.startsWith("TeleMetrum")) { - AltosRecordTM record_tm = new AltosRecordTM(); - AltosSensorTM sensor = new AltosSensorTM(link); - record_tm.accel = sensor.accel; - record_tm.pres = sensor.pres; - record_tm.batt = sensor.batt; - record_tm.temp = sensor.temp; - record_tm.drogue = sensor.drogue; - record_tm.main = sensor.main; - record_tm.ground_accel = record_tm.accel; - record_tm.ground_pres = record_tm.pres; - record_tm.accel_plus_g = config_data.accel_cal_plus; - record_tm.accel_minus_g = config_data.accel_cal_minus; - record_tm.tick = sensor.tick; - record = record_tm; + record = new AltosSensorTM(link, config_data); } else if (config_data.product.startsWith("MegaMetrum")) { AltosRecordMM record_mm = new AltosRecordMM(); AltosSensorMM sensor = new AltosSensorMM(link); @@ -390,24 +374,27 @@ public class AltosIdleMonitor extends Thread { record = new AltosRecord(); 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.new_gps = true; + state = new AltosState (record, state); } finally { if (remote) { link.stop_remote(); - rssi = AltosRSSI(); - } else - rssi = 0; + if (record != null) + record.rssi = AltosRSSI(); + } else { + if (record != null) + record.rssi = 0; + } } - record.version = 0; - record.callsign = config_data.callsign; - record.serial = config_data.serial; - record.flight = config_data.log_available() > 0 ? 255 : 0; - record.rssi = rssi; - record.status = 0; - record.state = AltosLib.ao_flight_idle; - - record.gps = gps; - state = new AltosState (record, state); } public void set_frequency(double in_frequency) { diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index d59e73ba..fd5db7e9 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -101,15 +101,23 @@ public abstract class AltosLink { try { for (;;) { c = getchar(); - if (Thread.interrupted()) + if (Thread.interrupted()) { + if (debug) + System.out.printf("INTERRUPTED\n"); break; + } if (c == ERROR) { + if (debug) + System.out.printf("ERROR\n"); add_telem (new AltosLine()); add_reply (new AltosLine()); break; } - if (c == TIMEOUT) + if (c == TIMEOUT) { + if (debug) + System.out.printf("TIMEOUT\n"); continue; + } if (c == '\r') continue; synchronized(this) { @@ -180,6 +188,14 @@ public abstract class AltosLink { reply_queue.put (line); } + public void abort_reply() { + try { + add_telem (new AltosLine()); + add_reply (new AltosLine()); + } catch (InterruptedException e) { + } + } + public void add_string(String line) throws InterruptedException { if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { add_telem(new AltosLine(line)); diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index e468f84b..8722bc05 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -127,7 +127,7 @@ public class AltosRecord implements Comparable , Cloneable { double p = filtered_pressure(); if (p == MISSING) - return MISSING; + return raw_altitude(); return AltosConvert.pressure_to_altitude(p); } diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java index afb70790..37accef6 100644 --- a/altoslib/AltosRecordTM.java +++ b/altoslib/AltosRecordTM.java @@ -177,14 +177,14 @@ public class AltosRecordTM extends AltosRecord { drogue = MISSING; main = MISSING; - flight_accel = 0; - flight_vel = 0; - flight_pres = 0; - - ground_accel = 0; - ground_pres = 0; - accel_plus_g = 0; - accel_minus_g = 0; + 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) { diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index e20ec9a7..3b37a3d4 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -38,6 +38,7 @@ public class AltosState { public boolean boost; /* under power */ public double ground_altitude; + public double altitude; public double height; public double speed; public double acceleration; @@ -82,6 +83,7 @@ public class AltosState { data = cur; ground_altitude = data.ground_altitude(); + altitude = data.raw_altitude(); height = data.filtered_height(); report_time = System.currentTimeMillis(); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index c4e9c697..8b692fa9 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -54,13 +54,19 @@ public class AltosSerial extends AltosLink implements Runnable { Frame frame; public int getchar() { + if (altos == null) + return ERROR; return libaltos.altos_getchar(altos, 0); } public void flush_output() { super.flush_output(); if (altos != null) { - libaltos.altos_flush(altos); + if (libaltos.altos_flush(altos) != 0) { + libaltos.altos_close(altos); + altos = null; + abort_reply(); + } } } @@ -155,7 +161,11 @@ public class AltosSerial extends AltosLink implements Runnable { private void putc(char c) { if (altos != null) - libaltos.altos_putchar(altos, c); + if (libaltos.altos_putchar(altos, c) != 0) { + libaltos.altos_close(altos); + altos = null; + abort_reply(); + } } public void print(String data) { diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 1cc27cbe..515432f9 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -221,7 +221,7 @@ altos_flush(struct altos_file *file) #endif if (ret < 0) { altos_set_last_posix_error(); - return -errno; + return -last_error.code; } if (ret) { memmove(file->out_data, file->out_data + ret, @@ -247,7 +247,7 @@ altos_putchar(struct altos_file *file, char c) ret = 0; if (file->out_used == USB_BUF_SIZE) ret = altos_flush(file); - return 0; + return ret; } #ifdef USE_POLL -- cgit v1.2.3 From 82a37d70e3cacf792c1aa18f8c0d2a19d6f321ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 4 Aug 2012 22:58:48 -0700 Subject: altosui: Move 'implements Runnable' from AltosSerial to AltosLink AltosLink is the class providing the 'run' method, after all... Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 2 +- altosui/AltosSerial.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index fd5db7e9..415c3c64 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -23,7 +23,7 @@ import java.util.concurrent.*; import java.util.*; import java.text.*; -public abstract class AltosLink { +public abstract class AltosLink implements Runnable { public final static int ERROR = -1; public final static int TIMEOUT = -2; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 8b692fa9..6cee1609 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -41,7 +41,7 @@ import libaltosJNI.*; * threads. */ -public class AltosSerial extends AltosLink implements Runnable { +public class AltosSerial extends AltosLink { static java.util.List devices_opened = Collections.synchronizedList(new LinkedList()); -- cgit v1.2.3 From 6d31f8d15ef4bf75ae039dd7b1a6a615d00eb215 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 31 Aug 2012 17:53:53 +1200 Subject: altoslib: add missing manufacturer parsing for AltosConfigData Signed-off-by: Mike Beattie --- altoslib/AltosConfigData.java | 1 + 1 file changed, 1 insertion(+) (limited to 'altoslib') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index ecc2d0aa..c143036c 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -170,6 +170,7 @@ public class AltosConfigData implements Iterable { try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} try { version = get_string(line,"software-version"); } catch (Exception e) {} try { product = get_string(line,"product"); } catch (Exception e) {} + try { manufacturer = get_string(line,"manufacturer"); } catch (Exception e) {} try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} -- cgit v1.2.3 From 20bc23ddb90f8a6da1f7ea70f02cf3a038059d32 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 17:32:07 +1200 Subject: altoslib: Remove un-needed imports Signed-off-by: Mike Beattie --- altoslib/AltosConfigData.java | 3 --- altoslib/AltosEepromChunk.java | 2 -- altoslib/AltosEepromIterable.java | 2 -- altoslib/AltosEepromLog.java | 3 --- altoslib/AltosEepromMega.java | 4 ---- altoslib/AltosEepromMegaIterable.java | 2 -- altoslib/AltosEepromRecord.java | 4 ---- altoslib/AltosEepromTeleScience.java | 4 ---- altoslib/AltosFile.java | 1 - altoslib/AltosFlightReader.java | 1 - altoslib/AltosFrequency.java | 4 ---- altoslib/AltosGPS.java | 1 - altoslib/AltosIdleMonitor.java | 3 --- altoslib/AltosIdleMonitorListener.java | 6 ------ altoslib/AltosIdleRecordTM.java | 4 ---- altoslib/AltosLib.java | 2 -- altoslib/AltosLink.java | 2 -- altoslib/AltosLog.java | 2 -- altoslib/AltosParse.java | 1 - altoslib/AltosPreferences.java | 4 ---- altoslib/AltosRecord.java | 5 ----- altoslib/AltosReplayReader.java | 3 --- altoslib/AltosTelemetry.java | 2 -- altoslib/AltosTelemetryMap.java | 1 - altoslib/AltosTelemetryReader.java | 1 - altoslib/AltosTelemetryRecordGeneral.java | 2 -- altoslib/AltosTelemetryRecordLegacy.java | 2 -- altoslib/AltosTelemetryRecordRaw.java | 4 ---- 28 files changed, 75 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index ecc2d0aa..c6e92e62 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -17,12 +17,9 @@ package org.altusmetrum.AltosLib; -import java.io.*; import java.util.*; import java.text.*; -import java.util.prefs.*; import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; public class AltosConfigData implements Iterable { diff --git a/altoslib/AltosEepromChunk.java b/altoslib/AltosEepromChunk.java index 6d889723..77b22fe2 100644 --- a/altoslib/AltosEepromChunk.java +++ b/altoslib/AltosEepromChunk.java @@ -17,8 +17,6 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; import java.text.*; import java.util.concurrent.*; diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index f8acdc16..fc308c34 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -20,8 +20,6 @@ package org.altusmetrum.AltosLib; import java.io.*; import java.util.*; import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; /* * AltosRecords with an index field so they can be sorted by tick while preserving diff --git a/altoslib/AltosEepromLog.java b/altoslib/AltosEepromLog.java index 7fca4bd9..e27c382a 100644 --- a/altoslib/AltosEepromLog.java +++ b/altoslib/AltosEepromLog.java @@ -17,10 +17,7 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; import java.text.*; -import java.util.prefs.*; import java.util.concurrent.*; /* diff --git a/altoslib/AltosEepromMega.java b/altoslib/AltosEepromMega.java index 2628279e..26bacf8d 100644 --- a/altoslib/AltosEepromMega.java +++ b/altoslib/AltosEepromMega.java @@ -17,11 +17,7 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; public class AltosEepromMega { public int cmd; diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java index f62cc45b..be20ba63 100644 --- a/altoslib/AltosEepromMegaIterable.java +++ b/altoslib/AltosEepromMegaIterable.java @@ -20,8 +20,6 @@ package org.altusmetrum.AltosLib; import java.io.*; import java.util.*; import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; /* * AltosRecords with an index field so they can be sorted by tick while preserving diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java index 1e845f46..c7ced6a3 100644 --- a/altoslib/AltosEepromRecord.java +++ b/altoslib/AltosEepromRecord.java @@ -17,11 +17,7 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; public class AltosEepromRecord { public int cmd; diff --git a/altoslib/AltosEepromTeleScience.java b/altoslib/AltosEepromTeleScience.java index 1758fa34..02ce4553 100644 --- a/altoslib/AltosEepromTeleScience.java +++ b/altoslib/AltosEepromTeleScience.java @@ -17,11 +17,7 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; public class AltosEepromTeleScience { public int type; diff --git a/altoslib/AltosFile.java b/altoslib/AltosFile.java index d2e4f2f7..1ab00b38 100644 --- a/altoslib/AltosFile.java +++ b/altoslib/AltosFile.java @@ -17,7 +17,6 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.io.File; import java.util.*; diff --git a/altoslib/AltosFlightReader.java b/altoslib/AltosFlightReader.java index 3fdea469..cbd64153 100644 --- a/altoslib/AltosFlightReader.java +++ b/altoslib/AltosFlightReader.java @@ -17,7 +17,6 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.text.*; import java.io.*; import java.util.concurrent.*; diff --git a/altoslib/AltosFrequency.java b/altoslib/AltosFrequency.java index f08ff116..e20f03b7 100644 --- a/altoslib/AltosFrequency.java +++ b/altoslib/AltosFrequency.java @@ -17,10 +17,6 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; -import java.text.*; - public class AltosFrequency { public double frequency; public String description; diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index f078a469..2c2fd36b 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -17,7 +17,6 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.text.*; public class AltosGPS { diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index 27ea3a2b..d83c4450 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -18,9 +18,6 @@ package org.altusmetrum.AltosLib; import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; import java.util.concurrent.*; class AltosSensorTM extends AltosRecordTM { diff --git a/altoslib/AltosIdleMonitorListener.java b/altoslib/AltosIdleMonitorListener.java index 3c18bfaa..9f9ababf 100644 --- a/altoslib/AltosIdleMonitorListener.java +++ b/altoslib/AltosIdleMonitorListener.java @@ -17,12 +17,6 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - public interface AltosIdleMonitorListener { public void update(AltosState state); } \ No newline at end of file diff --git a/altoslib/AltosIdleRecordTM.java b/altoslib/AltosIdleRecordTM.java index 112b847e..d48ff7e4 100644 --- a/altoslib/AltosIdleRecordTM.java +++ b/altoslib/AltosIdleRecordTM.java @@ -17,10 +17,6 @@ package org.altusmetrum.AltosLib; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; import java.util.concurrent.*; class AltosADCTM { diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 2402331e..8d383f12 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -17,9 +17,7 @@ package org.altusmetrum.AltosLib; -import java.awt.*; import java.util.*; -import java.text.*; import java.io.*; import java.nio.charset.Charset; diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 415c3c64..6d510563 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -17,11 +17,9 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.io.*; import java.util.concurrent.*; import java.util.*; -import java.text.*; public abstract class AltosLink implements Runnable { diff --git a/altoslib/AltosLog.java b/altoslib/AltosLog.java index 55a25bb4..3c124700 100644 --- a/altoslib/AltosLog.java +++ b/altoslib/AltosLog.java @@ -18,8 +18,6 @@ package org.altusmetrum.AltosLib; import java.io.*; -import java.lang.*; -import java.util.*; import java.text.ParseException; import java.util.concurrent.LinkedBlockingQueue; diff --git a/altoslib/AltosParse.java b/altoslib/AltosParse.java index 7d832f1a..e938a177 100644 --- a/altoslib/AltosParse.java +++ b/altoslib/AltosParse.java @@ -18,7 +18,6 @@ package org.altusmetrum.AltosLib; import java.text.*; -import java.lang.*; public class AltosParse { public static boolean isdigit(char c) { diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 9ab80cf5..13fee46d 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -19,11 +19,7 @@ package org.altusmetrum.AltosLib; import java.io.*; import java.util.*; -import java.text.*; import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.awt.Component; -import javax.swing.*; import javax.swing.filechooser.FileSystemView; public class AltosPreferences { diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index 8722bc05..dd741716 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -17,11 +17,6 @@ package org.altusmetrum.AltosLib; -import java.lang.*; -import java.text.*; -import java.util.HashMap; -import java.io.*; - public class AltosRecord implements Comparable , Cloneable { public static final int seen_flight = 1; diff --git a/altoslib/AltosReplayReader.java b/altoslib/AltosReplayReader.java index 1585f9eb..50bef07a 100644 --- a/altoslib/AltosReplayReader.java +++ b/altoslib/AltosReplayReader.java @@ -19,9 +19,6 @@ package org.altusmetrum.AltosLib; import java.io.*; import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; /* * Open an existing telemetry file and replay it in realtime diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index ee244824..15534158 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -17,9 +17,7 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.text.*; -import java.util.HashMap; /* * Telemetry data contents diff --git a/altoslib/AltosTelemetryMap.java b/altoslib/AltosTelemetryMap.java index 003cb6a9..bc1486d8 100644 --- a/altoslib/AltosTelemetryMap.java +++ b/altoslib/AltosTelemetryMap.java @@ -16,7 +16,6 @@ */ package org.altusmetrum.AltosLib; -import java.lang.*; import java.text.*; import java.util.HashMap; diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index bdb44eef..94fa560b 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -17,7 +17,6 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.text.*; import java.io.*; import java.util.concurrent.*; diff --git a/altoslib/AltosTelemetryRecordGeneral.java b/altoslib/AltosTelemetryRecordGeneral.java index 5e157a54..a53280cf 100644 --- a/altoslib/AltosTelemetryRecordGeneral.java +++ b/altoslib/AltosTelemetryRecordGeneral.java @@ -17,9 +17,7 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.text.*; -import java.util.HashMap; public class AltosTelemetryRecordGeneral { diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index 3976a07a..b11fed58 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -17,9 +17,7 @@ package org.altusmetrum.AltosLib; -import java.lang.*; import java.text.*; -import java.util.HashMap; /* * Telemetry data contents diff --git a/altoslib/AltosTelemetryRecordRaw.java b/altoslib/AltosTelemetryRecordRaw.java index dc1b8947..fbb373d5 100644 --- a/altoslib/AltosTelemetryRecordRaw.java +++ b/altoslib/AltosTelemetryRecordRaw.java @@ -17,10 +17,6 @@ package org.altusmetrum.AltosLib; -import java.lang.*; -import java.text.*; -import java.util.HashMap; - public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { int[] bytes; int serial; -- cgit v1.2.3 From b02c17b26e028a6f3a46781211a86a18272da4d0 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 17:34:17 +1200 Subject: altoslib: comment out un-used variables Signed-off-by: Mike Beattie --- altoslib/AltosEepromIterable.java | 2 +- altoslib/AltosEepromMegaIterable.java | 2 +- altoslib/AltosIgnite.java | 2 +- altoslib/AltosMs5607.java | 2 +- altoslib/AltosState.java | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index fc308c34..107ad9f0 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -236,7 +236,7 @@ public class AltosEepromIterable extends AltosRecordIterable { Iterator iterator = records.iterator(); AltosOrderedRecord record = null; AltosRecordTM state = new AltosRecordTM(); - boolean last_reported = false; + //boolean last_reported = false; EepromState eeprom = new EepromState(); state.state = AltosLib.ao_flight_pad; diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java index be20ba63..aeb9135d 100644 --- a/altoslib/AltosEepromMegaIterable.java +++ b/altoslib/AltosEepromMegaIterable.java @@ -283,7 +283,7 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { Iterator iterator = records.iterator(); AltosOrderedMegaRecord record = null; AltosRecordMM state = new AltosRecordMM(); - boolean last_reported = false; + //boolean last_reported = false; EepromState eeprom = new EepromState(); state.state = AltosLib.ao_flight_pad; diff --git a/altoslib/AltosIgnite.java b/altoslib/AltosIgnite.java index cc814337..e89f1b65 100644 --- a/altoslib/AltosIgnite.java +++ b/altoslib/AltosIgnite.java @@ -95,7 +95,7 @@ public class AltosIgnite { int status = Unknown; if (link == null) return status; - string_ref status_name = new string_ref(); + //string_ref status_name = new string_ref(); try { start_link(); link.printf("t\n"); diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index 5fd997d8..268e89f6 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -37,7 +37,7 @@ public class AltosMs5607 { int TEMP; long OFF; long SENS; - int P; + //int P; dT = raw_temp - ((int) tref << 8); diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 3b37a3d4..2806812e 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -77,8 +77,8 @@ public class AltosState { public double speak_altitude; public void init (AltosRecord cur, AltosState prev_state) { - int i; - AltosRecord prev; + //int i; + //AltosRecord prev; data = cur; -- cgit v1.2.3 From 369c5e23ac6d65bab4b456ed86737576ac61102f Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 17:35:29 +1200 Subject: altoslib: access static variables via class, not instance Signed-off-by: Mike Beattie --- altoslib/AltosEepromLog.java | 2 +- altoslib/AltosTelemetryRecordLegacy.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosEepromLog.java b/altoslib/AltosEepromLog.java index e27c382a..211fd706 100644 --- a/altoslib/AltosEepromLog.java +++ b/altoslib/AltosEepromLog.java @@ -72,7 +72,7 @@ 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 < eechunk.chunk_size; i += AltosEepromRecord.record_length) { + for (int i = 0; i < AltosEepromChunk.chunk_size; i += AltosEepromRecord.record_length) { try { AltosEepromRecord r = new AltosEepromRecord(eechunk, i); diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index b11fed58..9e75fa2c 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -476,7 +476,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { record.gps = new AltosGPS(); record.new_gps = true; - record.seen |= record.seen_gps_time | record.seen_gps_lat | record.seen_gps_lon; + 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; -- cgit v1.2.3 From 639f3e5e5171769429eac9e2f17a7b315fd62135 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 17:39:25 +1200 Subject: altoslib: comment out unused methods Signed-off-by: Mike Beattie --- altoslib/AltosIgnite.java | 2 ++ altoslib/AltosTelemetryRecordLegacy.java | 2 ++ 2 files changed, 4 insertions(+) (limited to 'altoslib') diff --git a/altoslib/AltosIgnite.java b/altoslib/AltosIgnite.java index e89f1b65..a48d0b69 100644 --- a/altoslib/AltosIgnite.java +++ b/altoslib/AltosIgnite.java @@ -64,6 +64,7 @@ public class AltosIgnite { } } + /* private boolean get_string(String line, String label, string_ref s) { if (line.startsWith(label)) { String quoted = line.substring(label.length()).trim(); @@ -78,6 +79,7 @@ public class AltosIgnite { return false; } } + */ private int status(String status_name) { if (status_name.equals("unknown")) diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index 9e75fa2c..21176069 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -392,9 +392,11 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { int[] bytes; int adjust; + /* private int int8(int i) { return AltosLib.int8(bytes, i + 1 + adjust); } + */ private int uint8(int i) { return AltosLib.uint8(bytes, i + 1 + adjust); } -- cgit v1.2.3 From 02d31db3d3255568cc348a41aa37a461d63ffde2 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 17:52:27 +1200 Subject: altoslib: resolve argument/variable ambiguity (and comment out set_flags() which had no corresponding variable anyway) Signed-off-by: Mike Beattie --- altoslib/AltosGPS.java | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index 2c2fd36b..ea0949ec 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -174,24 +174,26 @@ public class AltosGPS { lon = in_lon / 10.0e7; } - public void set_time(int hour, int minute, int second) { - hour = hour; - minute = minute; - second = second; + public void set_time(int in_hour, int in_minute, int in_second) { + hour = in_hour; + minute = in_minute; + second = in_second; } - public void set_date(int year, int month, int day) { - year = year; - month = month; - day = day; + public void set_date(int in_year, int in_month, int in_day) { + year = in_year; + month = in_month; + day = in_day; } - public void set_flags(int flags) { - flags = flags; + /* + public void set_flags(int in_flags) { + flags = in_flags; } + */ - public void set_altitude(int altitude) { - altitude = altitude; + public void set_altitude(int in_altitude) { + alt = in_altitude; } public void add_sat(int svid, int c_n0) { -- cgit v1.2.3 From bbbe1846346b4ba61330f535a12b7a5029877ee6 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 17:53:20 +1200 Subject: altoslib: remove dead code (if object creation fails, an exception will be thrown - not return null) Signed-off-by: Mike Beattie --- altoslib/AltosEepromIterable.java | 2 -- altoslib/AltosEepromMegaIterable.java | 2 -- 2 files changed, 4 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index 107ad9f0..7c752271 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -401,8 +401,6 @@ public class AltosEepromIterable extends AltosRecordIterable { if (line == null) break; AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); - if (record == null) - break; if (record.cmd == AltosLib.AO_LOG_INVALID) continue; prev_tick = record.tick; diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java index aeb9135d..f0786e12 100644 --- a/altoslib/AltosEepromMegaIterable.java +++ b/altoslib/AltosEepromMegaIterable.java @@ -450,8 +450,6 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { if (line == null) break; AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); - if (record == null) - break; if (record.cmd == AltosLib.AO_LOG_INVALID) continue; prev_tick = record.tick; -- cgit v1.2.3 From 88667f7b7dff52eaf5e30f8f83fed0d7f767268d Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 18:07:45 +1200 Subject: altoslib: rename AltosIdleRecordTM.java to AltosGPSQuery.java Signed-off-by: Mike Beattie --- altoslib/AltosGPSQuery.java | 264 ++++++++++++++++++++++++++++++++++++++++ altoslib/AltosIdleRecordTM.java | 264 ---------------------------------------- 2 files changed, 264 insertions(+), 264 deletions(-) create mode 100644 altoslib/AltosGPSQuery.java delete mode 100644 altoslib/AltosIdleRecordTM.java (limited to 'altoslib') diff --git a/altoslib/AltosGPSQuery.java b/altoslib/AltosGPSQuery.java new file mode 100644 index 00000000..d48ff7e4 --- /dev/null +++ b/altoslib/AltosGPSQuery.java @@ -0,0 +1,264 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.util.concurrent.*; + +class AltosADCTM { + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + + public AltosADCTM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + 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("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + break; + } + } +} + +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; + } + } +} + +public class AltosIdleMonitor extends Thread { + AltosLink link; + AltosIdleMonitorListener listener; + AltosState state; + boolean remote; + double frequency; + AltosState previous_state; + AltosConfigData config_data; + AltosADC adc; + AltosGPS gps; + + int AltosRSSI() throws TimeoutException, InterruptedException { + link.printf("s\n"); + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + if (items.length < 2) + return 0; + if (!items[0].equals("RSSI:")) + return 0; + int rssi = Integer.parseInt(items[1]); + return rssi; + } + + void update_state() throws InterruptedException, TimeoutException { + AltosRecordTM record = new AltosRecordTM(); + int rssi; + + try { + if (remote) { + link.set_radio_frequency(frequency); + link.start_remote(); + } else + link.flush_input(); + config_data = new AltosConfigData(link); + adc = new AltosADC(link); + gps = new AltosGPSQuery(link, config_data); + } finally { + if (remote) { + link.stop_remote(); + rssi = AltosRSSI(); + } else + rssi = 0; + } + + record.version = 0; + record.callsign = config_data.callsign; + record.serial = config_data.serial; + record.flight = config_data.log_available() > 0 ? 255 : 0; + record.rssi = rssi; + record.status = 0; + record.state = AltosLib.ao_flight_idle; + + record.tick = adc.tick; + + record.accel = adc.accel; + record.pres = adc.pres; + record.batt = adc.batt; + record.temp = adc.temp; + record.drogue = adc.drogue; + record.main = adc.main; + + record.ground_accel = record.accel; + record.ground_pres = record.pres; + record.accel_plus_g = config_data.accel_cal_plus; + record.accel_minus_g = config_data.accel_cal_minus; + record.acceleration = 0; + record.speed = 0; + record.height = 0; + record.gps = gps; + state = new AltosState (record, state); + } + + public void set_frequency(double in_frequency) { + frequency = in_frequency; + } + + public void post_state() { + listener.update(state); + } + + public void run() { + try { + for (;;) { + try { + update_state(); + post_state(); + } catch (TimeoutException te) { + } + Thread.sleep(1000); + } + } catch (InterruptedException ie) { + link.close(); + } + } + + public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) + throws FileNotFoundException, InterruptedException, TimeoutException { + listener = in_listener; + link = in_link; + remote = in_remote; + state = null; + } +} diff --git a/altoslib/AltosIdleRecordTM.java b/altoslib/AltosIdleRecordTM.java deleted file mode 100644 index d48ff7e4..00000000 --- a/altoslib/AltosIdleRecordTM.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright © 2012 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package org.altusmetrum.AltosLib; - -import java.util.concurrent.*; - -class AltosADCTM { - int tick; - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; - - public AltosADCTM(AltosLink link) throws InterruptedException, TimeoutException { - link.printf("a\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!line.startsWith("tick:")) - continue; - String[] items = line.split("\\s+"); - 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("accel:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("pres:")) { - pres = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("temp:")) { - temp = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("batt:")) { - batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("drogue:")) { - drogue = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("main:")) { - main = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; - } - break; - } - } -} - -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; - } - } -} - -public class AltosIdleMonitor extends Thread { - AltosLink link; - AltosIdleMonitorListener listener; - AltosState state; - boolean remote; - double frequency; - AltosState previous_state; - AltosConfigData config_data; - AltosADC adc; - AltosGPS gps; - - int AltosRSSI() throws TimeoutException, InterruptedException { - link.printf("s\n"); - String line = link.get_reply_no_dialog(5000); - if (line == null) - throw new TimeoutException(); - String[] items = line.split("\\s+"); - if (items.length < 2) - return 0; - if (!items[0].equals("RSSI:")) - return 0; - int rssi = Integer.parseInt(items[1]); - return rssi; - } - - void update_state() throws InterruptedException, TimeoutException { - AltosRecordTM record = new AltosRecordTM(); - int rssi; - - try { - if (remote) { - link.set_radio_frequency(frequency); - link.start_remote(); - } else - link.flush_input(); - config_data = new AltosConfigData(link); - adc = new AltosADC(link); - gps = new AltosGPSQuery(link, config_data); - } finally { - if (remote) { - link.stop_remote(); - rssi = AltosRSSI(); - } else - rssi = 0; - } - - record.version = 0; - record.callsign = config_data.callsign; - record.serial = config_data.serial; - record.flight = config_data.log_available() > 0 ? 255 : 0; - record.rssi = rssi; - record.status = 0; - record.state = AltosLib.ao_flight_idle; - - record.tick = adc.tick; - - record.accel = adc.accel; - record.pres = adc.pres; - record.batt = adc.batt; - record.temp = adc.temp; - record.drogue = adc.drogue; - record.main = adc.main; - - record.ground_accel = record.accel; - record.ground_pres = record.pres; - record.accel_plus_g = config_data.accel_cal_plus; - record.accel_minus_g = config_data.accel_cal_minus; - record.acceleration = 0; - record.speed = 0; - record.height = 0; - record.gps = gps; - state = new AltosState (record, state); - } - - public void set_frequency(double in_frequency) { - frequency = in_frequency; - } - - public void post_state() { - listener.update(state); - } - - public void run() { - try { - for (;;) { - try { - update_state(); - post_state(); - } catch (TimeoutException te) { - } - Thread.sleep(1000); - } - } catch (InterruptedException ie) { - link.close(); - } - } - - public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) - throws FileNotFoundException, InterruptedException, TimeoutException { - listener = in_listener; - link = in_link; - remote = in_remote; - state = null; - } -} -- cgit v1.2.3 From 82f798e7b1343a56203af2e89790f6de9ab9f98d Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 18:09:37 +1200 Subject: altoslib: remove duplicate AltosIdleMonitor class Signed-off-by: Mike Beattie --- altoslib/AltosGPSQuery.java | 105 -------------------------------------------- 1 file changed, 105 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosGPSQuery.java b/altoslib/AltosGPSQuery.java index d48ff7e4..ca04795d 100644 --- a/altoslib/AltosGPSQuery.java +++ b/altoslib/AltosGPSQuery.java @@ -157,108 +157,3 @@ class AltosGPSQuery extends AltosGPS { } } -public class AltosIdleMonitor extends Thread { - AltosLink link; - AltosIdleMonitorListener listener; - AltosState state; - boolean remote; - double frequency; - AltosState previous_state; - AltosConfigData config_data; - AltosADC adc; - AltosGPS gps; - - int AltosRSSI() throws TimeoutException, InterruptedException { - link.printf("s\n"); - String line = link.get_reply_no_dialog(5000); - if (line == null) - throw new TimeoutException(); - String[] items = line.split("\\s+"); - if (items.length < 2) - return 0; - if (!items[0].equals("RSSI:")) - return 0; - int rssi = Integer.parseInt(items[1]); - return rssi; - } - - void update_state() throws InterruptedException, TimeoutException { - AltosRecordTM record = new AltosRecordTM(); - int rssi; - - try { - if (remote) { - link.set_radio_frequency(frequency); - link.start_remote(); - } else - link.flush_input(); - config_data = new AltosConfigData(link); - adc = new AltosADC(link); - gps = new AltosGPSQuery(link, config_data); - } finally { - if (remote) { - link.stop_remote(); - rssi = AltosRSSI(); - } else - rssi = 0; - } - - record.version = 0; - record.callsign = config_data.callsign; - record.serial = config_data.serial; - record.flight = config_data.log_available() > 0 ? 255 : 0; - record.rssi = rssi; - record.status = 0; - record.state = AltosLib.ao_flight_idle; - - record.tick = adc.tick; - - record.accel = adc.accel; - record.pres = adc.pres; - record.batt = adc.batt; - record.temp = adc.temp; - record.drogue = adc.drogue; - record.main = adc.main; - - record.ground_accel = record.accel; - record.ground_pres = record.pres; - record.accel_plus_g = config_data.accel_cal_plus; - record.accel_minus_g = config_data.accel_cal_minus; - record.acceleration = 0; - record.speed = 0; - record.height = 0; - record.gps = gps; - state = new AltosState (record, state); - } - - public void set_frequency(double in_frequency) { - frequency = in_frequency; - } - - public void post_state() { - listener.update(state); - } - - public void run() { - try { - for (;;) { - try { - update_state(); - post_state(); - } catch (TimeoutException te) { - } - Thread.sleep(1000); - } - } catch (InterruptedException ie) { - link.close(); - } - } - - public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) - throws FileNotFoundException, InterruptedException, TimeoutException { - listener = in_listener; - link = in_link; - remote = in_remote; - state = null; - } -} -- cgit v1.2.3 From 42170d0e3a3b68a9d3db69714e043f7273a714fb Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 18:10:21 +1200 Subject: altoslib: remove duplicate AltosGPSQuery class Signed-off-by: Mike Beattie --- altoslib/AltosIdleMonitor.java | 76 ------------------------------------------ 1 file changed, 76 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index d83c4450..f38e3dac 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -233,82 +233,6 @@ class AltosMs5607Query extends AltosMs5607 { } } -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; - } - } -} - public class AltosIdleMonitor extends Thread { AltosLink link; AltosIdleMonitorListener listener; -- cgit v1.2.3 From 218c73b5bd5bd5673dc6f259f62b39541c52d6ff Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 18:11:13 +1200 Subject: altoslib: move distinct classes to separate files Signed-off-by: Mike Beattie --- altoslib/AltosIMUQuery.java | 46 +++++++++ altoslib/AltosIdleMonitor.java | 212 ----------------------------------------- altoslib/AltosMs5607Query.java | 67 +++++++++++++ altoslib/AltosSensorMM.java | 103 ++++++++++++++++++++ altoslib/AltosSensorTM.java | 81 ++++++++++++++++ 5 files changed, 297 insertions(+), 212 deletions(-) create mode 100644 altoslib/AltosIMUQuery.java create mode 100644 altoslib/AltosMs5607Query.java create mode 100644 altoslib/AltosSensorMM.java create mode 100644 altoslib/AltosSensorTM.java (limited to 'altoslib') diff --git a/altoslib/AltosIMUQuery.java b/altoslib/AltosIMUQuery.java new file mode 100644 index 00000000..0965fa39 --- /dev/null +++ b/altoslib/AltosIMUQuery.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +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/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index f38e3dac..ae3b7b06 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -20,218 +20,6 @@ package org.altusmetrum.AltosLib; import java.io.*; import java.util.concurrent.*; -class AltosSensorTM extends AltosRecordTM { - - public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException { - super(); - link.printf("a\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!line.startsWith("tick:")) - continue; - String[] items = line.split("\\s+"); - 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("accel:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("pres:")) { - pres = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("temp:")) { - temp = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("batt:")) { - batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("drogue:")) { - drogue = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("main:")) { - main = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; - } - break; - } - 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; - } -} - -class AltosSensorMM { - int tick; - int sense[]; - int v_batt; - int v_pyro; - int accel; - int accel_ref; - - public AltosSensorMM(AltosLink link) throws InterruptedException, TimeoutException { - link.printf("a\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!line.startsWith("tick:")) - continue; - String[] items = line.split("\\s+"); - sense = new int[6]; - 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("0:")) { - sense[0] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("1:")) { - sense[1] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("2:")) { - sense[2] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("3:")) { - sense[3] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("4:")) { - sense[4] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("5:")) { - sense[5] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("6:")) { - v_batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("7:")) { - v_pyro = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("8:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("9:")) { - accel_ref = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; - } - break; - } - } -} - -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; - } - } -} - -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(); - } - String[] items = line.split("\\s+"); - if (line.startsWith("Pressure:")) { - 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]); - } else if (line.startsWith("ms5607 reserved:")) { - if (items.length >= 3) - reserved = Integer.parseInt(items[2]); - } else if (line.startsWith("ms5607 sens:")) { - if (items.length >= 3) - sens = Integer.parseInt(items[2]); - } else if (line.startsWith("ms5607 off:")) { - if (items.length >= 3) - off = Integer.parseInt(items[2]); - } else if (line.startsWith("ms5607 tcs:")) { - if (items.length >= 3) - tcs = Integer.parseInt(items[2]); - } else if (line.startsWith("ms5607 tco:")) { - if (items.length >= 3) - tco = Integer.parseInt(items[2]); - } else if (line.startsWith("ms5607 tref:")) { - if (items.length >= 3) - tref = Integer.parseInt(items[2]); - } else if (line.startsWith("ms5607 tempsens:")) { - if (items.length >= 3) - tempsens = Integer.parseInt(items[2]); - } else if (line.startsWith("ms5607 crc:")) { - if (items.length >= 3) - crc = Integer.parseInt(items[2]); - } else if (line.startsWith("Altitude")) - break; - } - convert(); - } -} public class AltosIdleMonitor extends Thread { AltosLink link; diff --git a/altoslib/AltosMs5607Query.java b/altoslib/AltosMs5607Query.java new file mode 100644 index 00000000..3c746795 --- /dev/null +++ b/altoslib/AltosMs5607Query.java @@ -0,0 +1,67 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.util.concurrent.TimeoutException; + +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(); + } + String[] items = line.split("\\s+"); + if (line.startsWith("Pressure:")) { + 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]); + } else if (line.startsWith("ms5607 reserved:")) { + if (items.length >= 3) + reserved = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 sens:")) { + if (items.length >= 3) + sens = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 off:")) { + if (items.length >= 3) + off = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tcs:")) { + if (items.length >= 3) + tcs = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tco:")) { + if (items.length >= 3) + tco = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tref:")) { + if (items.length >= 3) + tref = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tempsens:")) { + if (items.length >= 3) + tempsens = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 crc:")) { + if (items.length >= 3) + crc = Integer.parseInt(items[2]); + } else if (line.startsWith("Altitude")) + break; + } + convert(); + } +} + diff --git a/altoslib/AltosSensorMM.java b/altoslib/AltosSensorMM.java new file mode 100644 index 00000000..b6f21ef0 --- /dev/null +++ b/altoslib/AltosSensorMM.java @@ -0,0 +1,103 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.util.concurrent.TimeoutException; + +class AltosSensorMM { + int tick; + int sense[]; + int v_batt; + int v_pyro; + int accel; + int accel_ref; + + public AltosSensorMM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + sense = new int[6]; + 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("0:")) { + sense[0] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("1:")) { + sense[1] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("2:")) { + sense[2] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("3:")) { + sense[3] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("4:")) { + sense[4] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("5:")) { + sense[5] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("6:")) { + v_batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("7:")) { + v_pyro = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("8:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("9:")) { + accel_ref = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + break; + } + } +} + diff --git a/altoslib/AltosSensorTM.java b/altoslib/AltosSensorTM.java new file mode 100644 index 00000000..75158cbf --- /dev/null +++ b/altoslib/AltosSensorTM.java @@ -0,0 +1,81 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.util.concurrent.TimeoutException; + +class AltosSensorTM extends AltosRecordTM { + + public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException { + super(); + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + 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("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + break; + } + 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; + } +} + -- cgit v1.2.3 From da053875c12b25b627e83430c3a956a994b435d5 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 18:19:07 +1200 Subject: altoslib: remove obsolete class Signed-off-by: Mike Beattie --- altoslib/AltosGPSQuery.java | 62 --------------------------------------------- 1 file changed, 62 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosGPSQuery.java b/altoslib/AltosGPSQuery.java index ca04795d..e93af259 100644 --- a/altoslib/AltosGPSQuery.java +++ b/altoslib/AltosGPSQuery.java @@ -19,68 +19,6 @@ package org.altusmetrum.AltosLib; import java.util.concurrent.*; -class AltosADCTM { - int tick; - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; - - public AltosADCTM(AltosLink link) throws InterruptedException, TimeoutException { - link.printf("a\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!line.startsWith("tick:")) - continue; - String[] items = line.split("\\s+"); - 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("accel:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("pres:")) { - pres = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("temp:")) { - temp = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("batt:")) { - batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("drogue:")) { - drogue = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("main:")) { - main = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; - } - break; - } - } -} - class AltosGPSQuery extends AltosGPS { public AltosGPSQuery (AltosLink link, AltosConfigData config_data) throws TimeoutException, InterruptedException { -- cgit v1.2.3 From 3fe932206f40f4d6f83a4ef49e064109a7a3de92 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Fri, 7 Sep 2012 18:19:43 +1200 Subject: altoslib: move distinct classes to separate files. Signed-off-by: Mike Beattie --- altoslib/AltosEepromIterable.java | 42 ----------------------- altoslib/AltosEepromMegaIterable.java | 44 ------------------------ altoslib/AltosOrderedMegaRecord.java | 64 +++++++++++++++++++++++++++++++++++ altoslib/AltosOrderedRecord.java | 63 ++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 86 deletions(-) create mode 100644 altoslib/AltosOrderedMegaRecord.java create mode 100644 altoslib/AltosOrderedRecord.java (limited to 'altoslib') diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index 7c752271..1aa816e1 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -21,48 +21,6 @@ import java.io.*; import java.util.*; import java.text.*; -/* - * 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 { - - 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; - } -} - public class AltosEepromIterable extends AltosRecordIterable { static final int seen_flight = 1; diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java index f0786e12..1ab2fcc8 100644 --- a/altoslib/AltosEepromMegaIterable.java +++ b/altoslib/AltosEepromMegaIterable.java @@ -21,50 +21,6 @@ import java.io.*; import java.util.*; import java.text.*; -/* - * 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 { - - 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 AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { - super(in_cmd, in_tick); - a = in_a; - b = in_b; - index = in_index; - } - - public String toString() { - return String.format("%d.%d %04x %04x %04x", - cmd, index, tick, a, b); - } - - public int compareTo(AltosOrderedMegaRecord o) { - int tick_diff = tick - o.tick; - if (tick_diff != 0) - return tick_diff; - return index - o.index; - } -} - public class AltosEepromMegaIterable extends AltosRecordIterable { static final int seen_flight = 1; diff --git a/altoslib/AltosOrderedMegaRecord.java b/altoslib/AltosOrderedMegaRecord.java new file mode 100644 index 00000000..05423dd9 --- /dev/null +++ b/altoslib/AltosOrderedMegaRecord.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +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 { + + 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 AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { + super(in_cmd, in_tick); + a = in_a; + b = in_b; + index = in_index; + } + + public String toString() { + return String.format("%d.%d %04x %04x %04x", + cmd, index, tick, a, b); + } + + 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 new file mode 100644 index 00000000..b4cfd8f2 --- /dev/null +++ b/altoslib/AltosOrderedRecord.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +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 { + + 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; + } +} + -- cgit v1.2.3 From 9682e9e6fe730417a77b47795fbe1f06c9a51177 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Sep 2012 12:29:32 -0700 Subject: altosui: Use helper functions to access arrays in AltosLib class These deal with out-of-range values correctly, instead of causing exceptions that will just break stuff. Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 18 ++++++++++++------ altosui/Altos.java | 14 -------------- altosui/AltosFlightStatsTable.java | 2 +- altosui/AltosScanUI.java | 2 +- 4 files changed, 14 insertions(+), 22 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 2402331e..d36b2ff7 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -111,7 +111,7 @@ public class AltosLib { public static final int ao_telemetry_0_8 = 3; public static final int ao_telemetry_max = 3; - public static final String[] ao_telemetry_name = { + private static final String[] ao_telemetry_name = { "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" }; @@ -121,13 +121,13 @@ public class AltosLib { public static final int ao_telemetry_0_9_len = 95; public static final int ao_telemetry_0_8_len = 94; - public static final int[] ao_telemetry_len = { + private static final int[] ao_telemetry_len = { 0, 32, 95, 94 }; - public static HashMap string_to_state = new HashMap(); + private static HashMap string_to_state = new HashMap(); - public static boolean map_initialized = false; + private static boolean map_initialized = false; public static void initialize_map() { @@ -159,7 +159,7 @@ public class AltosLib { telemetry)); } - public static String[] state_to_string = { + private static String[] state_to_string = { "startup", "idle", "pad", @@ -172,7 +172,7 @@ public class AltosLib { "invalid", }; - public static String[] state_to_string_capital = { + private static String[] state_to_string_capital = { "Startup", "Idle", "Pad", @@ -199,6 +199,12 @@ public class AltosLib { return state_to_string[state]; } + public static String state_name_capital(int state) { + if (state < 0 || state_to_string.length <= state) + return "invalid"; + return state_to_string_capital[state]; + } + public static final int AO_GPS_VALID = (1 << 4); public static final int AO_GPS_RUNNING = (1 << 5); public static final int AO_GPS_DATE_VALID = (1 << 6); diff --git a/altosui/Altos.java b/altosui/Altos.java index e60b3aaa..cd17a93e 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -72,20 +72,6 @@ public class Altos extends AltosLib { static final int text_width = 20; - static public int state(String state) { - if (!map_initialized) - initialize_map(); - if (string_to_state.containsKey(state)) - return string_to_state.get(state); - return ao_flight_invalid; - } - - static public String state_name(int state) { - if (state < 0 || state_to_string.length <= state) - return "invalid"; - return state_to_string[state]; - } - static public boolean initialized = false; static public boolean loaded_library = false; diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index c311b231..14e3bf8f 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -103,7 +103,7 @@ public class AltosFlightStatsTable extends JComponent { String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]), String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main]))); for (int s = Altos.ao_flight_boost; s <= Altos.ao_flight_main; s++) { - new FlightStat(layout, y++, String.format("%s time", Altos.state_to_string_capital[s]), + new FlightStat(layout, y++, String.format("%s time", AltosLib.state_name_capital(s)), String.format("%6.2f s", stats.state_end[s] - stats.state_start[s])); } new FlightStat(layout, y++, "Flight Time", diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index ef6389b6..9da1290f 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -427,7 +427,7 @@ public class AltosScanUI telemetry_boxes = new JCheckBox[Altos.ao_telemetry_max - Altos.ao_telemetry_min + 1]; for (int k = Altos.ao_telemetry_min; k <= Altos.ao_telemetry_max; k++) { int j = k - Altos.ao_telemetry_min; - telemetry_boxes[j] = new JCheckBox(Altos.ao_telemetry_name[k]); + telemetry_boxes[j] = new JCheckBox(AltosLib.telemetry_name(k)); c.gridy = 3 + j; pane.add(telemetry_boxes[j], c); telemetry_boxes[j].setActionCommand("telemetry"); -- cgit v1.2.3 From 47d87872c11a63a435fe5b703a4ce33503790d96 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Sep 2012 13:09:27 -0700 Subject: altoslib: Add in a bunch of java files mising after Mike's cleanups Signed-off-by: Keith Packard --- altoslib/Makefile.am | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'altoslib') diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 1f42140b..39b43f3d 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -25,14 +25,21 @@ AltosLib_JAVA = \ $(SRC)/AltosFlightReader.java \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ + $(SRC)/AltosGPSQuery.java \ $(SRC)/AltosGPSSat.java \ $(SRC)/AltosGreatCircle.java \ $(SRC)/AltosIdleMonitor.java \ $(SRC)/AltosIdleMonitorListener.java \ $(SRC)/AltosIgnite.java \ + $(SRC)/AltosIMU.java \ + $(SRC)/AltosIMUQuery.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosLink.java \ $(SRC)/AltosLog.java \ + $(SRC)/AltosMs5607.java \ + $(SRC)/AltosMs5607Query.java \ + $(SRC)/AltosOrderedRecord.java \ + $(SRC)/AltosOrderedMegaRecord.java \ $(SRC)/AltosParse.java \ $(SRC)/AltosPreferences.java \ $(SRC)/AltosRecordCompanion.java \ @@ -41,6 +48,8 @@ AltosLib_JAVA = \ $(SRC)/AltosRecordTM.java \ $(SRC)/AltosRecordMM.java \ $(SRC)/AltosReplayReader.java \ + $(SRC)/AltosSensorMM.java \ + $(SRC)/AltosSensorTM.java \ $(SRC)/AltosState.java \ $(SRC)/AltosTelemetry.java \ $(SRC)/AltosTelemetryIterable.java \ -- cgit v1.2.3 From 66a1e07efcac9324d33a1eca0dfb58a2724b667a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 10 Sep 2012 09:14:03 -0700 Subject: altoslib: Add imperial units conversion support "Redneck" mode support Signed-off-by: Keith Packard --- altoslib/AltosAccel.java | 43 +++++++++++++++++++++++++++++++ altoslib/AltosConvert.java | 28 +++++++++++++++++++++ altoslib/AltosDistance.java | 49 ++++++++++++++++++++++++++++++++++++ altoslib/AltosHeight.java | 43 +++++++++++++++++++++++++++++++ altoslib/AltosPreferences.java | 17 +++++++++++++ altoslib/AltosSpeed.java | 43 +++++++++++++++++++++++++++++++ altoslib/AltosUnits.java | 57 ++++++++++++++++++++++++++++++++++++++++++ altoslib/Makefile.am | 7 +++++- 8 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 altoslib/AltosAccel.java create mode 100644 altoslib/AltosDistance.java create mode 100644 altoslib/AltosHeight.java create mode 100644 altoslib/AltosSpeed.java create mode 100644 altoslib/AltosUnits.java (limited to 'altoslib') diff --git a/altoslib/AltosAccel.java b/altoslib/AltosAccel.java new file mode 100644 index 00000000..d14764a2 --- /dev/null +++ b/altoslib/AltosAccel.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosAccel extends AltosUnits { + + public double value(double v) { + if (AltosConvert.imperial_units) + return AltosConvert.meters_to_feet(v); + return v; + } + + public String show_units() { + if (AltosConvert.imperial_units) + return "ft/s²"; + return "m/s²"; + } + + public String say_units() { + if (AltosConvert.imperial_units) + return "feet per second squared"; + return "meters per second squared"; + } + + int show_fraction(int width) { + return width / 9; + } +} \ No newline at end of file diff --git a/altoslib/AltosConvert.java b/altoslib/AltosConvert.java index 3527b575..acd6c5f4 100644 --- a/altoslib/AltosConvert.java +++ b/altoslib/AltosConvert.java @@ -242,6 +242,14 @@ public class AltosConvert { return meters * (100 / (2.54 * 12)); } + public static double meters_to_miles(double meters) { + return meters_to_feet(meters) / 5280; + } + + public static double meters_to_mph(double mps) { + return meters_to_miles(mps) * 3600; + } + public static double meters_to_mach(double meters) { return meters / 343; /* something close to mach at usual rocket sites */ } @@ -250,6 +258,26 @@ public class AltosConvert { return meters / 9.80665; } + public static boolean imperial_units = false; + + public static AltosDistance distance = new AltosDistance(); + + public static AltosHeight height = new AltosHeight(); + + public static AltosSpeed speed = new AltosSpeed(); + + public static AltosAccel accel = new AltosAccel(); + + public static String show_gs(String format, double a) { + a = meters_to_g(a); + format = format.concat(" g"); + return String.format(format, a); + } + + public static String say_gs(double a) { + return String.format("%6.0 gees", meters_to_g(a)); + } + public static int checksum(int[] data, int start, int length) { int csum = 0x5a; for (int i = 0; i < length; i++) diff --git a/altoslib/AltosDistance.java b/altoslib/AltosDistance.java new file mode 100644 index 00000000..a5e7331c --- /dev/null +++ b/altoslib/AltosDistance.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosDistance extends AltosUnits { + + public double value(double v) { + if (AltosConvert.imperial_units) + return AltosConvert.meters_to_miles(v); + return v; + } + + public String show_units() { + if (AltosConvert.imperial_units) + return "miles"; + return "m"; + } + + public String say_units() { + if (AltosConvert.imperial_units) + return "miles"; + return "meters"; + } + + int show_fraction(int width) { + if (AltosConvert.imperial_units) + return width / 3; + return width / 9; + } + + int say_fraction() { + return 1; + } +} \ No newline at end of file diff --git a/altoslib/AltosHeight.java b/altoslib/AltosHeight.java new file mode 100644 index 00000000..da7ffdae --- /dev/null +++ b/altoslib/AltosHeight.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosHeight extends AltosUnits { + + public double value(double v) { + if (AltosConvert.imperial_units) + return AltosConvert.meters_to_feet(v); + return v; + } + + public String show_units() { + if (AltosConvert.imperial_units) + return "ft"; + return "m"; + } + + public String say_units() { + if (AltosConvert.imperial_units) + return "feet"; + return "meters"; + } + + int show_fraction(int width) { + return width / 9; + } +} \ No newline at end of file diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 13fee46d..065b6e99 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -93,6 +93,10 @@ public class AltosPreferences { public final static String frequency_format = "FREQUENCY-%d"; public final static String description_format = "DESCRIPTION-%d"; + /* Units preference */ + + public final static String unitsPreference = "IMPERIAL-UNITS"; + public static AltosFrequency[] load_common_frequencies() { AltosFrequency[] frequencies = null; boolean existing = false; @@ -176,6 +180,7 @@ public class AltosPreferences { common_frequencies = load_common_frequencies(); + AltosConvert.imperial_units = preferences.getBoolean(unitsPreference, false); } static { init(); } @@ -356,4 +361,16 @@ public class AltosPreferences { new_frequencies[i+1] = common_frequencies[i]; set_common_frequencies(new_frequencies); } + + public static boolean imperial_units() { + return AltosConvert.imperial_units; + } + + public static void set_imperial_units(boolean imperial_units) { + AltosConvert.imperial_units = imperial_units; + synchronized (preferences) { + preferences.putBoolean(unitsPreference, imperial_units); + flush_preferences(); + } + } } diff --git a/altoslib/AltosSpeed.java b/altoslib/AltosSpeed.java new file mode 100644 index 00000000..4e2daf5a --- /dev/null +++ b/altoslib/AltosSpeed.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public class AltosSpeed extends AltosUnits { + + public double value(double v) { + if (AltosConvert.imperial_units) + return AltosConvert.meters_to_mph(v); + return v; + } + + public String show_units() { + if (AltosConvert.imperial_units) + return "mph"; + return "m/s"; + } + + public String say_units() { + if (AltosConvert.imperial_units) + return "miles per hour"; + return "meters per second"; + } + + int show_fraction(int width) { + return width / 9; + } +} \ No newline at end of file diff --git a/altoslib/AltosUnits.java b/altoslib/AltosUnits.java new file mode 100644 index 00000000..47540c61 --- /dev/null +++ b/altoslib/AltosUnits.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public abstract class AltosUnits { + + public abstract double value(double v); + + public abstract String show_units(); + + public abstract String say_units(); + + abstract int show_fraction(int width); + + int say_fraction() { + return 0; + } + + private String show_format(int width) { + return String.format("%%%d.%df %s", width, show_fraction(width), show_units()); + } + + private String say_format() { + return String.format("%%1.%df", say_fraction()); + } + + private String say_units_format() { + return String.format("%%1.%df %s", say_fraction(), say_units()); + } + + public String show(int width, double v) { + return String.format(show_format(width), value(v)); + } + + public String say(double v) { + return String.format(say_format(), value(v)); + } + + public String say_units(double v) { + return String.format(say_units_format(), value(v)); + } +} \ No newline at end of file diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 39b43f3d..a9f810f9 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -68,7 +68,12 @@ AltosLib_JAVA = \ $(SRC)/AltosTelemetryRecordMegaData.java \ $(SRC)/AltosMs5607.java \ $(SRC)/AltosIMU.java \ - $(SRC)/AltosMag.java + $(SRC)/AltosMag.java \ + $(SRC)/AltosUnits.java \ + $(SRC)/AltosDistance.java \ + $(SRC)/AltosHeight.java \ + $(SRC)/AltosSpeed.java \ + $(SRC)/AltosAccel.java JAR=AltosLib.jar -- cgit v1.2.3 From e5a55dbf265354e7c94be3e2be53c2d5c8fba056 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 11 Sep 2012 15:53:36 -0700 Subject: Use ft/s for imperial speeds Bob Brown thinks this unit will be more useful than mph Signed-off-by: Keith Packard --- altoslib/AltosSpeed.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosSpeed.java b/altoslib/AltosSpeed.java index 4e2daf5a..af63ed17 100644 --- a/altoslib/AltosSpeed.java +++ b/altoslib/AltosSpeed.java @@ -21,19 +21,19 @@ public class AltosSpeed extends AltosUnits { public double value(double v) { if (AltosConvert.imperial_units) - return AltosConvert.meters_to_mph(v); + return AltosConvert.meters_to_feet(v); return v; } public String show_units() { if (AltosConvert.imperial_units) - return "mph"; + return "ft/s"; return "m/s"; } public String say_units() { if (AltosConvert.imperial_units) - return "miles per hour"; + return "feet per second"; return "meters per second"; } -- cgit v1.2.3