altos/driver: Improve quadrature debouncing for mechanical encoders
[fw/altos] / altosui / AltosConfigFC.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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 package altosui;
20
21 import java.awt.event.*;
22 import javax.swing.*;
23 import java.io.*;
24 import java.util.concurrent.*;
25 import java.text.*;
26 import org.altusmetrum.altoslib_12.*;
27 import org.altusmetrum.altosuilib_12.*;
28
29 public class AltosConfigFC implements ActionListener {
30
31         class int_ref {
32                 int     value;
33
34                 public int get() {
35                         return value;
36                 }
37                 public void set(int i) {
38                         value = i;
39                 }
40                 public int_ref(int i) {
41                         value = i;
42                 }
43         }
44
45         class string_ref {
46                 String  value;
47
48                 public String get() {
49                         return value;
50                 }
51                 public void set(String i) {
52                         value = i;
53                 }
54                 public string_ref(String i) {
55                         value = i;
56                 }
57         }
58
59         JFrame          owner;
60         AltosDevice     device;
61         AltosSerial     serial_line;
62         boolean         remote;
63
64         AltosConfigData data;
65         AltosConfigFCUI config_ui;
66         boolean         serial_started;
67         boolean         made_visible;
68
69         void start_serial() throws InterruptedException, TimeoutException {
70                 serial_started = true;
71                 if (remote)
72                         serial_line.start_remote();
73         }
74
75         void stop_serial() throws InterruptedException {
76                 if (!serial_started)
77                         return;
78                 serial_started = false;
79                 if (remote)
80                         serial_line.stop_remote();
81         }
82
83         void update_ui() {
84                 data.set_values(config_ui);
85                 config_ui.set_clean();
86                 if (!made_visible) {
87                         made_visible = true;
88                         config_ui.make_visible();
89                 }
90         }
91
92         int     pyro;
93
94         final static int        serial_mode_read = 0;
95         final static int        serial_mode_save = 1;
96         final static int        serial_mode_reboot = 2;
97
98         class SerialData implements Runnable {
99                 AltosConfigFC   config;
100                 int             serial_mode;
101
102                 void callback(String in_cmd) {
103                         final String cmd = in_cmd;
104                         Runnable r = new Runnable() {
105                                         public void run() {
106                                                 if (cmd.equals("abort")) {
107                                                         abort();
108                                                 } else if (cmd.equals("all finished")) {
109                                                         if (serial_line != null)
110                                                                 update_ui();
111                                                 }
112                                         }
113                                 };
114                         SwingUtilities.invokeLater(r);
115                 }
116
117                 void get_data() {
118                         data = null;
119                         try {
120                                 start_serial();
121                                 data = new AltosConfigData(config.serial_line);
122                         } catch (InterruptedException ie) {
123                         } catch (TimeoutException te) {
124                                 try {
125                                         stop_serial();
126                                         callback("abort");
127                                 } catch (InterruptedException ie) {
128                                 }
129                         } finally {
130                                 try {
131                                         stop_serial();
132                                 } catch (InterruptedException ie) {
133                                 }
134                         }
135                         callback("all finished");
136                 }
137
138                 void save_data() {
139                         try {
140                                 start_serial();
141                                 data.save(serial_line, remote);
142                                 if (remote)
143                                         AltosUIPreferences.set_frequency(device.getSerial(),
144                                                                          data.frequency());
145                         } catch (InterruptedException ie) {
146                         } catch (TimeoutException te) {
147                         } finally {
148                                 try {
149                                         stop_serial();
150                                 } catch (InterruptedException ie) {
151                                 }
152                         }
153                 }
154
155                 void reboot() {
156                         try {
157                                 start_serial();
158                                 serial_line.printf("r eboot\n");
159                                 serial_line.flush_output();
160                         } catch (InterruptedException ie) {
161                         } catch (TimeoutException te) {
162                         } finally {
163                                 try {
164                                         stop_serial();
165                                         serial_line.close();
166                                 } catch (InterruptedException ie) {
167                                 }
168                         }
169                 }
170
171                 public void run () {
172                         switch (serial_mode) {
173                         case serial_mode_save:
174                                 save_data();
175                                 /* fall through ... */
176                         case serial_mode_read:
177                                 get_data();
178                                 break;
179                         case serial_mode_reboot:
180                                 reboot();
181                                 break;
182                         }
183                 }
184
185                 public SerialData(AltosConfigFC in_config, int in_serial_mode) {
186                         config = in_config;
187                         serial_mode = in_serial_mode;
188                 }
189         }
190
191         void run_serial_thread(int serial_mode) {
192                 SerialData      sd = new SerialData(this, serial_mode);
193                 Thread          st = new Thread(sd);
194                 st.start();
195         }
196
197         void init_ui () throws InterruptedException, TimeoutException {
198                 config_ui = new AltosConfigFCUI(owner, remote);
199                 config_ui.addActionListener(this);
200                 serial_line.set_frame(owner);
201                 set_ui();
202         }
203
204         void abort() {
205                 if (serial_line != null) {
206                         serial_line.close();
207                         serial_line = null;
208                 }
209                 JOptionPane.showMessageDialog(owner,
210                                               String.format("Connection to \"%s\" failed",
211                                                             device.toShortString()),
212                                               "Connection Failed",
213                                               JOptionPane.ERROR_MESSAGE);
214                 config_ui.setVisible(false);
215         }
216
217         void set_ui() throws InterruptedException, TimeoutException {
218                 if (serial_line != null)
219                         run_serial_thread(serial_mode_read);
220                 else
221                         update_ui();
222         }
223
224         double frequency() {
225                 return AltosConvert.radio_to_frequency(data.radio_frequency,
226                                                        data.radio_setting,
227                                                        data.radio_calibration,
228                                                        data.radio_channel);
229         }
230
231         void save_data() {
232
233                 try {
234                         /* bounds check stuff */
235                         if (config_ui.flight_log_max() > data.log_space() / 1024) {
236                                 JOptionPane.showMessageDialog(owner,
237                                                               String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
238                                                                             config_ui.flight_log_max(),
239                                                                             data.log_space() / 1024),
240                                                               "Maximum Flight Log Too Large",
241                                                               JOptionPane.ERROR_MESSAGE);
242                                 return;
243                         }
244
245                         /* Pull data out of the UI and stuff back into our local data record */
246
247                         data.get_values(config_ui);
248                         run_serial_thread(serial_mode_save);
249                 } catch (AltosConfigDataException ae) {
250                         JOptionPane.showMessageDialog(owner,
251                                                       ae.getMessage(),
252                                                       "Configuration Data Error",
253                                                       JOptionPane.ERROR_MESSAGE);
254                 }
255         }
256
257         public void actionPerformed(ActionEvent e) {
258                 String  cmd = e.getActionCommand();
259                 try {
260                         if (cmd.equals("Save")) {
261                                 save_data();
262                         } else if (cmd.equals("Reset")) {
263                                 set_ui();
264                         } else if (cmd.equals("Reboot")) {
265                                 if (serial_line != null)
266                                         run_serial_thread(serial_mode_reboot);
267                         } else if (cmd.equals("Close")) {
268                                 if (serial_line != null)
269                                         serial_line.close();
270                         }
271                         else if (cmd.equals("Accel")) {
272                                 if (data.pad_orientation != AltosLib.MISSING) {
273                                         AltosUIAccelCal accel_ui = new AltosUIAccelCal(owner, serial_line, config_ui);
274                                         if (accel_ui != null)
275                                                 accel_ui.doit();
276                                 }
277                         }
278                 } catch (InterruptedException ie) {
279                         abort();
280                 } catch (TimeoutException te) {
281                         abort();
282                 }
283         }
284
285         public AltosConfigFC(JFrame given_owner) {
286                 owner = given_owner;
287
288                 device = AltosDeviceUIDialog.show(owner, Altos.product_any);
289                 if (device != null) {
290                         try {
291                                 serial_line = new AltosSerial(device);
292                                 try {
293                                         if (device.matchProduct(Altos.product_basestation))
294                                                 remote = true;
295                                         init_ui();
296                                 } catch (InterruptedException ie) {
297                                         abort();
298                                 } catch (TimeoutException te) {
299                                         abort();
300                                 }
301                         } catch (FileNotFoundException ee) {
302                                 JOptionPane.showMessageDialog(owner,
303                                                               ee.getMessage(),
304                                                               "Cannot open target device",
305                                                               JOptionPane.ERROR_MESSAGE);
306                         } catch (AltosSerialInUseException si) {
307                                 JOptionPane.showMessageDialog(owner,
308                                                               String.format("Device \"%s\" already in use",
309                                                                             device.toShortString()),
310                                                               "Device in use",
311                                                               JOptionPane.ERROR_MESSAGE);
312                         }
313                 }
314         }
315 }