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; version 2 of the License.
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.
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.
21 import java.awt.event.*;
26 import java.util.concurrent.*;
27 import org.altusmetrum.altoslib_4.*;
28 import org.altusmetrum.altosuilib_2.*;
30 public class AltosIgniteUI
32 implements ActionListener
39 javax.swing.Timer timer;
46 final static int timeout = 1 * 1000;
49 boolean timer_running;
51 LinkedBlockingQueue<String> command_queue;
53 LinkedBlockingQueue<String> reply_queue;
61 void set_status (int status) {
63 status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(status)));
66 Igniter(AltosIgniteUI ui, String label, String name, int y) {
67 Container pane = getContentPane();
68 GridBagConstraints c = new GridBagConstraints();
69 Insets i = new Insets(4,4,4,4);
72 this.status = AltosIgnite.Unknown;
77 c.anchor = GridBagConstraints.WEST;
78 button = new JRadioButton (label);
80 button.addActionListener(ui);
81 button.setActionCommand(name);
87 c.anchor = GridBagConstraints.WEST;
88 status_label = new JLabel("plenty of text");
89 pane.add(status_label, c);
91 status = AltosIgnite.Unknown;
97 void set_status(String _name, int _status) {
99 final String name = _name;
100 final int status = _status;
101 Runnable r = new Runnable() {
103 for (int p = 0; p < igniters.length; p++)
104 if (name.equals(igniters[p].name))
105 igniters[p].set_status(status);
108 SwingUtilities.invokeLater(r);
111 class IgniteHandler implements Runnable {
116 void send_exception(Exception e) {
117 final Exception f_e = e;
118 Runnable r = new Runnable() {
120 ignite_exception(f_e);
123 SwingUtilities.invokeLater(r);
128 ignite = new AltosIgnite(link,
129 !device.matchProduct(Altos.product_altimeter));
131 } catch (Exception e) {
140 String command = command_queue.take();
143 if (command.equals("get_status")) {
144 HashMap<String,Integer> status_map = ignite.status();
146 for (int p = 0; p < igniters.length; p++) {
147 Integer i = status_map.get(igniters[p].name);
149 set_status(igniters[p].name, i);
152 } else if (command.equals("get_npyro")) {
153 put_reply(String.format("%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")) {
217 void set_arm_text() {
218 if (arm.isSelected())
219 arm.setText(String.format("%d", time_remaining));
227 timer_running = true;
232 fire.setEnabled(false);
233 timer_running = false;
234 arm.setSelected(false);
235 arm.setEnabled(false);
240 group.clearSelection();
241 fire.setEnabled(false);
245 void send_command(String command) {
247 command_queue.put(command);
248 } catch (Exception ex) {
249 ignite_exception(ex);
253 void put_reply(String reply) {
255 reply_queue.put(reply);
256 } catch (Exception ex) {
257 ignite_exception(ex);
264 reply = reply_queue.take();
265 } catch (Exception ex) {
266 ignite_exception(ex);
271 boolean getting_status = false;
273 boolean visible = false;
275 void set_ignite_status() {
276 getting_status = false;
283 void poll_ignite_status() {
284 if (!getting_status) {
285 getting_status = true;
286 send_command("get_status");
291 send_command("get_npyro");
292 String reply = get_reply();
293 return Integer.parseInt(reply);
296 boolean firing = false;
298 void start_fire(String which) {
312 send_command("quit");
322 if (time_remaining <= 0)
327 poll_ignite_status();
331 if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
332 String igniter = "none";
334 for (int p = 0; p < igniters.length; p++)
335 if (igniters[p].button.isSelected()) {
336 igniter = igniters[p].name;
339 send_command(igniter);
344 public void actionPerformed(ActionEvent e) {
345 String cmd = e.getActionCommand();
347 for (int p = 0; p < igniters.length; p++)
348 if (cmd.equals(igniters[p].name)) {
350 arm.setEnabled(true);
354 if (cmd.equals("arm")) {
355 if (arm.isSelected()) {
356 fire.setEnabled(true);
361 if (cmd.equals("fire"))
363 if (cmd.equals("tick"))
365 if (cmd.equals("close"))
369 /* A window listener to catch closing events and tell the config code */
370 class ConfigListener extends WindowAdapter {
373 public ConfigListener(AltosIgniteUI this_ui) {
377 public void windowClosing(WindowEvent e) {
378 ui.actionPerformed(new ActionEvent(e.getSource(),
379 ActionEvent.ACTION_PERFORMED,
384 private boolean open() {
385 command_queue = new LinkedBlockingQueue<String>();
386 reply_queue = new LinkedBlockingQueue<String>();
389 device = AltosDeviceUIDialog.show(owner, Altos.product_any);
390 if (device != null) {
392 AltosSerial serial = new AltosSerial(device);
393 serial.set_frame(owner);
394 IgniteHandler handler = new IgniteHandler(owner, serial);
395 Thread t = new Thread(handler);
399 } catch (Exception ex) {
400 ignite_exception(ex);
406 public AltosIgniteUI(JFrame in_owner) {
413 group = new ButtonGroup();
415 Container pane = getContentPane();
417 GridBagConstraints c = new GridBagConstraints();
418 Insets i = new Insets(4,4,4,4);
420 timer = new javax.swing.Timer(timeout, this);
421 timer.setActionCommand("tick");
422 timer_running = false;
427 pane.setLayout(new GridBagLayout());
429 c.fill = GridBagConstraints.NONE;
430 c.anchor = GridBagConstraints.CENTER;
440 c.anchor = GridBagConstraints.CENTER;
441 label = new JLabel ("Fire Igniter");
446 int npyro = get_npyro();
448 igniters = new Igniter[2 + npyro];
450 igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
451 igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++);
453 for (int p = 0; p < npyro; p++) {
454 String name = String.format("%d", p);
455 String label = String.format("%c", 'A' + p);
456 igniters[2+p] = new Igniter(this, label, name, y++);
462 c.anchor = GridBagConstraints.CENTER;
463 arm = new JToggleButton ("Arm");
465 arm.addActionListener(this);
466 arm.setActionCommand("arm");
467 arm.setEnabled(false);
472 c.anchor = GridBagConstraints.CENTER;
473 fire = new JButton ("Fire");
474 fire.setEnabled(false);
476 fire.addActionListener(this);
477 fire.setActionCommand("fire");
484 c.anchor = GridBagConstraints.CENTER;
485 close = new JButton ("Close");
487 close.addActionListener(this);
488 close.setActionCommand("close");
491 setLocationRelativeTo(owner);
493 addWindowListener(new ConfigListener(this));