altosui: Accel calibration UI
authorKeith Packard <keithp@keithp.com>
Sat, 12 Aug 2017 03:42:53 +0000 (23:42 -0400)
committerKeith Packard <keithp@keithp.com>
Fri, 1 Sep 2017 20:22:58 +0000 (13:22 -0700)
Provides a GUI for re-calibrating accelerometers

Signed-off-by: Keith Packard <keithp@keithp.com>
altoslib/AltosAccelCal.java [new file with mode: 0644]
altoslib/AltosAccelCalListener.java [new file with mode: 0644]
altoslib/AltosConfigData.java
altoslib/AltosConfigValues.java
altoslib/AltosLink.java
altoslib/Makefile.am
altosui/AltosConfigFC.java
altosui/AltosConfigFCUI.java
altosuilib/AltosUIAccelCal.java [new file with mode: 0644]
altosuilib/Makefile.am

diff --git a/altoslib/AltosAccelCal.java b/altoslib/AltosAccelCal.java
new file mode 100644 (file)
index 0000000..03d9fbf
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright © 2017 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.altusmetrum.altoslib_12;
+
+import java.io.*;
+import java.util.concurrent.*;
+
+public class AltosAccelCal implements Runnable {
+
+       AltosLink               link;
+       AltosAccelCalListener   listener;
+
+       boolean                 remote;
+       boolean                 close_on_exit;
+       double                  frequency;
+       String                  callsign;
+
+       Thread                  accel_thread;
+
+       AltosConfigData         config_data;
+
+       public static final int phase_antenna_up = 0;
+       public static final int phase_antenna_down = 1;
+
+       void start_link() throws InterruptedException, TimeoutException {
+               if (remote) {
+                       link.set_radio_frequency(frequency);
+                       link.set_callsign(callsign);
+                       link.start_remote();
+               } else
+                       link.flush_input();
+       }
+
+       boolean stop_link() throws InterruptedException, TimeoutException {
+               if (remote)
+                       link.stop_remote();
+               return link.reply_abort;
+       }
+
+       public void set_frequency(double in_frequency) {
+               frequency = in_frequency;
+               link.abort_reply();
+       }
+
+       public void set_callsign(String in_callsign) {
+               callsign = in_callsign;
+               link.abort_reply();
+       }
+
+       public void abort() throws InterruptedException {
+               while (accel_thread.isAlive()) {
+                       accel_thread.interrupt();
+                       link.abort_reply();
+                       Thread.sleep(100);
+               }
+               accel_thread.join();
+       }
+
+       static private final String press_msg = "press a key...";
+
+       private Semaphore ui_signal_semaphore;
+       private boolean ui_signal_reply;
+
+       public void signal(boolean reply) {
+               System.out.printf("Signal cal semaphore %b\n", reply);
+               ui_signal_reply = reply;
+               ui_signal_semaphore.release();
+       }
+
+       private boolean wait_signal() throws InterruptedException {
+               System.out.printf("\twait for cal signal...\n");
+               ui_signal_semaphore.acquire();
+               System.out.printf("\tgot cal signal %b\n", ui_signal_reply);
+               return ui_signal_reply;
+       }
+
+       private boolean wait_press(int timeout) throws InterruptedException {
+               for (;;) {
+                       String line = link.get_reply(timeout);
+                       if (line == null) {
+                               System.out.printf("get_reply timeout\n");
+                               return false;
+                       }
+                       System.out.printf("got line %s\n", line);
+                       if (line.contains(press_msg))
+                               return true;
+                       if (line.contains("Invalid"))
+                               return false;
+                       if (line.contains("Syntax"))
+                               return false;
+                       if (line.contains("Calibrating"))
+                               listener.message(this, line);
+               }
+       }
+
+       static final int cal_timeout = 20 * 1000;
+
+       public void run() {
+               System.out.printf("start accel cal procedure\n");
+               try {
+                       AltosConfigData new_config = null;
+
+                       try {
+                               start_link();
+                               config_data = link.config_data();
+
+                               /* set back to antenna up for calibration */
+                               if (config_data.pad_orientation != 0)
+                                       link.printf("c o 0\n");
+
+                               /* Start calibration */
+                               try {
+                                       System.out.printf("*** start cal\n");
+                                       link.set_match(press_msg);
+                                       link.printf("c a 0\n");
+                                       System.out.printf("*** wait press\n");
+                                       if (!wait_press(cal_timeout))
+                                               throw new TimeoutException("timeout");
+                                       System.out.printf("*** set_phase antenna_up\n");
+                                       listener.set_phase(this, phase_antenna_up);
+                                       System.out.printf("*** wait_signal\n");
+                                       if (!wait_signal())
+                                               throw new InterruptedException("aborted");
+                                       link.set_match(press_msg);
+                                       System.out.printf("*** send newline\n");
+                                       link.printf("\n");
+                                       System.out.printf("*** wait press\n");
+                                       if (!wait_press(cal_timeout))
+                                               throw new TimeoutException("timeout");
+                                       System.out.printf("***set_phase antenna_down\n");
+                                       listener.set_phase(this, phase_antenna_down);
+                                       System.out.printf("*** wait_signal\n");
+                                       if (!wait_signal())
+                                               throw new InterruptedException("aborted");
+                                       System.out.printf("*** send newline and version command\n");
+                                       link.printf("\nv\n");
+                               } catch (TimeoutException e) {
+                                       throw e;
+                               } catch (InterruptedException e) {
+                                       throw e;
+                               }
+                               link.set_match(null);
+
+                               boolean worked = true;
+                               for (;;) {
+                                       String line = link.get_reply(cal_timeout);
+                                       if (line == null)
+                                               throw new TimeoutException();
+                                       System.out.printf("*** waiting for finish: %s\n", line);
+                                       if (line.contains("Invalid"))
+                                               worked = false;
+                                       if (line.contains("software-version"))
+                                               break;
+                                       if (line.contains("Calibrating"))
+                                               listener.message(this, line);
+                               }
+                               System.out.printf("*** worked: %b\n", worked);
+                               if (worked)
+                                       new_config = new AltosConfigData(link);
+                       } finally {
+                               System.out.printf("Restore orientation %d +g %d -g %d\n",
+                                                 config_data.pad_orientation,
+                                                 config_data.accel_cal_plus,
+                                                 config_data.accel_cal_minus);
+                               if (config_data.pad_orientation != AltosLib.MISSING && config_data.pad_orientation != 0)
+                                       link.printf("c o %d\n", config_data.pad_orientation);
+                               if (config_data.accel_cal_plus != AltosLib.MISSING && config_data.accel_cal_minus != AltosLib.MISSING)
+                                       link.printf("c a %d %d\n",
+                                                   config_data.accel_cal_plus, config_data.accel_cal_minus);
+                               stop_link();
+                       }
+                       if (new_config != null) {
+                               System.out.printf("*** +1g %d -1g %d\n",
+                                                 new_config.accel_cal_plus,
+                                                 new_config.accel_cal_minus);
+                               listener.cal_done(this, new_config.accel_cal_plus, new_config.accel_cal_minus);
+                               if (!wait_signal())
+                                       throw new InterruptedException("aborted");
+                       } else
+                               listener.error(this, "Calibration failed");
+               } catch (TimeoutException te) {
+                       System.out.printf("timeout");
+                       listener.error(this, "timeout");
+               } catch (InterruptedException ie) {
+                       System.out.printf("interrupted\n");
+                       listener.error(this, "interrupted");
+               }
+       }
+
+       public void start() {
+               accel_thread = new Thread(this);
+               listener.set_thread(this, accel_thread);
+               accel_thread.start();
+       }
+
+       public AltosAccelCal(AltosLink link, AltosAccelCalListener listener) {
+               this.link = link;
+               this.listener = listener;
+               ui_signal_semaphore = new Semaphore(0);
+       }
+}
diff --git a/altoslib/AltosAccelCalListener.java b/altoslib/AltosAccelCalListener.java
new file mode 100644 (file)
index 0000000..1735924
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2017 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.altusmetrum.altoslib_12;
+
+import java.io.*;
+import java.util.concurrent.*;
+
+public interface AltosAccelCalListener {
+       public void set_thread(AltosAccelCal cal, Thread thread);
+
+       public void set_phase(AltosAccelCal cal, int phase);
+
+       public void cal_done(AltosAccelCal cal, int plus, int minus);
+
+       public void error(AltosAccelCal cal, String msg);
+
+       public void message(AltosAccelCal cal, String msg);
+}
index 63c34310f6d12458338d08b2e3a46b8b4cffed06..d85f735b19d71ea2afb0d442d8343773718c707b 100644 (file)
@@ -525,6 +525,12 @@ public class AltosConfigData {
                if (pad_orientation != AltosLib.MISSING)
                        pad_orientation = source.pad_orientation();
 
                if (pad_orientation != AltosLib.MISSING)
                        pad_orientation = source.pad_orientation();
 
+               if (accel_cal_plus != AltosLib.MISSING)
+                       accel_cal_plus = source.accel_cal_plus();
+
+               if (accel_cal_minus != AltosLib.MISSING)
+                       accel_cal_minus = source.accel_cal_minus();
+
                /* HAS_LOG */
                if (flight_log_max != AltosLib.MISSING)
                        flight_log_max = source.flight_log_max();
                /* HAS_LOG */
                if (flight_log_max != AltosLib.MISSING)
                        flight_log_max = source.flight_log_max();
@@ -592,6 +598,7 @@ public class AltosConfigData {
                dest.set_flight_log_max(flight_log_max);
                dest.set_ignite_mode(ignite_mode);
                dest.set_pad_orientation(pad_orientation);
                dest.set_flight_log_max(flight_log_max);
                dest.set_ignite_mode(ignite_mode);
                dest.set_pad_orientation(pad_orientation);
+               dest.set_accel_cal(accel_cal_plus, accel_cal_minus);
                dest.set_callsign(callsign);
                if (npyro != AltosLib.MISSING)
                        dest.set_pyros(pyros);
                dest.set_callsign(callsign);
                if (npyro != AltosLib.MISSING)
                        dest.set_pyros(pyros);
@@ -669,9 +676,10 @@ public class AltosConfigData {
                        link.printf("c e %d\n", radio_enable);
 
                /* HAS_ACCEL */
                        link.printf("c e %d\n", radio_enable);
 
                /* HAS_ACCEL */
-               /* UI doesn't support accel cal */
                if (pad_orientation != AltosLib.MISSING)
                        link.printf("c o %d\n", pad_orientation);
                if (pad_orientation != AltosLib.MISSING)
                        link.printf("c o %d\n", pad_orientation);
+               if (accel_cal_plus != AltosLib.MISSING && accel_cal_minus != AltosLib.MISSING)
+                       link.printf("c a %d %d\n", accel_cal_plus, accel_cal_minus);
 
                /* HAS_LOG */
                if (flight_log_max != 0)
 
                /* HAS_LOG */
                if (flight_log_max != 0)
index 170b1112ea096048d06d61a893ad16444825973f..10478fd4f96313dff8684792356f2cc0be3e44c5 100644 (file)
@@ -74,6 +74,16 @@ public interface AltosConfigValues {
 
        public abstract int pad_orientation();
 
 
        public abstract int pad_orientation();
 
+       public abstract void set_accel_cal(int accel_cal_plus, int accel_cal_minus);
+
+       public abstract int accel_cal_plus();
+
+       public abstract int accel_cal_minus();
+
+       public abstract void set_dirty();
+
+       public abstract void set_clean();
+
        public abstract void set_pyros(AltosPyro[] new_pyros);
 
        public abstract AltosPyro[] pyros() throws AltosConfigDataException;
        public abstract void set_pyros(AltosPyro[] new_pyros);
 
        public abstract AltosPyro[] pyros() throws AltosConfigDataException;
index 5a802ef180230bdfb969d01212a0197781bb366d..5413de9dea7740fcaf56dcc2a19450d416c54f41 100644 (file)
@@ -43,6 +43,8 @@ public abstract class AltosLink implements Runnable {
        public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>();
        public LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>();
 
        public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>();
        public LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>();
 
+       private String match_string = null;
+
        public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) {
                set_monitor(true);
                monitors.add(q);
        public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) {
                set_monitor(true);
                monitors.add(q);
@@ -112,6 +114,15 @@ public abstract class AltosLink implements Runnable {
 
        private int     len_read = 0;
 
 
        private int     len_read = 0;
 
+       private boolean match_bytes(byte[] bytes, int byte_count, String match) {
+               if (byte_count < match.length())
+                       return false;
+               String  line = new String(bytes, 0, byte_count, AltosLib.unicode_set);
+               if (line == null)
+                       return false;
+               return line.indexOf(match) >= 0;
+       }
+
        public void run () {
                int c;
                byte[] line_bytes = null;
        public void run () {
                int c;
                byte[] line_bytes = null;
@@ -159,6 +170,11 @@ public abstract class AltosLink implements Runnable {
                                                        line_count = 0;
                                                        len_read = 0;
                                                }
                                                        line_count = 0;
                                                        len_read = 0;
                                                }
+                                               if (match_string != null && match_bytes(line_bytes, line_count, match_string)) {
+                                                       match_string = null;
+                                                       add_bytes(line_bytes, line_count);
+                                                       line_count = 0;
+                                               }
                                        }
                                }
                        }
                                        }
                                }
                        }
@@ -166,6 +182,9 @@ public abstract class AltosLink implements Runnable {
                }
        }
 
                }
        }
 
