62394fa6ca722c3c143d90d78b321ebb83202876
[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 import org.altusmetrum.AltosLib.*;
32
33 import libaltosJNI.*;
34
35 public class AltosConfigUI
36         extends AltosDialog
37         implements ActionListener, ItemListener, DocumentListener
38 {
39
40         Container       pane;
41         Box             box;
42         JLabel          product_label;
43         JLabel          version_label;
44         JLabel          serial_label;
45         JLabel          main_deploy_label;
46         JLabel          apogee_delay_label;
47         JLabel          apogee_lockout_label;
48         JLabel          frequency_label;
49         JLabel          radio_calibration_label;
50         JLabel          radio_frequency_label;
51         JLabel          radio_enable_label;
52         JLabel          flight_log_max_label;
53         JLabel          ignite_mode_label;
54         JLabel          pad_orientation_label;
55         JLabel          callsign_label;
56
57         public boolean          dirty;
58
59         JFrame          owner;
60         JLabel          product_value;
61         JLabel          version_value;
62         JLabel          serial_value;
63         JComboBox       main_deploy_value;
64         JComboBox       apogee_delay_value;
65         JComboBox       apogee_lockout_value;
66         AltosFreqList   radio_frequency_value;
67         JTextField      radio_calibration_value;
68         JRadioButton    radio_enable_value;
69         JComboBox       flight_log_max_value;
70         JComboBox       ignite_mode_value;
71         JComboBox       pad_orientation_value;
72         JTextField      callsign_value;
73
74         JButton         save;
75         JButton         reset;
76         JButton         reboot;
77         JButton         close;
78
79         ActionListener  listener;
80
81         static String[] main_deploy_values = {
82                 "100", "150", "200", "250", "300", "350",
83                 "400", "450", "500"
84         };
85
86         static String[] apogee_delay_values = {
87                 "0", "1", "2", "3", "4", "5"
88         };
89
90         static String[] apogee_lockout_values = {
91                 "0", "5", "10", "15", "20"
92         };
93
94         static String[] flight_log_max_values = {
95                 "64", "128", "192", "256", "320",
96                 "384", "448", "512", "576", "640",
97                 "704", "768", "832", "896", "960",
98         };
99
100         static String[] ignite_mode_values = {
101                 "Dual Deploy",
102                 "Redundant Apogee",
103                 "Redundant Main",
104         };
105
106         static String[] pad_orientation_values = {
107                 "Antenna Up",
108                 "Antenna Down",
109         };
110
111         /* A window listener to catch closing events and tell the config code */
112         class ConfigListener extends WindowAdapter {
113                 AltosConfigUI   ui;
114
115                 public ConfigListener(AltosConfigUI this_ui) {
116                         ui = this_ui;
117                 }
118
119                 public void windowClosing(WindowEvent e) {
120                         ui.actionPerformed(new ActionEvent(e.getSource(),
121                                                            ActionEvent.ACTION_PERFORMED,
122                                                            "Close"));
123                 }
124         }
125
126         boolean is_telemini() {
127                 String  product = product_value.getText();
128                 return product != null && product.startsWith("TeleMini");
129         }
130
131         boolean is_telemetrum() {
132                 String  product = product_value.getText();
133                 return product != null && product.startsWith("TeleMetrum");
134         }
135
136         void set_radio_calibration_tool_tip() {
137                 if (radio_calibration_value.isEnabled())
138                         radio_calibration_value.setToolTipText("Tune radio output to match desired frequency");
139                 else
140                         radio_calibration_value.setToolTipText("Cannot tune radio while connected over packet mode");
141         }
142
143         void set_radio_enable_tool_tip() {
144                 if (radio_enable_value.isEnabled())
145                         radio_enable_value.setToolTipText("Enable/Disable telemetry and RDF transmissions");
146                 else
147                         radio_enable_value.setToolTipText("Firmware version does not support disabling radio");
148         }
149
150         void set_flight_log_max_tool_tip() {
151                 if (flight_log_max_value.isEnabled())
152                         flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)");
153                 else {
154                         if (is_telemetrum())
155                                 flight_log_max_value.setToolTipText("Cannot set max value with flight logs in memory");
156                         else if (is_telemini())
157                                 flight_log_max_value.setToolTipText("TeleMini stores only one flight");
158                         else
159                                 flight_log_max_value.setToolTipText("Cannot set max flight log value");
160                 }
161         }
162
163         void set_ignite_mode_tool_tip() {
164                 if (ignite_mode_value.isEnabled())
165                         ignite_mode_value.setToolTipText("Select when igniters will be fired");
166                 else
167                         ignite_mode_value.setToolTipText("Older firmware could not select ignite mode");
168         }
169
170         void set_pad_orientation_tool_tip() {
171                 if (pad_orientation_value.isEnabled())
172                         pad_orientation_value.setToolTipText("How will TeleMetrum be mounted in the airframe");
173                 else {
174                         if (is_telemetrum())
175                                 pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");
176                         else if (is_telemini())
177                                 pad_orientation_value.setToolTipText("TeleMini doesn't care how it is mounted");
178                         else
179                                 pad_orientation_value.setToolTipText("Can't select orientation");
180                 }
181         }
182
183         /* Build the UI using a grid bag */
184         public AltosConfigUI(JFrame in_owner, boolean remote) {
185                 super (in_owner, "Configure TeleMetrum", false);
186
187                 owner = in_owner;
188                 GridBagConstraints c;
189                 int row = 0;
190
191                 Insets il = new Insets(4,4,4,4);
192                 Insets ir = new Insets(4,4,4,4);
193
194                 pane = getContentPane();
195                 pane.setLayout(new GridBagLayout());
196
197                 /* Product */
198                 c = new GridBagConstraints();
199                 c.gridx = 0; c.gridy = row;
200                 c.gridwidth = 4;
201                 c.fill = GridBagConstraints.NONE;
202                 c.anchor = GridBagConstraints.LINE_START;
203                 c.insets = il;
204                 product_label = new JLabel("Product:");
205                 pane.add(product_label, c);
206
207                 c = new GridBagConstraints();
208                 c.gridx = 4; c.gridy = row;
209                 c.gridwidth = 4;
210                 c.fill = GridBagConstraints.HORIZONTAL;
211                 c.weightx = 1;
212                 c.anchor = GridBagConstraints.LINE_START;
213                 c.insets = ir;
214                 product_value = new JLabel("");
215                 pane.add(product_value, c);
216                 row++;
217
218                 /* Version */
219                 c = new GridBagConstraints();
220                 c.gridx = 0; c.gridy = row;
221                 c.gridwidth = 4;
222                 c.fill = GridBagConstraints.NONE;
223                 c.anchor = GridBagConstraints.LINE_START;
224                 c.insets = il;
225                 c.ipady = 5;
226                 version_label = new JLabel("Software version:");
227                 pane.add(version_label, c);
228
229                 c = new GridBagConstraints();
230                 c.gridx = 4; c.gridy = row;
231                 c.gridwidth = 4;
232                 c.fill = GridBagConstraints.HORIZONTAL;
233                 c.weightx = 1;
234                 c.anchor = GridBagConstraints.LINE_START;
235                 c.insets = ir;
236                 c.ipady = 5;
237                 version_value = new JLabel("");
238                 pane.add(version_value, c);
239                 row++;
240
241                 /* Serial */
242                 c = new GridBagConstraints();
243                 c.gridx = 0; c.gridy = row;
244                 c.gridwidth = 4;
245                 c.fill = GridBagConstraints.NONE;
246                 c.anchor = GridBagConstraints.LINE_START;
247                 c.insets = il;
248                 c.ipady = 5;
249                 serial_label = new JLabel("Serial:");
250                 pane.add(serial_label, c);
251
252                 c = new GridBagConstraints();
253                 c.gridx = 4; c.gridy = row;
254                 c.gridwidth = 4;
255                 c.fill = GridBagConstraints.HORIZONTAL;
256                 c.weightx = 1;
257                 c.anchor = GridBagConstraints.LINE_START;
258                 c.insets = ir;
259                 c.ipady = 5;
260                 serial_value = new JLabel("");
261                 pane.add(serial_value, c);
262                 row++;
263
264                 /* Main deploy */
265                 c = new GridBagConstraints();
266                 c.gridx = 0; c.gridy = row;
267                 c.gridwidth = 4;
268                 c.fill = GridBagConstraints.NONE;
269                 c.anchor = GridBagConstraints.LINE_START;
270                 c.insets = il;
271                 c.ipady = 5;
272                 main_deploy_label = new JLabel("Main Deploy Altitude(m):");
273                 pane.add(main_deploy_label, c);
274
275                 c = new GridBagConstraints();
276                 c.gridx = 4; c.gridy = row;
277                 c.gridwidth = 4;
278                 c.fill = GridBagConstraints.HORIZONTAL;
279                 c.weightx = 1;
280                 c.anchor = GridBagConstraints.LINE_START;
281                 c.insets = ir;
282                 c.ipady = 5;
283                 main_deploy_value = new JComboBox(main_deploy_values);
284                 main_deploy_value.setEditable(true);
285                 main_deploy_value.addItemListener(this);
286                 pane.add(main_deploy_value, c);
287                 main_deploy_value.setToolTipText("Height above pad altitude to fire main charge");
288                 row++;
289
290                 /* Apogee delay */
291                 c = new GridBagConstraints();
292                 c.gridx = 0; c.gridy = row;
293                 c.gridwidth = 4;
294                 c.fill = GridBagConstraints.NONE;
295                 c.anchor = GridBagConstraints.LINE_START;
296                 c.insets = il;
297                 c.ipady = 5;
298                 apogee_delay_label = new JLabel("Apogee Delay(s):");
299                 pane.add(apogee_delay_label, c);
300
301                 c = new GridBagConstraints();
302                 c.gridx = 4; c.gridy = row;
303                 c.gridwidth = 4;
304                 c.fill = GridBagConstraints.HORIZONTAL;
305                 c.weightx = 1;
306                 c.anchor = GridBagConstraints.LINE_START;
307                 c.insets = ir;
308                 c.ipady = 5;
309                 apogee_delay_value = new JComboBox(apogee_delay_values);
310                 apogee_delay_value.setEditable(true);
311                 apogee_delay_value.addItemListener(this);
312                 pane.add(apogee_delay_value, c);
313                 apogee_delay_value.setToolTipText("Delay after apogee before charge fires");
314                 row++;
315
316                 /* Apogee lockout */
317                 c = new GridBagConstraints();
318                 c.gridx = 0; c.gridy = row;
319                 c.gridwidth = 4;
320                 c.fill = GridBagConstraints.NONE;
321                 c.anchor = GridBagConstraints.LINE_START;
322                 c.insets = il;
323                 c.ipady = 5;
324                 apogee_lockout_label = new JLabel("Apogee Lockout(s):");
325                 pane.add(apogee_lockout_label, c);
326
327                 c = new GridBagConstraints();
328                 c.gridx = 4; c.gridy = row;
329                 c.gridwidth = 4;
330                 c.fill = GridBagConstraints.HORIZONTAL;
331                 c.weightx = 1;
332                 c.anchor = GridBagConstraints.LINE_START;
333                 c.insets = ir;
334                 c.ipady = 5;
335                 apogee_lockout_value = new JComboBox(apogee_lockout_values);
336                 apogee_lockout_value.setEditable(true);
337                 apogee_lockout_value.addItemListener(this);
338                 pane.add(apogee_lockout_value, c);
339                 apogee_lockout_value.setToolTipText("Time after boost while apogee detection is locked out");
340                 row++;
341
342                 /* Frequency */
343                 c = new GridBagConstraints();
344                 c.gridx = 0; c.gridy = row;
345                 c.gridwidth = 4;
346                 c.fill = GridBagConstraints.NONE;
347                 c.anchor = GridBagConstraints.LINE_START;
348                 c.insets = il;
349                 c.ipady = 5;
350                 radio_frequency_label = new JLabel("Frequency:");
351                 pane.add(radio_frequency_label, c);
352
353                 c = new GridBagConstraints();
354                 c.gridx = 4; c.gridy = row;
355                 c.gridwidth = 4;
356                 c.fill = GridBagConstraints.HORIZONTAL;
357                 c.weightx = 1;
358                 c.anchor = GridBagConstraints.LINE_START;
359                 c.insets = ir;
360                 c.ipady = 5;
361                 radio_frequency_value = new AltosFreqList();
362                 radio_frequency_value.addItemListener(this);
363                 pane.add(radio_frequency_value, c);
364                 radio_frequency_value.setToolTipText("Telemetry, RDF and packet frequency");
365                 row++;
366
367                 /* Radio Calibration */
368                 c = new GridBagConstraints();
369                 c.gridx = 0; c.gridy = row;
370                 c.gridwidth = 4;
371                 c.fill = GridBagConstraints.NONE;
372                 c.anchor = GridBagConstraints.LINE_START;
373                 c.insets = il;
374                 c.ipady = 5;
375                 radio_calibration_label = new JLabel("RF Calibration:");
376                 pane.add(radio_calibration_label, c);
377
378                 c = new GridBagConstraints();
379                 c.gridx = 4; c.gridy = row;
380                 c.gridwidth = 4;
381                 c.fill = GridBagConstraints.HORIZONTAL;
382                 c.weightx = 1;
383                 c.anchor = GridBagConstraints.LINE_START;
384                 c.insets = ir;
385                 c.ipady = 5;
386                 radio_calibration_value = new JTextField(String.format("%d", 1186611));
387                 radio_calibration_value.getDocument().addDocumentListener(this);
388                 if (remote)
389                         radio_calibration_value.setEnabled(false);
390                 pane.add(radio_calibration_value, c);
391                 set_radio_calibration_tool_tip();
392                 row++;
393
394                 /* Radio Enable */
395                 c = new GridBagConstraints();
396                 c.gridx = 0; c.gridy = row;
397                 c.gridwidth = 4;
398                 c.fill = GridBagConstraints.NONE;
399                 c.anchor = GridBagConstraints.LINE_START;
400                 c.insets = il;
401                 c.ipady = 5;
402                 radio_enable_label = new JLabel("Telemetry/RDF Enable:");
403                 pane.add(radio_enable_label, c);
404
405                 c = new GridBagConstraints();
406                 c.gridx = 4; c.gridy = row;
407                 c.gridwidth = 4;
408                 c.fill = GridBagConstraints.HORIZONTAL;
409                 c.weightx = 1;
410                 c.anchor = GridBagConstraints.LINE_START;
411                 c.insets = ir;
412                 c.ipady = 5;
413                 radio_enable_value = new JRadioButton("Enabled");
414                 radio_enable_value.addItemListener(this);
415                 pane.add(radio_enable_value, c);
416                 set_radio_enable_tool_tip();
417                 row++;
418
419                 /* Callsign */
420                 c = new GridBagConstraints();
421                 c.gridx = 0; c.gridy = row;
422                 c.gridwidth = 4;
423                 c.fill = GridBagConstraints.NONE;
424                 c.anchor = GridBagConstraints.LINE_START;
425                 c.insets = il;
426                 c.ipady = 5;
427                 callsign_label = new JLabel("Callsign:");
428                 pane.add(callsign_label, c);
429
430                 c = new GridBagConstraints();
431                 c.gridx = 4; c.gridy = row;
432                 c.gridwidth = 4;
433                 c.fill = GridBagConstraints.HORIZONTAL;
434                 c.weightx = 1;
435                 c.anchor = GridBagConstraints.LINE_START;
436                 c.insets = ir;
437                 c.ipady = 5;
438                 callsign_value = new JTextField(AltosUIPreferences.callsign());
439                 callsign_value.getDocument().addDocumentListener(this);
440                 pane.add(callsign_value, c);
441                 callsign_value.setToolTipText("Callsign reported in telemetry data");
442                 row++;
443
444                 /* Flight log max */
445                 c = new GridBagConstraints();
446                 c.gridx = 0; c.gridy = row;
447                 c.gridwidth = 4;
448                 c.fill = GridBagConstraints.NONE;
449                 c.anchor = GridBagConstraints.LINE_START;
450                 c.insets = il;
451                 c.ipady = 5;
452                 flight_log_max_label = new JLabel("Maximum Flight Log Size:");
453                 pane.add(flight_log_max_label, c);
454
455                 c = new GridBagConstraints();
456                 c.gridx = 4; c.gridy = row;
457                 c.gridwidth = 4;
458                 c.fill = GridBagConstraints.HORIZONTAL;
459                 c.weightx = 1;
460                 c.anchor = GridBagConstraints.LINE_START;
461                 c.insets = ir;
462                 c.ipady = 5;
463                 flight_log_max_value = new JComboBox(flight_log_max_values);
464                 flight_log_max_value.setEditable(true);
465                 flight_log_max_value.addItemListener(this);
466                 pane.add(flight_log_max_value, c);
467                 set_flight_log_max_tool_tip();
468                 row++;
469
470                 /* Ignite mode */
471                 c = new GridBagConstraints();
472                 c.gridx = 0; c.gridy = row;
473                 c.gridwidth = 4;
474                 c.fill = GridBagConstraints.NONE;
475                 c.anchor = GridBagConstraints.LINE_START;
476                 c.insets = il;
477                 c.ipady = 5;
478                 ignite_mode_label = new JLabel("Igniter Firing Mode:");
479                 pane.add(ignite_mode_label, c);
480
481                 c = new GridBagConstraints();
482                 c.gridx = 4; c.gridy = row;
483                 c.gridwidth = 4;
484                 c.fill = GridBagConstraints.HORIZONTAL;
485                 c.weightx = 1;
486                 c.anchor = GridBagConstraints.LINE_START;
487                 c.insets = ir;
488                 c.ipady = 5;
489                 ignite_mode_value = new JComboBox(ignite_mode_values);
490                 ignite_mode_value.setEditable(false);
491                 ignite_mode_value.addItemListener(this);
492                 pane.add(ignite_mode_value, c);
493                 set_ignite_mode_tool_tip();
494                 row++;
495
496                 /* Pad orientation */
497                 c = new GridBagConstraints();
498                 c.gridx = 0; c.gridy = row;
499                 c.gridwidth = 4;
500                 c.fill = GridBagConstraints.NONE;
501                 c.anchor = GridBagConstraints.LINE_START;
502                 c.insets = il;
503                 c.ipady = 5;
504                 pad_orientation_label = new JLabel("Pad Orientation:");
505                 pane.add(pad_orientation_label, c);
506
507                 c = new GridBagConstraints();
508                 c.gridx = 4; c.gridy = row;
509                 c.gridwidth = 4;
510                 c.fill = GridBagConstraints.HORIZONTAL;
511                 c.weightx = 1;
512                 c.anchor = GridBagConstraints.LINE_START;
513                 c.insets = ir;
514                 c.ipady = 5;
515                 pad_orientation_value = new JComboBox(pad_orientation_values);
516                 pad_orientation_value.setEditable(false);
517                 pad_orientation_value.addItemListener(this);
518                 pane.add(pad_orientation_value, c);
519                 set_pad_orientation_tool_tip();
520                 row++;
521
522                 /* Buttons */
523                 c = new GridBagConstraints();
524                 c.gridx = 0; c.gridy = row;
525                 c.gridwidth = 2;
526                 c.fill = GridBagConstraints.NONE;
527                 c.anchor = GridBagConstraints.LINE_START;
528                 c.insets = il;
529                 save = new JButton("Save");
530                 pane.add(save, c);
531                 save.addActionListener(this);
532                 save.setActionCommand("Save");
533
534                 c = new GridBagConstraints();
535                 c.gridx = 2; c.gridy = row;
536                 c.gridwidth = 2;
537                 c.fill = GridBagConstraints.NONE;
538                 c.anchor = GridBagConstraints.CENTER;
539                 c.insets = il;
540                 reset = new JButton("Reset");
541                 pane.add(reset, c);
542                 reset.addActionListener(this);
543                 reset.setActionCommand("Reset");
544
545                 c = new GridBagConstraints();
546                 c.gridx = 4; c.gridy = row;
547                 c.gridwidth = 2;
548                 c.fill = GridBagConstraints.NONE;
549                 c.anchor = GridBagConstraints.CENTER;
550                 c.insets = il;
551                 reboot = new JButton("Reboot");
552                 pane.add(reboot, c);
553                 reboot.addActionListener(this);
554                 reboot.setActionCommand("Reboot");
555
556                 c = new GridBagConstraints();
557                 c.gridx = 6; c.gridy = row;
558                 c.gridwidth = 2;
559                 c.fill = GridBagConstraints.NONE;
560                 c.anchor = GridBagConstraints.LINE_END;
561                 c.insets = il;
562                 close = new JButton("Close");
563                 pane.add(close, c);
564                 close.addActionListener(this);
565                 close.setActionCommand("Close");
566
567                 addWindowListener(new ConfigListener(this));
568         }
569
570         /* Once the initial values are set, the config code will show the dialog */
571         public void make_visible() {
572                 pack();
573                 setLocationRelativeTo(owner);
574                 setVisible(true);
575         }
576
577         /* If any values have been changed, confirm before closing */
578         public boolean check_dirty(String operation) {
579                 if (dirty) {
580                         Object[] options = { String.format("%s anyway", operation), "Keep editing" };
581                         int i;
582                         i = JOptionPane.showOptionDialog(this,
583                                                          String.format("Configuration modified. %s anyway?", operation),
584                                                          "Configuration Modified",
585                                                          JOptionPane.DEFAULT_OPTION,
586                                                          JOptionPane.WARNING_MESSAGE,
587                                                          null, options, options[1]);
588                         if (i != 0)
589                                 return false;
590                 }
591                 return true;
592         }
593
594         /* Listen for events from our buttons */
595         public void actionPerformed(ActionEvent e) {
596                 String  cmd = e.getActionCommand();
597
598                 if (cmd.equals("Close") || cmd.equals("Reboot"))
599                         if (!check_dirty(cmd))
600                                 return;
601                 listener.actionPerformed(e);
602                 if (cmd.equals("Close") || cmd.equals("Reboot")) {
603                         setVisible(false);
604                         dispose();
605                 }
606                 dirty = false;
607         }
608
609         /* ItemListener interface method */
610         public void itemStateChanged(ItemEvent e) {
611                 dirty = true;
612         }
613
614         /* DocumentListener interface methods */
615         public void changedUpdate(DocumentEvent e) {
616                 dirty = true;
617         }
618
619         public void insertUpdate(DocumentEvent e) {
620                 dirty = true;
621         }
622
623         public void removeUpdate(DocumentEvent e) {
624                 dirty = true;
625         }
626
627         /* Let the config code hook on a listener */
628         public void addActionListener(ActionListener l) {
629                 listener = l;
630         }
631
632         /* set and get all of the dialog values */
633         public void set_product(String product) {
634                 radio_frequency_value.set_product(product);
635                 product_value.setText(product);
636                 set_pad_orientation_tool_tip();
637                 set_flight_log_max_tool_tip();
638         }
639
640         public void set_version(String version) {
641                 version_value.setText(version);
642         }
643
644         public void set_serial(int serial) {
645                 radio_frequency_value.set_serial(serial);
646                 serial_value.setText(String.format("%d", serial));
647         }
648
649         public void set_main_deploy(int new_main_deploy) {
650                 main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
651         }
652
653         public int main_deploy() {
654                 return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
655         }
656
657         public void set_apogee_delay(int new_apogee_delay) {
658                 apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
659         }
660
661         public int apogee_delay() {
662                 return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
663         }
664
665         public void set_apogee_lockout(int new_apogee_lockout) {
666                 apogee_lockout_value.setSelectedItem(Integer.toString(new_apogee_lockout));
667         }
668
669         public int apogee_lockout() {
670                 return Integer.parseInt(apogee_lockout_value.getSelectedItem().toString());
671         }
672
673         public void set_radio_frequency(double new_radio_frequency) {
674                 int i;
675                 for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
676                         AltosFrequency  f = (AltosFrequency) radio_frequency_value.getItemAt(i);
677                         
678                         if (f.close(new_radio_frequency)) {
679                                 radio_frequency_value.setSelectedIndex(i);
680                                 return;
681                         }
682                 }
683                 for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
684                         AltosFrequency  f = (AltosFrequency) radio_frequency_value.getItemAt(i);
685                         
686                         if (new_radio_frequency < f.frequency)
687                                 break;
688                 }
689                 String  description = String.format("%s serial %s",
690                                                     product_value.getText(),
691                                                     serial_value.getText());
692                 AltosFrequency  new_frequency = new AltosFrequency(new_radio_frequency, description);
693                 AltosUIPreferences.add_common_frequency(new_frequency);
694                 radio_frequency_value.insertItemAt(new_frequency, i);
695                 radio_frequency_value.setSelectedIndex(i);
696         }
697
698         public double radio_frequency() {
699                 return radio_frequency_value.frequency();
700         }
701
702         public void set_radio_calibration(int new_radio_calibration) {
703                 radio_calibration_value.setText(String.format("%d", new_radio_calibration));
704         }
705
706         public int radio_calibration() {
707                 return Integer.parseInt(radio_calibration_value.getText());
708         }
709
710         public void set_radio_enable(int new_radio_enable) {
711                 if (new_radio_enable >= 0) {
712                         radio_enable_value.setSelected(new_radio_enable > 0);
713                         radio_enable_value.setEnabled(true);
714                 } else {
715                         radio_enable_value.setSelected(true);
716                         radio_enable_value.setEnabled(false);
717                 }
718                 set_radio_enable_tool_tip();
719         }
720
721         public int radio_enable() {
722                 if (radio_enable_value.isEnabled())
723                         return radio_enable_value.isSelected() ? 1 : 0;
724                 else
725                         return -1;
726         }
727
728         public void set_callsign(String new_callsign) {
729                 callsign_value.setText(new_callsign);
730         }
731
732         public String callsign() {
733                 return callsign_value.getText();
734         }
735
736         public void set_flight_log_max(int new_flight_log_max) {
737                 if (new_flight_log_max == 0)
738                         flight_log_max_value.setEnabled(false);
739                 flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max));
740                 set_flight_log_max_tool_tip();
741         }
742
743         public void set_flight_log_max_enabled(boolean enable) {
744                 flight_log_max_value.setEnabled(enable);
745                 set_flight_log_max_tool_tip();
746         }
747
748         public int flight_log_max() {
749                 return Integer.parseInt(flight_log_max_value.getSelectedItem().toString());
750         }
751
752         public void set_flight_log_max_limit(int flight_log_max_limit) {
753                 boolean any_added = false;
754                 flight_log_max_value.removeAllItems();
755                 for (int i = 0; i < flight_log_max_values.length; i++) {
756                         if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){
757                                 flight_log_max_value.addItem(flight_log_max_values[i]);
758                                 any_added = true;
759                         }
760                 }
761                 flight_log_max_value.addItem(String.format("%d", flight_log_max_limit));
762         }
763
764         public void set_ignite_mode(int new_ignite_mode) {
765                 if (new_ignite_mode >= ignite_mode_values.length)
766                         new_ignite_mode = 0;
767                 if (new_ignite_mode < 0) {
768                         ignite_mode_value.setEnabled(false);
769                         new_ignite_mode = 0;
770                 } else {
771                         ignite_mode_value.setEnabled(true);
772                 }
773                 ignite_mode_value.setSelectedIndex(new_ignite_mode);
774                 set_ignite_mode_tool_tip();
775         }
776
777         public int ignite_mode() {
778                 if (ignite_mode_value.isEnabled())
779                         return ignite_mode_value.getSelectedIndex();
780                 else
781                         return -1;
782         }
783
784
785         public void set_pad_orientation(int new_pad_orientation) {
786                 if (new_pad_orientation >= pad_orientation_values.length)
787                         new_pad_orientation = 0;
788                 if (new_pad_orientation < 0) {
789                         pad_orientation_value.setEnabled(false);
790                         new_pad_orientation = 0;
791                 } else {
792                         pad_orientation_value.setEnabled(true);
793                 }
794                 pad_orientation_value.setSelectedIndex(new_pad_orientation);
795                 set_pad_orientation_tool_tip();
796         }
797
798         public int pad_orientation() {
799                 if (pad_orientation_value.isEnabled())
800                         return pad_orientation_value.getSelectedIndex();
801                 else
802                         return -1;
803         }
804
805         public void set_clean() {
806                 dirty = false;
807         }
808 }