From 4c319181e221a0be40257498f4093dcef62a97f6 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 16 Feb 2025 18:14:41 +0100 Subject: [PATCH] shared-xmm: Properly stop GPS if it was running on modem init With the recent addition of serial port scheduler it often happens that NMEA traces are mistaken for command responses at init time if GPS was left enabled in the modem. For this reason, the proper NMEA packet parser needs to be enabled early at modem init before the code ensures that GPS is stopped (if it is not supposed to be running of course). Since this modem disables GPS asynchronously with processing of the +XLSRSTOP AT command the full GPS stop machinery has be used to reliably achieve that GPS engine stop. It's also important to flush the existing serial port data after attaching the NMEA packet parser but before issuing that stop AT command, otherwise command processor for the stop command can also be confused by the existing queued data. Signed-off-by: Maciej S. Szmigiero --- src/plugins/xmm/mm-broadband-modem-xmm.c | 4 + src/plugins/xmm/mm-shared-xmm.c | 146 ++++++++++++++++++++--- src/plugins/xmm/mm-shared-xmm.h | 6 + 3 files changed, 141 insertions(+), 15 deletions(-) diff --git a/src/plugins/xmm/mm-broadband-modem-xmm.c b/src/plugins/xmm/mm-broadband-modem-xmm.c index 3364c639..7cc26dd8 100644 --- a/src/plugins/xmm/mm-broadband-modem-xmm.c +++ b/src/plugins/xmm/mm-broadband-modem-xmm.c @@ -149,4 +149,8 @@ mm_broadband_modem_xmm_class_init (MMBroadbandModemXmmClass *klass) MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass); broadband_modem_class->setup_ports = mm_shared_xmm_setup_ports; + broadband_modem_class->initialization_started = + mm_shared_xmm_initialization_started; + broadband_modem_class->initialization_started_finish = + mm_shared_xmm_initialization_started_finish; } diff --git a/src/plugins/xmm/mm-shared-xmm.c b/src/plugins/xmm/mm-shared-xmm.c index 208a994b..54f36a68 100644 --- a/src/plugins/xmm/mm-shared-xmm.c +++ b/src/plugins/xmm/mm-shared-xmm.c @@ -44,6 +44,7 @@ typedef enum { GPS_ENGINE_STATE_STANDALONE, GPS_ENGINE_STATE_AGPS_MSA, GPS_ENGINE_STATE_AGPS_MSB, + GPS_ENGINE_STATE_UNKNOWN, } GpsEngineState; typedef struct { @@ -105,7 +106,7 @@ get_private (MMSharedXmm *self) priv = g_object_get_qdata (G_OBJECT (self), private_quark); if (!priv) { priv = g_slice_new0 (Private); - priv->gps_engine_state = GPS_ENGINE_STATE_OFF; + priv->gps_engine_state = GPS_ENGINE_STATE_UNKNOWN; /* Setup regex for URCs */ priv->xbipi_regex = g_regex_new ("\\r\\n\\+XBIPI:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); @@ -1131,6 +1132,7 @@ gps_engine_start (GTask *task) pos_mode = 2; break; case GPS_ENGINE_STATE_OFF: + case GPS_ENGINE_STATE_UNKNOWN: default: g_assert_not_reached (); break; @@ -1357,6 +1359,8 @@ gps_engine_state_select (MMSharedXmm *self, GTask *task; Private *priv; + g_assert (state != GPS_ENGINE_STATE_UNKNOWN); + priv = get_private (self); task = g_task_new (self, NULL, callback, user_data); @@ -1706,7 +1710,6 @@ mm_shared_xmm_setup_ports (MMBroadbandModem *self) { Private *priv; MMPortSerialAt *ports[2]; - g_autoptr(MMPortSerialAt) gps_port = NULL; guint i; mm_obj_dbg (self, "setting up ports in XMM modem..."); @@ -1729,23 +1732,136 @@ mm_shared_xmm_setup_ports (MMBroadbandModem *self) priv->xbipi_regex, NULL, NULL, NULL); } +} + +gpointer +mm_shared_xmm_initialization_started_finish (MMBroadbandModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +initialization_started_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + MMBroadbandModem *self = MM_BROADBAND_MODEM (source_object); + g_autoptr(GTask) task = user_data; + Private *priv = get_private (MM_SHARED_XMM (self)); + g_autoptr(GError) error = NULL; + gpointer ret; + + g_assert (priv->broadband_modem_class_parent); + g_assert (priv->broadband_modem_class_parent->initialization_started_finish); + + ret = priv->broadband_modem_class_parent->initialization_started_finish (self, + res, + &error); + if (!ret) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_pointer (task, ret, NULL); +} + +static void +gps_init_stop_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + MMSharedXmm *self_xmm = MM_SHARED_XMM (source_object); + Private *priv = get_private (self_xmm); + MMBroadbandModem *self = MM_BROADBAND_MODEM (source_object); + g_autoptr(GTask) task = user_data; + g_autoptr(GError) error = NULL; + + if (!gps_engine_state_select_finish (self_xmm, res, &error)) { + mm_obj_dbg (self, "GPS stop at init failed: %s", + error ? error->message : "(unknown"); + + /* assume GPS simply wasn't on in the modem in the first place */ + if (priv->gps_port) { + MM_SHARED_XMM_GET_IFACE (self)->nmea_parser_register (self_xmm, + priv->gps_port, + FALSE); + + if (priv->gps_port_open) { + mm_port_serial_close (MM_PORT_SERIAL (priv->gps_port)); + priv->gps_port_open = FALSE; + } + + g_clear_object (&priv->gps_port); + } + + priv->gps_engine_state = GPS_ENGINE_STATE_OFF; + } + + g_assert (priv->broadband_modem_class_parent); + g_assert (priv->broadband_modem_class_parent->initialization_started); + + priv->broadband_modem_class_parent->initialization_started (self, + initialization_started_done, + g_steal_pointer (&task)); +} + +void +mm_shared_xmm_initialization_started (MMBroadbandModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMSharedXmm *self_xmm = MM_SHARED_XMM (self); + Private *priv = get_private (self_xmm); + g_autoptr(GTask) task = NULL; + g_autoptr(MMPortSerialAt) gps_port = NULL; + + task = g_task_new (self, NULL, callback, user_data); /* Setup the GPS port and stop GPS if it is not supposed to be running */ - gps_port = shared_xmm_get_gps_control_port (MM_SHARED_XMM (self), NULL); - if (gps_port && priv->gps_engine_state == GPS_ENGINE_STATE_OFF) { - /* After running AT+XLSRSTOP we may get an unsolicited response - * reporting its status, we just ignore it. */ - mm_port_serial_at_add_unsolicited_msg_handler ( - gps_port, - priv->xlsrstop_regex, - NULL, NULL, NULL); + gps_port = shared_xmm_get_gps_control_port (self_xmm, NULL); + if (gps_port && priv->gps_engine_state == GPS_ENGINE_STATE_UNKNOWN) { + g_autoptr(GError) gps_port_open_error = NULL; + g_autoptr(GError) gps_port_flush_error = NULL; - /* make sure GPS is stopped in case it was left enabled */ - mm_base_modem_at_command_full (MM_BASE_MODEM (self), - MM_IFACE_PORT_AT (gps_port), - "+XLSRSTOP", - 3, FALSE, FALSE, NULL, NULL, NULL); + g_assert (!priv->gps_port); + priv->gps_port = g_steal_pointer (&gps_port); + + MM_SHARED_XMM_GET_IFACE (self)->nmea_parser_register (self_xmm, + priv->gps_port, + TRUE); + + g_assert (!priv->gps_port_open); + if (!mm_port_serial_open (MM_PORT_SERIAL (priv->gps_port), + &gps_port_open_error)) { + mm_obj_warn (self, "unexpected init GPS port open error: %s", + gps_port_open_error->message); + } else { + priv->gps_port_open = TRUE; + } + + mm_obj_dbg (self, + "flushing pending data in GPS port"); + + if (!mm_port_serial_flush (MM_PORT_SERIAL (priv->gps_port), + MM_PORT_SERIAL_FLUSH_RX, + &gps_port_flush_error)) { + mm_obj_warn (self, "unexpected init GPS port flush error: %s", + gps_port_flush_error->message); + } + + gps_engine_state_select (self_xmm, GPS_ENGINE_STATE_OFF, + gps_init_stop_done, g_steal_pointer (&task)); + return; } + + g_assert (priv->broadband_modem_class_parent); + g_assert (priv->broadband_modem_class_parent->initialization_started); + + priv->broadband_modem_class_parent->initialization_started (self, + initialization_started_done, + g_steal_pointer (&task)); } /*****************************************************************************/ diff --git a/src/plugins/xmm/mm-shared-xmm.h b/src/plugins/xmm/mm-shared-xmm.h index c9d09e37..1896b8f5 100644 --- a/src/plugins/xmm/mm-shared-xmm.h +++ b/src/plugins/xmm/mm-shared-xmm.h @@ -46,6 +46,12 @@ struct _MMSharedXmmInterface { /* Shared XMM device setup */ void mm_shared_xmm_setup_ports (MMBroadbandModem *self); +void mm_shared_xmm_initialization_started (MMBroadbandModem *self, + GAsyncReadyCallback callback, + gpointer user_data); +gpointer mm_shared_xmm_initialization_started_finish (MMBroadbandModem *self, + GAsyncResult *res, + GError **error); /* Shared XMM device management support */