From cfc09e8f1f263595972cbb6af23f22e2d749c744 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Sep 2017 18:00:36 -0700 Subject: altoslib: Add tilt and pyro data to CSV export It's now version 6. Also removed duplicate time values and made radio values conditional on having radio data. Signed-off-by: Keith Packard --- altoslib/AltosCSV.java | 87 +++++++++++++++++++++++++++++++++++------ altoslib/AltosFlightSeries.java | 2 +- altoslib/AltosLib.java | 6 ++- 3 files changed, 80 insertions(+), 15 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosCSV.java b/altoslib/AltosCSV.java index f55b4785..a8de23f0 100644 --- a/altoslib/AltosCSV.java +++ b/altoslib/AltosCSV.java @@ -29,9 +29,11 @@ public class AltosCSV implements AltosWriter { int boost_tick; boolean has_basic; + boolean has_radio; boolean has_battery; boolean has_flight_state; boolean has_advanced; + boolean has_igniter; boolean has_gps; boolean has_gps_sat; boolean has_companion; @@ -39,7 +41,7 @@ public class AltosCSV implements AltosWriter { AltosFlightSeries series; int[] indices; - static final int ALTOS_CSV_VERSION = 5; + static final int ALTOS_CSV_VERSION = 6; /* Version 4 format: * @@ -49,7 +51,8 @@ public class AltosCSV implements AltosWriter { * flight number * callsign * time (seconds since boost) - * clock (tick count / 100) + * + * Radio info (if available) * rssi * link quality * @@ -81,6 +84,14 @@ public class AltosCSV implements AltosWriter { * mag_x (g) * mag_y (g) * mag_z (g) + * tilt (d) + * + * Extra igniter voltages (if available) + * pyro (V) + * igniter_a (V) + * igniter_b (V) + * igniter_c (V) + * igniter_d (V) * * GPS data (if available) * connected (1/0) @@ -115,13 +126,26 @@ public class AltosCSV implements AltosWriter { */ void write_general_header() { - out.printf("version,serial,flight,call,time,clock,rssi,lqi"); + out.printf("version,serial,flight,call,time"); } double time() { return series.time(indices); } + void write_general() { + out.printf("%s, %d, %d, %s, %8.2f", + ALTOS_CSV_VERSION, + series.cal_data().serial, + series.cal_data().flight, + series.cal_data().callsign, + time()); + } + + void write_radio_header() { + out.printf("rssi,lqi"); + } + int rssi() { return (int) series.value(AltosFlightSeries.rssi_name, indices); } @@ -130,12 +154,8 @@ public class AltosCSV implements AltosWriter { return (int) series.value(AltosFlightSeries.status_name, indices); } - void write_general() { - double time = time(); - out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d", - ALTOS_CSV_VERSION, series.cal_data().serial, - series.cal_data().flight, series.cal_data().callsign, - time, time, + void write_radio() { + out.printf("%4d, %3d", rssi(), status() & 0x7f); } @@ -149,7 +169,7 @@ public class AltosCSV implements AltosWriter { void write_flight() { int state = state(); - out.printf("%d,%8s", state, AltosLib.state_name(state)); + out.printf("%2d,%8s", state, AltosLib.state_name(state)); } void write_basic_header() { @@ -189,7 +209,7 @@ public class AltosCSV implements AltosWriter { } void write_advanced_header() { - out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z"); + out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z,tilt"); } double accel_along() { return series.value(AltosFlightSeries.accel_along_name, indices); } @@ -204,11 +224,30 @@ public class AltosCSV implements AltosWriter { double mag_across() { return series.value(AltosFlightSeries.mag_across_name, indices); } double mag_through() { return series.value(AltosFlightSeries.mag_through_name, indices); } + double tilt() { return series.value(AltosFlightSeries.orient_name, indices); } + void write_advanced() { - out.printf("%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f", + out.printf("%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f", accel_along(), accel_across(), accel_through(), gyro_roll(), gyro_pitch(), gyro_yaw(), - mag_along(), mag_across(), mag_through()); + mag_along(), mag_across(), mag_through(), + tilt()); + } + + void write_igniter_header() { + out.printf("pyro"); + for (int i = 0; i < series.igniter_voltage.length; i++) + out.printf(",%s", AltosLib.igniter_short_name(i)); + } + + double pyro() { return series.value(AltosFlightSeries.pyro_voltage_name, indices); } + + double igniter_value(int channel) { return series.value(series.igniter_voltage_name(channel), indices); } + + void write_igniter() { + out.printf("%5.2f", pyro()); + for (int i = 0; i < series.igniter_voltage.length; i++) + out.printf(",%5.2f", igniter_value(i)); } void write_gps_header() { @@ -306,6 +345,10 @@ public class AltosCSV implements AltosWriter { void write_header() { out.printf("#"); write_general_header(); + if (has_radio) { + out.printf(","); + write_radio_header(); + } if (has_flight_state) { out.printf(","); write_flight_header(); @@ -322,6 +365,10 @@ public class AltosCSV implements AltosWriter { out.printf(","); write_advanced_header(); } + if (has_igniter) { + out.printf(","); + write_igniter_header(); + } if (has_gps) { out.printf(","); write_gps_header(); @@ -339,6 +386,10 @@ public class AltosCSV implements AltosWriter { void write_one() { write_general(); + if (has_radio) { + out.printf(","); + write_radio(); + } if (has_flight_state) { out.printf(","); write_flight(); @@ -355,6 +406,10 @@ public class AltosCSV implements AltosWriter { out.printf(","); write_advanced(); } + if (has_igniter) { + out.printf(","); + write_igniter(); + } if (has_gps) { out.printf(","); write_gps(); @@ -395,14 +450,18 @@ public class AltosCSV implements AltosWriter { series.finish(); + has_radio = false; has_flight_state = false; has_basic = false; has_battery = false; has_advanced = false; + has_igniter = false; has_gps = false; has_gps_sat = false; has_companion = false; + if (series.has_series(AltosFlightSeries.rssi_name)) + has_radio = true; if (series.has_series(AltosFlightSeries.state_name)) has_flight_state = true; if (series.has_series(AltosFlightSeries.accel_name) || series.has_series(AltosFlightSeries.pressure_name)) @@ -411,6 +470,8 @@ public class AltosCSV implements AltosWriter { has_battery = true; if (series.has_series(AltosFlightSeries.accel_across_name)) has_advanced = true; + if (series.has_series(AltosFlightSeries.pyro_voltage_name)) + has_igniter = true; if (series.gps_series != null) has_gps = true; diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index 57f1a491..df575189 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -643,7 +643,7 @@ public class AltosFlightSeries extends AltosDataListener { public void set_igniter_voltage(double[] voltage) { int channels = voltage.length; if (igniter_voltage == null || igniter_voltage.length <= channels) { - AltosTimeSeries[] new_igniter_voltage = new AltosTimeSeries[channels + 1]; + AltosTimeSeries[] new_igniter_voltage = new AltosTimeSeries[channels]; int i = 0; if (igniter_voltage != null) { diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index d1063509..77b3fcc4 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -587,7 +587,11 @@ public class AltosLib { } public static String igniter_name(int i) { - return String.format("Ignitor %c", 'A' + i); + return String.format("Igniter %c", 'A' + i); + } + + public static String igniter_short_name(int i) { + return String.format("igniter_%c", 'a' + i); } public static AltosRecordSet record_set(File file) throws FileNotFoundException, IOException { -- cgit v1.2.3 From de2b6ec1cdfd48c948bff7edbfe2540440429b1b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Oct 2017 16:55:18 -0700 Subject: altoslib,altosuilib,altosui: log_format/device_type TeleGPS selects stateless When the device being analyzed has no flight state, we want to use the 'stateless' state so that the UI can display reasonable information. This bit was lost in the recent AltosState shuffle and this patch brings it back. Signed-off-by: Keith Packard --- altoslib/AltosCalData.java | 7 +++++++ altoslib/AltosDataListener.java | 31 +++++++++++++++++++++++++--- altoslib/AltosEepromRecord.java | 2 +- altoslib/AltosEepromRecordSet.java | 2 ++ altoslib/AltosFlightSeries.java | 16 +++++++-------- altoslib/AltosState.java | 34 +++++++++++-------------------- altoslib/AltosTelemetry.java | 2 +- altoslib/AltosTelemetryConfiguration.java | 2 +- altoslib/AltosTelemetryFile.java | 2 +- altoslib/AltosTelemetryReader.java | 8 ++------ 10 files changed, 62 insertions(+), 44 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosCalData.java b/altoslib/AltosCalData.java index 6258c1a8..7415d5ad 100644 --- a/altoslib/AltosCalData.java +++ b/altoslib/AltosCalData.java @@ -72,6 +72,13 @@ public class AltosCalData { } } + public int log_format = AltosLib.MISSING; + + public void set_log_format(int log_format) { + if (log_format != AltosLib.MISSING) + this.log_format = log_format; + } + public int config_major = AltosLib.MISSING; public int config_minor = AltosLib.MISSING; public int flight_log_max = AltosLib.MISSING; diff --git a/altoslib/AltosDataListener.java b/altoslib/AltosDataListener.java index be6d840f..fb37fe3d 100644 --- a/altoslib/AltosDataListener.java +++ b/altoslib/AltosDataListener.java @@ -19,7 +19,6 @@ public abstract class AltosDataListener { private AltosCalData cal_data = null; public double time = AltosLib.MISSING; - public int state = AltosLib.MISSING; public double frequency = AltosLib.MISSING; public void set_tick(int tick) { @@ -42,14 +41,34 @@ public abstract class AltosDataListener { cal_data().set_serial(serial); } + public void set_device_type(int device_type) { + cal_data().set_device_type(device_type); + switch (device_type) { + case AltosLib.product_telegps: + set_state(AltosLib.ao_flight_stateless); + break; + } + } + + public void set_log_format(int log_format) { + cal_data().set_log_format(log_format); + switch (log_format) { + case AltosLib.AO_LOG_FORMAT_TELEGPS: + set_state(AltosLib.ao_flight_stateless); + break; + } + } + public double time() { return time; } public void set_state(int state) { cal_data().set_state(state); - if (state != AltosLib.MISSING) - this.state = state; + } + + public int state() { + return cal_data().state; } public void set_flight(int flight) { @@ -64,6 +83,12 @@ public abstract class AltosDataListener { public void finish() { } + public void init() { + set_state(AltosLib.ao_flight_invalid); + time = AltosLib.MISSING; + frequency = AltosLib.MISSING; + } + public abstract void set_rssi(int rssi, int status); public abstract void set_received_time(long received_time); diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java index 094584fe..e937c3d0 100644 --- a/altoslib/AltosEepromRecord.java +++ b/altoslib/AltosEepromRecord.java @@ -83,7 +83,7 @@ public abstract class AltosEepromRecord implements Comparable /* AltosDataProvider */ public void provide_data(AltosDataListener listener, AltosCalData cal_data) { - cal_data.set_tick(tick()); + listener.set_tick(tick()); if (cmd() == AltosLib.AO_LOG_FLIGHT) cal_data.set_boost_tick(); listener.set_time(cal_data.time()); diff --git a/altoslib/AltosEepromRecordSet.java b/altoslib/AltosEepromRecordSet.java index 48e90c05..d91ae3ac 100644 --- a/altoslib/AltosEepromRecordSet.java +++ b/altoslib/AltosEepromRecordSet.java @@ -44,6 +44,8 @@ public class AltosEepromRecordSet implements AltosRecordSet { AltosCalData cal_data = cal_data(); cal_data.reset(); + listener.set_log_format(config_data().log_format); + for (AltosEepromRecord record : ordered) { record.provide_data(listener, cal_data); } diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index df575189..f7ea0d15 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -150,15 +150,13 @@ public class AltosFlightSeries extends AltosDataListener { public void set_state(int state) { - if (state == AltosLib.ao_flight_pad) - return; - - if (state_series == null) - state_series = add_series(state_name, AltosConvert.state_name); - else if (this.state == state) - return; - this.state = state; - state_series.add(time(), state); + if (state != AltosLib.ao_flight_pad && state != AltosLib.MISSING && state != AltosLib.ao_flight_stateless) { + if (state_series == null) + state_series = add_series(state_name, AltosConvert.state_name); + if (this.state() != state) + state_series.add(time(), state); + } + super.set_state(state); } public AltosTimeSeries accel_series; diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 39ab10da..54c70094 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -480,7 +480,7 @@ public class AltosState extends AltosDataListener { class AltosPressure extends AltosValue { void set(double p, double time) { super.set(p, time); - if (state == AltosLib.ao_flight_pad) + if (state() == AltosLib.ao_flight_pad) ground_pressure.set_filtered(p, time); double a = pressure_to_altitude(p); altitude.set_computed(a, time); @@ -557,7 +557,7 @@ public class AltosState extends AltosDataListener { class AltosSpeed extends AltosCValue { boolean can_max() { - return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless; + return state() < AltosLib.ao_flight_fast || state() == AltosLib.ao_flight_stateless; } void set_accel() { @@ -615,7 +615,7 @@ public class AltosState extends AltosDataListener { class AltosAccel extends AltosCValue { boolean can_max() { - return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless; + return state() < AltosLib.ao_flight_fast || state() == AltosLib.ao_flight_stateless; } void set_measured(double a, double time) { @@ -712,11 +712,11 @@ public class AltosState extends AltosDataListener { } public void init() { + super.init(); + set = 0; received_time = System.currentTimeMillis(); - time = AltosLib.MISSING; - state = AltosLib.ao_flight_invalid; landed = false; boost = false; rssi = AltosLib.MISSING; @@ -819,9 +819,9 @@ public class AltosState extends AltosDataListener { if (gps.locked && gps.nsat >= 4) { /* Track consecutive 'good' gps reports, waiting for 10 of them */ - if (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_stateless) { + if (state() == AltosLib.ao_flight_pad || state() == AltosLib.ao_flight_stateless) { set_npad(npad+1); - if (pad_lat != AltosLib.MISSING && (npad < 10 || state == AltosLib.ao_flight_pad)) { + if (pad_lat != AltosLib.MISSING && (npad < 10 || state() == AltosLib.ao_flight_pad)) { pad_lat = (pad_lat * 31 + gps.lat) / 32; pad_lon = (pad_lon * 31 + gps.lon) / 32; gps_ground_altitude.set_filtered(gps.alt, time); @@ -859,24 +859,14 @@ public class AltosState extends AltosDataListener { } public String state_name() { - return AltosLib.state_name(state); + return AltosLib.state_name(state()); } public void set_state(int state) { - if (state != AltosLib.ao_flight_invalid) { - this.state = state; - ascent = (AltosLib.ao_flight_boost <= state && - state <= AltosLib.ao_flight_coast); - boost = (AltosLib.ao_flight_boost == state); - } - } - - public int state() { - return state; - } - - private void re_init() { - init(); + super.set_state(state); + ascent = (AltosLib.ao_flight_boost <= state() && + state() <= AltosLib.ao_flight_coast); + boost = (AltosLib.ao_flight_boost == state()); } public int rssi() { diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index f17e1171..fe536c6a 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -51,7 +51,7 @@ public abstract class AltosTelemetry implements AltosDataProvider { public void provide_data(AltosDataListener listener) { listener.set_serial(serial()); - if (listener.state == AltosLib.ao_flight_invalid) + if (listener.state() == AltosLib.ao_flight_invalid) listener.set_state(AltosLib.ao_flight_startup); if (frequency != AltosLib.MISSING) listener.set_frequency(frequency); diff --git a/altoslib/AltosTelemetryConfiguration.java b/altoslib/AltosTelemetryConfiguration.java index ea307442..c8026a83 100644 --- a/altoslib/AltosTelemetryConfiguration.java +++ b/altoslib/AltosTelemetryConfiguration.java @@ -40,7 +40,7 @@ public class AltosTelemetryConfiguration extends AltosTelemetryStandard { AltosCalData cal_data = listener.cal_data(); - cal_data.set_device_type(device_type()); + listener.set_device_type(device_type()); cal_data.set_flight(flight()); cal_data.set_config(config_major(), config_minor(), flight_log_max()); if (device_type() == AltosLib.product_telegps) diff --git a/altoslib/AltosTelemetryFile.java b/altoslib/AltosTelemetryFile.java index 135b0284..e51455f8 100644 --- a/altoslib/AltosTelemetryFile.java +++ b/altoslib/AltosTelemetryFile.java @@ -128,7 +128,7 @@ public class AltosTelemetryFile implements AltosRecordSet { /* Try to pick up at least one pre-boost value */ if (cal_data.time() >= -2) telem.provide_data(listener); - if (listener.state == AltosLib.ao_flight_landed) + if (listener.state() == AltosLib.ao_flight_landed) break; } listener.finish(); diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 26fe4f26..8fb61a4f 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -41,19 +41,15 @@ public class AltosTelemetryReader extends AltosFlightReader { throw new IOException("IO error"); } while (!link.get_monitor()); AltosTelemetry telem = AltosTelemetry.parse(l.line); - if (state == null) { - System.out.printf("Make state\n"); + if (state == null) state = new AltosState(cal_data()); - } telem.provide_data(state); return state; } public AltosCalData cal_data() { - if (cal_data == null) { - System.out.printf("Make cal data\n"); + if (cal_data == null) cal_data = new AltosCalData(); - } return cal_data; } -- cgit v1.2.3 From c6be13e8ef80e5afc836e04cbfe4cb17631540e4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Oct 2017 16:58:53 -0700 Subject: altoslib: Allow early bail-out on bad telemetry CRC Check the CRC status in the packet before creating a new telemetry object. Signed-off-by: Keith Packard --- altoslib/AltosTelemetry.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index fe536c6a..a374519d 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -28,8 +28,11 @@ public abstract class AltosTelemetry implements AltosDataProvider { int[] bytes; /* All telemetry packets have these fields */ - public int rssi() { return AltosConvert.telem_to_rssi(AltosLib.int8(bytes, bytes.length - 3)); } - public int status() { return AltosLib.uint8(bytes, bytes.length - 2); } + static public int rssi(int[] bytes) { return AltosConvert.telem_to_rssi(AltosLib.int8(bytes, bytes.length - 3)); } + static public int status(int[] bytes) { return AltosLib.uint8(bytes, bytes.length - 2); } + + public int rssi() { return rssi(bytes); } + public int status() { return status(bytes); } /* All telemetry packets report these fields in some form */ public abstract int serial(); @@ -96,6 +99,9 @@ public abstract class AltosTelemetry implements AltosDataProvider { if (!cksum(bytes)) throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + if ((status(bytes) & PKT_APPEND_STATUS_1_CRC_OK) == 0) + throw new AltosCRCException(rssi(bytes)); + /* length, data ..., rssi, status, checksum -- 4 bytes extra */ switch (bytes.length) { case AltosLib.ao_telemetry_standard_len + 4: -- cgit v1.2.3 From d75e8b9046295051c91696461e8d5f59c8260ccc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Oct 2017 17:02:18 -0700 Subject: altosuilib: Show raw tick values in graph and info table Not terribly useful, but did help validate firmware handling of tick wrapping, so we'll keep it. Signed-off-by: Keith Packard --- altoslib/AltosDataListener.java | 7 +++++++ altoslib/AltosFlightSeries.java | 11 +++++++++++ altosuilib/AltosGraph.java | 16 +++++++++++++++- altosuilib/AltosInfoTable.java | 2 ++ 4 files changed, 35 insertions(+), 1 deletion(-) (limited to 'altoslib') diff --git a/altoslib/AltosDataListener.java b/altoslib/AltosDataListener.java index fb37fe3d..359d04c9 100644 --- a/altoslib/AltosDataListener.java +++ b/altoslib/AltosDataListener.java @@ -21,7 +21,14 @@ public abstract class AltosDataListener { public double time = AltosLib.MISSING; public double frequency = AltosLib.MISSING; + public int raw_tick = AltosLib.MISSING; + + public int tick() { + return raw_tick; + } + public void set_tick(int tick) { + raw_tick = tick; cal_data.set_tick(tick); set_time(cal_data.time()); } diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index f7ea0d15..ab7943b3 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -191,6 +191,17 @@ public class AltosFlightSeries extends AltosDataListener { public void set_received_time(long received_time) { } + public AltosTimeSeries tick_series; + + public static final String tick_name = "Tick"; + + public void set_tick(int tick) { + super.set_tick(tick); + if (tick_series == null) + tick_series = add_series(tick_name, null); + tick_series.add(time(), tick); + } + public AltosTimeSeries rssi_series; public static final String rssi_name = "RSSI"; diff --git a/altosuilib/AltosGraph.java b/altosuilib/AltosGraph.java index 31042abb..5df95233 100644 --- a/altosuilib/AltosGraph.java +++ b/altosuilib/AltosGraph.java @@ -80,6 +80,7 @@ public class AltosGraph extends AltosUIGraph { static final private Color orient_color = new Color(31, 31, 31); static AltosUnits dop_units = null; + static AltosUnits tick_units = null; AltosUIFlightSeries flight_series; @@ -89,7 +90,7 @@ public class AltosGraph extends AltosUIGraph { AltosUIAxis height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis; AltosUIAxis distance_axis, pressure_axis, thrust_axis; AltosUIAxis gyro_axis, orient_axis, mag_axis; - AltosUIAxis course_axis, dop_axis; + AltosUIAxis course_axis, dop_axis, tick_axis; if (stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING) setName(String.format("%s %d flight %d\n", stats.product, stats.serial, stats.flight)); @@ -98,6 +99,7 @@ public class AltosGraph extends AltosUIGraph { pressure_axis = newAxis("Pressure", AltosConvert.pressure, pressure_color, 0); speed_axis = newAxis("Speed", AltosConvert.speed, speed_color); thrust_axis = newAxis("Thrust", AltosConvert.force, thrust_color); + tick_axis = newAxis("Tick", tick_units, accel_color, 0); accel_axis = newAxis("Acceleration", AltosConvert.accel, accel_color); voltage_axis = newAxis("Voltage", AltosConvert.voltage, voltage_color); temperature_axis = newAxis("Temperature", AltosConvert.temperature, temperature_color, 0); @@ -129,6 +131,11 @@ public class AltosGraph extends AltosUIGraph { plot, false); + flight_series.register_axis(AltosUIFlightSeries.tick_name, + accel_color, + false, + tick_axis); + flight_series.register_axis(AltosUIFlightSeries.accel_name, accel_color, true, @@ -320,6 +327,12 @@ public class AltosGraph extends AltosUIGraph { return flight_series.series(cal_data); } + public void set_filter(double filter) { + System.out.printf("filter set to %f\n", filter); + flight_series.set_filter(filter, filter); + units_changed(false); + } + public void set_data(AltosFlightStats stats, AltosUIFlightSeries flight_series) { set_series(setup(stats, flight_series)); } @@ -330,6 +343,7 @@ public class AltosGraph extends AltosUIGraph { public AltosGraph(AltosUIEnable enable, AltosFlightStats stats, AltosUIFlightSeries flight_series) { this(enable); + this.flight_series = flight_series; set_series(setup(stats, flight_series)); } } diff --git a/altosuilib/AltosInfoTable.java b/altosuilib/AltosInfoTable.java index 9e528b1f..e759394b 100644 --- a/altosuilib/AltosInfoTable.java +++ b/altosuilib/AltosInfoTable.java @@ -142,6 +142,8 @@ public class AltosInfoTable extends JTable implements AltosFlightDisplay, Hierar info_add_row(0, "Device", "%s", AltosLib.product_name(cal_data.device_type)); else if (cal_data.product != null) info_add_row(0, "Device", "%s", cal_data.product); + if (state.tick() != AltosLib.MISSING) + info_add_row(0, "Tick", "%6d", state.tick()); if (state.altitude() != AltosLib.MISSING) info_add_row(0, "Altitude", "%6.0f m", state.altitude()); if (cal_data.ground_altitude != AltosLib.MISSING) -- cgit v1.2.3 From 98dc29a7a964f8d653b73989c6751695d168844c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Oct 2017 19:33:37 -0700 Subject: altoslib: Add user-selectable filter width for data smoothing Also switch smoothing window to Kaiser and change default accel filter width to 1 second instead of 4 seconds. Now users can play with the filter and see what it does. Signed-off-by: Keith Packard --- altoslib/AltosFlightSeries.java | 90 +++++++++++++++++++++++++---------- altoslib/AltosTimeSeries.java | 42 ++++++++++++++-- altoslib/Makefile.am | 1 + altosui/AltosGraphUI.java | 23 +++++++-- altosuilib/AltosFlightStatsTable.java | 84 ++++++++++++++++++++++++-------- altosuilib/AltosGraph.java | 8 +--- altosuilib/AltosUIEnable.java | 82 ++++++++++++++++++++++++++++++- altosuilib/AltosUIGraph.java | 4 ++ altosuilib/AltosUITimeSeries.java | 3 +- micropeak/MicroPeak.java | 23 ++++++++- telegps/TeleGPSGraphUI.java | 26 ++++++++-- 11 files changed, 320 insertions(+), 66 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index ab7943b3..02bf64ff 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -21,7 +21,7 @@ public class AltosFlightSeries extends AltosDataListener { public ArrayList series = new ArrayList(); public double speed_filter_width = 4.0; - public double accel_filter_width = 4.0; + public double accel_filter_width = 1.0; public int[] indices() { int[] indices = new int[series.size()]; @@ -160,6 +160,7 @@ public class AltosFlightSeries extends AltosDataListener { } public AltosTimeSeries accel_series; + public boolean accel_computed; public static final String accel_name = "Accel"; @@ -174,17 +175,44 @@ public class AltosFlightSeries extends AltosDataListener { accel_series = add_series(accel_name, AltosConvert.accel); accel_series.add(time(), acceleration); + accel_computed = false; } - private void compute_accel() { - if (accel_series != null) - return; + private AltosTimeSeries compute_accel() { + AltosTimeSeries new_accel_series = null; if (speed_series != null) { - AltosTimeSeries temp_series = make_series(speed_name, AltosConvert.speed); - speed_series.filter(temp_series, accel_filter_width); - accel_series = add_series(accel_name, AltosConvert.accel); - temp_series.differentiate(accel_series); + AltosTimeSeries temp_series; + if (accel_filter_width > 0) { + temp_series = make_series(speed_name, AltosConvert.speed); + speed_series.filter(temp_series, accel_filter_width); + } else + temp_series = speed_series; + + new_accel_series = make_series(accel_name, AltosConvert.accel); + temp_series.differentiate(new_accel_series); + } + return new_accel_series; + } + + public void set_filter(double speed_filter, double accel_filter) { + this.speed_filter_width = speed_filter; + this.accel_filter_width = accel_filter; + + AltosTimeSeries new_speed_series = compute_speed(); + + if (new_speed_series != null) { + speed_series.erase_values(); + for (AltosTimeValue tv : new_speed_series) + speed_series.add(tv); + } + if (accel_computed) { + AltosTimeSeries new_accel_series = compute_accel(); + if (new_accel_series != null) { + accel_series.erase_values(); + for (AltosTimeValue tv : new_accel_series) + accel_series.add(tv); + } } } @@ -268,21 +296,24 @@ public class AltosFlightSeries extends AltosDataListener { public static final String speed_name = "Speed"; - private void compute_speed() { - if (speed_series != null) - return; - + private AltosTimeSeries compute_speed() { + AltosTimeSeries new_speed_series = null; AltosTimeSeries alt_speed_series = null; AltosTimeSeries accel_speed_series = null; if (altitude_series != null) { - AltosTimeSeries temp_series = make_series(altitude_name, AltosConvert.height); - altitude_series.filter(temp_series, speed_filter_width); + AltosTimeSeries temp_series; + + if (speed_filter_width > 0) { + temp_series = make_series(speed_name, AltosConvert.height); + altitude_series.filter(temp_series, speed_filter_width); + } else + temp_series = altitude_series; alt_speed_series = make_series(speed_name, AltosConvert.speed); temp_series.differentiate(alt_speed_series); } - if (accel_series != null) { + if (accel_series != null && !accel_computed) { if (orient_series != null) { vert_accel_series = add_series(vert_accel_name, AltosConvert.accel); @@ -318,26 +349,25 @@ public class AltosFlightSeries extends AltosDataListener { } } if (apogee_time == AltosLib.MISSING) { - speed_series = alt_speed_series; + new_speed_series = alt_speed_series; } else { - speed_series = make_series(speed_name, AltosConvert.speed); + new_speed_series = make_series(speed_name, AltosConvert.speed); for (AltosTimeValue d : accel_speed_series) { if (d.time <= apogee_time) - speed_series.add(d); + new_speed_series.add(d); } for (AltosTimeValue d : alt_speed_series) { if (d.time > apogee_time) - speed_series.add(d); + new_speed_series.add(d); } } } else if (alt_speed_series != null) { - speed_series = alt_speed_series; + new_speed_series = alt_speed_series; } else if (accel_speed_series != null) { - speed_series = accel_speed_series; + new_speed_series = accel_speed_series; } - if (speed_series != null) - add_series(speed_series); + return new_speed_series; } public AltosTimeSeries orient_series; @@ -690,8 +720,18 @@ public class AltosFlightSeries extends AltosDataListener { public void finish() { compute_orient(); - compute_speed(); - compute_accel(); + if (speed_series == null) { + speed_series = compute_speed(); + if (speed_series != null) + add_series(speed_series); + } + if (accel_series == null) { + accel_series = compute_accel(); + if (accel_series != null) { + add_series(accel_series); + accel_computed = true; + } + } compute_height(); } diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index 9f3b4d80..7208c176 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -20,15 +20,30 @@ public class AltosTimeSeries implements Iterable, Comparable values; + boolean data_changed; public int compareTo(AltosTimeSeries other) { return label.compareTo(other.label); } public void add(AltosTimeValue tv) { + data_changed = true; values.add(tv); } + public void erase_values() { + data_changed = true; + this.values = new ArrayList(); + } + + public void clear_changed() { + data_changed = false; + } + +// public boolean changed() { +// return data_changed; +// } + public void add(double time, double value) { add(new AltosTimeValue(time, value)); } @@ -264,14 +279,35 @@ public class AltosTimeSeries implements Iterable, Comparable 0); + return s; + } + + private static double kaiser(double n, double m, double beta) { + double alpha = m / 2; + double t = (n - alpha) / alpha; + + if (t > 1) + t = 1; + double k = i0 (beta * Math.sqrt (1 - t*t)) / i0(beta); + return k; + } + + private double filter_coeff(double dist, double width) { + return kaiser(dist + width/2.0, width, 2 * Math.PI); } public AltosTimeSeries filter(AltosTimeSeries f, double width) { + double half_width = width/2; + int half_point = values.size() / 2; for (int i = 0; i < values.size(); i++) { double center_time = values.get(i).time; double left_time = center_time - half_width; diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 08af9496..2a1cb8e4 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -55,6 +55,7 @@ altoslib_JAVA = \ AltosEepromList.java \ AltosEepromLog.java \ AltosFile.java \ + AltosFilterListener.java \ AltosFlash.java \ AltosFlashListener.java \ AltosDataListener.java \ diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 042f9277..f387ed9b 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -31,7 +31,7 @@ import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.ui.RefineryUtilities; -public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener +public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener { JTabbedPane pane; AltosGraph graph; @@ -82,6 +82,23 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt enable.units_changed(imperial_units); } + AltosUIFlightSeries flight_series; + + public void filter_changed(double speed_filter, double accel_filter) { + flight_series.set_filter(speed_filter, accel_filter); + graph.filter_changed(); + stats = new AltosFlightStats(flight_series); + statsTable.filter_changed(stats); + } + + public double speed_filter() { + return flight_series.speed_filter_width; + } + + public double accel_filter() { + return flight_series.accel_filter_width; + } + AltosGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException { super(file.getName()); AltosCalData cal_data = set.cal_data(); @@ -89,9 +106,9 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt pane = new JTabbedPane(); - enable = new AltosUIEnable(); + flight_series = new AltosUIFlightSeries(cal_data); - AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data); + enable = new AltosUIEnable(this); set.capture_series(flight_series); diff --git a/altosuilib/AltosFlightStatsTable.java b/altosuilib/AltosFlightStatsTable.java index 415c0244..8f7e9bff 100644 --- a/altosuilib/AltosFlightStatsTable.java +++ b/altosuilib/AltosFlightStatsTable.java @@ -38,6 +38,11 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen value[i].setFont(AltosUILib.value_font); } + public void set(String ... values) { + for (int j = 0; j < values.length; j++) + value[j].setText(values[j]); + } + public FlightStat(GridBagLayout layout, int y, String label_text, String ... values) { GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad); @@ -87,6 +92,43 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen return String.format("%s %4d° %9.6f'", h, deg, min); } + private FlightStat max_height_stat; + private FlightStat max_speed_stat; + private FlightStat max_accel_stat; + private FlightStat boost_accel_stat; + private FlightStat drogue_descent_stat; + private FlightStat main_descent_stat; + + public void set_values(AltosFlightStats stats) { + if (max_height_stat != null && stats.max_height != AltosLib.MISSING) { + max_height_stat.set(String.format("%6.1f m", stats.max_height), + String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); + } + if (max_speed_stat != null && stats.max_speed != AltosLib.MISSING) { + max_speed_stat.set(String.format("%6.1f m/s", stats.max_speed), + String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)), + String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); + } + if (max_accel_stat != null && stats.max_acceleration != AltosLib.MISSING) { + max_accel_stat.set(String.format("%6.1f m/s²", stats.max_acceleration), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); + } + if (boost_accel_stat != null && stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING) { + boost_accel_stat.set(String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost]))); + } + if (drogue_descent_stat != null && stats.state_speed[AltosLib.ao_flight_drogue] != AltosLib.MISSING) { + drogue_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]), + String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue]))); + } + if (main_descent_stat != null && stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING) { + main_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]), + String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main]))); + } + } + public void set_stats(AltosFlightStats stats) { int y = 0; if (stats.serial != AltosLib.MISSING) { @@ -113,9 +155,9 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second)); } if (stats.max_height != AltosLib.MISSING) { - new FlightStat(layout, y++, "Maximum height", - String.format("%6.1f m", stats.max_height), - String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); + max_height_stat = new FlightStat(layout, y++, "Maximum height", + String.format("%6.1f m", stats.max_height), + String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); } if (stats.max_gps_height != AltosLib.MISSING) { new FlightStat(layout, y++, "Maximum GPS height", @@ -123,21 +165,21 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_gps_height))); } if (stats.max_speed != AltosLib.MISSING) { - new FlightStat(layout, y++, "Maximum speed", - String.format("%6.1f m/s", stats.max_speed), - String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)), - String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); + max_speed_stat = new FlightStat(layout, y++, "Maximum speed", + String.format("%6.1f m/s", stats.max_speed), + String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)), + String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); } if (stats.max_acceleration != AltosLib.MISSING) - new FlightStat(layout, y++, "Maximum boost acceleration", - String.format("%6.1f m/s²", stats.max_acceleration), - String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), - String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); + max_accel_stat = new FlightStat(layout, y++, "Maximum boost acceleration", + String.format("%6.1f m/s²", stats.max_acceleration), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); if (stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING) - new FlightStat(layout, y++, "Average boost acceleration", - String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]), - String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])), - String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost]))); + boost_accel_stat = new FlightStat(layout, y++, "Average boost acceleration", + String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost]))); if (stats.state_time[AltosLib.ao_flight_boost] != 0 || stats.state_time[AltosLib.ao_flight_fast] != 0 || stats.state_time[AltosLib.ao_flight_coast] != 0) { double boost_time = stats.state_time[AltosLib.ao_flight_boost]; @@ -167,14 +209,14 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen label = "Descent rate"; else label = "Drogue descent rate"; - new FlightStat(layout, y++, label, + drogue_descent_stat = new FlightStat(layout, y++, label, String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]), String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue]))); } if (stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING) - new FlightStat(layout, y++, "Main descent rate", - String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]), - String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main]))); + main_descent_stat = new FlightStat(layout, y++, "Main descent rate", + String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]), + String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main]))); if (stats.state_time[AltosLib.ao_flight_drogue] != 0 || stats.state_time[AltosLib.ao_flight_main] != 0) { double drogue_duration = stats.state_time[AltosLib.ao_flight_drogue]; double main_duration = stats.state_time[AltosLib.ao_flight_main]; @@ -210,6 +252,10 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen AltosUIPreferences.unregister_font_listener(this); } + public void filter_changed(AltosFlightStats stats) { + set_values(stats); + } + public AltosFlightStatsTable() { layout = new GridBagLayout(); diff --git a/altosuilib/AltosGraph.java b/altosuilib/AltosGraph.java index 5df95233..3f610285 100644 --- a/altosuilib/AltosGraph.java +++ b/altosuilib/AltosGraph.java @@ -92,7 +92,7 @@ public class AltosGraph extends AltosUIGraph { AltosUIAxis gyro_axis, orient_axis, mag_axis; AltosUIAxis course_axis, dop_axis, tick_axis; - if (stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING) + if (stats != null && stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING) setName(String.format("%s %d flight %d\n", stats.product, stats.serial, stats.flight)); height_axis = newAxis("Height", AltosConvert.height, height_color); @@ -327,12 +327,6 @@ public class AltosGraph extends AltosUIGraph { return flight_series.series(cal_data); } - public void set_filter(double filter) { - System.out.printf("filter set to %f\n", filter); - flight_series.set_filter(filter, filter); - units_changed(false); - } - public void set_data(AltosFlightStats stats, AltosUIFlightSeries flight_series) { set_series(setup(stats, flight_series)); } diff --git a/altosuilib/AltosUIEnable.java b/altosuilib/AltosUIEnable.java index 0c23fa8d..4bd07c52 100644 --- a/altosuilib/AltosUIEnable.java +++ b/altosuilib/AltosUIEnable.java @@ -21,6 +21,7 @@ package org.altusmetrum.altosuilib_12; import java.awt.*; import java.awt.event.*; import javax.swing.*; +import javax.swing.event.*; import java.io.*; import java.util.concurrent.*; import java.util.*; @@ -36,12 +37,17 @@ import org.jfree.chart.labels.*; import org.jfree.data.xy.*; import org.jfree.data.*; -public class AltosUIEnable extends Container { +public class AltosUIEnable extends Container implements ChangeListener { Insets il, ir; int y; int x; JCheckBox imperial_units; + JLabel speed_filter_label; + JSlider speed_filter; + JLabel accel_filter_label; + JSlider accel_filter; + AltosFilterListener filter_listener; static final int max_rows = 14; @@ -69,11 +75,15 @@ public class AltosUIEnable extends Container { } } + LinkedList elements = new LinkedList(); + public void add(String name, AltosUIGrapher grapher, boolean enabled) { GraphElement e = new GraphElement(name, grapher, enabled); GridBagConstraints c = new GridBagConstraints(); + elements.add(e); + /* Add element */ c = new GridBagConstraints(); c.gridx = x; c.gridy = y; @@ -90,6 +100,17 @@ public class AltosUIEnable extends Container { } } + public void stateChanged(ChangeEvent e) { + JSlider filter = (JSlider) e.getSource(); + if (!filter.getValueIsAdjusting()) { + double speed_value = (int) speed_filter.getValue() / 1000.0; + double accel_value = (int) accel_filter.getValue() / 1000.0; + if (filter_listener != null) { + filter_listener.filter_changed(speed_value, accel_value); + } + } + } + public void add_units() { /* Imperial units setting */ @@ -109,9 +130,66 @@ public class AltosUIEnable extends Container { c.anchor = GridBagConstraints.LINE_START; c.insets = il; add(imperial_units, c); + + speed_filter_label = new JLabel("Speed Filter(ms)"); + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1001; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(speed_filter_label, c); + + speed_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.speed_filter() * 1000.0)); + Hashtable label_table = new Hashtable(); + for (int i = 0; i <= 10000; i += 5000) { + label_table.put(new Integer(i), new JLabel(String.format("%d", i))); + } + speed_filter.setPaintTicks(true); + speed_filter.setMajorTickSpacing(1000); + speed_filter.setMinorTickSpacing(250); + speed_filter.setLabelTable(label_table); + speed_filter.setPaintTrack(false); + speed_filter.setSnapToTicks(true); + speed_filter.setPaintLabels(true); + speed_filter.addChangeListener(this); + + c = new GridBagConstraints(); + c.gridx = 1; c.gridy = 1001; + c.gridwidth = 1000; c.gridheight = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(speed_filter, c); + + accel_filter_label = new JLabel("Acceleration Filter(ms)"); + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1002; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(accel_filter_label, c); + + accel_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.accel_filter() * 1000.0)); + accel_filter.setPaintTicks(true); + accel_filter.setMajorTickSpacing(1000); + accel_filter.setMinorTickSpacing(250); + accel_filter.setLabelTable(label_table); + accel_filter.setPaintTrack(false); + accel_filter.setSnapToTicks(true); + accel_filter.setPaintLabels(true); + accel_filter.addChangeListener(this); + + c = new GridBagConstraints(); + c.gridx = 1; c.gridy = 1002; + c.gridwidth = 1000; c.gridheight = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(accel_filter, c); } - public AltosUIEnable() { + public AltosUIEnable(AltosFilterListener filter_listener) { + this.filter_listener = filter_listener; il = new Insets(4,4,4,4); ir = new Insets(4,4,4,4); x = 0; diff --git a/altosuilib/AltosUIGraph.java b/altosuilib/AltosUIGraph.java index 0caabcfa..efc3d493 100644 --- a/altosuilib/AltosUIGraph.java +++ b/altosuilib/AltosUIGraph.java @@ -95,6 +95,10 @@ public class AltosUIGraph implements AltosUnitsListener { s.set_units(); } + public void filter_changed() { + units_changed(false); + } + public void setName (String name) { chart.setTitle(name); } diff --git a/altosuilib/AltosUITimeSeries.java b/altosuilib/AltosUITimeSeries.java index 08f95ca7..71166064 100644 --- a/altosuilib/AltosUITimeSeries.java +++ b/altosuilib/AltosUITimeSeries.java @@ -89,7 +89,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher public void fireSeriesChanged() { } - void set_data() { + public void set_data() { if (marker) { if (markers != null) { for (ValueMarker marker : markers) @@ -124,6 +124,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher } xy_series.setNotify(true); } + clear_changed(); } public void set_units() { diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java index 749d0f64..c6a2a3c9 100644 --- a/micropeak/MicroPeak.java +++ b/micropeak/MicroPeak.java @@ -27,7 +27,7 @@ import java.util.*; import org.altusmetrum.altoslib_12.*; import org.altusmetrum.altosuilib_12.*; -public class MicroPeak extends MicroFrame implements ActionListener, ItemListener { +public class MicroPeak extends MicroFrame implements ActionListener, ItemListener, AltosFilterListener { File filename; AltosGraph graph; @@ -206,6 +206,25 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene Preferences(); } + public void filter_changed(double speed_filter, double accel_filter) { + data.flight_series.set_filter(speed_filter, accel_filter); + graph.filter_changed(); + data.flight_stats = new AltosFlightStats(data.flight_series); + statsTable.filter_changed(data.flight_stats); + } + + public double speed_filter() { + if (data != null && data.flight_series != null) + return data.flight_series.speed_filter_width; + return 4.0; + } + + public double accel_filter() { + if (data != null && data.flight_series != null) + return data.flight_series.accel_filter_width; + return 1.0; + } + public MicroPeak() { ++number_of_windows; @@ -267,7 +286,7 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene } }); - enable = new AltosUIEnable(); + enable = new AltosUIEnable(this); graph = new AltosGraph(enable); statsTable = new AltosFlightStatsTable(); diff --git a/telegps/TeleGPSGraphUI.java b/telegps/TeleGPSGraphUI.java index 9d8c6bf5..c68f2bad 100644 --- a/telegps/TeleGPSGraphUI.java +++ b/telegps/TeleGPSGraphUI.java @@ -34,7 +34,7 @@ import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.ui.RefineryUtilities; -public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener +public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener { JTabbedPane pane; AltosGraph graph; @@ -92,20 +92,38 @@ public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, A enable.units_changed(imperial_units); } + AltosUIFlightSeries flight_series; + + public void filter_changed(double speed_filter, double accel_filter) { + flight_series.set_filter(speed_filter, accel_filter); + graph.filter_changed(); + stats = new AltosFlightStats(flight_series); + statsTable.filter_changed(stats); + } + + public double speed_filter() { + return flight_series.speed_filter_width; + } + + public double accel_filter() { + return flight_series.accel_filter_width; + } + TeleGPSGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException { super(file.getName()); AltosCalData cal_data = set.cal_data(); - AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data); + flight_series = new AltosUIFlightSeries(cal_data); set.capture_series(flight_series); flight_series.finish(); pane = new JTabbedPane(); - enable = new AltosUIEnable(); + graph = new AltosGraph(enable, stats, flight_series); + stats = new AltosFlightStats(flight_series); - graph = new AltosGraph(enable, stats, flight_series); + enable = new AltosUIEnable(this); statsTable = new AltosFlightStatsTable(stats); -- cgit v1.2.3 From 730ee7bf91f607ece42c010a10c53d0013492b96 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 4 Oct 2017 13:42:16 -0700 Subject: altoslib: Adapt KML output to make TRA record people happier Provide two paths, one using GPS data the other baro. Replace separate path segments for each state with markers so that the path is a single unit, able to be displayed in the elevation profile widget. Signed-off-by: Keith Packard --- altoslib/AltosFlightStats.java | 7 + altoslib/AltosKML.java | 289 ++++++++++++++++++++++++++++++----------- 2 files changed, 222 insertions(+), 74 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index ea1a9675..6bb83581 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -27,6 +27,8 @@ public class AltosFlightStats { public double max_acceleration; public double[] state_speed = new double[AltosLib.ao_flight_invalid + 1]; public double[] state_enter_speed = new double[AltosLib.ao_flight_invalid + 1]; + public double[] state_enter_height = new double[AltosLib.ao_flight_invalid + 1]; + public double[] state_enter_gps_height = new double[AltosLib.ao_flight_invalid + 1]; public double[] state_accel = new double[AltosLib.ao_flight_invalid + 1]; public double[] state_time = new double[AltosLib.ao_flight_invalid + 1]; public String product; @@ -134,6 +136,11 @@ public class AltosFlightStats { if (0 <= state && state <= AltosLib.ao_flight_invalid && delta_time > 0) { if (state_enter_speed[state] == AltosLib.MISSING) state_enter_speed[state] = series.speed_series.value(start_time); + if (state_enter_height[state] == AltosLib.MISSING) + state_enter_height[state] = series.height_series.value(start_time); + if (state_enter_gps_height[state] == AltosLib.MISSING) + if (series.gps_height != null) + state_enter_gps_height[state] = series.gps_height.value(start_time); speeds[state].value += series.speed_series.average(start_time, end_time) * delta_time; speeds[state].time += delta_time; accels[state].value += series.accel_series.average(start_time, end_time) * delta_time; diff --git a/altoslib/AltosKML.java b/altoslib/AltosKML.java index 587b845b..4738ac91 100644 --- a/altoslib/AltosKML.java +++ b/altoslib/AltosKML.java @@ -38,16 +38,18 @@ public class AltosKML implements AltosWriter { int flight_state = -1; AltosGPS prev = null; double gps_start_altitude = AltosLib.MISSING; + AltosFlightSeries series; AltosFlightStats stats; + AltosCalData cal_data; static final String[] kml_state_colors = { "FF000000", // startup "FF000000", // idle "FF000000", // pad "FF0000FF", // boost + "FF8040FF", // coast "FF4080FF", // fast - "FF00FFFF", // coast - "FFFF0000", // drogue + "FF00FFFF", // drogue "FF00FF00", // main "FF000000", // landed "FFFFFFFF", // invalid @@ -60,85 +62,169 @@ public class AltosKML implements AltosWriter { return kml_state_colors[state]; } + static final String[] kml_style_colors = { + "FF0000FF", // baro + "FFFF0000", // gps + }; + + static String style_color(int style) { + if (style < 0 || kml_style_colors.length <= style) + return kml_style_colors[0]; + return kml_style_colors[style]; + } + static final String kml_header_start = "\n" + "\n" + "\n" + " AO Flight#%d S/N: %03d\n" + - " \n"; + " \n"; + static final String kml_header_end = - " \n" + - " 0\n"; - - static final String kml_style_start = - " \n"; - - static final String kml_placemark_start = - " \n" + - " %s\n" + - " #ao-flightstate-%s\n" + - " \n" + - " 1\n" + - " absolute\n" + - " \n"; + " \n" + + " 1\n"; + + static final String kml_folder_start = + " \n" + + " %s\n"; + + static final String kml_path_style_start = + " \n"; + + static final String kml_point_style_start = + " \n"; + + static final String kml_path_start = + " \n" + + " %s\n" + + " #ao-style-%s\n" + + " \n" + + " 1\n" + + " absolute\n" + + " \n"; static final String kml_coord_fmt = - " %.7f,%.7f,%.7f \n"; + " %.7f,%.7f,%.7f \n"; - static final String kml_placemark_end = - " \n" + - " \n" + - " \n"; + static final String kml_path_end = + " \n" + + " \n" + + " \n"; + + static final String kml_point_start = + " \n" + + " %s\n" + + " #ao-style-%s\n" + + " \n" + + " 1\n" + + " absolute\n" + + " \n"; + + static final String kml_point_end = + " \n" + + " \n" + + " \n"; + + static final String kml_folder_end = + " \n"; static final String kml_footer = "\n" + "\n"; - void start (AltosCalData cal_data) { + void start () { AltosGPS gps = cal_data.gps_pad; gps_start_altitude = cal_data.gps_pad_altitude; out.printf(kml_header_start, cal_data.flight, cal_data.serial); - out.printf("Date: %04d-%02d-%02d\n", + out.printf("Product: %s\n", stats.product); + out.printf("Firmware: %s\n", stats.firmware_version); + out.printf("Date: %04d-%02d-%02d\n", gps.year, gps.month, gps.day); - out.printf("Time: %2d:%02d:%02d\n", + out.printf("Time: %2d:%02d:%02d\n", gps.hour, gps.minute, gps.second); + if (stats.max_height != AltosLib.MISSING) + out.printf("Max baro height: %s\n", AltosConvert.height.show(6, stats.max_height)); + if (stats.max_gps_height != AltosLib.MISSING) + out.printf("Max GPS Height: %s\n", AltosConvert.height.show(6, stats.max_gps_height)); + if (stats.max_speed != AltosLib.MISSING) + out.printf("Max speed: %s\n", AltosConvert.speed.show(6, stats.max_speed)); + if (stats.max_acceleration != AltosLib.MISSING) + out.printf("Max accel: %s\n", AltosConvert.accel.show(6, stats.max_acceleration)); out.printf("%s", kml_header_end); } - boolean started = false; + void folder_start(String folder_name) { + out.printf(kml_folder_start, folder_name); + } - void state_start(int state) { - String state_name = AltosLib.state_name(state); - String state_color = state_color(state); - out.printf(kml_style_start, state_name, state_color); - out.printf("State: %s\n", state_name); - out.printf("Time: %6.2f s\n", stats.state_time[state]); - out.printf("Average speed: %s\n", AltosConvert.speed.show(6, stats.state_speed[state])); - out.printf("Average accel: %s\n", AltosConvert.accel.show(6, stats.state_accel[state])); - out.printf("%s", kml_style_end); - out.printf(kml_placemark_start, state_name, state_name); + void folder_end() { + out.printf(kml_folder_end); } - void state_end() { - out.printf("%s", kml_placemark_end); + void path_style_start(String style, String color) { + out.printf(kml_path_style_start, style, color); } - void coord(double time, AltosGPS gps, int state, double height) { - double altitude; + void path_style_end() { + out.printf(kml_path_style_end); + } + + void point_style_start(String style, String color) { + out.printf(kml_point_style_start, style, color, color); + } + + void point_style_end() { + out.printf(kml_point_style_end); + } - if (height != AltosLib.MISSING) - altitude = height + gps_start_altitude; - else - altitude = gps.alt; + void path_start(String name, String style) { + out.printf(kml_path_start, name, style); + } + + void path_end() { + out.printf(kml_path_end); + } + + void point_start(String name, String style) { + out.printf(kml_point_start, name, style); + } + + void point_end() { + out.printf(kml_point_end); + } + + boolean started = false; + + private double baro_altitude(AltosFlightSeries series, double time) { + double height = series.value(AltosFlightSeries.height_name, time); + + if (height == AltosLib.MISSING) + return AltosLib.MISSING; + if (cal_data.gps_pad_altitude == AltosLib.MISSING) + return AltosLib.MISSING; + + return height + cal_data.gps_pad_altitude; + } + + void coord(double time, AltosGPS gps, double altitude) { out.printf(kml_coord_fmt, gps.lon, gps.lat, altitude, (double) gps.alt, @@ -150,48 +236,103 @@ public class AltosKML implements AltosWriter { } public void close() { - if (prev != null) { - state_end(); - end(); - prev = null; - } if (out != null) { out.close(); out = null; } } - public void write(AltosGPSTimeValue gtv, AltosCalData cal_data, int state, double height) { - AltosGPS gps = gtv.gps; + public void write(AltosGPS gps, double alt) + { if (gps.lat == AltosLib.MISSING) return; if (gps.lon == AltosLib.MISSING) return; - if (state != flight_state) { - flight_state = state; - if (prev != null) { - coord(gtv.time, gps, state, height); - state_end(); - } - state_start(state); + if (alt == AltosLib.MISSING) { + alt = cal_data.gps_pad_altitude; + if (alt == AltosLib.MISSING) + return; } - coord(0, gps, state, height); + coord(0, gps, alt); prev = gps; } - private int state(AltosFlightSeries series, double time) { - return (int) series.value_before(AltosFlightSeries.state_name, time); - } + public void write_point(AltosTimeValue tv, boolean is_gps) { + int state = (int) tv.value; + String style_prefix = is_gps ? "gps-" : "baro-"; + String state_name = AltosLib.state_name(state); + String state_label = AltosLib.state_name_capital(state); + String style_name = style_prefix + state_name; + String folder_name = is_gps ? "GPS" : "Baro"; + String full_name = state_label + " (" + folder_name + ")"; + AltosGPS gps = series.gps_before(tv.time); + double altitude = is_gps ? gps.alt : baro_altitude(series, tv.time); - private double height(AltosFlightSeries series, double time) { - return series.value(AltosFlightSeries.height_name, time); + point_style_start(style_name, state_color(state)); + out.printf("%s\n", full_name); + switch (state) { + case AltosLib.ao_flight_boost: + out.printf("Max accel %s\n", AltosConvert.accel.show(6, stats.max_acceleration)); + out.printf("Max speed %s\n", AltosConvert.speed.show(6, stats.max_speed)); + break; + case AltosLib.ao_flight_coast: + case AltosLib.ao_flight_fast: + out.printf("Entry speed %s\n", AltosConvert.speed.show(6, stats.state_enter_speed[state])); + out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude)); + break; + case AltosLib.ao_flight_drogue: + out.printf("Max height %s\n", AltosConvert.height.show(6, is_gps ? stats.max_gps_height : stats.max_height)); + out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state])); + break; + case AltosLib.ao_flight_main: + out.printf("Entry speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state])); + out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude)); + out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state])); + break; + case AltosLib.ao_flight_landed: + out.printf("Landing speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state])); + break; + } + point_style_end(); + point_start(full_name, style_name); + gps = series.gps_before(tv.time); + write(gps, altitude); + point_end(); } public void write(AltosFlightSeries series) { + this.series = series; + series.finish(); stats = new AltosFlightStats(series); - start(series.cal_data()); + cal_data = series.cal_data(); + start(); + folder_start("Barometric Altitude"); + path_style_start("baro", style_color(0)); + out.printf("Barometric Altitude\n"); + out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height)); + path_style_end(); + path_start("Barometric Altitude", "baro"); for (AltosGPSTimeValue gtv : series.gps_series) - write(gtv, series.cal_data(), state(series, gtv.time), height(series, gtv.time)); + write(gtv.gps, baro_altitude(series, gtv.time)); + path_end(); + for (AltosTimeValue tv : series.state_series) { + write_point(tv, false); + } + folder_end(); + folder_start("GPS Altitude"); + path_style_start("gps", style_color(1)); + out.printf("GPS Altitude"); + out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_gps_height)); + path_style_end(); + path_start("GPS Altitude", "gps"); + for (AltosGPSTimeValue gtv : series.gps_series) + write(gtv.gps, gtv.gps.alt); + path_end(); + for (AltosTimeValue tv : series.state_series) { + write_point(tv, true); + } + folder_end(); + end(); } public AltosKML(File in_name) throws FileNotFoundException { -- cgit v1.2.3 From 7e971b45f22aa77421061ff2925e0458835014b2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 4 Oct 2017 13:44:31 -0700 Subject: altoslib: Missing file for filter additions. Signed-off-by: Keith Packard --- altoslib/AltosFilterListener.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 altoslib/AltosFilterListener.java (limited to 'altoslib') diff --git a/altoslib/AltosFilterListener.java b/altoslib/AltosFilterListener.java new file mode 100644 index 00000000..fe91100a --- /dev/null +++ b/altoslib/AltosFilterListener.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2017 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +package org.altusmetrum.altoslib_12; + +public interface AltosFilterListener { + void filter_changed(double speed_filter, double accel_filter); + + double speed_filter(); + double accel_filter(); +} -- cgit v1.2.3 From a69d5773a63dbe5d6d758cea8eca2bf724e9d672 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 12 Oct 2017 00:26:31 -0700 Subject: altoslib: Allow gps time later than requested if it's first When generating a KML file, we want to position markers near the start of the flight section. This is done by looking for a GPS coordinate 'before' the starting point of the flight, which doesn't work well when the first GPS coordinate is later than that. Pick the first point after the chosen time if there isn't an earlier one. Signed-off-by: Keith Packard --- altoslib/AltosFlightSeries.java | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index 02bf64ff..2eaf8033 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -489,13 +489,24 @@ public class AltosFlightSeries extends AltosDataListener { public ArrayList gps_series; public AltosGPS gps_before(double time) { - AltosGPS gps = null; - for (AltosGPSTimeValue gtv : gps_series) - if (gtv.time <= time) - gps = gtv.gps; - else - break; - return gps; + AltosGPSTimeValue nearest = null; + for (AltosGPSTimeValue gtv : gps_series) { + if (nearest == null) + nearest = gtv; + else { + if (gtv.time <= time) { + if (nearest.time <= time && gtv.time > nearest.time) + nearest = gtv; + } else { + if (nearest.time > time && gtv.time < nearest.time) + nearest = gtv; + } + } + } + if (nearest != null) + return nearest.gps; + else + return null; } public AltosTimeSeries sats_in_view; -- cgit v1.2.3 From e04679ba52761d5531037117a21ab1f1896358b0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 12 Oct 2017 00:29:07 -0700 Subject: altoslib: Don't crash if there's no GPS coord to write KML Just check for null before writing as a precaution. Signed-off-by: Keith Packard --- altoslib/AltosKML.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'altoslib') diff --git a/altoslib/AltosKML.java b/altoslib/AltosKML.java index 4738ac91..aa98f0e6 100644 --- a/altoslib/AltosKML.java +++ b/altoslib/AltosKML.java @@ -244,6 +244,8 @@ public class AltosKML implements AltosWriter { public void write(AltosGPS gps, double alt) { + if (gps == null) + return; if (gps.lat == AltosLib.MISSING) return; if (gps.lon == AltosLib.MISSING) -- cgit v1.2.3 From 77d1aee917306ad59492c4c8352fe2125b430d0c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 12 Oct 2017 00:30:23 -0700 Subject: altoslib: Fix time series filter window computation Small floating point rounding errors could lead to NaNs. Signed-off-by: Keith Packard --- altoslib/AltosTimeSeries.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altoslib') diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index 7208c176..c6a780a3 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -294,7 +294,7 @@ public class AltosTimeSeries implements Iterable, Comparable 1) + if (t > 1 || t < -1) t = 1; double k = i0 (beta * Math.sqrt (1 - t*t)) / i0(beta); return k; -- cgit v1.2.3 From 964a14568b73296194f84c728cc7e01d6f0e2f64 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Oct 2017 12:05:07 -0700 Subject: altoslib: Report un-adjusted ground accel in idle IMU monitor The ground accel is the basis of the accel adjustment, so it needs to be delivered in un-adjusted form. Signed-off-by: Keith Packard --- altoslib/AltosIMU.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index dee28a92..ba6f1a82 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -83,9 +83,9 @@ public class AltosIMU implements Cloneable { listener.set_gyro(cal_data.gyro_roll(imu.gyro_y), cal_data.gyro_pitch(imu.gyro_x), cal_data.gyro_yaw(imu.gyro_z)); - listener.set_accel_ground(cal_data.accel_along(imu.accel_y), - cal_data.accel_across(imu.accel_x), - cal_data.accel_through(imu.accel_z)); + listener.set_accel_ground(imu.accel_y, + imu.accel_x, + imu.accel_z); } } catch (TimeoutException te) { } -- cgit v1.2.3 From e98235e314ac764509af26c93da9e6d1de8184ea Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Oct 2017 12:18:26 -0700 Subject: altoslib: Save separate config for local and remote. Use in idle When using the remote link, there are two separate configuration data blocks, that for the local device and for remote. Make the link report both versions, depending on whether it is in remote mode or not. Request config data in remote mode when running idle monitoring so that the presented data is for the remote device, not the local one. Signed-off-by: Keith Packard --- altoslib/AltosIdleMonitor.java | 17 +++++------ altoslib/AltosLink.java | 63 +++++++++++++++++++++++++++-------------- altosui/AltosIdleMonitorUI.java | 2 +- 3 files changed, 52 insertions(+), 30 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index fc5d4cc8..834d9aa5 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -33,6 +33,7 @@ public class AltosIdleMonitor extends Thread { double frequency; String callsign; + AltosState state; AltosListenerState listener_state; AltosConfigData config_data; AltosGPS gps; @@ -52,20 +53,23 @@ public class AltosIdleMonitor extends Thread { return link.reply_abort; } - boolean provide_data(AltosDataListener listener) throws InterruptedException, TimeoutException, AltosUnknownProduct { + boolean provide_data() throws InterruptedException, TimeoutException, AltosUnknownProduct { boolean worked = false; boolean aborted = false; try { start_link(); - fetch.provide_data(listener); + link.config_data(); + if (state == null) + state = new AltosState(new AltosCalData(link.config_data())); + fetch.provide_data(state); if (!link.has_error && !link.reply_abort) worked = true; } finally { aborted = stop_link(); if (worked) { if (remote) - listener.set_rssi(link.rssi(), 0); + state.set_rssi(link.rssi(), 0); listener_state.battery = link.monitor_battery(); } } @@ -92,14 +96,11 @@ public class AltosIdleMonitor extends Thread { } public void run() { - AltosState state = null; + state = null; try { for (;;) { try { - link.config_data(); - if (state == null) - state = new AltosState(new AltosCalData(link.config_data())); - provide_data(state); + provide_data(); listener.update(state, listener_state); } catch (TimeoutException te) { } catch (AltosUnknownProduct ae) { diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 5413de9d..829a1a63 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -355,7 +355,8 @@ public abstract class AltosLink implements Runnable { public int telemetry_rate = -1; public double frequency; public String callsign; - AltosConfigData config_data; + private AltosConfigData config_data_local; + private AltosConfigData config_data_remote; private Object config_data_lock = new Object(); @@ -390,7 +391,7 @@ public abstract class AltosLink implements Runnable { public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { frequency = in_frequency; - config_data(); + AltosConfigData config_data = config_data(); set_radio_frequency(frequency, config_data.radio_frequency > 0, config_data.radio_setting > 0, @@ -446,11 +447,24 @@ public abstract class AltosLink implements Runnable { public AltosConfigData config_data() throws InterruptedException, TimeoutException { synchronized(config_data_lock) { - if (config_data == null) { - printf("m 0\n"); - config_data = new AltosConfigData(this); - if (monitor_mode) - set_monitor(true); + AltosConfigData config_data; + + if (remote) { + if (config_data_remote == null) { + printf("m 0\n"); + config_data_remote = new AltosConfigData(this); + if (monitor_mode) + set_monitor(true); + } + config_data = config_data_remote; + } else { + if (config_data_local == null) { + printf("m 0\n"); + config_data_local = new AltosConfigData(this); + if (monitor_mode) + set_monitor(true); + } + config_data = config_data_local; } return config_data; } @@ -551,14 +565,23 @@ public abstract class AltosLink implements Runnable { } public boolean has_monitor_battery() { - return config_data.has_monitor_battery(); + try { + return config_data().has_monitor_battery(); + } catch (InterruptedException ie) { + return false; + } catch (TimeoutException te) { + return false; + } } public double monitor_battery() throws InterruptedException { - int monitor_batt = AltosLib.MISSING; + double volts = AltosLib.MISSING; - if (config_data.has_monitor_battery()) { - try { + try { + AltosConfigData config_data = config_data(); + int monitor_batt = AltosLib.MISSING; + + if (config_data.has_monitor_battery()) { String[] items = adc(); for (int i = 0; i < items.length;) { if (items[i].equals("batt")) { @@ -568,19 +591,17 @@ public abstract class AltosLink implements Runnable { } i++; } - } catch (TimeoutException te) { } - } - if (monitor_batt == AltosLib.MISSING) - return AltosLib.MISSING; + if (monitor_batt != AltosLib.MISSING) { + if (config_data.product.startsWith("TeleBT-v3") || config_data.product.startsWith("TeleBT-v4")) { + volts = AltosConvert.tele_bt_3_battery(monitor_batt); + } else { + volts = AltosConvert.cc_battery_to_voltage(monitor_batt); + } + } - double volts = AltosLib.MISSING; - if (config_data.product.startsWith("TeleBT-v3") || config_data.product.startsWith("TeleBT-v4")) { - volts = AltosConvert.tele_bt_3_battery(monitor_batt); - } else { - volts = AltosConvert.cc_battery_to_voltage(monitor_batt); + } catch (TimeoutException te) { } - return volts; } diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index a2696f15..584f143a 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -295,7 +295,7 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl pack(); setVisible(true); - thread = new AltosIdleMonitor((AltosIdleMonitorListener) this, link, (boolean) remote); + thread = new AltosIdleMonitor(this, link, (boolean) remote); status_update = new AltosFlightStatusUpdate(flightStatus); -- cgit v1.2.3 From 749400fd244eba38806c623d2a35722642230698 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 22 Oct 2017 14:04:09 -0500 Subject: altoslib: Move temp GPS API from cal_data to data_listener This makes the API more consistent, and means that the listener is responsible for mangaing the temp gps state. In particular, the AltosDataListener set_gps API now calls the cal_data function. Signed-off-by: Keith Packard --- altoslib/AltosCalData.java | 39 ++++---- altoslib/AltosDataListener.java | 13 ++- altoslib/AltosEepromDownload.java | 1 + altoslib/AltosEepromRecord.java | 6 +- altoslib/AltosEepromRecordFull.java | 12 +-- altoslib/AltosEepromRecordMega.java | 4 +- altoslib/AltosEepromRecordMetrum.java | 6 +- altoslib/AltosFlightListener.java | 162 ---------------------------------- altoslib/AltosFlightSeries.java | 1 + altoslib/AltosReplayReader.java | 2 +- altoslib/AltosState.java | 1 + altoslib/AltosTelemetryLocation.java | 7 +- altoslib/AltosTelemetrySatellite.java | 3 +- 13 files changed, 47 insertions(+), 210 deletions(-) delete mode 100644 altoslib/AltosFlightListener.java (limited to 'altoslib') diff --git a/altoslib/AltosCalData.java b/altoslib/AltosCalData.java index 7415d5ad..fdea5e21 100644 --- a/altoslib/AltosCalData.java +++ b/altoslib/AltosCalData.java @@ -199,7 +199,6 @@ public class AltosCalData { tick = AltosLib.MISSING; prev_tick = AltosLib.MISSING; temp_gps = null; - prev_gps = null; temp_gps_sat_tick = AltosLib.MISSING; accel = AltosLib.MISSING; } @@ -244,11 +243,14 @@ public class AltosCalData { public double gps_pad_altitude = AltosLib.MISSING; - public void set_gps(AltosGPS gps) { - if ((state != AltosLib.MISSING && state < AltosLib.ao_flight_boost) || gps_pad == null) - gps_pad = gps; - if (gps_pad_altitude == AltosLib.MISSING && gps.alt != AltosLib.MISSING) - gps_pad_altitude = gps.alt; + public void set_cal_gps(AltosGPS gps) { + if (gps.locked && gps.nsat >= 4) { + if ((state != AltosLib.MISSING && state < AltosLib.ao_flight_boost) || gps_pad == null) + gps_pad = gps; + if (gps_pad_altitude == AltosLib.MISSING && gps.alt != AltosLib.MISSING) + gps_pad_altitude = gps.alt; + } + temp_gps = null; } /* @@ -256,33 +258,24 @@ public class AltosCalData { * object and then deliver the result atomically to the listener */ AltosGPS temp_gps = null; - AltosGPS prev_gps = null; int temp_gps_sat_tick = AltosLib.MISSING; - public AltosGPS temp_gps() { + public AltosGPS temp_cal_gps() { return temp_gps; } - public void reset_temp_gps() { - if (temp_gps != null) { - if (temp_gps.locked && temp_gps.nsat >= 4) - set_gps(temp_gps); - prev_gps = temp_gps; - temp_gps = null; - } + public void reset_temp_cal_gps() { + if (temp_gps != null) + set_cal_gps(temp_gps); } - public boolean gps_pending() { + public boolean cal_gps_pending() { return temp_gps != null; } - public AltosGPS make_temp_gps(int tick, boolean sats) { - if (temp_gps == null) { - if (prev_gps != null) - temp_gps = prev_gps.clone(); - else - temp_gps = new AltosGPS(); - } + public AltosGPS make_temp_cal_gps(int tick, boolean sats) { + if (temp_gps == null) + temp_gps = new AltosGPS(); if (sats) { if (tick != temp_gps_sat_tick) temp_gps.cc_gps_sat = null; diff --git a/altoslib/AltosDataListener.java b/altoslib/AltosDataListener.java index 359d04c9..9a1e1465 100644 --- a/altoslib/AltosDataListener.java +++ b/altoslib/AltosDataListener.java @@ -111,7 +111,18 @@ public abstract class AltosDataListener { public abstract void set_apogee_voltage(double volts); public abstract void set_main_voltage(double volts); - public abstract void set_gps(AltosGPS gps); + public void set_gps(AltosGPS gps) { + AltosCalData cal_data = cal_data(); + cal_data.set_cal_gps(gps); + } + + public AltosGPS make_temp_gps(boolean sats) { + return cal_data().make_temp_cal_gps(tick(), sats); + } + + public AltosGPS temp_gps() { + return cal_data().temp_cal_gps(); + } public abstract void set_orient(double orient); public abstract void set_gyro(double roll, double pitch, double yaw); diff --git a/altoslib/AltosEepromDownload.java b/altoslib/AltosEepromDownload.java index 33f0dd17..3df8a5b4 100644 --- a/altoslib/AltosEepromDownload.java +++ b/altoslib/AltosEepromDownload.java @@ -40,6 +40,7 @@ class AltosEepromNameData extends AltosDataListener { public void set_main_voltage(double volts) { } public void set_gps(AltosGPS gps) { + super.set_gps(gps); if (gps != null && gps.year != AltosLib.MISSING && gps.month != AltosLib.MISSING && diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java index e937c3d0..12519e6b 100644 --- a/altoslib/AltosEepromRecord.java +++ b/altoslib/AltosEepromRecord.java @@ -90,11 +90,9 @@ public abstract class AltosEepromRecord implements Comparable /* Flush any pending GPS changes */ if (!AltosLib.is_gps_cmd(cmd())) { - AltosGPS gps = cal_data.temp_gps(); - if (gps != null) { + AltosGPS gps = listener.temp_gps(); + if (gps != null) listener.set_gps(gps); - cal_data.reset_temp_gps(); - } } } diff --git a/altoslib/AltosEepromRecordFull.java b/altoslib/AltosEepromRecordFull.java index 32df9578..7e92d353 100644 --- a/altoslib/AltosEepromRecordFull.java +++ b/altoslib/AltosEepromRecordFull.java @@ -53,7 +53,7 @@ public class AltosEepromRecordFull extends AltosEepromRecord { listener.set_state(data16(0)); break; case AltosLib.AO_LOG_GPS_TIME: - gps = cal_data.make_temp_gps(tick(),false); + gps = listener.make_temp_gps(false); gps.hour = data8(0); gps.minute = data8(1); @@ -67,29 +67,29 @@ public class AltosEepromRecordFull extends AltosEepromRecord { AltosLib.AO_GPS_NUM_SAT_SHIFT; break; case AltosLib.AO_LOG_GPS_LAT: - gps = cal_data.make_temp_gps(tick(),false); + gps = listener.make_temp_gps(false); int lat32 = data32(0); gps.lat = (double) lat32 / 1e7; break; case AltosLib.AO_LOG_GPS_LON: - gps = cal_data.make_temp_gps(tick(),false); + gps = listener.make_temp_gps(false); int lon32 = data32(0); gps.lon = (double) lon32 / 1e7; break; case AltosLib.AO_LOG_GPS_ALT: - gps = cal_data.make_temp_gps(tick(),false); + gps = listener.make_temp_gps(false); gps.alt = data16(0); break; case AltosLib.AO_LOG_GPS_SAT: - gps = cal_data.make_temp_gps(tick(),true); + gps = listener.make_temp_gps(true); int svid = data16(0); int c_n0 = data16(2); gps.add_sat(svid, c_n0); break; case AltosLib.AO_LOG_GPS_DATE: - gps = cal_data.make_temp_gps(tick(),false); + gps = listener.make_temp_gps(false); gps.year = data8(0) + 2000; gps.month = data8(1); gps.day = data8(2); diff --git a/altoslib/AltosEepromRecordMega.java b/altoslib/AltosEepromRecordMega.java index ad3e23fd..ea5aff5c 100644 --- a/altoslib/AltosEepromRecordMega.java +++ b/altoslib/AltosEepromRecordMega.java @@ -188,7 +188,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord { listener.set_pyro_fired(pyro()); break; case AltosLib.AO_LOG_GPS_TIME: - gps = cal_data.make_temp_gps(tick(), false); + gps = listener.make_temp_gps(false); gps.lat = latitude() / 1e7; gps.lon = longitude() / 1e7; @@ -231,7 +231,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord { } break; case AltosLib.AO_LOG_GPS_SAT: - gps = cal_data.make_temp_gps(tick(), true); + gps = listener.make_temp_gps(true); int n = nsat(); if (n > max_sat) diff --git a/altoslib/AltosEepromRecordMetrum.java b/altoslib/AltosEepromRecordMetrum.java index 3da50544..888a06cc 100644 --- a/altoslib/AltosEepromRecordMetrum.java +++ b/altoslib/AltosEepromRecordMetrum.java @@ -91,7 +91,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord { listener.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m())); break; case AltosLib.AO_LOG_GPS_POS: - gps = cal_data.make_temp_gps(tick(), false); + gps = listener.make_temp_gps(false); gps.lat = latitude() / 1e7; gps.lon = longitude() / 1e7; if (config_data().altitude_32()) @@ -100,7 +100,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord { gps.alt = altitude_low(); break; case AltosLib.AO_LOG_GPS_TIME: - gps = cal_data.make_temp_gps(tick(), false); + gps = listener.make_temp_gps(false); gps.hour = hour(); gps.minute = minute(); @@ -119,7 +119,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord { gps.pdop = pdop() / 10.0; break; case AltosLib.AO_LOG_GPS_SAT: - gps = cal_data.make_temp_gps(tick(), true); + gps = listener.make_temp_gps(true); int n = nsat(); for (int i = 0; i < n; i++) diff --git a/altoslib/AltosFlightListener.java b/altoslib/AltosFlightListener.java deleted file mode 100644 index d61831a9..00000000 --- a/altoslib/AltosFlightListener.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright © 2017 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, either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ - -package org.altusmetrum.altoslib_12; - -public abstract class AltosFlightListener { - - public int flight; - public int serial; - public int tick; - public int boost_tick; - public int state; - - public double accel_plus_g; - public double accel_minus_g; - public double accel; - - public double ground_pressure; - public double ground_altitude; - - AltosGPS temp_gps; - int temp_gps_sat_tick; - int gps_sequence; - - /* AltosEepromRecord */ - public void set_boost_tick(int boost_tick) { - if (boost_tick != AltosLib.MISSING) - this.boost_tick = boost_tick; - } - - public void set_tick(int tick) { - if (tick != AltosLib.MISSING) - this.tick = tick; - } - - public double time() { - if (tick == AltosLib.MISSING) - return AltosLib.MISSING; - if (boost_tick != AltosLib.MISSING) - return (tick - boost_tick) / 100.0; - else - return tick / 100.0; - } - - public double boost_time() { - if (boost_tick == AltosLib.MISSING) - return AltosLib.MISSING; - return boost_tick / 100.0; - } - - public abstract void set_rssi(int rssi, int status); - public abstract void set_received_time(long received_time); - - /* AltosEepromRecordFull */ - - public void set_serial(int serial) { - if (serial != AltosLib.MISSING) - this.serial = serial; - } - - public void set_state(int state) { - if (state != AltosLib.MISSING) - this.state = state; - } - - public int state() { return state; } - - public abstract void set_ground_accel(double ground_accel); - public void set_flight(int flight) { - if (flight != AltosLib.MISSING) - this.flight = flight; - } - public int flight() { - return flight; - } - - public abstract void set_accel(double accel); - public abstract void set_acceleration(double accel); - public abstract void set_accel_g(double accel_plus_g, double accel_minus_g); - public abstract void set_pressure(double pa); - public abstract void set_thrust(double N); - - public abstract void set_temperature(double deg_c); - public abstract void set_battery_voltage(double volts); - - public abstract void set_apogee_voltage(double volts); - public abstract void set_main_voltage(double volts); - - public void set_temp_gps() { - temp_gps = null; - } - - public boolean gps_pending() { - return temp_gps != null; - } - - public AltosGPS make_temp_gps(boolean sats) { - if (temp_gps == null) { - temp_gps = new AltosGPS(); - } - if (sats) { - if (tick != temp_gps_sat_tick) - temp_gps.cc_gps_sat = null; - temp_gps_sat_tick = tick; - } - return temp_gps; - } - - public void set_ground_pressure(double ground_pressure) { - if (ground_pressure != AltosLib.MISSING) { - this.ground_pressure = ground_pressure; - this.ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure); - } - } - - public abstract void set_accel_ground(double along, double across, double through); - public abstract void set_gyro_zero(double roll, double pitch, double yaw); - public abstract void check_imu_wrap(AltosIMU imu); - public abstract void set_imu(AltosIMU imu); - public abstract void set_mag(AltosMag mag); - public abstract void set_pyro_voltage(double volts); - public abstract void set_igniter_voltage(double[] voltage); - public abstract void set_pyro_fired(int pyro_mask); - - public void copy(AltosFlightListener old) { - flight = old.flight; - serial = old.serial; - tick = old.tick; - boost_tick = old.boost_tick; - accel_plus_g = old.accel_plus_g; - accel_minus_g = old.accel_minus_g; - ground_pressure = old.ground_pressure; - ground_altitude = old.ground_altitude; - temp_gps = old.temp_gps; - temp_gps_sat_tick = old.temp_gps_sat_tick; - } - - public void init() { - flight = AltosLib.MISSING; - serial = AltosLib.MISSING; - tick = AltosLib.MISSING; - boost_tick = AltosLib.MISSING; - accel_plus_g = AltosLib.MISSING; - accel_minus_g = AltosLib.MISSING; - accel = AltosLib.MISSING; - ground_pressure = AltosLib.MISSING; - ground_altitude = AltosLib.MISSING; - temp_gps = null; - temp_gps_sat_tick = AltosLib.MISSING; - } -} diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index 2eaf8033..d130d3ad 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -532,6 +532,7 @@ public class AltosFlightSeries extends AltosDataListener { public static final String gps_hdop_name = "GPS Horizontal Dilution of Precision"; public void set_gps(AltosGPS gps) { + super.set_gps(gps); if (gps_series == null) gps_series = new ArrayList(); gps_series.add(new AltosGPSTimeValue(time(), gps)); diff --git a/altoslib/AltosReplayReader.java b/altoslib/AltosReplayReader.java index 24b425b7..7ce4197b 100644 --- a/altoslib/AltosReplayReader.java +++ b/altoslib/AltosReplayReader.java @@ -70,7 +70,7 @@ class AltosReplay extends AltosDataListener implements Runnable { public void set_apogee_voltage(double volts) { state.set_apogee_voltage(volts); } public void set_main_voltage(double volts) { state.set_main_voltage(volts); } - public void set_gps(AltosGPS gps) { state.set_gps(gps); } + public void set_gps(AltosGPS gps) { super.set_gps(gps); state.set_gps(gps); } public void set_orient(double orient) { state.set_orient(orient); } public void set_gyro(double roll, double pitch, double yaw) { state.set_gyro(roll, pitch, yaw); } diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 54c70094..68097faf 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -887,6 +887,7 @@ public class AltosState extends AltosDataListener { } public void set_gps(AltosGPS gps) { + super.set_gps(gps); if (gps != null) { this.gps = gps; update_gps(); diff --git a/altoslib/AltosTelemetryLocation.java b/altoslib/AltosTelemetryLocation.java index f4366e33..e2925a58 100644 --- a/altoslib/AltosTelemetryLocation.java +++ b/altoslib/AltosTelemetryLocation.java @@ -54,7 +54,7 @@ public class AltosTelemetryLocation extends AltosTelemetryStandard { AltosCalData cal_data = listener.cal_data(); - AltosGPS gps = cal_data.make_temp_gps(tick(), false); + AltosGPS gps = listener.make_temp_gps(false); int flags = flags(); gps.nsat = flags & 0xf; @@ -77,12 +77,7 @@ public class AltosTelemetryLocation extends AltosTelemetryStandard { gps.ground_speed = ground_speed() * 1.0e-2; gps.course = course() * 2; gps.climb_rate = climb_rate() * 1.0e-2; - - if (gps.nsat >= 4) - cal_data.set_gps(gps); } listener.set_gps(gps); - cal_data.set_gps(gps); - cal_data.reset_temp_gps(); } } diff --git a/altoslib/AltosTelemetrySatellite.java b/altoslib/AltosTelemetrySatellite.java index 60bc4a51..0965df9f 100644 --- a/altoslib/AltosTelemetrySatellite.java +++ b/altoslib/AltosTelemetrySatellite.java @@ -49,10 +49,9 @@ public class AltosTelemetrySatellite extends AltosTelemetryStandard { AltosCalData cal_data = listener.cal_data(); - AltosGPS gps = cal_data.make_temp_gps(tick(), true); + AltosGPS gps = listener.make_temp_gps(true); gps.cc_gps_sat = sats(); listener.set_gps(gps); - cal_data.reset_temp_gps(); } } -- cgit v1.2.3 From e80005ea63bb9b1eee33a8876ad74ed5d50478ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 11 Nov 2017 20:44:27 -0800 Subject: altoslib: Don't write KML record when height data is missing This avoids a crash dealing with corrupted flight data Signed-off-by: Keith Packard --- altoslib/AltosKML.java | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosKML.java b/altoslib/AltosKML.java index aa98f0e6..d5248a17 100644 --- a/altoslib/AltosKML.java +++ b/altoslib/AltosKML.java @@ -308,19 +308,23 @@ public class AltosKML implements AltosWriter { stats = new AltosFlightStats(series); cal_data = series.cal_data(); start(); - folder_start("Barometric Altitude"); - path_style_start("baro", style_color(0)); - out.printf("Barometric Altitude\n"); - out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height)); - path_style_end(); - path_start("Barometric Altitude", "baro"); - for (AltosGPSTimeValue gtv : series.gps_series) - write(gtv.gps, baro_altitude(series, gtv.time)); - path_end(); - for (AltosTimeValue tv : series.state_series) { - write_point(tv, false); + if (series.height_series != null) { + folder_start("Barometric Altitude"); + path_style_start("baro", style_color(0)); + out.printf("Barometric Altitude\n"); + out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height)); + path_style_end(); + path_start("Barometric Altitude", "baro"); + for (AltosGPSTimeValue gtv : series.gps_series) + write(gtv.gps, baro_altitude(series, gtv.time)); + path_end(); + if (series.state_series != null) { + for (AltosTimeValue tv : series.state_series) { + write_point(tv, false); + } + } + folder_end(); } - folder_end(); folder_start("GPS Altitude"); path_style_start("gps", style_color(1)); out.printf("GPS Altitude"); @@ -330,8 +334,10 @@ public class AltosKML implements AltosWriter { for (AltosGPSTimeValue gtv : series.gps_series) write(gtv.gps, gtv.gps.alt); path_end(); - for (AltosTimeValue tv : series.state_series) { - write_point(tv, true); + if (series.state_series != null) { + for (AltosTimeValue tv : series.state_series) { + write_point(tv, true); + } } folder_end(); end(); -- cgit v1.2.3 From 10834eb60f7a44fee159d9e9ad5ffb2e013fe9cf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 11 Nov 2017 20:46:45 -0800 Subject: altoslib: Remove spurious semicolon in AltosReplayReader.java Signed-off-by: Keith Packard --- altoslib/AltosReplayReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altoslib') diff --git a/altoslib/AltosReplayReader.java b/altoslib/AltosReplayReader.java index 7ce4197b..fab28cac 100644 --- a/altoslib/AltosReplayReader.java +++ b/altoslib/AltosReplayReader.java @@ -31,7 +31,7 @@ class AltosReplay extends AltosDataListener implements Runnable { AltosState state; AltosRecordSet record_set; double last_time = AltosLib.MISSING; - Semaphore semaphore = new Semaphore(1);; + Semaphore semaphore = new Semaphore(1); boolean done = false; public void set_time(double time) { -- cgit v1.2.3 From 9a7b4f02ad32ca43a45ed9fe446b8db96e60b5e5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 11 Nov 2017 20:49:20 -0800 Subject: altoslib: Improve EEprom download * Catch and report CRC errors * Deal with corrupted flight records * Add ability to immediately graph new data * Check before overwriting existing files Signed-off-by: Keith Packard --- altoslib/AltosEeprom.java | 1 + altoslib/AltosEepromDownload.java | 42 +++++++++++++++----- altoslib/AltosEepromList.java | 4 +- altoslib/AltosEepromLog.java | 18 +++++++-- altoslib/AltosEepromMonitor.java | 6 ++- altoslib/AltosEepromRecord.java | 25 +++++++----- altoslib/AltosEepromRecordSet.java | 6 +-- altoslib/AltosFile.java | 17 +++++++- altosui/AltosUI.java | 13 +++++- altosuilib/AltosEepromDelete.java | 2 +- altosuilib/AltosEepromManage.java | 72 ++++++++++++++++++++------------- altosuilib/AltosEepromMonitorUI.java | 77 +++++++++++++++++------------------- altosuilib/AltosEepromSelect.java | 74 +++++++++++++++++++++++++++++----- telegps/TeleGPS.java | 19 ++++++++- 14 files changed, 260 insertions(+), 116 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosEeprom.java b/altoslib/AltosEeprom.java index ad7bf881..124bd478 100644 --- a/altoslib/AltosEeprom.java +++ b/altoslib/AltosEeprom.java @@ -22,6 +22,7 @@ public class AltosEeprom { private AltosJson config; ArrayList data; private AltosConfigData config_data; + int errors = 0; /* * Public accessor APIs diff --git a/altoslib/AltosEepromDownload.java b/altoslib/AltosEepromDownload.java index 3df8a5b4..547b523f 100644 --- a/altoslib/AltosEepromDownload.java +++ b/altoslib/AltosEepromDownload.java @@ -200,25 +200,47 @@ public class AltosEepromDownload implements Runnable { AltosFile f = MakeFile(flights.config_data.serial, log.flight, name_data); - monitor.set_filename(f.toString()); + log.set_file(f); - FileWriter w = new FileWriter(f); + boolean do_write = true; - eeprom.write(w); - w.close(); + if (f.exists()) + do_write = monitor.check_overwrite(f); + + if (do_write) { + FileWriter w = new FileWriter(f); + + eeprom.write(w); + w.close(); + } + + if (eeprom.errors != 0) + throw new ParseException(String.format("%d CRC Errors", eeprom.errors), 0); + } + + static String label(int flight) { + if (flight < 0) + return "Corrupt"; + else + return "Flight"; + } + + static int flight(int flight) { + if (flight < 0) + return -flight; + return flight; } public void run () { boolean success = false; try { - boolean failed = false; if (remote) link.start_remote(); for (AltosEepromLog log : flights) { parse_errors = null; - if (log.selected) { + if (log.download_selected) { monitor.reset(); try { CaptureLog(log); @@ -226,16 +248,16 @@ public class AltosEepromDownload implements Runnable { LogError(e.getMessage()); } } + success = true; if (parse_errors != null) { - failed = true; - monitor.show_message(String.format("Flight %d download error. Valid log data saved\n%s", - log.flight, + monitor.show_message(String.format("%s %d download error. Valid log data saved\n%s", + label(log.flight), + flight(log.flight), parse_errors), link.name, AltosEepromMonitor.WARNING_MESSAGE); } } - success = !failed; } catch (IOException ee) { monitor.show_message(ee.getLocalizedMessage(), link.name, diff --git a/altoslib/AltosEepromList.java b/altoslib/AltosEepromList.java index 55d47e20..c55bcaaa 100644 --- a/altoslib/AltosEepromList.java +++ b/altoslib/AltosEepromList.java @@ -87,7 +87,7 @@ public class AltosEepromList extends ArrayList { start = AltosParse.parse_hex(tokens[3]); if (tokens[4].equals("end")) end = AltosParse.parse_hex(tokens[5]); - if (flight > 0 && start >= 0 && end > 0) + if (flight != 0 && start >= 0 && end > 0) flights.add(new AltosEepromFlight(flight, start, end)); } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); } } @@ -115,4 +115,4 @@ public class AltosEepromList extends ArrayList { link.flush_output(); } } -} \ No newline at end of file +} diff --git a/altoslib/AltosEepromLog.java b/altoslib/AltosEepromLog.java index 8d1f3fc4..ba722b89 100644 --- a/altoslib/AltosEepromLog.java +++ b/altoslib/AltosEepromLog.java @@ -18,6 +18,7 @@ package org.altusmetrum.altoslib_12; +import java.io.*; import java.text.*; import java.util.concurrent.*; @@ -32,7 +33,15 @@ public class AltosEepromLog { public int start_block; public int end_block; - public boolean selected; + public boolean download_selected; + public boolean delete_selected; + public boolean graph_selected; + + public File file; + + public void set_file(File file) { + this.file = file; + } public AltosEepromLog(AltosConfigData config_data, AltosLink link, @@ -50,8 +59,11 @@ public class AltosEepromLog { serial = config_data.serial; /* - * Select all flights for download + * Select all flights for download and graph, but not + * for delete */ - selected = true; + download_selected = true; + delete_selected = false; + graph_selected = true; } } diff --git a/altoslib/AltosEepromMonitor.java b/altoslib/AltosEepromMonitor.java index a99ec687..11144a3a 100644 --- a/altoslib/AltosEepromMonitor.java +++ b/altoslib/AltosEepromMonitor.java @@ -18,6 +18,8 @@ package org.altusmetrum.altoslib_12; +import java.io.*; + public interface AltosEepromMonitor { public void set_block(int in_block); @@ -28,8 +30,6 @@ public interface AltosEepromMonitor { public void set_flight(int in_flight); - public void set_filename(String in_file); - public void set_thread(Thread eeprom_thread); final static int INFO_MESSAGE = 0; @@ -38,6 +38,8 @@ public interface AltosEepromMonitor { public void show_message(String message, String title, int message_type); + public Boolean check_overwrite(File file); + public void start(); public void done(boolean success); diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java index 12519e6b..43e8ea4d 100644 --- a/altoslib/AltosEepromRecord.java +++ b/altoslib/AltosEepromRecord.java @@ -50,8 +50,22 @@ public abstract class AltosEepromRecord implements Comparable return data8(i) | (data8(i+1) << 8) | (data8(i+2) << 16) | (data8(i+3) << 24); } + public boolean empty(int s) { + for (int i = 0; i < length; i++) + if (eeprom.data8(s + i) != 0xff) + return false; + return true; + } + public boolean valid(int s) { - return AltosConvert.checksum(eeprom.data, s, length) == 0; + int ck = AltosConvert.checksum(eeprom.data, s, length); + + if (ck != 0) { + ++eeprom.errors; + System.out.printf("invalid checksum 0x%x at 0x%x\n", ck, s); + return false; + } + return true; } public boolean valid() { @@ -100,25 +114,18 @@ public abstract class AltosEepromRecord implements Comparable int s = start + length; while (s + length <= eeprom.data.size()) { - if (valid(s)) + if (!empty(s) && valid(s)) return s; s += length; } return -1; } - public boolean hasNext() { - return next_start() >= 0; - } - public abstract AltosEepromRecord next(); public AltosEepromRecord(AltosEeprom eeprom, int start, int length) { this.eeprom = eeprom; this.start = start; this.length = length; - - while (start + length < eeprom.data.size() && !valid()) - start += length; } } diff --git a/altoslib/AltosEepromRecordSet.java b/altoslib/AltosEepromRecordSet.java index d91ae3ac..82a5ea2a 100644 --- a/altoslib/AltosEepromRecordSet.java +++ b/altoslib/AltosEepromRecordSet.java @@ -97,7 +97,7 @@ public class AltosEepromRecordSet implements AltosRecordSet { int tick = 0; boolean first = true; - for (;;) { + do { int t = record.tick(); if (first) { @@ -110,10 +110,8 @@ public class AltosEepromRecordSet implements AltosRecordSet { } record.wide_tick = tick; ordered.add(record); - if (!record.hasNext()) - break; record = record.next(); - } + } while (record != null); } public AltosEepromRecordSet(InputStream input) throws IOException { diff --git a/altoslib/AltosFile.java b/altoslib/AltosFile.java index 69f779c1..6f98b87a 100644 --- a/altoslib/AltosFile.java +++ b/altoslib/AltosFile.java @@ -36,10 +36,23 @@ public class AltosFile extends File { return String.format("-via-%04d", receiver); } + static private String label(int flight) { + if (flight < 0) + return "corrupt"; + else + return "flight"; + } + + static private int flight(int flight) { + if (flight < 0) + return -flight; + return flight; + } + public AltosFile(int year, int month, int day, int serial, int flight, int receiver, String extension) { super (AltosPreferences.logdir(), - String.format("%04d-%02d-%02d-serial-%s-flight-%s%s.%s", - year, month, day, number(serial), number(flight), receiver(receiver), extension)); + String.format("%04d-%02d-%02d-serial-%s-%s-%s%s.%s", + year, month, day, number(serial), label(flight), number(flight(flight)), receiver(receiver), extension)); } public AltosFile(int year, int month, int day, int serial, int flight, String extension) { diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index bc8eaa71..02e49a94 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -26,7 +26,7 @@ import java.util.concurrent.*; import org.altusmetrum.altoslib_12.*; import org.altusmetrum.altosuilib_12.*; -public class AltosUI extends AltosUIFrame { +public class AltosUI extends AltosUIFrame implements AltosEepromGrapher { public AltosVoice voice = new AltosVoice(); public static boolean load_library(Frame frame) { @@ -320,8 +320,17 @@ public class AltosUI extends AltosUIFrame { /* Connect to TeleMetrum, either directly or through * a TeleDongle over the packet link */ + + public void graph_flights(AltosEepromList flights) { + for (AltosEepromLog flight : flights) { + if (flight.graph_selected && flight.file != null) { + process_graph(flight.file); + } + } + } + private void SaveFlightData() { - new AltosEepromManage(AltosUI.this, AltosLib.product_any); + new AltosEepromManage(this, this, AltosLib.product_any); } private static AltosFlightSeries make_series(AltosRecordSet set) { diff --git a/altosuilib/AltosEepromDelete.java b/altosuilib/AltosEepromDelete.java index 87e80a51..d7dde6df 100644 --- a/altosuilib/AltosEepromDelete.java +++ b/altosuilib/AltosEepromDelete.java @@ -84,7 +84,7 @@ public class AltosEepromDelete implements Runnable { serial_line.start_remote(); for (AltosEepromLog log : flights) { - if (log.selected) { + if (log.delete_selected) { DeleteLog(log); } } diff --git a/altosuilib/AltosEepromManage.java b/altosuilib/AltosEepromManage.java index 93827139..1adf1f0a 100644 --- a/altosuilib/AltosEepromManage.java +++ b/altosuilib/AltosEepromManage.java @@ -33,6 +33,7 @@ public class AltosEepromManage implements ActionListener { AltosEepromList flights; AltosEepromDownload download; AltosEepromDelete delete; + AltosEepromGrapher grapher; public void finish() { if (serial_line != null) { @@ -48,7 +49,7 @@ public class AltosEepromManage implements ActionListener { private int countDeletedFlights() { int count = 0; for (AltosEepromLog flight : flights) { - if (flight.selected) + if (flight.delete_selected) count++; } return count; @@ -58,7 +59,7 @@ public class AltosEepromManage implements ActionListener { String result = ""; for (AltosEepromLog flight : flights) { - if (flight.selected) { + if (flight.delete_selected) { if (result.equals("")) result = String.format("%d", flight.flight); else @@ -68,38 +69,49 @@ public class AltosEepromManage implements ActionListener { return result; } - public boolean download_done() { - AltosEepromSelect select = new AltosEepromSelect(frame, flights, "Delete"); - - if (select.run()) { - boolean any_selected = false; - for (AltosEepromLog flight : flights) - any_selected = any_selected || flight.selected; - if (any_selected) { - delete = new AltosEepromDelete(frame, - serial_line, - remote, - flights); - delete.addActionListener(this); - /* - * Start flight log delete - */ - - delete.start(); - return true; - } + public boolean delete_start() { + + boolean any_selected = false; + for (AltosEepromLog flight : flights) + any_selected = any_selected || flight.delete_selected; + if (any_selected) { + delete = new AltosEepromDelete(frame, + serial_line, + remote, + flights); + delete.addActionListener(this); + /* + * Start flight log delete + */ + + delete.start(); + return true; } return false; } + public void graph_start() { + boolean any_selected = false; + for (AltosEepromLog flight : flights) { + if (!flight.download_selected) + flight.graph_selected = false; + any_selected = any_selected || flight.graph_selected; + } + if (any_selected && grapher != null) + grapher.graph_flights(flights); + } + public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); boolean success = e.getID() != 0; boolean running = false; if (cmd.equals("download")) { - if (success) - running = download_done(); + if (success) { + running = delete_start(); + if (!running) + graph_start(); + } } else if (cmd.equals("delete")) { if (success) { JOptionPane.showMessageDialog(frame, @@ -108,6 +120,7 @@ public class AltosEepromManage implements ActionListener { showDeletedFlights()), serial_line.device.toShortString(), JOptionPane.INFORMATION_MESSAGE); + graph_start(); } } if (!running) @@ -126,12 +139,12 @@ public class AltosEepromManage implements ActionListener { serial_line.device.toShortString(), JOptionPane.INFORMATION_MESSAGE); } else { - AltosEepromSelect select = new AltosEepromSelect(frame, flights, "Download"); + AltosEepromSelect select = new AltosEepromSelect(frame, flights, grapher != null); if (select.run()) { boolean any_selected = false; for (AltosEepromLog flight : flights) - any_selected = any_selected || flight.selected; + any_selected = any_selected || flight.download_selected; if (any_selected) { AltosEepromMonitorUI monitor = new AltosEepromMonitorUI(frame); monitor.addActionListener(this); @@ -147,7 +160,9 @@ public class AltosEepromManage implements ActionListener { download.start(); running = true; } else { - running = download_done(); + running = delete_start(); + if (!running) + graph_start(); } } } @@ -205,11 +220,12 @@ public class AltosEepromManage implements ActionListener { } } - public AltosEepromManage(JFrame given_frame, int product) { + public AltosEepromManage(JFrame given_frame, AltosEepromGrapher grapher, int product) { //boolean running = false; frame = given_frame; + this.grapher = grapher; device = AltosDeviceUIDialog.show(frame, product); remote = false; diff --git a/altosuilib/AltosEepromMonitorUI.java b/altosuilib/AltosEepromMonitorUI.java index 3427fe0f..fc6c95c6 100644 --- a/altosuilib/AltosEepromMonitorUI.java +++ b/altosuilib/AltosEepromMonitorUI.java @@ -18,11 +18,18 @@ package org.altusmetrum.altosuilib_12; +import java.io.*; +import java.util.*; +import java.util.concurrent.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import org.altusmetrum.altoslib_12.*; + class result_holder { + static int result; + } + public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMonitor { JFrame owner; Container pane; @@ -32,7 +39,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo JLabel file_label; JLabel serial_value; JLabel flight_value; - JLabel file_value; JButton cancel; JProgressBar pbar; ActionListener listener; @@ -42,6 +48,8 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo public AltosEepromMonitorUI(JFrame owner) { super (owner, "Download Flight Data", false); + setMinimumSize(new Dimension(600, 100)); + this.owner = owner; GridBagConstraints c; @@ -85,30 +93,11 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo flight_value = new JLabel(""); pane.add(flight_value, c); - c = new GridBagConstraints(); - c.fill = GridBagConstraints.NONE; - c.gridx = 0; c.gridy = 2; - c.anchor = GridBagConstraints.LINE_START; - c.insets = il; - file_label = new JLabel("File:"); - pane.add(file_label, c); - - c = new GridBagConstraints(); - c.fill = GridBagConstraints.HORIZONTAL; - c.weightx = 1; - c.gridx = 1; c.gridy = 2; - c.anchor = GridBagConstraints.LINE_START; - c.insets = ir; - file_value = new JLabel(""); - pane.add(file_value, c); - pbar = new JProgressBar(); pbar.setMinimum(0); pbar.setMaximum(progress_max); - pbar.setValue(0); - pbar.setString("startup"); pbar.setStringPainted(true); - pbar.setPreferredSize(new Dimension(600, 20)); + set_block_internal(0); c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.CENTER; @@ -118,7 +107,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo c.insets = ib; pane.add(pbar, c); - cancel = new JButton("Cancel"); c = new GridBagConstraints(); c.fill = GridBagConstraints.NONE; @@ -141,8 +129,9 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo final Thread eeprom_thread = in_eeprom_thread; cancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - if (eeprom_thread != null) + if (eeprom_thread != null) { eeprom_thread.interrupt(); + } } }); } @@ -162,6 +151,7 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo s = String.format("block %d of %d", block, max_block); pbar.setString(s); + pbar.setStringPainted(true); pbar.setValue((int) (pos * progress_max)); } @@ -216,23 +206,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo SwingUtilities.invokeLater(r); } - private void set_filename_internal(String filename) { - file_value.setText(String.format("%s", filename)); - } - - public void set_filename(String in_filename) { - final String filename = in_filename; - Runnable r = new Runnable() { - public void run() { - try { - set_filename_internal(filename); - } catch (Exception ex) { - } - } - }; - SwingUtilities.invokeLater(r); - } - private void done_internal(boolean success) { listener.actionPerformed(new ActionEvent(this, success ? 1 : 0, @@ -258,7 +231,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo set_max(1); set_block_internal(0); set_flight_internal(0); - set_filename_internal(""); } public void reset() { @@ -293,6 +265,29 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo joption_message_type); } + public Boolean check_overwrite(File in_file) { + final Semaphore check_overwrite_done = new Semaphore(0); + final File file = in_file; + final result_holder result = new result_holder(); + + Runnable r = new Runnable() { + public void run() { + result_holder.result = JOptionPane.showConfirmDialog(owner, + String.format("\"%s\" already exists, overwrite?", + file.toString()), + "Overwrite Existing File?", + JOptionPane.YES_NO_OPTION); + check_overwrite_done.release(); + } + }; + + SwingUtilities.invokeLater(r); + try { + check_overwrite_done.acquire(); + } catch (Exception e) {} + return result_holder.result == JOptionPane.YES_OPTION; + } + public void show_message(String in_message, String in_title, int in_message_type) { final String message = in_message; final String title = in_title; diff --git a/altosuilib/AltosEepromSelect.java b/altosuilib/AltosEepromSelect.java index 0c890c8b..f88f2bd6 100644 --- a/altosuilib/AltosEepromSelect.java +++ b/altosuilib/AltosEepromSelect.java @@ -27,23 +27,35 @@ import org.altusmetrum.altoslib_12.*; class AltosEepromItem implements ActionListener { AltosEepromLog log; JLabel label; - JCheckBox action; + JCheckBox download; JCheckBox delete; + JCheckBox graph; public void actionPerformed(ActionEvent e) { - log.selected = action.isSelected(); + log.download_selected = download.isSelected(); + log.delete_selected = delete.isSelected(); + log.graph_selected = graph.isSelected(); } public AltosEepromItem(AltosEepromLog in_log) { log = in_log; String text; - text = String.format("Flight #%02d", log.flight); + if (log.flight >= 0) + text = String.format("Flight #%02d", log.flight); + else + text = String.format("Corrupt #%02d", -log.flight); label = new JLabel(text); - action = new JCheckBox("", log.selected); - action.addActionListener(this); + download = new JCheckBox("", log.download_selected); + download.addActionListener(this); + + delete = new JCheckBox("", log.delete_selected); + delete.addActionListener(this); + + graph = new JCheckBox("", log.graph_selected); + graph.addActionListener(this); } } @@ -72,7 +84,7 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener { public AltosEepromSelect (JFrame in_frame, AltosEepromList flights, - String action) { + boolean has_graph) { super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true); frame = in_frame; @@ -81,7 +93,7 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener { Container contentPane = getContentPane(); /* First, we create a pane containing the dialog's header/title */ - JLabel selectLabel = new JLabel(String.format ("Select flights to %s", action), SwingConstants.CENTER); + JLabel selectLabel = new JLabel(String.format ("Select flights"), SwingConstants.CENTER); JPanel labelPane = new JPanel(); labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS)); @@ -118,9 +130,31 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener { c.weightx = 0.5; c.anchor = GridBagConstraints.CENTER; c.insets = i; - JLabel downloadHeaderLabel = new JLabel(action); + JLabel downloadHeaderLabel = new JLabel("Download"); flightPane.add(downloadHeaderLabel, c); + /* Delete Header */ + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = 0; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + JLabel deleteHeaderLabel = new JLabel("Delete"); + flightPane.add(deleteHeaderLabel, c); + + if (has_graph) { + /* Graph Header */ + c = new GridBagConstraints(); + c.gridx = 3; c.gridy = 0; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + JLabel graphHeaderLabel = new JLabel("Graph"); + flightPane.add(graphHeaderLabel, c); + } + /* Add the flights to the GridBag */ AltosEepromItem item; int itemNumber = 1; @@ -139,14 +173,34 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener { c.insets = i; flightPane.add(item.label, c); - /* Add action checkbox for the flight */ + /* Add download checkbox for the flight */ c = new GridBagConstraints(); c.gridx = 1; c.gridy = itemNumber; c.fill = GridBagConstraints.NONE; c.weightx = 0.5; c.anchor = GridBagConstraints.CENTER; c.insets = i; - flightPane.add(item.action, c); + flightPane.add(item.download, c); + + /* Add delete checkbox for the flight */ + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = itemNumber; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + flightPane.add(item.delete, c); + + if (has_graph) { + /* Add graph checkbox for the flight */ + c = new GridBagConstraints(); + c.gridx = 3; c.gridy = itemNumber; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + flightPane.add(item.graph, c); + } itemNumber++; } diff --git a/telegps/TeleGPS.java b/telegps/TeleGPS.java index 3646f000..1433c9e1 100644 --- a/telegps/TeleGPS.java +++ b/telegps/TeleGPS.java @@ -30,7 +30,7 @@ import org.altusmetrum.altosuilib_12.*; public class TeleGPS extends AltosUIFrame - implements AltosFlightDisplay, AltosFontListener, AltosUnitsListener, ActionListener + implements AltosFlightDisplay, AltosFontListener, AltosUnitsListener, ActionListener, AltosEepromGrapher { static String[] telegps_icon_names = { @@ -280,7 +280,7 @@ public class TeleGPS } void download(){ - new AltosEepromManage(this, AltosLib.product_telegps); + new AltosEepromManage(this, this, AltosLib.product_telegps); } void configure() { @@ -316,6 +316,21 @@ public class TeleGPS } } + public void graph_flights(AltosEepromList list) { + for (AltosEepromLog log : list) { + if (log.file != null) { + AltosRecordSet set = record_set(log.file); + if (set != null) { + try { + new TeleGPSGraphUI(set, log.file); + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + } + } + } + } + void flash() { AltosFlashUI.show(this); } -- cgit v1.2.3 From b986a12b478a6d4ff550786d24aa8628dc0abe32 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Dec 2017 15:59:17 -0600 Subject: altoslib: Add support for TeleMega v3.0 log files These look much like TeleMega v2.0 log files, except that the mag sensor data now comes from the mpu9250 instead of an external hmc5883. The gyro and 3-axis accel data from the mpu9250 are the same as the mpu6000. Signed-off-by: Keith Packard --- altoslib/AltosEepromRecordMega.java | 3 +++ altoslib/AltosEepromRecordSet.java | 1 + altoslib/AltosLib.java | 1 + 3 files changed, 5 insertions(+) (limited to 'altoslib') diff --git a/altoslib/AltosEepromRecordMega.java b/altoslib/AltosEepromRecordMega.java index ea5aff5c..86343fe0 100644 --- a/altoslib/AltosEepromRecordMega.java +++ b/altoslib/AltosEepromRecordMega.java @@ -31,6 +31,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord { private int ground_roll() { switch (log_format) { case AltosLib.AO_LOG_FORMAT_TELEMEGA: + case AltosLib.AO_LOG_FORMAT_TELEMEGA_3: return data32(16); case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD: return data16(14); @@ -41,6 +42,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord { private int ground_pitch() { switch (log_format) { case AltosLib.AO_LOG_FORMAT_TELEMEGA: + case AltosLib.AO_LOG_FORMAT_TELEMEGA_3: return data32(20); case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD: return data16(16); @@ -51,6 +53,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord { private int ground_yaw() { switch (log_format) { case AltosLib.AO_LOG_FORMAT_TELEMEGA: + case AltosLib.AO_LOG_FORMAT_TELEMEGA_3: return data32(24); case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD: return data16(18); diff --git a/altoslib/AltosEepromRecordSet.java b/altoslib/AltosEepromRecordSet.java index 82a5ea2a..36075931 100644 --- a/altoslib/AltosEepromRecordSet.java +++ b/altoslib/AltosEepromRecordSet.java @@ -69,6 +69,7 @@ public class AltosEepromRecordSet implements AltosRecordSet { case AltosLib.AO_LOG_FORMAT_TELEMETRY: case AltosLib.AO_LOG_FORMAT_TELESCIENCE: case AltosLib.AO_LOG_FORMAT_TELEMEGA: + case AltosLib.AO_LOG_FORMAT_TELEMEGA_3: case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD: record = new AltosEepromRecordMega(eeprom); break; diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 77b3fcc4..c25a6273 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -363,6 +363,7 @@ public class AltosLib { public static final int AO_LOG_FORMAT_TELEMINI3 = 12; public static final int AO_LOG_FORMAT_TELEFIRETWO = 13; public static final int AO_LOG_FORMAT_EASYMINI2 = 14; + public static final int AO_LOG_FORMAT_TELEMEGA_3 = 15; public static final int AO_LOG_FORMAT_NONE = 127; public static boolean isspace(int c) { -- cgit v1.2.3 From 111622dbcd56c225a9d5ace9f0ef745e62f8a94c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 9 Dec 2017 16:57:35 -0800 Subject: altoslib: Fix 8 to 12 bit conversion for Mega pyro voltage data The conversion was losing the replicated top four bits by shifting by the wrong amount. Signed-off-by: Keith Packard --- altoslib/AltosTelemetryMegaData.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'altoslib') diff --git a/altoslib/AltosTelemetryMegaData.java b/altoslib/AltosTelemetryMegaData.java index 7ef9c637..f5961c8c 100644 --- a/altoslib/AltosTelemetryMegaData.java +++ b/altoslib/AltosTelemetryMegaData.java @@ -24,7 +24,9 @@ public class AltosTelemetryMegaData extends AltosTelemetryStandard { int v_batt() { return int16(6); } int v_pyro() { return int16(8); } - int sense(int i) { int v = uint8(10+i); return v << 4 | v >> 8; } + + /* pyro sense values are sent in 8 bits, expand to 12 bits */ + int sense(int i) { int v = uint8(10+i); return (v << 4) | (v >> 4); } int ground_pres() { return int32(16); } int ground_accel() { return int16(20); } -- cgit v1.2.3 From 2efb997865ee46bf0e8d5145c95d051a7656222a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 11 Dec 2017 14:42:45 -0800 Subject: altoslib: Keep old GPS values when updating data This way, updating satellite information doesn't drop all of the regular GPS data on the floor. Signed-off-by: Keith Packard --- altoslib/AltosCalData.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'altoslib') diff --git a/altoslib/AltosCalData.java b/altoslib/AltosCalData.java index fdea5e21..03e2cbd7 100644 --- a/altoslib/AltosCalData.java +++ b/altoslib/AltosCalData.java @@ -241,6 +241,8 @@ public class AltosCalData { public AltosGPS gps_pad = null; + public AltosGPS prev_gps = null; + public double gps_pad_altitude = AltosLib.MISSING; public void set_cal_gps(AltosGPS gps) { @@ -251,6 +253,7 @@ public class AltosCalData { gps_pad_altitude = gps.alt; } temp_gps = null; + prev_gps = gps; } /* @@ -275,7 +278,7 @@ public class AltosCalData { public AltosGPS make_temp_cal_gps(int tick, boolean sats) { if (temp_gps == null) - temp_gps = new AltosGPS(); + temp_gps = new AltosGPS(prev_gps); if (sats) { if (tick != temp_gps_sat_tick) temp_gps.cc_gps_sat = null; -- cgit v1.2.3