clean up all existing lintian warnings
[fw/altos] / altosui / AltosIdleMonitorUI.java
1 /*
2  * Copyright © 2010 Keith Packard <keithp@keithp.com>
3  *
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.
7  *
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.
12  *
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.
16  */
17
18 package altosui;
19
20 import java.awt.*;
21 import java.awt.event.*;
22 import javax.swing.*;
23 import javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
25 import java.io.*;
26 import java.util.*;
27 import java.text.*;
28 import java.util.prefs.*;
29 import java.util.concurrent.*;
30
31 class AltosADC {
32         int     tick;
33         int     accel;
34         int     pres;
35         int     temp;
36         int     batt;
37         int     drogue;
38         int     main;
39
40         public AltosADC(AltosSerial serial) throws InterruptedException, TimeoutException {
41                 serial.printf("a\n");
42                 for (;;) {
43                         String line = serial.get_reply_no_dialog(5000);
44                         if (line == null) {
45                                 throw new TimeoutException();
46                         }
47                         if (!line.startsWith("tick:"))
48                                 continue;
49                         String[] items = line.split("\\s+");
50                         for (int i = 0; i < items.length;) {
51                                 if (items[i].equals("tick:")) {
52                                         tick = Integer.parseInt(items[i+1]);
53                                         i += 2;
54                                         continue;
55                                 }
56                                 if (items[i].equals("accel:")) {
57                                         accel = Integer.parseInt(items[i+1]);
58                                         i += 2;
59                                         continue;
60                                 }
61                                 if (items[i].equals("pres:")) {
62                                         pres = Integer.parseInt(items[i+1]);
63                                         i += 2;
64                                         continue;
65                                 }
66                                 if (items[i].equals("temp:")) {
67                                         temp = Integer.parseInt(items[i+1]);
68                                         i += 2;
69                                         continue;
70                                 }
71                                 if (items[i].equals("batt:")) {
72                                         batt = Integer.parseInt(items[i+1]);
73                                         i += 2;
74                                         continue;
75                                 }
76                                 if (items[i].equals("drogue:")) {
77                                         drogue = Integer.parseInt(items[i+1]);
78                                         i += 2;
79                                         continue;
80                                 }
81                                 if (items[i].equals("main:")) {
82                                         main = Integer.parseInt(items[i+1]);
83                                         i += 2;
84                                         continue;
85                                 }
86                         }
87                         break;
88                 }
89         }
90 }
91
92 class AltosGPSQuery extends AltosGPS {
93         public AltosGPSQuery (AltosSerial serial) throws TimeoutException, InterruptedException {
94                 serial.printf("g\n");
95                 for (;;) {
96                         String line = serial.get_reply_no_dialog(5000);
97                         if (line == null)
98                                 throw new TimeoutException();
99                         String[] bits = line.split("\\s+");
100                         if (bits.length == 0)
101                                 continue;
102                         if (line.startsWith("Date:")) {
103                                 if (bits.length < 2)
104                                         continue;
105                                 String[] d = bits[1].split(":");
106                                 if (d.length < 3)
107                                         continue;
108                                 year = Integer.parseInt(d[0]) + 2000;
109                                 month = Integer.parseInt(d[1]);
110                                 day = Integer.parseInt(d[2]);
111                                 continue;
112                         }
113                         if (line.startsWith("Time:")) {
114                                 if (bits.length < 2)
115                                         continue;
116                                 String[] d = bits[1].split("/");
117                                 if (d.length < 3)
118                                         continue;
119                                 hour = Integer.parseInt(d[0]);
120                                 minute = Integer.parseInt(d[1]);
121                                 second = Integer.parseInt(d[2]);
122                                 continue;
123                         }
124                         if (line.startsWith("Lat/Lon:")) {
125                                 if (bits.length < 3)
126                                         continue;
127                                 lat = Integer.parseInt(bits[1]) * 1.0e-7;
128                                 lon = Integer.parseInt(bits[2]) * 1.0e-7;
129                                 continue;
130                         }
131                         if (line.startsWith("Alt:")) {
132                                 if (bits.length < 2)
133                                         continue;
134                                 alt = Integer.parseInt(bits[1]);
135                                 continue;
136                         }
137                         if (line.startsWith("Flags:")) {
138                                 if (bits.length < 2)
139                                         continue;
140                                 int status = Integer.decode(bits[1]);
141                                 connected = (status & Altos.AO_GPS_RUNNING) != 0;
142                                 locked = (status & Altos.AO_GPS_VALID) != 0;
143                                 continue;
144                         }
145                         if (line.startsWith("Sats:")) {
146                                 if (bits.length < 2)
147                                         continue;
148                                 nsat = Integer.parseInt(bits[1]);
149                                 cc_gps_sat = new AltosGPSSat[nsat];
150                                 for (int i = 0; i < nsat; i++) {
151                                         int     svid = Integer.parseInt(bits[2+i*2]);
152                                         int     cc_n0 = Integer.parseInt(bits[3+i*2]);
153                                         cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0);
154                                 }
155                         }
156                         if (line.startsWith("done"))
157                                 break;
158                         if (line.startsWith("Syntax error"))
159                                 break;
160                 }
161         }
162 }
163
164 class AltosIdleMonitor extends Thread {
165         AltosDevice             device;
166         AltosSerial             serial;
167         AltosIdleMonitorUI      ui;
168         AltosState              state;
169         boolean                 remote;
170         int                     channel;
171         AltosState              previous_state;
172         AltosConfigData         config_data;
173         AltosADC                adc;
174         AltosGPS                gps;
175
176         void update_state() throws InterruptedException, TimeoutException {
177                 AltosRecord     record = new AltosRecord();
178
179                 try {
180                         if (remote) {
181                                 set_channel(channel);
182                                 serial.start_remote();
183                         } else
184                                 serial.flush_input();
185                         config_data = new AltosConfigData(serial);
186                         adc = new AltosADC(serial);
187                         gps = new AltosGPSQuery(serial);
188                 } finally {
189                         if (remote)
190                                 serial.stop_remote();
191                 }
192
193                 record.version = 0;
194                 record.callsign = config_data.callsign;
195                 record.serial = config_data.serial;
196                 record.flight = 0;
197                 record.rssi = 0;
198                 record.status = 0;
199                 record.state = Altos.ao_flight_idle;
200
201                 record.tick = adc.tick;
202                 record.accel = adc.accel;
203                 record.pres = adc.pres;
204                 record.batt = adc.batt;
205                 record.temp = adc.temp;
206                 record.drogue = adc.drogue;
207                 record.main = adc.main;
208
209                 record.ground_accel = record.accel;
210                 record.ground_pres = record.pres;
211                 record.accel_plus_g = config_data.accel_cal_plus;
212                 record.accel_minus_g = config_data.accel_cal_minus;
213                 record.acceleration = 0;
214                 record.speed = 0;
215                 record.height = 0;
216                 record.gps = gps;
217                 state = new AltosState (record, state);
218         }
219
220         void set_channel(int in_channel) {
221                 channel = in_channel;
222         }
223
224         public void post_state() {
225                 Runnable r = new Runnable() {
226                                 public void run() {
227                                         ui.update(state);
228                                 }
229                         };
230                 SwingUtilities.invokeLater(r);
231         }
232
233         public void run() {
234                 try {
235                         for (;;) {
236                                 try {
237                                         update_state();
238                                         post_state();
239                                 } catch (TimeoutException te) {
240                                 }
241                                 Thread.sleep(1000);
242                         }
243                 } catch (InterruptedException ie) {
244                         serial.close();
245                 }
246         }
247
248         public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote)
249                 throws FileNotFoundException, AltosSerialInUseException {
250                 device = in_device;
251                 ui = in_ui;
252                 serial = new AltosSerial(device);
253                 remote = in_remote;
254                 state = null;
255         }
256 }
257
258 public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay {
259         AltosDevice             device;
260         JTabbedPane             pane;
261         AltosPad                pad;
262         AltosInfoTable          flightInfo;
263         AltosFlightStatus       flightStatus;
264         AltosIdleMonitor        thread;
265         int                     serial;
266         boolean                 remote;
267
268         void stop_display() {
269                 if (thread != null && thread.isAlive()) {
270                         thread.interrupt();
271                         try {
272                                 thread.join();
273                         } catch (InterruptedException ie) {}
274                 }
275                 thread = null;
276         }
277
278         void disconnect() {
279                 stop_display();
280         }
281
282         public void reset() {
283                 pad.reset();
284                 flightInfo.clear();
285         }
286
287         public void show(AltosState state, int crc_errors) {
288                 try {
289                         pad.show(state, crc_errors);
290                         flightStatus.show(state, crc_errors);
291                         flightInfo.show(state, crc_errors);
292                 } catch (Exception e) {
293                         System.out.print("Show exception" + e);
294                 }
295         }
296
297         public void update(AltosState state) {
298                 show (state, 0);
299         }
300
301         Container       bag;
302         JComboBox       channels;
303
304         public AltosIdleMonitorUI(JFrame in_owner) throws FileNotFoundException, AltosSerialInUseException {
305
306                 device = AltosDeviceDialog.show(in_owner, Altos.product_any);
307                 remote = false;
308                 if (!device.matchProduct(Altos.product_telemetrum))
309                         remote = true;
310
311                 serial = device.getSerial();
312                 bag = getContentPane();
313                 bag.setLayout(new GridBagLayout());
314
315                 GridBagConstraints c = new GridBagConstraints();
316
317                 java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
318                 if (imgURL != null)
319                         setIconImage(new ImageIcon(imgURL).getImage());
320
321                 setTitle(String.format("AltOS %s", device.toShortString()));
322
323                 /* Stick channel selector at top of table for telemetry monitoring */
324                 if (remote && serial >= 0) {
325                         // Channel menu
326                         channels = new AltosChannelMenu(AltosPreferences.channel(serial));
327                         channels.addActionListener(new ActionListener() {
328                                 public void actionPerformed(ActionEvent e) {
329                                         int channel = channels.getSelectedIndex();
330                                         thread.set_channel(channel);
331                                 }
332                         });
333                         c.gridx = 0;
334                         c.gridy = 0;
335                         c.insets = new Insets(3, 3, 3, 3);
336                         c.anchor = GridBagConstraints.WEST;
337                         bag.add (channels, c);
338                 }
339
340
341                 /* Flight status is always visible */
342                 flightStatus = new AltosFlightStatus();
343                 c.gridx = 0;
344                 c.gridy = 1;
345                 c.fill = GridBagConstraints.HORIZONTAL;
346                 c.weightx = 1;
347                 c.gridwidth = 2;
348                 bag.add(flightStatus, c);
349                 c.gridwidth = 1;
350
351                 /* The rest of the window uses a tabbed pane to
352                  * show one of the alternate data views
353                  */
354                 pane = new JTabbedPane();
355
356                 pad = new AltosPad();
357                 pane.add("Launch Pad", pad);
358
359                 flightInfo = new AltosInfoTable();
360                 pane.add("Table", new JScrollPane(flightInfo));
361
362                 /* Make the tabbed pane use the rest of the window space */
363                 c.gridx = 0;
364                 c.gridy = 2;
365                 c.fill = GridBagConstraints.BOTH;
366                 c.weightx = 1;
367                 c.weighty = 1;
368                 c.gridwidth = 2;
369                 bag.add(pane, c);
370
371                 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
372                 addWindowListener(new WindowAdapter() {
373                                 @Override
374                                 public void windowClosing(WindowEvent e) {
375                                         disconnect();
376                                         setVisible(false);
377                                         dispose();
378                                 }
379                         });
380
381                 pack();
382                 setVisible(true);
383
384                 thread = new AltosIdleMonitor(this, device, remote);
385
386                 thread.start();
387         }
388 }