altosui: Handle already-opened link in IgniteUI
[fw/altos] / altosui / AltosIgniteUI.java
index d542729cd0de5003d2272b5ad902a0d2450472e5..2e69249f42771db2c9d5854e5d64da8583002def 100644 (file)
@@ -20,39 +20,200 @@ package altosui;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import javax.swing.event.*;
 import java.io.*;
-import java.util.*;
 import java.text.*;
-import java.util.prefs.*;
+import java.util.*;
 import java.util.concurrent.*;
+import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altosuilib_1.*;
 
 public class AltosIgniteUI
-       extends JDialog
+       extends AltosUIDialog
        implements ActionListener
 {
        AltosDevice     device;
-       AltosIgnite     ignite;
        JFrame          owner;
        JLabel          label;
-       JRadioButton    apogee;
-       JLabel          apogee_status_label;
-       JRadioButton    main;
-       JLabel          main_status_label;
        JToggleButton   arm;
        JButton         fire;
        javax.swing.Timer       timer;
+       JButton         close;
+       ButtonGroup     group;
+       Boolean         opened;
 
-       int             apogee_status;
-       int             main_status;
+       int             npyro;
 
        final static int        timeout = 1 * 1000;
 
        int             time_remaining;
        boolean         timer_running;
 
+       LinkedBlockingQueue<String>     command_queue;
+
+       LinkedBlockingQueue<String>     reply_queue;
+
+       class Igniter {
+               JRadioButton    button;
+               JLabel          status_label;
+               String          name;
+               int             status;
+
+               void set_status (int status) {
+                       this.status = status;
+                       status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(status)));
+               }
+
+               Igniter(AltosIgniteUI ui, String label, String name, int y) {
+                       Container               pane = getContentPane();
+                       GridBagConstraints      c = new GridBagConstraints();
+                       Insets                  i = new Insets(4,4,4,4);
+
+                       this.name = name;
+                       this.status = AltosIgnite.Unknown;
+
+                       c.gridx = 0;
+                       c.gridy = y;
+                       c.gridwidth = 1;
+                       c.anchor = GridBagConstraints.WEST;
+                       button = new JRadioButton (label);
+                       pane.add(button, c);
+                       button.addActionListener(ui);
+                       button.setActionCommand(name);
+                       group.add(button);
+
+                       c.gridx = 1;
+                       c.gridy = y;
+                       c.gridwidth = 1;
+                       c.anchor = GridBagConstraints.WEST;
+                       status_label = new JLabel("plenty of text");
+                       pane.add(status_label, c);
+
+                       status = AltosIgnite.Unknown;
+               }
+       }
+
+       Igniter igniters[];
+
+       void set_status(String _name, int _status) {
+
+               final String name = _name;
+               final int status = _status;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       for (int p = 0; p < igniters.length; p++)
+                                               if (name.equals(igniters[p].name))
+                                                       igniters[p].set_status(status);
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       class IgniteHandler implements Runnable {
+               AltosIgnite     ignite;
+               JFrame          owner;
+               AltosLink       link;
+
+               void send_exception(Exception e) {
+                       final Exception f_e = e;
+                       Runnable r = new Runnable() {
+                                       public void run() {
+                                               ignite_exception(f_e);
+                                       }
+                               };
+                       SwingUtilities.invokeLater(r);
+               }
+
+               public void run () {
+                       try {
+                               ignite = new AltosIgnite(link,
+                                                        !device.matchProduct(Altos.product_altimeter));
+
+                       } catch (Exception e) {
+                               send_exception(e);
+                               return;
+                       }
+
+                       for (;;) {
+                               Runnable        r;
+
+                               try {
+                                       String          command = command_queue.take();
+                                       String          reply = null;
+
+                                       if (command.equals("get_status")) {
+                                               HashMap<String,Integer> status_map = ignite.status();
+
+                                               for (int p = 0; p < igniters.length; p++) {
+                                                       Integer i = status_map.get(igniters[p].name);
+                                                       if (i != null)
+                                                               set_status(igniters[p].name, i);
+                                               }
+                                               reply = "status";
+                                       } else if (command.equals("get_npyro")) {
+                                               put_reply(String.format("%d", ignite.npyro()));
+                                               continue;
+                                       } else if (command.equals("quit")) {
+                                               ignite.close();
+                                               break;
+                                       } else {
+                                               ignite.fire(command);
+                                               reply = "fired";
+                                       }
+                                       final String f_reply = reply;
+                                       r = new Runnable() {
+                                                       public void run() {
+                                                               ignite_reply(f_reply);
+                                                       }
+                                               };
+                                       SwingUtilities.invokeLater(r);
+                               } catch (Exception e) {
+                                       send_exception(e);
+                               }
+                       }
+               }
+
+               public IgniteHandler(JFrame in_owner, AltosLink in_link) {
+                       owner = in_owner;
+                       link = in_link;
+               }
+       }
+
+       void ignite_exception(Exception e) {
+               if (e instanceof FileNotFoundException) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     ((FileNotFoundException) e).getMessage(),
+                                                     "Cannot open target device",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else if (e instanceof AltosSerialInUseException) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     String.format("Device \"%s\" already in use",
+                                                                   device.toShortString()),
+                                                     "Device in use",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else if (e instanceof IOException) {
+                       IOException ee = (IOException) e;
+                       JOptionPane.showMessageDialog(owner,
+                                                     device.toShortString(),
+                                                     ee.getLocalizedMessage(),
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else {
+                       JOptionPane.showMessageDialog(owner,
+                                                     String.format("Connection to \"%s\" failed",
+                                                                   device.toShortString()),
+                                                     "Connection Failed",
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+               close();
+       }
+
+       void ignite_reply(String reply) {
+               if (reply.equals("status")) {
+                       set_ignite_status();
+               } else if (reply.equals("fired")) {
+                       fired();
+               }
+       }
+
        void set_arm_text() {
                if (arm.isSelected())
                        arm.setText(String.format("%d", time_remaining));
@@ -68,44 +229,91 @@ public class AltosIgniteUI
 
        void stop_timer() {
                time_remaining = 0;
-               arm.setSelected(false);
-               arm.setEnabled(false);
                fire.setEnabled(false);
                timer_running = false;
+               arm.setSelected(false);
+               arm.setEnabled(false);
                set_arm_text();
        }
 
        void cancel () {
-               apogee.setSelected(false);
-               main.setSelected(false);
+               group.clearSelection();
                fire.setEnabled(false);
                stop_timer();
        }
 
-       void get_ignite_status() throws InterruptedException, TimeoutException {
-               apogee_status = ignite.status(AltosIgnite.Apogee);
-               main_status = ignite.status(AltosIgnite.Main);
+       void send_command(String command) {
+               try {
+                       command_queue.put(command);
+               } catch (Exception ex) {
+                       ignite_exception(ex);
+               }
        }
 
-       void set_ignite_status() throws InterruptedException, TimeoutException {
-               get_ignite_status();
-               apogee_status_label.setText(String.format("\"%s\"", ignite.status_string(apogee_status)));
-               main_status_label.setText(String.format("\"%s\"", ignite.status_string(main_status)));
+       void put_reply(String reply) {
+               try {
+                       reply_queue.put(reply);
+               } catch (Exception ex) {
+                       ignite_exception(ex);
+               }
        }
 
-       void close() {
-               timer.stop();
-               setVisible(false);
-               ignite.close();
+       String get_reply() {
+               String reply = "";
+               try {
+                       reply = reply_queue.take();
+               } catch (Exception ex) {
+                       ignite_exception(ex);
+               }
+               return reply;
        }
 
-       void abort() {
-               close();
-               JOptionPane.showMessageDialog(owner,
-                                             String.format("Connection to \"%s\" failed",
-                                                           device.toShortString()),
-                                             "Connection Failed",
-                                             JOptionPane.ERROR_MESSAGE);
+       boolean getting_status = false;
+
+       boolean visible = false;
+
+       void set_ignite_status() {
+               getting_status = false;
+               if (!visible) {
+                       visible = true;
+                       setVisible(true);
+               }
+       }
+
+       void poll_ignite_status() {
+               if (!getting_status) {
+                       getting_status = true;
+                       send_command("get_status");
+               }
+       }
+
+       int get_npyro() {
+               send_command("get_npyro");
+               String reply = get_reply();
+               return Integer.parseInt(reply);
+       }
+
+       boolean firing = false;
+
+       void start_fire(String which) {
+               if (!firing) {
+                       firing = true;
+                       send_command(which);
+               }
+       }
+
+       void fired() {
+               firing = false;
+               cancel();
+       }
+
+       void close() {
+               if (opened) {
+                       send_command("quit");
+                       timer.stop();
+               }
+               setVisible(false);
+               dispose();
        }
 
        void tick_timer() {
@@ -116,41 +324,32 @@ public class AltosIgniteUI
                        else
                                set_arm_text();
                }
-               try {
-                       set_ignite_status();
-               } catch (InterruptedException ie) {
-                       abort();
-               } catch (TimeoutException te) {
-                       abort();
-               }
+               poll_ignite_status();
        }
 
        void fire() {
                if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
-                       int     igniter = AltosIgnite.None;
-                       if (apogee.isSelected() && !main.isSelected())
-                               igniter = AltosIgnite.Apogee;
-                       else if (main.isSelected() && !apogee.isSelected())
-                               igniter = AltosIgnite.Main;
-                       ignite.fire(igniter);
+                       String  igniter = "none";
+
+                       for (int p = 0; p < igniters.length; p++)
+                               if (igniters[p].button.isSelected()) {
+                                       igniter = igniters[p].name;
+                                       break;
+                               }
+                       send_command(igniter);
                        cancel();
                }
        }
 
        public void actionPerformed(ActionEvent e) {
                String cmd = e.getActionCommand();
-               if (cmd.equals("apogee") || cmd.equals("main")) {
-                       stop_timer();
-               }
 
-               if (cmd.equals("apogee") && apogee.isSelected()) {
-                       main.setSelected(false);
-                       arm.setEnabled(true);
-               }
-               if (cmd.equals("main") && main.isSelected()) {
-                       apogee.setSelected(false);
-                       arm.setEnabled(true);
-               }
+               for (int p = 0; p < igniters.length; p++)
+                       if (cmd.equals(igniters[p].name)) {
+                               stop_timer();
+                               arm.setEnabled(true);
+                               break;
+                       }
 
                if (cmd.equals("arm")) {
                        if (arm.isSelected()) {
@@ -163,9 +362,8 @@ public class AltosIgniteUI
                        fire();
                if (cmd.equals("tick"))
                        tick_timer();
-               if (cmd.equals("close")) {
+               if (cmd.equals("close"))
                        close();
-               }
        }
 
        /* A window listener to catch closing events and tell the config code */
@@ -184,28 +382,22 @@ public class AltosIgniteUI
        }
 
        private boolean open() {
-               device = AltosDeviceDialog.show(owner, AltosDevice.product_any);
+               command_queue = new LinkedBlockingQueue<String>();
+               reply_queue = new LinkedBlockingQueue<String>();
+
+               opened = false;
+               device = AltosDeviceUIDialog.show(owner, Altos.product_any);
                if (device != null) {
                        try {
-                               ignite = new AltosIgnite(device);
+                               AltosSerial     serial = new AltosSerial(device);
+                               serial.set_frame(owner);
+                               IgniteHandler   handler = new IgniteHandler(owner, serial);
+                               Thread          t = new Thread(handler);
+                               t.start();
+                               opened = true;
                                return true;
-                       } catch (FileNotFoundException ee) {
-                               JOptionPane.showMessageDialog(owner,
-                                                             String.format("Cannot open device \"%s\"",
-                                                                           device.toShortString()),
-                                                             "Cannot open target device",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       } catch (AltosSerialInUseException si) {
-                               JOptionPane.showMessageDialog(owner,
-                                                             String.format("Device \"%s\" already in use",
-                                                                           device.toShortString()),
-                                                             "Device in use",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       } catch (IOException ee) {
-                               JOptionPane.showMessageDialog(owner,
-                                                             device.toShortString(),
-                                                             ee.getLocalizedMessage(),
-                                                             JOptionPane.ERROR_MESSAGE);
+                       } catch (Exception ex) {
+                               ignite_exception(ex);
                        }
                }
                return false;
@@ -214,13 +406,14 @@ public class AltosIgniteUI
        public AltosIgniteUI(JFrame in_owner) {
 
                owner = in_owner;
-               apogee_status = AltosIgnite.Unknown;
-               main_status = AltosIgnite.Unknown;
 
                if (!open())
                        return;
 
+               group = new ButtonGroup();
+
                Container               pane = getContentPane();
+
                GridBagConstraints      c = new GridBagConstraints();
                Insets                  i = new Insets(4,4,4,4);
 
@@ -236,60 +429,35 @@ public class AltosIgniteUI
                c.fill = GridBagConstraints.NONE;
                c.anchor = GridBagConstraints.CENTER;
                c.insets = i;
-               c.weightx = 1;
-               c.weighty = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+
+               int y = 0;
 
                c.gridx = 0;
-               c.gridy = 0;
+               c.gridy = y;
                c.gridwidth = 2;
                c.anchor = GridBagConstraints.CENTER;
                label = new JLabel ("Fire Igniter");
                pane.add(label, c);
 
-               c.gridx = 0;
-               c.gridy = 1;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.WEST;
-               apogee = new JRadioButton ("Apogee");
-               pane.add(apogee, c);
-               apogee.addActionListener(this);
-               apogee.setActionCommand("apogee");
+               y++;
 
-               c.gridx = 1;
-               c.gridy = 1;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.WEST;
-               apogee_status_label = new JLabel();
-               pane.add(apogee_status_label, c);
+               int npyro = get_npyro();
 
-               c.gridx = 0;
-               c.gridy = 2;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.WEST;
-               main = new JRadioButton ("Main");
-               pane.add(main, c);
-               main.addActionListener(this);
-               main.setActionCommand("main");
+               igniters = new Igniter[2 + npyro];
 
-               c.gridx = 1;
-               c.gridy = 2;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.WEST;
-               main_status_label = new JLabel();
-               pane.add(main_status_label, c);
+               igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
+               igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++);
 
-               try {
-                       set_ignite_status();
-               } catch (InterruptedException ie) {
-                       abort();
-                       return;
-               } catch (TimeoutException te) {
-                       abort();
-                       return;
+               for (int p = 0; p < npyro; p++) {
+                       String  name = String.format("%d", p);
+                       String  label = String.format("%c", 'A' + p);
+                       igniters[2+p] = new Igniter(this, label, name, y++);
                }
 
                c.gridx = 0;
-               c.gridy = 3;
+               c.gridy = y;
                c.gridwidth = 1;
                c.anchor = GridBagConstraints.CENTER;
                arm = new JToggleButton ("Arm");
@@ -299,7 +467,7 @@ public class AltosIgniteUI
                arm.setEnabled(false);
 
                c.gridx = 1;
-               c.gridy = 3;
+               c.gridy = y;
                c.gridwidth = 1;
                c.anchor = GridBagConstraints.CENTER;
                fire = new JButton ("Fire");
@@ -308,9 +476,19 @@ public class AltosIgniteUI
                fire.addActionListener(this);
                fire.setActionCommand("fire");
 
+               y++;
+
+               c.gridx = 0;
+               c.gridy = y;
+               c.gridwidth = 2;
+               c.anchor = GridBagConstraints.CENTER;
+               close = new JButton ("Close");
+               pane.add(close, c);
+               close.addActionListener(this);
+               close.setActionCommand("close");
+                       
                pack();
                setLocationRelativeTo(owner);
-               setVisible(true);
 
                addWindowListener(new ConfigListener(this));
        }