altosui: Add companion support to the flight UI and CSV conversion
authorKeith Packard <keithp@keithp.com>
Fri, 12 Aug 2011 21:58:34 +0000 (14:58 -0700)
committerKeith Packard <keithp@keithp.com>
Sun, 14 Aug 2011 01:46:12 +0000 (18:46 -0700)
Shows the companion data in a new tab. Also put companion data into
CSV file.

Signed-off-by: Keith Packard <keithp@keithp.com>
altosui/AltosCSV.java
altosui/AltosCompanionInfo.java [new file with mode: 0644]
altosui/AltosFlightUI.java
altosui/AltosRecord.java
altosui/AltosRecordCompanion.java [new file with mode: 0644]
altosui/AltosState.java
altosui/AltosTelemetryRecordCompanion.java [new file with mode: 0644]
altosui/AltosTelemetryRecordRaw.java
altosui/Makefile.am

index 5277c16..cf649db 100644 (file)
@@ -31,9 +31,9 @@ public class AltosCSV implements AltosWriter {
        LinkedList<AltosRecord> pad_records;
        AltosState              state;
 
-       static final int ALTOS_CSV_VERSION = 2;
+       static final int ALTOS_CSV_VERSION = 3;
 
-       /* Version 2 format:
+       /* Version 3 format:
         *
         * General info
         *      version number
@@ -81,6 +81,13 @@ public class AltosCSV implements AltosWriter {
         *
         * GPS Sat data
         *      C/N0 data for all 32 valid SDIDs
+        *
+        * Companion data
+        *      companion_id (1-255. 10 is TeleScience)
+        *      time of last companion data (seconds since boost)
+        *      update_period (0.1-2.55 minimum telemetry interval)
+        *      channels (0-12)
+        *      channel data for all 12 possible channels
         */
 
        void write_general_header() {
@@ -179,7 +186,32 @@ public class AltosCSV implements AltosWriter {
                }
        }
 
-       void write_header(boolean gps) {
+       void write_companion_header() {
+               out.printf("companion_id,companion_time,companion_update,companion_channels");
+               for (int i = 0; i < 12; i++)
+                       out.printf(",companion_%02d", i);
+       }
+
+       void write_companion(AltosRecord record) {
+               AltosRecordCompanion companion = record.companion;
+
+               int     channels_written = 0;
+               if (companion == null) {
+                       out.printf("0,0,0,0");
+               } else {
+                       out.printf("%3d,%5.2f,%5.2f,%2d",
+                                  companion.board_id,
+                                  (companion.tick - boost_tick) / 100.0,
+                                  companion.update_period / 100.0,
+                                  companion.channels);
+                       for (; channels_written < companion.channels; channels_written++)
+                               out.printf(",%5d", companion.companion_data[channels_written]);
+               }
+               for (; channels_written < 12; channels_written++)
+                       out.printf(",0");
+       }
+
+       void write_header(boolean gps, boolean companion) {
                out.printf("#"); write_general_header();
                out.printf(","); write_flight_header();
                out.printf(","); write_basic_header();
@@ -187,6 +219,9 @@ public class AltosCSV implements AltosWriter {
                        out.printf(","); write_gps_header();
                        out.printf(","); write_gps_sat_header();
                }
+               if (companion) {
+                       out.printf(","); write_companion_header();
+               }
                out.printf ("\n");
        }
 
@@ -200,6 +235,10 @@ public class AltosCSV implements AltosWriter {
                        write_gps(record); out.printf(",");
                        write_gps_sat(record);
                }
+               if (record.companion != null) {
+                       out.printf(",");
+                       write_companion(record);
+               }
                out.printf ("\n");
        }
 
@@ -210,8 +249,10 @@ public class AltosCSV implements AltosWriter {
        }
 
        public void write(AltosRecord record) {
+               if (record.state == Altos.ao_flight_startup)
+                       return;
                if (!header_written) {
-                       write_header(record.gps != null);
+                       write_header(record.gps != null, record.companion != null);
                        header_written = true;
                }
                if (!seen_boost) {
diff --git a/altosui/AltosCompanionInfo.java b/altosui/AltosCompanionInfo.java
new file mode 100644 (file)
index 0000000..f287a8e
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosCompanionInfo extends JTable {
+       private AltosFlightInfoTableModel model;
+
+       private Font infoLabelFont = new Font("SansSerif", Font.PLAIN, 14);
+       private Font infoValueFont = new Font("Monospaced", Font.PLAIN, 14);
+
+       static final int info_columns = 2;
+       static final int info_rows = 17;
+
+       int desired_row_height() {
+               FontMetrics     infoValueMetrics = getFontMetrics(infoValueFont);
+               return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10;
+       }
+
+       public AltosCompanionInfo() {
+               super(new AltosFlightInfoTableModel(info_rows, info_columns));
+               model = (AltosFlightInfoTableModel) getModel();
+               setFont(infoValueFont);
+               setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
+               setShowGrid(true);
+               setRowHeight(desired_row_height());
+               doLayout();
+       }
+
+       public Dimension getPreferredScrollableViewportSize() {
+               return getPreferredSize();
+       }
+
+       void info_reset() {
+               model.reset();
+       }
+
+       void info_add_row(int col, String name, String value) {
+               model.addRow(col, name, value);
+       }
+
+       void info_add_row(int col, String name, String format, Object... parameters) {
+               info_add_row (col, name, String.format(format, parameters));
+       }
+
+       void info_finish() {
+               model.finish();
+       }
+
+       public void clear() {
+               model.clear();
+       }
+
+       AltosRecordCompanion    companion;
+
+       public String board_name() {
+               if (companion == null)
+                       return "None";
+               switch (companion.board_id) {
+               case AltosRecordCompanion.board_id_telescience:
+                       return "TeleScience";
+               default:
+                       return String.format("%02x\n", companion.board_id);
+               }
+       }
+       
+       public void show(AltosState state, int crc_errors) {
+               if (state == null)
+                       return;
+               if (state.data.companion != null)
+                       companion = state.data.companion;
+               info_reset();
+               info_add_row(0, "Companion board", "%s", board_name());
+               if (companion != null) {
+                       info_add_row(0, "Last Data", "%5d", companion.tick);
+                       info_add_row(0, "Update period", "%5.2f s",
+                                    companion.update_period / 100.0);
+                       info_add_row(0, "Channels", "%3d", companion.channels);
+
+                       for (int i = 0; i < companion.channels; i++)
+                               info_add_row(1, String.format("Channel %2d", i),
+                                            "%6d", companion.companion_data[i]);
+               }
+               info_finish();
+       }
+}
index f0626e7..5176804 100644 (file)
@@ -39,8 +39,10 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
        AltosAscent     ascent;
        AltosDescent    descent;
        AltosLanded     landed;
+       AltosCompanionInfo      companion;
        AltosSiteMap    sitemap;
        boolean         has_map;
+       boolean         has_companion;
 
        private AltosFlightStatus flightStatus;
        private AltosInfoTable flightInfo;
@@ -96,7 +98,20 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
                }
                flightStatus.show(state, crc_errors);
                flightInfo.show(state, crc_errors);
-               if (state.gps != null) {
+
+               if (state.data.companion != null) {
+                       if (!has_companion) {
+                               pane.add("Companion", companion);
+                               has_companion= true;
+                       }
+                       companion.show(state, crc_errors);
+               } else {
+                       if (has_companion) {
+                               pane.remove(companion);
+                               has_companion = false;
+                       }
+               }
+               if (state.gps != null && state.gps.connected) {
                        if (!has_map) {
                                pane.add("Site Map", sitemap);
                                has_map = true;
@@ -216,6 +231,9 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
                flightInfo = new AltosInfoTable();
                pane.add("Table", new JScrollPane(flightInfo));
 
+               companion = new AltosCompanionInfo();
+               has_companion = false;
+
                sitemap = new AltosSiteMap();
                has_map = false;
 
index 144b1c3..ce6d86a 100644 (file)
@@ -32,6 +32,7 @@ public class AltosRecord {
        static final int        seen_gps_time = 16;
        static final int        seen_gps_lat = 32;
        static final int        seen_gps_lon = 64;
+       static final int        seen_companion = 128;
        int                     seen;
 
        int     version;
@@ -74,6 +75,8 @@ public class AltosRecord {
        int     main_deploy;
        int     flight_log_max;
        String  firmware_version;
+
+       AltosRecordCompanion companion;
        /*
         * Values for our MP3H6115A pressure sensor
         *
@@ -267,6 +270,7 @@ public class AltosRecord {
                speed = old.speed;
                height = old.height;
                gps = new AltosGPS(old.gps);
+               companion = old.companion;
        }
 
        public AltosRecord() {
@@ -296,5 +300,6 @@ public class AltosRecord {
                speed = MISSING;
                height = MISSING;
                gps = new AltosGPS();
+               companion = null;
        }
 }
diff --git a/altosui/AltosRecordCompanion.java b/altosui/AltosRecordCompanion.java
new file mode 100644 (file)
index 0000000..0a8f9f4
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+public class AltosRecordCompanion {
+       final static int        board_id_telescience = 0x0a;
+       final static int        MAX_CHANNELS = 12;
+
+       int     tick;
+       int     board_id;
+       int     update_period;
+       int     channels;
+       int[]   companion_data;
+
+       public AltosRecordCompanion(int in_channels) {
+               channels = in_channels;
+               if (channels < 0)
+                       channels = 0;
+               if (channels > MAX_CHANNELS)
+                       channels = MAX_CHANNELS;
+               companion_data = new int[channels];
+       }
+}
index 378930b..072cb79 100644 (file)
@@ -73,7 +73,6 @@ public class AltosState {
        int     speak_tick;
        double  speak_altitude;
 
-
        void init (AltosRecord cur, AltosState prev_state) {
                int             i;
                AltosRecord prev;
diff --git a/altosui/AltosTelemetryRecordCompanion.java b/altosui/AltosTelemetryRecordCompanion.java
new file mode 100644 (file)
index 0000000..11b349e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw {
+
+       AltosRecordCompanion    companion;
+
+       public AltosTelemetryRecordCompanion(int[] in_bytes) {
+               super(in_bytes);
+
+               int     off = 0;
+               if (uint8(6) == 0)
+                       off = 1;
+               int channels = uint8(7+off);
+
+               if (off != 0 && channels >= 12)
+                       channels = 11;
+
+               companion = new AltosRecordCompanion(channels);
+               companion.tick          = tick;
+               companion.board_id      = uint8(5);
+               companion.update_period = uint8(6+off);
+               for (int i = 0; i < channels; i++)
+                       companion.companion_data[i] = uint16(8 + off + i * 2);
+       }
+
+       public AltosRecord update_state(AltosRecord previous) {
+               AltosRecord     next = super.update_state(previous);
+
+               next.companion = companion;
+               next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;
+
+               companion.tick = tick;
+               return next;
+       }
+}
index 4b34f01..39b2ba0 100644 (file)
@@ -33,6 +33,7 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord {
        final static int packet_type_configuration = 0x04;
        final static int packet_type_location = 0x05;
        final static int packet_type_satellite = 0x06;
+       final static int packet_type_companion = 0x07;
        
        final static int PKT_APPEND_STATUS_1_CRC_OK             = (1 << 7);
        final static int PKT_APPEND_STATUS_1_LQI_MASK           = (0x7f);
@@ -89,6 +90,9 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord {
                        case packet_type_satellite:
                                r = new AltosTelemetryRecordSatellite(bytes);
                                break;
+                       case packet_type_companion:
+                               r = new AltosTelemetryRecordCompanion(bytes);
+                               break;
                        default:
                                r = new AltosTelemetryRecordRaw(bytes);
                                break;
@@ -139,9 +143,11 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord {
 
        public AltosRecord update_state(AltosRecord previous) {
                AltosRecord     next;
-               if (previous != null)
+               if (previous != null) {
                        next = new AltosRecord(previous);
-               else
+                       while (tick < previous.tick)
+                               tick += 65536;
+               } else
                        next = new AltosRecord();
                next.serial = serial;
                next.tick = tick;
index bab8f81..8351035 100644 (file)
@@ -20,6 +20,7 @@ altosui_JAVA = \
        GrabNDrag.java \
        AltosAscent.java \
        AltosChannelMenu.java \
+       AltosCompanionInfo.java \
        AltosConfig.java \
        AltosConfigData.java \
        AltosConfigFreqUI.java \
@@ -77,6 +78,7 @@ altosui_JAVA = \
        AltosPreferences.java \
        AltosReader.java \
        AltosRecord.java \
+       AltosRecordCompanion.java \
        AltosRecordIterable.java \
        AltosTelemetryReader.java \
        AltosTelemetryRecord.java \
@@ -86,6 +88,7 @@ altosui_JAVA = \
        AltosTelemetryRecordConfiguration.java \
        AltosTelemetryRecordLocation.java \
        AltosTelemetryRecordSatellite.java \
+       AltosTelemetryRecordCompanion.java \
        AltosTelemetryRecordLegacy.java \
        AltosTelemetryMap.java \
        AltosReplayReader.java \