doc: Add 1.9 release notes
[fw/altos] / altoslib / AltosGPS.java
index 2c2fd36bc0f853d31f39162152252af5baff165f..8037eb93deb37ec63e44b49d5b3975c7e31b8dd8 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;
+package org.altusmetrum.altoslib_13;
 
 import java.text.*;
+import java.util.concurrent.*;
+import java.io.*;
+import java.time.*;
 
-public class AltosGPS {
+public class AltosGPS implements Cloneable {
 
-       public final static int MISSING = AltosRecord.MISSING;
+       public final static int MISSING = AltosLib.MISSING;
 
        public int      nsat;
        public boolean  locked;
        public boolean  connected;
        public double   lat;            /* degrees (+N -S) */
        public double   lon;            /* degrees (+E -W) */
-       public int      alt;            /* m */
+       public double   alt;            /* m */
        public int      year;
        public int      month;
        public int      day;
@@ -39,10 +43,11 @@ public class AltosGPS {
        public double   ground_speed;   /* m/s */
        public int      course;         /* degrees */
        public double   climb_rate;     /* m/s */
+       public double   pdop;           /* unitless */
        public double   hdop;           /* unitless */
        public double   vdop;           /* unitless */
-       public int      h_error;        /* m */
-       public int      v_error;        /* m */
+       public double   h_error;        /* m */
+       public double   v_error;        /* m */
 
        public AltosGPSSat[] cc_gps_sat;        /* tracking data */
 
@@ -65,40 +70,59 @@ public class AltosGPS {
        }
 
        public void ClearGPSTime() {
-               year = month = day = 0;
-               hour = minute = second = 0;
+               year = month = day = AltosLib.MISSING;
+               hour = minute = second = AltosLib.MISSING;
+       }
+
+       /* Return time since epoc in seconds */
+       public long seconds() {
+               if (year == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               if (month == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               if (day == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               if (hour == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               if (minute == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               if (second == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               OffsetDateTime  odt = OffsetDateTime.of(year, month, day, hour, minute, second, 0, ZoneOffset.UTC);
+               return odt.toEpochSecond();
        }
 
        public AltosGPS(AltosTelemetryMap map) throws ParseException {
-               String  state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE,
-                                              AltosTelemetry.AO_TELEM_GPS_STATE_ERROR);
+               String  state = map.get_string(AltosTelemetryLegacy.AO_TELEM_GPS_STATE,
+                                              AltosTelemetryLegacy.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)) {
+               nsat = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_NUM_SAT, 0);
+               if (state.equals(AltosTelemetryLegacy.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);
+                       lat = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7);
+                       lon = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7);
+                       alt = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_ALTITUDE, MISSING);
+                       year = map.get_int(AltosTelemetryLegacy.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)) {
+                       month = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MONTH, MISSING);
+                       day = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_DAY, MISSING);
+
+                       hour = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HOUR, 0);
+                       minute = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MINUTE, 0);
+                       second = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_SECOND, 0);
+
+                       ground_speed = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HORIZONTAL_SPEED,
+                                                     AltosLib.MISSING, 1/100.0);
+                       course = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_COURSE,
+                                            AltosLib.MISSING);
+                       pdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_PDOP, MISSING, 1.0);
+                       hdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HDOP, MISSING, 1.0);
+                       vdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_VDOP, MISSING, 1.0);
+                       h_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HERROR, MISSING);
+                       v_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_VERROR, MISSING);
+               } else if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_UNLOCKED)) {
                        connected = true;
                        locked = false;
                } else {
@@ -107,6 +131,62 @@ public class AltosGPS {
                }
        }
 
