X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=ao-tools%2Faltosui%2FAltosUI.java;h=4915376645d71ca5543d4d87a5e3af8b331cfaf3;hb=6205547ec7191aab0259a8449520e966a96129e6;hp=4f3b5ddeb1c1c2fa68ab8d639135a0c32e18232e;hpb=68967157cee620ebedcc8c2ffd6fc7656532087b;p=fw%2Faltos diff --git a/ao-tools/altosui/AltosUI.java b/ao-tools/altosui/AltosUI.java index 4f3b5dde..49153766 100644 --- a/ao-tools/altosui/AltosUI.java +++ b/ao-tools/altosui/AltosUI.java @@ -44,6 +44,7 @@ import altosui.AltosChannelMenu; import altosui.AltosFlashUI; import altosui.AltosLogfileChooser; import altosui.AltosCSVUI; +import altosui.AltosLine; import libaltosJNI.*; @@ -74,6 +75,10 @@ public class AltosUI extends JFrame { String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" }; Object[][] statusData = { { "0", "pad", "-50", "0" } }; + java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg"); + if (imgURL != null) + setIconImage(new ImageIcon(imgURL).getImage()); + AltosPreferences.init(this); vbox = Box.createVerticalBox(); @@ -168,21 +173,19 @@ public class AltosUI extends JFrame { flightInfoModel[i].finish(); } - public void show(AltosState state) { + public void show(AltosState state, int crc_errors) { + if (state == null) + return; flightStatusModel.set(state); info_reset(); - if (state.gps_ready) - info_add_row(0, "Ground state", "%s", "ready"); - else - info_add_row(0, "Ground state", "wait (%d)", - state.gps_waiting); info_add_row(0, "Rocket state", "%s", state.data.state()); info_add_row(0, "Callsign", "%s", state.data.callsign); info_add_row(0, "Rocket serial", "%6d", state.data.serial); info_add_row(0, "Rocket flight", "%6d", state.data.flight); info_add_row(0, "RSSI", "%6d dBm", state.data.rssi); + info_add_row(0, "CRC Errors", "%6d", crc_errors); info_add_row(0, "Height", "%6.0f m", state.height); info_add_row(0, "Max height", "%6.0f m", state.max_height); info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration); @@ -197,6 +200,11 @@ public class AltosUI extends JFrame { if (state.gps == null) { info_add_row(1, "GPS", "not available"); } else { + if (state.gps_ready) + info_add_row(1, "GPS state", "%s", "ready"); + else + info_add_row(1, "GPS state", "wait (%d)", + state.gps_waiting); if (state.data.gps.locked) info_add_row(1, "GPS", " locked"); else if (state.data.gps.connected) @@ -223,11 +231,19 @@ public class AltosUI extends JFrame { if (state.npad > 0) { if (state.from_pad != null) { - info_add_row(1, "Distance from pad", "%6.0f m", state.from_pad.distance); - info_add_row(1, "Direction from pad", "%6.0f°", state.from_pad.bearing); + info_add_row(1, "Distance from pad", "%6d m", + (int) (state.from_pad.distance + 0.5)); + info_add_row(1, "Direction from pad", "%6d°", + (int) (state.from_pad.bearing + 0.5)); + info_add_row(1, "Elevation from pad", "%6d°", + (int) (state.elevation + 0.5)); + info_add_row(1, "Range from pad", "%6d m", + (int) (state.range + 0.5)); } else { info_add_row(1, "Distance from pad", "unknown"); info_add_row(1, "Direction from pad", "unknown"); + info_add_row(1, "Elevation from pad", "unknown"); + info_add_row(1, "Range from pad", "unknown"); } info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S'); info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W'); @@ -264,7 +280,7 @@ public class AltosUI extends JFrame { private AltosState state; int reported_landing; - public void report(boolean last) { + public synchronized void report(boolean last) { if (state == null) return; @@ -278,7 +294,16 @@ public class AltosUI extends JFrame { } /* If the rocket isn't on the pad, then report height */ - if (state.state > Altos.ao_flight_pad) { + if (Altos.ao_flight_drogue <= state.state && + state.state < Altos.ao_flight_landed && + state.range >= 0) + { + voice.speak("Height %d, bearing %d, elevation %d, range %d.\n", + (int) (state.height + 0.5), + (int) (state.from_pad.bearing + 0.5), + (int) (state.elevation + 0.5), + (int) (state.range + 0.5)); + } else if (state.state > Altos.ao_flight_pad) { voice.speak("%d meters", (int) (state.height + 0.5)); } else { reported_landing = 0; @@ -288,7 +313,7 @@ public class AltosUI extends JFrame { * either we've got a landed report or we haven't heard from it in * a long time */ - if (!state.ascent && + if (state.state >= Altos.ao_flight_drogue && (last || System.currentTimeMillis() - state.report_time >= 15000 || state.state == Altos.ao_flight_landed)) @@ -298,7 +323,7 @@ public class AltosUI extends JFrame { else voice.speak("rocket may have crashed"); if (state.from_pad != null) - voice.speak("bearing %d degrees, range %d meters", + voice.speak("Bearing %d degrees, range %d meters.", (int) (state.from_pad.bearing + 0.5), (int) (state.from_pad.distance + 0.5)); ++reported_landing; @@ -311,7 +336,7 @@ public class AltosUI extends JFrame { state = null; try { for (;;) { - Thread.sleep(10000); + Thread.sleep(20000); report(false); } } catch (InterruptedException ie) { @@ -319,7 +344,10 @@ public class AltosUI extends JFrame { } public void notice(AltosState new_state) { + AltosState old_state = state; state = new_state; + if (old_state != null && old_state.state != state.state) + report(false); } } @@ -350,13 +378,18 @@ public class AltosUI extends JFrame { String name; - AltosRecord read() throws InterruptedException, ParseException { return null; } + int crc_errors; + + void init() { } - void close() { } + AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } + + void close(boolean interrupted) { } void update(AltosState state) throws InterruptedException { } public void run() { + boolean interrupted = false; String line; AltosState state = null; AltosState old_state = null; @@ -375,17 +408,29 @@ public class AltosUI extends JFrame { old_state = state; state = new AltosState(record, state); update(state); - show(state); + show(state, crc_errors); tell(state, old_state); idle_thread.notice(state); } catch (ParseException pp) { System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); + } catch (AltosCRCException ce) { + ++crc_errors; + show(state, crc_errors); } } } catch (InterruptedException ee) { + interrupted = true; + } catch (IOException ie) { + JOptionPane.showMessageDialog(AltosUI.this, + String.format("Error reading from \"%s\"", name), + "Telemetry Read Error", + JOptionPane.ERROR_MESSAGE); } finally { - close(); + close(interrupted); idle_thread.interrupt(); + try { + idle_thread.join(); + } catch (InterruptedException ie) {} } } @@ -397,22 +442,25 @@ public class AltosUI extends JFrame { class DeviceThread extends DisplayThread { AltosSerial serial; - LinkedBlockingQueue telem; + LinkedBlockingQueue telem; - AltosRecord read() throws InterruptedException, ParseException { - return new AltosTelemetry(telem.take()); + AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { + AltosLine l = telem.take(); + if (l.line == null) + throw new IOException("IO error"); + return new AltosTelemetry(l.line); } - void close() { + void close(boolean interrupted) { serial.close(); serial.remove_monitor(telem); } - public DeviceThread(AltosSerial s) { + public DeviceThread(AltosSerial s, String in_name) { serial = s; - telem = new LinkedBlockingQueue(); + telem = new LinkedBlockingQueue(); serial.add_monitor(telem); - name = "telemetry"; + name = in_name; } } @@ -421,8 +469,9 @@ public class AltosUI extends JFrame { if (device != null) { try { + stop_display(); serial_line.open(device); - DeviceThread thread = new DeviceThread(serial_line); + DeviceThread thread = new DeviceThread(serial_line, device.getPath()); serial_line.set_channel(AltosPreferences.channel()); serial_line.set_callsign(AltosPreferences.callsign()); run_display(thread); @@ -486,8 +535,9 @@ public class AltosUI extends JFrame { return null; } - public void close () { - report(); + public void close (boolean interrupted) { + if (!interrupted) + report(); } public ReplayThread(AltosReader in_reader, String in_name) { @@ -516,8 +566,12 @@ public class AltosUI extends JFrame { Thread display_thread; private void stop_display() { - if (display_thread != null && display_thread.isAlive()) + if (display_thread != null && display_thread.isAlive()) { display_thread.interrupt(); + try { + display_thread.join(); + } catch (InterruptedException ie) {} + } display_thread = null; }