+       public void set_match(String match) {
+               match_string = match;
+       }
 
        public String get_reply(int timeout) throws InterruptedException {
                boolean can_cancel = can_cancel_reply();
 
        public String get_reply(int timeout) throws InterruptedException {
                boolean can_cancel = can_cancel_reply();
index 11b5d562ee643ae1f7e061bc9a885702c6d22a86..08af9496e00199f32226024da1f35049142cef25 100644 (file)
@@ -26,6 +26,8 @@ record_files = \
 
 altoslib_JAVA = \
        AltosLib.java \
 
 altoslib_JAVA = \
        AltosLib.java \
+       AltosAccelCal.java \
+       AltosAccelCalListener.java \
        AltosCalData.java \
        AltosCompanion.java \
        AltosConfigData.java \
        AltosCalData.java \
        AltosCompanion.java \
        AltosConfigData.java \
index beff71b7279db119e094f10f8cae37688dfcae14..5e2aa7f4ef405470c0106a3255fb9a7bf8399e55 100644 (file)
@@ -268,6 +268,13 @@ public class AltosConfigFC implements ActionListener {
                                if (serial_line != null)
                                        serial_line.close();
                        }
                                if (serial_line != null)
                                        serial_line.close();
                        }
+                       else if (cmd.equals("Accel")) {
+                               if (data.pad_orientation != AltosLib.MISSING) {
+                                       AltosUIAccelCal accel_ui = new AltosUIAccelCal(owner, serial_line, config_ui);
+                                       if (accel_ui != null)
+                                               accel_ui.doit();
+                               }
+                       }
                } catch (InterruptedException ie) {
                        abort();
                } catch (TimeoutException te) {
                } catch (InterruptedException ie) {
                        abort();
                } catch (TimeoutException te) {
index c0c37254673188fad2026a90cba7d591a062a2b9..3fe6cf94b0b0bb6352b914e04a04c65280a26728 100644 (file)
@@ -49,6 +49,8 @@ public class AltosConfigFCUI
        JLabel                  flight_log_max_label;
        JLabel                  ignite_mode_label;
        JLabel                  pad_orientation_label;
        JLabel                  flight_log_max_label;
        JLabel                  ignite_mode_label;
        JLabel                  pad_orientation_label;
+       JLabel                  accel_plus_label;
+       JLabel                  accel_minus_label;
        JLabel                  callsign_label;
        JLabel                  beep_label;
        JLabel                  tracker_motion_label;
        JLabel                  callsign_label;
        JLabel                  beep_label;
        JLabel                  tracker_motion_label;
@@ -73,12 +75,15 @@ public class AltosConfigFCUI
        JComboBox<String>       flight_log_max_value;
        JComboBox<String>       ignite_mode_value;
        JComboBox<String>       pad_orientation_value;
        JComboBox<String>       flight_log_max_value;
        JComboBox<String>       ignite_mode_value;
        JComboBox<String>       pad_orientation_value;
+       JTextField              accel_plus_value;
+       JTextField              accel_minus_value;
        JTextField              callsign_value;
        JComboBox<String>       beep_value;
        JComboBox<String>       tracker_motion_value;
        JComboBox<String>       tracker_interval_value;
 
        JButton                 pyro;
        JTextField              callsign_value;
        JComboBox<String>       beep_value;
        JComboBox<String>       tracker_motion_value;
        JComboBox<String>       tracker_interval_value;
 
        JButton                 pyro;
+       JButton                 accel_cal;
 
        JButton                 save;
        JButton                 reset;
 
        JButton                 save;
        JButton                 reset;
@@ -250,9 +255,9 @@ public class AltosConfigFCUI
        }
 
        void set_pad_orientation_tool_tip() {
        }
 
        void set_pad_orientation_tool_tip() {
-               if (pad_orientation_value.isVisible())
+               if (pad_orientation_value.isVisible()) {
                        pad_orientation_value.setToolTipText("How will the computer be mounted in the airframe");
                        pad_orientation_value.setToolTipText("How will the computer be mounted in the airframe");
-               else {
+               else {
                        if (is_telemetrum())
                                pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");
                        else if (is_telemini() || is_easymini())
                        if (is_telemetrum())
                                pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");
                        else if (is_telemini() || is_easymini())
@@ -262,6 +267,16 @@ public class AltosConfigFCUI
                }
        }
 
                }
        }
 
