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; either version 2 of the License, or
7 * (at your option) any later version.
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.
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.
22 import java.awt.event.*;
27 import java.util.concurrent.*;
28 import org.altusmetrum.altoslib_11.*;
29 import org.altusmetrum.altosuilib_11.*;
31 public class AltosIgniteUI
33 implements ActionListener
40 javax.swing.Timer timer;
47 final static int timeout = 1 * 1000;
50 boolean timer_running;
54 LinkedBlockingQueue<String> command_queue;
62 void set_status (int status) {
64 status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(status)));
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);
73 this.status = AltosIgnite.Unknown;
78 c.anchor = GridBagConstraints.WEST;
79 button = new JRadioButton (label);
81 button.addActionListener(ui);
82 button.setActionCommand(name);
88 c.anchor = GridBagConstraints.WEST;
89 status_label = new JLabel("plenty of text");
90 pane.add(status_label, c);
92 status = AltosIgnite.Unknown;
98 void set_status(String _name, int _status) {
100 final String name = _name;
101 final int status = _status;
102 Runnable r = new Runnable() {
104 for (int p = 0; p < igniters.length; p++)
105 if (name.equals(igniters[p].name))
106 igniters[p].set_status(status);
109 SwingUtilities.invokeLater(r);
112 class IgniteHandler implements Runnable {
117 void send_exception(Exception e) {
118 final Exception f_e = e;
119 Runnable r = new Runnable() {
121 ignite_exception(f_e);
124 SwingUtilities.invokeLater(r);
129 ignite = new AltosIgnite(link,
130 !device.matchProduct(Altos.product_altimeter));
132 } catch (Exception e) {
141 String command = command_queue.take();
144 if (command.equals("get_status")) {
145 HashMap<String,Integer> status_map = ignite.status();
147 for (int p = 0; p < igniters.length; p++) {
148 Integer i = status_map.get(igniters[p].name);
150 set_status(igniters[p].name, i);
153 } else if (command.equals("get_npyro")) {
154 reply = String.format("npyro %d", ignite.npyro());
155 } else if (command.equals("quit")) {
159 ignite.fire(command);
162 final String f_reply = reply;
165 ignite_reply(f_reply);
168 SwingUtilities.invokeLater(r);
169 } catch (Exception e) {
175 public IgniteHandler(JFrame in_owner, AltosLink in_link) {
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()),
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);
200 JOptionPane.showMessageDialog(owner,
201 String.format("Connection to \"%s\" failed",
202 device.toShortString()),
204 JOptionPane.ERROR_MESSAGE);
209 void ignite_reply(String reply) {
210 if (reply.equals("status")) {
212 } else if (reply.equals("fired")) {
214 } else if (reply.startsWith("npyro")) {
215 npyro = Integer.parseInt(reply.substring(6));
220 void set_arm_text() {
221 if (arm.isSelected())
222 arm.setText(String.format("%d", time_remaining));
230 timer_running = true;
235 fire.setEnabled(false);
236 timer_running = false;
237 arm.setSelected(false);
238 arm.setEnabled(false);
243 group.clearSelection();
244 fire.setEnabled(false);
248 void send_command(String command) {
250 command_queue.put(command);
251 } catch (Exception ex) {
252 ignite_exception(ex);
256 boolean getting_status = false;
258 boolean visible = false;
260 void set_ignite_status() {
261 getting_status = false;
269 void poll_ignite_status() {
270 if (poll_remaining > 0) {
274 if (!getting_status) {
275 getting_status = true;
276 send_command("get_status");
280 boolean firing = false;
282 void start_fire(String which) {
296 send_command("quit");
307 if (time_remaining <= 0)
312 poll_ignite_status();
316 if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
317 String igniter = "none";
319 for (int p = 0; p < igniters.length; p++)
320 if (igniters[p].button.isSelected()) {
321 igniter = igniters[p].name;
324 send_command(igniter);
329 public void actionPerformed(ActionEvent e) {
330 String cmd = e.getActionCommand();
332 for (int p = 0; p < igniters.length; p++)
333 if (cmd.equals(igniters[p].name)) {
335 arm.setEnabled(true);
339 if (cmd.equals("arm")) {
340 if (arm.isSelected()) {
341 fire.setEnabled(true);
346 if (cmd.equals("fire"))
348 if (cmd.equals("tick"))
350 if (cmd.equals("close"))
354 /* A window listener to catch closing events and tell the config code */
355 class ConfigListener extends WindowAdapter {
358 public ConfigListener(AltosIgniteUI this_ui) {
362 public void windowClosing(WindowEvent e) {
363 ui.actionPerformed(new ActionEvent(e.getSource(),
364 ActionEvent.ACTION_PERFORMED,
369 private boolean open() {
370 command_queue = new LinkedBlockingQueue<String>();
373 device = AltosDeviceUIDialog.show(owner, Altos.product_any);
374 if (device != null) {
376 AltosSerial serial = new AltosSerial(device);
377 serial.set_frame(owner);
378 IgniteHandler handler = new IgniteHandler(owner, serial);
379 Thread t = new Thread(handler);
383 } catch (Exception ex) {
384 ignite_exception(ex);
390 private void make_ui() {
391 group = new ButtonGroup();
393 Container pane = getContentPane();
395 GridBagConstraints c = new GridBagConstraints();
396 Insets i = new Insets(4,4,4,4);
398 timer = new javax.swing.Timer(timeout, this);
399 timer.setActionCommand("tick");
400 timer_running = false;
403 pane.setLayout(new GridBagLayout());
405 c.fill = GridBagConstraints.NONE;
406 c.anchor = GridBagConstraints.CENTER;
416 c.anchor = GridBagConstraints.CENTER;
417 label = new JLabel ("Fire Igniter");
422 igniters = new Igniter[2 + npyro];
424 igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
425 igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++);
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++);
436 c.anchor = GridBagConstraints.CENTER;
437 arm = new JToggleButton ("Arm");
439 arm.addActionListener(this);
440 arm.setActionCommand("arm");
441 arm.setEnabled(false);
446 c.anchor = GridBagConstraints.CENTER;
447 fire = new JButton ("Fire");
448 fire.setEnabled(false);
450 fire.addActionListener(this);
451 fire.setActionCommand("fire");
458 c.anchor = GridBagConstraints.CENTER;
459 close = new JButton ("Close");
461 close.addActionListener(this);
462 close.setActionCommand("close");
465 setLocationRelativeTo(owner);
467 addWindowListener(new ConfigListener(this));
470 public AltosIgniteUI(JFrame in_owner) {
477 send_command("get_npyro");