ce1f2ab74c24f0b3539af1c8e8f8ec3961499399
[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 javax.swing.*;
22 import org.altusmetrum.altoslib_4.*;
23 import org.altusmetrum.altosuilib_2.*;
24
25 public class AltosPad extends JComponent implements AltosFlightDisplay {
26         GridBagLayout   layout;
27
28         public class LaunchStatus implements AltosFontListener, AltosUnitsListener {
29                 JLabel          label;
30                 JTextField      value;
31                 AltosLights     lights;
32
33                 void show(AltosState state, AltosListenerState listener_state) {}
34
35                 void reset() {
36                         value.setText("");
37                         lights.set(false);
38                 }
39
40                 public void show() {
41                         label.setVisible(true);
42                         value.setVisible(true);
43                         lights.setVisible(true);
44                 }
45
46                 void show(String s) {
47                         show();
48                         value.setText(s);
49                 }
50
51                 void show(String format, double value) {
52                         show(String.format(format, value));
53                 }
54
55                 void show(String format, int value) {
56                         show(String.format(format, value));
57                 }
58
59                 public void hide() {
60                         label.setVisible(false);
61                         value.setVisible(false);
62                         lights.setVisible(false);
63                 }
64
65                 public void font_size_changed(int font_size) {
66                         label.setFont(Altos.label_font);
67                         value.setFont(Altos.value_font);
68                 }
69
70                 public void units_changed(boolean imperial_units) {
71                 }
72
73                 public void set_label(String text) {
74                         label.setText(text);
75                 }
76
77                 public LaunchStatus (GridBagLayout layout, int y, String text) {
78                         GridBagConstraints      c = new GridBagConstraints();
79                         c.weighty = 1;
80
81                         lights = new AltosLights();
82                         c.gridx = 0; c.gridy = y;
83                         c.anchor = GridBagConstraints.CENTER;
84                         c.fill = GridBagConstraints.VERTICAL;
85                         c.weightx = 0;
86                         layout.setConstraints(lights, c);
87                         add(lights);
88
89                         label = new JLabel(text);
90                         label.setFont(Altos.label_font);
91                         label.setHorizontalAlignment(SwingConstants.LEFT);
92                         c.gridx = 1; c.gridy = y;
93                         c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
94                         c.anchor = GridBagConstraints.WEST;
95                         c.fill = GridBagConstraints.VERTICAL;
96                         c.weightx = 0;
97                         layout.setConstraints(label, c);
98                         add(label);
99
100                         value = new JTextField(Altos.text_width);
101                         value.setFont(Altos.value_font);
102                         value.setHorizontalAlignment(SwingConstants.RIGHT);
103                         c.gridx = 2; c.gridy = y;
104                         c.anchor = GridBagConstraints.WEST;
105                         c.fill = GridBagConstraints.BOTH;
106                         c.weightx = 1;
107                         layout.setConstraints(value, c);
108                         add(value);
109
110                 }
111         }
112
113         public abstract class LaunchValue implements AltosFontListener, AltosUnitsListener {
114                 JLabel          label;
115                 JTextField      value;
116                 AltosUnits      units;
117                 double          v;
118
119                 abstract void show(AltosState state, AltosListenerState listener_state);
120
121                 void show() {
122                         label.setVisible(true);
123                         value.setVisible(true);
124                 }
125
126                 void hide() {
127                         label.setVisible(false);
128                         value.setVisible(false);
129                 }
130
131                 public void font_size_changed(int font_size) {
132                         label.setFont(Altos.label_font);
133                         value.setFont(Altos.value_font);
134                 }
135
136                 public void units_changed(boolean imperial_units) {
137                         if (units != null)
138                                 show(v);
139                 }
140
141                 void show(String s) {
142                         show();
143                         value.setText(s);
144                 }
145
146                 void show(double v) {
147                         this.v = v;
148                         show(units.show(8, v));
149                 }
150
151                 void show(String format, double v) {
152                         show(String.format(format, v));
153                 }
154
155                 public void set_label(String text) {
156                         label.setText(text);
157                 }
158
159                 void reset() {
160                         value.setText("");
161                 }
162
163                 public LaunchValue (GridBagLayout layout, int y, AltosUnits units, String text) {
164                         this.units = units;
165
166                         GridBagConstraints      c = new GridBagConstraints();
167                         c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
168                         c.weighty = 1;
169
170                         label = new JLabel(text);
171                         label.setFont(Altos.label_font);
172                         label.setHorizontalAlignment(SwingConstants.LEFT);
173                         c.gridx = 1; c.gridy = y;
174                         c.anchor = GridBagConstraints.WEST;
175                         c.fill = GridBagConstraints.VERTICAL;
176                         c.weightx = 0;
177                         layout.setConstraints(label, c);
178                         add(label);
179
180                         value = new JTextField(Altos.text_width);
181                         value.setFont(Altos.value_font);
182                         value.setHorizontalAlignment(SwingConstants.RIGHT);
183                         c.gridx = 2; c.gridy = y;
184                         c.anchor = GridBagConstraints.EAST;
185                         c.fill = GridBagConstraints.BOTH;
186                         c.weightx = 1;
187                         layout.setConstraints(value, c);
188                         add(value);
189                 }
190
191                 public LaunchValue (GridBagLayout layout, int y, String text) {
192                         this(layout, y, null, text);
193                 }
194         }
195
196         class Battery extends LaunchStatus {
197                 void show (AltosState state, AltosListenerState listener_state) {
198                         if (state == null || state.battery_voltage == AltosLib.MISSING)
199                                 hide();
200                         else {
201                                 show("%4.2f V", state.battery_voltage);
202                                 lights.set(state.battery_voltage >= AltosLib.ao_battery_good);
203                         }
204                 }
205                 public Battery (GridBagLayout layout, int y) {
206                         super(layout, y, "Battery Voltage");
207                 }
208         }
209
210         Battery battery;
211
212         class Apogee extends LaunchStatus {
213                 void show (AltosState state, AltosListenerState listener_state) {
214                         if (state == null || state.apogee_voltage == AltosLib.MISSING)
215                                 hide();
216                         else {
217                                 show("%4.2f V", state.apogee_voltage);
218                                 lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
219                         }
220                 }
221                 public Apogee (GridBagLayout layout, int y) {
222                         super(layout, y, "Apogee Igniter Voltage");
223                 }
224         }
225
226         Apogee apogee;
227
228         class Main extends LaunchStatus {
229                 void show (AltosState state, AltosListenerState listener_state) {
230                         if (state == null || state.main_voltage == AltosLib.MISSING)
231                                 hide();
232                         else {
233                                 show("%4.2f V", state.main_voltage);
234                                 lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
235                         }
236                 }
237                 public Main (GridBagLayout layout, int y) {
238                         super(layout, y, "Main Igniter Voltage");
239                 }
240         }
241
242         Main main;
243
244         class LoggingReady extends LaunchStatus {
245                 void show (AltosState state, AltosListenerState listener_state) {
246                         if (state == null || state.flight == AltosLib.MISSING) {
247                                 hide();
248                         } else {
249                                 if (state.flight != 0) {
250                                         if (state.state <= Altos.ao_flight_pad)
251                                                 show("Ready to record");
252                                         else if (state.state < Altos.ao_flight_landed)
253                                                 show("Recording data");
254                                         else
255                                                 show("Recorded data");
256                                 } else
257                                         show("Storage full");
258                                 lights.set(state.flight != 0);
259                         }
260                 }
261                 public LoggingReady (GridBagLayout layout, int y) {
262                         super(layout, y, "On-board Data Logging");
263                 }
264         }
265
266         LoggingReady logging_ready;
267
268         class GPSLocked extends LaunchStatus {
269                 void show (AltosState state, AltosListenerState listener_state) {
270                         if (state == null || state.gps == null)
271                                 hide();
272                         else {
273                                 show("%4d sats", state.gps.nsat);
274                                 lights.set(state.gps.locked && state.gps.nsat >= 4);
275                         }
276                 }
277                 public GPSLocked (GridBagLayout layout, int y) {
278                         super (layout, y, "GPS Locked");
279                 }
280         }
281
282         GPSLocked gps_locked;
283
284         class GPSReady extends LaunchStatus {
285                 void show (AltosState state, AltosListenerState listener_state) {
286                         if (state == null || state.gps == null)
287                                 hide();
288                         else {
289                                 if (state.gps_ready)
290                                         show("Ready");
291                                 else
292                                         show("Waiting %d", state.gps_waiting);
293                                 lights.set(state.gps_ready);
294                         }
295                 }
296                 public GPSReady (GridBagLayout layout, int y) {
297                         super (layout, y, "GPS Ready");
298                 }
299         }
300
301         GPSReady gps_ready;
302
303         class ReceiverBattery extends LaunchStatus {
304                 void show (AltosState state, AltosListenerState listener_state) {
305                         if (listener_state == null || listener_state.battery == AltosLib.MISSING)
306                                 hide();
307                         else {
308                                 show("%4.2f V", listener_state.battery);
309                                 lights.set(listener_state.battery > AltosLib.ao_battery_good);
310                         }
311                 }
312                 public ReceiverBattery (GridBagLayout layout, int y) {
313                         super(layout, y, "Receiver Battery");
314                 }
315         }
316
317         ReceiverBattery receiver_battery;
318
319         String pos(double p, String pos, String neg) {
320                 String  h = pos;
321                 if (p < 0) {
322                         h = neg;
323                         p = -p;
324                 }
325                 int deg = (int) Math.floor(p);
326                 double min = (p - Math.floor(p)) * 60.0;
327                 return String.format("%s %4d° %9.6f", h, deg, min);
328         }
329
330         class PadLat extends LaunchValue {
331                 void show (AltosState state, AltosListenerState listener_state) {
332                         double lat = AltosLib.MISSING;
333                         String label = null;
334
335                         if (state != null) {
336                                 if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.lat != AltosLib.MISSING) {
337                                         lat = state.gps.lat;
338                                         label = "Latitude";
339                                 } else {
340                                         lat = state.pad_lat;
341                                         label = "Pad Latitude";
342                                 }
343                         }
344                         if (lat != AltosLib.MISSING) {
345                                 show(pos(lat,"N", "S"));
346                                 set_label(label);
347                         } else
348                                 hide();
349                 }
350                 public PadLat (GridBagLayout layout, int y) {
351                         super (layout, y, "Pad Latitude");
352                 }
353         }
354
355         PadLat pad_lat;
356
357         class PadLon extends LaunchValue {
358                 void show (AltosState state, AltosListenerState listener_state) {
359                         double lon = AltosLib.MISSING;
360                         String label = null;
361
362                         if (state != null) {
363                                 if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.lon != AltosLib.MISSING) {
364                                         lon = state.gps.lon;
365                                         label = "Longitude";
366                                 } else {
367                                         lon = state.pad_lon;
368                                         label = "Pad Longitude";
369                                 }
370                         }
371                         if (lon != AltosLib.MISSING) {
372                                 show(pos(lon,"E", "W"));
373                                 set_label(label);
374                         } else
375                                 hide();
376                 }
377                 public PadLon (GridBagLayout layout, int y) {
378                         super (layout, y, "Pad Longitude");
379                 }
380         }
381
382         PadLon pad_lon;
383
384         class PadAlt extends LaunchValue {
385                 void show (AltosState state, AltosListenerState listener_state) {
386                         double alt = AltosLib.MISSING;
387                         String label = null;
388
389                         if (state != null) {
390                                 if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.alt != AltosLib.MISSING) {
391                                         alt = state.gps.alt;
392                                         label = "Altitude";
393                                 } else {
394                                         alt = state.pad_alt;
395                                         label = "Pad Altitude";
396                                 }
397                         }
398                         if (alt != AltosLib.MISSING) {
399                                 show(alt);
400                                 set_label(label);
401                         } else
402                                 hide();
403                 }
404                 public PadAlt (GridBagLayout layout, int y) {
405                         super (layout, y, AltosConvert.height, "Pad Altitude");
406                 }
407         }
408
409         PadAlt pad_alt;
410
411         public void reset() {
412                 battery.reset();
413                 apogee.reset();
414                 main.reset();
415                 logging_ready.reset();
416                 gps_locked.reset();
417                 gps_ready.reset();
418                 receiver_battery.reset();
419                 pad_lat.reset();
420                 pad_lon.reset();
421                 pad_alt.reset();
422         }
423
424         public void font_size_changed(int font_size) {
425                 battery.font_size_changed(font_size);
426                 apogee.font_size_changed(font_size);
427                 main.font_size_changed(font_size);
428                 logging_ready.font_size_changed(font_size);
429                 gps_locked.font_size_changed(font_size);
430                 gps_ready.font_size_changed(font_size);
431                 receiver_battery.font_size_changed(font_size);
432                 pad_lat.font_size_changed(font_size);
433                 pad_lon.font_size_changed(font_size);
434                 pad_alt.font_size_changed(font_size);
435         }
436
437         public void units_changed(boolean imperial_units) {
438                 battery.units_changed(imperial_units);
439                 apogee.units_changed(imperial_units);
440                 main.units_changed(imperial_units);
441                 logging_ready.units_changed(imperial_units);
442                 gps_locked.units_changed(imperial_units);
443                 gps_ready.units_changed(imperial_units);
444                 receiver_battery.units_changed(imperial_units);
445                 pad_lat.units_changed(imperial_units);
446                 pad_lon.units_changed(imperial_units);
447                 pad_alt.units_changed(imperial_units);
448         }
449
450         public void show(AltosState state, AltosListenerState listener_state) {
451                 battery.show(state, listener_state);
452                 apogee.show(state, listener_state);
453                 main.show(state, listener_state);
454                 logging_ready.show(state, listener_state);
455                 pad_alt.show(state, listener_state);
456                 receiver_battery.show(state, listener_state);
457                 gps_locked.show(state, listener_state);
458                 gps_ready.show(state, listener_state);
459                 pad_lat.show(state, listener_state);
460                 pad_lon.show(state, listener_state);
461         }
462
463         public AltosPad() {
464                 layout = new GridBagLayout();
465
466                 setLayout(layout);
467
468                 /* Elements in pad display:
469                  *
470                  * Battery voltage
471                  * Igniter continuity
472                  * GPS lock status
473                  * GPS ready status
474                  * GPS location
475                  * Pad altitude
476                  * RSSI
477                  */
478                 battery = new Battery(layout, 0);
479                 apogee = new Apogee(layout, 1);
480                 main = new Main(layout, 2);
481                 logging_ready = new LoggingReady(layout, 3);
482                 gps_locked = new GPSLocked(layout, 4);
483                 gps_ready = new GPSReady(layout, 5);
484                 receiver_battery = new ReceiverBattery(layout, 6);
485                 pad_lat = new PadLat(layout, 7);
486                 pad_lon = new PadLon(layout, 8);
487                 pad_alt = new PadAlt(layout, 9);
488                 show(null, null);
489         }
490 }