+       void set_accel_tool_tips() {
+               if (accel_plus_value.isVisible()) {
+                       accel_plus_value.setToolTipText("Pad acceleration value in flight orientation");
+                       accel_minus_value.setToolTipText("Upside-down acceleration value");
+               } else {
+                       accel_plus_value.setToolTipText("No accelerometer");
+                       accel_minus_value.setToolTipText("No accelerometer");
+               }
+       }
+
        void set_beep_tool_tip() {
                if (beep_value.isVisible())
                        beep_value.setToolTipText("What frequency the beeper will sound at");
        void set_beep_tool_tip() {
                if (beep_value.isVisible())
                        beep_value.setToolTipText("What frequency the beeper will sound at");
@@ -709,6 +724,57 @@ public class AltosConfigFCUI
                set_pad_orientation_tool_tip();
                row++;
 
                set_pad_orientation_tool_tip();
                row++;
 
+               /* Accel plus */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               accel_plus_label = new JLabel("Accel Plus:");
+               pane.add(accel_plus_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               accel_plus_value = new JTextField(10);
+               accel_plus_value.setEditable(true);
+               accel_plus_value.getDocument().addDocumentListener(this);
+               pane.add(accel_plus_value, c);
+               row++;
+
+               /* Accel minus */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               accel_minus_label = new JLabel("Accel Minus:");
+               pane.add(accel_minus_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               accel_minus_value = new JTextField(10);
+               accel_minus_value.setEditable(true);
+               accel_minus_value.getDocument().addDocumentListener(this);
+               pane.add(accel_minus_value, c);
+               row++;
+               set_accel_tool_tips();
+
                /* Beeper */
                c = new GridBagConstraints();
                c.gridx = 0; c.gridy = row;
                /* Beeper */
                c = new GridBagConstraints();
                c.gridx = 0; c.gridy = row;
@@ -800,6 +866,20 @@ public class AltosConfigFCUI
                pyro.setActionCommand("Pyro");
                row++;
 
                pyro.setActionCommand("Pyro");
                row++;
 
+               /* Accel cal */
+               c = new GridBagConstraints();
+               c.gridx = 5; c.gridy = row;
+               c.gridwidth = 5;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               accel_cal = new JButton("Calibrate Accelerometer");
+               pane.add(accel_cal, c);
+               accel_cal.addActionListener(this);
+               accel_cal.setActionCommand("Accel");
+               row++;
+
                /* Buttons */
                c = new GridBagConstraints();
                c.gridx = 0; c.gridy = row;
                /* Buttons */
                c = new GridBagConstraints();
                c.gridx = 0; c.gridy = row;
@@ -873,12 +953,14 @@ public class AltosConfigFCUI
                return true;
        }
 
                return true;
        }
 
-       void set_dirty() {
+       public void set_dirty() {
+               System.out.printf("set dirty\n");
                dirty = true;
                save.setEnabled(true);
        }
 
        public void set_clean() {
                dirty = true;
                save.setEnabled(true);
        }
 
        public void set_clean() {
+               System.out.printf("set clean\n");
                dirty = false;
                save.setEnabled(false);
        }
                dirty = false;
                save.setEnabled(false);
        }
@@ -912,7 +994,8 @@ public class AltosConfigFCUI
                        setVisible(false);
                        dispose();
                }
                        setVisible(false);
                        dispose();
                }
