If the modem supports ^SIND psinfo reporting, we enable the URC and
flag the access technology polling unsupported, so that we only update
access technology via the +CIEV URCs.

E.g.:

    (ttyACM1): --> 'AT^SIND="psinfo",1<CR>'
    (ttyACM1): <-- '<CR><LF>^SIND: psinfo,1,10<CR><LF><CR><LF>OK<CR><LF>'
    Reporting initial access technologies...
    Modem /org/freedesktop/ModemManager1/Modem/0: access technology changed 
(unknown -> hsdpa, hsupa)
    ...
    (ttyACM1): <-- '<CR><LF>+CIEV: psinfo,4<CR><LF>'
    Modem /org/freedesktop/ModemManager1/Modem/0: access technology changed 
(hsdpa, hsupa -> edge)
    ...
---
 plugins/cinterion/mm-broadband-modem-cinterion.c | 439 ++++++++++++++++-------
 plugins/cinterion/mm-modem-helpers-cinterion.c   |  33 ++
 plugins/cinterion/mm-modem-helpers-cinterion.h   |   5 +
 3 files changed, 339 insertions(+), 138 deletions(-)

diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c 
b/plugins/cinterion/mm-broadband-modem-cinterion.c
index 735f15bc..06f4357f 100644
--- a/plugins/cinterion/mm-broadband-modem-cinterion.c
+++ b/plugins/cinterion/mm-broadband-modem-cinterion.c
@@ -61,7 +61,7 @@ typedef enum {
 } FeatureSupport;
 
 struct _MMBroadbandModemCinterionPrivate {
-    /* Flag to know if we should try AT^SIND or not to get psinfo */
+    /* Flag to know if AT^SIND indications are supported */
     gboolean sind_psinfo;
 
     /* Command to go into sleep mode */
@@ -80,6 +80,9 @@ struct _MMBroadbandModemCinterionPrivate {
     GArray *cnmi_supported_ds;
     GArray *cnmi_supported_bfr;
 
+    /* +CIEV 'psinfo' indications */
+    GRegex *ciev_psinfo_regex;
+
     /*Flags for SWWAN support*/
     FeatureSupport swwan_support;
 };
@@ -572,185 +575,329 @@ modem_power_off (MMIfaceModem *self,
 }
 
 /*****************************************************************************/
-/* ACCESS TECHNOLOGIES */
+/* Access technologies polling */
 
 static gboolean
-load_access_technologies_finish (MMIfaceModem *self,
-                                 GAsyncResult *res,
-                                 MMModemAccessTechnology *access_technologies,
-                                 guint *mask,
-                                 GError **error)
+load_access_technologies_finish (MMIfaceModem             *self,
+                                 GAsyncResult             *res,
+                                 MMModemAccessTechnology  *access_technologies,
+                                 guint                    *mask,
+                                 GError                  **error)
 {
-    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), 
error))
+    gssize val;
+
+    if ((val = g_task_propagate_int (G_TASK (res), error)) < 0)
         return FALSE;
 
-    *access_technologies = (MMModemAccessTechnology) GPOINTER_TO_UINT (
-        g_simple_async_result_get_op_res_gpointer (
-            G_SIMPLE_ASYNC_RESULT (res)));
+    *access_technologies = (MMModemAccessTechnology) val;
     *mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY;
     return TRUE;
 }
 
 static void
-smong_query_ready (MMBroadbandModemCinterion *self,
+smong_query_ready (MMBaseModem  *self,
                    GAsyncResult *res,
-                   GSimpleAsyncResult *operation_result)
+                   GTask        *task)
 {
     const gchar             *response;
     GError                  *error = NULL;
     MMModemAccessTechnology  access_tech;
 
-    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, 
&error);
-    if (!response) {
-        /* Let the error be critical. */
-        g_simple_async_result_take_error (operation_result, error);
-    } else if (!mm_cinterion_parse_smong_response (response, &access_tech, 
&error)) {
-        /* We'll reset here the flag to try to use SIND/psinfo the next time */
-        self->priv->sind_psinfo = TRUE;
-        g_simple_async_result_take_error (operation_result, error);
-    } else {
-        /* We'll default to use SMONG then */
-        self->priv->sind_psinfo = FALSE;
-        g_simple_async_result_set_op_res_gpointer (operation_result, 
GUINT_TO_POINTER (access_tech), NULL);
+    response = mm_base_modem_at_command_finish (self, res, &error);
+    if (!response || !mm_cinterion_parse_smong_response (response, 
&access_tech, &error))
+        g_task_return_error (task, error);
+    else
+        g_task_return_int (task, (gssize) access_tech);
+    g_object_unref (task);
+}
+
+static void
+load_access_technologies (MMIfaceModem        *_self,
+                          GAsyncReadyCallback  callback,
+                          gpointer             user_data)
+{
+    MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
+    GTask                     *task;
+
+    task = g_task_new (self, NULL, callback, user_data);
+
+    /* Abort access technology polling if ^SIND psinfo URCs are enabled */
+    if (self->priv->sind_psinfo) {
+        g_task_return_new_error (task, MM_CORE_ERROR, 
MM_CORE_ERROR_UNSUPPORTED, "No need to poll access technologies");
+        g_object_unref (task);
+        return;
     }
 
-    g_simple_async_result_complete (operation_result);
-    g_object_unref (operation_result);
+    mm_base_modem_at_command (
+        MM_BASE_MODEM (self),
+        "^SMONG",
+        3,
+        FALSE,
+        (GAsyncReadyCallback)smong_query_ready,
+        task);
 }
 
