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