-               set_clean();
+               if (cmd.equals("Save") || cmd.equals("Reset"))
+                       set_clean();
        }
 
        /* ItemListener interface method */
        }
 
        /* ItemListener interface method */
@@ -943,6 +1026,7 @@ public class AltosConfigFCUI
                radio_frequency_value.set_product(product);
                product_value.setText(product);
                set_pad_orientation_tool_tip();
                radio_frequency_value.set_product(product);
                product_value.setText(product);
                set_pad_orientation_tool_tip();
+               set_accel_tool_tips();
                set_flight_log_max_tool_tip();
        }
 
                set_flight_log_max_tool_tip();
        }
 
@@ -1196,6 +1280,7 @@ public class AltosConfigFCUI
                }
                pad_orientation_value.setVisible(new_pad_orientation != AltosLib.MISSING);
                pad_orientation_label.setVisible(new_pad_orientation != AltosLib.MISSING);
                }
                pad_orientation_value.setVisible(new_pad_orientation != AltosLib.MISSING);
                pad_orientation_label.setVisible(new_pad_orientation != AltosLib.MISSING);
+               accel_cal.setVisible(new_pad_orientation != AltosLib.MISSING);
 
                set_pad_orientation_tool_tip();
        }
 
                set_pad_orientation_tool_tip();
        }
