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