2 * Copyright © 2014 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18 package org.altusmetrum.telegps;
21 import java.awt.event.*;
24 import java.util.concurrent.*;
26 import org.altusmetrum.altoslib_4.*;
27 import org.altusmetrum.altosuilib_2.*;
31 implements AltosFlightDisplay, AltosFontListener, AltosUnitsListener, ActionListener
34 static String[] telegps_icon_names = {
43 static { set_icon_names(telegps_icon_names); }
45 static AltosVoice voice;
47 static AltosVoice voice() {
49 voice = new AltosVoice();
53 AltosFlightReader reader;
54 TeleGPSDisplayThread thread;
61 AltosFreqList frequencies;
65 TeleGPSStatus telegps_status;
66 TeleGPSStatusUpdate status_update;
72 TeleGPSState gps_state;
73 AltosInfoTable info_table;
75 LinkedList<AltosFlightDisplay> displays;
78 final static String new_command = "new";
79 final static String graph_command = "graph";
80 final static String export_command = "export";
81 final static String load_maps_command = "loadmaps";
82 final static String preferences_command = "preferences";
83 final static String close_command = "close";
84 final static String exit_command = "exit";
86 static final String[][] file_menu_entries = new String[][] {
87 { "New Window", new_command },
88 { "Graph Data", graph_command },
89 { "Export Data", export_command },
90 { "Load Maps", load_maps_command },
91 { "Preferences", preferences_command },
92 { "Close", close_command },
93 { "Exit", exit_command },
97 final static String connect_command = "connect";
98 final static String disconnect_command = "disconnect";
99 final static String scan_command = "scan";
101 static final String[][] monitor_menu_entries = new String[][] {
102 { "Connect Device", connect_command },
103 { "Disconnect", disconnect_command },
104 { "Scan Channels", scan_command },
108 final static String download_command = "download";
109 final static String configure_command = "configure";
110 final static String flash_command = "flash";
112 static final String[][] device_menu_entries = new String[][] {
113 { "Download Data", download_command },
114 { "Configure Device", configure_command },
115 { "Flash Device", flash_command },
118 void stop_display() {
119 if (thread != null && thread.isAlive()) {
123 } catch (InterruptedException ie) {}
128 public void reset() {
129 for (AltosFlightDisplay display : displays)
133 public void font_size_changed(int font_size) {
134 for (AltosFlightDisplay display : displays)
135 display.font_size_changed(font_size);
138 public void units_changed(boolean imperial_units) {
139 for (AltosFlightDisplay display : displays)
140 display.units_changed(imperial_units);
143 public void show(AltosState state, AltosListenerState listener_state) {
145 status_update.saved_state = state;
148 state = new AltosState();
151 for (AltosFlightDisplay display : displays) {
152 display.show(state, listener_state);
155 } catch (Exception ex) {
156 System.out.printf("Exception %s\n", ex.toString());
157 for (StackTraceElement e : ex.getStackTrace())
158 System.out.printf("%s\n", e.toString());
167 new TeleGPSPreferences(this, voice());
171 new AltosUIMapPreload(this);
177 remove_frequency_menu();
180 void connect(AltosDevice device) {
184 AltosFlightReader reader = new AltosTelemetryReader(new AltosSerial(device));
186 add_frequency_menu(device.getSerial(), reader);
187 } catch (FileNotFoundException ee) {
188 JOptionPane.showMessageDialog(this,
190 String.format ("Cannot open %s", device.toShortString()),
191 JOptionPane.ERROR_MESSAGE);
192 } catch (AltosSerialInUseException si) {
193 JOptionPane.showMessageDialog(this,
194 String.format("Device \"%s\" already in use",
195 device.toShortString()),
197 JOptionPane.ERROR_MESSAGE);
198 } catch (IOException ee) {
199 JOptionPane.showMessageDialog(this,
200 String.format ("Unknown I/O error on %s", device.toShortString()),
202 JOptionPane.ERROR_MESSAGE);
203 } catch (TimeoutException te) {
204 JOptionPane.showMessageDialog(this,
205 String.format ("Timeout on %s", device.toShortString()),
207 JOptionPane.ERROR_MESSAGE);
208 } catch (InterruptedException ie) {
209 JOptionPane.showMessageDialog(this,
210 String.format("Interrupted %s", device.toShortString()),
211 "Interrupted exception",
212 JOptionPane.ERROR_MESSAGE);
217 AltosDevice device = AltosDeviceUIDialog.show(this,
218 AltosLib.product_basestation);
224 public void scan_device_selected(AltosDevice device) {
229 new AltosScanUI(this, false);
233 new AltosEepromManage(this, AltosLib.product_telegps);
237 new TeleGPSConfig(this);
241 AltosDataChooser chooser;
242 chooser = new AltosDataChooser(this);
243 AltosStateIterable states = chooser.runDialog();
246 new AltosCSVUI(this, states, chooser.file());
250 AltosDataChooser chooser;
251 chooser = new AltosDataChooser(this);
252 AltosStateIterable states = chooser.runDialog();
256 new TeleGPSGraphUI(states, chooser.file());
257 } catch (InterruptedException ie) {
258 } catch (IOException ie) {
263 AltosFlashUI.show(this);
266 public void actionPerformed(ActionEvent ev) {
269 if (new_command.equals(ev.getActionCommand())) {
273 if (preferences_command.equals(ev.getActionCommand())) {
277 if (load_maps_command.equals(ev.getActionCommand())) {
281 if (close_command.equals(ev.getActionCommand())) {
285 if (exit_command.equals(ev.getActionCommand()))
289 if (connect_command.equals(ev.getActionCommand())) {
293 if (disconnect_command.equals(ev.getActionCommand())) {
297 if (scan_command.equals(ev.getActionCommand())) {
303 if (download_command.equals(ev.getActionCommand())) {
307 if (configure_command.equals(ev.getActionCommand())) {
311 if (export_command.equals(ev.getActionCommand())) {
315 if (graph_command.equals(ev.getActionCommand())) {
319 if (flash_command.equals(ev.getActionCommand())) {
325 void add_frequency_menu(int serial, final AltosFlightReader reader) {
327 if (frequencies != null)
330 frequencies = new AltosFreqList(AltosUIPreferences.frequency(serial));
331 frequencies.set_product("Monitor");
332 frequencies.set_serial(serial);
333 frequencies.addActionListener(new ActionListener() {
334 public void actionPerformed(ActionEvent e) {
335 double frequency = frequencies.frequency();
337 reader.set_frequency(frequency);
338 } catch (TimeoutException te) {
339 } catch (InterruptedException ie) {
341 reader.save_frequency();
344 menu_bar.add(frequencies);
347 void remove_frequency_menu() {
348 if (frequencies != null) {
349 menu_bar.remove(frequencies);
355 public void set_reader(AltosFlightReader reader) {
356 setTitle(String.format("TeleGPS %s", reader.name));
357 thread = new TeleGPSDisplayThread(this, voice(), this, reader);
361 static int number_of_windows;
363 static public void add_window() {
367 static public void subtract_window() {
369 if (number_of_windows == 0)
373 private void close() {
375 AltosUIPreferences.unregister_font_listener(this);
376 AltosPreferences.unregister_units_listener(this);
382 private void add_menu(JMenu menu, String label, String action) {
383 JMenuItem item = new JMenuItem(label);
385 item.addActionListener(this);
386 item.setActionCommand(action);
390 private JMenu make_menu(String label, String[][] items) {
391 JMenu menu = new JMenu(label);
392 for (int i = 0; i < items.length; i++)
393 add_menu(menu, items[i][0], items[i][1]);
400 AltosUIPreferences.set_component(this);
404 bag = getContentPane();
405 bag.setLayout(new GridBagLayout());
407 GridBagConstraints c = new GridBagConstraints();
411 menu_bar = new JMenuBar();
412 setJMenuBar(menu_bar);
414 file_menu = make_menu("File", file_menu_entries);
415 monitor_menu = make_menu("Monitor", monitor_menu_entries);
416 device_menu = make_menu("Device", device_menu_entries);
417 displays = new LinkedList<AltosFlightDisplay>();
421 /* TeleGPS status is always visible */
422 telegps_status = new TeleGPSStatus();
425 c.fill = GridBagConstraints.HORIZONTAL;
428 bag.add(telegps_status, c);
430 displays.add(telegps_status);
433 /* The rest of the window uses a tabbed pane to
434 * show one of the alternate data views
436 pane = new JTabbedPane();
438 /* Make the tabbed pane use the rest of the window space */
441 c.fill = GridBagConstraints.BOTH;
447 map = new AltosUIMap();
448 pane.add(map.getName(), map);
451 gps_info = new TeleGPSInfo();
452 pane.add(gps_info.getName(), gps_info);
453 displays.add(gps_info);
455 gps_state = new TeleGPSState();
456 pane.add(gps_state.getName(), gps_state);
457 displays.add(gps_state);
459 info_table = new AltosInfoTable();
460 pane.add("Table", info_table);
461 displays.add(info_table);
463 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
465 AltosUIPreferences.register_font_listener(this);
466 AltosPreferences.register_units_listener(this);
468 addWindowListener(new WindowAdapter() {
470 public void windowClosing(WindowEvent e) {
480 status_update = new TeleGPSStatusUpdate(telegps_status);
482 new javax.swing.Timer(100, status_update).start();
485 public TeleGPS(AltosFlightReader reader) {
490 public TeleGPS(AltosDevice device) {
495 static AltosStateIterable record_iterable(File file) {
498 in = new FileInputStream(file);
499 } catch (Exception e) {
500 System.out.printf("Failed to open file '%s'\n", file);
503 if (file.getName().endsWith("telem"))
504 return new AltosTelemetryFile(in);
506 return new AltosEepromFile(in);
509 static AltosReplayReader replay_file(File file) {
510 AltosStateIterable states = record_iterable(file);
513 return new AltosReplayReader(states.iterator(), file);
516 static boolean process_graph(File file) {
517 AltosStateIterable states = record_iterable(file);
521 new TeleGPSGraphUI(states, file);
522 } catch (Exception e) {
528 static boolean process_replay(File file) {
529 AltosReplayReader new_reader = replay_file(file);
530 if (new_reader == null)
533 new TeleGPS(new_reader);
537 static final int process_none = 0;
538 static final int process_csv = 1;
539 static final int process_kml = 2;
540 static final int process_graph = 3;
541 static final int process_replay = 4;
542 static final int process_summary = 5;
543 static final int process_cat = 6;
545 public static boolean load_library(Frame frame) {
546 if (!AltosUILib.load_library()) {
547 JOptionPane.showMessageDialog(frame,
548 String.format("No AltOS library in \"%s\"",
549 System.getProperty("java.library.path","<undefined>")),
550 "Cannot load device access library",
551 JOptionPane.ERROR_MESSAGE);
557 public static void help(int code) {
558 System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
559 System.out.printf(" Options:\n");
560 System.out.printf(" --fetchmaps <lat> <lon>\tpre-fetch maps for site map view\n");
561 System.out.printf(" --replay <filename>\t\trelive the glory of past flights \n");
562 System.out.printf(" --graph <filename>\t\tgraph a flight\n");
563 System.out.printf(" --csv\tgenerate comma separated output for spreadsheets, etc\n");
564 System.out.printf(" --kml\tgenerate KML output for use with Google Earth\n");
568 public static void main(String[] args) {
573 UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel());
574 } catch (Exception e) {
577 boolean any_created = false;
580 /* Handle batch-mode */
581 int process = process_none;
582 for (int i = 0; i < args.length; i++) {
583 if (args[i].equals("--help"))
585 else if (args[i].equals("--fetchmaps")) {
586 if (args.length < i + 3) {
589 double lat = Double.parseDouble(args[i+1]);
590 double lon = Double.parseDouble(args[i+2]);
591 AltosUIMap.prefetch_maps(lat, lon);
594 } else if (args[i].equals("--replay"))
595 process = process_replay;
596 else if (args[i].equals("--kml"))
597 process = process_kml;
598 else if (args[i].equals("--csv"))
599 process = process_csv;
600 else if (args[i].equals("--graph"))
601 process = process_graph;
602 else if (args[i].equals("--summary"))
603 process = process_summary;
604 else if (args[i].equals("--cat"))
605 process = process_cat;
606 else if (args[i].startsWith("--"))
609 File file = new File(args[i]);
613 if (!process_graph(file))
617 if (!process_replay(file))
627 case process_summary:
637 if (number_of_windows == 0) {
638 java.util.List<AltosDevice> devices = AltosUSBDevice.list(AltosLib.product_basestation);
640 for (AltosDevice device : devices) {
644 if (number_of_windows == 0)