2 * Copyright © 2010 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.
21 import java.awt.event.*;
23 import javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
28 import java.util.prefs.*;
29 import java.util.concurrent.*;
30 import org.altusmetrum.AltosLib.*;
41 public AltosADC(AltosSerial serial) throws InterruptedException, TimeoutException {
44 String line = serial.get_reply_no_dialog(5000);
46 throw new TimeoutException();
48 if (!line.startsWith("tick:"))
50 String[] items = line.split("\\s+");
51 for (int i = 0; i < items.length;) {
52 if (items[i].equals("tick:")) {
53 tick = Integer.parseInt(items[i+1]);
57 if (items[i].equals("accel:")) {
58 accel = Integer.parseInt(items[i+1]);
62 if (items[i].equals("pres:")) {
63 pres = Integer.parseInt(items[i+1]);
67 if (items[i].equals("temp:")) {
68 temp = Integer.parseInt(items[i+1]);
72 if (items[i].equals("batt:")) {
73 batt = Integer.parseInt(items[i+1]);
77 if (items[i].equals("drogue:")) {
78 drogue = Integer.parseInt(items[i+1]);
82 if (items[i].equals("main:")) {
83 main = Integer.parseInt(items[i+1]);
93 class AltosGPSQuery extends AltosGPS {
94 public AltosGPSQuery (AltosSerial serial, AltosConfigData config_data)
95 throws TimeoutException, InterruptedException {
96 boolean says_done = config_data.compare_version("1.0") >= 0;
99 String line = serial.get_reply_no_dialog(5000);
101 throw new TimeoutException();
102 String[] bits = line.split("\\s+");
103 if (bits.length == 0)
105 if (line.startsWith("Date:")) {
108 String[] d = bits[1].split(":");
111 year = Integer.parseInt(d[0]) + 2000;
112 month = Integer.parseInt(d[1]);
113 day = Integer.parseInt(d[2]);
116 if (line.startsWith("Time:")) {
119 String[] d = bits[1].split("/");
122 hour = Integer.parseInt(d[0]);
123 minute = Integer.parseInt(d[1]);
124 second = Integer.parseInt(d[2]);
127 if (line.startsWith("Lat/Lon:")) {
130 lat = Integer.parseInt(bits[1]) * 1.0e-7;
131 lon = Integer.parseInt(bits[2]) * 1.0e-7;
134 if (line.startsWith("Alt:")) {
137 alt = Integer.parseInt(bits[1]);
140 if (line.startsWith("Flags:")) {
143 int status = Integer.decode(bits[1]);
144 connected = (status & Altos.AO_GPS_RUNNING) != 0;
145 locked = (status & Altos.AO_GPS_VALID) != 0;
150 if (line.startsWith("Sats:")) {
153 nsat = Integer.parseInt(bits[1]);
154 cc_gps_sat = new AltosGPSSat[nsat];
155 for (int i = 0; i < nsat; i++) {
156 int svid = Integer.parseInt(bits[2+i*2]);
157 int cc_n0 = Integer.parseInt(bits[3+i*2]);
158 cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0);
161 if (line.startsWith("done"))
163 if (line.startsWith("Syntax error"))
169 class AltosIdleMonitor extends Thread {
172 AltosIdleMonitorUI ui;
176 AltosState previous_state;
177 AltosConfigData config_data;
181 int AltosRSSI() throws TimeoutException, InterruptedException {
182 serial.printf("s\n");
183 String line = serial.get_reply_no_dialog(5000);
185 throw new TimeoutException();
186 String[] items = line.split("\\s+");
187 if (items.length < 2)
189 if (!items[0].equals("RSSI:"))
191 int rssi = Integer.parseInt(items[1]);
195 void update_state() throws InterruptedException, TimeoutException {
196 AltosRecordTM record = new AltosRecordTM();
201 serial.set_radio_frequency(frequency);
202 serial.start_remote();
204 serial.flush_input();
205 config_data = new AltosConfigData(serial);
206 adc = new AltosADC(serial);
207 gps = new AltosGPSQuery(serial, config_data);
210 serial.stop_remote();
217 record.callsign = config_data.callsign;
218 record.serial = config_data.serial;
219 record.flight = config_data.log_available() > 0 ? 255 : 0;
222 record.state = Altos.ao_flight_idle;
224 record.tick = adc.tick;
226 record.accel = adc.accel;
227 record.pres = adc.pres;
228 record.batt = adc.batt;
229 record.temp = adc.temp;
230 record.drogue = adc.drogue;
231 record.main = adc.main;
233 record.ground_accel = record.accel;
234 record.ground_pres = record.pres;
235 record.accel_plus_g = config_data.accel_cal_plus;
236 record.accel_minus_g = config_data.accel_cal_minus;
237 record.acceleration = 0;
241 state = new AltosState (record, state);
244 void set_frequency(double in_frequency) {
245 frequency = in_frequency;
248 public void post_state() {
249 Runnable r = new Runnable() {
254 SwingUtilities.invokeLater(r);
263 } catch (TimeoutException te) {
264 if (AltosSerial.debug)
265 System.out.printf ("monitor idle data timeout\n");
269 } catch (InterruptedException ie) {
274 public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote)
275 throws FileNotFoundException, AltosSerialInUseException, InterruptedException, TimeoutException {
278 serial = new AltosSerial(device);
284 public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener {
288 AltosInfoTable flightInfo;
289 AltosFlightStatus flightStatus;
290 AltosIdleMonitor thread;
294 void stop_display() {
295 if (thread != null && thread.isAlive()) {
299 } catch (InterruptedException ie) {}
308 public void reset() {
313 public void set_font() {
315 flightInfo.set_font();
318 public void font_size_changed(int font_size) {
322 AltosFlightStatusUpdate status_update;
324 public void show(AltosState state, int crc_errors) {
325 status_update.saved_state = state;
327 pad.show(state, crc_errors);
328 flightStatus.show(state, crc_errors);
329 flightInfo.show(state, crc_errors);
330 } catch (Exception e) {
331 System.out.print("Show exception" + e);
335 public void update(AltosState state) {
340 AltosFreqList frequencies;
342 public AltosIdleMonitorUI(JFrame in_owner)
343 throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException {
345 device = AltosDeviceDialog.show(in_owner, Altos.product_any);
347 if (!device.matchProduct(Altos.product_altimeter))
350 serial = device.getSerial();
351 bag = getContentPane();
352 bag.setLayout(new GridBagLayout());
354 GridBagConstraints c = new GridBagConstraints();
356 java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
358 setIconImage(new ImageIcon(imgURL).getImage());
360 setTitle(String.format("AltOS %s", device.toShortString()));
362 /* Stick frequency selector at top of table for telemetry monitoring */
363 if (remote && serial >= 0) {
365 frequencies = new AltosFreqList(AltosUIPreferences.frequency(serial));
366 frequencies.addActionListener(new ActionListener() {
367 public void actionPerformed(ActionEvent e) {
368 double frequency = frequencies.frequency();
369 thread.set_frequency(frequency);
370 AltosUIPreferences.set_frequency(device.getSerial(),
376 c.insets = new Insets(3, 3, 3, 3);
377 c.anchor = GridBagConstraints.WEST;
378 bag.add (frequencies, c);
382 /* Flight status is always visible */
383 flightStatus = new AltosFlightStatus();
386 c.fill = GridBagConstraints.HORIZONTAL;
389 bag.add(flightStatus, c);
392 /* The rest of the window uses a tabbed pane to
393 * show one of the alternate data views
395 pane = new JTabbedPane();
397 pad = new AltosPad();
398 pane.add("Launch Pad", pad);
400 flightInfo = new AltosInfoTable();
401 pane.add("Table", new JScrollPane(flightInfo));
403 /* Make the tabbed pane use the rest of the window space */
406 c.fill = GridBagConstraints.BOTH;
412 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
414 AltosUIPreferences.register_font_listener(this);
416 addWindowListener(new WindowAdapter() {
418 public void windowClosing(WindowEvent e) {
422 AltosUIPreferences.unregister_font_listener(AltosIdleMonitorUI.this);
429 thread = new AltosIdleMonitor(this, device, remote);
431 status_update = new AltosFlightStatusUpdate(flightStatus);
433 new javax.swing.Timer(100, status_update).start();