92191564e395219270cb1cf1795aa078b664f36e
[fw/altos] / altosui / AltosConfig.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.event.*;
21 import javax.swing.*;
22 import java.io.*;
23 import java.util.concurrent.*;
24 import org.altusmetrum.AltosLib.*;
25 import java.text.*;
26
27 public class AltosConfig implements ActionListener {
28
29         class int_ref {
30                 int     value;
31
32                 public int get() {
33                         return value;
34                 }
35                 public void set(int i) {
36                         value = i;
37                 }
38                 public int_ref(int i) {
39                         value = i;
40                 }
41         }
42
43         class string_ref {
44                 String  value;
45
46                 public String get() {
47                         return value;
48                 }
49                 public void set(String i) {
50                         value = i;
51                 }
52                 public string_ref(String i) {
53                         value = i;
54                 }
55         }
56
57         JFrame          owner;
58         AltosDevice     device;
59         AltosSerial     serial_line;
60         boolean         remote;
61
62         AltosConfigData data;
63         AltosConfigUI   config_ui;
64         boolean         serial_started;
65         boolean         made_visible;
66
67         void start_serial() throws InterruptedException, TimeoutException {
68                 serial_started = true;
69                 if (remote)
70                         serial_line.start_remote();
71         }
72
73         void stop_serial() throws InterruptedException {
74                 if (!serial_started)
75                         return;
76                 serial_started = false;
77                 if (remote)
78                         serial_line.stop_remote();
79         }
80
81         int log_limit() {
82                 if (data.storage_size > 0 && data.storage_erase_unit > 0) {
83                         int     log_limit = data.storage_size - data.storage_erase_unit;
84                         if (log_limit > 0)
85                                 return log_limit / 1024;
86                 }
87                 return 1024;
88         }
89
90         void update_ui() {
91                 config_ui.set_serial(data.serial);
92                 config_ui.set_product(data.product);
93                 config_ui.set_version(data.version);
94                 config_ui.set_main_deploy(data.main_deploy);
95                 config_ui.set_apogee_delay(data.apogee_delay);
96                 config_ui.set_apogee_lockout(data.apogee_lockout);
97                 config_ui.set_radio_calibration(data.radio_calibration);
98                 config_ui.set_radio_frequency(frequency());
99                 boolean max_enabled = true;
100                 switch (data.log_format) {
101                 case Altos.AO_LOG_FORMAT_TINY:
102                         max_enabled = false;
103                         break;
104                 default:
105                         if (data.stored_flight >= 0)
106                                 max_enabled = false;
107                         break;
108                 }
109                 config_ui.set_flight_log_max_enabled(max_enabled);
110                 config_ui.set_radio_enable(data.radio_enable);
111                 config_ui.set_flight_log_max_limit(log_limit());
112                 config_ui.set_flight_log_max(data.flight_log_max);
113                 config_ui.set_ignite_mode(data.ignite_mode);
114                 config_ui.set_pad_orientation(data.pad_orientation);
115                 config_ui.set_callsign(data.callsign);
116                 config_ui.set_pyros(data.pyros);
117                 config_ui.set_has_pyro(data.npyro > 0);
118                 config_ui.set_clean();
119                 if (!made_visible) {
120                         made_visible = true;
121                         config_ui.make_visible();
122                 }
123         }
124
125         int     pyro;
126
127         final static int        serial_mode_read = 0;
128         final static int        serial_mode_save = 1;
129         final static int        serial_mode_reboot = 2;
130
131         class SerialData implements Runnable {
132                 AltosConfig     config;
133                 int             serial_mode;
134
135                 void callback(String in_cmd) {
136                         final String cmd = in_cmd;
137                         Runnable r = new Runnable() {
138                                         public void run() {
139                                                 if (cmd.equals("abort")) {
140                                                         abort();
141                                                 } else if (cmd.equals("all finished")) {
142                                                         if (serial_line != null)
143                                                                 update_ui();
144                                                 }
145                                         }
146                                 };
147                         SwingUtilities.invokeLater(r);
148                 }
149
150                 void get_data() {
151                         data = null;
152                         try {
153                                 start_serial();
154                                 data = new AltosConfigData(config.serial_line);
155                         } catch (InterruptedException ie) {
156                         } catch (TimeoutException te) {
157                                 try {
158                                         stop_serial();
159                                         callback("abort");
160                                 } catch (InterruptedException ie) {
161                                 }
162                         } finally {
163                                 try {
164                                         stop_serial();
165                                 } catch (InterruptedException ie) {
166                                 }
167                         }
168                         callback("all finished");
169                 }
170
171                 void save_data() {
172                         try {
173                                 double frequency = frequency();
174                                 boolean has_frequency = data.radio_frequency > 0;
175                                 boolean has_setting = data.radio_setting > 0;
176                                 start_serial();
177                                 serial_line.printf("c m %d\n", data.main_deploy);
178                                 serial_line.printf("c d %d\n", data.apogee_delay);
179                                 serial_line.printf("c L %d\n", data.apogee_lockout);
180                                 if (!remote)
181                                         serial_line.printf("c f %d\n", data.radio_calibration);
182                                 serial_line.set_radio_frequency(frequency,
183                                                                 has_frequency,
184                                                                 has_setting,
185                                                                 data.radio_calibration);
186                                 if (remote) {
187                                         serial_line.stop_remote();
188                                         serial_line.set_radio_frequency(frequency);
189                                         AltosUIPreferences.set_frequency(device.getSerial(), frequency);
190                                         serial_line.start_remote();
191                                 }
192                                 serial_line.printf("c c %s\n", data.callsign);
193                                 if (data.flight_log_max != 0)
194                                         serial_line.printf("c l %d\n", data.flight_log_max);
195                                 if (data.radio_enable >= 0)
196                                         serial_line.printf("c e %d\n", data.radio_enable);
197                                 if (data.ignite_mode >= 0)
198                                         serial_line.printf("c i %d\n", data.ignite_mode);
199                                 if (data.pad_orientation >= 0)
200                                         serial_line.printf("c o %d\n", data.pad_orientation);
201                                 if (data.pyros.length > 0) {
202                                         for (int p = 0; p < data.pyros.length; p++) {
203                                                 serial_line.printf("c P %s\n",
204                                                                    data.pyros[p].toString());
205                                         }
206                                 }
207                                 serial_line.printf("c w\n");
208                         } catch (InterruptedException ie) {
209                         } catch (TimeoutException te) {
210                         } finally {
211                                 try {
212                                         stop_serial();
213                                 } catch (InterruptedException ie) {
214                                 }
215                         }
216                 }
217
218                 void reboot() {
219                         try {
220                                 start_serial();
221                                 serial_line.printf("r eboot\n");
222                                 serial_line.flush_output();
223                         } catch (InterruptedException ie) {
224                         } catch (TimeoutException te) {
225                         } finally {
226                                 try {
227                                         stop_serial();
228                                 } catch (InterruptedException ie) {
229                                 }
230                                 serial_line.close();
231                         }
232                 }
233
234                 public void run () {
235                         switch (serial_mode) {
236                         case serial_mode_save:
237                                 save_data();
238                                 /* fall through ... */
239                         case serial_mode_read:
240                                 get_data();
241                                 break;
242                         case serial_mode_reboot:
243                                 reboot();
244                                 break;
245                         }
246                 }
247
248                 public SerialData(AltosConfig in_config, int in_serial_mode) {
249                         config = in_config;
250                         serial_mode = in_serial_mode;
251                 }
252         }
253
254         void run_serial_thread(int serial_mode) {
255                 SerialData      sd = new SerialData(this, serial_mode);
256                 Thread          st = new Thread(sd);
257                 st.start();
258         }
259
260         void init_ui () throws InterruptedException, TimeoutException {
261                 config_ui = new AltosConfigUI(owner, remote);
262                 config_ui.addActionListener(this);
263                 serial_line.set_frame(owner);
264                 set_ui();
265         }
266
267         void abort() {
268                 if (serial_line != null) {
269                         serial_line.close();
270                         serial_line = null;
271                 }
272                 JOptionPane.showMessageDialog(owner,
273                                               String.format("Connection to \"%s\" failed",
274                                                             device.toShortString()),
275                                               "Connection Failed",
276                                               JOptionPane.ERROR_MESSAGE);
277                 config_ui.setVisible(false);
278         }
279
280         void set_ui() throws InterruptedException, TimeoutException {
281                 if (serial_line != null)
282                         run_serial_thread(serial_mode_read);
283                 else
284                         update_ui();
285         }
286
287         double frequency() {
288                 return AltosConvert.radio_to_frequency(data.radio_frequency,
289                                                        data.radio_setting,
290                                                        data.radio_calibration,
291                                                        data.radio_channel);
292         }
293
294         void set_frequency(double freq) {
295                 int     frequency = data.radio_frequency;
296                 int     setting = data.radio_setting;
297
298                 if (frequency > 0) {
299                         data.radio_frequency = (int) Math.floor (freq * 1000 + 0.5);
300                         data.radio_channel = 0;
301                 } else if (setting > 0) {
302                         data.radio_setting =AltosConvert.radio_frequency_to_setting(freq,
303                                                                                     data.radio_calibration);
304                         data.radio_channel = 0;
305                 } else {
306                         data.radio_channel = AltosConvert.radio_frequency_to_channel(freq);
307                 }
308         }
309
310         void save_data() {
311
312                 /* bounds check stuff */
313                 if (config_ui.flight_log_max() > log_limit()) {
314                         JOptionPane.showMessageDialog(owner,
315                                                       String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
316                                                                     config_ui.flight_log_max(),
317                                                                     log_limit()),
318                                                       "Maximum Flight Log Too Large",
319                                                       JOptionPane.ERROR_MESSAGE);
320                         return;
321                 }
322
323                 data.main_deploy = config_ui.main_deploy();
324                 data.apogee_delay = config_ui.apogee_delay();
325                 data.apogee_lockout = config_ui.apogee_lockout();
326                 data.radio_calibration = config_ui.radio_calibration();
327                 set_frequency(config_ui.radio_frequency());
328                 data.flight_log_max = config_ui.flight_log_max();
329                 if (data.radio_enable >= 0)
330                         data.radio_enable = config_ui.radio_enable();
331                 if (data.ignite_mode >= 0)
332                         data.ignite_mode = config_ui.ignite_mode();
333                 if (data.pad_orientation >= 0)
334                         data.pad_orientation = config_ui.pad_orientation();
335                 data.callsign = config_ui.callsign();
336                 if (data.npyro > 0) {
337                         data.pyros = config_ui.pyros();
338                 }
339                 run_serial_thread(serial_mode_save);
340         }
341
342         public void actionPerformed(ActionEvent e) {
343                 String  cmd = e.getActionCommand();
344                 try {
345                         if (cmd.equals("Save")) {
346                                 save_data();
347                         } else if (cmd.equals("Reset")) {
348                                 set_ui();
349                         } else if (cmd.equals("Reboot")) {
350                                 if (serial_line != null)
351                                         run_serial_thread(serial_mode_reboot);
352                         } else if (cmd.equals("Close")) {
353                                 if (serial_line != null)
354                                         serial_line.close();
355                         }
356                 } catch (InterruptedException ie) {
357                         abort();
358                 } catch (TimeoutException te) {
359                         abort();
360                 }
361         }
362
363         public AltosConfig(JFrame given_owner) {
364                 owner = given_owner;
365
366                 device = AltosDeviceDialog.show(owner, Altos.product_any);
367                 if (device != null) {
368                         try {
369                                 serial_line = new AltosSerial(device);
370                                 try {
371                                         if (device.matchProduct(Altos.product_basestation))
372                                                 remote = true;
373                                         init_ui();
374                                 } catch (InterruptedException ie) {
375                                         abort();
376                                 } catch (TimeoutException te) {
377                                         abort();
378                                 }
379                         } catch (FileNotFoundException ee) {
380                                 JOptionPane.showMessageDialog(owner,
381                                                               ee.getMessage(),
382                                                               "Cannot open target device",
383                                                               JOptionPane.ERROR_MESSAGE);
384                         } catch (AltosSerialInUseException si) {
385                                 JOptionPane.showMessageDialog(owner,
386                                                               String.format("Device \"%s\" already in use",
387                                                                             device.toShortString()),
388                                                               "Device in use",
389                                                               JOptionPane.ERROR_MESSAGE);
390                         }
391                 }
392         }
393 }