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.*;
29 public class TeleGPS extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener, ActionListener {
31 static String[] telegps_icon_names = {
40 static { set_icon_names(telegps_icon_names); }
42 static AltosVoice voice;
44 static AltosVoice voice() {
46 voice = new AltosVoice();
50 AltosFlightReader reader;
51 AltosDisplayThread thread;
64 final static String new_command = "new";
65 final static String preferences_command = "preferences";
66 final static String load_maps_command = "loadmaps";
67 final static String close_command = "close";
68 final static String exit_command = "exit";
70 static final String[][] file_menu_entries = new String[][] {
71 { "New Window", new_command },
72 { "Preferences", preferences_command },
73 { "Load Maps", load_maps_command },
74 { "Close", close_command },
75 { "Exit", exit_command },
79 final static String monitor_command = "monitor";
80 final static String disconnect_command = "disconnect";
81 final static String scan_command = "scan";
83 static final String[][] monitor_menu_entries = new String[][] {
84 { "Monitor Device", monitor_command },
85 { "Disconnect", disconnect_command },
86 { "Scan Channels", scan_command },
90 final static String download_command = "download";
91 final static String configure_command = "configure";
92 final static String export_command = "export";
93 final static String graph_command = "graph";
95 static final String[][] device_menu_entries = new String[][] {
96 { "Download Data", download_command },
97 { "Configure Device", configure_command },
98 { "Export Data", export_command },
99 { "Graph Data", graph_command },
102 // private AltosInfoTable flightInfo;
104 boolean exit_on_close = false;
106 void stop_display() {
107 if (thread != null && thread.isAlive()) {
111 } catch (InterruptedException ie) {}
116 public void reset() {
120 public void set_font() {
124 public void font_size_changed(int font_size) {
129 // AltosFlightStatusUpdate status_update;
131 public void show(AltosState state, AltosListenerState listener_state) {
132 // status_update.saved_state = state;
135 state = new AltosState();
137 sitemap.show(state, listener_state);
138 telegps_status.show(state, listener_state);
142 AltosFreqList frequencies;
144 TeleGPSStatus telegps_status;
145 TeleGPSStatusUpdate status_update;
147 ActionListener show_timer;
154 new TeleGPSPreferences(this, voice());
158 new AltosSiteMapPreload(this);
164 remove_frequency_menu();
167 void connect(AltosDevice device) {
171 AltosFlightReader reader = new AltosTelemetryReader(new AltosSerial(device));
173 add_frequency_menu(device.getSerial(), reader);
174 } catch (FileNotFoundException ee) {
175 JOptionPane.showMessageDialog(this,
177 String.format ("Cannot open %s", device.toShortString()),
178 JOptionPane.ERROR_MESSAGE);
179 } catch (AltosSerialInUseException si) {
180 JOptionPane.showMessageDialog(this,
181 String.format("Device \"%s\" already in use",
182 device.toShortString()),
184 JOptionPane.ERROR_MESSAGE);
185 } catch (IOException ee) {
186 JOptionPane.showMessageDialog(this,
187 String.format ("Unknown I/O error on %s", device.toShortString()),
189 JOptionPane.ERROR_MESSAGE);
190 } catch (TimeoutException te) {
191 JOptionPane.showMessageDialog(this,
192 String.format ("Timeout on %s", device.toShortString()),
194 JOptionPane.ERROR_MESSAGE);
195 } catch (InterruptedException ie) {
196 JOptionPane.showMessageDialog(this,
197 String.format("Interrupted %s", device.toShortString()),
198 "Interrupted exception",
199 JOptionPane.ERROR_MESSAGE);
204 AltosDevice device = AltosDeviceUIDialog.show(this,
205 AltosLib.product_basestation);
211 public void scan_device_selected(AltosDevice device) {
216 new AltosScanUI(this, false);
220 new AltosEepromManage(this, AltosLib.product_telegps);
224 new TeleGPSConfig(this);
233 public void actionPerformed(ActionEvent ev) {
236 if (new_command.equals(ev.getActionCommand())) {
240 if (preferences_command.equals(ev.getActionCommand())) {
244 if (load_maps_command.equals(ev.getActionCommand())) {
248 if (close_command.equals(ev.getActionCommand())) {
252 if (exit_command.equals(ev.getActionCommand()))
256 if (monitor_command.equals(ev.getActionCommand())) {
260 if (disconnect_command.equals(ev.getActionCommand())) {
264 if (scan_command.equals(ev.getActionCommand())) {
270 if (download_command.equals(ev.getActionCommand())) {
274 if (configure_command.equals(ev.getActionCommand())) {
278 if (export_command.equals(ev.getActionCommand())) {
282 if (graph_command.equals(ev.getActionCommand())) {
288 void add_frequency_menu(int serial, final AltosFlightReader reader) {
290 frequencies = new AltosFreqList(AltosUIPreferences.frequency(serial));
291 frequencies.set_product("Monitor");
292 frequencies.set_serial(serial);
293 frequencies.addActionListener(new ActionListener() {
294 public void actionPerformed(ActionEvent e) {
295 double frequency = frequencies.frequency();
297 reader.set_frequency(frequency);
298 } catch (TimeoutException te) {
299 } catch (InterruptedException ie) {
301 reader.save_frequency();
304 menu_bar.add(frequencies);
307 void remove_frequency_menu() {
308 if (frequencies != null) {
309 menu_bar.remove(frequencies);
314 public void set_reader(AltosFlightReader reader) {
315 setTitle(String.format("TeleGPS %s", reader.name));
316 thread = new AltosDisplayThread(this, voice(), this, reader);
320 static int number_of_windows;
322 private void close() {
323 AltosUIPreferences.unregister_font_listener(this);
327 if (number_of_windows == 0)
331 private void add_menu(JMenu menu, String label, String action) {
332 JMenuItem item = new JMenuItem(label);
334 item.addActionListener(this);
335 item.setActionCommand(action);
339 private JMenu make_menu(String label, String[][] items) {
340 JMenu menu = new JMenu(label);
341 for (int i = 0; i < items.length; i++)
342 add_menu(menu, items[i][0], items[i][1]);
349 AltosUIPreferences.set_component(this);
353 bag = getContentPane();
354 bag.setLayout(new GridBagLayout());
356 GridBagConstraints c = new GridBagConstraints();
360 menu_bar = new JMenuBar();
361 setJMenuBar(menu_bar);
363 file_menu = make_menu("File", file_menu_entries);
364 monitor_menu = make_menu("Monitor", monitor_menu_entries);
365 device_menu = make_menu("Device", device_menu_entries);
369 /* TeleGPS status is always visible */
370 telegps_status = new TeleGPSStatus();
373 c.fill = GridBagConstraints.HORIZONTAL;
376 bag.add(telegps_status, c);
380 /* The rest of the window uses a tabbed pane to
381 * show one of the alternate data views
383 pane = new JTabbedPane();
385 /* Make the tabbed pane use the rest of the window space */
388 c.fill = GridBagConstraints.BOTH;
394 sitemap = new AltosSiteMap();
395 pane.add("Site Map", sitemap);
397 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
399 AltosUIPreferences.register_font_listener(this);
401 addWindowListener(new WindowAdapter() {
403 public void windowClosing(WindowEvent e) {
413 status_update = new TeleGPSStatusUpdate(telegps_status);
415 new javax.swing.Timer(100, status_update).start();
418 public TeleGPS(AltosFlightReader reader) {
423 static AltosStateIterable record_iterable(File file) {
426 in = new FileInputStream(file);
427 } catch (Exception e) {
428 System.out.printf("Failed to open file '%s'\n", file);
431 if (file.getName().endsWith("telem"))
432 return new AltosTelemetryFile(in);
434 return new AltosEepromFile(in);
437 static AltosReplayReader replay_file(File file) {
438 AltosStateIterable states = record_iterable(file);
441 return new AltosReplayReader(states.iterator(), file);
444 static boolean process_replay(File file) {
445 AltosReplayReader new_reader = replay_file(file);
446 if (new_reader == null)
449 new TeleGPS(new_reader);
453 static final int process_none = 0;
454 static final int process_csv = 1;
455 static final int process_kml = 2;
456 static final int process_graph = 3;
457 static final int process_replay = 4;
458 static final int process_summary = 5;
459 static final int process_cat = 6;
461 public static boolean load_library(Frame frame) {
462 if (!AltosUILib.load_library()) {
463 JOptionPane.showMessageDialog(frame,
464 String.format("No AltOS library in \"%s\"",
465 System.getProperty("java.library.path","<undefined>")),
466 "Cannot load device access library",
467 JOptionPane.ERROR_MESSAGE);
473 public static void help(int code) {
474 System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
475 System.out.printf(" Options:\n");
476 System.out.printf(" --fetchmaps <lat> <lon>\tpre-fetch maps for site map view\n");
477 System.out.printf(" --replay <filename>\t\trelive the glory of past flights \n");
478 System.out.printf(" --graph <filename>\t\tgraph a flight\n");
479 System.out.printf(" --csv\tgenerate comma separated output for spreadsheets, etc\n");
480 System.out.printf(" --kml\tgenerate KML output for use with Google Earth\n");
484 public static void main(String[] args) {
489 UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel());
490 } catch (Exception e) {
493 boolean any_created = false;
496 /* Handle batch-mode */
497 int process = process_none;
498 for (int i = 0; i < args.length; i++) {
499 if (args[i].equals("--help"))
501 else if (args[i].equals("--fetchmaps")) {
502 if (args.length < i + 3) {
505 double lat = Double.parseDouble(args[i+1]);
506 double lon = Double.parseDouble(args[i+2]);
507 AltosSiteMap.prefetchMaps(lat, lon);
510 } else if (args[i].equals("--replay"))
511 process = process_replay;
512 else if (args[i].equals("--kml"))
513 process = process_kml;
514 else if (args[i].equals("--csv"))
515 process = process_csv;
516 else if (args[i].equals("--graph"))
517 process = process_graph;
518 else if (args[i].equals("--summary"))
519 process = process_summary;
520 else if (args[i].equals("--cat"))
521 process = process_cat;
522 else if (args[i].startsWith("--"))
525 File file = new File(args[i]);
532 if (!process_replay(file))
542 case process_summary: