From 0787d04a3993a4e0af5dc89f6cb4a54ea5a88ba1 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 26 Jan 2025 21:32:22 +0100 Subject: [PATCH] intel: XMM7360: Better NMEA packets parsing XMM7360 modem NMEA trace packets are wrapped to look like AT command responses (with "OK" at the end). This wrapping causes problems if a genuine AT command was just sent and ModemManager is expecting a similarly formatted response to it. In such case the NMEA trace packet is taken as the response to the AT command, which usually causes the command to fail due to response parsing failure. Fix this by implementing a custom NMEA trace packets parser for these modems. Signed-off-by: Maciej S. Szmigiero --- .../intel/mm-broadband-modem-xmm7360.c | 69 +++++++++++++++++++ src/plugins/xmm/mm-shared-xmm.c | 35 +++++++--- src/plugins/xmm/mm-shared-xmm.h | 3 + 3 files changed, 98 insertions(+), 9 deletions(-) diff --git a/src/plugins/intel/mm-broadband-modem-xmm7360.c b/src/plugins/intel/mm-broadband-modem-xmm7360.c index f949c253..a57d47d3 100644 --- a/src/plugins/intel/mm-broadband-modem-xmm7360.c +++ b/src/plugins/intel/mm-broadband-modem-xmm7360.c @@ -38,20 +38,24 @@ #include "mm-port-scheduler-rr.h" #include "mm-port-serial-xmmrpc-xmm7360.h" #include "mm-bearer-xmm7360.h" +#include "mm-shared-xmm.h" #include "mm-sim-xmm7360.h" static void iface_modem_init (MMIfaceModemInterface *iface); static void iface_modem_3gpp_init (MMIfaceModem3gppInterface *iface); +static void iface_shared_xmm_init (MMSharedXmmInterface *iface); static MMIfaceModemInterface *iface_modem_parent; G_DEFINE_TYPE_EXTENDED (MMBroadbandModemXmm7360, mm_broadband_modem_xmm7360, MM_TYPE_BROADBAND_MODEM_XMM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_XMM, iface_shared_xmm_init) ) struct _MMBroadbandModemXmm7360Private { MMUnlockRetries *unlock_retries; + GRegex *nmea_regex_full, *nmea_regex_trace; }; /*****************************************************************************/ @@ -1158,6 +1162,56 @@ initialization_started (MMBroadbandModem *modem, task); } +/*****************************************************************************/ + +static void +nmea_received (MMPortSerialAt *port, + GMatchInfo *info_full, + MMBroadbandModemXmm7360 *self) +{ + g_autofree gchar *trace_full = NULL; + g_autoptr(GMatchInfo) info = NULL; + + trace_full = g_match_info_fetch (info_full, 1); + if (!trace_full) { + return; + } + + g_regex_match (self->priv->nmea_regex_trace, trace_full, 0, &info); + while (g_match_info_matches (info)) { + g_autofree gchar *trace = NULL; + + trace = g_match_info_fetch (info, 1); + if (!trace) { + mm_obj_err (self, "fetching NMEA trace failed"); + } else { + mm_iface_modem_location_gps_update (MM_IFACE_MODEM_LOCATION (self), trace); + } + + g_match_info_next (info, NULL); + } +} + +static void +nmea_parser_register (MMSharedXmm *self_shared_xmm, MMPortSerialAt *gps_port, + gboolean is_register) +{ + MMBroadbandModemXmm7360 *self = MM_BROADBAND_MODEM_XMM7360 (self_shared_xmm); + + if (is_register) { + mm_port_serial_at_add_unsolicited_msg_handler (gps_port, + self->priv->nmea_regex_full, + (MMPortSerialAtUnsolicitedMsgFn)nmea_received, + self, + NULL); + } else { + mm_port_serial_at_add_unsolicited_msg_handler (gps_port, + self->priv->nmea_regex_full, + NULL, NULL, NULL); + } +} + + /*****************************************************************************/ MMBroadbandModemXmm7360 * @@ -1187,6 +1241,13 @@ mm_broadband_modem_xmm7360_init (MMBroadbandModemXmm7360 *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_BROADBAND_MODEM_XMM7360, MMBroadbandModemXmm7360Private); + + self->priv->nmea_regex_full = g_regex_new ("(?:\\r\\n){2}((?:\\$G.*?\\r\\n)+)(?:\\r\\n){2}OK(?:\\r\\n)", + G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, + NULL); + self->priv->nmea_regex_trace = g_regex_new ("(\\$G.*?)\\r\\n", + G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, + NULL); } static void @@ -1194,6 +1255,8 @@ dispose (GObject *object) { MMBroadbandModemXmm7360 *self = MM_BROADBAND_MODEM_XMM7360 (object); + g_clear_pointer (&self->priv->nmea_regex_trace, g_regex_unref); + g_clear_pointer (&self->priv->nmea_regex_full, g_regex_unref); g_clear_object (&self->priv->unlock_retries); G_OBJECT_CLASS (mm_broadband_modem_xmm7360_parent_class)->dispose (object); @@ -1219,6 +1282,12 @@ iface_modem_3gpp_init (MMIfaceModem3gppInterface *iface) iface->set_initial_eps_bearer_settings_finish = modem_3gpp_set_initial_eps_bearer_settings_finish; } +static void +iface_shared_xmm_init (MMSharedXmmInterface *iface) +{ + iface->nmea_parser_register = nmea_parser_register; +} + static void mm_broadband_modem_xmm7360_class_init (MMBroadbandModemXmm7360Class *klass) { diff --git a/src/plugins/xmm/mm-shared-xmm.c b/src/plugins/xmm/mm-shared-xmm.c index 0142f404..208a994b 100644 --- a/src/plugins/xmm/mm-shared-xmm.c +++ b/src/plugins/xmm/mm-shared-xmm.c @@ -1003,6 +1003,25 @@ nmea_received (MMPortSerialAt *port, g_free (trace); } +static void +nmea_parser_register (MMSharedXmm *self, MMPortSerialAt *gps_port, + gboolean is_register) +{ + Private *priv = get_private (self); + + if (is_register) { + mm_port_serial_at_add_unsolicited_msg_handler (gps_port, + priv->nmea_regex, + (MMPortSerialAtUnsolicitedMsgFn)nmea_received, + self, + NULL); + } else { + mm_port_serial_at_add_unsolicited_msg_handler (gps_port, + priv->nmea_regex, + NULL, NULL, NULL); + } +} + /*****************************************************************************/ /* GPS engine state selection */ @@ -1053,11 +1072,10 @@ xlcslsr_ready (MMBaseModem *self, mm_obj_dbg (self, "GPS engine started"); g_assert (priv->gps_port); - mm_port_serial_at_add_unsolicited_msg_handler (priv->gps_port, - priv->nmea_regex, - (MMPortSerialAtUnsolicitedMsgFn)nmea_received, - self, - NULL); + MM_SHARED_XMM_GET_IFACE (self)->nmea_parser_register (MM_SHARED_XMM (self), + priv->gps_port, + TRUE); + priv->gps_engine_state = ctx->state; /* @@ -1188,10 +1206,8 @@ gps_engine_stopped (GTask *task) ctx = g_task_get_task_data (task); g_assert (priv->gps_port); - mm_port_serial_at_add_unsolicited_msg_handler ( - priv->gps_port, - priv->nmea_regex, - NULL, NULL, NULL); + MM_SHARED_XMM_GET_IFACE (self)->nmea_parser_register (self, priv->gps_port, + FALSE); if (priv->gps_port_open) { mm_port_serial_close (MM_PORT_SERIAL (priv->gps_port)); @@ -1737,4 +1753,5 @@ mm_shared_xmm_setup_ports (MMBroadbandModem *self) static void mm_shared_xmm_default_init (MMSharedXmmInterface *iface) { + iface->nmea_parser_register = nmea_parser_register; } diff --git a/src/plugins/xmm/mm-shared-xmm.h b/src/plugins/xmm/mm-shared-xmm.h index e78467e7..c9d09e37 100644 --- a/src/plugins/xmm/mm-shared-xmm.h +++ b/src/plugins/xmm/mm-shared-xmm.h @@ -38,6 +38,9 @@ struct _MMSharedXmmInterface { /* Peek location interface of the parent class of the object */ MMIfaceModemLocationInterface * (* peek_parent_location_interface) (MMSharedXmm *self); + + void (* nmea_parser_register) (MMSharedXmm *self, MMPortSerialAt *gps_port, + gboolean is_register); }; /* Shared XMM device setup */