+       public boolean parse_string (String line, boolean says_done) {
+               String[] bits = line.split("\\s+");
+               if (bits.length == 0)
+                       return false;
+               if (line.startsWith("Date:")) {
+                       if (bits.length < 2)
+                               return false;
+                       String[] d = bits[1].split("/");
+                       if (d.length < 3)
+                               return false;
+                       year = Integer.parseInt(d[0]) + 2000;
+                       month = Integer.parseInt(d[1]);
+                       day = Integer.parseInt(d[2]);
+               } else if (line.startsWith("Time:")) {
+                       if (bits.length < 2)
+                               return false;
+                       String[] d = bits[1].split(":");
+                       if (d.length < 3)
+                               return false;
+                       hour = Integer.parseInt(d[0]);
+                       minute = Integer.parseInt(d[1]);
+                       second = Integer.parseInt(d[2]);
+               } else if (line.startsWith("Lat/Lon:")) {
+                       if (bits.length < 3)
+                               return false;
+                       lat = Integer.parseInt(bits[1]) * 1.0e-7;
+                       lon = Integer.parseInt(bits[2]) * 1.0e-7;
+               } else if (line.startsWith("Alt:")) {
+                       if (bits.length < 2)
+                               return false;
+                       alt = Integer.parseInt(bits[1]);
+               } else if (line.startsWith("Flags:")) {
+                       if (bits.length < 2)
+                               return false;
+                       int status = Integer.decode(bits[1]);
+                       connected = (status & AltosLib.AO_GPS_RUNNING) != 0;
+                       locked = (status & AltosLib.AO_GPS_VALID) != 0;
+                       if (!says_done)
+                               return false;
+               } else if (line.startsWith("Sats:")) {
+                       if (bits.length < 2)
+                               return false;
+                       nsat = Integer.parseInt(bits[1]);
+                       cc_gps_sat = new AltosGPSSat[nsat];
+                       for (int i = 0; i < nsat; i++) {
+                               int     svid = Integer.parseInt(bits[2+i*2]);
+                               int     cc_n0 = Integer.parseInt(bits[3+i*2]);
+                               cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0);
+                       }
+               } else if (line.startsWith("done")) {
+                       return false;
+               } else
+                       return false;
+               return true;
+       }
+
        public AltosGPS(String[] words, int i, int version) throws ParseException {
                AltosParse.word(words[i++], "GPS");
                nsat = AltosParse.parse_int(words[i++]);
@@ -135,10 +215,10 @@ public class AltosGPS {
                        lon = AltosParse.parse_coord(words[i++]);
                        alt = AltosParse.parse_int(words[i++]);
                        if (version > 1 || (i < words.length && !words[i].equals("SAT"))) {
-                               ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)"));
+                               ground_speed = AltosParse.parse_double_net(AltosParse.strip_suffix(words[i++], "m/s(H)"));
                                course = AltosParse.parse_int(words[i++]);
-                               climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)"));
-                               hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)"));
+                               climb_rate = AltosParse.parse_double_net(AltosParse.strip_suffix(words[i++], "m/s(V)"));
+                               hdop = AltosParse.parse_double_net(AltosParse.strip_suffix(words[i++], "(hdop)"));
                                h_error = AltosParse.parse_int(words[i++]);
                                v_error = AltosParse.parse_int(words[i++]);
                        }
@@ -174,24 +254,26 @@ public class AltosGPS {
                lon = in_lon / 10.0e7;
        }
 
