altosui: Split eeprom download code apart
[fw/altos] / altosui / AltosEepromDownload.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 java.io.*;
26 import java.util.*;
27 import java.text.*;
28 import java.util.prefs.*;
29 import java.util.concurrent.*;
30
31 import libaltosJNI.*;
32
33 public class AltosEepromDownload implements Runnable {
34
35         JFrame                  frame;
36         AltosDevice             device;
37         AltosSerial             serial_line;
38         boolean                 remote;
39         Thread                  eeprom_thread;
40         AltosEepromMonitor      monitor;
41         int                     serial = 0;
42         int                     flight = 0;
43         int                     year = 0, month = 0, day = 0;
44         boolean                 want_file = false;
45         FileWriter              eeprom_file = null;
46         LinkedList<String>      eeprom_pending = new LinkedList<String>();
47         AltosConfigData         config_data;
48
49         private void FlushPending() throws IOException {
50                 for (String s : config_data) {
51                         eeprom_file.write(s);
52                         eeprom_file.write('\n');
53                 }
54
55                 for (String s : eeprom_pending)
56                         eeprom_file.write(s);
57         }
58
59         private void CheckFile(boolean force) throws IOException {
60                 if (eeprom_file != null)
61                         return;
62                 if (force || (flight != 0 && want_file)) {
63                         AltosFile               eeprom_name;
64                         if (year != 0 && month != 0 && day != 0)
65                                 eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom");
66                         else
67                                 eeprom_name = new AltosFile(serial, flight, "eeprom");
68
69                         eeprom_file = new FileWriter(eeprom_name);
70                         if (eeprom_file != null) {
71                                 monitor.set_file(eeprom_name.getName());
72                                 FlushPending();
73                                 eeprom_pending = null;
74                         }
75                 }
76         }
77
78         void CaptureLog(int start_block, int end_block) throws IOException, InterruptedException, TimeoutException {
79                 int                     block, state_block = 0;
80                 int                     state = 0;
81                 boolean                 done = false;
82                 int                     record;
83
84                 config_data = new AltosConfigData(serial_line);
85                 serial = config_data.serial;
86                 if (serial == 0)
87                         throw new IOException("no serial number found");
88
89                 monitor.set_serial(serial);
90                 /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
91
92                 state = 0; state_block = start_block;
93                 for (block = start_block; !done && block < end_block; block++) {
94                         monitor.set_value(Altos.state_to_string[state], state, block - state_block);
95
96                         AltosEepromBlock        eeblock = new AltosEepromBlock(serial_line, block);
97                         if (eeblock.has_flight) {
98                                 flight = eeblock.flight;
99                                 monitor.set_flight(flight);
100                         }
101                         if (eeblock.has_date) {
102                                 year = eeblock.year;
103                                 month = eeblock.month;
104                                 day = eeblock.day;
105                                 want_file = true;
106                         }
107
108                         if (eeblock.size() == 0 ||
109                             eeblock.has_state && eeblock.state == Altos.ao_flight_landed)
110                                         done = true;
111
112                         /* Monitor state transitions to update display */
113                         if (eeblock.has_state) {
114                                 if (eeblock.state > Altos.ao_flight_pad)
115                                         want_file = true;
116                                 if (eeblock.state > state)
117                                         state = eeblock.state;
118                         }
119
120                         CheckFile(true);
121
122                         for (record = 0; record < eeblock.size(); record++) {
123                                 AltosEepromRecord r = eeblock.get(record);
124
125                                 String log_line = String.format("%c %4x %4x %4x\n",
126                                                                 r.cmd, r.tick, r.a, r.b);
127                                 if (eeprom_file != null)
128                                         eeprom_file.write(log_line);
129                                 else
130                                         eeprom_pending.add(log_line);
131                         }
132                 }
133                 CheckFile(true);
134                 if (eeprom_file != null) {
135                         eeprom_file.flush();
136                         eeprom_file.close();
137                 }
138         }
139
140         private void show_error_internal(String message, String title) {
141                 JOptionPane.showMessageDialog(frame,
142                                               message,
143                                               title,
144                                               JOptionPane.ERROR_MESSAGE);
145         }
146
147         private void show_error(String in_message, String in_title) {
148                 final String message = in_message;
149                 final String title = in_title;
150                 Runnable r = new Runnable() {
151                                 public void run() {
152                                         try {
153                                                 show_error_internal(message, title);
154                                         } catch (Exception ex) {
155                                         }
156                                 }
157                         };
158                 SwingUtilities.invokeLater(r);
159         }
160
161         int     start_block, end_block;
162
163         public void run () {
164                 if (remote) {
165                         serial_line.set_radio();
166                         serial_line.printf("p\nE 0\n");
167                         serial_line.flush_input();
168                 }
169
170                 try {
171                         CaptureLog(start_block, end_block);
172                 } catch (IOException ee) {
173                         show_error (device.toShortString(),
174                                     ee.getLocalizedMessage());
175                 } catch (InterruptedException ie) {
176                 } catch (TimeoutException te) {
177                         show_error (String.format("Connection to \"%s\" failed",
178                                                   device.toShortString()),
179                                     "Connection Failed");
180                 }
181                 if (remote)
182                         serial_line.printf("~");
183                 monitor.done();
184                 serial_line.flush_output();
185                 serial_line.close();
186         }
187
188         public AltosEepromDownload(JFrame given_frame) {
189                 frame = given_frame;
190                 device = AltosDeviceDialog.show(frame, AltosDevice.product_any);
191
192                 remote = false;
193
194                 if (device != null) {
195                         try {
196                                 serial_line = new AltosSerial(device);
197                                 if (!device.matchProduct(AltosDevice.product_telemetrum))
198                                         remote = true;
199
200                                 monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed);
201                                 monitor.addActionListener(new ActionListener() {
202                                                 public void actionPerformed(ActionEvent e) {
203                                                         if (eeprom_thread != null)
204                                                                 eeprom_thread.interrupt();
205                                                 }
206                                         });
207
208                                 eeprom_thread = new Thread(this);
209                                 start_block = 0;
210                                 end_block = 0xfff;
211                                 eeprom_thread.start();
212                         } catch (FileNotFoundException ee) {
213                                 JOptionPane.showMessageDialog(frame,
214                                                               String.format("Cannot open device \"%s\"",
215                                                                             device.toShortString()),
216                                                               "Cannot open target device",
217                                                               JOptionPane.ERROR_MESSAGE);
218                         } catch (AltosSerialInUseException si) {
219                                 JOptionPane.showMessageDialog(frame,
220                                                               String.format("Device \"%s\" already in use",
221                                                                             device.toShortString()),
222                                                               "Device in use",
223                                                               JOptionPane.ERROR_MESSAGE);
224                         } catch (IOException ee) {
225                                 JOptionPane.showMessageDialog(frame,
226                                                               device.toShortString(),
227                                                               ee.getLocalizedMessage(),
228                                                               JOptionPane.ERROR_MESSAGE);
229                         }
230                 }
231         }
232 }