[PATCH 2/2] broadband-modem: implement support for the +CEMODE command

Aleksander Morgado aleksander at aleksander.es
Thu Dec 28 17:41:51 UTC 2017


The +CEMODE command is defined in 3GPP TS 27.007 (e.g. in section
10.1.28 in v11.0.0). This command allows querying or updating the
current UE mode, as well as checking the supported modes.

We implement support for loading the current mode and updating it. It
is assumed that the device does any additional operation needed by the
setting update, e.g. un-registering from CS when selecting an EPS-only
mode.
---
 src/mm-broadband-modem.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/mm-modem-helpers.c   | 45 +++++++++++++++++++++++++++++++++
 src/mm-modem-helpers.h   |  6 +++++
 3 files changed, 117 insertions(+)

diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index f82122b1..1e3bae69 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -3821,6 +3821,68 @@ modem_3gpp_load_subscription_state (MMIfaceModem3gpp *self,
     g_object_unref (task);
 }
 
+/*****************************************************************************/
+/* UE mode of operation for EPS loading (3GPP interface) */
+
+static MMModem3gppEpsUeModeOperation
+modem_3gpp_load_eps_ue_mode_operation_finish (MMIfaceModem3gpp  *self,
+                                              GAsyncResult      *res,
+                                              GError          **error)
+{
+    MMModem3gppEpsUeModeOperation  mode;
+    const gchar                   *result;
+
+    result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+    if (!result || !mm_3gpp_parse_cemode_query_response (result, &mode, error))
+        return MM_MODEM_3GPP_EPS_UE_MODE_OPERATION_UNKNOWN;
+
+    return mode;
+}
+
+static void
+modem_3gpp_load_eps_ue_mode_operation (MMIfaceModem3gpp    *self,
+                                       GAsyncReadyCallback  callback,
+                                       gpointer             user_data)
+{
+    mm_dbg ("loading UE mode of operation for EPS...");
+    mm_base_modem_at_command (MM_BASE_MODEM (self),
+                              "+CEMODE?",
+                              3,
+                              FALSE,
+                              callback,
+                              user_data);
+}
+
+/*****************************************************************************/
+/* UE mode of operation for EPS settin (3GPP interface) */
+
+static gboolean
+modem_3gpp_set_eps_ue_mode_operation_finish (MMIfaceModem3gpp  *self,
+                                             GAsyncResult      *res,
+                                             GError          **error)
+{
+    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+}
+
+static void
+modem_3gpp_set_eps_ue_mode_operation (MMIfaceModem3gpp              *self,
+                                      MMModem3gppEpsUeModeOperation  mode,
+                                      GAsyncReadyCallback            callback,
+                                      gpointer                       user_data)
+{
+    gchar *cmd;
+
+    mm_dbg ("updating UE mode of operation for EPS...");
+    cmd = mm_3gpp_build_cemode_set_request (mode);
+    mm_base_modem_at_command (MM_BASE_MODEM (self),
+                              cmd,
+                              3,
+                              FALSE,
+                              callback,
+                              user_data);
+    g_free (cmd);
+}
+
 /*****************************************************************************/
 /* Unsolicited registration messages handling (3GPP interface) */
 
@@ -10922,6 +10984,8 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
     iface->load_imei_finish = modem_3gpp_load_imei_finish;
     iface->load_enabled_facility_locks = modem_3gpp_load_enabled_facility_locks;
     iface->load_enabled_facility_locks_finish = modem_3gpp_load_enabled_facility_locks_finish;
+    iface->load_eps_ue_mode_operation = modem_3gpp_load_eps_ue_mode_operation;
+    iface->load_eps_ue_mode_operation_finish = modem_3gpp_load_eps_ue_mode_operation_finish;
 
     /* Enabling steps */
     iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events;
@@ -10956,6 +11020,8 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
     iface->register_in_network_finish = modem_3gpp_register_in_network_finish;
     iface->scan_networks = modem_3gpp_scan_networks;
     iface->scan_networks_finish = modem_3gpp_scan_networks_finish;
+    iface->set_eps_ue_mode_operation = modem_3gpp_set_eps_ue_mode_operation;
+    iface->set_eps_ue_mode_operation_finish = modem_3gpp_set_eps_ue_mode_operation_finish;
 }
 
 static void
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index b2806dfa..9ba8c750 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -2485,6 +2485,51 @@ mm_3gpp_parse_cfun_query_generic_response (const gchar        *response,
     }
 }
 
+static MMModem3gppEpsUeModeOperation cemode_values[] = {
+    [0] = MM_MODEM_3GPP_EPS_UE_MODE_OPERATION_PS_2,
+    [1] = MM_MODEM_3GPP_EPS_UE_MODE_OPERATION_CSPS_1,
+    [2] = MM_MODEM_3GPP_EPS_UE_MODE_OPERATION_CSPS_2,
+    [3] = MM_MODEM_3GPP_EPS_UE_MODE_OPERATION_PS_1,
+};
+
+gchar *
+mm_3gpp_build_cemode_set_request (MMModem3gppEpsUeModeOperation mode)
+{
+    guint i;
+
+    g_return_val_if_fail (mode != MM_MODEM_3GPP_EPS_UE_MODE_OPERATION_UNKNOWN, NULL);
+
+    for (i = 0; i < G_N_ELEMENTS (cemode_values); i++) {
+        if (mode == cemode_values[i])
+            return g_strdup_printf ("+CEMODE=%u", i);
+    }
+
+    g_assert_not_reached ();
+    return NULL;
+}
+
+gboolean
+mm_3gpp_parse_cemode_query_response (const gchar                    *response,
+                                     MMModem3gppEpsUeModeOperation  *out_mode,
+                                     GError                        **error)
+{
+    guint value = 0;
+
+    response = mm_strip_tag (response, "+CEMODE:");
+    if (mm_get_uint_from_str (response, &value) && value < G_N_ELEMENTS (cemode_values)) {
+        if (out_mode)
+            *out_mode = cemode_values[value];
+        return TRUE;
+    }
+
+    g_set_error (error,
+                 MM_CORE_ERROR,
+                 MM_CORE_ERROR_FAILED,
+                 "Couldn't parse UE mode of operation: '%s' (value %u)",
+                 response, value);
+    return FALSE;
+}
+
 /*************************************************************************/
 
 static MMSmsStorage
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index 524f05ae..d14eb17b 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -328,6 +328,12 @@ gboolean mm_3gpp_cesq_response_to_signal_info (const gchar  *response,
                                                MMSignal    **out_lte,
                                                GError      **error);
 
+/* CEMODE? response parser */
+gchar    *mm_3gpp_build_cemode_set_request    (MMModem3gppEpsUeModeOperation   mode);
+gboolean  mm_3gpp_parse_cemode_query_response (const gchar                    *response,
+                                               MMModem3gppEpsUeModeOperation  *out_mode,
+                                               GError                        **error);
+
 /* Additional 3GPP-specific helpers */
 
 MMModem3gppFacility mm_3gpp_acronym_to_facility (const gchar *str);
-- 
2.15.0



More information about the ModemManager-devel mailing list