-       public void set_time(int hour, int minute, int second) {
-               hour = hour;
-               minute = minute;
-               second = second;
+       public void set_time(int in_hour, int in_minute, int in_second) {
+               hour = in_hour;
+               minute = in_minute;
+               second = in_second;
        }
 
-       public void set_date(int year, int month, int day) {
-               year = year;
-               month = month;
-               day = day;
+       public void set_date(int in_year, int in_month, int in_day) {
+               year = in_year;
+               month = in_month;
+               day = in_day;
        }
 
-       public void set_flags(int flags) {
-               flags = flags;
+       /*
+       public void set_flags(int in_flags) {
+               flags = in_flags;
        }
+       */
 
-       public void set_altitude(int altitude) {
-               altitude = altitude;
+       public void set_altitude(int in_altitude) {
+               alt = in_altitude;
        }
 
        public void add_sat(int svid, int c_n0) {
@@ -209,39 +291,117 @@ public class AltosGPS {
                cc_gps_sat[cc_gps_sat.length - 1] = sat;
        }
 
-       public AltosGPS() {
+       private void init() {
+               lat = AltosLib.MISSING;
+               lon = AltosLib.MISSING;
+               alt = AltosLib.MISSING;
+               ground_speed = AltosLib.MISSING;
+               course = AltosLib.MISSING;
+               climb_rate = AltosLib.MISSING;
+               pdop = AltosLib.MISSING;
+               hdop = AltosLib.MISSING;
+               vdop = AltosLib.MISSING;
+               h_error = AltosLib.MISSING;
+               v_error = AltosLib.MISSING;
                ClearGPSTime();
                cc_gps_sat = null;
        }
 
+       public AltosGPS() {
+               init();
+       }
+
+       public AltosGPS clone() {
+               AltosGPS        g = new AltosGPS();
+
+               g.nsat = nsat;
+               g.locked = locked;
+               g.connected = connected;
+               g.lat = lat;            /* degrees (+N -S) */
+               g.lon = lon;            /* degrees (+E -W) */
+               g.alt = alt;            /* m */
+               g.year = year;
+               g.month = month;
+               g.day = day;
+               g.hour = hour;
+               g.minute = minute;
+               g.second = second;
+
+               g.ground_speed = ground_speed;  /* m/s */
+               g.course = course;              /* degrees */
+               g.climb_rate = climb_rate;      /* m/s */
+               g.pdop = pdop;          /* unitless */
+               g.hdop = hdop;          /* unitless */
+               g.vdop = vdop;          /* unitless */
+               g.h_error = h_error;    /* m */
+               g.v_error = v_error;    /* m */
+
+               if (cc_gps_sat != null) {
+                       g.cc_gps_sat = new AltosGPSSat[cc_gps_sat.length];
+                       for (int i = 0; i < cc_gps_sat.length; i++) {
+                               g.cc_gps_sat[i] = new AltosGPSSat(cc_gps_sat[i].svid,
+                                                                 cc_gps_sat[i].c_n0);
+                       }
+               }
+               return g;
+       }
+
        public AltosGPS(AltosGPS old) {
-               nsat = old.nsat;
-               locked = old.locked;
-               connected = old.connected;
-               lat = old.lat;          /* degrees (+N -S) */
-               lon = old.lon;          /* degrees (+E -W) */
-               alt = old.alt;          /* m */
-               year = old.year;
-               month = old.month;
-               day = old.day;
-               hour = old.hour;
-               minute = old.minute;
-               second = old.second;
-
-               ground_speed = old.ground_speed;        /* m/s */
-               course = old.course;            /* degrees */
-               climb_rate = old.climb_rate;    /* m/s */
-               hdop = old.hdop;                /* unitless? */
-               h_error = old.h_error;  /* m */
-               v_error = old.v_error;  /* m */
-
-               if (old.cc_gps_sat != null) {
-                       cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length];
-                       for (int i = 0; i < old.cc_gps_sat.length; i++) {
-                               cc_gps_sat[i] = new AltosGPSSat();
-                               cc_gps_sat[i].svid = old.cc_gps_sat[i].svid;
-                               cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0;
+               if (old != null) {
+                       nsat = old.nsat;
+                       locked = old.locked;
+                       connected = old.connected;
+                       lat = old.lat;          /* degrees (+N -S) */
+                       lon = old.lon;          /* degrees (+E -W) */
+                       alt = old.alt;          /* m */
+                       year = old.year;
+                       month = old.month;
+                       day = old.day;
+                       hour = old.hour;
+                       minute = old.minute;
+                       second = old.second;
+
+                       ground_speed = old.ground_speed;        /* m/s */
+                       course = old.course;            /* degrees */
+                       climb_rate = old.climb_rate;    /* m/s */
+                       pdop = old.pdop;                /* unitless? */
+                       hdop = old.hdop;                /* unitless? */
+                       vdop = old.vdop;                /* unitless? */
+                       h_error = old.h_error;          /* m */
+                       v_error = old.v_error;          /* m */
+
+                       if (old.cc_gps_sat != null) {
+                               cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length];
+                               for (int i = 0; i < old.cc_gps_sat.length; i++) {
+                                       cc_gps_sat[i] = new AltosGPSSat();
+                                       cc_gps_sat[i].svid = old.cc_gps_sat[i].svid;
+                                       cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0;
+                               }
                        }
+               } else {
+                       init();
+               }
+       }
+
+       static public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException {
+               try {
+                       AltosGPS gps = new AltosGPS(link, link.config_data());
+                       if (gps != null)
+                               listener.set_gps(gps);
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosGPS (AltosLink link, AltosConfigData config_data) throws TimeoutException, InterruptedException {
+               boolean says_done = config_data.compare_version("1.0") >= 0;
+               init();
+               link.printf("g\n");
+               for (;;) {
+                       String line = link.get_reply_no_dialog(5000);
+                       if (line == null)
+                               throw new TimeoutException();
+                       if (!parse_string(line, says_done))
+                               break;
                }
        }
 }