add --replay command line argument
[fw/altos] / ao-tools / altosui / AltosUI.java
index 89eaac156b17d34f5c3b39d02191316536b7357e..2861444da7b5e9008e875d3285d7f225226ea18a 100644 (file)
@@ -20,47 +20,161 @@ 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 gnu.io.CommPortIdentifier;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
 
+import altosui.Altos;
 import altosui.AltosSerial;
 import altosui.AltosSerialMonitor;
+import altosui.AltosRecord;
+import altosui.AltosTelemetry;
+import altosui.AltosState;
+import altosui.AltosDeviceDialog;
+import altosui.AltosPreferences;
+import altosui.AltosLog;
+import altosui.AltosVoice;
+import altosui.AltosFlightInfoTableModel;
+import altosui.AltosFlashUI;
+import altosui.AltosLogfileChooser;
+import altosui.AltosCSVUI;
+import altosui.AltosLine;
+import altosui.AltosStatusTable;
+import altosui.AltosInfoTable;
+import altosui.AltosDisplayThread;
+
+import libaltosJNI.*;
 
-class AltosUIMonitor implements AltosSerialMonitor {
-       public void data(String data) {
-               System.out.println(data);
+public class AltosUI extends JFrame {
+       public AltosVoice voice = new AltosVoice();
+
+       public static boolean load_library(Frame frame) {
+               if (!AltosDevice.load_library()) {
+                       JOptionPane.showMessageDialog(frame,
+                                                     String.format("No AltOS library in \"%s\"",
+                                                                   System.getProperty("java.library.path","<undefined>")),
+                                                     "Cannot load device access library",
+                                                     JOptionPane.ERROR_MESSAGE);
+                       return false;
+               }
+               return true;
        }
-}
 
-public class AltosUI extends JFrame {
-       private int channel = -1;
+       void telemetry_window(AltosDevice device) {
+               try {
+                       AltosFlightReader reader = new AltosTelemetryReader(device);
+                       if (reader != null)
+                               new AltosFlightUI(voice, reader, device.getSerial());
+               } catch (FileNotFoundException ee) {
+                       JOptionPane.showMessageDialog(AltosUI.this,
+                                                     String.format("Cannot open device \"%s\"",
+                                                                   device.getPath()),
+                                                     "Cannot open target device",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (IOException ee) {
+                       JOptionPane.showMessageDialog(AltosUI.this,
+                                                     device.getPath(),
+                                                     "Unkonwn I/O error",
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+       }
+
+       Container       pane;
+       GridBagLayout   gridbag;
 
-       private JTable flightStatus;
-       private JTable flightInfo;
-       private AltosSerial serialLine;
+       JButton addButton(int x, int y, String label) {
+               GridBagConstraints      c;
+               JButton                 b;
+
+               c = new GridBagConstraints();
+               c.gridx = x; c.gridy = y;
+               c.fill = GridBagConstraints.BOTH;
+               c.weightx = 1;
+               c.weighty = 1;
+               b = new JButton(label);
+
+               Dimension ps = b.getPreferredSize();
+
+               gridbag.setConstraints(b, c);
+               add(b, c);
+               return b;
+       }
 
        public AltosUI() {
 
-               String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
-               Object[][] statusData = { { "0", "pad", "-50", "0" } };
+               load_library(null);
 
-               flightStatus = new JTable(statusData, statusNames);
+               java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
+               if (imgURL != null)
+                       setIconImage(new ImageIcon(imgURL).getImage());
 
-               flightStatus.setShowGrid(false);
+               AltosPreferences.init(this);
 
-               this.add(flightStatus);
+               pane = getContentPane();
+               gridbag = new GridBagLayout();
+               pane.setLayout(gridbag);
+
+               JButton b;
+
+               b = addButton(0, 0, "Monitor Flight");
+               b.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               ConnectToDevice();
+                                       }
+                               });
+               b = addButton(1, 0, "Save Flight Data");
+               b.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               SaveFlightData();
+                                       }
+                               });
+               b = addButton(2, 0, "Replay Flight");
+               b.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               Replay();
+                                       }
+                               });
+               b = addButton(0, 1, "Graph Data");
+               b.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               GraphData();
+                                       }
+                               });
+               b = addButton(1, 1, "Export Data");
+               b.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               ExportData();
+                                       }
+                               });
+               b = addButton(2, 1, "Configure TeleMetrum");
+               b.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               ConfigureTeleMetrum();
+                                       }
+                               });
 
                setTitle("AltOS");
 
                createMenu();
 
