From 0e3e4f9c1e6a6bf972514f12c9d622258aa2aec2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 01:47:29 -0700 Subject: [PATCH] altosui: Convert from channels to frequencies Major areas: * Preferences are stored as frequencies instead of channels * Serial configuration is done using frequencies * UI is presented with frequency lists Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 54 ++++++++++--- altosui/AltosConfigData.java | 4 +- altosui/AltosConfigFreqUI.java | 4 +- altosui/AltosConfigUI.java | 58 +++++++++----- altosui/AltosConvert.java | 33 ++++++++ altosui/AltosEepromDelete.java | 15 ++-- altosui/AltosEepromDownload.java | 13 ++-- altosui/AltosFlightReader.java | 7 +- altosui/AltosFlightUI.java | 26 ++++--- altosui/AltosFreqList.java | 87 +++++++++++++++++++++ altosui/AltosFrequency.java | 6 ++ altosui/AltosIdleMonitorUI.java | 35 +++++---- altosui/AltosIgnite.java | 37 +++++---- altosui/AltosPreferences.java | 47 +++++++---- altosui/AltosScanUI.java | 125 +++++++++++++++++++----------- altosui/AltosSerial.java | 72 +++++++++++------ altosui/AltosTelemetryReader.java | 27 +++++-- altosui/AltosUI.java | 12 ++- altosui/Makefile.am | 1 + 19 files changed, 486 insertions(+), 177 deletions(-) create mode 100644 altosui/AltosFreqList.java diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 04d75528..694ef4db 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -64,6 +64,8 @@ public class AltosConfig implements ActionListener { AltosDevice device; AltosSerial serial_line; boolean remote; + AltosConfigData remote_config_data; + double remote_frequency; int_ref serial; int_ref main_deploy; int_ref apogee_delay; @@ -72,6 +74,7 @@ public class AltosConfig implements ActionListener { int_ref flight_log_max; int_ref ignite_mode; int_ref pad_orientation; + int_ref radio_setting; string_ref version; string_ref product; string_ref callsign; @@ -109,7 +112,7 @@ public class AltosConfig implements ActionListener { } } - void start_serial() throws InterruptedException { + void start_serial() throws InterruptedException, TimeoutException { serial_started = true; if (remote) serial_line.start_remote(); @@ -129,12 +132,13 @@ public class AltosConfig implements ActionListener { config_ui.set_version(version.get()); config_ui.set_main_deploy(main_deploy.get()); config_ui.set_apogee_delay(apogee_delay.get()); - config_ui.set_radio_channel(radio_channel.get()); + config_ui.set_radio_frequency(frequency()); config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_ignite_mode(ignite_mode.get()); config_ui.set_pad_orientation(pad_orientation.get()); config_ui.set_callsign(callsign.get()); + config_ui.set_radio_setting(radio_setting.get()); config_ui.set_clean(); config_ui.make_visible(); } @@ -157,6 +161,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Max flight log:", flight_log_max); get_int(line, "Ignite mode:", ignite_mode); get_int(line, "Pad orientation:", pad_orientation); + get_int(line, "Radio setting:", radio_setting); get_string(line, "Callsign:", callsign); get_string(line,"software-version", version); get_string(line,"product", product); @@ -200,6 +205,7 @@ public class AltosConfig implements ActionListener { } } } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -211,16 +217,20 @@ public class AltosConfig implements ActionListener { void save_data() { try { - int channel; + double frequency = frequency(); + boolean has_setting = radio_setting.get() != 0; start_serial(); serial_line.printf("c m %d\n", main_deploy.get()); serial_line.printf("c d %d\n", apogee_delay.get()); - channel = radio_channel.get(); - serial_line.printf("c r %d\n", channel); + serial_line.set_radio_frequency(frequency, + has_setting, + radio_calibration.get()); if (remote) { serial_line.stop_remote(); - serial_line.set_channel(channel); - AltosPreferences.set_channel(device.getSerial(), channel); + serial_line.set_radio_frequency(frequency, + has_setting, + radio_calibration.get()); + AltosPreferences.set_frequency(device.getSerial(), frequency); serial_line.start_remote(); } if (!remote) @@ -234,6 +244,7 @@ public class AltosConfig implements ActionListener { serial_line.printf("c o %d\n", pad_orientation.get()); serial_line.printf("c w\n"); } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -248,6 +259,7 @@ public class AltosConfig implements ActionListener { serial_line.printf("r eboot\n"); serial_line.flush_output(); } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -308,11 +320,32 @@ public class AltosConfig implements ActionListener { update_ui(); } + double frequency() { + int setting = radio_setting.get(); + + if (setting != 0) + return AltosConvert.radio_setting_to_frequency(setting, radio_calibration.get()); + else + return AltosConvert.radio_channel_to_frequency(radio_channel.get()); + } + + void set_frequency(double freq) { + int setting = radio_setting.get(); + + if (setting != 0) { + radio_setting.set(AltosConvert.radio_frequency_to_setting(freq, + radio_calibration.get())); + radio_channel.set(0); + } else { + radio_channel.set(AltosConvert.radio_frequency_to_channel(freq)); + } + } + void save_data() { main_deploy.set(config_ui.main_deploy()); apogee_delay.set(config_ui.apogee_delay()); - radio_channel.set(config_ui.radio_channel()); radio_calibration.set(config_ui.radio_calibration()); + set_frequency(config_ui.radio_frequency()); flight_log_max.set(config_ui.flight_log_max()); ignite_mode.set(config_ui.ignite_mode()); pad_orientation.set(config_ui.pad_orientation()); @@ -348,6 +381,7 @@ public class AltosConfig implements ActionListener { main_deploy = new int_ref(250); apogee_delay = new int_ref(0); radio_channel = new int_ref(0); + radio_setting = new int_ref(0); radio_calibration = new int_ref(1186611); flight_log_max = new int_ref(0); ignite_mode = new int_ref(-1); @@ -360,9 +394,9 @@ public class AltosConfig implements ActionListener { if (device != null) { try { serial_line = new AltosSerial(device); - if (!device.matchProduct(Altos.product_telemetrum)) - remote = true; try { + if (!device.matchProduct(Altos.product_telemetrum)) + remote = true; init_ui(); } catch (InterruptedException ie) { abort(); diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 1d50ade9..aa7a90de 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -47,6 +47,7 @@ public class AltosConfigData implements Iterable { int main_deploy; int apogee_delay; int radio_channel; + int radio_setting; String callsign; int accel_cal_plus, accel_cal_minus; int radio_calibration; @@ -85,7 +86,7 @@ public class AltosConfigData implements Iterable { serial_line.printf("c s\nv\n"); lines = new LinkedList(); for (;;) { - String line = serial_line.get_reply_no_dialog(5000); + String line = serial_line.get_reply(); if (line == null) throw new TimeoutException(); if (line.contains("Syntax error")) @@ -95,6 +96,7 @@ public class AltosConfigData implements Iterable { try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} try { if (line.startsWith("Accel cal")) { String[] bits = line.split("\\s+"); diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index d68151ec..063d21b4 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -177,9 +177,9 @@ public class AltosConfigFreqUI extends JDialog implements ActionListener { int i; for (i = 0; i < list_model.size(); i++) { AltosFrequency f = (AltosFrequency) list_model.get(i); - if (f.frequency == frequency.frequency) + if (frequency.frequency == f.frequency) return; - if (f.frequency > frequency.frequency) + if (frequency.frequency < f.frequency) break; } list_model.insertElementAt(frequency, i); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 1a48c1d3..c109924e 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -43,8 +43,9 @@ public class AltosConfigUI JLabel serial_label; JLabel main_deploy_label; JLabel apogee_delay_label; - JLabel radio_channel_label; + JLabel frequency_label; JLabel radio_calibration_label; + JLabel radio_frequency_label; JLabel flight_log_max_label; JLabel ignite_mode_label; JLabel pad_orientation_label; @@ -58,7 +59,7 @@ public class AltosConfigUI JLabel serial_value; JComboBox main_deploy_value; JComboBox apogee_delay_value; - JComboBox radio_channel_value; + AltosFreqList radio_frequency_value; JTextField radio_calibration_value; JComboBox flight_log_max_value; JComboBox ignite_mode_value; @@ -98,13 +99,6 @@ public class AltosConfigUI "Antenna Down", }; - static String[] radio_channel_values = new String[10]; - { - for (int i = 0; i <= 9; i++) - radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)", - i, 434.550 + i * 0.1); - } - /* A window listener to catch closing events and tell the config code */ class ConfigListener extends WindowAdapter { AltosConfigUI ui; @@ -245,7 +239,7 @@ public class AltosConfigUI apogee_delay_value.addItemListener(this); pane.add(apogee_delay_value, c); - /* Radio channel */ + /* Frequency */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = 5; c.gridwidth = 4; @@ -253,8 +247,8 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = il; c.ipady = 5; - radio_channel_label = new JLabel("Radio Channel:"); - pane.add(radio_channel_label, c); + radio_frequency_label = new JLabel("Frequency:"); + pane.add(radio_frequency_label, c); c = new GridBagConstraints(); c.gridx = 4; c.gridy = 5; @@ -264,10 +258,9 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = ir; c.ipady = 5; - radio_channel_value = new JComboBox(radio_channel_values); - radio_channel_value.setEditable(false); - radio_channel_value.addItemListener(this); - pane.add(radio_channel_value, c); + radio_frequency_value = new AltosFreqList(); + radio_frequency_value.addItemListener(this); + pane.add(radio_frequency_value, c); /* Radio Calibration */ c = new GridBagConstraints(); @@ -501,6 +494,7 @@ public class AltosConfigUI /* set and get all of the dialog values */ public void set_product(String product) { + radio_frequency_value.set_product(product); product_value.setText(product); } @@ -509,6 +503,7 @@ public class AltosConfigUI } public void set_serial(int serial) { + radio_frequency_value.set_serial(serial); serial_value.setText(String.format("%d", serial)); } @@ -528,12 +523,32 @@ public class AltosConfigUI return Integer.parseInt(apogee_delay_value.getSelectedItem().toString()); } - public void set_radio_channel(int new_radio_channel) { - radio_channel_value.setSelectedIndex(new_radio_channel); + public void set_radio_frequency(double new_radio_frequency) { + int i; + for (i = 0; i < radio_frequency_value.getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i); + + if (f.close(new_radio_frequency)) { + radio_frequency_value.setSelectedIndex(i); + return; + } + } + for (i = 0; i < radio_frequency_value.getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i); + + if (new_radio_frequency < f.frequency) + break; + } + String description = String.format("%s serial %s", + product_value.getText(), + serial_value.getText()); + AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description); + AltosPreferences.add_common_frequency(new_frequency); + radio_frequency_value.insertItemAt(new_frequency, i); } - public int radio_channel() { - return radio_channel_value.getSelectedIndex(); + public double radio_frequency() { + return radio_frequency_value.frequency(); } public void set_radio_calibration(int new_radio_calibration) { @@ -548,6 +563,9 @@ public class AltosConfigUI callsign_value.setText(new_callsign); } + public void set_radio_setting(int new_radio_setting) { + } + public String callsign() { return callsign_value.getText(); } diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java index 8cc1df27..6a9b699c 100644 --- a/altosui/AltosConvert.java +++ b/altosui/AltosConvert.java @@ -189,4 +189,37 @@ public class AltosConvert { { return ignite / 32767 * 15.0; } + + static double + radio_setting_to_frequency(int setting, int cal) { + double f; + + f = 434.550 * setting / cal; + /* Round to nearest 50KHz */ + f = Math.floor (20.0 * f + 0.5) / 20.0; + return f; + } + + static int + radio_frequency_to_setting(double frequency, int cal) { + double set = frequency / 434.550 * cal; + + return (int) Math.floor (set + 0.5); + } + + static double + radio_channel_to_frequency(int channel) { + return 434.550 + channel * 0.100; + } + + static int + radio_frequency_to_channel(double frequency) { + int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); + + if (channel < 0) + channel = 0; + if (channel > 9) + channel = 9; + return channel; + } } diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index ecd82c18..94951ced 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -84,11 +84,11 @@ public class AltosEepromDelete implements Runnable { } public void run () { - if (remote) - serial_line.start_remote(); - success = false; try { + if (remote) + serial_line.start_remote(); + for (AltosEepromLog log : flights) { if (log.delete) { DeleteLog(log); @@ -103,11 +103,12 @@ public class AltosEepromDelete implements Runnable { show_error (String.format("Connection to \"%s\" failed", serial_line.device.toShortString()), "Connection Failed"); + } finally { + if (remote) + serial_line.stop_remote(); + serial_line.flush_output(); + serial_line.close(); } - if (remote) - serial_line.stop_remote(); - serial_line.flush_output(); - serial_line.close(); if (listener != null) { Runnable r = new Runnable() { public void run() { diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 82f01ef5..64dcdff7 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -264,11 +264,11 @@ public class AltosEepromDownload implements Runnable { } public void run () { - if (remote) - serial_line.start_remote(); - try { boolean failed = false; + if (remote) + serial_line.start_remote(); + for (AltosEepromLog log : flights) { parse_exception = null; if (log.download) { @@ -295,11 +295,12 @@ public class AltosEepromDownload implements Runnable { serial_line.device.toShortString()), "Connection Failed", JOptionPane.ERROR_MESSAGE); + } finally { + if (remote) + serial_line.stop_remote(); + serial_line.flush_output(); } - if (remote) - serial_line.stop_remote(); monitor.done(); - serial_line.flush_output(); if (listener != null) { Runnable r = new Runnable() { public void run() { diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java index f665bda8..3a171444 100644 --- a/altosui/AltosFlightReader.java +++ b/altosui/AltosFlightReader.java @@ -20,6 +20,7 @@ package altosui; import java.lang.*; import java.text.*; import java.io.*; +import java.util.concurrent.*; public class AltosFlightReader { String name; @@ -32,9 +33,13 @@ public class AltosFlightReader { void close(boolean interrupted) { } - void set_channel(int channel) { } + void set_frequency(double frequency) throws InterruptedException, TimeoutException { } + + void save_frequency() { } void set_telemetry(int telemetry) { } + void save_telemetry() { } + void update(AltosState state) throws InterruptedException { } } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 04bfc90d..8c3f821e 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -26,7 +26,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.*; public class AltosFlightUI extends JFrame implements AltosFlightDisplay { AltosVoice voice; @@ -118,7 +118,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { } Container bag; - JComboBox channels; + AltosFreqList frequencies; JComboBox telemetries; public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) { @@ -141,18 +141,25 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { /* Stick channel selector at top of table for telemetry monitoring */ if (serial >= 0) { // Channel menu - channels = new AltosChannelMenu(AltosPreferences.channel(serial)); - channels.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int channel = channels.getSelectedIndex(); - reader.set_channel(channel); - } + frequencies = new AltosFreqList(AltosPreferences.frequency(serial)); + frequencies.set_product("Monitor"); + frequencies.set_serial(serial); + frequencies.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + double frequency = frequencies.frequency(); + reader.save_frequency(); + try { + reader.set_frequency(frequency); + } catch (TimeoutException te) { + } catch (InterruptedException ie) { + } + } }); c.gridx = 0; c.gridy = 0; c.insets = new Insets(3, 3, 3, 3); c.anchor = GridBagConstraints.WEST; - bag.add (channels, c); + bag.add (frequencies, c); // Telemetry format menu telemetries = new JComboBox(); @@ -168,6 +175,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { public void actionPerformed(ActionEvent e) { int telemetry = telemetries.getSelectedIndex() + 1; reader.set_telemetry(telemetry); + reader.save_telemetry(); } }); c.gridx = 1; diff --git a/altosui/AltosFreqList.java b/altosui/AltosFreqList.java new file mode 100644 index 00000000..59b0e127 --- /dev/null +++ b/altosui/AltosFreqList.java @@ -0,0 +1,87 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFreqList extends JComboBox { + + String product; + int serial; + int calibrate; + + public void set_frequency(double new_frequency) { + int i; + for (i = 0; i < getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) getItemAt(i); + + if (f.close(new_frequency)) { + setSelectedIndex(i); + return; + } + } + for (i = 0; i < getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) getItemAt(i); + + if (new_frequency < f.frequency) + break; + } + String description = String.format("%s serial %d", product, serial); + AltosFrequency frequency = new AltosFrequency(new_frequency, description); + AltosPreferences.add_common_frequency(frequency); + insertItemAt(frequency, i); + setMaximumRowCount(getItemCount()); + } + + public void set_product(String new_product) { + product = new_product; + } + + public void set_serial(int new_serial) { + serial = new_serial; + } + + public double frequency() { + AltosFrequency f = (AltosFrequency) getSelectedItem(); + if (f != null) + return f.frequency; + return 434.550; + } + + public AltosFreqList () { + super(AltosPreferences.common_frequencies()); + setMaximumRowCount(getItemCount()); + setEditable(false); + product = "Unknown"; + serial = 0; + } + + public AltosFreqList(double in_frequency) { + this(); + set_frequency(in_frequency); + } +} diff --git a/altosui/AltosFrequency.java b/altosui/AltosFrequency.java index 8265eafc..0617ce74 100644 --- a/altosui/AltosFrequency.java +++ b/altosui/AltosFrequency.java @@ -44,6 +44,12 @@ public class AltosFrequency { frequency, description); } + public boolean close(double f) { + double diff = Math.abs(frequency - f); + + return diff < 0.010; + } + public AltosFrequency(double f, String d) { frequency = f; description = d; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index a4262cae..0370efa9 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -167,7 +167,7 @@ class AltosIdleMonitor extends Thread { AltosIdleMonitorUI ui; AltosState state; boolean remote; - int channel; + double frequency; AltosState previous_state; AltosConfigData config_data; AltosADC adc; @@ -178,7 +178,7 @@ class AltosIdleMonitor extends Thread { try { if (remote) { - set_channel(channel); + serial.set_radio_frequency(frequency); serial.start_remote(); } else serial.flush_input(); @@ -217,8 +217,8 @@ class AltosIdleMonitor extends Thread { state = new AltosState (record, state); } - void set_channel(int in_channel) { - channel = in_channel; + void set_frequency(double in_frequency) { + frequency = in_frequency; } public void post_state() { @@ -246,7 +246,7 @@ class AltosIdleMonitor extends Thread { } public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote) - throws FileNotFoundException, AltosSerialInUseException { + throws FileNotFoundException, AltosSerialInUseException, InterruptedException, TimeoutException { device = in_device; ui = in_ui; serial = new AltosSerial(device); @@ -299,9 +299,10 @@ public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { } Container bag; - JComboBox channels; + AltosFreqList frequencies; - public AltosIdleMonitorUI(JFrame in_owner) throws FileNotFoundException, AltosSerialInUseException { + public AltosIdleMonitorUI(JFrame in_owner) + throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException { device = AltosDeviceDialog.show(in_owner, Altos.product_any); remote = false; @@ -320,21 +321,23 @@ public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { setTitle(String.format("AltOS %s", device.toShortString())); - /* Stick channel selector at top of table for telemetry monitoring */ + /* Stick frequency selector at top of table for telemetry monitoring */ if (remote && serial >= 0) { - // Channel menu - channels = new AltosChannelMenu(AltosPreferences.channel(serial)); - channels.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int channel = channels.getSelectedIndex(); - thread.set_channel(channel); - } + // Frequency menu + frequencies = new AltosFreqList(AltosPreferences.frequency(serial)); + frequencies.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + double frequency = frequencies.frequency(); + thread.set_frequency(frequency); + AltosPreferences.set_frequency(device.getSerial(), + frequency); + } }); c.gridx = 0; c.gridy = 0; c.insets = new Insets(3, 3, 3, 3); c.anchor = GridBagConstraints.WEST; - bag.add (channels, c); + bag.add (frequencies, c); } diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index 7a06c63d..3e52ea36 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -40,7 +40,7 @@ public class AltosIgnite { final static int Active = 2; final static int Open = 3; - private void start_serial() throws InterruptedException { + private void start_serial() throws InterruptedException, TimeoutException { serial_started = true; if (remote) serial.start_remote(); @@ -102,22 +102,25 @@ public class AltosIgnite { if (serial == null) return status; string_ref status_name = new string_ref(); - start_serial(); - serial.printf("t\n"); - for (;;) { - String line = serial.get_reply(5000); - if (line == null) - throw new TimeoutException(); - if (get_string(line, "Igniter: drogue Status: ", status_name)) - if (igniter == Apogee) - status = status(status_name.get()); - if (get_string(line, "Igniter: main Status: ", status_name)) { - if (igniter == Main) - status = status(status_name.get()); - break; + try { + start_serial(); + serial.printf("t\n"); + for (;;) { + String line = serial.get_reply(5000); + if (line == null) + throw new TimeoutException(); + if (get_string(line, "Igniter: drogue Status: ", status_name)) + if (igniter == Apogee) + status = status(status_name.get()); + if (get_string(line, "Igniter: main Status: ", status_name)) { + if (igniter == Main) + status = status(status_name.get()); + break; + } } + } finally { + stop_serial(); } - stop_serial(); return status; } @@ -145,6 +148,7 @@ public class AltosIgnite { break; } } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -166,7 +170,8 @@ public class AltosIgnite { serial.set_frame(frame); } - public AltosIgnite(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { + public AltosIgnite(AltosDevice in_device) + throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException { device = in_device; serial = new AltosSerial(device); diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index e92b9532..8609f94e 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -34,6 +34,9 @@ class AltosPreferences { /* channel preference name */ final static String channelPreferenceFormat = "CHANNEL-%d"; + /* frequency preference name */ + final static String frequencyPreferenceFormat = "FREQUENCY-%d"; + /* telemetry format preference name */ final static String telemetryPreferenceFormat = "TELEMETRY-%d"; @@ -61,9 +64,6 @@ class AltosPreferences { /* Map directory -- hangs of logdir */ static File mapdir; - /* Channel (map serial to channel) */ - static Hashtable channels; - /* Frequency (map serial to frequency) */ static Hashtable frequencies; @@ -148,7 +148,7 @@ class AltosPreferences { if (!mapdir.exists()) mapdir.mkdirs(); - channels = new Hashtable(); + frequencies = new Hashtable(); telemetries = new Hashtable(); @@ -242,20 +242,24 @@ class AltosPreferences { return mapdir; } - public static void set_channel(int serial, int new_channel) { - channels.put(serial, new_channel); + public static void set_frequency(int serial, double new_frequency) { + frequencies.put(serial, new_frequency); synchronized (preferences) { - preferences.putInt(String.format(channelPreferenceFormat, serial), new_channel); + preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); flush_preferences(); } } - public static int channel(int serial) { - if (channels.containsKey(serial)) - return channels.get(serial); - int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); - channels.put(serial, channel); - return channel; + public static double frequency(int serial) { + if (frequencies.containsKey(serial)) + return frequencies.get(serial); + double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); + if (frequency == 0.0) { + int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); + frequency = AltosConvert.radio_channel_to_frequency(channel); + } + frequencies.put(serial, frequency); + return frequency; } public static void set_telemetry(int serial, int new_telemetry) { @@ -339,4 +343,21 @@ class AltosPreferences { flush_preferences(); } } + + public static void add_common_frequency(AltosFrequency frequency) { + AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; + int i; + + for (i = 0; i < common_frequencies.length; i++) { + if (frequency.frequency == common_frequencies[i].frequency) + return; + if (frequency.frequency < common_frequencies[i].frequency) + break; + new_frequencies[i] = common_frequencies[i]; + } + new_frequencies[i] = frequency; + for (; i < common_frequencies.length; i++) + new_frequencies[i+1] = common_frequencies[i]; + set_common_frequencies(new_frequencies); + } } diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 96cab73b..9a483138 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -33,27 +33,27 @@ class AltosScanResult { String callsign; int serial; int flight; - int channel; + double frequency; int telemetry; boolean interrupted = false; public String toString() { - return String.format("%-9.9s serial %-4d flight %-4d (channel %-2d %s)", - callsign, serial, flight, channel, Altos.telemetry_name(telemetry)); + return String.format("%-9.9s serial %-4d flight %-4d (frequency %7.3f %s)", + callsign, serial, flight, frequency, Altos.telemetry_name(telemetry)); } public String toShortString() { - return String.format("%s %d %d %d %d", - callsign, serial, flight, channel, telemetry); + return String.format("%s %d %d %7.3f %d", + callsign, serial, flight, frequency, telemetry); } public AltosScanResult(String in_callsign, int in_serial, - int in_flight, int in_channel, int in_telemetry) { + int in_flight, double in_frequency, int in_telemetry) { callsign = in_callsign; serial = in_serial; flight = in_flight; - channel = in_channel; + frequency = in_frequency; telemetry = in_telemetry; } @@ -61,7 +61,7 @@ class AltosScanResult { return (callsign.equals(other.callsign) && serial == other.serial && flight == other.flight && - channel == other.channel && + frequency == other.frequency && telemetry == other.telemetry); } } @@ -107,20 +107,25 @@ public class AltosScanUI { AltosUI owner; AltosDevice device; + AltosConfigData config_data; AltosTelemetryReader reader; private JList list; private JLabel scanning_label; + private JLabel frequency_label; + private JLabel telemetry_label; private JButton cancel_button; private JButton monitor_button; javax.swing.Timer timer; AltosScanResults results = new AltosScanResults(); int telemetry; - int channel; + double frequency; final static int timeout = 1200; TelemetryHandler handler; Thread thread; + AltosFrequency[] frequencies; + int frequency_index; void scan_exception(Exception e) { if (e instanceof FileNotFoundException) { @@ -167,7 +172,7 @@ public class AltosScanUI final AltosScanResult result = new AltosScanResult(record.callsign, record.serial, record.flight, - channel, + frequency, telemetry); Runnable r = new Runnable() { public void run() { @@ -190,26 +195,30 @@ public class AltosScanUI } void set_label() { - scanning_label.setText(String.format("Scanning: channel %d %s", - channel, - Altos.telemetry_name(telemetry))); + frequency_label.setText(String.format("Frequency: %s", frequencies[frequency_index].toString())); + telemetry_label.setText(String.format("Telemetry: %s", Altos.telemetry_name(telemetry))); } - void next() { + void set_telemetry() { + reader.set_telemetry(telemetry); + } + + void set_frequency() throws InterruptedException, TimeoutException { + reader.set_frequency(frequencies[frequency_index].frequency); + } + + void next() throws InterruptedException, TimeoutException { reader.serial.set_monitor(false); - try { - Thread.sleep(100); - } catch (InterruptedException ie){ - } - ++channel; - if (channel > 9) { - channel = 0; + Thread.sleep(100); + ++frequency_index; + if (frequency_index >= frequencies.length) { + frequency_index = 0; ++telemetry; if (telemetry > Altos.ao_telemetry_max) telemetry = Altos.ao_telemetry_min; - reader.serial.set_telemetry(telemetry); + set_telemetry(); } - reader.serial.set_channel(channel); + set_frequency(); set_label(); reader.serial.set_monitor(true); } @@ -229,31 +238,37 @@ public class AltosScanUI dispose(); } - void tick_timer() { + void tick_timer() throws InterruptedException, TimeoutException { next(); } public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); - if (cmd.equals("cancel")) - close(); - - if (cmd.equals("tick")) - tick_timer(); - - if (cmd.equals("monitor")) { - close(); - AltosScanResult r = (AltosScanResult) (list.getSelectedValue()); - if (r != null) { - if (device != null) { - if (reader != null) { - reader.set_telemetry(r.telemetry); - reader.set_channel(r.channel); - owner.telemetry_window(device); + try { + if (cmd.equals("cancel")) + close(); + + if (cmd.equals("tick")) + tick_timer(); + + if (cmd.equals("monitor")) { + close(); + AltosScanResult r = (AltosScanResult) (list.getSelectedValue()); + if (r != null) { + if (device != null) { + if (reader != null) { + reader.set_telemetry(r.telemetry); + reader.set_frequency(r.frequency); + owner.telemetry_window(device); + } } } } + } catch (TimeoutException te) { + close(); + } catch (InterruptedException ie) { + close(); } } @@ -278,8 +293,8 @@ public class AltosScanUI return false; try { reader = new AltosTelemetryReader(device); - reader.serial.set_channel(channel); - reader.serial.set_telemetry(telemetry); + set_frequency(); + set_telemetry(); try { Thread.sleep(100); } catch (InterruptedException ie) { @@ -306,6 +321,16 @@ public class AltosScanUI device.toShortString(), "Unkonwn I/O error", JOptionPane.ERROR_MESSAGE); + } catch (TimeoutException te) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + "Timeout error", + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + "Interrupted exception", + JOptionPane.ERROR_MESSAGE); } if (reader != null) reader.close(false); @@ -316,7 +341,8 @@ public class AltosScanUI owner = in_owner; - channel = 0; + frequencies = AltosPreferences.common_frequencies(); + frequency_index = 0; telemetry = Altos.ao_telemetry_min; if (!open()) @@ -335,11 +361,13 @@ public class AltosScanUI pane.setLayout(new GridBagLayout()); scanning_label = new JLabel("Scanning:"); + frequency_label = new JLabel(""); + telemetry_label = new JLabel(""); set_label(); c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.CENTER; + c.anchor = GridBagConstraints.WEST; c.insets = i; c.weightx = 1; c.weighty = 1; @@ -347,9 +375,12 @@ public class AltosScanUI c.gridx = 0; c.gridy = 0; c.gridwidth = 2; - c.anchor = GridBagConstraints.CENTER; pane.add(scanning_label, c); + c.gridy = 1; + pane.add(frequency_label, c); + c.gridy = 2; + pane.add(telemetry_label, c); list = new JList(results) { //Subclass JList to workaround bug 4832765, which can cause the @@ -417,7 +448,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 0; - c.gridy = 1; + c.gridy = 3; c.gridwidth = 2; c.anchor = GridBagConstraints.CENTER; @@ -434,7 +465,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 0; - c.gridy = 2; + c.gridy = 4; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; @@ -451,7 +482,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 1; - c.gridy = 2; + c.gridy = 4; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index f45aa18b..6c687f5f 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -54,11 +54,12 @@ public class AltosSerial implements Runnable { int line_count; boolean monitor_mode; int telemetry; - int channel; + double frequency; static boolean debug; boolean remote; LinkedList pending_output = new LinkedList(); Frame frame; + AltosConfigData config_data; static void set_debug(boolean new_debug) { debug = new_debug; @@ -154,7 +155,7 @@ public class AltosSerial implements Runnable { Object[] options = { "Cancel" }; JOptionPane pane = new JOptionPane(); - pane.setMessage(String.format("Connecting to %s", device.getPath())); + pane.setMessage(String.format("Connecting to %s, %7.3f MHz", device.toShortString(), frequency)); pane.setOptions(options); pane.setInitialValue(null); @@ -208,20 +209,13 @@ public class AltosSerial implements Runnable { } while (got_some); } - public String get_reply() throws InterruptedException { - if (SwingUtilities.isEventDispatchThread()) - System.out.printf("Uh-oh, reading serial device from swing thread\n"); - flush_output(); - AltosLine line = reply_queue.take(); - return line.line; - } - int in_reply; public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = true; ++in_reply; + System.out.printf("get_reply %d\n", timeout); if (SwingUtilities.isEventDispatchThread()) { can_cancel = false; System.out.printf("Uh-oh, reading serial device from swing thread\n"); @@ -239,7 +233,6 @@ public class AltosSerial implements Runnable { --in_reply; return line.line; } - System.out.printf("no line remote %b can_cancel %b\n", remote, can_cancel); if (!remote || !can_cancel || check_timeout()) { --in_reply; return null; @@ -247,8 +240,13 @@ public class AltosSerial implements Runnable { } } + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { flush_output(); + System.out.printf("get_reply_no_dialog\n"); AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); if (line != null) return line.line; @@ -267,6 +265,8 @@ public class AltosSerial implements Runnable { } public void close() { + if (remote) + stop_remote(); if (in_reply != 0) System.out.printf("Uh-oh. Closing active serial device\n"); @@ -328,19 +328,11 @@ public class AltosSerial implements Runnable { flush_output(); } - public void set_radio() { - telemetry = AltosPreferences.telemetry(device.getSerial()); - channel = AltosPreferences.channel(device.getSerial()); - set_channel(channel); - set_callsign(AltosPreferences.callsign()); - } - private int telemetry_len() { return Altos.telemetry_len(telemetry); } - public void set_channel(int in_channel) { - channel = in_channel; + private void set_channel(int channel) { if (altos != null) { if (monitor_mode) printf("m 0\nc r %d\nm %x\n", @@ -351,6 +343,33 @@ public class AltosSerial implements Runnable { } } + private void set_radio_setting(int setting) { + if (altos != null) { + if (monitor_mode) + printf("m 0\nc R %d\nc r 0\nm %x\n", + setting, telemetry_len()); + else + printf("c R %d\nc r 0\n", setting); + } + } + + public void set_radio_frequency(double frequency, + boolean has_setting, + int cal) { + if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + public void set_telemetry(int in_telemetry) { telemetry = in_telemetry; if (altos != null) { @@ -378,10 +397,19 @@ public class AltosSerial implements Runnable { } } - public void start_remote() { + public AltosConfigData config_data() throws InterruptedException, TimeoutException { + if (config_data == null) + config_data = new AltosConfigData(this); + return config_data; + } + + public void start_remote() throws TimeoutException, InterruptedException { if (debug) System.out.printf("start remote\n"); - set_radio(); + if (frequency == 0.0) + frequency = AltosPreferences.frequency(device.getSerial()); + set_radio_frequency(frequency); + set_callsign(AltosPreferences.callsign()); printf("p\nE 0\n"); flush_input(); remote = true; diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 23524b2c..4512e761 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -27,6 +27,9 @@ class AltosTelemetryReader extends AltosFlightReader { AltosSerial serial; AltosLog log; AltosRecord previous; + AltosConfigData config_data; + double frequency; + int telemetry; LinkedBlockingQueue telem; @@ -49,18 +52,26 @@ class AltosTelemetryReader extends AltosFlightReader { serial.close(); } - void set_channel(int channel) { - serial.set_channel(channel); - AltosPreferences.set_channel(device.getSerial(), channel); + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + serial.set_radio_frequency(frequency); } - void set_telemetry(int telemetry) { + void save_frequency() { + AltosPreferences.set_frequency(device.getSerial(), frequency); + } + + void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; serial.set_telemetry(telemetry); + } + + void save_telemetry() { AltosPreferences.set_telemetry(device.getSerial(), telemetry); } public AltosTelemetryReader (AltosDevice in_device) - throws FileNotFoundException, AltosSerialInUseException, IOException { + throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { device = in_device; serial = new AltosSerial(device); log = new AltosLog(serial); @@ -68,7 +79,11 @@ class AltosTelemetryReader extends AltosFlightReader { previous = null; telem = new LinkedBlockingQueue(); - serial.set_radio(); + frequency = AltosPreferences.frequency(device.getSerial()); + set_frequency(frequency); + telemetry = AltosPreferences.telemetry(device.getSerial()); + set_telemetry(telemetry); + serial.set_callsign(AltosPreferences.callsign()); serial.add_monitor(telem); } } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 033f233c..885e60cd 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -26,7 +26,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.*; import libaltosJNI.*; @@ -67,6 +67,16 @@ public class AltosUI extends JFrame { device.toShortString(), "Unkonwn I/O error", JOptionPane.ERROR_MESSAGE); + } catch (TimeoutException te) { + JOptionPane.showMessageDialog(this, + device.toShortString(), + "Timeout error", + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { + JOptionPane.showMessageDialog(this, + device.toShortString(), + "Interrupted exception", + JOptionPane.ERROR_MESSAGE); } } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index d6fd0e6d..4bac6df1 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -52,6 +52,7 @@ altosui_JAVA = \ AltosFlightStatus.java \ AltosFlightUI.java \ AltosFrequency.java \ + AltosFreqList.java \ AltosGPS.java \ AltosGPSSat.java \ AltosGreatCircle.java \ -- 2.30.2