altosui: Convert from channels to frequencies
authorKeith Packard <keithp@keithp.com>
Mon, 8 Aug 2011 08:47:29 +0000 (01:47 -0700)
committerKeith Packard <keithp@keithp.com>
Mon, 8 Aug 2011 19:13:29 +0000 (12:13 -0700)
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 <keithp@keithp.com>
19 files changed:
altosui/AltosConfig.java
altosui/AltosConfigData.java
altosui/AltosConfigFreqUI.java
altosui/AltosConfigUI.java
altosui/AltosConvert.java
altosui/AltosEepromDelete.java
altosui/AltosEepromDownload.java
altosui/AltosFlightReader.java
altosui/AltosFlightUI.java
altosui/AltosFreqList.java [new file with mode: 0644]
altosui/AltosFrequency.java
altosui/AltosIdleMonitorUI.java
altosui/AltosIgnite.java
altosui/AltosPreferences.java
altosui/AltosScanUI.java
altosui/AltosSerial.java
altosui/AltosTelemetryReader.java
altosui/AltosUI.java
altosui/Makefile.am

index 04d7552..694ef4d 100644 (file)
@@ -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();
index 1d50ade..aa7a90d 100644 (file)
@@ -47,6 +47,7 @@ public class AltosConfigData implements Iterable<String> {
        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<String> {
                serial_line.printf("c s\nv\n");
                lines = new LinkedList<String>();
                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<String> {
                        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+");
index d68151e..063d21b 100644 (file)
@@ -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);
index 1a48c1d..c109924 100644 (file)
@@ -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();
        }
index 8cc1df2..6a9b699 100644 (file)
@@ -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;
+       }
 }
index ecd82c1..94951ce 100644 (file)
@@ -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() {
index 82f01ef..64dcdff 100644 (file)
@@ -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() {
index f665bda..3a17144 100644 (file)
@@ -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 { }
 }
index 04bfc90..8c3f821 100644 (file)
@@ -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 (file)
index 0000000..59b0e12
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * 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);
+       }
+}
index 8265eaf..0617ce7 100644 (file)
@@ -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;
index a4262ca..0370efa 100644 (file)
@@ -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);
                }
 
 
index 7a06c63..3e52ea3 100644 (file)
@@ -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);
index e92b953..8609f94 100644 (file)
@@ -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<Integer, Integer> channels;
-
        /* Frequency (map serial to frequency) */
        static Hashtable<Integer, Double> frequencies;
 
@@ -148,7 +148,7 @@ class AltosPreferences {
                if (!mapdir.exists())
                        mapdir.mkdirs();
 
-               channels = new Hashtable<Integer,Integer>();
+               frequencies = new Hashtable<Integer, Double>();
 
                telemetries = new Hashtable<Integer,Integer>();
 
@@ -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);
+       }
 }
index 96cab73..9a48313 100644 (file)
@@ -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;
 
index f45aa18..6c687f5 100644 (file)
@@ -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<String> pending_output = new LinkedList<String>();
        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;
index 23524b2..4512e76 100644 (file)
@@ -27,6 +27,9 @@ class AltosTelemetryReader extends AltosFlightReader {
        AltosSerial     serial;
        AltosLog        log;
        AltosRecord     previous;
+       AltosConfigData config_data;
+       double          frequency;
+       int             telemetry;
 
        LinkedBlockingQueue<AltosLine> 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<AltosLine>();
-               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);
        }
 }
index 033f233..885e60c 100644 (file)
@@ -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);
                }
        }
 
index d6fd0e6..4bac6df 100644 (file)
@@ -52,6 +52,7 @@ altosui_JAVA = \
        AltosFlightStatus.java \
        AltosFlightUI.java \
        AltosFrequency.java \
+       AltosFreqList.java \
        AltosGPS.java \
        AltosGPSSat.java \
        AltosGreatCircle.java \