-               serialLine = new AltosSerial();
-               serialLine.monitor(new AltosUIMonitor());
-               int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
-               this.setSize(new Dimension (dpi * 5, dpi * 4));
-               this.validate();
+               pane.doLayout();
+               pane.validate();
+
+               doLayout();
+               validate();
+
+               setVisible(true);
+
+               Insets i = getInsets();
+               Dimension ps = rootPane.getPreferredSize();
+               ps.width += i.left + i.right;
+               ps.height += i.top + i.bottom;
+               setPreferredSize(ps);
+               setSize(ps);
                setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
                addWindowListener(new WindowAdapter() {
                        @Override
@@ -70,94 +184,69 @@ public class AltosUI extends JFrame {
                });
        }
 
-       final JFileChooser deviceChooser = new JFileChooser();
+       private void ConnectToDevice() {
+               AltosDevice     device = AltosDeviceDialog.show(AltosUI.this,
+                                                               AltosDevice.product_basestation);
 
-       private void PickSerialDevice() {
-               java.util.Enumeration<CommPortIdentifier> port_list = CommPortIdentifier.getPortIdentifiers();
-               while (port_list.hasMoreElements()) {
-                       CommPortIdentifier identifier = port_list.nextElement();
-                       System.out.println("Serial port " + identifier.getName());
-               }
+               if (device != null)
+                       telemetry_window(device);
        }
 
-       private void ConnectToDevice() {
-               PickSerialDevice();
-               int returnVal = deviceChooser.showOpenDialog(AltosUI.this);
-
-               if (returnVal == JFileChooser.APPROVE_OPTION) {
-                       File file = deviceChooser.getSelectedFile();
-                       try {
-                               serialLine.open(file);
-                       } catch (FileNotFoundException ee) {
-                               JOptionPane.showMessageDialog(AltosUI.this,
-                                                             file.getName(),
-                                                             "Cannot open serial port",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       }
-               }
+       void ConfigureCallsign() {
+               String  result;
+               result = JOptionPane.showInputDialog(AltosUI.this,
+                                                    "Configure Callsign",
+                                                    AltosPreferences.callsign());
+               if (result != null)
+                       AltosPreferences.set_callsign(result);
        }
 
-       String readline(FileInputStream s) throws IOException {
-               int c;
-               String  line = "";
+       void ConfigureTeleMetrum() {
+               new AltosConfig(AltosUI.this);
+       }
 
-               while ((c = s.read()) != -1) {
-                       if (c == '\r')
-                               continue;
-                       if (c == '\n')
-                               return line;
-                       line = line + (char) c;
-               }
-               return null;
+       void FlashImage() {
+               new AltosFlashUI(AltosUI.this);
        }
 
+       /*
+        * Replay a flight from telemetry data
+        */
        private void Replay() {
-//             int returnVal = deviceChooser.showOpenDialog(AltosUI.this);
-
-               /*              if (returnVal == JFileChooser.APPROVE_OPTION) */ {
-//                     File file = deviceChooser.getSelectedFile();
-//                     String  filename = file.getName();
-                       String  filename = "/home/keithp/src/cc1111/flights/2010-02-13-serial-051-flight-002.telem";
-                       try {
-//                             FileInputStream replay = new FileInputStream(file);
-                               FileInputStream replay = new FileInputStream(filename);
-                               String  line;
-
-                               try {
-                                       while ((line = readline(replay)) != null) {
-                                               try {
-                                                       AltosTelemetry  t = new AltosTelemetry(line);
-                                                       System.out.println ("Version " + t.version + t.callsign);
-                                               } catch (ParseException pp) {
-                                                       JOptionPane.showMessageDialog(AltosUI.this,
-                                                                                     line,
-                                                                                     "error parsing",
-                                                                                     JOptionPane.ERROR_MESSAGE);
-                                                       break;
-                                               }
-                                       }
-                               } catch (IOException ee) {
-                                       JOptionPane.showMessageDialog(AltosUI.this,
-                                                                     filename,
-                                                                     "error reading",
-                                                                     JOptionPane.ERROR_MESSAGE);
-                               } finally {
-                                       try {
-                                               replay.close();
-                                       } catch (IOException e) {}
-                               }
-                       } catch (FileNotFoundException ee) {
-                               JOptionPane.showMessageDialog(AltosUI.this,
-                                                             filename,
-                                                             "Cannot open serial port",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       }
+               AltosLogfileChooser chooser = new AltosLogfileChooser(
+                       AltosUI.this);
+               AltosRecordIterable iterable = chooser.runDialog();
+               if (iterable != null) {
+                       AltosFlightReader reader = new AltosReplayReader(iterable.iterator(),
+                                                                        chooser.filename());
+                       new AltosFlightUI(voice, reader);
                }
        }
 
+       /* Connect to TeleMetrum, either directly or through
+        * a TeleDongle over the packet link
+        */
        private void SaveFlightData() {
+               new AltosEepromDownload(AltosUI.this);
        }
 
+       /* Load a flight log file and write out a CSV file containing
+        * all of the data in standard units
+        */
+
+       private void ExportData() {
+               new AltosCSVUI(AltosUI.this);
+       }
+
+       /* Load a flight log CSV file and display a pretty graph.
+        */
+
+       private void GraphData() {
+               new AltosGraphUI(AltosUI.this);
+       }
+
+       /* Create the AltosUI menus
+        */
        private void createMenu() {
                JMenuBar menubar = new JMenuBar();
                JMenu menu;
@@ -170,11 +259,36 @@ public class AltosUI extends JFrame {
                        menu.setMnemonic(KeyEvent.VK_F);
                        menubar.add(menu);
 
+                       item = new JMenuItem("Flash Image",KeyEvent.VK_I);
+                       item.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               FlashImage();
+                                       }
+                               });
+                       menu.add(item);
+
+                       item = new JMenuItem("Export Data",KeyEvent.VK_E);
+                       item.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               ExportData();
+                                       }
+                               });
+                       menu.add(item);
+
+                       item = new JMenuItem("Graph Data",KeyEvent.VK_G);
+                       item.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               GraphData();
+                                       }
+                               });
+                       menu.add(item);
+
                        item = new JMenuItem("Quit",KeyEvent.VK_Q);
                        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
                                                                   ActionEvent.CTRL_MASK));
                        item.addActionListener(new ActionListener() {
                                        public void actionPerformed(ActionEvent e) {
+                                               System.out.printf("exiting\n");
                                                System.exit(0);
                                        }
                                });
