From f7da97989bcd85ec2c00d3621c47671deed17272 Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Sun, 11 Jan 2026 00:17:53 +0300 Subject: [PATCH] location-gps-nmea: add complete sequence to traces at once Currently sequence messages are added to traces as they are received. Therefore content of traces depends at the time, when request is issued and data is reported. Sometimes not all sequence traces are reported, because only first record was received yet and it overwrote previous full sequence trace. For example, ``` $GPGSV,3,1,12,01,35,282,,02,68,264,,03,02,243,,08,35,206,,1*68 $GPGSV,3,2,12,10,46,074,,14,16,312,,17,,,,22,16,327,,1*53 $GPGSV,3,3,12,23,07,068,,24,15,030,,27,14,181,,32,51,120,,1*60 $GLGSV,2,1,08,82,25,135,,76,11,029,,75,21,334,,69,11,201,,1*7A ``` one GSV sentence is missing and second later full sequence is reported ``` $GPGSV,3,1,12,01,35,282,,02,68,264,,03,02,243,,08,35,206,,1*68 $GPGSV,3,2,12,10,46,074,,14,16,312,,17,,,,22,16,327,,1*53 $GPGSV,3,3,12,23,07,068,,24,15,030,,27,14,181,,32,51,120,,1*60 $GLGSV,2,1,08,82,25,135,,76,11,029,,75,21,334,,69,11,201,,1*7A $GLGSV,2,2,08,84,40,306,,83,79,161,,67,56,056,,68,58,177,,1*7D ``` Therefore client software reports different number of visible satellites. Usually sequence sentences are reported consequently in NMEA stream. Let's cache and join sequence sentences until new trace type is received. In that case full sequence always overrides previous full sequence. Signed-off-by: Andrey Skvortsov --- libmm-glib/mm-location-gps-nmea.c | 74 +++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/libmm-glib/mm-location-gps-nmea.c b/libmm-glib/mm-location-gps-nmea.c index ab693fa9..2cad8dae 100644 --- a/libmm-glib/mm-location-gps-nmea.c +++ b/libmm-glib/mm-location-gps-nmea.c @@ -45,16 +45,20 @@ G_DEFINE_TYPE (MMLocationGpsNmea, mm_location_gps_nmea, G_TYPE_OBJECT) struct _MMLocationGpsNmeaPrivate { GHashTable *traces; - GRegex *sequence_regex; + gchar *sequence_last_trace; + gchar *sequence_last_trace_type; + GRegex *sequence_regex; }; /*****************************************************************************/ static gboolean -check_append_or_replace (MMLocationGpsNmea *self, - const gchar *trace) +is_sequence_trace_type (MMLocationGpsNmea *self, + const gchar *trace, + gboolean *first) { g_autoptr(GMatchInfo) match_info = NULL; + guint index; if (G_UNLIKELY (!self->priv->sequence_regex)) self->priv->sequence_regex = g_regex_new ("\\$..(?:ALM|GSV|RTE|SFI),(\\d),(\\d).*", @@ -62,15 +66,13 @@ check_append_or_replace (MMLocationGpsNmea *self, 0, NULL); + *first = FALSE; if (g_regex_match (self->priv->sequence_regex, trace, 0, &match_info)) { - guint index; - - /* If we don't have the first element of a sequence, append */ - if (mm_get_uint_from_match_info (match_info, 2, &index) && index != 1) + if (mm_get_uint_from_match_info (match_info, 2, &index)) { + *first = (index == 1); return TRUE; + } } - - /* By default, replace */ return FALSE; } @@ -81,6 +83,10 @@ location_gps_nmea_take_trace (MMLocationGpsNmea *self, gchar *i; g_autofree gchar *trace_type = NULL; g_autofree gchar *trace = _trace; + g_autofree gchar *sequence = NULL; + gboolean first; + gboolean sequence_trace; + i = strchr (trace, ','); if (!i || i == trace) @@ -93,14 +99,38 @@ location_gps_nmea_take_trace (MMLocationGpsNmea *self, /* Some traces are part of a SEQUENCE; so we need to decide whether we * completely replace the previous trace, or we append the new one to * the already existing list */ - if (check_append_or_replace (self, trace)) { + sequence_trace = is_sequence_trace_type (self, trace, &first); + + /* Save previous sequence trace, if + * new trace type is different or this is the first sequence trace */ + if (self->priv->sequence_last_trace_type && + self->priv->sequence_last_trace && + (g_strcmp0 (self->priv->sequence_last_trace_type, trace_type) || + (sequence_trace && first))) { + g_hash_table_replace (self->priv->traces, + g_steal_pointer (&self->priv->sequence_last_trace_type), + g_steal_pointer (&self->priv->sequence_last_trace)); + } + + if (!sequence_trace) { + g_hash_table_replace (self->priv->traces, + g_steal_pointer (&trace_type), + g_steal_pointer (&trace)); + return TRUE; + } + + /* Process the trace as part of a sequence. */ + if (first) { + /* Record first record in the sequence */ + sequence = g_steal_pointer (&trace); + } else { /* Append */ - const gchar *previous; + const gchar *previous = self->priv->sequence_last_trace; + + if (!previous) + previous = g_hash_table_lookup (self->priv->traces, trace_type); - previous = g_hash_table_lookup (self->priv->traces, trace_type); if (previous) { - g_autofree gchar *sequence = NULL; - /* Skip the trace if we already have it there */ if (strstr (previous, trace)) return TRUE; @@ -109,14 +139,18 @@ location_gps_nmea_take_trace (MMLocationGpsNmea *self, previous, g_str_has_suffix (previous, "\r\n") ? "" : "\r\n", trace); - g_free (trace); - trace = g_steal_pointer (&sequence); + } else { + /* No previous records, record first record in the sequence */ + sequence = g_steal_pointer (&trace); } } - g_hash_table_replace (self->priv->traces, - g_steal_pointer (&trace_type), - g_steal_pointer (&trace)); + g_clear_pointer (&self->priv->sequence_last_trace, g_free); + self->priv->sequence_last_trace = g_steal_pointer (&sequence); + + g_clear_pointer (&self->priv->sequence_last_trace_type, g_free); + self->priv->sequence_last_trace_type = g_steal_pointer (&trace_type); + return TRUE; } @@ -287,6 +321,8 @@ finalize (GObject *object) g_hash_table_destroy (self->priv->traces); if (self->priv->sequence_regex) g_regex_unref (self->priv->sequence_regex); + g_free (self->priv->sequence_last_trace); + g_free (self->priv->sequence_last_trace_type); G_OBJECT_CLASS (mm_location_gps_nmea_parent_class)->finalize (object); }