@@ -1207,6 +1292,31 @@ public class AltosConfigFCUI
                        return AltosLib.MISSING;
        }
 
                        return AltosLib.MISSING;
        }
 
+       public void set_accel_cal(int accel_plus, int accel_minus) {
+               if (accel_plus != AltosLib.MISSING) {
+                       accel_plus_value.setText(String.format("%d", accel_plus));
+                       accel_minus_value.setText(String.format("%d", accel_minus));
+               }
+               accel_plus_value.setVisible(accel_plus != AltosLib.MISSING);
+               accel_plus_label.setVisible(accel_plus != AltosLib.MISSING);
+               accel_minus_value.setVisible(accel_minus != AltosLib.MISSING);
+               accel_minus_label.setVisible(accel_minus != AltosLib.MISSING);
+
+               set_accel_tool_tips();
+       }
+
+       public int accel_cal_plus() {
+               if (accel_plus_value.isVisible())
+                       return Integer.parseInt(accel_plus_value.getText());
+               return AltosLib.MISSING;
+       }
+
+       public int accel_cal_minus() {
+               if (accel_minus_value.isVisible())
+                       return Integer.parseInt(accel_minus_value.getText());
+               return AltosLib.MISSING;
+       }
+
        public void set_beep(int new_beep) {
                if (new_beep != AltosLib.MISSING) {
                        int new_freq = (int) Math.floor (AltosConvert.beep_value_to_freq(new_beep) + 0.5);
        public void set_beep(int new_beep) {
                if (new_beep != AltosLib.MISSING) {
                        int new_freq = (int) Math.floor (AltosConvert.beep_value_to_freq(new_beep) + 0.5);
diff --git a/altosuilib/AltosUIAccelCal.java b/altosuilib/AltosUIAccelCal.java
new file mode 100644 (file)
index 0000000..ea1869d
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright © 2017 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.altusmetrum.altosuilib_12;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.altusmetrum.altoslib_12.*;
+
+public class AltosUIAccelCal
+       extends AltosUIDialog
+       implements AltosAccelCalListener, ActionListener
+{
+       Frame owner;
+       AltosLink link;
+       AltosAccelCal cal;
+       AltosConfigValues       config_values;
+       Thread thread;
+       Container pane;
+       JTextField message;
+       JButton antenna_up;
+       JButton antenna_down;
+       JButton ok;
+       JButton cancel;
+       boolean success;
+       int accel_plus, accel_minus;
+
+       private void make_visible() {
+               System.out.printf("Make calibration dialog visible\n");
+               pack();
+               cal.start();
+               setVisible(true);
+       }
+
+       public boolean doit() {
+               success = false;
+               make_visible();
+               return success;
+       }
+
+       public int accel_cal_plus() {
+               if (success)
+                       return accel_plus;
+               return AltosLib.MISSING;
+       }
+
+       public int accel_cal_minus() {
+               if (success)
+                       return accel_minus;
+               return AltosLib.MISSING;
+       }
+
+       /* AltosAccelCalListener interface */
+       public void set_thread(AltosAccelCal cal, Thread thread) {
+               this.thread = thread;
+       }
+
+       public void set_phase(AltosAccelCal cal, final int phase) {
+               SwingUtilities.invokeLater(new Runnable() {
+                               public void run() {
+                                       switch (phase) {
+                                       case AltosAccelCal.phase_antenna_up:
+                                               message.setText("Orient antenna upwards and click on Antenna Up");
+                                               antenna_up.setEnabled(true);
+                                               antenna_down.setEnabled(false);
+                                               ok.setEnabled(false);
+                                               break;
+                                       case AltosAccelCal.phase_antenna_down:
+                                               message.setText("Orient antenna downwards and click on Antenna Down");
+                                               antenna_up.setEnabled(false);
+                                               antenna_down.setEnabled(true);
+                                               ok.setEnabled(false);
+                                               break;
+                                       }
+                               }
+                       });
+       }
+
+       public void cal_done(AltosAccelCal cal, int plus, int minus) {
+               accel_plus = plus;
+               accel_minus = minus;
+               success = true;
+               SwingUtilities.invokeLater(new Runnable() {
+                               public void run() {
+                                       message.setText(String.format("Calibration succeeded, plus %d minus %d, press OK to continue", accel_plus, accel_minus));
+                                       antenna_up.setEnabled(false);
+                                       antenna_down.setEnabled(false);
+                                       ok.setEnabled(true);
+                               }
+                       });
+       }
+
+       public void message(AltosAccelCal cal, final String msg) {
+               SwingUtilities.invokeLater(new Runnable() {
+                               public void run() {
+                                       message.setText(msg);
+                               }
+                       });
+       }
+
+       public void error(AltosAccelCal cal, String msg) {
+               message(cal, msg);
+       }
+
+       /* ActionListener interface */
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+
+               if ("up".equals(cmd)) {
+                       cal.signal(true);
+                       antenna_up.setEnabled(false);
+               } else if ("down".equals(cmd)) {
+                       cal.signal(true);
+                       antenna_down.setEnabled(false);
+               } else if ("ok".equals(cmd)) {
+                       cal.signal(true);
+                       this.setVisible(false);
+                       if (success) {
+                               System.out.printf("set accel cal to %d/%d\n", accel_plus, accel_minus);
+                               config_values.set_accel_cal(accel_plus, accel_minus);
+                               config_values.set_dirty();
+                       }
+                       try {
+                               cal.abort();
+                       } catch (InterruptedException ie) {
+                       }
+               } else if ("cancel".equals(cmd)) {
+                       cal.signal(false);
+                       this.setVisible(false);
+                       try {
+                               cal.abort();
+                       } catch (InterruptedException ie) {
+                       }
+               }
+       }
+       public AltosUIAccelCal(Frame owner, AltosLink link, AltosConfigValues config_values) {
+               super(owner, "Calibrate Accelerometer", true);
+
+               this.owner = owner;
+               this.link = link;
+               this.config_values = config_values;
+
+               pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               GridBagConstraints c = new GridBagConstraints();
+               c.insets = new Insets(4,4,4,4);
+
+               int x = 0;
+               int y = 0;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = x;
+               c.gridy = y;
+               c.gridwidth = 4;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               message = new JTextField(64);
+               pane.add(message, c);
+
+               y++; x = 0;
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = x;
+               c.gridy = y;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               antenna_up = new JButton("Antenna Up");
+               antenna_up.setActionCommand("up");
+               antenna_up.setEnabled(false);
+               antenna_up.addActionListener(this);
+               pane.add(antenna_up, c);
+
+               x++;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = x;
+               c.gridy = y;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               antenna_down = new JButton("Antenna Down");
+               antenna_down.setActionCommand("down");
+               antenna_down.setEnabled(false);
+               antenna_down.addActionListener(this);
+               pane.add(antenna_down, c);
+
+               x++;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = x;
+               c.gridy = y;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               ok = new JButton("OK");
+               ok.setActionCommand("ok");
+               ok.setEnabled(false);
+               ok.addActionListener(this);
+               pane.add(ok, c);
+
+               x++;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = x;
+               c.gridy = y;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               cancel = new JButton("Cancel");
+               cancel.setActionCommand("cancel");
+               cancel.setEnabled(true);
+               cancel.addActionListener(this);
+               pane.add(cancel, c);
+
+               cal = new AltosAccelCal(this.link, this);
+       }
+}
index 4b5eb524c09824995393bb4a25d856f0f682dd6e..ce86d21e3a1405a4665cd86a04bb7b58f26a8774 100644 (file)
@@ -13,6 +13,7 @@ altosuilib_JAVA = \
        AltosDevice.java \
        AltosDeviceDialog.java \
        AltosPositionListener.java \
        AltosDevice.java \
        AltosDeviceDialog.java \
        AltosPositionListener.java \
+       AltosUIAccelCal.java \
        AltosUIConfigure.java \
        AltosUIAxis.java \
        AltosUIDataMissing.java \
        AltosUIConfigure.java \
        AltosUIAxis.java \
        AltosUIDataMissing.java \