@@ -182,7 +296,7 @@ public class AltosUI extends JFrame {
                }
 
                // Device menu
-               {
+               if (false) {
                        menu = new JMenu("Device");
                        menu.setMnemonic(KeyEvent.VK_D);
                        menubar.add(menu);
@@ -195,30 +309,24 @@ public class AltosUI extends JFrame {
                                });
                        menu.add(item);
 
-                       item = new JMenuItem("Disconnect from Device",KeyEvent.VK_D);
-                       item.addActionListener(new ActionListener() {
-                                       public void actionPerformed(ActionEvent e) {
-                                               serialLine.close();
-                                       }
-                               });
-                       menu.add(item);
-
                        menu.addSeparator();
 
-                       item = new JMenuItem("Save Flight Data",KeyEvent.VK_S);
+                       item = new JMenuItem("Set Callsign",KeyEvent.VK_S);
                        item.addActionListener(new ActionListener() {
                                        public void actionPerformed(ActionEvent e) {
-                                               SaveFlightData();
+                                               ConfigureCallsign();
                                        }
                                });
+
                        menu.add(item);
 
-                       item = new JMenuItem("Replay",KeyEvent.VK_R);
+                       item = new JMenuItem("Configure TeleMetrum device",KeyEvent.VK_T);
                        item.addActionListener(new ActionListener() {
                                        public void actionPerformed(ActionEvent e) {
-                                               Replay();
+                                               ConfigureTeleMetrum();
                                        }
                                });
+
                        menu.add(item);
                }
                // Log menu
@@ -237,6 +345,7 @@ public class AltosUI extends JFrame {
                        item = new JMenuItem("Configure Log",KeyEvent.VK_C);
                        item.addActionListener(new ActionListener() {
                                        public void actionPerformed(ActionEvent e) {
+                                               AltosPreferences.ConfigureLog();
                                        }
                                });
                        menu.add(item);
@@ -247,42 +356,141 @@ public class AltosUI extends JFrame {
                        menu.setMnemonic(KeyEvent.VK_V);
                        menubar.add(menu);
 
-                       radioitem = new JRadioButtonMenuItem("Enable Voice");
+                       radioitem = new JRadioButtonMenuItem("Enable Voice", AltosPreferences.voice());
                        radioitem.addActionListener(new ActionListener() {
                                        public void actionPerformed(ActionEvent e) {
+                                               JRadioButtonMenuItem item = (JRadioButtonMenuItem) e.getSource();
+                                               boolean enabled = item.isSelected();
+                                               AltosPreferences.set_voice(enabled);
+                                               if (enabled)
+                                                       voice.speak_always("Enable voice.");
+                                               else
+                                                       voice.speak_always("Disable voice.");
                                        }
                                });
                        menu.add(radioitem);
+                       item = new JMenuItem("Test Voice",KeyEvent.VK_T);
+                       item.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               voice.speak("That's one small step for man; one giant leap for mankind.");
+                                       }
+                               });
+                       menu.add(item);
                }
