From: Keith Packard Date: Sat, 31 Aug 2013 06:48:02 +0000 (-0500) Subject: altoslib/altosui: Get legacy telem working with new AltosState structure X-Git-Tag: 1.2.9.4~114 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=f07f6d55edf5b97020680b3ce1d9e00bb3df64a6 altoslib/altosui: Get legacy telem working with new AltosState structure Make AltosTelemetry work without AltosRecord Signed-off-by: Keith Packard --- diff --git a/altoslib/AltosEepromFile.java b/altoslib/AltosEepromFile.java index bcc7171e..2f4c54d7 100644 --- a/altoslib/AltosEepromFile.java +++ b/altoslib/AltosEepromFile.java @@ -57,6 +57,7 @@ public class AltosEepromFile extends AltosStateIterable { AltosEepromIterable headers; AltosEepromIterable body; + AltosState start; public void write_comments(PrintStream out) { headers.write(out); @@ -70,9 +71,9 @@ public class AltosEepromFile extends AltosStateIterable { public AltosEepromFile(FileInputStream input) { headers = new AltosEepromIterable(AltosEepromHeader.read(input)); - AltosState state = headers.state(); + start = headers.state(); - switch (state.log_format) { + switch (start.log_format) { case AltosLib.AO_LOG_FORMAT_FULL: body = new AltosEepromIterable(AltosEepromTM.read(input)); break; @@ -86,26 +87,24 @@ public class AltosEepromFile extends AltosStateIterable { body = new AltosEepromIterable(AltosEepromMini.read(input)); break; } - } - int boost_tick (AltosState start) { + /* Find boost tick */ AltosState state = start.clone(); for (AltosEeprom eeprom : body) { eeprom.update_state(state); - if (state.state >= AltosLib.ao_flight_boost) - return state.tick; + if (state.state >= AltosLib.ao_flight_boost) { + start.set_boost_tick(state.tick); + break; + } } - return 0; } public Iterator iterator() { - - AltosState state = headers.state(); - Iterator i = body.iterator(); + AltosState state = start.clone(); + Iterator i = body.iterator(); while (i.hasNext() && !state.valid()) i.next().update_state(state); - state.set_boost_tick(boost_tick(state)); return new AltosEepromIterator(state, i); } } \ No newline at end of file diff --git a/altoslib/AltosFile.java b/altoslib/AltosFile.java index 90dbc6db..54c54824 100644 --- a/altoslib/AltosFile.java +++ b/altoslib/AltosFile.java @@ -22,10 +22,17 @@ import java.util.*; public class AltosFile extends File { + static String number(int n) { + if (n == AltosRecord.MISSING) + return "unk"; + else + return String.format("%03d", n); + } + 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)); + String.format("%04d-%02d-%02d-serial-%s-flight-%s.%s", + year, month, day, number(serial), number(flight), extension)); } public AltosFile(int serial, int flight, String extension) { @@ -37,7 +44,7 @@ public class AltosFile extends File { extension); } - public AltosFile(AltosRecord telem) { - this(telem.serial, telem.flight, "telem"); + public AltosFile(AltosState state) { + this(state.serial, state.flight, "telem"); } } diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index eb384e4d..399e95b1 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -70,35 +70,35 @@ public class AltosGPS implements Cloneable { } public AltosGPS(AltosTelemetryMap map) throws ParseException { - String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, - AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); + String state = map.get_string(AltosTelemetryLegacy.AO_TELEM_GPS_STATE, + AltosTelemetryLegacy.AO_TELEM_GPS_STATE_ERROR); - nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); - if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { + nsat = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_NUM_SAT, 0); + if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_LOCKED)) { connected = true; locked = true; - lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); - lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); - alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); - year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); + lat = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); + lon = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); + alt = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_ALTITUDE, MISSING); + year = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_YEAR, MISSING); if (year != MISSING) year += 2000; - month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); - day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); + month = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MONTH, MISSING); + day = map.get_int(AltosTelemetryLegacy.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); + hour = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HOUR, 0); + minute = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MINUTE, 0); + second = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_SECOND, 0); - ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, + ground_speed = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HORIZONTAL_SPEED, AltosRecord.MISSING, 1/100.0); - course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, + course = map.get_int(AltosTelemetryLegacy.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)) { + hdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HDOP, MISSING, 1.0); + vdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_VDOP, MISSING, 1.0); + h_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HERROR, MISSING); + v_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_VERROR, MISSING); + } else if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_UNLOCKED)) { connected = true; locked = false; } else { diff --git a/altoslib/AltosLog.java b/altoslib/AltosLog.java index 974c9f0f..7f69bb65 100644 --- a/altoslib/AltosLog.java +++ b/altoslib/AltosLog.java @@ -57,8 +57,8 @@ public class AltosLog implements Runnable { return file; } - boolean open (AltosRecord telem) throws IOException { - AltosFile a = new AltosFile(telem); + boolean open (AltosState state) throws IOException { + AltosFile a = new AltosFile(state); log_file = new FileWriter(a, true); if (log_file != null) { @@ -78,22 +78,25 @@ public class AltosLog implements Runnable { public void run () { try { - AltosRecord previous = null; + AltosState state = null; for (;;) { AltosLine line = input_queue.take(); if (line.line == null) continue; try { - AltosRecord telem = AltosTelemetry.parse(line.line, previous); - if ((telem.seen & AltosRecord.seen_flight) != 0 && - (telem.serial != serial || telem.flight != flight || log_file == null)) + AltosTelemetry telem = new AltosTelemetryLegacy(line.line); + if (state != null) + state = state.clone(); + else + state = new AltosState(); + telem.update_state(state); + if (state.serial != serial || state.flight != flight || log_file == null) { close_log_file(); - serial = telem.serial; - flight = telem.flight; - open(telem); + serial = state.serial; + flight = state.flight; + open(state); } - previous = telem; } catch (ParseException pe) { } catch (AltosCRCException ce) { } diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index daf06c19..52650062 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -104,6 +104,7 @@ public class AltosState implements Cloneable { public double accel_minus_g; public double accel; public double ground_accel; + public double ground_accel_avg; public int log_format; @@ -201,6 +202,7 @@ public class AltosState implements Cloneable { accel_minus_g = AltosRecord.MISSING; accel = AltosRecord.MISSING; ground_accel = AltosRecord.MISSING; + ground_accel_avg = AltosRecord.MISSING; log_format = AltosRecord.MISSING; serial = AltosRecord.MISSING; @@ -306,6 +308,7 @@ public class AltosState implements Cloneable { accel_minus_g = old.accel_minus_g; accel = old.accel; ground_accel = old.ground_accel; + ground_accel_avg = old.ground_accel_avg; log_format = old.log_format; serial = old.serial; @@ -396,9 +399,13 @@ public class AltosState implements Cloneable { } void update_accel() { + double ground = ground_accel; + + if (ground == AltosRecord.MISSING) + ground = ground_accel_avg; if (accel == AltosRecord.MISSING) return; - if (ground_accel == AltosRecord.MISSING) + if (ground == AltosRecord.MISSING) return; if (accel_plus_g == AltosRecord.MISSING) return; @@ -408,7 +415,7 @@ public class AltosState implements Cloneable { double counts_per_g = (accel_minus_g - accel_plus_g) / 2.0; double counts_per_mss = counts_per_g / 9.80665; - acceleration = (ground_accel - accel) / counts_per_mss; + acceleration = (ground - accel) / counts_per_mss; /* Only look at accelerometer data under boost */ if (boost && acceleration != AltosRecord.MISSING && (max_acceleration == AltosRecord.MISSING || acceleration > max_acceleration)) @@ -556,9 +563,6 @@ public class AltosState implements Cloneable { public void set_gps(AltosGPS gps, int sequence) { if (gps != null) { - System.out.printf ("gps date: %d-%d-%d time %d:%d:%d\n", - gps.year, gps.month, gps.day, - gps.hour, gps.minute, gps.second); this.gps = gps.clone(); gps_sequence = sequence; update_gps(); @@ -623,6 +627,12 @@ public class AltosState implements Cloneable { public void set_accel(double accel) { if (accel != AltosRecord.MISSING) { this.accel = accel; + if (state == AltosLib.ao_flight_pad) { + if (ground_accel_avg == AltosRecord.MISSING) + ground_accel_avg = accel; + else + ground_accel_avg = (ground_accel_avg * 7 + accel) / 8; + } } update_accel(); } diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index e7322349..b84455d3 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -23,217 +23,136 @@ import java.text.*; * Telemetry data contents */ +public abstract class AltosTelemetry implements AltosStateUpdate { + + /* All telemetry packets have these fields */ + public int tick; + public int serial; + public int rssi; + public int status; + + /* Mark when we received the packet */ + long received_time; + + static boolean cksum(int[] bytes) { + int sum = 0x5a; + for (int i = 1; i < bytes.length - 1; i++) + sum += bytes[i]; + sum &= 0xff; + return sum == bytes[bytes.length - 1]; + } + + public void update_state(AltosState state) { + } + final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); + final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); + final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; + + final static int packet_type_TM_sensor = 0x01; + final static int packet_type_Tm_sensor = 0x02; + final static int packet_type_Tn_sensor = 0x03; + final static int packet_type_configuration = 0x04; + final static int packet_type_location = 0x05; + final static int packet_type_satellite = 0x06; + final static int packet_type_companion = 0x07; + final static int packet_type_MM_sensor = 0x08; + final static int packet_type_MM_data = 0x09; + final static int packet_type_Mini = 0x10; + + static AltosTelemetry parse_hex(String hex) throws ParseException, AltosCRCException { + AltosTelemetry telem = null; + + int[] bytes; + try { + bytes = AltosLib.hexbytes(hex); + } catch (NumberFormatException ne) { + throw new ParseException(ne.getMessage(), 0); + } + + /* one for length, one for checksum */ + if (bytes[0] != bytes.length - 2) + throw new ParseException(String.format("invalid length %d != %d\n", + bytes[0], + bytes.length - 2), 0); + if (!cksum(bytes)) + throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + + int rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74; + int status = AltosLib.uint8(bytes, bytes.length - 2); + + if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) + throw new AltosCRCException(rssi); + + /* length, data ..., rssi, status, checksum -- 4 bytes extra */ + switch (bytes.length) { + case AltosLib.ao_telemetry_standard_len + 4: + int type = AltosLib.uint8(bytes, 4 + 1); /* - * 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 - * - */ + switch (type) { + case packet_type_TM_sensor: + case packet_type_Tm_sensor: + case packet_type_Tn_sensor: + telem = new AltosTelemetrySensor(bytes); + break; + case packet_type_configuration: + telem = new AltosTelemetryConfiguration(bytes); + break; + case packet_type_location: + telem = new AltosTelemetryLocation(bytes); + break; + case packet_type_satellite: + telem = new AltosTelemetrySatellite(bytes); + break; + case packet_type_companion: + telem = new AltosTelemetryCompanion(bytes); + break; + case packet_type_MM_sensor: + telem = new AltosTelemetryMegaSensor(bytes); + break; + case packet_type_MM_data: + telem = new AltosTelemetryMegaData(bytes); + break; + default: + telem = new AltosTelemetryRaw(bytes); + break; + } +*/ + break; + case AltosLib.ao_telemetry_0_9_len + 4: + telem = new AltosTelemetryLegacy(bytes); + break; + case AltosLib.ao_telemetry_0_8_len + 4: + telem = new AltosTelemetryLegacy(bytes); + break; + default: + throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); + } + if (telem != null) { + telem.received_time = System.currentTimeMillis(); + telem.rssi = rssi; + telem.status = status; + } + return telem; + } + + public static AltosTelemetry parse(String line) throws ParseException, AltosCRCException { + String[] word = line.split("\\s+"); + int i =0; + + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + AltosTelemetry telem; -public abstract class AltosTelemetry extends AltosRecord { - - /* - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - */ - - final static String AO_TELEM_VERSION = "VERSION"; - final static String AO_TELEM_CALL = "c"; - final static String AO_TELEM_SERIAL = "n"; - final static String AO_TELEM_FLIGHT = "f"; - final static String AO_TELEM_RSSI = "r"; - final static String AO_TELEM_STATE = "s"; - final static String AO_TELEM_TICK = "t"; - - /* - * Raw sensor values - * - * Name Value - * r_a Accelerometer reading (integer) - * r_b Barometer reading (integer) - * r_t Thermometer reading (integer) - * r_v Battery reading (integer) - * r_d Drogue continuity (integer) - * r_m Main continuity (integer) - */ - - final static String AO_TELEM_RAW_ACCEL = "r_a"; - final static String AO_TELEM_RAW_BARO = "r_b"; - final static String AO_TELEM_RAW_THERMO = "r_t"; - final static String AO_TELEM_RAW_BATT = "r_v"; - final static String AO_TELEM_RAW_DROGUE = "r_d"; - final static String AO_TELEM_RAW_MAIN = "r_m"; - - /* - * Sensor calibration values - * - * Name Value - * c_a Ground accelerometer reading (integer) - * c_b Ground barometer reading (integer) - * c_p Accelerometer reading for +1g - * c_m Accelerometer reading for -1g - */ - - final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; - final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; - final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; - final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; - - /* - * Kalman state values - * - * Name Value - * k_h Height above pad (integer, meters) - * k_s Vertical speeed (integer, m/s * 16) - * k_a Vertical acceleration (integer, m/s² * 16) - */ - - final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; - final static String AO_TELEM_KALMAN_SPEED = "k_s"; - final static String AO_TELEM_KALMAN_ACCEL = "k_a"; - - /* - * Ad-hoc flight values - * - * Name Value - * a_a Acceleration (integer, sensor units) - * a_s Speed (integer, integrated acceleration value) - * a_b Barometer reading (integer, sensor units) - */ - - final static String AO_TELEM_ADHOC_ACCEL = "a_a"; - final static String AO_TELEM_ADHOC_SPEED = "a_s"; - final static String AO_TELEM_ADHOC_BARO = "a_b"; - - /* - * GPS values - * - * Name Value - * g_s GPS state (string): - * l locked - * u unlocked - * e error (missing or broken) - * g_n Number of sats used in solution - * g_ns Latitude (degrees * 10e7) - * g_ew Longitude (degrees * 10e7) - * g_a Altitude (integer meters) - * g_Y GPS year (integer) - * g_M GPS month (integer - 1-12) - * g_D GPS day (integer - 1-31) - * g_h GPS hour (integer - 0-23) - * g_m GPS minute (integer - 0-59) - * g_s GPS second (integer - 0-59) - * g_v GPS vertical speed (integer, cm/sec) - * g_s GPS horizontal speed (integer, cm/sec) - * g_c GPS course (integer, 0-359) - * g_hd GPS hdop (integer * 10) - * g_vd GPS vdop (integer * 10) - * g_he GPS h error (integer) - * g_ve GPS v error (integer) - */ - - final static String AO_TELEM_GPS_STATE = "g"; - final static String AO_TELEM_GPS_STATE_LOCKED = "l"; - final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; - final static String AO_TELEM_GPS_STATE_ERROR = "e"; - final static String AO_TELEM_GPS_NUM_SAT = "g_n"; - final static String AO_TELEM_GPS_LATITUDE = "g_ns"; - final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; - final static String AO_TELEM_GPS_ALTITUDE = "g_a"; - final static String AO_TELEM_GPS_YEAR = "g_Y"; - final static String AO_TELEM_GPS_MONTH = "g_M"; - final static String AO_TELEM_GPS_DAY = "g_D"; - final static String AO_TELEM_GPS_HOUR = "g_h"; - final static String AO_TELEM_GPS_MINUTE = "g_m"; - final static String AO_TELEM_GPS_SECOND = "g_s"; - final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; - final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; - final static String AO_TELEM_GPS_COURSE = "g_c"; - final static String AO_TELEM_GPS_HDOP = "g_hd"; - final static String AO_TELEM_GPS_VDOP = "g_vd"; - final static String AO_TELEM_GPS_HERROR = "g_he"; - final static String AO_TELEM_GPS_VERROR = "g_ve"; - - /* - * GPS satellite values - * - * Name Value - * s_n Number of satellites reported (integer) - * s_v0 Space vehicle ID (integer) for report 0 - * s_c0 C/N0 number (integer) for report 0 - * s_v1 Space vehicle ID (integer) for report 1 - * s_c1 C/N0 number (integer) for report 1 - * ... - */ - - final static String AO_TELEM_SAT_NUM = "s_n"; - final static String AO_TELEM_SAT_SVID = "s_v"; - final static String AO_TELEM_SAT_C_N_0 = "s_c"; - - static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { - AltosTelemetryRecord r = AltosTelemetryRecord.parse(line); - - return r.update_state(previous); + if (word[i].equals("TELEM")) { + telem = parse_hex(word[i+1]); + } else { + telem = new AltosTelemetryLegacy(line); + } + return telem; } } diff --git a/altoslib/AltosTelemetryFile.java b/altoslib/AltosTelemetryFile.java new file mode 100644 index 00000000..9e992576 --- /dev/null +++ b/altoslib/AltosTelemetryFile.java @@ -0,0 +1,94 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +class AltosTelemetryIterator implements Iterator { + AltosState state; + Iterator telems; + AltosTelemetry next; + boolean seen; + + public boolean hasNext() { + return !seen || telems.hasNext(); + } + + public AltosState next() { + if (seen) { + AltosState n = state.clone(); + AltosTelemetry t = telems.next(); + + t.update_state(n); + state = n; + } + seen = true; + return state; + } + + public void remove () { + } + + public AltosTelemetryIterator(AltosState start, Iterator telems) { + this.state = start; + this.telems = telems; + this.seen = false; + } +} + +public class AltosTelemetryFile extends AltosStateIterable { + + AltosTelemetryIterable telems; + AltosState start; + + public void write_comments(PrintStream out) { + } + + public void write(PrintStream out) { + + } + + public AltosTelemetryFile(FileInputStream input) { + telems = new AltosTelemetryIterable(input); + start = new AltosState(); + + /* Find boost tick */ + AltosState state = start.clone(); + + for (AltosTelemetry telem : telems) { + telem.update_state(state); + if (state.state >= AltosLib.ao_flight_boost) { + start.set_boost_tick(state.tick); + break; + } + } + } + + public Iterator iterator() { + AltosState state = start.clone(); + Iterator i = telems.iterator(); + + while (i.hasNext() && !state.valid()) { + AltosTelemetry t = i.next(); + t.update_state(state); + } + return new AltosTelemetryIterator(state, i); + } +} \ No newline at end of file diff --git a/altoslib/AltosTelemetryIterable.java b/altoslib/AltosTelemetryIterable.java index 57033638..b7489f77 100644 --- a/altoslib/AltosTelemetryIterable.java +++ b/altoslib/AltosTelemetryIterable.java @@ -21,27 +21,15 @@ import java.io.*; import java.util.*; import java.text.*; -public class AltosTelemetryIterable extends AltosRecordIterable { - TreeSet records; +public class AltosTelemetryIterable implements Iterable { + LinkedList telems; - public Iterator iterator () { - return records.iterator(); + public Iterator iterator () { + return telems.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 (); + telems = new LinkedList (); try { for (;;) { @@ -50,32 +38,10 @@ public class AltosTelemetryIterable extends AltosRecordIterable { break; } try { - AltosRecord record = AltosTelemetry.parse(line, previous); - if (record == null) + AltosTelemetry telem = AltosTelemetry.parse(line); + if (telem == null) break; - if (records.isEmpty()) { - current_tick = record.tick; - } else { - int tick = record.tick; - while (tick < current_tick - 0x1000) - tick += 0x10000; - current_tick = tick; - record.tick = current_tick; - } - if (!saw_boost && record.state >= AltosLib.ao_flight_boost) - { - saw_boost = true; - boost_tick = record.tick; - } - if (record.acceleration() != AltosRecord.MISSING) - has_accel = true; - if (record.gps != null) - has_gps = true; - if (record.main_voltage() != AltosRecord.MISSING) - has_ignite = true; - if (previous != null && previous.tick != record.tick) - records.add(previous); - previous = record; + telems.add(telem); } catch (ParseException pe) { System.out.printf("parse exception %s\n", pe.getMessage()); } catch (AltosCRCException ce) { @@ -84,26 +50,5 @@ public class AltosTelemetryIterable extends AltosRecordIterable { } catch (IOException io) { System.out.printf("io exception\n"); } - - if (previous != null) - records.add(previous); - - /* Adjust all tick counts to match expected eeprom values, - * which starts with a 16-bit tick count 16 samples before boost - */ - - int tick_adjust = (boost_tick - 16) & 0xffff0000; - for (AltosRecord r : this) - r.tick -= tick_adjust; - boost_tick -= tick_adjust; - - /* adjust all tick counts to be relative to boost time */ - for (AltosRecord r : this) - r.time = (r.tick - boost_tick) / 100.0; - - try { - input.close(); - } catch (IOException ie) { - } } } diff --git a/altoslib/AltosTelemetryLegacy.java b/altoslib/AltosTelemetryLegacy.java new file mode 100644 index 00000000..45e5c315 --- /dev/null +++ b/altoslib/AltosTelemetryLegacy.java @@ -0,0 +1,556 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.text.*; + +/* + * 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 AltosTelemetryLegacy extends AltosTelemetry { + /* + * 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"; + + public int version; + public String callsign; + public int flight; + public int state; + + public AltosGPS gps; + public int gps_sequence; + + /* Telemetry sources have these values recorded from the flight computer */ + public double kalman_height; + public double kalman_speed; + public double kalman_acceleration; + + /* Sensor values */ + public int accel; + public int pres; + public int temp; + public int batt; + public int apogee; + public int main; + + public int ground_accel; + public int ground_pres; + public int accel_plus_g; + public int accel_minus_g; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + private void parse_v4(String[] words, int i) throws ParseException { + AltosTelemetryMap map = new AltosTelemetryMap(words, i); + + callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); + serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); + flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); + rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); + state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid")); + tick = map.get_int(AO_TELEM_TICK, 0); + + /* raw sensor values */ + accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING); + pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); + temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); + batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); + apogee = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); + main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); + + /* sensor calibration information */ + ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); + ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); + accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); + accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); + + /* flight computer values */ + kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); + kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); + kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); + + flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); + flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); + flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING); + + if (map.has(AO_TELEM_GPS_STATE)) + gps = new AltosGPS(map); + else + gps = null; + } + + private void parse_legacy(String[] words, int i) throws ParseException { + + AltosParse.word (words[i++], "CALL"); + callsign = words[i++]; + + AltosParse.word (words[i++], "SERIAL"); + serial = AltosParse.parse_int(words[i++]); + + if (version >= 2) { + AltosParse.word (words[i++], "FLIGHT"); + flight = AltosParse.parse_int(words[i++]); + } else + flight = 0; + + AltosParse.word(words[i++], "RSSI"); + rssi = AltosParse.parse_int(words[i++]); + + /* Older telemetry data had mis-computed RSSI value */ + if (version <= 2) + rssi = (rssi + 74) / 2 - 74; + + AltosParse.word(words[i++], "STATUS"); + status = AltosParse.parse_hex(words[i++]); + + AltosParse.word(words[i++], "STATE"); + state = AltosLib.state(words[i++]); + + tick = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a:"); + accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "p:"); + pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "t:"); + temp = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "v:"); + batt = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "d:"); + apogee = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "m:"); + main = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fa:"); + flight_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "ga:"); + ground_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fv:"); + flight_vel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fp:"); + flight_pres = AltosParse.parse_int(words[i++]); + + /* Old TeleDongle code with kalman-reporting TeleMetrum code */ + if ((flight_vel & 0xffff0000) == 0x80000000) { + kalman_speed = ((short) flight_vel) / 16.0; + kalman_acceleration = flight_accel / 16.0; + kalman_height = flight_pres; + flight_vel = AltosRecord.MISSING; + flight_pres = AltosRecord.MISSING; + flight_accel = AltosRecord.MISSING; + } else { + kalman_speed = AltosRecord.MISSING; + kalman_acceleration = AltosRecord.MISSING; + kalman_height = AltosRecord.MISSING; + } + + AltosParse.word(words[i++], "gp:"); + ground_pres = AltosParse.parse_int(words[i++]); + + if (version >= 1) { + AltosParse.word(words[i++], "a+:"); + accel_plus_g = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a-:"); + accel_minus_g = AltosParse.parse_int(words[i++]); + } else { + accel_plus_g = ground_accel; + accel_minus_g = ground_accel + 530; + } + + gps = new AltosGPS(words, i, version); + gps_sequence++; + } + + public AltosTelemetryLegacy(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(words[i++], "RSSI"); + rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(rssi); + } + if (words[i].equals("CALL")) { + version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + version = AltosParse.parse_int(words[i++]); + } + + if (version < 4) + parse_legacy(words, i); + else + parse_v4(words, i); + } + + /* + * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM 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 AltosTelemetryLegacy(int[] in_bytes) { + bytes = in_bytes; + version = 4; + adjust = 0; + + if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { + serial = uint8(0); + adjust = -1; + } else + serial = uint16(0); + + callsign = string(62, 8); + flight = uint16(2); + state = uint8(4); + tick = uint16(21); + accel = int16(23); + pres = int16(25); + temp = int16(27); + batt = int16(29); + apogee = int16(31); + main = int16(33); + + ground_accel = int16(7); + ground_pres = int16(15); + accel_plus_g = int16(17); + accel_minus_g = int16(19); + + if (uint16(11) == 0x8000) { + kalman_acceleration = int16(5); + kalman_speed = int16(9); + kalman_height = int16(13); + flight_accel = AltosRecord.MISSING; + flight_vel = AltosRecord.MISSING; + flight_pres = AltosRecord.MISSING; + } else { + flight_accel = int16(5); + flight_vel = uint32(9); + flight_pres = int16(13); + kalman_acceleration = AltosRecord.MISSING; + kalman_speed = AltosRecord.MISSING; + kalman_height = AltosRecord.MISSING; + } + + gps = null; + + int gps_flags = uint8(41); + + if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { + gps = new AltosGPS(); + gps_sequence++; + + gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); + gps.locked = (gps_flags & AO_GPS_VALID) != 0; + gps.connected = true; + gps.lat = uint32(42) / 1.0e7; + gps.lon = uint32(46) / 1.0e7; + gps.alt = int16(50); + gps.ground_speed = uint16(52) / 100.0; + gps.course = uint8(54) * 2; + gps.hdop = uint8(55) / 5.0; + gps.h_error = uint16(58); + gps.v_error = uint16(60); + + int n_tracking_reported = uint8(70); + if (n_tracking_reported > 12) + 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) { + 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) + gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); + } + } + } + } + + public void update_state(AltosState state) { + state.set_tick(tick); + state.set_state(this.state); + state.set_flight(flight); + state.set_serial(serial); + state.set_rssi(rssi, status); + + state.set_pressure(AltosConvert.barometer_to_pressure(pres)); + state.set_accel_g(accel_plus_g, accel_minus_g); + state.set_accel(accel); + if (kalman_height != AltosRecord.MISSING) + state.set_kalman(kalman_height, kalman_speed, kalman_acceleration); + state.set_temperature(AltosEepromTM.thermometer_to_temperature(temp)); + state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(batt)); + state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(apogee)); + state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(main)); + if (gps != null) + state.set_gps(gps, gps_sequence); + } +} diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 3915927c..b1cc009c 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -35,9 +35,12 @@ public class AltosTelemetryReader extends AltosFlightReader { AltosLine l = telem.take(); if (l.line == null) throw new IOException("IO error"); - AltosRecord next = AltosTelemetry.parse(l.line, previous); - previous = next; - state = new AltosState (next, state); + AltosTelemetry telem = AltosTelemetryLegacy.parse(l.line); + if (state == null) + state = new AltosState(); + else + state = state.clone(); + telem.update_state(state); return state; } diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index bbcca906..59e0ec1c 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -72,21 +72,11 @@ altoslib_JAVA = \ AltosStateIterable.java \ AltosStateUpdate.java \ AltosTelemetry.java \ + AltosTelemetryFile.java \ AltosTelemetryIterable.java \ + AltosTelemetryLegacy.java \ AltosTelemetryMap.java \ AltosTelemetryReader.java \ - AltosTelemetryRecordCompanion.java \ - AltosTelemetryRecordConfiguration.java \ - AltosTelemetryRecordGeneral.java \ - AltosTelemetryRecord.java \ - AltosTelemetryRecordLegacy.java \ - AltosTelemetryRecordLocation.java \ - AltosTelemetryRecordRaw.java \ - AltosTelemetryRecordSatellite.java \ - AltosTelemetryRecordSensor.java \ - AltosTelemetryRecordMegaSensor.java \ - AltosTelemetryRecordMegaData.java \ - AltosTelemetryRecordMini.java \ AltosUnitsListener.java \ AltosMs5607.java \ AltosIMU.java \ diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 6d5ce185..72b2c0d9 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -437,7 +437,7 @@ public class AltosUI extends AltosUIFrame { if (file.getName().endsWith("eeprom")) { return new AltosEepromFile(in); } else { - return null; // new AltosTelemetryIterable(in); + return new AltosTelemetryFile(in); } } @@ -517,9 +517,9 @@ public class AltosUI extends AltosUIFrame { static boolean process_cat(File file) { try { - FileInputStream input = new FileInputStream(file); - AltosEepromFile eef = new AltosEepromFile(input); + AltosStateIterable eef = record_iterable(file); + System.out.printf ("process cat\n"); for (AltosState state : eef) { if ((state.set & AltosState.set_gps) != 0) System.out.printf ("time %g lat %g lon %g alt %g\n",