altosui: Add TeleMini v3.0 and EasyMini v2.0 firmware to windows package
[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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 package altosui;
20
21 import java.awt.*;
22 import java.awt.event.*;
23 import javax.swing.*;
24 import java.io.*;
25 import java.text.*;
26 import java.util.*;
27 import java.util.concurrent.*;
28 import org.altusmetrum.altoslib_11.*;
29 import org.altusmetrum.altosuilib_11.*;
30
31 public class AltosIgniteUI
32         extends AltosUIDialog
33         implements ActionListener
34 {
35         AltosDevice     device;
36         JFrame          owner;
37         JLabel          label;
38         JToggleButton   arm;
39         JButton         fire;
40         javax.swing.Timer       timer;
41         JButton         close;
42         ButtonGroup     group;
43         Boolean         opened;
44
45         int             npyro;
46
47         final static int        timeout = 1 * 1000;
48
49         int             time_remaining;
50         boolean         timer_running;
51
52         int             poll_remaining;
53
54         LinkedBlockingQueue<String>     command_queue;
55
56         class Igniter {
57                 JRadioButton    button;
58                 JLabel          status_label;
59                 String          name;
60                 int             status;
61
62                 void set_status (int status) {
63                         this.status = status;
64                         status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(status)));
65                 }
66
67                 Igniter(AltosIgniteUI ui, String label, String name, int y) {
68                         Container               pane = getContentPane();
69                         GridBagConstraints      c = new GridBagConstraints();
70                         Insets                  i = new Insets(4,4,4,4);
71
72                         this.name = name;
73                         this.status = AltosIgnite.Unknown;
74
75                         c.gridx = 0;
76                         c.gridy = y;
77                         c.gridwidth = 1;
78                         c.anchor = GridBagConstraints.WEST;
79                         button = new JRadioButton (label);
80                         pane.add(button, c);
81                         button.addActionListener(ui);
82                         button.setActionCommand(name);
83                         group.add(button);
84
85                         c.gridx = 1;
86                         c.gridy = y;
87                         c.gridwidth = 1;
88                         c.anchor = GridBagConstraints.WEST;
89                         status_label = new JLabel("plenty of text");
90                         pane.add(status_label, c);
91
92                         status = AltosIgnite.Unknown;
93                 }
94         }
95
96         Igniter igniters[];
97
98         void set_status(String _name, int _status) {
99
100                 final String name = _name;
101                 final int status = _status;
102                 Runnable r = new Runnable() {
103                                 public void run() {
104                                         for (int p = 0; p < igniters.length; p++)
105                                                 if (name.equals(igniters[p].name))
106                                                         igniters[p].set_status(status);
107                                 }
108                         };
109                 SwingUtilities.invokeLater(r);
110         }
111
112         class IgniteHandler implements Runnable {
113                 AltosIgnite     ignite;
114                 JFrame          owner;
115                 AltosLink       link;
116
117                 void send_exception(Exception e) {
118                         final Exception f_e = e;
119                         Runnable r = new Runnable() {
120                                         public void run() {
121                                                 ignite_exception(f_e);
122                                         }
123                                 };
124                         SwingUtilities.invokeLater(r);
125                 }
126
127                 public void run () {
128                         try {
129                                 ignite = new AltosIgnite(link,
130                                                          !device.matchProduct(Altos.product_altimeter));
131
132                         } catch (Exception e) {
133                                 send_exception(e);
134                                 return;
135                         }
136
137                         for (;;) {
138                                 Runnable        r;
139
140                                 try {
141                                         String          command = command_queue.take();
142                                         String          reply = null;
143
144                                         if (command.equals("get_status")) {
145                                                 HashMap<String,Integer> status_map = ignite.status();
146
147                                                 for (int p = 0; p < igniters.length; p++) {
148                                                         Integer i = status_map.get(igniters[p].name);
149                                                         if (i != null)
150                                                                 set_status(igniters[p].name, i);
151                                                 }
152                                                 reply = "status";
153                                         } else if (command.equals("get_npyro")) {
154                                                 reply = String.format("npyro %d", ignite.npyro());
155                                         } else if (command.equals("quit")) {
156                                                 ignite.close();
157                                                 break;
158                                         } else {
159                                                 ignite.fire(command);
160                                                 reply = "fired";
161                                         }
162                                         final String f_reply = reply;
163                                         r = new Runnable() {
164                                                         public void run() {
165                                                                 ignite_reply(f_reply);
166                                                         }
167                                                 };
168                                         SwingUtilities.invokeLater(r);
169                                 } catch (Exception e) {
170                                         send_exception(e);
171                                 }
172                         }
173                 }
174
175                 public IgniteHandler(JFrame in_owner, AltosLink in_link) {
176                         owner = in_owner;
177                         link = in_link;
178                 }
179         }
180
181         void ignite_exception(Exception e) {
182                 if (e instanceof FileNotFoundException) {
183                         JOptionPane.showMessageDialog(owner,
184                                                       ((FileNotFoundException) e).getMessage(),
185                                                       "Cannot open target device",
186                                                       JOptionPane.ERROR_MESSAGE);
187                 } else if (e instanceof AltosSerialInUseException) {
188                         JOptionPane.showMessageDialog(owner,
189                                                       String.format("Device \"%s\" already in use",
190                                                                     device.toShortString()),
191                                                       "Device in use",
192                                                       JOptionPane.ERROR_MESSAGE);
193                 } else if (e instanceof IOException) {
194                         IOException ee = (IOException) e;
195                         JOptionPane.showMessageDialog(owner,
196                                                       device.toShortString(),
197                                                       ee.getLocalizedMessage(),
198                                                       JOptionPane.ERROR_MESSAGE);
199                 } else {
200                         JOptionPane.showMessageDialog(owner,
201                                                       String.format("Connection to \"%s\" failed",
202                                                                     device.toShortString()),
203                                                       "Connection Failed",
204                                                       JOptionPane.ERROR_MESSAGE);
205                 }
206                 close();
207         }
208
209         void ignite_reply(String reply) {
210                 if (reply.equals("status")) {
211                         set_ignite_status();
212                 } else if (reply.equals("fired")) {
213                         fired();
214                 } else if (reply.startsWith("npyro")) {
215                         npyro = Integer.parseInt(reply.substring(6));
216                         make_ui();
217                 }
218         }
219
220         void set_arm_text() {
221                 if (arm.isSelected())
222                         arm.setText(String.format("%d", time_remaining));
223                 else
224                         arm.setText("Arm");
225         }
226
227         void start_timer() {
228                 time_remaining = 10;
229                 set_arm_text();
230                 timer_running = true;
231         }
232
233         void stop_timer() {
234                 time_remaining = 0;
235                 fire.setEnabled(false);
236                 timer_running = false;
237                 arm.setSelected(false);
238                 arm.setEnabled(false);
239                 set_arm_text();
240         }
241
242         void cancel () {
243                 group.clearSelection();
244                 fire.setEnabled(false);
245                 stop_timer();
246         }
247
248         void send_command(String command) {
249                 try {
250                         command_queue.put(command);
251                 } catch (Exception ex) {
252                         ignite_exception(ex);
253                 }
254         }
255
256         boolean getting_status = false;
257
258         boolean visible = false;
259
260         void set_ignite_status() {
261                 getting_status = false;
262                 poll_remaining = 2;
263                 if (!visible) {
264                         visible = true;
265                         setVisible(true);
266                 }
267         }
268
269         void poll_ignite_status() {
270                 if (poll_remaining > 0) {
271                         --poll_remaining;
272                         return;
273                 }
274                 if (!getting_status) {
275                         getting_status = true;
276                         send_command("get_status");
277                 }
278         }
279
280         boolean firing = false;
281
282         void start_fire(String which) {
283                 if (!firing) {
284                         firing = true;
285                         send_command(which);
286                 }
287         }
288
289         void fired() {
290                 firing = false;
291                 cancel();
292         }
293
294         void close() {
295                 if (opened) {
296                         send_command("quit");
297                 }
298                 if (timer != null)
299                         timer.stop();
300                 setVisible(false);
301                 dispose();
302         }
303
304         void tick_timer() {
305                 if (timer_running) {
306                         --time_remaining;
307                         if (time_remaining <= 0)
308                                 cancel();
309                         else
310                                 set_arm_text();
311                 }
312                 poll_ignite_status();
313         }
314
315         void fire() {
316                 if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
317                         String  igniter = "none";
318
319                         for (int p = 0; p < igniters.length; p++)
320                                 if (igniters[p].button.isSelected()) {
321                                         igniter = igniters[p].name;
322                                         break;
323                                 }
324                         send_command(igniter);
325                         cancel();
326                 }
327         }
328
329         public void actionPerformed(ActionEvent e) {
330                 String cmd = e.getActionCommand();
331
332                 for (int p = 0; p < igniters.length; p++)
333                         if (cmd.equals(igniters[p].name)) {
334                                 stop_timer();
335                                 arm.setEnabled(true);
336                                 break;
337                         }
338
339                 if (cmd.equals("arm")) {
340                         if (arm.isSelected()) {
341                                 fire.setEnabled(true);
342                                 start_timer();
343                         } else
344                                 cancel();
345                 }
346                 if (cmd.equals("fire"))
347                         fire();
348                 if (cmd.equals("tick"))
349                         tick_timer();
350                 if (cmd.equals("close"))
351                         close();
352         }
353
354         /* A window listener to catch closing events and tell the config code */
355         class ConfigListener extends WindowAdapter {
356                 AltosIgniteUI   ui;
357
358                 public ConfigListener(AltosIgniteUI this_ui) {
359                         ui = this_ui;
360                 }
361
362                 public void windowClosing(WindowEvent e) {
363                         ui.actionPerformed(new ActionEvent(e.getSource(),
364                                                            ActionEvent.ACTION_PERFORMED,
365                                                            "close"));
366                 }
367         }
368
369         private boolean open() {
370                 command_queue = new LinkedBlockingQueue<String>();
371
372                 opened = false;
373                 device = AltosDeviceUIDialog.show(owner, Altos.product_any);
374                 if (device != null) {
375                         try {
376                                 AltosSerial     serial = new AltosSerial(device);
377                                 serial.set_frame(owner);
378                                 IgniteHandler   handler = new IgniteHandler(owner, serial);
379                                 Thread          t = new Thread(handler);
380                                 t.start();
381                                 opened = true;
382                                 return true;
383                         } catch (Exception ex) {
384                                 ignite_exception(ex);
385                         }
386                 }
387                 return false;
388         }
389
390         private void make_ui() {
391                 group = new ButtonGroup();
392
393                 Container               pane = getContentPane();
394
395                 GridBagConstraints      c = new GridBagConstraints();
396                 Insets                  i = new Insets(4,4,4,4);
397
398                 timer = new javax.swing.Timer(timeout, this);
399                 timer.setActionCommand("tick");
400                 timer_running = false;
401                 timer.restart();
402
403                 pane.setLayout(new GridBagLayout());
404
405                 c.fill = GridBagConstraints.NONE;
406                 c.anchor = GridBagConstraints.CENTER;
407                 c.insets = i;
408                 c.weightx = 0;
409                 c.weighty = 0;
410
411                 int y = 0;
412
413                 c.gridx = 0;
414                 c.gridy = y;
415                 c.gridwidth = 2;
416                 c.anchor = GridBagConstraints.CENTER;
417                 label = new JLabel ("Fire Igniter");
418                 pane.add(label, c);
419
420                 y++;
421
422                 igniters = new Igniter[2 + npyro];
423
424                 igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
425                 igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++);
426
427                 for (int p = 0; p < npyro; p++) {
428                         String  name = String.format("%d", p);
429                         String  label = String.format("%c", 'A' + p);
430                         igniters[2+p] = new Igniter(this, label, name, y++);
431                 }
432
433                 c.gridx = 0;
434                 c.gridy = y;
435                 c.gridwidth = 1;
436                 c.anchor = GridBagConstraints.CENTER;
437                 arm = new JToggleButton ("Arm");
438                 pane.add(arm, c);
439                 arm.addActionListener(this);
440                 arm.setActionCommand("arm");
441                 arm.setEnabled(false);
442
443                 c.gridx = 1;
444                 c.gridy = y;
445                 c.gridwidth = 1;
446                 c.anchor = GridBagConstraints.CENTER;
447                 fire = new JButton ("Fire");
448                 fire.setEnabled(false);
449                 pane.add(fire, c);
450                 fire.addActionListener(this);
451                 fire.setActionCommand("fire");
452
453                 y++;
454
455                 c.gridx = 0;
456                 c.gridy = y;
457                 c.gridwidth = 2;
458                 c.anchor = GridBagConstraints.CENTER;
459                 close = new JButton ("Close");
460                 pane.add(close, c);
461                 close.addActionListener(this);
462                 close.setActionCommand("close");
463
464                 pack();
465                 setLocationRelativeTo(owner);
466
467                 addWindowListener(new ConfigListener(this));
468         }
469
470         public AltosIgniteUI(JFrame in_owner) {
471
472                 owner = in_owner;
473
474                 if (!open())
475                         return;
476
477                 send_command("get_npyro");
478         }
479 }