+               this.setJMenuBar(menubar);
+       }
 
-               // Channel menu
-               {
-                       menu = new JMenu("Channel", true);
-                       menu.setMnemonic(KeyEvent.VK_C);
-                       menubar.add(menu);
-                       ButtonGroup group = new ButtonGroup();
-
-                       for (int c = 0; c <= 9; c++) {
-                               radioitem = new JRadioButtonMenuItem(String.format("Channel %1d (%7.3fMHz)", c,
-                                                                                  434.550 + c * 0.1),
-                                                                    c == 0);
-                               radioitem.setActionCommand(String.format("%d", c));
-                               radioitem.addActionListener(new ActionListener() {
-                                               public void actionPerformed(ActionEvent e) {
-                                                       System.out.println("Command: " + e.getActionCommand() + " param: " +
-                                                                          e.paramString());
-                                               }
-                                       });
-                               menu.add(radioitem);
-                               group.add(radioitem);
-                       }
+       static AltosRecordIterable open_logfile(String filename) {
+               File file = new File (filename);
+               try {
+                       FileInputStream in;
+
+                       in = new FileInputStream(file);
+                       if (filename.endsWith("eeprom"))
+                               return new AltosEepromIterable(in);
+                       else
+                               return new AltosTelemetryIterable(in);
+               } catch (FileNotFoundException fe) {
+                       System.out.printf("Cannot open '%s'\n", filename);
+                       return null;
                }
+       }
 
-               this.setJMenuBar(menubar);
+       static AltosWriter open_csv(String filename) {
+               File file = new File (filename);
+               try {
+                       return new AltosCSV(file);
+               } catch (FileNotFoundException fe) {
+                       System.out.printf("Cannot open '%s'\n", filename);
+                       return null;
+               }
+       }
 
+       static AltosWriter open_kml(String filename) {
+               File file = new File (filename);
+               try {
+                       return new AltosKML(file);
+               } catch (FileNotFoundException fe) {
+                       System.out.printf("Cannot open '%s'\n", filename);
+                       return null;
+               }
        }
+
+       static final int process_csv = 1;
+       static final int process_kml = 2;
+
+       static void process_file(String input, int process) {
+               AltosRecordIterable iterable = open_logfile(input);
+               if (iterable == null)
+                       return;
+               if (process == 0)
+                       process = process_csv;
+               if ((process & process_csv) != 0) {
+                       String output = Altos.replace_extension(input,".csv");
+                       System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+                       if (input.equals(output)) {
+                               System.out.printf("Not processing '%s'\n", input);
+                       } else {
+                               AltosWriter writer = open_csv(output);
+                               if (writer != null) {
+                                       writer.write(iterable);
+                                       writer.close();
+                               }
+                       }
+               }
+               if ((process & process_kml) != 0) {
+                       String output = Altos.replace_extension(input,".kml");
+                       System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+                       if (input.equals(output)) {
+                               System.out.printf("Not processing '%s'\n", input);
+                       } else {
+                               AltosWriter writer = open_kml(output);
+                               if (writer == null)
+                                       return;
+                               writer.write(iterable);
+                               writer.close();
+                       }
+               }
+       }
+
        public static void main(final String[] args) {
-               AltosUI altosui = new AltosUI();
-               altosui.setVisible(true);
+               int     process = 0;
+               /* Handle batch-mode */
+        if (args.length == 2 && args[0].equals("--replay")) {
+            String filename = args[1];
+            FileInputStream in;
+            try {
+                in = new FileInputStream(filename);
+            } catch (Exception e) {
+                System.out.printf("Failed to open file '%s'\n", filename);
+                return;
+            }
+            AltosRecordIterable recs;
+            AltosReplayReader reader;
+            if (filename.endsWith("eeprom")) {
+              recs = new AltosEepromIterable(in);
+            } else {
+              recs = new AltosTelemetryIterable(in); 
+            }
+            reader = new AltosReplayReader(recs.iterator(), filename);
+            new AltosFlightUI(new AltosVoice(), reader);
+            return;
+        } else if (args.length > 0) {
+                       for (int i = 0; i < args.length; i++) {
+                               if (args[i].equals("--kml"))
+                                       process |= process_kml;
+                               else if (args[i].equals("--csv"))
+                                       process |= process_csv;
+                               else
+                                       process_file(args[i], process);
+                       }
+               } else {
+                       AltosUI altosui = new AltosUI();
+                       altosui.setVisible(true);
+
+                       AltosDevice[] devices = AltosDevice.list(AltosDevice.product_basestation);
+                       for (int i = 0; i < devices.length; i++)
+                               altosui.telemetry_window(devices[i]);
+               }
        }
-}
\ No newline at end of file
+}