54e0bbc4b9b503b80269e03b43cb02b2d471d03a
[fw/altos] / ao-tools / altosui / AltosEeprom.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.LinkedBlockingQueue;
30
31 import altosui.AltosSerial;
32 import altosui.AltosSerialMonitor;
33 import altosui.AltosTelemetry;
34 import altosui.AltosState;
35 import altosui.AltosDeviceDialog;
36 import altosui.AltosPreferences;
37 import altosui.AltosLog;
38 import altosui.AltosVoice;
39
40 import libaltosJNI.*;
41
42 public class AltosEeprom {
43
44         static final int AO_LOG_FLIGHT = 'F';
45         static final int AO_LOG_SENSOR = 'A';
46         static final int AO_LOG_TEMP_VOLT = 'T';
47         static final int AO_LOG_DEPLOY = 'D';
48         static final int AO_LOG_STATE = 'S';
49         static final int AO_LOG_GPS_TIME = 'G';
50         static final int AO_LOG_GPS_LAT = 'N';
51         static final int AO_LOG_GPS_LON = 'W';
52         static final int AO_LOG_GPS_ALT = 'H';
53         static final int AO_LOG_GPS_SAT = 'V';
54         static final int AO_LOG_GPS_DATE = 'Y';
55
56         static final int ao_flight_startup = 0;
57         static final int ao_flight_idle = 1;
58         static final int ao_flight_pad = 2;
59         static final int ao_flight_boost = 3;
60         static final int ao_flight_fast = 4;
61         static final int ao_flight_coast = 5;
62         static final int ao_flight_drogue = 6;
63         static final int ao_flight_main = 7;
64         static final int ao_flight_landed = 8;
65         static final int ao_flight_invalid = 9;
66
67         static String[] state_names = {
68                 "startup",
69                 "idle",
70                 "pad",
71                 "boost",
72                 "fast",
73                 "coast",
74                 "drogue",
75                 "main",
76                 "landed",
77                 "invalid",
78         };
79
80         static int[] ParseHex(String line) {
81                 String[] tokens = line.split("\\s+");
82                 int[] array = new int[tokens.length];
83
84                 for (int i = 0; i < tokens.length; i++)
85                         try {
86                                 array[i] = Integer.parseInt(tokens[i], 16);
87                         } catch (NumberFormatException ne) {
88                                 return null;
89                         }
90                 return array;
91         }
92
93         static int checksum(int[] line) {
94                 int     csum = 0x5a;
95                 for (int i = 1; i < line.length; i++)
96                         csum += line[i];
97                 return csum & 0xff;
98         }
99
100         static void FlushPending(FileWriter file, LinkedList<String> pending) throws IOException {
101                 while (!pending.isEmpty()) {
102                         file.write(pending.remove());
103                 }
104         }
105
106         static void CaptureLog(AltosSerial serial_line) throws IOException, InterruptedException {
107                 int                     serial = 0;
108                 int                     block;
109                 int                     addr;
110                 int                     flight = 0;
111                 int                     year = 0, month = 0, day = 0;
112                 int                     state = 0;
113                 boolean                 done = false;
114                 boolean                 want_file = false;
115                 boolean                 any_valid;
116                 FileWriter              eeprom_file = null;
117                 AltosFile               eeprom_name;
118                 LinkedList<String>      eeprom_pending = new LinkedList<String>();
119
120                 serial_line.printf("v\n");
121
122                 /* Pull the serial number out of the version information */
123
124                 for (;;) {
125                         String  line = serial_line.get_reply();
126
127                         if (line.startsWith("serial-number")) {
128                                 try {
129                                         serial = Integer.parseInt(line.substring(13).trim());
130                                         eeprom_pending.add(String.format("%s\n", line));
131                                 } catch (NumberFormatException ne) {
132                                         serial = 0;
133                                 }
134                         }
135
136                         /* signals the end of the version info */
137                         if (line.startsWith("software-version"))
138                                 break;
139                 }
140                 if (serial == 0)
141                         throw new IOException("no serial number found");
142
143                 /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
144
145                 for (block = 0; !done && block < 511; block++) {
146                         serial_line.printf("e %x\n", block);
147                         any_valid = false;
148                         for (addr = 0; addr < 0x100;) {
149                                 String  line = serial_line.get_reply();
150                                 int[] values = ParseHex(line);
151
152                                 if (values == null) {
153                                         System.out.printf("invalid line: %s\n", line);
154                                 } else if (values[0] != addr) {
155                                         System.out.printf("data address out of sync at 0x%x\n",
156                                                           block * 256 + values[0]);
157                                 } else if (checksum(values) != 0) {
158                                         System.out.printf("invalid checksum at 0x%x\n",
159                                                           block * 256 + values[0]);
160                                 } else {
161                                         any_valid = true;
162                                         int     cmd = values[1];
163                                         int     tick = values[3] + (values[4] << 8);
164                                         int     a = values[5] + (values[6] << 8);
165                                         int     b = values[7] + (values[8] << 8);
166
167                                         if (cmd == AO_LOG_FLIGHT)
168                                                 flight = b;
169
170                                         /* Monitor state transitions to update display */
171                                         if (cmd == AO_LOG_STATE && a <= ao_flight_landed) {
172                                                 System.out.printf ("%s\n", state_names[a]);
173                                                 if (a > ao_flight_pad)
174                                                         want_file = true;
175                                                 state = a;
176                                         }
177
178                                         if (cmd == AO_LOG_GPS_DATE) {
179                                                 year = 2000 + (a & 0xff);
180                                                 month = (a >> 8) & 0xff;
181                                                 day = (b & 0xff);
182                                                 want_file = true;
183                                         }
184
185                                         if (eeprom_file == null) {
186                                                 if (serial != 0 && flight != 0 && want_file) {
187                                                         if (year != 0 && month != 0 && day != 0)
188                                                                 eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom-new");
189                                                         else
190                                                                 eeprom_name = new AltosFile(serial, flight, "eeprom-new");
191
192                                                         eeprom_file = new FileWriter(eeprom_name);
193                                                         if (eeprom_file != null) {
194                                                                 FlushPending(eeprom_file, eeprom_pending);
195                                                                 eeprom_pending = null;
196                                                         }
197                                                 }
198                                         }
199
200                                         String log_line = String.format("%c %4x %4x %4x\n",
201                                                                         cmd, tick, a, b);
202                                         if (eeprom_file != null)
203                                                 eeprom_file.write(log_line);
204                                         else
205                                                 eeprom_pending.add(log_line);
206
207                                         if (cmd == AO_LOG_STATE && a == ao_flight_landed) {
208                                                 done = true;
209                                         }
210                                 }
211                                 addr += 8;
212                         }
213                         if (!any_valid)
214                                 done = true;
215                 }
216                 if (eeprom_file == null) {
217                         eeprom_name = new AltosFile(serial,flight,"eeprom-new");
218                         eeprom_file = new FileWriter(eeprom_name);
219                         if (eeprom_file != null) {
220                                 FlushPending(eeprom_file, eeprom_pending);
221                         }
222                 }
223                 if (eeprom_file != null) {
224                         eeprom_file.flush();
225                         eeprom_file.close();
226                 }
227         }
228
229         public static void SaveFlightData (JFrame frame) {
230                 altos_device    device = AltosDeviceDialog.show(frame, null);
231                 boolean         remote = false;
232                 AltosSerial     serial_line = new AltosSerial();
233
234                 if (device == null)
235                         return;
236                 try {
237                         serial_line.open(device);
238                         if (!device.getProduct().startsWith("TeleMetrum"))
239                                 remote = true;
240
241                         if (remote) {
242                                 serial_line.printf("m 0\n");
243                                 serial_line.set_channel(AltosPreferences.channel());
244                                 serial_line.printf("p\n");
245                         }
246                         CaptureLog(serial_line);
247                         if (remote)
248                                 serial_line.printf("~");
249                         serial_line.close();
250                 } catch (FileNotFoundException ee) {
251                         JOptionPane.showMessageDialog(frame,
252                                                       String.format("Cannot open device \"%s\"",
253                                                                     device.getPath()),
254                                                       "Cannot open target device",
255                                                       JOptionPane.ERROR_MESSAGE);
256                 } catch (IOException ee) {
257                         JOptionPane.showMessageDialog(frame,
258                                                       device.getPath(),
259                                                       ee.getLocalizedMessage(),
260                                                       JOptionPane.ERROR_MESSAGE);
261                 } catch (InterruptedException ie) {
262                 }
263         }
264 }