altosui: Add support for telemetry version 4
authorKeith Packard <keithp@keithp.com>
Wed, 23 Mar 2011 20:27:57 +0000 (05:27 +0900)
committerKeith Packard <keithp@keithp.com>
Wed, 23 Mar 2011 20:27:57 +0000 (05:27 +0900)
New telemetry format needed to support TeleNano and TeleMini

Signed-off-by: Keith Packard <keithp@keithp.com>
16 files changed:
altosui/AltosAscent.java
altosui/AltosCSV.java
altosui/AltosDataPointReader.java
altosui/AltosDescent.java
altosui/AltosFlightUI.java
altosui/AltosGPS.java
altosui/AltosLanded.java
altosui/AltosPad.java
altosui/AltosRecord.java
altosui/AltosSiteMap.java
altosui/AltosState.java
altosui/AltosTelemetry.java
altosui/AltosTelemetryIterable.java
altosui/AltosUI.java
altosui/Makefile.am
src/ao_telem.h

index 64bdcf3..0fbc5de 100644 (file)
@@ -87,6 +87,16 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
                void reset() {
                        value.setText("");
                }
+
+               void show() {
+                       label.show();
+                       value.show();
+               }
+
+               void hide() {
+                       label.hide();
+                       value.hide();
+               }
                public AscentValue (GridBagLayout layout, int y, String text) {
                        GridBagConstraints      c = new GridBagConstraints();
                        c.weighty = 1;
@@ -247,6 +257,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Lat extends AscentValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        if (state.gps != null)
                                value.setText(pos(state.gps.lat,"N", "S"));
                        else
@@ -261,6 +272,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Lon extends AscentValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        if (state.gps != null)
                                value.setText(pos(state.gps.lon,"E", "W"));
                        else
@@ -284,8 +296,13 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
        }
 
        public void show(AltosState state, int crc_errors) {
-               lat.show(state, crc_errors);
-               lon.show(state, crc_errors);
+               if (state.gps != null) {
+                       lat.show(state, crc_errors);
+                       lon.show(state, crc_errors);
+               } else {
+                       lat.hide();
+                       lon.hide();
+               }
                height.show(state, crc_errors);
                main.show(state, crc_errors);
                apogee.show(state, crc_errors);
index df98b2b..5277c16 100644 (file)
@@ -60,7 +60,7 @@ public class AltosCSV implements AltosWriter {
         *      drogue (V)
         *      main (V)
         *
-        * GPS data
+        * GPS data (if available)
         *      connected (1/0)
         *      locked (1/0)
         *      nsat (used for solution)
@@ -179,12 +179,14 @@ public class AltosCSV implements AltosWriter {
                }
        }
 
-       void write_header() {
+       void write_header(boolean gps) {
                out.printf("#"); write_general_header();
                out.printf(","); write_flight_header();
                out.printf(","); write_basic_header();
-               out.printf(","); write_gps_header();
-               out.printf(","); write_gps_sat_header();
+               if (gps) {
+                       out.printf(","); write_gps_header();
+                       out.printf(","); write_gps_sat_header();
+               }
                out.printf ("\n");
        }
 
@@ -192,9 +194,12 @@ public class AltosCSV implements AltosWriter {
                state = new AltosState(record, state);
                write_general(record); out.printf(",");
                write_flight(record); out.printf(",");
-               write_basic(record); out.printf(",");
-               write_gps(record); out.printf(",");
-               write_gps_sat(record);
+               write_basic(record);
+               if (record.gps != null) {
+                       out.printf(",");
+                       write_gps(record); out.printf(",");
+                       write_gps_sat(record);
+               }
                out.printf ("\n");
        }
 
@@ -206,7 +211,7 @@ public class AltosCSV implements AltosWriter {
 
        public void write(AltosRecord record) {
                if (!header_written) {
-                       write_header();
+                       write_header(record.gps != null);
                        header_written = true;
                }
                if (!seen_boost) {
@@ -240,12 +245,16 @@ public class AltosCSV implements AltosWriter {
                        write(r);
        }
 
-       public AltosCSV(File in_name) throws FileNotFoundException {
+       public AltosCSV(PrintStream in_out, File in_name) {
                name = in_name;
-               out = new PrintStream(name);
+               out = in_out;
                pad_records = new LinkedList<AltosRecord>();
        }
 
+       public AltosCSV(File in_name) throws FileNotFoundException {
+               this(new PrintStream(in_name), in_name);
+       }
+
        public AltosCSV(String in_string) throws FileNotFoundException {
                this(new File(in_string));
        }
index 7704310..ee57d2c 100644 (file)
@@ -15,6 +15,8 @@ class AltosDataPointReader implements Iterable<AltosDataPoint> {
     AltosState state;
     AltosRecord record;
 
+    final static int MISSING = AltosRecord.MISSING;
+
     public AltosDataPointReader(Iterable<AltosRecord> reader) {
         this.iter = reader.iterator();
         this.state = null;
index 16ccd45..594a7a0 100644 (file)
@@ -37,6 +37,19 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
                AltosLights     lights;
 
                abstract void show(AltosState state, int crc_errors);
+
+               void show() {
+                       label.show();
+                       value.show();
+                       lights.show();
+               }
+
+               void hide() {
+                       label.hide();
+                       value.hide();
+                       lights.hide();
+               }
+
                void reset() {
                        value.setText("");
                        lights.set(false);
@@ -90,6 +103,16 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
                abstract void show(AltosState state, int crc_errors);
 
+               void show() {
+                       label.show();
+                       value.show();
+               }
+
+               void hide() {
+                       label.hide();
+                       value.hide();
+               }
+
                void show(String format, double v) {
                        value.setText(String.format(format, v));
                }
@@ -134,12 +157,27 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
                        value2.setText("");
                }
 
+               void show() {
+                       label.show();
+                       value1.show();
+                       value2.show();
+               }
+
+               void hide() {
+                       label.hide();
+                       value1.hide();
+                       value2.hide();
+               }
+
                abstract void show(AltosState state, int crc_errors);
+
                void show(String v1, String v2) {
+                       show();
                        value1.setText(v1);
                        value2.setText(v2);
                }
                void show(String f1, double v1, String f2, double v2) {
+                       show();
                        value1.setText(String.format(f1, v1));
                        value2.setText(String.format(f2, v2));
                }
@@ -260,6 +298,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        class Main extends DescentStatus {
                void show (AltosState state, int crc_errors) {
+                       show();
                        value.setText(String.format("%4.2f V", state.main_sense));
                        lights.set(state.main_sense > 3.2);
                }
@@ -324,11 +363,19 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
        public void show(AltosState state, int crc_errors) {
                height.show(state, crc_errors);
                speed.show(state, crc_errors);
-               bearing.show(state, crc_errors);
-               range.show(state, crc_errors);
-               elevation.show(state, crc_errors);
-               lat.show(state, crc_errors);
-               lon.show(state, crc_errors);
+               if (state.gps != null) {
+                       bearing.show(state, crc_errors);
+                       range.show(state, crc_errors);
+                       elevation.show(state, crc_errors);
+                       lat.show(state, crc_errors);
+                       lon.show(state, crc_errors);
+               } else {
+                       bearing.hide();
+                       range.hide();
+                       elevation.hide();
+                       lat.hide();
+                       lon.hide();
+               }
                main.show(state, crc_errors);
                apogee.show(state, crc_errors);
        }
index 7fcfb8b..68e0ef8 100644 (file)
@@ -29,9 +29,6 @@ import java.util.prefs.*;
 import java.util.concurrent.LinkedBlockingQueue;
 
 public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
-       String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
-       Object[][] statusData = { { "0", "pad", "-50", "0" } };
-
        AltosVoice              voice;
        AltosFlightReader       reader;
        AltosDisplayThread      thread;
@@ -43,6 +40,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
        AltosDescent    descent;
        AltosLanded     landed;
        AltosSiteMap    sitemap;
+       boolean         has_map;
 
        private AltosFlightStatus flightStatus;
        private AltosInfoTable flightInfo;
@@ -85,6 +83,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
 
        public void show(AltosState state, int crc_errors) {
                JComponent tab = which_tab(state);
+               try {
                pad.show(state, crc_errors);
                ascent.show(state, crc_errors);
                descent.show(state, crc_errors);
@@ -97,7 +96,21 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
                }
                flightStatus.show(state, crc_errors);
                flightInfo.show(state, crc_errors);
-               sitemap.show(state, crc_errors);
+               if (state.gps != null) {
+                       if (!has_map) {
+                               pane.add("Site Map", sitemap);
+                               has_map = true;
+                       }
+                       sitemap.show(state, crc_errors);
+               } else {
+                       if (has_map) {
+                               pane.remove(sitemap);
+                               has_map = false;
+                       }
+               }
+               } catch (Exception e) {
+                       System.out.print("Show exception" + e);
+               }
        }
 
        public void set_exit_on_close() {
@@ -169,7 +182,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
                pane.add("Table", new JScrollPane(flightInfo));
 
                sitemap = new AltosSiteMap();
-               pane.add("Site Map", sitemap);
+               has_map = false;
 
                /* Make the tabbed pane use the rest of the window space */
                c.gridx = 0;
index 8382184..0dbc836 100644 (file)
@@ -26,10 +26,11 @@ public class AltosGPS {
                int     c_n0;
        }
 
+       final static int MISSING = AltosRecord.MISSING;
+
        int     nsat;
        boolean locked;
        boolean connected;
-       boolean date_valid;
        double  lat;            /* degrees (+N -S) */
        double  lon;            /* degrees (+E -W) */
        int     alt;            /* m */
@@ -40,11 +41,11 @@ public class AltosGPS {
        int     minute;
        int     second;
 
-       int     gps_extended;   /* has extra data */
        double  ground_speed;   /* m/s */
        int     course;         /* degrees */
        double  climb_rate;     /* m/s */
-       double  hdop;           /* unitless? */
+       double  hdop;           /* unitless */
+       double  vdop;           /* unitless */
        int     h_error;        /* m */
        int     v_error;        /* m */
 
@@ -73,6 +74,44 @@ public class AltosGPS {
                hour = minute = second = 0;
        }
 
+       public AltosGPS(AltosTelemetryMap map) throws ParseException {
+               String  state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE,
+                                              AltosTelemetry.AO_TELEM_GPS_STATE_ERROR);
+
+               nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0);
+               if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) {
+                       connected = true;
+                       locked = true;
+                       lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7);
+                       lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7);
+                       alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING);
+                       year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING);
+                       if (year != MISSING)
+                               year += 2000;
+                       month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING);
+                       day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING);
+
+                       hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0);
+                       minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0);
+                       second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0);
+
+                       ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED,
+                                                     AltosRecord.MISSING, 1/100.0);
+                       course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE,
+                                            AltosRecord.MISSING);
+                       hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0);
+                       vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0);
+                       h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING);
+                       v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING);
+               } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) {
+                       connected = true;
+                       locked = false;
+               } else {
+                       connected = false;
+                       locked = false;
+               }
+       }
+
        public AltosGPS(String[] words, int i, int version) throws ParseException {
                AltosParse.word(words[i++], "GPS");
                nsat = AltosParse.parse_int(words[i++]);
@@ -184,7 +223,6 @@ public class AltosGPS {
                nsat = old.nsat;
                locked = old.locked;
                connected = old.connected;
-               date_valid = old.date_valid;
                lat = old.lat;          /* degrees (+N -S) */
                lon = old.lon;          /* degrees (+E -W) */
                alt = old.alt;          /* m */
@@ -195,7 +233,6 @@ public class AltosGPS {
                minute = old.minute;
                second = old.second;
 
-               gps_extended = old.gps_extended;        /* has extra data */
                ground_speed = old.ground_speed;        /* m/s */
                course = old.course;            /* degrees */
                climb_rate = old.climb_rate;    /* m/s */
index d34efe6..0717ffe 100644 (file)
@@ -42,10 +42,22 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {
                        value.setText("");
                }
 
+               void show() {
+                       label.show();
+                       value.show();
+               }
+
+               void hide() {
+                       label.hide();
+                       value.hide();
+               }
+
                void show(String format, double v) {
+                       show();
                        value.setText(String.format(format, v));
                }
 
+
                public LandedValue (GridBagLayout layout, int y, String text) {
                        GridBagConstraints      c = new GridBagConstraints();
                        c.weighty = 1;
@@ -86,6 +98,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {
 
        class Lat extends LandedValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        if (state.gps != null)
                                value.setText(pos(state.gps.lat,"N", "S"));
                        else
@@ -100,6 +113,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {
 
        class Lon extends LandedValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        if (state.gps != null)
                                value.setText(pos(state.gps.lon,"E", "W"));
                        else
@@ -114,6 +128,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {
 
        class Bearing extends LandedValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        if (state.from_pad != null)
                                show("%3.0f°", state.from_pad.bearing);
                        else
@@ -128,6 +143,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {
 
        class Distance extends LandedValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        if (state.from_pad != null)
                                show("%6.0f m", state.from_pad.distance);
                        else
@@ -184,10 +200,17 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {
        }
 
        public void show(AltosState state, int crc_errors) {
-               bearing.show(state, crc_errors);
-               distance.show(state, crc_errors);
-               lat.show(state, crc_errors);
-               lon.show(state, crc_errors);
+               if (state.gps != null) {
+                       bearing.show(state, crc_errors);
+                       distance.show(state, crc_errors);
+                       lat.show(state, crc_errors);
+                       lon.show(state, crc_errors);
+               } else {
+                       bearing.hide();
+                       distance.hide();
+                       lat.hide();
+                       lon.hide();
+               }
                height.show(state, crc_errors);
                speed.show(state, crc_errors);
                accel.show(state, crc_errors);
index e345e5d..2f59e87 100644 (file)
@@ -42,6 +42,18 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
                        lights.set(false);
                }
 
+               public void show() {
+                       label.show();
+                       value.show();
+                       lights.show();
+               }
+
+               public void hide() {
+                       label.hide();
+                       value.hide();
+                       lights.hide();
+               }
+
                public LaunchStatus (GridBagLayout layout, int y, String text) {
                        GridBagConstraints      c = new GridBagConstraints();
                        c.weighty = 1;
@@ -83,6 +95,16 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
                JTextField      value;
                void show(AltosState state, int crc_errors) {}
 
+               void show() {
+                       label.show();
+                       value.show();
+               }
+
+               void hide() {
+                       label.hide();
+                       value.hide();
+               }
+
                void reset() {
                        value.setText("");
                }
@@ -151,6 +173,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class GPSLocked extends LaunchStatus {
                void show (AltosState state, int crc_errors) {
+                       show();
                        value.setText(String.format("%4d sats", state.gps.nsat));
                        lights.set(state.gps.locked && state.gps.nsat >= 4);
                }
@@ -163,6 +186,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class GPSReady extends LaunchStatus {
                void show (AltosState state, int crc_errors) {
+                       show();
                        if (state.gps_ready)
                                value.setText("Ready");
                        else
@@ -189,6 +213,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class PadLat extends LaunchValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        value.setText(pos(state.pad_lat,"N", "S"));
                }
                public PadLat (GridBagLayout layout, int y) {
@@ -200,6 +225,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class PadLon extends LaunchValue {
                void show (AltosState state, int crc_errors) {
+                       show();
                        value.setText(pos(state.pad_lon,"E", "W"));
                }
                public PadLon (GridBagLayout layout, int y) {
@@ -235,11 +261,18 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
                battery.show(state, crc_errors);
                apogee.show(state, crc_errors);
                main.show(state, crc_errors);
-               gps_locked.show(state, crc_errors);
-               gps_ready.show(state, crc_errors);
-               pad_lat.show(state, crc_errors);
-               pad_lon.show(state, crc_errors);
                pad_alt.show(state, crc_errors);
+               if (state.gps != null) {
+                       gps_locked.show(state, crc_errors);
+                       gps_ready.show(state, crc_errors);
+                       pad_lat.show(state, crc_errors);
+                       pad_lon.show(state, crc_errors);
+               } else {
+                       gps_locked.hide();
+                       gps_ready.hide();
+                       pad_lat.hide();
+                       pad_lon.hide();
+               }
        }
 
        public AltosPad() {
index 1160a27..46e96b9 100644 (file)
@@ -23,6 +23,8 @@ import java.util.HashMap;
 import java.io.*;
 
 public class AltosRecord {
+       final static int        MISSING = 0x7fffffff;
+
        int     version;
        String  callsign;
        int     serial;
@@ -31,19 +33,27 @@ public class AltosRecord {
        int     status;
        int     state;
        int     tick;
+
        int     accel;
        int     pres;
        int     temp;
        int     batt;
        int     drogue;
        int     main;
-       int     flight_accel;
+
        int     ground_accel;
-       int     flight_vel;
-       int     flight_pres;
        int     ground_pres;
        int     accel_plus_g;
        int     accel_minus_g;
+
+       double  acceleration;
+       double  speed;
+       double  height;
+
+       int     flight_accel;
+       int     flight_vel;
+       int     flight_pres;
+
        AltosGPS        gps;
 
        double  time;   /* seconds since boost */
@@ -72,46 +82,82 @@ public class AltosRecord {
        }
 
        public double raw_pressure() {
+               if (pres == MISSING)
+                       return MISSING;
                return barometer_to_pressure(pres);
        }
 
        public double filtered_pressure() {
+               if (flight_pres == MISSING)
+                       return MISSING;
                return barometer_to_pressure(flight_pres);
        }
 
        public double ground_pressure() {
+               if (ground_pres == MISSING)
+                       return MISSING;
                return barometer_to_pressure(ground_pres);
        }
 
-       public double filtered_altitude() {
-               return AltosConvert.pressure_to_altitude(filtered_pressure());
-       }
-
        public double raw_altitude() {
-               return AltosConvert.pressure_to_altitude(raw_pressure());
+               double p = raw_pressure();
+               if (p == MISSING)
+                       return MISSING;
+               return AltosConvert.pressure_to_altitude(p);
        }
 
        public double ground_altitude() {
-               return AltosConvert.pressure_to_altitude(ground_pressure());
+               double p = ground_pressure();
+               if (p == MISSING)
+                       return MISSING;
+               return AltosConvert.pressure_to_altitude(p);
+       }
+
+       public double filtered_altitude() {
+               if (height != MISSING && ground_pres != MISSING)
+                       return height + ground_altitude();
+
+               double  p = filtered_pressure();
+               if (p == MISSING)
+                       return MISSING;
+               return AltosConvert.pressure_to_altitude(p);
        }
 
        public double filtered_height() {
-               return filtered_altitude() - ground_altitude();
+               if (height != MISSING)
+                       return height;
+
+               double f = filtered_altitude();
+               double g = ground_altitude();
+               if (f == MISSING || g == MISSING)
+                       return MISSING;
+               return f - g;
        }
 
        public double raw_height() {
-               return raw_altitude() - ground_altitude();
+               double r = raw_altitude();
+               double g = ground_altitude();
+
+               if (r == MISSING || g == MISSING)
+                       return MISSING;
+               return r - g;
        }
 
        public double battery_voltage() {
+               if (batt == MISSING)
+                       return MISSING;
                return AltosConvert.cc_battery_to_voltage(batt);
        }
 
        public double main_voltage() {
+               if (main == MISSING)
+                       return MISSING;
                return AltosConvert.cc_ignitor_to_voltage(main);
        }
 
        public double drogue_voltage() {
+               if (drogue == MISSING)
+                       return MISSING;
                return AltosConvert.cc_ignitor_to_voltage(drogue);
        }
 
@@ -131,6 +177,8 @@ public class AltosRecord {
        }
 
        public double temperature() {
+               if (temp == MISSING)
+                       return MISSING;
                return thermometer_to_temperature(temp);
        }
 
@@ -139,13 +187,22 @@ public class AltosRecord {
 
                return counts_per_g / 9.80665;
        }
+
        public double acceleration() {
+               if (acceleration != MISSING)
+                       return acceleration;
+
+               if (ground_accel == MISSING || accel == MISSING)
+                       return MISSING;
                return (ground_accel - accel) / accel_counts_per_mss();
        }
 
        public double accel_speed() {
-               double speed = flight_vel / (accel_counts_per_mss() * 100.0);
-               return speed;
+               if (speed != MISSING)
+                       return speed;
+               if (flight_vel == MISSING)
+                       return MISSING;
+               return flight_vel / (accel_counts_per_mss() * 100.0);
        }
 
        public String state() {
index d6bd6d1..f4b6b7e 100644 (file)
@@ -228,8 +228,6 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
        int last_state = -1;
        public void show(final AltosState state, final int crc_errors) {
                // if insufficient gps data, nothing to update
-               if (state.gps == null)
-                       return;
                if (!state.gps.locked && state.gps.nsat < 4)
                        return;
 
index ec499d5..4e165f8 100644 (file)
@@ -79,7 +79,8 @@ public class AltosState {
                data = cur;
 
                ground_altitude = data.ground_altitude();
-               height = data.filtered_altitude() - ground_altitude;
+               height = data.filtered_height();
+               System.out.printf("height %g\n", height);
 
                report_time = System.currentTimeMillis();
 
@@ -114,10 +115,14 @@ public class AltosState {
                        /* compute barometric speed */
 
                        double height_change = height - prev_state.height;
-                       if (time_change > 0)
-                               baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0;
-                       else
-                               baro_speed = prev_state.baro_speed;
+                       if (data.speed != AltosRecord.MISSING)
+                               baro_speed = data.speed;
+                       else {
+                               if (time_change > 0)
+                                       baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0;
+                               else
+                                       baro_speed = prev_state.baro_speed;
+                       }
                } else {
                        npad = 0;
                        ngps = 0;
index bdb6466..3eb0efa 100644 (file)
@@ -27,10 +27,40 @@ import java.util.HashMap;
 
 
 /*
- * The telemetry data stream is a bit of a mess at present, with no consistent
- * formatting. In particular, the GPS data is formatted for viewing instead of parsing.
- * However, the key feature is that every telemetry line contains all of the information
- * necessary to describe the current rocket state, including the calibration values
+ * Version 4 is a replacement with consistent syntax. Each telemetry line
+ * contains a sequence of space-separated names and values, the values are
+ * either integers or strings. The names are all unique. All values are
+ * optional
+ *
+ * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
+ *   r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
+ *   a_s 0 a_b 26439 g_s u g_n 0 s_n 0
+ *
+ * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
+ *   r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
+ *
+ * General header fields
+ *
+ *     Name            Value
+ *
+ *     VERSION         Telemetry version number (4 or more). Must be first.
+ *     c               Callsign (string, no spaces allowed)
+ *     n               Flight unit serial number (integer)
+ *     f               Flight number (integer)
+ *     r               Packet RSSI value (integer)
+ *     s               Flight computer state (string, no spaces allowed)
+ *     t               Flight computer clock (integer in centiseconds)
+ *
+ * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
+ * in 1/2dB increments while this protocol provides only integers. So,
+ * the syntax didn't change just the interpretation of the RSSI
+ * values.
+ *
+ * Version 2 of the telemetry data stream is a bit of a mess, with no
+ * consistent formatting. In particular, the GPS data is formatted for
+ * viewing instead of parsing.  However, the key feature is that every
+ * telemetry line contains all of the information necessary to
+ * describe the current rocket state, including the calibration values
  * for accelerometer and barometer.
  *
  * GPS unlocked:
@@ -47,25 +77,201 @@ import java.util.HashMap;
  *     GPS  9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W  1790m  \
  *     0.00m/s(H) 0°     0.00m/s(V) 1.0(hdop)     0(herr)     0(verr) \
  *     SAT 10   29  30  24  28   5  25  21  20  15  33   1  23  30  24  18  26  10  29   2  26
+ *
  */
 
 public class AltosTelemetry extends AltosRecord {
-       public AltosTelemetry(String line) throws ParseException, AltosCRCException {
-               String[] words = line.split("\\s+");
-               int     i = 0;
+       /*
+        * General header fields
+        *
+        *      Name            Value
+        *
+        *      VERSION         Telemetry version number (4 or more). Must be first.
+        *      c               Callsign (string, no spaces allowed)
+        *      n               Flight unit serial number (integer)
+        *      f               Flight number (integer)
+        *      r               Packet RSSI value (integer)
+        *      s               Flight computer state (string, no spaces allowed)
+        *      t               Flight computer clock (integer in centiseconds)
+        */
 
-               if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
-                       i += 2;
-                       AltosParse.word(words[i++], "RSSI");
-                       rssi = AltosParse.parse_int(words[i++]);
-                       throw new AltosCRCException(rssi);
-               }
-               if (words[i].equals("CALL")) {
-                       version = 0;
-               } else {
-                       AltosParse.word (words[i++], "VERSION");
-                       version = AltosParse.parse_int(words[i++]);
-               }
+       final static String AO_TELEM_VERSION    = "VERSION";
+       final static String AO_TELEM_CALL       = "c";
+       final static String AO_TELEM_SERIAL     = "n";
+       final static String AO_TELEM_FLIGHT     = "f";
+       final static String AO_TELEM_RSSI       = "r";
+       final static String AO_TELEM_STATE      = "s";
+       final static String AO_TELEM_TICK       = "t";
+
+       /*
+        * Raw sensor values
+        *
+        *      Name            Value
+        *      r_a             Accelerometer reading (integer)
+        *      r_b             Barometer reading (integer)
+        *      r_t             Thermometer reading (integer)
+        *      r_v             Battery reading (integer)
+        *      r_d             Drogue continuity (integer)
+        *      r_m             Main continuity (integer)
+        */
+
+       final static String AO_TELEM_RAW_ACCEL  = "r_a";
+       final static String AO_TELEM_RAW_BARO   = "r_b";
+       final static String AO_TELEM_RAW_THERMO = "r_t";
+       final static String AO_TELEM_RAW_BATT   = "r_v";
+       final static String AO_TELEM_RAW_DROGUE = "r_d";
+       final static String AO_TELEM_RAW_MAIN   = "r_m";
+
+       /*
+        * Sensor calibration values
+        *
+        *      Name            Value
+        *      c_a             Ground accelerometer reading (integer)
+        *      c_b             Ground barometer reading (integer)
+        *      c_p             Accelerometer reading for +1g
+        *      c_m             Accelerometer reading for -1g
+        */
+
+       final static String AO_TELEM_CAL_ACCEL_GROUND   = "c_a";
+       final static String AO_TELEM_CAL_BARO_GROUND    = "c_b";
+       final static String AO_TELEM_CAL_ACCEL_PLUS     = "c_p";
+       final static String AO_TELEM_CAL_ACCEL_MINUS    = "c_m";
+
+       /*
+        * Kalman state values
+        *
+        *      Name            Value
+        *      k_h             Height above pad (integer, meters)
+        *      k_s             Vertical speeed (integer, m/s * 16)
+        *      k_a             Vertical acceleration (integer, m/s² * 16)
+        */
+
+       final static String AO_TELEM_KALMAN_HEIGHT      = "k_h";
+       final static String AO_TELEM_KALMAN_SPEED       = "k_s";
+       final static String AO_TELEM_KALMAN_ACCEL       = "k_a";
+
+       /*
+        * Ad-hoc flight values
+        *
+        *      Name            Value
+        *      a_a             Acceleration (integer, sensor units)
+        *      a_s             Speed (integer, integrated acceleration value)
+        *      a_b             Barometer reading (integer, sensor units)
+        */
+
+       final static String AO_TELEM_ADHOC_ACCEL        = "a_a";
+       final static String AO_TELEM_ADHOC_SPEED        = "a_s";
+       final static String AO_TELEM_ADHOC_BARO         = "a_b";
+
+       /*
+        * GPS values
+        *
+        *      Name            Value
+        *      g_s             GPS state (string):
+        *                              l       locked
+        *                              u       unlocked
+        *                              e       error (missing or broken)
+        *      g_n             Number of sats used in solution
+        *      g_ns            Latitude (degrees * 10e7)
+        *      g_ew            Longitude (degrees * 10e7)
+        *      g_a             Altitude (integer meters)
+        *      g_Y             GPS year (integer)
+        *      g_M             GPS month (integer - 1-12)
+        *      g_D             GPS day (integer - 1-31)
+        *      g_h             GPS hour (integer - 0-23)
+        *      g_m             GPS minute (integer - 0-59)
+        *      g_s             GPS second (integer - 0-59)
+        *      g_v             GPS vertical speed (integer, cm/sec)
+        *      g_s             GPS horizontal speed (integer, cm/sec)
+        *      g_c             GPS course (integer, 0-359)
+        *      g_hd            GPS hdop (integer * 10)
+        *      g_vd            GPS vdop (integer * 10)
+        *      g_he            GPS h error (integer)
+        *      g_ve            GPS v error (integer)
+        */
+
+       final static String AO_TELEM_GPS_STATE                  = "g";
+       final static String AO_TELEM_GPS_STATE_LOCKED           = "l";
+       final static String AO_TELEM_GPS_STATE_UNLOCKED         = "u";
+       final static String AO_TELEM_GPS_STATE_ERROR            = "e";
+       final static String AO_TELEM_GPS_NUM_SAT                = "g_n";
+       final static String AO_TELEM_GPS_LATITUDE               = "g_ns";
+       final static String AO_TELEM_GPS_LONGITUDE              = "g_ew";
+       final static String AO_TELEM_GPS_ALTITUDE               = "g_a";
+       final static String AO_TELEM_GPS_YEAR                   = "g_Y";
+       final static String AO_TELEM_GPS_MONTH                  = "g_M";
+       final static String AO_TELEM_GPS_DAY                    = "g_D";
+       final static String AO_TELEM_GPS_HOUR                   = "g_h";
+       final static String AO_TELEM_GPS_MINUTE                 = "g_m";
+       final static String AO_TELEM_GPS_SECOND                 = "g_s";
+       final static String AO_TELEM_GPS_VERTICAL_SPEED         = "g_v";
+       final static String AO_TELEM_GPS_HORIZONTAL_SPEED       = "g_g";
+       final static String AO_TELEM_GPS_COURSE                 = "g_c";
+       final static String AO_TELEM_GPS_HDOP                   = "g_hd";
+       final static String AO_TELEM_GPS_VDOP                   = "g_vd";
+       final static String AO_TELEM_GPS_HERROR                 = "g_he";
+       final static String AO_TELEM_GPS_VERROR                 = "g_ve";
+
+       /*
+        * GPS satellite values
+        *
+        *      Name            Value
+        *      s_n             Number of satellites reported (integer)
+        *      s_v0            Space vehicle ID (integer) for report 0
+        *      s_c0            C/N0 number (integer) for report 0
+        *      s_v1            Space vehicle ID (integer) for report 1
+        *      s_c1            C/N0 number (integer) for report 1
+        *      ...
+        */
+
+       final static String AO_TELEM_SAT_NUM    = "s_n";
+       final static String AO_TELEM_SAT_SVID   = "s_v";
+       final static String AO_TELEM_SAT_C_N_0  = "s_c";
+
+       private void parse_v4(String[] words, int i) throws ParseException {
+               AltosTelemetryMap       map = new AltosTelemetryMap(words, i);
+
+               callsign = map.get_string(AO_TELEM_CALL, "N0CALL");
+               serial = map.get_int(AO_TELEM_SERIAL, MISSING);
+               flight = map.get_int(AO_TELEM_FLIGHT, MISSING);
+               rssi = map.get_int(AO_TELEM_RSSI, MISSING);
+               state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid"));
+               tick = map.get_int(AO_TELEM_TICK, 0);
+
+               /* raw sensor values */
+               accel = map.get_int(AO_TELEM_RAW_ACCEL, MISSING);
+               pres = map.get_int(AO_TELEM_RAW_BARO, MISSING);
+               temp = map.get_int(AO_TELEM_RAW_THERMO, MISSING);
+               batt = map.get_int(AO_TELEM_RAW_BATT, MISSING);
+               drogue = map.get_int(AO_TELEM_RAW_DROGUE, MISSING);
+               main = map.get_int(AO_TELEM_RAW_MAIN, MISSING);
+
+               /* sensor calibration information */
+               ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, MISSING);
+               ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, MISSING);
+               accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, MISSING);
+               accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING);
+
+               /* flight computer values */
+               acceleration = map.get_int(AO_TELEM_KALMAN_ACCEL, MISSING);
+               if (acceleration != MISSING)
+                       acceleration /= 16.0;
+               speed = map.get_int(AO_TELEM_KALMAN_SPEED, MISSING);
+               if (speed != MISSING)
+                       speed /= 16.0;
+               height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING);
+
+               flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING);
+               flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING);
+               flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING);
+
+               if (map.has(AO_TELEM_GPS_STATE))
+                       gps = new AltosGPS(map);
+               else
+                       gps = null;
+       }
+
+       private void parse_legacy(String[] words, int i) throws ParseException {
 
                AltosParse.word (words[i++], "CALL");
                callsign = words[i++];
@@ -140,4 +346,27 @@ public class AltosTelemetry extends AltosRecord {
 
                gps = new AltosGPS(words, i, version);
        }
+
+       public AltosTelemetry(String line) throws ParseException, AltosCRCException {
+               String[] words = line.split("\\s+");
+               int     i = 0;
+
+               if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
+                       i += 2;
+                       AltosParse.word(words[i++], "RSSI");
+                       rssi = AltosParse.parse_int(words[i++]);
+                       throw new AltosCRCException(rssi);
+               }
+               if (words[i].equals("CALL")) {
+                       version = 0;
+               } else {
+                       AltosParse.word (words[i++], "VERSION");
+                       version = AltosParse.parse_int(words[i++]);
+               }
+
+               if (version < 4)
+                       parse_legacy(words, i);
+               else
+                       parse_v4(words, i);
+       }
 }
index a71ab87..14b5f27 100644 (file)
@@ -63,7 +63,6 @@ public class AltosTelemetryIterable extends AltosRecordIterable {
                                } catch (ParseException pe) {
                                        System.out.printf("parse exception %s\n", pe.getMessage());
                                } catch (AltosCRCException ce) {
-                                       System.out.printf("crc error\n");
                                }
                        }
                } catch (IOException io) {
index 90e3d7f..4d17b0d 100644 (file)
@@ -328,7 +328,7 @@ public class AltosUI extends JFrame {
                        if (input.equals(output)) {
                                System.out.printf("Not processing '%s'\n", input);
                        } else {
-                               AltosWriter writer = open_csv(output);
+                               AltosWriter writer = open_csv("/dev/stdout");
                                if (writer != null) {
                                        writer.write(iterable);
                                        writer.close();
index 288fca0..49f34ce 100644 (file)
@@ -65,6 +65,7 @@ altosui_JAVA = \
        AltosRecord.java \
        AltosRecordIterable.java \
        AltosTelemetryReader.java \
+       AltosTelemetryMap.java \
        AltosReplayReader.java \
        AltosRomconfig.java \
        AltosRomconfigUI.java \
index b1624fe..1a8da29 100644 (file)
  * GPS values
  *
  *     Name            Value
- *     g_s             GPS state (string):
+ *     g               GPS state (string):
  *                             l       locked
  *                             u       unlocked
  *                             e       error (missing or broken)
  *     g_m             GPS minute (integer - 0-59)
  *     g_s             GPS second (integer - 0-59)
  *     g_v             GPS vertical speed (integer, cm/sec)
- *     g_s             GPS horizontal speed (integer, cm/sec)
+ *     g_g             GPS horizontal speed (integer, cm/sec)
  *     g_c             GPS course (integer, 0-359)
  *     g_hd            GPS hdop (integer * 10)
  *     g_vd            GPS vdop (integer * 10)
  *     g_ve            GPS v error (integer)
  */
 
-#define AO_TELEM_GPS_STATE             "g_s"
+#define AO_TELEM_GPS_STATE             "g"
 #define AO_TELEM_GPS_STATE_LOCKED      'l'
 #define AO_TELEM_GPS_STATE_UNLOCKED    'u'
 #define AO_TELEM_GPS_STATE_ERROR       'e'
 #define AO_TELEM_GPS_MINUTE            "g_m"
 #define AO_TELEM_GPS_SECOND            "g_s"
 #define AO_TELEM_GPS_VERTICAL_SPEED    "g_v"
-#define AO_TELEM_GPS_HORIZONTAL_SPEED  "g_s"
+#define AO_TELEM_GPS_HORIZONTAL_SPEED  "g_g"
 #define AO_TELEM_GPS_COURSE            "g_c"
 #define AO_TELEM_GPS_HDOP              "g_hd"
 #define AO_TELEM_GPS_VDOP              "g_vd"