altos/stm32f4-disco: Start hooking up stm32f413 USB for the disco board
[fw/altos] / altoslib / AltosKML.java
index cc9a9f51051b9339eefde74b40954053e62744a3..cafc7f96bf0e11591f1a861463575b7974f987b0 100644 (file)
@@ -3,7 +3,8 @@
  *
  * 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.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_13;
 
 import java.io.*;
+import java.util.*;
+
+class KMLWriter extends PrintWriter {
+       public PrintWriter printf(String format, Object ... arguments) {
+               return printf(Locale.ROOT, format, arguments);
+       }
+
+       public KMLWriter(File name) throws FileNotFoundException {
+               super(name);
+       }
+}
 
 public class AltosKML implements AltosWriter {
 
        File                    name;
-       PrintStream             out;
+       PrintWriter             out;
        int                     flight_state = -1;
-       AltosState              prev = null;
-       double                  gps_start_altitude;
+       AltosGPS                prev = null;
+       double                  gps_start_altitude = AltosLib.MISSING;
+       AltosFlightSeries       series;
+       AltosFlightStats        stats;
+       AltosCalData            cal_data;
 
        static final String[] kml_state_colors = {
-               "FF000000",
-               "FF000000",
-               "FF000000",
-               "FF0000FF",
-               "FF4080FF",
-               "FF00FFFF",
-               "FFFF0000",
-               "FF00FF00",
-               "FF000000",
-               "FFFFFFFF"
+               "FF000000",     // startup
+               "FF000000",     // idle
+               "FF000000",     // pad
+               "FF0000FF",     // boost
+               "FF8040FF",     // coast
+               "FF4080FF",     // fast
+               "FF00FFFF",     // drogue
+               "FF00FF00",     // main
+               "FF000000",     // landed
+               "FFFFFFFF",     // invalid
+               "FFFF0000",     // stateless
+       };
+
+       static String state_color(int state) {
+               if (state < 0 || kml_state_colors.length <= state)
+                       return kml_state_colors[AltosLib.ao_flight_invalid];
+               return kml_state_colors[state];
+       }
+
+       static final String[] kml_style_colors = {
+               "FF0000FF",     // baro
+               "FFFF0000",     // gps
        };
 
+       static String style_color(int style) {
+               if (style < 0 || kml_style_colors.length <= style)
+                       return kml_style_colors[0];
+               return kml_style_colors[style];
+       }
+
        static final String kml_header_start =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
                "<Document>\n" +
                "  <name>AO Flight#%d S/N: %03d</name>\n" +
-               "  <description>\n";
+               "  <Snippet maxLines=\"8\">\n";
+
        static final String kml_header_end =
-               "  </description>\n" +
-               "  <open>0</open>\n";
-
-       static final String kml_style_start =
-               "  <Style id=\"ao-flightstate-%s\">\n" +
-               "    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
-               "    <BalloonStyle>\n" +
-               "      <text>\n";
-
-       static final String kml_style_end =
-               "      </text>\n" +
-               "    </BalloonStyle>\n" +
-               "  </Style>\n";
-
-       static final String kml_placemark_start =
-               "  <Placemark>\n" +
-               "    <name>%s</name>\n" +
-               "    <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
-               "    <LineString>\n" +
-               "      <tessellate>1</tessellate>\n" +
-               "      <altitudeMode>absolute</altitudeMode>\n" +
-               "      <coordinates>\n";
+               "  </Snippet>\n" +
+               "  <open>1</open>\n";
+
+       static final String kml_folder_start =
+               "  <Folder>\n" +
+               "    <name>%s</name>\n";
+
+       static final String kml_path_style_start =
+               "    <Style id=\"ao-style-%s\">\n" +
+               "      <LineStyle><color>%s</color><width>8</width></LineStyle>\n" +
+               "      <BalloonStyle>\n" +
+               "        <text>\n";
+
+       static final String kml_path_style_end =
+               "        </text>\n" +
+               "      </BalloonStyle>\n" +
+               "    </Style>\n";
+
+       static final String kml_point_style_start =
+               "    <Style id=\"ao-style-%s\">\n" +
+               "      <LabelStyle><color>%s</color></LabelStyle>\n" +
+               "      <IconStyle><color>%s</color></IconStyle>\n" +
+               "      <BalloonStyle>\n" +
+               "        <text>\n";
+
+       static final String kml_point_style_end =
+               "        </text>\n" +
+               "      </BalloonStyle>\n" +
+               "    </Style>\n";
+
+       static final String kml_path_start =
+               "    <Placemark>\n" +
+               "      <name>%s</name>\n" +
+               "      <styleUrl>#ao-style-%s</styleUrl>\n" +
+               "      <LineString>\n" +
+               "        <tessellate>1</tessellate>\n" +
+               "        <altitudeMode>absolute</altitudeMode>\n" +
+               "        <coordinates>\n";
 
        static final String kml_coord_fmt =
-       "        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+       "          %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+
+       static final String kml_path_end =
+               "        </coordinates>\n" +
+               "      </LineString>\n" +
+               "    </Placemark>\n";
+
+       static final String kml_point_start =
+               "    <Placemark>\n" +
+               "      <name>%s</name>\n" +
+               "      <styleUrl>#ao-style-%s</styleUrl>\n" +
+               "      <Point>\n" +
+               "        <tessellate>1</tessellate>\n" +
+               "        <altitudeMode>absolute</altitudeMode>\n" +
+               "        <coordinates>\n";
+
+       static final String kml_point_end =
+               "        </coordinates>\n" +
+               "      </Point>\n" +
+               "    </Placemark>\n";
 
-       static final String kml_placemark_end =
-               "      </coordinates>\n" +
-               "    </LineString>\n" +
-               "  </Placemark>\n";
+       static final String kml_folder_end =
+               "  </Folder>\n";
 
        static final String kml_footer =
                "</Document>\n" +
                "</kml>\n";
 
-       void start (AltosState record) {
-               out.printf(kml_header_start, record.flight, record.serial);
-               out.printf("Date:   %04d-%02d-%02d\n",
-                          record.gps.year, record.gps.month, record.gps.day);
-               out.printf("Time:     %2d:%02d:%02d\n",
-                          record.gps.hour, record.gps.minute, record.gps.second);
+       void start () {
+               AltosGPS gps = cal_data.gps_pad;
+
+               gps_start_altitude = cal_data.gps_pad_altitude;
+               out.printf(kml_header_start, cal_data.flight, cal_data.serial);
+               out.printf("Product: %s\n", stats.product);
+               out.printf("Firmware: %s\n", stats.firmware_version);
+               out.printf("Date: %04d-%02d-%02d\n",
+                          gps.year, gps.month, gps.day);
+               out.printf("Time: %2d:%02d:%02d\n",
+                          gps.hour, gps.minute, gps.second);
+               if (stats.max_height != AltosLib.MISSING)
+                       out.printf("Max baro height: %s\n", AltosConvert.height.show(6, stats.max_height));
+               if (stats.max_gps_height != AltosLib.MISSING)
+                       out.printf("Max GPS Height: %s\n", AltosConvert.height.show(6, stats.max_gps_height));
+               if (stats.max_speed != AltosLib.MISSING)
+                       out.printf("Max speed: %s\n", AltosConvert.speed.show(6, stats.max_speed));
+               if (stats.max_acceleration != AltosLib.MISSING)
+                       out.printf("Max accel: %s\n", AltosConvert.accel.show(6, stats.max_acceleration));
                out.printf("%s", kml_header_end);
        }
 
-       boolean started = false;
+       void folder_start(String folder_name) {
+               out.printf(kml_folder_start, folder_name);
+       }
 
-       void state_start(AltosState state) {
-               String  state_name = AltosLib.state_name(state.state);
-               out.printf(kml_style_start, state_name, kml_state_colors[state.state]);
-               out.printf("\tState: %s\n", state_name);
-               out.printf("%s", kml_style_end);
-               out.printf(kml_placemark_start, state_name, state_name);
+       void folder_end() {
+               out.printf(kml_folder_end);
        }
 
-       void state_end(AltosState state) {
-               out.printf("%s", kml_placemark_end);
+       void path_style_start(String style, String color) {
+               out.printf(kml_path_style_start, style, color);
        }
 
-       void coord(AltosState state) {
-               AltosGPS        gps = state.gps;
-               double          altitude;
+       void path_style_end() {
+               out.printf(kml_path_style_end);
+       }
+
+       void point_style_start(String style, String color) {
+               out.printf(kml_point_style_start, style, color, color);
+       }
 
-               if (state.height() != AltosLib.MISSING)
-                       altitude = state.height() + gps_start_altitude;
-               else
-                       altitude = gps.alt;
+       void point_style_end() {
+               out.printf(kml_point_style_end);
+       }
+
+       void path_start(String name, String style) {
+               out.printf(kml_path_start, name, style);
+       }
+
+       void path_end() {
+               out.printf(kml_path_end);
+       }
+
+       void point_start(String name, String style) {
+               out.printf(kml_point_start, name, style);
+       }
+
+       void point_end() {
+               out.printf(kml_point_end);
+       }
+
+       boolean started = false;
+
+       private double baro_altitude(AltosFlightSeries series, double time) {
+               double height = series.value(AltosFlightSeries.height_name, time);
+
+               if (height == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               if (cal_data.gps_pad_altitude == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+
+               return height + cal_data.gps_pad_altitude;
+       }
+
+       void coord(double time, AltosGPS gps, double altitude) {
                out.printf(kml_coord_fmt,
                           gps.lon, gps.lat,
                           altitude, (double) gps.alt,
-                          state.time, gps.nsat);
+                          time, gps.nsat);
        }
 
        void end() {
@@ -124,52 +236,116 @@ public class AltosKML implements AltosWriter {
        }
 
        public void close() {
-               if (prev != null) {
-                       state_end(prev);
-                       end();
-                       prev = null;
+               if (out != null) {
+                       out.close();
+                       out = null;
                }
        }
 
-       public void write(AltosState state) {
-               AltosGPS        gps = state.gps;
-
+       public void write(AltosGPS gps, double alt)
+       {
                if (gps == null)
                        return;
-
                if (gps.lat == AltosLib.MISSING)
                        return;
                if (gps.lon == AltosLib.MISSING)
                        return;
-               if (!started) {
-                       start(state);
-                       started = true;
-                       gps_start_altitude = gps.alt;
+               if (alt == AltosLib.MISSING) {
+                       alt = cal_data.gps_pad_altitude;
+                       if (alt == AltosLib.MISSING)
+                               return;
                }
-               if (prev != null && prev.gps_sequence == state.gps_sequence)
-                       return;
-               if (state.state != flight_state) {
-                       flight_state = state.state;
-                       if (prev != null) {
-                               coord(state);
-                               state_end(prev);
-                       }
-                       state_start(state);
+               coord(0, gps, alt);
+               prev = gps;
+       }
+
+       public void write_point(AltosTimeValue tv, boolean is_gps) {
+               int             state = (int) tv.value;
+               String          style_prefix = is_gps ? "gps-" : "baro-";
+               String          state_name = AltosLib.state_name(state);
+               String          state_label = AltosLib.state_name_capital(state);
+               String          style_name = style_prefix + state_name;
+               String          folder_name = is_gps ? "GPS" : "Baro";
+               String          full_name = state_label + " (" + folder_name + ")";
+               AltosGPS        gps = series.gps_before(tv.time);
+               double          altitude = is_gps ? gps.alt : baro_altitude(series, tv.time);
+
+               point_style_start(style_name, state_color(state));
+               out.printf("%s\n", full_name);
+               switch (state) {
+               case AltosLib.ao_flight_boost:
+                       out.printf("Max accel %s\n", AltosConvert.accel.show(6, stats.max_acceleration));
+                       out.printf("Max speed %s\n", AltosConvert.speed.show(6, stats.max_speed));
+                       break;
+               case AltosLib.ao_flight_coast:
+               case AltosLib.ao_flight_fast:
+                       out.printf("Entry speed %s\n", AltosConvert.speed.show(6, stats.state_enter_speed[state]));
+                       out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude));
+                       break;
+               case AltosLib.ao_flight_drogue:
+                       out.printf("Max height %s\n", AltosConvert.height.show(6, is_gps ? stats.max_gps_height : stats.max_height));
+                       out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state]));
+                       break;
+               case AltosLib.ao_flight_main:
+                       out.printf("Entry speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state]));
+                       out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude));
+                       out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state]));
+                       break;
+               case AltosLib.ao_flight_landed:
+                       out.printf("Landing speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state]));
+                       break;
                }
-               coord(state);
-               prev = state;
+               point_style_end();
+               point_start(full_name, style_name);
+               gps = series.gps_before(tv.time);
+               write(gps, altitude);
+               point_end();
        }
 
-       public void write(AltosStateIterable states) {
-               for (AltosState state : states) {
-                       if ((state.set & AltosState.set_gps) != 0)
-                               write(state);
+       public void write(AltosFlightSeries series) {
+               this.series = series;
+               series.finish();
+               stats = new AltosFlightStats(series);
+               cal_data = series.cal_data();
+               start();
+               if (series.height_series != null) {
+                       folder_start("Barometric Altitude");
+                       path_style_start("baro", style_color(0));
+                       out.printf("Barometric Altitude\n");
+                       out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height));
+                       path_style_end();
+                       path_start("Barometric Altitude", "baro");
+                       for (AltosGPSTimeValue gtv : series.gps_series)
+                               write(gtv.gps, baro_altitude(series, gtv.time));
+                       path_end();
+                       if (series.state_series != null) {
+                               for (AltosTimeValue tv : series.state_series) {
+                                       write_point(tv, false);
+                               }
+                       }
+                       folder_end();
+               }
+               folder_start("GPS Altitude");
+               path_style_start("gps", style_color(1));
+               out.printf("GPS Altitude");
+               out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_gps_height));
+               path_style_end();
+               path_start("GPS Altitude", "gps");
+               for (AltosGPSTimeValue gtv : series.gps_series)
+                       write(gtv.gps, gtv.gps.alt);
+               path_end();
+               if (series.state_series != null) {
+                       for (AltosTimeValue tv : series.state_series) {
+                               write_point(tv, true);
+                       }
                }
+               folder_end();
+               end();
        }
 
        public AltosKML(File in_name) throws FileNotFoundException {
                name = in_name;
-               out = new PrintStream(name);
+               out = new KMLWriter(name);
        }
 
        public AltosKML(String in_string) throws FileNotFoundException {