From a7fd31842a602a8ac803d0e09efb4ffabf7a289b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 28 May 2014 20:19:44 -0700 Subject: telegps: Add device configuration dialogs Signed-off-by: Keith Packard --- telegps/TeleGPSConfig.java | 291 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 telegps/TeleGPSConfig.java (limited to 'telegps/TeleGPSConfig.java') diff --git a/telegps/TeleGPSConfig.java b/telegps/TeleGPSConfig.java new file mode 100644 index 00000000..ffb2d612 --- /dev/null +++ b/telegps/TeleGPSConfig.java @@ -0,0 +1,291 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.telegps; + +import java.awt.event.*; +import javax.swing.*; +import java.io.*; +import java.util.concurrent.*; +import java.text.*; +import org.altusmetrum.altoslib_4.*; +import org.altusmetrum.altosuilib_2.*; + +public class TeleGPSConfig implements ActionListener { + + class int_ref { + int value; + + public int get() { + return value; + } + public void set(int i) { + value = i; + } + public int_ref(int i) { + value = i; + } + } + + class string_ref { + String value; + + public String get() { + return value; + } + public void set(String i) { + value = i; + } + public string_ref(String i) { + value = i; + } + } + + JFrame owner; + AltosDevice device; + AltosSerial serial_line; + + AltosConfigData data; + TeleGPSConfigUI config_ui; + boolean serial_started; + boolean made_visible; + + void start_serial() throws InterruptedException, TimeoutException { + serial_started = true; + } + + void stop_serial() throws InterruptedException { + if (!serial_started) + return; + serial_started = false; + } + + void update_ui() { + data.set_values(config_ui); + config_ui.set_clean(); + if (!made_visible) { + made_visible = true; + config_ui.make_visible(); + } + } + + int pyro; + + final static int serial_mode_read = 0; + final static int serial_mode_save = 1; + final static int serial_mode_reboot = 2; + + class SerialData implements Runnable { + TeleGPSConfig config; + int serial_mode; + + void callback(String in_cmd) { + final String cmd = in_cmd; + Runnable r = new Runnable() { + public void run() { + if (cmd.equals("abort")) { + abort(); + } else if (cmd.equals("all finished")) { + if (serial_line != null) + update_ui(); + } + } + }; + SwingUtilities.invokeLater(r); + } + + void get_data() { + data = null; + try { + start_serial(); + data = new AltosConfigData(config.serial_line); + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + try { + stop_serial(); + callback("abort"); + } catch (InterruptedException ie) { + } + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + callback("all finished"); + } + + void save_data() { + try { + start_serial(); + data.save(serial_line, false); + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + } + + void reboot() { + try { + start_serial(); + serial_line.printf("r eboot\n"); + serial_line.flush_output(); + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + } finally { + try { + stop_serial(); + serial_line.close(); + } catch (InterruptedException ie) { + } + } + } + + public void run () { + switch (serial_mode) { + case serial_mode_save: + save_data(); + /* fall through ... */ + case serial_mode_read: + get_data(); + break; + case serial_mode_reboot: + reboot(); + break; + } + } + + public SerialData(TeleGPSConfig in_config, int in_serial_mode) { + config = in_config; + serial_mode = in_serial_mode; + } + } + + void run_serial_thread(int serial_mode) { + SerialData sd = new SerialData(this, serial_mode); + Thread st = new Thread(sd); + st.start(); + } + + void init_ui () throws InterruptedException, TimeoutException { + config_ui = new TeleGPSConfigUI(owner); + config_ui.addActionListener(this); + serial_line.set_frame(owner); + set_ui(); + } + + void abort() { + if (serial_line != null) { + serial_line.close(); + serial_line = null; + } + JOptionPane.showMessageDialog(owner, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + config_ui.setVisible(false); + } + + void set_ui() throws InterruptedException, TimeoutException { + if (serial_line != null) + run_serial_thread(serial_mode_read); + else + update_ui(); + } + + double frequency() { + return AltosConvert.radio_to_frequency(data.radio_frequency, + data.radio_setting, + data.radio_calibration, + data.radio_channel); + } + + void save_data() { + + /* bounds check stuff */ + if (config_ui.flight_log_max() > data.log_limit()) { + JOptionPane.showMessageDialog(owner, + String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", + config_ui.flight_log_max(), + data.log_limit()), + "Maximum Flight Log Too Large", + JOptionPane.ERROR_MESSAGE); + return; + } + + /* Pull data out of the UI and stuff back into our local data record */ + + data.get_values(config_ui); + + run_serial_thread(serial_mode_save); + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + try { + if (cmd.equals("Save")) { + save_data(); + } else if (cmd.equals("Reset")) { + set_ui(); + } else if (cmd.equals("Reboot")) { + if (serial_line != null) + run_serial_thread(serial_mode_reboot); + } else if (cmd.equals("Close")) { + if (serial_line != null) + serial_line.close(); + } + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } + } + + public TeleGPSConfig(JFrame given_owner) { + owner = given_owner; + + device = AltosDeviceUIDialog.show(owner, AltosLib.product_telegps); + if (device != null) { + try { + serial_line = new AltosSerial(device); + try { + init_ui(); + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(owner, + ee.getMessage(), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } + } + } +} -- cgit v1.2.3 From cd2179cb0d71749f3637cc3ee03ccc6adfd74aae Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jun 2014 22:59:23 -0700 Subject: telegps: Trap AltosConfigDataException in telegps config This was added for pyro configuration errors in AltosUI Signed-off-by: Keith Packard --- telegps/TeleGPSConfig.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'telegps/TeleGPSConfig.java') diff --git a/telegps/TeleGPSConfig.java b/telegps/TeleGPSConfig.java index ffb2d612..22e6a3ac 100644 --- a/telegps/TeleGPSConfig.java +++ b/telegps/TeleGPSConfig.java @@ -234,9 +234,15 @@ public class TeleGPSConfig implements ActionListener { /* Pull data out of the UI and stuff back into our local data record */ - data.get_values(config_ui); - - run_serial_thread(serial_mode_save); + try { + data.get_values(config_ui); + run_serial_thread(serial_mode_save); + } catch (AltosConfigDataException ae) { + JOptionPane.showMessageDialog(owner, + ae.getMessage(), + "Configuration Data Error", + JOptionPane.ERROR_MESSAGE); + } } public void actionPerformed(ActionEvent e) { -- cgit v1.2.3 From ae1174317fc476e39077f7dc257ec08709c6b301 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jun 2014 10:11:03 -0700 Subject: altoslib/altosui/telegps: Change log size configuration * Use new log-space value provided by firmware when available. * Divide that up into 1-8 flights and offer those sizes as options to the user instead of a fixed set of sizes. * Show how many flights each selection will store * This also checks values provided by the user Signed-off-by: Keith Packard --- altoslib/AltosConfigData.java | 38 ++++--- altosui/AltosConfig.java | 24 ++--- altosui/AltosConfigUI.java | 72 ++++++++----- telegps/Makefile.am | 3 +- telegps/TeleGPS.java | 4 +- telegps/TeleGPSConfig.java | 24 ++--- telegps/TeleGPSConfigUI.java | 64 +++++++----- telegps/TeleGPSDisplayThread.java | 209 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 345 insertions(+), 93 deletions(-) create mode 100644 telegps/TeleGPSDisplayThread.java (limited to 'telegps/TeleGPSConfig.java') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 9292a5a2..9462ae6f 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -29,6 +29,7 @@ public class AltosConfigData implements Iterable { public int serial; public int flight; public int log_format; + public int log_space; public String version; /* Strings returned */ @@ -124,6 +125,22 @@ public class AltosConfigData implements Iterable { return lines.iterator(); } + public int log_space() { + if (log_space > 0) + return log_space; + + if (storage_size > 0) { + int space = storage_size; + + if (storage_erase_unit > 0 && use_flash_for_config()) + space -= storage_erase_unit; + + if (space > 0) + return space; + } + return 0; + } + public int log_available() { switch (log_format) { case AltosLib.AO_LOG_FORMAT_TINY: @@ -137,7 +154,7 @@ public class AltosConfigData implements Iterable { if (flight_log_max <= 0) return 1; int log_max = flight_log_max * 1024; - int log_space = storage_size - storage_erase_unit; + int log_space = log_space(); int log_used; if (stored_flight <= 0) @@ -202,6 +219,7 @@ public class AltosConfigData implements Iterable { serial = 0; flight = 0; log_format = AltosLib.AO_LOG_FORMAT_UNKNOWN; + log_space = -1; version = "unknown"; main_deploy = -1; @@ -247,6 +265,7 @@ public class AltosConfigData implements Iterable { try { serial = get_int(line, "serial-number"); } catch (Exception e) {} try { flight = get_int(line, "current-flight"); } catch (Exception e) {} try { log_format = get_int(line, "log-format"); } catch (Exception e) {} + try { log_space = get_int(line, "log-space"); } catch (Exception e) {} try { version = get_string(line, "software-version"); } catch (Exception e) {} /* Version also contains MS5607 info, which we ignore here */ @@ -390,19 +409,6 @@ public class AltosConfigData implements Iterable { } - public int log_limit() { - if (storage_size > 0) { - int log_limit = storage_size; - - if (storage_erase_unit > 0 && use_flash_for_config()) - log_limit -= storage_erase_unit; - - if (log_limit > 0) - return log_limit / 1024; - } - return 1024; - } - public void get_values(AltosConfigValues source) throws AltosConfigDataException { /* HAS_FLIGHT */ @@ -462,7 +468,7 @@ public class AltosConfigData implements Iterable { dest.set_radio_frequency(frequency()); boolean max_enabled = true; - if (log_limit() == 0) + if (log_space() == 0) max_enabled = false; switch (log_format) { @@ -477,7 +483,7 @@ public class AltosConfigData implements Iterable { dest.set_flight_log_max_enabled(max_enabled); dest.set_radio_enable(radio_enable); - dest.set_flight_log_max_limit(log_limit()); + dest.set_flight_log_max_limit(log_space() / 1024); dest.set_flight_log_max(flight_log_max); dest.set_ignite_mode(ignite_mode); dest.set_pad_orientation(pad_orientation); diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 2cf69525..6eb7d40c 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -229,20 +229,20 @@ public class AltosConfig implements ActionListener { void save_data() { - /* bounds check stuff */ - if (config_ui.flight_log_max() > data.log_limit()) { - JOptionPane.showMessageDialog(owner, - String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", - config_ui.flight_log_max(), - data.log_limit()), - "Maximum Flight Log Too Large", - JOptionPane.ERROR_MESSAGE); - return; - } + try { + /* bounds check stuff */ + if (config_ui.flight_log_max() > data.log_space() / 1024) { + JOptionPane.showMessageDialog(owner, + String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", + config_ui.flight_log_max(), + data.log_space() / 1024), + "Maximum Flight Log Too Large", + JOptionPane.ERROR_MESSAGE); + return; + } - /* Pull data out of the UI and stuff back into our local data record */ + /* Pull data out of the UI and stuff back into our local data record */ - try { data.get_values(config_ui); run_serial_thread(serial_mode_save); } catch (AltosConfigDataException ae) { diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index bcb3e12c..f936d92c 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -99,12 +99,6 @@ public class AltosConfigUI "0", "5", "10", "15", "20" }; - static String[] flight_log_max_values = { - "64", "128", "192", "256", "320", - "384", "448", "512", "576", "640", - "704", "768", "832", "896", "960", - }; - static String[] ignite_mode_values = { "Dual Deploy", "Redundant Apogee", @@ -546,7 +540,7 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = il; c.ipady = 5; - flight_log_max_label = new JLabel("Maximum Flight Log Size:"); + flight_log_max_label = new JLabel("Maximum Flight Log Size (kB):"); pane.add(flight_log_max_label, c); c = new GridBagConstraints(); @@ -557,7 +551,7 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = ir; c.ipady = 5; - flight_log_max_value = new JComboBox(flight_log_max_values); + flight_log_max_value = new JComboBox(); flight_log_max_value.setEditable(true); flight_log_max_value.addItemListener(this); pane.add(flight_log_max_value, c); @@ -918,8 +912,19 @@ public class AltosConfigUI apogee_delay_value.setEnabled(new_apogee_delay >= 0); } - public int apogee_delay() { - return Integer.parseInt(apogee_delay_value.getSelectedItem().toString()); + private int parse_int(String name, String s, boolean split) throws AltosConfigDataException { + String v = s; + if (split) + v = s.split("\\s+")[0]; + try { + return Integer.parseInt(v); + } catch (NumberFormatException ne) { + throw new AltosConfigDataException("Invalid %s \"%s\"", name, s); + } + } + + public int apogee_delay() throws AltosConfigDataException { + return parse_int("apogee delay", apogee_delay_value.getSelectedItem().toString(), false); } public void set_apogee_lockout(int new_apogee_lockout) { @@ -927,8 +932,8 @@ public class AltosConfigUI apogee_lockout_value.setEnabled(new_apogee_lockout >= 0); } - public int apogee_lockout() { - return Integer.parseInt(apogee_lockout_value.getSelectedItem().toString()); + public int apogee_lockout() throws AltosConfigDataException { + return parse_int("apogee lockout", apogee_lockout_value.getSelectedItem().toString(), false); } public void set_radio_frequency(double new_radio_frequency) { @@ -947,8 +952,8 @@ public class AltosConfigUI radio_calibration_value.setText(String.format("%d", new_radio_calibration)); } - public int radio_calibration() { - return Integer.parseInt(radio_calibration_value.getText()); + public int radio_calibration() throws AltosConfigDataException { + return parse_int("radio calibration", radio_calibration_value.getText(), false); } public void set_radio_enable(int new_radio_enable) { @@ -979,8 +984,22 @@ public class AltosConfigUI return callsign_value.getText(); } + int flight_log_max_limit; + int flight_log_max; + + public String flight_log_max_label(int flight_log_max) { + if (flight_log_max_limit != 0) { + int nflight = flight_log_max_limit / flight_log_max; + String plural = nflight > 1 ? "s" : ""; + + return String.format("%d (%d flight%s)", flight_log_max, nflight, plural); + } + return String.format("%d", flight_log_max); + } + public void set_flight_log_max(int new_flight_log_max) { - flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max)); + flight_log_max_value.setSelectedItem(flight_log_max_label(new_flight_log_max)); + flight_log_max = new_flight_log_max; set_flight_log_max_tool_tip(); } @@ -989,20 +1008,19 @@ public class AltosConfigUI set_flight_log_max_tool_tip(); } - public int flight_log_max() { - return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); + public int flight_log_max() throws AltosConfigDataException { + return parse_int("flight log max", flight_log_max_value.getSelectedItem().toString(), true); } - public void set_flight_log_max_limit(int flight_log_max_limit) { - //boolean any_added = false; + public void set_flight_log_max_limit(int new_flight_log_max_limit) { + flight_log_max_limit = new_flight_log_max_limit; flight_log_max_value.removeAllItems(); - for (int i = 0; i < flight_log_max_values.length; i++) { - if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){ - flight_log_max_value.addItem(flight_log_max_values[i]); - //any_added = true; - } + for (int i = 8; i >= 1; i--) { + int size = flight_log_max_limit / i; + flight_log_max_value.addItem(String.format("%d (%d flights)", size, i)); } - flight_log_max_value.addItem(String.format("%d", flight_log_max_limit)); + if (flight_log_max != 0) + set_flight_log_max(flight_log_max); } public void set_ignite_mode(int new_ignite_mode) { @@ -1165,11 +1183,11 @@ public class AltosConfigUI set_aprs_interval_tool_tip(); } - public int aprs_interval() { + public int aprs_interval() throws AltosConfigDataException { String s = aprs_interval_value.getSelectedItem().toString(); if (s.equals("Disabled")) return 0; - return Integer.parseInt(s); + return parse_int("aprs interval", s, false); } } diff --git a/telegps/Makefile.am b/telegps/Makefile.am index 7e17b331..e0d596e7 100644 --- a/telegps/Makefile.am +++ b/telegps/Makefile.am @@ -19,7 +19,8 @@ telegps_JAVA= \ TeleGPSConfig.java \ TeleGPSConfigUI.java \ TeleGPSPreferences.java \ - TeleGPSGraphUI.java + TeleGPSGraphUI.java \ + TeleGPSDisplayThread.java JFREECHART_CLASS= \ jfreechart.jar diff --git a/telegps/TeleGPS.java b/telegps/TeleGPS.java index 71174436..c61b245e 100644 --- a/telegps/TeleGPS.java +++ b/telegps/TeleGPS.java @@ -51,7 +51,7 @@ public class TeleGPS } AltosFlightReader reader; - AltosDisplayThread thread; + TeleGPSDisplayThread thread; JMenuBar menu_bar; @@ -349,7 +349,7 @@ public class TeleGPS public void set_reader(AltosFlightReader reader) { setTitle(String.format("TeleGPS %s", reader.name)); - thread = new AltosDisplayThread(this, voice(), this, reader); + thread = new TeleGPSDisplayThread(this, voice(), this, reader); thread.start(); } diff --git a/telegps/TeleGPSConfig.java b/telegps/TeleGPSConfig.java index 22e6a3ac..3505b0bb 100644 --- a/telegps/TeleGPSConfig.java +++ b/telegps/TeleGPSConfig.java @@ -221,20 +221,20 @@ public class TeleGPSConfig implements ActionListener { void save_data() { - /* bounds check stuff */ - if (config_ui.flight_log_max() > data.log_limit()) { - JOptionPane.showMessageDialog(owner, - String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", - config_ui.flight_log_max(), - data.log_limit()), - "Maximum Flight Log Too Large", - JOptionPane.ERROR_MESSAGE); - return; - } + try { + /* bounds check stuff */ + if (config_ui.flight_log_max() > data.log_space()/1024) { + JOptionPane.showMessageDialog(owner, + String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", + config_ui.flight_log_max(), + data.log_space()/1024), + "Maximum Flight Log Too Large", + JOptionPane.ERROR_MESSAGE); + return; + } - /* Pull data out of the UI and stuff back into our local data record */ + /* Pull data out of the UI and stuff back into our local data record */ - try { data.get_values(config_ui); run_serial_thread(serial_mode_save); } catch (AltosConfigDataException ae) { diff --git a/telegps/TeleGPSConfigUI.java b/telegps/TeleGPSConfigUI.java index 863d61bb..03666036 100644 --- a/telegps/TeleGPSConfigUI.java +++ b/telegps/TeleGPSConfigUI.java @@ -65,12 +65,6 @@ public class TeleGPSConfigUI ActionListener listener; - static String[] flight_log_max_values = { - "64", "128", "192", "256", "320", - "384", "448", "512", "576", "640", - "704", "768", "832", "896", "960", - }; - static String[] aprs_interval_values = { "Disabled", "2", @@ -376,7 +370,7 @@ public class TeleGPSConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = il; c.ipady = 5; - flight_log_max_label = new JLabel("Maximum Flight Log Size:"); + flight_log_max_label = new JLabel("Maximum Log Size (kB):"); pane.add(flight_log_max_label, c); c = new GridBagConstraints(); @@ -387,7 +381,7 @@ public class TeleGPSConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = ir; c.ipady = 5; - flight_log_max_value = new JComboBox(flight_log_max_values); + flight_log_max_value = new JComboBox(); flight_log_max_value.setEditable(true); flight_log_max_value.addItemListener(this); pane.add(flight_log_max_value, c); @@ -636,8 +630,19 @@ public class TeleGPSConfigUI radio_calibration_value.setText(String.format("%d", new_radio_calibration)); } - public int radio_calibration() { - return Integer.parseInt(radio_calibration_value.getText()); + private int parse_int(String name, String s, boolean split) throws AltosConfigDataException { + String v = s; + if (split) + v = s.split("\\s+")[0]; + try { + return Integer.parseInt(v); + } catch (NumberFormatException ne) { + throw new AltosConfigDataException("Invalid %s \"%s\"", name, s); + } + } + + public int radio_calibration() throws AltosConfigDataException { + return parse_int("radio calibration", radio_calibration_value.getText(), false); } public void set_radio_enable(int new_radio_enable) { @@ -668,8 +673,22 @@ public class TeleGPSConfigUI return callsign_value.getText(); } + int flight_log_max_limit; + int flight_log_max; + + public String flight_log_max_label(int flight_log_max) { + if (flight_log_max_limit != 0) { + int nflight = flight_log_max_limit / flight_log_max; + String plural = nflight > 1 ? "s" : ""; + + return String.format("%d (%d flight%s)", flight_log_max, nflight, plural); + } + return String.format("%d", flight_log_max); + } + public void set_flight_log_max(int new_flight_log_max) { - flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max)); + flight_log_max_value.setSelectedItem(flight_log_max_label(new_flight_log_max)); + flight_log_max = new_flight_log_max; set_flight_log_max_tool_tip(); } @@ -678,20 +697,19 @@ public class TeleGPSConfigUI set_flight_log_max_tool_tip(); } - public int flight_log_max() { - return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); + public int flight_log_max() throws AltosConfigDataException { + return parse_int("flight log max", flight_log_max_value.getSelectedItem().toString(), true); } - public void set_flight_log_max_limit(int flight_log_max_limit) { - //boolean any_added = false; + public void set_flight_log_max_limit(int new_flight_log_max_limit) { + flight_log_max_limit = new_flight_log_max_limit; flight_log_max_value.removeAllItems(); - for (int i = 0; i < flight_log_max_values.length; i++) { - if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){ - flight_log_max_value.addItem(flight_log_max_values[i]); - //any_added = true; - } + for (int i = 8; i >= 1; i--) { + int size = flight_log_max_limit / i; + flight_log_max_value.addItem(String.format("%d (%d flights)", size, i)); } - flight_log_max_value.addItem(String.format("%d", flight_log_max_limit)); + if (flight_log_max != 0) + set_flight_log_max(flight_log_max); } public void set_ignite_mode(int new_ignite_mode) { } @@ -791,11 +809,11 @@ public class TeleGPSConfigUI set_aprs_interval_tool_tip(); } - public int aprs_interval() { + public int aprs_interval() throws AltosConfigDataException { String s = aprs_interval_value.getSelectedItem().toString(); if (s.equals("Disabled")) return 0; - return Integer.parseInt(s); + return parse_int("aprs interval", s, false); } } diff --git a/telegps/TeleGPSDisplayThread.java b/telegps/TeleGPSDisplayThread.java new file mode 100644 index 00000000..9de33098 --- /dev/null +++ b/telegps/TeleGPSDisplayThread.java @@ -0,0 +1,209 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.telegps; + +import java.awt.*; +import javax.swing.*; +import java.io.*; +import java.text.*; +import org.altusmetrum.altoslib_4.*; +import org.altusmetrum.altosuilib_2.*; + +public class TeleGPSDisplayThread extends Thread { + + Frame parent; + IdleThread idle_thread; + AltosVoice voice; + AltosFlightReader reader; + AltosState old_state, state; + AltosListenerState listener_state; + AltosFlightDisplay display; + + synchronized void show_safely() { + final AltosState my_state = state; + final AltosListenerState my_listener_state = listener_state; + Runnable r = new Runnable() { + public void run() { + try { + display.show(my_state, my_listener_state); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + void reading_error_internal() { + JOptionPane.showMessageDialog(parent, + String.format("Error reading from \"%s\"", reader.name), + "Telemetry Read Error", + JOptionPane.ERROR_MESSAGE); + } + + void reading_error_safely() { + Runnable r = new Runnable() { + public void run() { + try { + reading_error_internal(); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + class IdleThread extends Thread { + + boolean started; + int report_interval; + long report_time; + + public synchronized void report(boolean last) { + if (state == null) + return; + + if (state.height() != AltosLib.MISSING) { + if (state.from_pad != null) { + voice.speak("Height %s, bearing %s %d, elevation %d, range %s, .\n", + AltosConvert.height.say(state.gps_height()), + state.from_pad.bearing_words( + AltosGreatCircle.BEARING_VOICE), + (int) (state.from_pad.bearing + 0.5), + (int) (state.elevation + 0.5), + AltosConvert.distance.say(state.range)); + } else { + voice.speak("Height %s.\n", + AltosConvert.height.say(state.height())); + } + } else { + voice.speak("Height is unknown.\n"); + } + } + + long now () { + return System.currentTimeMillis(); + } + + void set_report_time() { + report_time = now() + report_interval; + } + + public void run () { + try { + for (;;) { + if (reader.has_monitor_battery()) { + listener_state.battery = reader.monitor_battery(); + show_safely(); + } + set_report_time(); + for (;;) { + voice.drain(); + synchronized (this) { + long sleep_time = report_time - now(); + if (sleep_time <= 0) + break; + wait(sleep_time); + } + } + + report(false); + } + } catch (InterruptedException ie) { + try { + voice.drain(); + } catch (InterruptedException iie) { } + } + } + + public synchronized void notice(boolean spoken) { + if (old_state != null && old_state.state != state.state) { + report_time = now(); + this.notify(); + } else if (spoken) + set_report_time(); + } + + public IdleThread() { + report_interval = 10000; + } + } + + synchronized boolean tell() { + boolean ret = false; + if (old_state == null || old_state.gps_ready != state.gps_ready) { + if (state.gps_ready) { + voice.speak("GPS ready"); + ret = true; + } + else if (old_state != null) { + voice.speak("GPS lost"); + ret = true; + } + } + old_state = state; + return ret; + } + + public void run() { + boolean interrupted = false; + boolean told; + + idle_thread = new IdleThread(); + idle_thread.start(); + + try { + for (;;) { + try { + state = reader.read(); + if (state == null) + break; + reader.update(state); + show_safely(); + told = tell(); + idle_thread.notice(told); + } catch (ParseException pp) { + System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); + } catch (AltosCRCException ce) { + ++listener_state.crc_errors; + show_safely(); + } + } + } catch (InterruptedException ee) { + interrupted = true; + } catch (IOException ie) { + reading_error_safely(); + } finally { + if (!interrupted) + idle_thread.report(true); + reader.close(interrupted); + idle_thread.interrupt(); + try { + idle_thread.join(); + } catch (InterruptedException ie) {} + } + } + + public TeleGPSDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) { + listener_state = new AltosListenerState(); + parent = in_parent; + voice = in_voice; + display = in_display; + reader = in_reader; + display.reset(); + } +} -- cgit v1.2.3