-static MMModemAccessTechnology
-get_access_technology_from_psinfo (const gchar *psinfo,
-                                   GError **error)
-{
-    guint psinfoval;
-
-    if (mm_get_uint_from_str (psinfo, &psinfoval)) {
-        switch (psinfoval) {
-        case 0:
-            return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
-        case 1:
-        case 2:
-            return MM_MODEM_ACCESS_TECHNOLOGY_GPRS;
-        case 3:
-        case 4:
-            return MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
-        case 5:
-        case 6:
-            return MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
-        case 7:
-        case 8:
-            return MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
-        case 9:
-        case 10:
-            return (MM_MODEM_ACCESS_TECHNOLOGY_HSDPA | 
MM_MODEM_ACCESS_TECHNOLOGY_HSUPA);
-        case 16:
-        case 17:
-            return MM_MODEM_ACCESS_TECHNOLOGY_LTE;
-        default:
-            mm_dbg ("Unable to identify access technology in case:%i", 
psinfoval);
-            break;
-        }
+/*****************************************************************************/
+/* Disable unsolicited events (3GPP interface) */
+
+static gboolean
+modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp  *self,
+                                              GAsyncResult      *res,
+                                              GError           **error)
+{
+    return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self,
+                                         GAsyncResult     *res,
+                                         GTask            *task)
+{
+    GError *error = NULL;
+
+    if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, 
res, &error)) {
+        mm_warn ("Couldn't disable parent 3GPP unsolicited events: %s", 
error->message);
+        g_error_free (error);
     }
-    else
-        mm_err ("FAILED get_access_technology_from_psinfo-int");
 
-    g_set_error (error,
-                 MM_CORE_ERROR,
-                 MM_CORE_ERROR_INVALID_ARGS,
-                 "Couldn't get network capabilities, "
-                 "invalid psinfo value: '%s'",
-                 psinfo);
-    return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+    g_task_return_boolean (task, TRUE);
+    g_object_unref (task);
 }
 
 static void
