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