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_14.*;
29 import org.altusmetrum.altosuilib_14.*;
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 = getScrollablePane();
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));
216 if (npyro == AltosLib.MISSING)
222 void set_arm_text() {
223 if (arm.isSelected())
224 arm.setText(String.format("%d", time_remaining));
232 timer_running = true;
237 fire.setEnabled(false);
238 timer_running = false;
239 arm.setSelected(false);
240 arm.setEnabled(false);
245 group.clearSelection();
246 fire.setEnabled(false);
250 void send_command(String command) {
252 command_queue.put(command);
253 } catch (Exception ex) {
254 ignite_exception(ex);
258 boolean getting_status = false;
260 void set_ignite_status() {
261 getting_status = false;
267 void poll_ignite_status() {
268 if (poll_remaining > 0) {
272 if (!getting_status) {
273 getting_status = true;
274 send_command("get_status");
278 boolean firing = false;
280 void start_fire(String which) {
294 send_command("quit");
305 if (time_remaining <= 0)
310 poll_ignite_status();
314 if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
315 String igniter = "none";
317 for (int p = 0; p < igniters.length; p++)
318 if (igniters[p].button.isSelected()) {
319 igniter = igniters[p].name;
322 send_command(igniter);
327 public void actionPerformed(ActionEvent e) {
328 String cmd = e.getActionCommand();
330 for (int p = 0; p < igniters.length; p++)
331 if (cmd.equals(igniters[p].name)) {
333 arm.setEnabled(true);
337 if (cmd.equals("arm")) {
338 if (arm.isSelected()) {
339 fire.setEnabled(true);
344 if (cmd.equals("fire"))
346 if (cmd.equals("tick"))
348 if (cmd.equals("close"))
352 /* A window listener to catch closing events and tell the config code */
353 class ConfigListener extends WindowAdapter {
356 public ConfigListener(AltosIgniteUI this_ui) {
360 public void windowClosing(WindowEvent e) {
361 ui.actionPerformed(new ActionEvent(e.getSource(),
362 ActionEvent.ACTION_PERFORMED,
367 private boolean open() {
368 command_queue = new LinkedBlockingQueue<String>();
371 device = AltosDeviceUIDialog.show(owner, Altos.product_any);
372 if (device != null) {
374 AltosSerial serial = new AltosSerial(device);
375 serial.set_frame(owner);
376 IgniteHandler handler = new IgniteHandler(owner, serial);
377 Thread t = new Thread(handler);
381 } catch (Exception ex) {
382 ignite_exception(ex);
388 private void make_ui() {
389 group = new ButtonGroup();
391 Container pane = getScrollablePane();
393 GridBagConstraints c = new GridBagConstraints();
394 Insets i = new Insets(4,4,4,4);
396 timer = new javax.swing.Timer(timeout, this);
397 timer.setActionCommand("tick");
398 timer_running = false;
401 pane.setLayout(new GridBagLayout());
403 c.fill = GridBagConstraints.NONE;
404 c.anchor = GridBagConstraints.CENTER;
414 c.anchor = GridBagConstraints.CENTER;
415 label = new JLabel ("Fire Igniter");
420 igniters = new Igniter[2 + npyro];
422 igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
423 igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++);
425 for (int p = 0; p < npyro; p++) {
426 String name = String.format("%d", p);
427 String label = String.format("%c", 'A' + p);
428 igniters[2+p] = new Igniter(this, label, name, y++);
434 c.anchor = GridBagConstraints.CENTER;
435 arm = new JToggleButton ("Arm");
437 arm.addActionListener(this);
438 arm.setActionCommand("arm");
439 arm.setEnabled(false);
444 c.anchor = GridBagConstraints.CENTER;
445 fire = new JButton ("Fire");
446 fire.setEnabled(false);
448 fire.addActionListener(this);
449 fire.setActionCommand("fire");
456 c.anchor = GridBagConstraints.CENTER;
457 close = new JButton ("Close");
459 close.addActionListener(this);
460 close.setActionCommand("close");
463 setLocationRelativeTo(owner);
465 addWindowListener(new ConfigListener(this));
468 public AltosIgniteUI(JFrame in_owner) {
475 send_command("get_npyro");