-sind_query_ready (MMBroadbandModemCinterion *self,
-                  GAsyncResult *res,
-                  GSimpleAsyncResult *operation_result)
+sind_psinfo_disable_ready (MMBaseModem  *self,
+                           GAsyncResult *res,
+                           GTask        *task)
 {
-    const gchar *response;
     GError *error = NULL;
-    GMatchInfo *match_info = NULL;
-    GRegex *regex;
 
-    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, 
&error);
-    if (!response) {
-        /* Let the error be critical. */
-        g_simple_async_result_take_error (operation_result, error);
-        g_simple_async_result_complete (operation_result);
-        g_object_unref (operation_result);
-        return;
+    if (!mm_base_modem_at_command_finish (self, res, &error)) {
+        mm_warn ("Couldn't disable ^SIND psinfo notifications: %s", 
error->message);
+        g_error_free (error);
     }
 
-    /* The AT^SIND? command replies a list of several different indicators.
-     * We will only look for 'psinfo' which is the one which may tell us
-     * the available network access technology. Note that only 3G-enabled
-     * devices seem to have this indicator.
-     *
-     * AT+SIND?
-     * ^SIND: battchg,1,1
-     * ^SIND: signal,1,99
-     * ...
-     */
-    regex = g_regex_new ("\\r\\n\\^SIND:\\s*psinfo,\\s*(\\d*),\\s*(\\d*)", 0, 
0, NULL);
-    if (g_regex_match_full (regex, response, strlen (response), 0, 0, 
&match_info, NULL)) {
-        MMModemAccessTechnology act;
-        gchar *ind_value;
-
-        ind_value = g_match_info_fetch (match_info, 2);
-        act = get_access_technology_from_psinfo (ind_value, &error);
-        g_free (ind_value);
-        g_simple_async_result_set_op_res_gpointer (operation_result, 
GUINT_TO_POINTER (act), NULL);
-        g_simple_async_result_complete (operation_result);
-        g_object_unref (operation_result);
+    /* Chain up parent's disabñe */
+    iface_modem_3gpp_parent->disable_unsolicited_events (
+        MM_IFACE_MODEM_3GPP (self),
+        (GAsyncReadyCallback)parent_disable_unsolicited_events_ready,
+        task);
+}
+
+static void
+modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp    *self,
+                                       GAsyncReadyCallback  callback,
+                                       gpointer             user_data)
+{
+    GTask *task;
+
+    task = g_task_new (self, NULL, callback, user_data);
+
+    /* Disable access technology update reporting */
+    mm_base_modem_at_command (MM_BASE_MODEM (self),
+                              "AT^SIND=\"psinfo\",0",
+                              3,
+                              FALSE,
+                              (GAsyncReadyCallback)sind_psinfo_disable_ready,
+                              task);
+}
+
+/*****************************************************************************/
+/* Enable unsolicited events (3GPP interface) */
+
+static gboolean
+modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp  *self,
+                                             GAsyncResult      *res,
+                                             GError           **error)
+{
+    return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+sind_psinfo_enable_ready (MMBaseModem  *_self,
+                          GAsyncResult *res,
+                          GTask        *task)
+{
+    MMBroadbandModemCinterion *self;
+    GError                    *error = NULL;
+    const gchar               *response;
+    guint                      mode;
+    guint                      val;
+
+    self = MM_BROADBAND_MODEM_CINTERION (_self);
+    if (!(response = mm_base_modem_at_command_finish (_self, res, &error))) {
+        mm_warn ("Couldn't enable ^SIND psinfo notifications: %s", 
error->message);
+        g_error_free (error);
+    } else if (!mm_cinterion_parse_sind_response (response, NULL, &mode, &val, 
&error)) {
+        mm_warn ("Couldn't parse ^SIND psinfo response: %s", error->message);
+        g_error_free (error);
     } else {
-        /* If there was no 'psinfo' indicator, we'll try AT^SMONG and read the 
cell
-         * info table. */
-        mm_base_modem_at_command (
-            MM_BASE_MODEM (self),
-            "^SMONG",
-            3,
-            FALSE,
-            (GAsyncReadyCallback)smong_query_ready,
-            operation_result);
+        /* If enabled the indications, flag ^SIND psinfo supported so that we 
don't poll */
+        self->priv->sind_psinfo = TRUE;
+
+        /* Report initial access technology gathered right away */
+        mm_dbg ("Reporting initial access technologies...");
+        mm_iface_modem_update_access_technologies (MM_IFACE_MODEM (self),
+                                                   
mm_cinterion_get_access_technology_from_sind_psinfo (val),
+                                                   
MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK);
     }
 
-    g_match_info_free (match_info);
-    g_regex_unref (regex);
+    g_task_return_boolean (task, TRUE);
+    g_object_unref (task);
 }
 
 static void
-load_access_technologies (MMIfaceModem *self,
-                          GAsyncReadyCallback callback,
-                          gpointer user_data)
+parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self,
+                                        GAsyncResult     *res,
+                                        GTask            *task)
 {
-    MMBroadbandModemCinterion *broadband = MM_BROADBAND_MODEM_CINTERION (self);
-    GSimpleAsyncResult *result;
+    GError *error = NULL;
 
-    result = g_simple_async_result_new (G_OBJECT (self),
-                                        callback,
-                                        user_data,
-                                        load_access_technologies);
+    if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, 
&error)) {
+        mm_warn ("Couldn't enable parent 3GPP unsolicited events: %s", 
error->message);
+        g_error_free (error);
+    }
 
