changeset 56:3535be2e3824

print-state: print assembled Galileo state Feed all Galileo related UBX-RXM-SFRBX messages into the Galileo state parsing code, and print the resulting ephemeris and time info. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Thu, 16 Jan 2020 18:28:59 -0500
parents af7b01ad6d05
children a259f88f6a11
files .hgignore CMakeLists.txt print-state.c
diffstat 3 files changed, 226 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Jan 16 18:25:07 2020 -0500
+++ b/.hgignore	Thu Jan 16 18:28:59 2020 -0500
@@ -13,3 +13,4 @@
 capture
 dump-ecef
 dump-ubx
+print-state
--- a/CMakeLists.txt	Thu Jan 16 18:25:07 2020 -0500
+++ b/CMakeLists.txt	Thu Jan 16 18:28:59 2020 -0500
@@ -98,3 +98,13 @@
 target_link_libraries(dump-ubx
 	ublox8
 )
+
+add_executable(print-state
+	dump-common.c
+	print-state.c
+)
+
+target_link_libraries(print-state
+	gnss
+	ublox8
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/print-state.c	Thu Jan 16 18:28:59 2020 -0500
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <time.h>
+#include <math.h>
+
+#include "dump-common.h"
+#include "gnss.h"
+#include "gnss-galileo.h"
+
+struct info {
+	enum gnssid gnssid;
+	unsigned svid;
+	unsigned channel;
+
+	union {
+		struct galileo_inav_page galileo;
+		struct {
+			int freqid;
+		} glonass;
+	};
+};
+
+static bool msg2info(const struct ubx_rxm_sfrbx *msg,
+		     const uint32_t *words, struct info *info)
+{
+	ASSERT3U(msg->version, ==, 0x02);
+
+	info->gnssid = msg->gnssid;
+	info->svid = msg->svid;
+	info->channel = msg->channel;
+
+	switch (info->gnssid) {
+		case GNSSID_GPS:
+			ASSERT3U(msg->num_words, ==, 10);
+			return true;
+		case GNSSID_SBAS:
+			ASSERT3U(msg->num_words, ==, 8);
+			return true;
+		case GNSSID_GALILEO:
+			return galileo_parse_inav_page(&info->galileo, words,
+						       msg->num_words);
+		case GNSSID_BEIDOU:
+			ASSERT3U(msg->num_words, ==, 10);
+			return true;
+		case GNSSID_IMES:
+		case GNSSID_QZSS:
+			panic("not yet implemented - gnssid %u", info->gnssid);
+		case GNSSID_GLONASS:
+			ASSERT3U(msg->num_words, ==, 4);
+
+			info->glonass.freqid = msg->freqid - 7;
+			return true;
+	}
+
+	fprintf(stderr, "Unknown gnssid %u in ubx message\n", msg->gnssid);
+
+	return false;
+}
+
+static void galileo_update_eph(struct galileo_state *state,
+			       const struct galileo_ephemeris *prev,
+			       const struct galileo_ephemeris *new)
+{
+	double disco_now;
+	double disco_t0;
+	double prev_eph_age;
+
+	if (!prev) {
+		/* nothing to do */
+		disco_now = NAN;
+		disco_t0 = NAN;
+		prev_eph_age = NAN;
+	} else if (!memcmp(prev, new, sizeof(struct galileo_ephemeris))) {
+		/* The ephemeris is exactly the same - we don't care. */
+		return;
+	} else {
+		/*
+		 * A different ephemeris - must have a newer t0.
+		 *
+		 * Note: It is tempting to assert that the iod has changed
+		 * (i.e., is not the same) but that would assume that we
+		 * received all messages.  It would fail if we just happened
+		 * to see two ephemeris updates in a row with the same iod
+		 * because we failed to receive all updates in between.
+		 */
+		ASSERT3U(prev->t0.gst, <, new->t0.gst);
+
+		prev_eph_age = new->t0.gst - prev->t0.gst;
+
+		/* calculate the discontinuity... */
+		struct ecef prev_ecef;
+		struct ecef new_ecef;
+		struct ecef diff;
+
+		/* ...at t0 for the new ephemeris */
+		galileo_eph_ecef(prev, new->t0.gst, &prev_ecef);
+		galileo_eph_ecef(new, new->t0.gst, &new_ecef);
+		ecef_subtract(&diff, &new_ecef, &prev_ecef);
+		disco_t0 = ecef_magnitude(&diff);
+
+		/* ...right now */
+		galileo_eph_ecef(prev, state->time.gst, &prev_ecef);
+		galileo_eph_ecef(new, state->time.gst, &new_ecef);
+		ecef_subtract(&diff, &new_ecef, &prev_ecef);
+		disco_now = ecef_magnitude(&diff);
+	}
+
+	printf("got %s eph for E%02u (prev %.1f hrs older): disco %f m @ t0, %f m now\n",
+	       prev ? "updated" : "new", new->sv, prev_eph_age / 3600,
+	       disco_t0, disco_now);
+	galileo_print_eph(new);
+}
+
+static void galileo_time(struct galileo_state *state,
+			 const unsigned int tx_sv,
+			 const struct galileo_state_time *now,
+			 const struct galileo_state_time *prev_sv_time)
+{
+	const time_t utc = now->gst + 935280000 - 13;
+	struct tm tm;
+
+	ASSERT3U(prev_sv_time->gst, <, now->gst);
+
+	gmtime_r(&utc, &tm);
+
+	printf("E%02u GST %u (WN %u TOW %u): %04u-%02u-%02u %02u:%02u:%02u "
+	       "(prev %svalid %u, missed %u)\n",
+	       tx_sv, now->gst, now->wn, now->tow,
+	       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
+	       tm.tm_min, tm.tm_sec,
+	       prev_sv_time->valid ? "" : "not ", prev_sv_time->gst,
+	       (now->gst - prev_sv_time->gst) / 30 - 1);
+}
+
+static const struct galileo_state_ops galileo_ops = {
+	.eph_update = galileo_update_eph,
+	.time = galileo_time,
+};
+
+void process_ubx_message(const struct ubx_header *header,
+			 const uint8_t *raw, size_t len,
+			 uint64_t tick)
+{
+	static struct galileo_state galileo_state;
+	static bool initialized;
+	struct ubx_rxm_sfrbx msg;
+	struct info info;
+	uint32_t *words;
+	int i;
+
+	if ((header->class != UBX_CLASS_RXM) || (header->id != 0x13))
+		return;
+
+	/* initialize galileo gnss state as needed */
+	if (!initialized) {
+		galileo_state_init(&galileo_state, &galileo_ops);
+		initialized = true;
+	}
+
+	/*
+	 * Parse UBX-RXM-SFRBX
+	 */
+
+	memcpy(&msg, raw, sizeof(struct ubx_rxm_sfrbx));
+
+	/* sanity check */
+	ASSERT3U(len, ==, sizeof(struct ubx_rxm_sfrbx) +
+		 sizeof(uint32_t) * msg.num_words);
+
+	/* allocate temp buffer */
+	words = alloca(msg.num_words * sizeof(uint32_t));
+
+	/* copy into temp buffer */
+	memcpy(words, &raw[offsetof(struct ubx_rxm_sfrbx, words)],
+	       msg.num_words * sizeof(uint32_t));
+
+	/* byte order words */
+	for (i = 0; i < msg.num_words; i++)
+		words[i] = le32_to_cpu(words[i]);
+
+	/* parse */
+	if (!msg2info(&msg, words, &info)) {
+		fprintf(stderr, "Failed to parse ubx message for gnss %u sv %u\n",
+			msg.gnssid, msg.svid);
+		return;
+	}
+
+	/*
+	 * Update state with parsed info
+	 */
+
+	if ((info.gnssid == GNSSID_GALILEO) &&
+	    !galileo_state_apply_page(&galileo_state, info.svid, &info.galileo))
+		printf("Galileo page application failure.\n");
+}