fix bashism that prevents building with /bin/sh->/bin/dash
[fw/altos] / altosui / AltosPad.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 public class AltosPad extends JComponent implements AltosFlightDisplay {
32         GridBagLayout   layout;
33
34         public class LaunchStatus {
35                 JLabel          label;
36                 JTextField      value;
37                 AltosLights     lights;
38
39                 void show(AltosState state, int crc_errors) {}
40                 void reset() {
41                         value.setText("");
42                         lights.set(false);
43                 }
44
45                 public void show() {
46                         label.setVisible(true);
47                         value.setVisible(true);
48                         lights.setVisible(true);
49                 }
50
51                 public void hide() {
52                         label.setVisible(false);
53                         value.setVisible(false);
54                         lights.setVisible(false);
55                 }
56
57                 public void set_font() {
58                         label.setFont(Altos.label_font);
59                         value.setFont(Altos.value_font);
60                 }
61
62                 public LaunchStatus (GridBagLayout layout, int y, String text) {
63                         GridBagConstraints      c = new GridBagConstraints();
64                         c.weighty = 1;
65
66                         lights = new AltosLights();
67                         c.gridx = 0; c.gridy = y;
68                         c.anchor = GridBagConstraints.CENTER;
69                         c.fill = GridBagConstraints.VERTICAL;
70                         c.weightx = 0;
71                         layout.setConstraints(lights, c);
72                         add(lights);
73
74                         label = new JLabel(text);
75                         label.setFont(Altos.label_font);
76                         label.setHorizontalAlignment(SwingConstants.LEFT);
77                         c.gridx = 1; c.gridy = y;
78                         c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
79                         c.anchor = GridBagConstraints.WEST;
80                         c.fill = GridBagConstraints.VERTICAL;
81                         c.weightx = 0;
82                         layout.setConstraints(label, c);
83                         add(label);
84
85                         value = new JTextField(Altos.text_width);
86                         value.setFont(Altos.value_font);
87                         value.setHorizontalAlignment(SwingConstants.RIGHT);
88                         c.gridx = 2; c.gridy = y;
89                         c.anchor = GridBagConstraints.WEST;
90                         c.fill = GridBagConstraints.BOTH;
91                         c.weightx = 1;
92                         layout.setConstraints(value, c);
93                         add(value);
94
95                 }
96         }
97
98         public class LaunchValue {
99                 JLabel          label;
100                 JTextField      value;
101                 void show(AltosState state, int crc_errors) {}
102
103                 void show() {
104                         label.setVisible(true);
105                         value.setVisible(true);
106                 }
107
108                 void hide() {
109                         label.setVisible(false);
110                         value.setVisible(false);
111                 }
112
113                 public void set_font() {
114                         label.setFont(Altos.label_font);
115                         value.setFont(Altos.value_font);
116                 }
117
118                 void reset() {
119                         value.setText("");
120                 }
121                 public LaunchValue (GridBagLayout layout, int y, String text) {
122                         GridBagConstraints      c = new GridBagConstraints();
123                         c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
124                         c.weighty = 1;
125
126                         label = new JLabel(text);
127                         label.setFont(Altos.label_font);
128                         label.setHorizontalAlignment(SwingConstants.LEFT);
129                         c.gridx = 1; c.gridy = y;
130                         c.anchor = GridBagConstraints.WEST;
131                         c.fill = GridBagConstraints.VERTICAL;
132                         c.weightx = 0;
133                         layout.setConstraints(label, c);
134                         add(label);
135
136                         value = new JTextField(Altos.text_width);
137                         value.setFont(Altos.value_font);
138                         value.setHorizontalAlignment(SwingConstants.RIGHT);
139                         c.gridx = 2; c.gridy = y;
140                         c.anchor = GridBagConstraints.EAST;
141                         c.fill = GridBagConstraints.BOTH;
142                         c.weightx = 1;
143                         layout.setConstraints(value, c);
144                         add(value);
145                 }
146         }
147
148         class Battery extends LaunchStatus {
149                 void show (AltosState state, int crc_errors) {
150                         value.setText(String.format("%4.2f V", state.battery));
151                         lights.set(state.battery > 3.7);
152                 }
153                 public Battery (GridBagLayout layout, int y) {
154                         super(layout, y, "Battery Voltage");
155                 }
156         }
157
158         Battery battery;
159
160         class Apogee extends LaunchStatus {
161                 void show (AltosState state, int crc_errors) {
162                         show();
163                         value.setText(String.format("%4.2f V", state.drogue_sense));
164                         lights.set(state.drogue_sense > 3.2);
165                 }
166                 public Apogee (GridBagLayout layout, int y) {
167                         super(layout, y, "Apogee Igniter Voltage");
168                 }
169         }
170
171         Apogee apogee;
172
173         class Main extends LaunchStatus {
174                 void show (AltosState state, int crc_errors) {
175                         show();
176                         value.setText(String.format("%4.2f V", state.main_sense));
177                         lights.set(state.main_sense > 3.2);
178                 }
179                 public Main (GridBagLayout layout, int y) {
180                         super(layout, y, "Main Igniter Voltage");
181                 }
182         }
183
184         Main main;
185
186         class LoggingReady extends LaunchStatus {
187                 void show (AltosState state, int crc_errors) {
188                         show();
189                         if (state.data.flight != 0) {
190                                 if (state.data.state <= Altos.ao_flight_pad)
191                                         value.setText("Ready to record");
192                                 else if (state.data.state < Altos.ao_flight_landed)
193                                         value.setText("Recording data");
194                                 else
195                                         value.setText("Recorded data");
196                         }
197                         else
198                                 value.setText("Storage full");
199                         lights.set(state.data.flight != 0);
200                 }
201                 public LoggingReady (GridBagLayout layout, int y) {
202                         super(layout, y, "On-board Data Logging");
203                 }
204         }
205
206         LoggingReady logging_ready;
207
208         class GPSLocked extends LaunchStatus {
209                 void show (AltosState state, int crc_errors) {
210                         show();
211                         value.setText(String.format("%4d sats", state.gps.nsat));
212                         lights.set(state.gps.locked && state.gps.nsat >= 4);
213                 }
214                 public GPSLocked (GridBagLayout layout, int y) {
215                         super (layout, y, "GPS Locked");
216                 }
217         }
218
219         GPSLocked gps_locked;
220
221         class GPSReady extends LaunchStatus {
222                 void show (AltosState state, int crc_errors) {
223                         show();
224                         if (state.gps_ready)
225                                 value.setText("Ready");
226                         else
227                                 value.setText(String.format("Waiting %d", state.gps_waiting));
228                         lights.set(state.gps_ready);
229                 }
230                 public GPSReady (GridBagLayout layout, int y) {
231                         super (layout, y, "GPS Ready");
232                 }
233         }
234
235         GPSReady gps_ready;
236
237         String pos(double p, String pos, String neg) {
238                 String  h = pos;
239                 if (p < 0) {
240                         h = neg;
241                         p = -p;
242                 }
243                 int deg = (int) Math.floor(p);
244                 double min = (p - Math.floor(p)) * 60.0;
245                 return String.format("%s %4d° %9.6f", h, deg, min);
246         }
247
248         class PadLat extends LaunchValue {
249                 void show (AltosState state, int crc_errors) {
250                         show();
251                         value.setText(pos(state.pad_lat,"N", "S"));
252                 }
253                 public PadLat (GridBagLayout layout, int y) {
254                         super (layout, y, "Pad Latitude");
255                 }
256         }
257
258         PadLat pad_lat;
259
260         class PadLon extends LaunchValue {
261                 void show (AltosState state, int crc_errors) {
262                         show();
263                         value.setText(pos(state.pad_lon,"E", "W"));
264                 }
265                 public PadLon (GridBagLayout layout, int y) {
266                         super (layout, y, "Pad Longitude");
267                 }
268         }
269
270         PadLon pad_lon;
271
272         class PadAlt extends LaunchValue {
273                 void show (AltosState state, int crc_errors) {
274                         value.setText(String.format("%4.0f m", state.pad_alt));
275                 }
276                 public PadAlt (GridBagLayout layout, int y) {
277                         super (layout, y, "Pad Altitude");
278                 }
279         }
280
281         PadAlt pad_alt;
282
283         public void reset() {
284                 battery.reset();
285                 apogee.reset();
286                 main.reset();
287                 logging_ready.reset();
288                 gps_locked.reset();
289                 gps_ready.reset();
290                 pad_lat.reset();
291                 pad_lon.reset();
292                 pad_alt.reset();
293         }
294
295         public void set_font() {
296                 battery.set_font();
297                 apogee.set_font();
298                 main.set_font();
299                 logging_ready.set_font();
300                 gps_locked.set_font();
301                 gps_ready.set_font();
302                 pad_lat.set_font();
303                 pad_lon.set_font();
304                 pad_alt.set_font();
305         }
306         
307         public void show(AltosState state, int crc_errors) {
308                 battery.show(state, crc_errors);
309                 if (state.drogue_sense == AltosRecord.MISSING)
310                         apogee.hide();
311                 else
312                         apogee.show(state, crc_errors);
313                 if (state.main_sense == AltosRecord.MISSING)
314                         main.hide();
315                 else
316                         main.show(state, crc_errors);
317                 logging_ready.show(state, crc_errors);
318                 pad_alt.show(state, crc_errors);
319                 if (state.gps != null && state.gps.connected) {
320                         gps_locked.show(state, crc_errors);
321                         gps_ready.show(state, crc_errors);
322                         pad_lat.show(state, crc_errors);
323                         pad_lon.show(state, crc_errors);
324                 } else {
325                         gps_locked.hide();
326                         gps_ready.hide();
327                         pad_lat.hide();
328                         pad_lon.hide();
329                 }
330         }
331
332         public AltosPad() {
333                 layout = new GridBagLayout();
334
335                 setLayout(layout);
336
337                 /* Elements in pad display:
338                  *
339                  * Battery voltage
340                  * Igniter continuity
341                  * GPS lock status
342                  * GPS ready status
343                  * GPS location
344                  * Pad altitude
345                  * RSSI
346                  */
347                 battery = new Battery(layout, 0);
348                 apogee = new Apogee(layout, 1);
349                 main = new Main(layout, 2);
350                 logging_ready = new LoggingReady(layout, 3);
351                 gps_locked = new GPSLocked(layout, 4);
352                 gps_ready = new GPSReady(layout, 5);
353                 pad_lat = new PadLat(layout, 6);
354                 pad_lon = new PadLon(layout, 7);
355                 pad_alt = new PadAlt(layout, 8);
356         }
357 }