-    if (broadband->priv->sind_psinfo) {
-        /* TODO: Trigger off psinfo URC instead of this polling. */
-        mm_base_modem_at_command (
-            MM_BASE_MODEM (self),
-            "^SIND?",
-            3,
-            FALSE,
-            (GAsyncReadyCallback)sind_query_ready,
-            result);
+    /* Enable access technology update reporting */
+    mm_base_modem_at_command (MM_BASE_MODEM (self),
+                              "AT^SIND=\"psinfo\",1",
+                              3,
+                              FALSE,
+                              (GAsyncReadyCallback)sind_psinfo_enable_ready,
+                              task);
+}
+
+static void
+modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp    *self,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             user_data)
+{
+    GTask *task;
+
+    task = g_task_new (self, NULL, callback, user_data);
+
+    /* Chain up parent's enable */
+    iface_modem_3gpp_parent->enable_unsolicited_events (
+        self,
+        (GAsyncReadyCallback)parent_enable_unsolicited_events_ready,
+        task);
+}
+
+/*****************************************************************************/
+/* Setup/Cleanup unsolicited events (3GPP interface) */
+
+static void
+sind_psinfo_received (MMPortSerialAt            *port,
+                      GMatchInfo                *match_info,
+                      MMBroadbandModemCinterion *self)
+{
+    guint val;
+
+    if (!mm_get_uint_from_match_info (match_info, 1, &val)) {
+        mm_dbg ("Failed to convert psinfo value");
         return;
     }
 
-    mm_base_modem_at_command (
-        MM_BASE_MODEM (self),
-        "^SMONG",
-        3,
-        FALSE,
-        (GAsyncReadyCallback)smong_query_ready,
-        result);
+    mm_iface_modem_update_access_technologies (MM_IFACE_MODEM (self),
+                                               
mm_cinterion_get_access_technology_from_sind_psinfo (val),
+                                               
MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK);
+}
+
+static void
+set_unsolicited_events_handlers (MMBroadbandModemCinterion *self,
+                                 gboolean                   enable)
+{
+    MMPortSerialAt *ports[2];
+    guint           i;
+
+    ports[0] = mm_base_modem_peek_port_primary   (MM_BASE_MODEM (self));
+    ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
+
+    /* Enable unsolicited events in given port */
+    for (i = 0; i < 2; i++) {
+        if (!ports[i])
+            continue;
+
+        mm_port_serial_at_add_unsolicited_msg_handler (
+            ports[i],
+            self->priv->ciev_psinfo_regex,
+            enable ? (MMPortSerialAtUnsolicitedMsgFn)sind_psinfo_received : 
NULL,
+            enable ? self : NULL,
+            NULL);
+    }
+}
+
+static gboolean
+modem_3gpp_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gpp  *self,
+                                                    GAsyncResult      *res,
+                                                    GError           **error)
+{
+    return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_setup_unsolicited_events_ready (MMIfaceModem3gpp *self,
+                                       GAsyncResult     *res,
+                                       GTask            *task)
+{
+    GError *error = NULL;
+
+    if (!iface_modem_3gpp_parent->setup_unsolicited_events_finish (self, res, 
&error))
+        g_task_return_error (task, error);
+    else {
+        /* Our own setup now */
+        set_unsolicited_events_handlers (MM_BROADBAND_MODEM_CINTERION (self), 
TRUE);
+        g_task_return_boolean (task, TRUE);
+    }
+    g_object_unref (task);
+}
+
+static void
+modem_3gpp_setup_unsolicited_events (MMIfaceModem3gpp    *self,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data)
+{
+    GTask *task;
+
+    task = g_task_new (self, NULL, callback, user_data);
+
+    /* Chain up parent's setup */
+    iface_modem_3gpp_parent->setup_unsolicited_events (
+        self,
+        (GAsyncReadyCallback)parent_setup_unsolicited_events_ready,
+        task);
+}
+
+static void
+parent_cleanup_unsolicited_events_ready (MMIfaceModem3gpp *self,
+                                         GAsyncResult     *res,
+                                         GTask            *task)
+{
+    GError *error = NULL;
+
+    if (!iface_modem_3gpp_parent->cleanup_unsolicited_events_finish (self, 
res, &error))
+        g_task_return_error (task, error);
+    else
+        g_task_return_boolean (task, TRUE);
+    g_object_unref (task);
+}
+
+static void
+modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp    *self,
+                                       GAsyncReadyCallback  callback,
+                                       gpointer             user_data)
+{
+    GTask *task;
+
+    task = g_task_new (self, NULL, callback, user_data);
+
+    /* Our own cleanup first */
+    set_unsolicited_events_handlers (MM_BROADBAND_MODEM_CINTERION (self), 
FALSE);
+
+    /* And now chain up parent's cleanup */
+    iface_modem_3gpp_parent->cleanup_unsolicited_events (
+        self,
+        (GAsyncReadyCallback)parent_cleanup_unsolicited_events_ready,
+        task);
 }
 
 /*****************************************************************************/
