altosui: Add RF calibration to TeleMetrum config dialog
[fw/altos] / ao-tools / 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 altosui.Altos;
33 import altosui.AltosSerial;
34 import altosui.AltosSerialMonitor;
35 import altosui.AltosRecord;
36 import altosui.AltosTelemetry;
37 import altosui.AltosState;
38 import altosui.AltosDeviceDialog;
39 import altosui.AltosPreferences;
40 import altosui.AltosLog;
41 import altosui.AltosVoice;
42 import altosui.AltosFlightStatusTableModel;
43 import altosui.AltosFlightInfoTableModel;
44
45 import libaltosJNI.*;
46
47 public class AltosConfigUI
48         extends JDialog
49         implements ActionListener, ItemListener, DocumentListener
50 {
51
52         Container       pane;
53         Box             box;
54         JLabel          product_label;
55         JLabel          version_label;
56         JLabel          serial_label;
57         JLabel          main_deploy_label;
58         JLabel          apogee_delay_label;
59         JLabel          radio_channel_label;
60         JLabel          radio_calibration_label;
61         JLabel          callsign_label;
62
63         public boolean          dirty;
64
65         JFrame          owner;
66         JLabel          product_value;
67         JLabel          version_value;
68         JLabel          serial_value;
69         JComboBox       main_deploy_value;
70         JComboBox       apogee_delay_value;
71         JComboBox       radio_channel_value;
72         JTextField      radio_calibration_value;
73         JTextField      callsign_value;
74
75         JButton         save;
76         JButton         reset;
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[] radio_channel_values = new String[10];
91                 {
92                         for (int i = 0; i <= 9; i++)
93                                 radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)",
94                                                                         i, 434.550 + i * 0.1);
95                 }
96
97         /* A window listener to catch closing events and tell the config code */
98         class ConfigListener extends WindowAdapter {
99                 AltosConfigUI   ui;
100
101                 public ConfigListener(AltosConfigUI this_ui) {
102                         ui = this_ui;
103                 }
104
105                 public void windowClosing(WindowEvent e) {
106                         ui.actionPerformed(new ActionEvent(e.getSource(),
107                                                            ActionEvent.ACTION_PERFORMED,
108                                                            "close"));
109                 }
110         }
111
112         /* Build the UI using a grid bag */
113         public AltosConfigUI(JFrame in_owner) {
114                 super (in_owner, "Configure TeleMetrum", false);
115
116                 owner = in_owner;
117                 GridBagConstraints c;
118
119                 Insets il = new Insets(4,4,4,4);
120                 Insets ir = new Insets(4,4,4,4);
121
122                 pane = getContentPane();
123                 pane.setLayout(new GridBagLayout());
124
125                 /* Product */
126                 c = new GridBagConstraints();
127                 c.gridx = 0; c.gridy = 0;
128                 c.gridwidth = 3;
129                 c.fill = GridBagConstraints.NONE;
130                 c.anchor = GridBagConstraints.LINE_START;
131                 c.insets = il;
132                 product_label = new JLabel("Product:");
133                 pane.add(product_label, c);
134
135                 c = new GridBagConstraints();
136                 c.gridx = 3; c.gridy = 0;
137                 c.gridwidth = 3;
138                 c.fill = GridBagConstraints.HORIZONTAL;
139                 c.weightx = 1;
140                 c.anchor = GridBagConstraints.LINE_START;
141                 c.insets = ir;
142                 product_value = new JLabel("");
143                 pane.add(product_value, c);
144
145                 /* Version */
146                 c = new GridBagConstraints();
147                 c.gridx = 0; c.gridy = 1;
148                 c.gridwidth = 3;
149                 c.fill = GridBagConstraints.NONE;
150                 c.anchor = GridBagConstraints.LINE_START;
151                 c.insets = il;
152                 c.ipady = 5;
153                 version_label = new JLabel("Software version:");
154                 pane.add(version_label, c);
155
156                 c = new GridBagConstraints();
157                 c.gridx = 3; c.gridy = 1;
158                 c.gridwidth = 3;
159                 c.fill = GridBagConstraints.HORIZONTAL;
160                 c.weightx = 1;
161                 c.anchor = GridBagConstraints.LINE_START;
162                 c.insets = ir;
163                 c.ipady = 5;
164                 version_value = new JLabel("");
165                 pane.add(version_value, c);
166
167                 /* Serial */
168                 c = new GridBagConstraints();
169                 c.gridx = 0; c.gridy = 2;
170                 c.gridwidth = 3;
171                 c.fill = GridBagConstraints.NONE;
172                 c.anchor = GridBagConstraints.LINE_START;
173                 c.insets = il;
174                 c.ipady = 5;
175                 serial_label = new JLabel("Serial:");
176                 pane.add(serial_label, c);
177
178                 c = new GridBagConstraints();
179                 c.gridx = 3; c.gridy = 2;
180                 c.gridwidth = 3;
181                 c.fill = GridBagConstraints.HORIZONTAL;
182                 c.weightx = 1;
183                 c.anchor = GridBagConstraints.LINE_START;
184                 c.insets = ir;
185                 c.ipady = 5;
186                 serial_value = new JLabel("");
187                 pane.add(serial_value, c);
188
189                 /* Main deploy */
190                 c = new GridBagConstraints();
191                 c.gridx = 0; c.gridy = 3;
192                 c.gridwidth = 3;
193                 c.fill = GridBagConstraints.NONE;
194                 c.anchor = GridBagConstraints.LINE_START;
195                 c.insets = il;
196                 c.ipady = 5;
197                 main_deploy_label = new JLabel("Main Deploy Altitude(m):");
198                 pane.add(main_deploy_label, c);
199
200                 c = new GridBagConstraints();
201                 c.gridx = 3; c.gridy = 3;
202                 c.gridwidth = 3;
203                 c.fill = GridBagConstraints.HORIZONTAL;
204                 c.weightx = 1;
205                 c.anchor = GridBagConstraints.LINE_START;
206                 c.insets = ir;
207                 c.ipady = 5;
208                 main_deploy_value = new JComboBox(main_deploy_values);
209                 main_deploy_value.setEditable(true);
210                 main_deploy_value.addItemListener(this);
211                 pane.add(main_deploy_value, c);
212
213                 /* Apogee delay */
214                 c = new GridBagConstraints();
215                 c.gridx = 0; c.gridy = 4;
216                 c.gridwidth = 3;
217                 c.fill = GridBagConstraints.NONE;
218                 c.anchor = GridBagConstraints.LINE_START;
219                 c.insets = il;
220                 c.ipady = 5;
221                 apogee_delay_label = new JLabel("Apogee Delay(s):");
222                 pane.add(apogee_delay_label, c);
223
224                 c = new GridBagConstraints();
225                 c.gridx = 3; c.gridy = 4;
226                 c.gridwidth = 3;
227                 c.fill = GridBagConstraints.HORIZONTAL;
228                 c.weightx = 1;
229                 c.anchor = GridBagConstraints.LINE_START;
230                 c.insets = ir;
231                 c.ipady = 5;
232                 apogee_delay_value = new JComboBox(apogee_delay_values);
233                 apogee_delay_value.setEditable(true);
234                 apogee_delay_value.addItemListener(this);
235                 pane.add(apogee_delay_value, c);
236
237                 /* Radio channel */
238                 c = new GridBagConstraints();
239                 c.gridx = 0; c.gridy = 5;
240                 c.gridwidth = 3;
241                 c.fill = GridBagConstraints.NONE;
242                 c.anchor = GridBagConstraints.LINE_START;
243                 c.insets = il;
244                 c.ipady = 5;
245                 radio_channel_label = new JLabel("Radio Channel:");
246                 pane.add(radio_channel_label, c);
247
248                 c = new GridBagConstraints();
249                 c.gridx = 3; c.gridy = 5;
250                 c.gridwidth = 3;
251                 c.fill = GridBagConstraints.HORIZONTAL;
252                 c.weightx = 1;
253                 c.anchor = GridBagConstraints.LINE_START;
254                 c.insets = ir;
255                 c.ipady = 5;
256                 radio_channel_value = new JComboBox(radio_channel_values);
257                 radio_channel_value.setEditable(false);
258                 radio_channel_value.addItemListener(this);
259                 pane.add(radio_channel_value, c);
260
261                 /* Radio Calibration */
262                 c = new GridBagConstraints();
263                 c.gridx = 0; c.gridy = 6;
264                 c.gridwidth = 3;
265                 c.fill = GridBagConstraints.NONE;
266                 c.anchor = GridBagConstraints.LINE_START;
267                 c.insets = il;
268                 c.ipady = 5;
269                 radio_calibration_label = new JLabel("RF Calibration:");
270                 pane.add(radio_calibration_label, c);
271
272                 c = new GridBagConstraints();
273                 c.gridx = 3; c.gridy = 6;
274                 c.gridwidth = 3;
275                 c.fill = GridBagConstraints.HORIZONTAL;
276                 c.weightx = 1;
277                 c.anchor = GridBagConstraints.LINE_START;
278                 c.insets = ir;
279                 c.ipady = 5;
280                 radio_calibration_value = new JTextField(String.format("%d", 1186611));
281                 radio_calibration_value.getDocument().addDocumentListener(this);
282                 pane.add(radio_calibration_value, c);
283
284                 /* Callsign */
285                 c = new GridBagConstraints();
286                 c.gridx = 0; c.gridy = 7;
287                 c.gridwidth = 3;
288                 c.fill = GridBagConstraints.NONE;
289                 c.anchor = GridBagConstraints.LINE_START;
290                 c.insets = il;
291                 c.ipady = 5;
292                 callsign_label = new JLabel("Callsign:");
293                 pane.add(callsign_label, c);
294
295                 c = new GridBagConstraints();
296                 c.gridx = 3; c.gridy = 7;
297                 c.gridwidth = 3;
298                 c.fill = GridBagConstraints.HORIZONTAL;
299                 c.weightx = 1;
300                 c.anchor = GridBagConstraints.LINE_START;
301                 c.insets = ir;
302                 c.ipady = 5;
303                 callsign_value = new JTextField("N0CALL");
304                 callsign_value.getDocument().addDocumentListener(this);
305                 pane.add(callsign_value, c);
306
307                 /* Buttons */
308                 c = new GridBagConstraints();
309                 c.gridx = 0; c.gridy = 8;
310                 c.gridwidth = 6;
311                 c.fill = GridBagConstraints.NONE;
312                 c.anchor = GridBagConstraints.LINE_START;
313                 c.insets = il;
314                 save = new JButton("Save");
315                 pane.add(save, c);
316                 save.addActionListener(this);
317                 save.setActionCommand("save");
318
319                 c = new GridBagConstraints();
320                 c.gridx = 0; c.gridy = 8;
321                 c.gridwidth = 6;
322                 c.fill = GridBagConstraints.NONE;
323                 c.anchor = GridBagConstraints.CENTER;
324                 c.insets = il;
325                 reset = new JButton("Reset");
326                 pane.add(reset, c);
327                 reset.addActionListener(this);
328                 reset.setActionCommand("reset");
329
330                 c = new GridBagConstraints();
331                 c.gridx = 0; c.gridy = 8;
332                 c.gridwidth = 6;
333                 c.fill = GridBagConstraints.NONE;
334                 c.anchor = GridBagConstraints.LINE_END;
335                 c.insets = il;
336                 close = new JButton("Close");
337                 pane.add(close, c);
338                 close.addActionListener(this);
339                 close.setActionCommand("close");
340
341                 addWindowListener(new ConfigListener(this));
342         }
343
344         /* Once the initial values are set, the config code will show the dialog */
345         public void make_visible() {
346                 pack();
347                 setLocationRelativeTo(owner);
348                 setVisible(true);
349         }
350
351         /* If any values have been changed, confirm before closing */
352         public boolean check_dirty() {
353                 if (dirty) {
354                         Object[] options = { "Close anyway", "Keep editing" };
355                         int i;
356                         i = JOptionPane.showOptionDialog(this,
357                                                          "Configuration modified, close anyway?",
358                                                          "Configuration Modified",
359                                                          JOptionPane.DEFAULT_OPTION,
360                                                          JOptionPane.WARNING_MESSAGE,
361                                                          null, options, options[1]);
362                         if (i != 0)
363                                 return false;
364                 }
365                 return true;
366         }
367
368         /* Listen for events from our buttons */
369         public void actionPerformed(ActionEvent e) {
370                 String  cmd = e.getActionCommand();
371
372                 if (cmd.equals("close"))
373                         if (!check_dirty())
374                                 return;
375                 listener.actionPerformed(e);
376                 if (cmd.equals("close")) {
377                         setVisible(false);
378                         dispose();
379                 }
380                 dirty = false;
381         }
382
383         /* ItemListener interface method */
384         public void itemStateChanged(ItemEvent e) {
385                 dirty = true;
386         }
387
388         /* DocumentListener interface methods */
389         public void changedUpdate(DocumentEvent e) {
390                 dirty = true;
391         }
392
393         public void insertUpdate(DocumentEvent e) {
394                 dirty = true;
395         }
396
397         public void removeUpdate(DocumentEvent e) {
398                 dirty = true;
399         }
400
401         /* Let the config code hook on a listener */
402         public void addActionListener(ActionListener l) {
403                 listener = l;
404         }
405
406         /* set and get all of the dialog values */
407         public void set_product(String product) {
408                 product_value.setText(product);
409         }
410
411         public void set_version(String version) {
412                 version_value.setText(version);
413         }
414
415         public void set_serial(int serial) {
416                 serial_value.setText(String.format("%d", serial));
417         }
418
419         public void set_main_deploy(int new_main_deploy) {
420                 main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
421         }
422
423         public int main_deploy() {
424                 return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
425         }
426
427         public void set_apogee_delay(int new_apogee_delay) {
428                 apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
429         }
430
431         public int apogee_delay() {
432                 return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
433         }
434
435         public void set_radio_channel(int new_radio_channel) {
436                 radio_channel_value.setSelectedIndex(new_radio_channel);
437         }
438
439         public int radio_channel() {
440                 return radio_channel_value.getSelectedIndex();
441         }
442
443         public void set_radio_calibration(int new_radio_calibration) {
444                 radio_calibration_value.setText(String.format("%d", new_radio_calibration));
445         }
446
447         public int radio_calibration() {
448                 return Integer.parseInt(radio_calibration_value.getText());
449         }
450
451         public void set_callsign(String new_callsign) {
452                 callsign_value.setText(new_callsign);
453         }
454
455         public String callsign() {
456                 return callsign_value.getText();
457         }
458
459         public void set_clean() {
460                 dirty = false;
461         }
462
463  }