altos/altosui: Add pad orientation configure option
[fw/altos] / altosui / AltosConfigUI.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 javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
25 import javax.swing.event.*;
26 import java.io.*;
27 import java.util.*;
28 import java.text.*;
29 import java.util.prefs.*;
30 import java.util.concurrent.LinkedBlockingQueue;
31
32 import libaltosJNI.*;
33
34 public class AltosConfigUI
35         extends JDialog
36         implements ActionListener, ItemListener, DocumentListener
37 {
38
39         Container       pane;
40         Box             box;
41         JLabel          product_label;
42         JLabel          version_label;
43         JLabel          serial_label;
44         JLabel          main_deploy_label;
45         JLabel          apogee_delay_label;
46         JLabel          radio_channel_label;
47         JLabel          radio_calibration_label;
48         JLabel          flight_log_max_label;
49         JLabel          ignite_mode_label;
50         JLabel          pad_orientation_label;
51         JLabel          callsign_label;
52
53         public boolean          dirty;
54
55         JFrame          owner;
56         JLabel          product_value;
57         JLabel          version_value;
58         JLabel          serial_value;
59         JComboBox       main_deploy_value;
60         JComboBox       apogee_delay_value;
61         JComboBox       radio_channel_value;
62         JTextField      radio_calibration_value;
63         JComboBox       flight_log_max_value;
64         JComboBox       ignite_mode_value;
65         JComboBox       pad_orientation_value;
66         JTextField      callsign_value;
67
68         JButton         save;
69         JButton         reset;
70         JButton         reboot;
71         JButton         close;
72
73         ActionListener  listener;
74
75         static String[] main_deploy_values = {
76                 "100", "150", "200", "250", "300", "350",
77                 "400", "450", "500"
78         };
79
80         static String[] apogee_delay_values = {
81                 "0", "1", "2", "3", "4", "5"
82         };
83
84         static String[] flight_log_max_values = {
85                 "64", "128", "192", "256", "320",
86                 "384", "448", "512", "576", "640",
87                 "704", "768", "832", "896", "960",
88         };
89
90         static String[] ignite_mode_values = {
91                 "Dual Deploy",
92                 "Redundant Apogee",
93                 "Redundant Main",
94         };
95
96         static String[] pad_orientation_values = {
97                 "Antenna Up",
98                 "Antenna Down",
99         };
100
101         static String[] radio_channel_values = new String[10];
102                 {
103                         for (int i = 0; i <= 9; i++)
104                                 radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)",
105                                                                         i, 434.550 + i * 0.1);
106                 }
107
108         /* A window listener to catch closing events and tell the config code */
109         class ConfigListener extends WindowAdapter {
110                 AltosConfigUI   ui;
111
112                 public ConfigListener(AltosConfigUI this_ui) {
113                         ui = this_ui;
114                 }
115
116                 public void windowClosing(WindowEvent e) {
117                         ui.actionPerformed(new ActionEvent(e.getSource(),
118                                                            ActionEvent.ACTION_PERFORMED,
119                                                            "Close"));
120                 }
121         }
122
123         /* Build the UI using a grid bag */
124         public AltosConfigUI(JFrame in_owner, boolean remote) {
125                 super (in_owner, "Configure TeleMetrum", false);
126
127                 owner = in_owner;
128                 GridBagConstraints c;
129
130                 Insets il = new Insets(4,4,4,4);
131                 Insets ir = new Insets(4,4,4,4);
132
133                 pane = getContentPane();
134                 pane.setLayout(new GridBagLayout());
135
136                 /* Product */
137                 c = new GridBagConstraints();
138                 c.gridx = 0; c.gridy = 0;
139                 c.gridwidth = 4;
140                 c.fill = GridBagConstraints.NONE;
141                 c.anchor = GridBagConstraints.LINE_START;
142                 c.insets = il;
143                 product_label = new JLabel("Product:");
144                 pane.add(product_label, c);
145
146                 c = new GridBagConstraints();
147                 c.gridx = 4; c.gridy = 0;
148                 c.gridwidth = 4;
149                 c.fill = GridBagConstraints.HORIZONTAL;
150                 c.weightx = 1;
151                 c.anchor = GridBagConstraints.LINE_START;
152                 c.insets = ir;
153                 product_value = new JLabel("");
154                 pane.add(product_value, c);
155
156                 /* Version */
157                 c = new GridBagConstraints();
158                 c.gridx = 0; c.gridy = 1;
159                 c.gridwidth = 4;
160                 c.fill = GridBagConstraints.NONE;
161                 c.anchor = GridBagConstraints.LINE_START;
162                 c.insets = il;
163                 c.ipady = 5;
164                 version_label = new JLabel("Software version:");
165                 pane.add(version_label, c);
166
167                 c = new GridBagConstraints();
168                 c.gridx = 4; c.gridy = 1;
169                 c.gridwidth = 4;
170                 c.fill = GridBagConstraints.HORIZONTAL;
171                 c.weightx = 1;
172                 c.anchor = GridBagConstraints.LINE_START;
173                 c.insets = ir;
174                 c.ipady = 5;
175                 version_value = new JLabel("");
176                 pane.add(version_value, c);
177
178                 /* Serial */
179                 c = new GridBagConstraints();
180                 c.gridx = 0; c.gridy = 2;
181                 c.gridwidth = 4;
182                 c.fill = GridBagConstraints.NONE;
183                 c.anchor = GridBagConstraints.LINE_START;
184                 c.insets = il;
185                 c.ipady = 5;
186                 serial_label = new JLabel("Serial:");
187                 pane.add(serial_label, c);
188
189                 c = new GridBagConstraints();
190                 c.gridx = 4; c.gridy = 2;
191                 c.gridwidth = 4;
192                 c.fill = GridBagConstraints.HORIZONTAL;
193                 c.weightx = 1;
194                 c.anchor = GridBagConstraints.LINE_START;
195                 c.insets = ir;
196                 c.ipady = 5;
197                 serial_value = new JLabel("");
198                 pane.add(serial_value, c);
199
200                 /* Main deploy */
201                 c = new GridBagConstraints();
202                 c.gridx = 0; c.gridy = 3;
203                 c.gridwidth = 4;
204                 c.fill = GridBagConstraints.NONE;
205                 c.anchor = GridBagConstraints.LINE_START;
206                 c.insets = il;
207                 c.ipady = 5;
208                 main_deploy_label = new JLabel("Main Deploy Altitude(m):");
209                 pane.add(main_deploy_label, c);
210
211                 c = new GridBagConstraints();
212                 c.gridx = 4; c.gridy = 3;
213                 c.gridwidth = 4;
214                 c.fill = GridBagConstraints.HORIZONTAL;
215                 c.weightx = 1;
216                 c.anchor = GridBagConstraints.LINE_START;
217                 c.insets = ir;
218                 c.ipady = 5;
219                 main_deploy_value = new JComboBox(main_deploy_values);
220                 main_deploy_value.setEditable(true);
221                 main_deploy_value.addItemListener(this);
222                 pane.add(main_deploy_value, c);
223
224                 /* Apogee delay */
225                 c = new GridBagConstraints();
226                 c.gridx = 0; c.gridy = 4;
227                 c.gridwidth = 4;
228                 c.fill = GridBagConstraints.NONE;
229                 c.anchor = GridBagConstraints.LINE_START;
230                 c.insets = il;
231                 c.ipady = 5;
232                 apogee_delay_label = new JLabel("Apogee Delay(s):");
233                 pane.add(apogee_delay_label, c);
234
235                 c = new GridBagConstraints();
236                 c.gridx = 4; c.gridy = 4;
237                 c.gridwidth = 4;
238                 c.fill = GridBagConstraints.HORIZONTAL;
239                 c.weightx = 1;
240                 c.anchor = GridBagConstraints.LINE_START;
241                 c.insets = ir;
242                 c.ipady = 5;
243                 apogee_delay_value = new JComboBox(apogee_delay_values);
244                 apogee_delay_value.setEditable(true);
245                 apogee_delay_value.addItemListener(this);
246                 pane.add(apogee_delay_value, c);
247
248                 /* Radio channel */
249                 c = new GridBagConstraints();
250                 c.gridx = 0; c.gridy = 5;
251                 c.gridwidth = 4;
252                 c.fill = GridBagConstraints.NONE;
253                 c.anchor = GridBagConstraints.LINE_START;
254                 c.insets = il;
255                 c.ipady = 5;
256                 radio_channel_label = new JLabel("Radio Channel:");
257                 pane.add(radio_channel_label, c);
258
259                 c = new GridBagConstraints();
260                 c.gridx = 4; c.gridy = 5;
261                 c.gridwidth = 4;
262                 c.fill = GridBagConstraints.HORIZONTAL;
263                 c.weightx = 1;
264                 c.anchor = GridBagConstraints.LINE_START;
265                 c.insets = ir;
266                 c.ipady = 5;
267                 radio_channel_value = new JComboBox(radio_channel_values);
268                 radio_channel_value.setEditable(false);
269                 radio_channel_value.addItemListener(this);
270                 pane.add(radio_channel_value, c);
271
272                 /* Radio Calibration */
273                 c = new GridBagConstraints();
274                 c.gridx = 0; c.gridy = 6;
275                 c.gridwidth = 4;
276                 c.fill = GridBagConstraints.NONE;
277                 c.anchor = GridBagConstraints.LINE_START;
278                 c.insets = il;
279                 c.ipady = 5;
280                 radio_calibration_label = new JLabel("RF Calibration:");
281                 pane.add(radio_calibration_label, c);
282
283                 c = new GridBagConstraints();
284                 c.gridx = 4; c.gridy = 6;
285                 c.gridwidth = 4;
286                 c.fill = GridBagConstraints.HORIZONTAL;
287                 c.weightx = 1;
288                 c.anchor = GridBagConstraints.LINE_START;
289                 c.insets = ir;
290                 c.ipady = 5;
291                 radio_calibration_value = new JTextField(String.format("%d", 1186611));
292                 radio_calibration_value.getDocument().addDocumentListener(this);
293                 if (remote)
294                         radio_calibration_value.setEnabled(false);
295                 pane.add(radio_calibration_value, c);
296
297                 /* Callsign */
298                 c = new GridBagConstraints();
299                 c.gridx = 0; c.gridy = 7;
300                 c.gridwidth = 4;
301                 c.fill = GridBagConstraints.NONE;
302                 c.anchor = GridBagConstraints.LINE_START;
303                 c.insets = il;
304                 c.ipady = 5;
305                 callsign_label = new JLabel("Callsign:");
306                 pane.add(callsign_label, c);
307
308                 c = new GridBagConstraints();
309                 c.gridx = 4; c.gridy = 7;
310                 c.gridwidth = 4;
311                 c.fill = GridBagConstraints.HORIZONTAL;
312                 c.weightx = 1;
313                 c.anchor = GridBagConstraints.LINE_START;
314                 c.insets = ir;
315                 c.ipady = 5;
316                 callsign_value = new JTextField(AltosPreferences.callsign());
317                 callsign_value.getDocument().addDocumentListener(this);
318                 pane.add(callsign_value, c);
319
320                 /* Flight log max */
321                 c = new GridBagConstraints();
322                 c.gridx = 0; c.gridy = 8;
323                 c.gridwidth = 4;
324                 c.fill = GridBagConstraints.NONE;
325                 c.anchor = GridBagConstraints.LINE_START;
326                 c.insets = il;
327                 c.ipady = 5;
328                 flight_log_max_label = new JLabel("Maximum Flight Log Size:");
329                 pane.add(flight_log_max_label, c);
330
331                 c = new GridBagConstraints();
332                 c.gridx = 4; c.gridy = 8;
333                 c.gridwidth = 4;
334                 c.fill = GridBagConstraints.HORIZONTAL;
335                 c.weightx = 1;
336                 c.anchor = GridBagConstraints.LINE_START;
337                 c.insets = ir;
338                 c.ipady = 5;
339                 flight_log_max_value = new JComboBox(flight_log_max_values);
340                 flight_log_max_value.setEditable(true);
341                 flight_log_max_value.addItemListener(this);
342                 pane.add(flight_log_max_value, c);
343
344                 /* Ignite mode */
345                 c = new GridBagConstraints();
346                 c.gridx = 0; c.gridy = 9;
347                 c.gridwidth = 4;
348                 c.fill = GridBagConstraints.NONE;
349                 c.anchor = GridBagConstraints.LINE_START;
350                 c.insets = il;
351                 c.ipady = 5;
352                 ignite_mode_label = new JLabel("Igniter Firing Mode:");
353                 pane.add(ignite_mode_label, c);
354
355                 c = new GridBagConstraints();
356                 c.gridx = 4; c.gridy = 9;
357                 c.gridwidth = 4;
358                 c.fill = GridBagConstraints.HORIZONTAL;
359                 c.weightx = 1;
360                 c.anchor = GridBagConstraints.LINE_START;
361                 c.insets = ir;
362                 c.ipady = 5;
363                 ignite_mode_value = new JComboBox(ignite_mode_values);
364                 ignite_mode_value.setEditable(false);
365                 ignite_mode_value.addItemListener(this);
366                 pane.add(ignite_mode_value, c);
367
368                 /* Pad orientation */
369                 c = new GridBagConstraints();
370                 c.gridx = 0; c.gridy = 10;
371                 c.gridwidth = 4;
372                 c.fill = GridBagConstraints.NONE;
373                 c.anchor = GridBagConstraints.LINE_START;
374                 c.insets = il;
375                 c.ipady = 5;
376                 pad_orientation_label = new JLabel("Pad Orientation:");
377                 pane.add(pad_orientation_label, c);
378
379                 c = new GridBagConstraints();
380                 c.gridx = 4; c.gridy = 10;
381                 c.gridwidth = 4;
382                 c.fill = GridBagConstraints.HORIZONTAL;
383                 c.weightx = 1;
384                 c.anchor = GridBagConstraints.LINE_START;
385                 c.insets = ir;
386                 c.ipady = 5;
387                 pad_orientation_value = new JComboBox(pad_orientation_values);
388                 pad_orientation_value.setEditable(false);
389                 pad_orientation_value.addItemListener(this);
390                 pane.add(pad_orientation_value, c);
391
392                 /* Buttons */
393                 c = new GridBagConstraints();
394                 c.gridx = 0; c.gridy = 11;
395                 c.gridwidth = 2;
396                 c.fill = GridBagConstraints.NONE;
397                 c.anchor = GridBagConstraints.LINE_START;
398                 c.insets = il;
399                 save = new JButton("Save");
400                 pane.add(save, c);
401                 save.addActionListener(this);
402                 save.setActionCommand("Save");
403
404                 c = new GridBagConstraints();
405                 c.gridx = 2; c.gridy = 11;
406                 c.gridwidth = 2;
407                 c.fill = GridBagConstraints.NONE;
408                 c.anchor = GridBagConstraints.CENTER;
409                 c.insets = il;
410                 reset = new JButton("Reset");
411                 pane.add(reset, c);
412                 reset.addActionListener(this);
413                 reset.setActionCommand("Reset");
414
415                 c = new GridBagConstraints();
416                 c.gridx = 4; c.gridy = 11;
417                 c.gridwidth = 2;
418                 c.fill = GridBagConstraints.NONE;
419                 c.anchor = GridBagConstraints.CENTER;
420                 c.insets = il;
421                 reboot = new JButton("Reboot");
422                 pane.add(reboot, c);
423                 reboot.addActionListener(this);
424                 reboot.setActionCommand("Reboot");
425
426                 c = new GridBagConstraints();
427                 c.gridx = 6; c.gridy = 11;
428                 c.gridwidth = 2;
429                 c.fill = GridBagConstraints.NONE;
430                 c.anchor = GridBagConstraints.LINE_END;
431                 c.insets = il;
432                 close = new JButton("Close");
433                 pane.add(close, c);
434                 close.addActionListener(this);
435                 close.setActionCommand("Close");
436
437                 addWindowListener(new ConfigListener(this));
438         }
439
440         /* Once the initial values are set, the config code will show the dialog */
441         public void make_visible() {
442                 pack();
443                 setLocationRelativeTo(owner);
444                 setVisible(true);
445         }
446
447         /* If any values have been changed, confirm before closing */
448         public boolean check_dirty(String operation) {
449                 if (dirty) {
450                         Object[] options = { String.format("%s anyway", operation), "Keep editing" };
451                         int i;
452                         i = JOptionPane.showOptionDialog(this,
453                                                          String.format("Configuration modified. %s anyway?", operation),
454                                                          "Configuration Modified",
455                                                          JOptionPane.DEFAULT_OPTION,
456                                                          JOptionPane.WARNING_MESSAGE,
457                                                          null, options, options[1]);
458                         if (i != 0)
459                                 return false;
460                 }
461                 return true;
462         }
463
464         /* Listen for events from our buttons */
465         public void actionPerformed(ActionEvent e) {
466                 String  cmd = e.getActionCommand();
467
468                 if (cmd.equals("Close") || cmd.equals("Reboot"))
469                         if (!check_dirty(cmd))
470                                 return;
471                 listener.actionPerformed(e);
472                 if (cmd.equals("Close") || cmd.equals("Reboot")) {
473                         setVisible(false);
474                         dispose();
475                 }
476                 dirty = false;
477         }
478
479         /* ItemListener interface method */
480         public void itemStateChanged(ItemEvent e) {
481                 dirty = true;
482         }
483
484         /* DocumentListener interface methods */
485         public void changedUpdate(DocumentEvent e) {
486                 dirty = true;
487         }
488
489         public void insertUpdate(DocumentEvent e) {
490                 dirty = true;
491         }
492
493         public void removeUpdate(DocumentEvent e) {
494                 dirty = true;
495         }
496
497         /* Let the config code hook on a listener */
498         public void addActionListener(ActionListener l) {
499                 listener = l;
500         }
501
502         /* set and get all of the dialog values */
503         public void set_product(String product) {
504                 product_value.setText(product);
505         }
506
507         public void set_version(String version) {
508                 version_value.setText(version);
509         }
510
511         public void set_serial(int serial) {
512                 serial_value.setText(String.format("%d", serial));
513         }
514
515         public void set_main_deploy(int new_main_deploy) {
516                 main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
517         }
518
519         public int main_deploy() {
520                 return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
521         }
522
523         public void set_apogee_delay(int new_apogee_delay) {
524                 apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
525         }
526
527         public int apogee_delay() {
528                 return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
529         }
530
531         public void set_radio_channel(int new_radio_channel) {
532                 radio_channel_value.setSelectedIndex(new_radio_channel);
533         }
534
535         public int radio_channel() {
536                 return radio_channel_value.getSelectedIndex();
537         }
538
539         public void set_radio_calibration(int new_radio_calibration) {
540                 radio_calibration_value.setText(String.format("%d", new_radio_calibration));
541         }
542
543         public int radio_calibration() {
544                 return Integer.parseInt(radio_calibration_value.getText());
545         }
546
547         public void set_callsign(String new_callsign) {
548                 callsign_value.setText(new_callsign);
549         }
550
551         public String callsign() {
552                 return callsign_value.getText();
553         }
554
555         public void set_flight_log_max(int new_flight_log_max) {
556                 if (new_flight_log_max == 0)
557                         flight_log_max_value.setEnabled(false);
558                 flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max));
559         }
560
561         public int flight_log_max() {
562                 return Integer.parseInt(flight_log_max_value.getSelectedItem().toString());
563         }
564
565         public void set_ignite_mode(int new_ignite_mode) {
566                 if (new_ignite_mode < 0) {
567                         ignite_mode_value.setEnabled(false);
568                         new_ignite_mode = 0;
569                 } else {
570                         ignite_mode_value.setEnabled(true);
571                 }
572                 ignite_mode_value.setSelectedIndex(new_ignite_mode);
573         }
574
575         public int ignite_mode() {
576                 return ignite_mode_value.getSelectedIndex();
577         }
578
579
580         public void set_pad_orientation(int new_pad_orientation) {
581                 if (new_pad_orientation < 0) {
582                         pad_orientation_value.setEnabled(false);
583                         new_pad_orientation = 0;
584                 } else {
585                         pad_orientation_value.setEnabled(true);
586                 }
587                 pad_orientation_value.setSelectedIndex(new_pad_orientation);
588         }
589
590         public int pad_orientation() {
591                 return pad_orientation_value.getSelectedIndex();
592         }
593
594         public void set_clean() {
595                 dirty = false;
596         }
597 }