@@ -1733,6 +1880,9 @@ mm_broadband_modem_cinterion_init 
(MMBroadbandModemCinterion *self)
     /* Initialize private variables */
     self->priv->sind_psinfo = TRUE; /* Initially, always try to get psinfo */
     self->priv->swwan_support = FEATURE_SUPPORT_UNKNOWN;
+
+    self->priv->ciev_psinfo_regex = g_regex_new ("\\r\\n\\+CIEV: 
psinfo,(\\d+)\\r\\n",
+                                                 G_REGEX_RAW | 
G_REGEX_OPTIMIZE, 0, NULL);
 }
 
 static void
@@ -1754,6 +1904,8 @@ finalize (GObject *object)
     if (self->priv->cnmi_supported_bfr)
         g_array_unref (self->priv->cnmi_supported_bfr);
 
+    g_regex_unref (self->priv->ciev_psinfo_regex);
+
     G_OBJECT_CLASS (mm_broadband_modem_cinterion_parent_class)->finalize 
(object);
 }
 
@@ -1792,6 +1944,17 @@ static void
 iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
 {
     iface_modem_3gpp_parent = g_type_interface_peek_parent (iface);
+
+    iface->enable_unsolicited_events = modem_3gpp_enable_unsolicited_events;
+    iface->enable_unsolicited_events_finish = 
modem_3gpp_enable_unsolicited_events_finish;
+    iface->disable_unsolicited_events = modem_3gpp_disable_unsolicited_events;
+    iface->disable_unsolicited_events_finish = 
modem_3gpp_disable_unsolicited_events_finish;
+
+    iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events;
+    iface->setup_unsolicited_events_finish = 
modem_3gpp_setup_cleanup_unsolicited_events_finish;
+    iface->cleanup_unsolicited_events = modem_3gpp_cleanup_unsolicited_events;
+    iface->cleanup_unsolicited_events_finish = 
modem_3gpp_setup_cleanup_unsolicited_events_finish;
+
     iface->register_in_network = register_in_network;
     iface->register_in_network_finish = register_in_network_finish;
 }
diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.c 
b/plugins/cinterion/mm-modem-helpers-cinterion.c
index da1e7787..3c7a0a0c 100644
--- a/plugins/cinterion/mm-modem-helpers-cinterion.c
+++ b/plugins/cinterion/mm-modem-helpers-cinterion.c
@@ -624,3 +624,36 @@ mm_cinterion_parse_smong_response (const gchar             
 *response,
     g_assert (access_tech != MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
     return TRUE;
 }
+
+/*****************************************************************************/
+/* ^SIND psinfo helper */
+
+MMModemAccessTechnology
+mm_cinterion_get_access_technology_from_sind_psinfo (guint val)
+{
+    switch (val) {
+    case 0:
+        return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+    case 1:
+    case 2:
+        return MM_MODEM_ACCESS_TECHNOLOGY_GPRS;
+    case 3:
+    case 4:
+        return MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
+    case 5:
+    case 6:
+        return MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
+    case 7:
+    case 8:
+        return MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
+    case 9:
+    case 10:
+        return (MM_MODEM_ACCESS_TECHNOLOGY_HSDPA | 
MM_MODEM_ACCESS_TECHNOLOGY_HSUPA);
+    case 16:
+    case 17:
+        return MM_MODEM_ACCESS_TECHNOLOGY_LTE;
+    default:
+        mm_dbg ("Unable to identify access technology from psinfo reported 
value: %u", val);
+        return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+    }
+}
diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.h 
b/plugins/cinterion/mm-modem-helpers-cinterion.h
index bcf02f9d..2ec05157 100644
--- a/plugins/cinterion/mm-modem-helpers-cinterion.h
+++ b/plugins/cinterion/mm-modem-helpers-cinterion.h
@@ -82,4 +82,9 @@ gboolean mm_cinterion_parse_smong_response (const gchar       
       *response,
                                             MMModemAccessTechnology  
*access_tech,
                                             GError                  **error);
 
+/*****************************************************************************/
+/* ^SIND psinfo helper */
+
+MMModemAccessTechnology mm_cinterion_get_access_technology_from_sind_psinfo 
(guint val);
+
 #endif  /* MM_MODEM_HELPERS_CINTERION_H */
-- 
2.12.2

_______________________________________________
ModemManager-devel mailing list
ModemManager-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/modemmanager-devel

Reply via email to