+#else /* AO_UBLOX_VERSION < 10 */
+
+/*
+ * NAV-PVT message parsing
+ */
+
+static struct nav_pvt {
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t min;
+ uint8_t sec;
+ uint8_t valid;
+ int32_t nano;
+ uint8_t flags;
+ uint8_t num_sv;
+ int32_t lat;
+ int32_t lon;
+ int32_t alt_msl;
+ int32_t vel_d;
+ int32_t g_speed;
+ int32_t heading;
+} nav_pvt;
+
+static const struct ublox_packet_parse nav_pvt_packet[] = {
+ { UBLOX_DISCARD, 4 }, /* 0 iTOW */
+ { UBLOX_U16, offsetof(struct nav_pvt, year) }, /* 4 year */
+ { UBLOX_U8, offsetof(struct nav_pvt, month) }, /* 6 month */
+ { UBLOX_U8, offsetof(struct nav_pvt, day) }, /* 7 day */
+ { UBLOX_U8, offsetof(struct nav_pvt, hour) }, /* 8 hour */
+ { UBLOX_U8, offsetof(struct nav_pvt, min) }, /* 9 min */
+ { UBLOX_U8, offsetof(struct nav_pvt, sec) }, /* 10 sec */
+ { UBLOX_U8, offsetof(struct nav_pvt, valid) }, /* 11 valid */
+ { UBLOX_DISCARD, 4 }, /* 12 tAcc */
+ { UBLOX_U32, offsetof(struct nav_pvt, nano) }, /* 16 nano */
+ { UBLOX_DISCARD, 1 }, /* 20 fixType */
+ { UBLOX_U8, offsetof(struct nav_pvt, flags) }, /* 21 gpsFix */
+ { UBLOX_DISCARD, 1 }, /* 22 flags2 */
+ { UBLOX_U8, offsetof(struct nav_pvt, num_sv) }, /* 23 numSV */
+ { UBLOX_U32, offsetof(struct nav_pvt, lon) }, /* 24 Longitude */
+ { UBLOX_U32, offsetof(struct nav_pvt, lat) }, /* 28 Latitude */
+ { UBLOX_DISCARD, 4 }, /* 32 height above ellipsoid */
+ { UBLOX_U32, offsetof(struct nav_pvt, alt_msl) }, /* 36 Height above mean sea level */
+ { UBLOX_DISCARD, 16 }, /* 40 hAcc, vAcc, velN, velE */
+ { UBLOX_U32, offsetof(struct nav_pvt, vel_d) }, /* 56 velD */
+ { UBLOX_U32, offsetof(struct nav_pvt, g_speed) }, /* 60 gSpeed */
+ { UBLOX_U32, offsetof(struct nav_pvt, heading) }, /* 64 headMot */
+ { UBLOX_DISCARD, 92 - 68 }, /* 68 sAcc .. magAcc */
+ { UBLOX_END, 0 }
+};
+
+#define NAV_PVT_VALID_DATE 0
+#define NAV_PVT_VALID_TIME 1
+#define NAV_PVT_VALID_FULLY_RESOLVED 2
+#define NAV_PVT_VALID_MAG 3
+
+#define NAV_PVT_FLAGS_GNSSFIXOK 0
+#define NAV_PVT_FLAGS_DIFFSOLN 1
+#define NAV_PVT_FLAGS_PSM_STATE 2
+#define NAV_PVT_FLAGS_HEAD_VEH_VALID 5
+#define NAV_PVT_FLAGS_CARR_SOLN 6
+
+static void
+ao_ublox_parse_nav_pvt(void)
+{
+ ao_ublox_parse(&nav_pvt, nav_pvt_packet);
+#if AO_UBLOX_DEBUG
+ ao_gps_dbg(DBG_PROTO, "\t%d-%d-%d %02d:%02d:%02d %ld (%02x)\n",
+ nav_pvt.year, nav_pvt.month, nav_pvt.day,
+ nav_pvt.hour, nav_pvt.min, nav_pvt.sec,
+ (long) nav_pvt.nano, nav_pvt.valid);
+ ao_gps_dbg(DBG_PROTO, "\tflags %02x numSV %d lon %ld lat %ld alt %ld\n",
+ nav_pvt.flags, nav_pvt.num_sv,
+ (long) nav_pvt.lon, (long) nav_pvt.lat, (long) nav_pvt.alt_msl);
+#endif
+}
+
+/*
+ * NAV-SAT message parsing
+ */
+
+static struct nav_sat {
+ uint8_t num_svs;
+} nav_sat;
+
+static const struct ublox_packet_parse nav_sat_packet[] = {
+ { UBLOX_DISCARD, 4 }, /* 0 iTOW */
+ { UBLOX_DISCARD, 1 }, /* 4 version */
+ { UBLOX_U8, offsetof(struct nav_sat, num_svs) }, /* 4 numSvs */
+ { UBLOX_DISCARD, 2 }, /* 6 reserved0 */
+ { UBLOX_END, 0 }
+};
+
+#define NAV_SAT_MAX_SAT AO_TELEMETRY_SATELLITE_MAX_SAT
+
+static struct nav_sat_sat {
+ uint8_t svid;
+ uint8_t cno;
+} nav_sat_sat[NAV_SAT_MAX_SAT];
+
+static uint8_t nav_sat_nsat;
+
+static struct nav_sat_real_sat {
+ uint8_t svid;
+ uint8_t cno;
+ uint32_t flags;
+} nav_sat_real_sat;
+
+static const struct ublox_packet_parse nav_sat_sat_packet[] = {
+ { UBLOX_DISCARD, 1 }, /* 8 + 12*N gnssid */
+ { UBLOX_U8, offsetof(struct nav_sat_real_sat, svid) }, /* 9 + 12*N svid */
+ { UBLOX_U8, offsetof(struct nav_sat_real_sat, cno) }, /* 10 + 12*N cno */
+ { UBLOX_DISCARD, 5 }, /* 11 + 12*N elev, azim, prRes */
+ { UBLOX_U32, offsetof(struct nav_sat_real_sat, flags) }, /* 16 + 12*N flags */
+ { UBLOX_END, 0 }
+};
+
+static uint32_t
+ao_ublox_sat_quality(struct nav_sat_real_sat *sat)
+{
+ return (sat->flags >> UBLOX_NAV_SAT_FLAGS_QUALITY) & UBLOX_NAV_SAT_FLAGS_QUALITY_MASK;
+}
+
+static uint32_t
+ao_ublox_sat_health(struct nav_sat_real_sat *sat)
+{
+ return (sat->flags >> UBLOX_NAV_SAT_FLAGS_SV_HEALTH) & UBLOX_NAV_SAT_FLAGS_SV_HEALTH_MASK;
+}
+
+static void
+ao_ublox_parse_nav_sat(void)
+{
+ uint8_t nsat;
+ nav_sat_nsat = 0;
+
+ ao_ublox_parse(&nav_sat, nav_sat_packet);
+ for (nsat = 0; nsat < nav_sat.num_svs && ao_ublox_len >= 12; nsat++) {
+ ao_ublox_parse(&nav_sat_real_sat, nav_sat_sat_packet);
+ if (nav_sat_nsat < NAV_SAT_MAX_SAT &&
+ ao_ublox_sat_health(&nav_sat_real_sat) == UBLOX_NAV_SAT_FLAGS_SV_HEALTH_HEALTHY &&
+ ao_ublox_sat_quality(&nav_sat_real_sat) >= UBLOX_NAV_SAT_FLAGS_QUALITY_ACQUIRED)
+ {
+ nav_sat_sat[nav_sat_nsat].svid = nav_sat_real_sat.svid;
+ nav_sat_sat[nav_sat_nsat].cno = nav_sat_real_sat.cno;
+ nav_sat_nsat++;
+ }
+ }
+#if AO_UBLOX_DEBUG
+ ao_gps_dbg(DBG_PROTO, "sat num_svs %d\n", nav_sat.num_svs);
+ for (nsat = 0; nsat < nav_sat.num_svs; nsat++) {
+ if (nsat < NAV_SAT_MAX_SAT) {
+ ao_gps_dbg(DBG_PROTO, "\t%d: svid %d cno %d\n",
+ nsat,
+ nav_sat_sat[nsat].svid,
+ nav_sat_sat[nsat].cno);
+ } else {
+ ao_gps_dbg(DBG_PROTO, "\t%d: skipped\n", nsat);
+ }
+ }
+#endif
+}
+
+#endif /* else AO_UBLOX_VERSION < 10 */
+