Changed package name from altosui to AltosUI
[fw/altos] / altosui / AltosIgniteUI.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 javax.swing.event.*;
26 import java.io.*;
27 import java.util.*;
28 import java.text.*;
29 import java.util.prefs.*;
30 import java.util.concurrent.*;
31 import org.altusmetrum.AltosLib.*;
32
33 public class AltosIgniteUI
34         extends AltosDialog
35         implements ActionListener
36 {
37         AltosDevice     device;
38         JFrame          owner;
39         JLabel          label;
40         JRadioButton    apogee;
41         JLabel          apogee_status_label;
42         JRadioButton    main;
43         JLabel          main_status_label;
44         JToggleButton   arm;
45         JButton         fire;
46         javax.swing.Timer       timer;
47         JButton         close;
48
49         int             apogee_status;
50         int             main_status;
51
52         final static int        timeout = 1 * 1000;
53
54         int             time_remaining;
55         boolean         timer_running;
56
57         LinkedBlockingQueue<String>     command_queue;
58
59         class IgniteHandler implements Runnable {
60                 AltosIgnite     ignite;
61                 JFrame          owner;
62
63                 void send_exception(Exception e) {
64                         final Exception f_e = e;
65                         Runnable r = new Runnable() {
66                                         public void run() {
67                                                 ignite_exception(f_e);
68                                         }
69                                 };
70                         SwingUtilities.invokeLater(r);
71                 }
72
73                 public void run () {
74                         try {
75                                 AltosSerial     serial = new AltosSerial(device);
76                                 serial.set_frame(owner);
77                                 ignite = new AltosIgnite(serial,
78                                                          !device.matchProduct(Altos.product_altimeter));
79
80                         } catch (Exception e) {
81                                 send_exception(e);
82                                 return;
83                         }
84
85                         for (;;) {
86                                 Runnable        r;
87
88                                 try {
89                                         String          command = command_queue.take();
90                                         String          reply = null;
91
92                                         if (command.equals("get_status")) {
93                                                 apogee_status = ignite.status(AltosIgnite.Apogee);
94                                                 main_status = ignite.status(AltosIgnite.Main);
95                                                 reply = "status";
96                                         } else if (command.equals("main")) {
97                                                 ignite.fire(AltosIgnite.Main);
98                                                 reply = "fired";
99                                         } else if (command.equals("apogee")) {
100                                                 ignite.fire(AltosIgnite.Apogee);
101                                                 reply = "fired";
102                                         } else if (command.equals("quit")) {
103                                                 ignite.close();
104                                                 break;
105                                         } else {
106                                                 throw new ParseException(String.format("invalid command %s", command), 0);
107                                         }
108                                         final String f_reply = reply;
109                                         r = new Runnable() {
110                                                         public void run() {
111                                                                 ignite_reply(f_reply);
112                                                         }
113                                                 };
114                                         SwingUtilities.invokeLater(r);
115                                 } catch (Exception e) {
116                                         send_exception(e);
117                                 }
118                         }
119                 }
120
121                 public IgniteHandler(JFrame in_owner) {
122                         owner = in_owner;
123                 }
124         }
125
126         void ignite_exception(Exception e) {
127                 if (e instanceof FileNotFoundException) {
128                         JOptionPane.showMessageDialog(owner,
129                                                       ((FileNotFoundException) e).getMessage(),
130                                                       "Cannot open target device",
131                                                       JOptionPane.ERROR_MESSAGE);
132                 } else if (e instanceof AltosSerialInUseException) {
133                         JOptionPane.showMessageDialog(owner,
134                                                       String.format("Device \"%s\" already in use",
135                                                                     device.toShortString()),
136                                                       "Device in use",
137                                                       JOptionPane.ERROR_MESSAGE);
138                 } else if (e instanceof IOException) {
139                         IOException ee = (IOException) e;
140                         JOptionPane.showMessageDialog(owner,
141                                                       device.toShortString(),
142                                                       ee.getLocalizedMessage(),
143                                                       JOptionPane.ERROR_MESSAGE);
144                 } else {
145                         JOptionPane.showMessageDialog(owner,
146                                                       String.format("Connection to \"%s\" failed",
147                                                                     device.toShortString()),
148                                                       "Connection Failed",
149                                                       JOptionPane.ERROR_MESSAGE);
150                 }
151                 close();
152         }
153
154         void ignite_reply(String reply) {
155                 if (reply.equals("status")) {
156                         set_ignite_status();
157                 } else if (reply.equals("fired")) {
158                         fired();
159                 }
160         }
161
162         void set_arm_text() {
163                 if (arm.isSelected())
164                         arm.setText(String.format("%d", time_remaining));
165                 else
166                         arm.setText("Arm");
167         }
168
169         void start_timer() {
170                 time_remaining = 10;
171                 set_arm_text();
172                 timer_running = true;
173         }
174
175         void stop_timer() {
176                 time_remaining = 0;
177                 arm.setSelected(false);
178                 arm.setEnabled(false);
179                 fire.setEnabled(false);
180                 timer_running = false;
181                 set_arm_text();
182         }
183
184         void cancel () {
185                 apogee.setSelected(false);
186                 main.setSelected(false);
187                 fire.setEnabled(false);
188                 stop_timer();
189         }
190
191         void send_command(String command) {
192                 try {
193                         command_queue.put(command);
194                 } catch (Exception ex) {
195                         ignite_exception(ex);
196                 }
197         }
198
199         boolean getting_status = false;
200
201         boolean visible = false;
202         void set_ignite_status() {
203                 getting_status = false;
204                 apogee_status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(apogee_status)));
205                 main_status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(main_status)));
206                 if (!visible) {
207                         visible = true;
208                         setVisible(true);
209                 }
210         }
211
212         void poll_ignite_status() {
213                 if (!getting_status) {
214                         getting_status = true;
215                         send_command("get_status");
216                 }
217         }
218
219         boolean firing = false;
220
221         void start_fire(String which) {
222                 if (!firing) {
223                         firing = true;
224                         send_command(which);
225                 }
226         }
227
228         void fired() {
229                 firing = false;
230                 cancel();
231         }
232
233         void close() {
234                 send_command("quit");
235                 timer.stop();
236                 setVisible(false);
237                 dispose();
238         }
239
240         void tick_timer() {
241                 if (timer_running) {
242                         --time_remaining;
243                         if (time_remaining <= 0)
244                                 cancel();
245                         else
246                                 set_arm_text();
247                 }
248                 poll_ignite_status();
249         }
250
251         void fire() {
252                 if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
253                         String  igniter = "none";
254                         if (apogee.isSelected() && !main.isSelected())
255                                 igniter = "apogee";
256                         else if (main.isSelected() && !apogee.isSelected())
257                                 igniter = "main";
258                         send_command(igniter);
259                         cancel();
260                 }
261         }
262
263         public void actionPerformed(ActionEvent e) {
264                 String cmd = e.getActionCommand();
265                 if (cmd.equals("apogee") || cmd.equals("main")) {
266                         stop_timer();
267                 }
268
269                 if (cmd.equals("apogee") && apogee.isSelected()) {
270                         main.setSelected(false);
271                         arm.setEnabled(true);
272                 }
273                 if (cmd.equals("main") && main.isSelected()) {
274                         apogee.setSelected(false);
275                         arm.setEnabled(true);
276                 }
277
278                 if (cmd.equals("arm")) {
279                         if (arm.isSelected()) {
280                                 fire.setEnabled(true);
281                                 start_timer();
282                         } else
283                                 cancel();
284                 }
285                 if (cmd.equals("fire"))
286                         fire();
287                 if (cmd.equals("tick"))
288                         tick_timer();
289                 if (cmd.equals("close")) {
290                         close();
291                 }
292         }
293
294         /* A window listener to catch closing events and tell the config code */
295         class ConfigListener extends WindowAdapter {
296                 AltosIgniteUI   ui;
297
298                 public ConfigListener(AltosIgniteUI this_ui) {
299                         ui = this_ui;
300                 }
301
302                 public void windowClosing(WindowEvent e) {
303                         ui.actionPerformed(new ActionEvent(e.getSource(),
304                                                            ActionEvent.ACTION_PERFORMED,
305                                                            "close"));
306                 }
307         }
308
309         private boolean open() {
310                 command_queue = new LinkedBlockingQueue<String>();
311
312                 device = AltosDeviceDialog.show(owner, Altos.product_any);
313                 if (device != null) {
314                                 IgniteHandler   handler = new IgniteHandler(owner);
315                                 Thread          t = new Thread(handler);
316                                 t.start();
317                                 return true;
318                 }
319                 return false;
320         }
321
322         public AltosIgniteUI(JFrame in_owner) {
323
324                 owner = in_owner;
325                 apogee_status = AltosIgnite.Unknown;
326                 main_status = AltosIgnite.Unknown;
327
328                 if (!open())
329                         return;
330
331                 Container               pane = getContentPane();
332                 GridBagConstraints      c = new GridBagConstraints();
333                 Insets                  i = new Insets(4,4,4,4);
334
335                 timer = new javax.swing.Timer(timeout, this);
336                 timer.setActionCommand("tick");
337                 timer_running = false;
338                 timer.restart();
339
340                 owner = in_owner;
341
342                 pane.setLayout(new GridBagLayout());
343
344                 c.fill = GridBagConstraints.NONE;
345                 c.anchor = GridBagConstraints.CENTER;
346                 c.insets = i;
347                 c.weightx = 0;
348                 c.weighty = 0;
349
350                 c.gridx = 0;
351                 c.gridy = 0;
352                 c.gridwidth = 2;
353                 c.anchor = GridBagConstraints.CENTER;
354                 label = new JLabel ("Fire Igniter");
355                 pane.add(label, c);
356
357                 c.gridx = 0;
358                 c.gridy = 1;
359                 c.gridwidth = 1;
360                 c.anchor = GridBagConstraints.WEST;
361                 apogee = new JRadioButton ("Apogee");
362                 pane.add(apogee, c);
363                 apogee.addActionListener(this);
364                 apogee.setActionCommand("apogee");
365
366                 c.gridx = 1;
367                 c.gridy = 1;
368                 c.gridwidth = 1;
369                 c.anchor = GridBagConstraints.WEST;
370                 apogee_status_label = new JLabel();
371                 pane.add(apogee_status_label, c);
372
373                 c.gridx = 0;
374                 c.gridy = 2;
375                 c.gridwidth = 1;
376                 c.anchor = GridBagConstraints.WEST;
377                 main = new JRadioButton ("Main");
378                 pane.add(main, c);
379                 main.addActionListener(this);
380                 main.setActionCommand("main");
381
382                 c.gridx = 1;
383                 c.gridy = 2;
384                 c.gridwidth = 1;
385                 c.anchor = GridBagConstraints.WEST;
386                 main_status_label = new JLabel();
387                 pane.add(main_status_label, c);
388
389                 c.gridx = 0;
390                 c.gridy = 3;
391                 c.gridwidth = 1;
392                 c.anchor = GridBagConstraints.CENTER;
393                 arm = new JToggleButton ("Arm");
394                 pane.add(arm, c);
395                 arm.addActionListener(this);
396                 arm.setActionCommand("arm");
397                 arm.setEnabled(false);
398
399                 c.gridx = 1;
400                 c.gridy = 3;
401                 c.gridwidth = 1;
402                 c.anchor = GridBagConstraints.CENTER;
403                 fire = new JButton ("Fire");
404                 fire.setEnabled(false);
405                 pane.add(fire, c);
406                 fire.addActionListener(this);
407                 fire.setActionCommand("fire");
408
409                 c.gridx = 0;
410                 c.gridy = 4;
411                 c.gridwidth = 2;
412                 c.anchor = GridBagConstraints.CENTER;
413                 close = new JButton ("Close");
414                 pane.add(close, c);
415                 close.addActionListener(this);
416                 close.setActionCommand("close");
417                         
418                 pack();
419                 setLocationRelativeTo(owner);
420
421                 addWindowListener(new ConfigListener(this));
422         }
423 }