[PATCH v2] broadband-modem-huawei: implement Modem.Signal extended signal info interface

Dan Williams dcbw at redhat.com
Tue Aug 30 20:32:01 UTC 2016


Implement the detailed signal info interface for some Huawei 3GPP modems.

---
 plugins/huawei/mm-broadband-modem-huawei.c       | 318 ++++++++++++++++++++++-
 plugins/huawei/mm-modem-helpers-huawei.c         |  71 +++++
 plugins/huawei/mm-modem-helpers-huawei.h         |  12 +
 plugins/huawei/tests/test-modem-helpers-huawei.c |  61 +++++
 src/mm-modem-helpers.c                           |  17 +-
 5 files changed, 471 insertions(+), 8 deletions(-)

diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c
index fe6c217..af560a4 100644
--- a/plugins/huawei/mm-broadband-modem-huawei.c
+++ b/plugins/huawei/mm-broadband-modem-huawei.c
@@ -43,6 +43,7 @@
 #include "mm-iface-modem-location.h"
 #include "mm-iface-modem-time.h"
 #include "mm-iface-modem-cdma.h"
+#include "mm-iface-modem-signal.h"
 #include "mm-iface-modem-voice.h"
 #include "mm-broadband-modem-huawei.h"
 #include "mm-broadband-bearer-huawei.h"
@@ -58,6 +59,7 @@ static void iface_modem_location_init (MMIfaceModemLocation *iface);
 static void iface_modem_cdma_init (MMIfaceModemCdma *iface);
 static void iface_modem_time_init (MMIfaceModemTime *iface);
 static void iface_modem_voice_init (MMIfaceModemVoice *iface);
+static void iface_modem_signal_init (MMIfaceModemSignal *iface);
 
 static MMIfaceModem *iface_modem_parent;
 static MMIfaceModem3gpp *iface_modem_3gpp_parent;
@@ -72,7 +74,8 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemHuawei, mm_broadband_modem_huawei, MM_TY
                         G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)
                         G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
                         G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
-                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init));
+                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
+                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init));
 
 typedef enum {
     FEATURE_SUPPORT_UNKNOWN,
@@ -80,6 +83,14 @@ typedef enum {
     FEATURE_SUPPORTED
 } FeatureSupport;
 
+typedef struct {
+    MMSignal *cdma;
+    MMSignal *evdo;
+    MMSignal *gsm;
+    MMSignal *umts;
+    MMSignal *lte;
+} DetailedSignal;
+
 struct _MMBroadbandModemHuaweiPrivate {
     /* Regex for signal quality related notifications */
     GRegex *rssi_regex;
@@ -134,6 +145,8 @@ struct _MMBroadbandModemHuaweiPrivate {
     GArray *syscfg_supported_modes;
     GArray *syscfgex_supported_modes;
     GArray *prefmode_supported_modes;
+
+    DetailedSignal detailed_signal;
 };
 
 /*****************************************************************************/
@@ -1740,6 +1753,136 @@ huawei_ndisstat_changed (MMPortSerialAt *port,
 }
 
 static void
+detailed_signal_clear (DetailedSignal *signal)
+{
+    g_clear_object (&signal->cdma);
+    g_clear_object (&signal->evdo);
+    g_clear_object (&signal->gsm);
+    g_clear_object (&signal->umts);
+    g_clear_object (&signal->lte);
+}
+
+static gboolean
+get_rssi_dbm (guint rssi, gdouble *out_val)
+{
+    if (rssi <= 96) {
+        *out_val = (double) (-121.0 + rssi);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean
+get_ecio_db (guint ecio, gdouble *out_val)
+{
+    if (ecio <= 65) {
+        *out_val = -32.5 + ((double) ecio / 2.0);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean
+get_rsrp_dbm (guint rsrp, gdouble *out_val)
+{
+    if (rsrp <= 97) {
+        *out_val = (double) (-141.0 + rsrp);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean
+get_sinr_db (guint sinr, gdouble *out_val)
+{
+    if (sinr <= 251) {
+        *out_val = -20.2 + (double) (sinr / 5.0);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean
+get_rsrq_db (guint rsrq, gdouble *out_val)
+{
+    if (rsrq <= 34) {
+        *out_val = -20 + (double) (rsrq / 2.0);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static void
+huawei_hcsq_changed (MMPortSerialAt *port,
+                     GMatchInfo *match_info,
+                     MMBroadbandModemHuawei *self)
+{
+    gchar *str;
+    MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+    guint value1 = 0;
+    guint value2 = 0;
+    guint value3 = 0;
+    guint value4 = 0;
+    guint value5 = 0;
+    gdouble v;
+    GError *error = NULL;
+
+    str = g_match_info_fetch (match_info, 1);
+    if (!mm_huawei_parse_hcsq_response (str,
+                                        &act,
+                                        &value1,
+                                        &value2,
+                                        &value3,
+                                        &value4,
+                                        &value5,
+                                        &error)) {
+        mm_dbg ("Ignored invalid ^HCSQ message: %s (error %s)", str, error->message);
+        g_error_free (error);
+        g_free (str);
+        return;
+    }
+
+    detailed_signal_clear (&self->priv->detailed_signal);
+
+    switch (act) {
+    case MM_MODEM_ACCESS_TECHNOLOGY_GSM:
+        self->priv->detailed_signal.gsm = mm_signal_new ();
+        /* value1: gsm_rssi */
+        if (get_rssi_dbm (value1, &v))
+            mm_signal_set_rssi (self->priv->detailed_signal.gsm, v);
+        break;
+    case MM_MODEM_ACCESS_TECHNOLOGY_UMTS:
+        self->priv->detailed_signal.umts = mm_signal_new ();
+        /* value1: wcdma_rssi */
+        if (get_rssi_dbm (value1, &v))
+            mm_signal_set_rssi (self->priv->detailed_signal.umts, v);
+        /* value2: wcdma_rscp; unused */
+        /* value3: wcdma_ecio */
+        if (get_ecio_db (value3, &v))
+            mm_signal_set_ecio (self->priv->detailed_signal.umts, v);
+        break;
+    case MM_MODEM_ACCESS_TECHNOLOGY_LTE:
+        self->priv->detailed_signal.lte = mm_signal_new ();
+        /* value1: lte_rssi */
+        if (get_rssi_dbm (value1, &v))
+            mm_signal_set_rssi (self->priv->detailed_signal.lte, v);
+        /* value2: lte_rsrp */
+        if (get_rsrp_dbm (value2, &v))
+            mm_signal_set_rsrp (self->priv->detailed_signal.lte, v);
+        /* value3: lte_sinr -> SNR? */
+        if (get_sinr_db (value3, &v))
+            mm_signal_set_snr (self->priv->detailed_signal.lte, v);
+        /* value4: lte_rsrq */
+        if (get_rsrq_db (value4, &v))
+            mm_signal_set_rsrq (self->priv->detailed_signal.lte, v);
+        break;
+    default:
+        /* CDMA and EVDO not yet supported */
+        break;
+    }
+}
+
+static void
 set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
                                       gboolean enable)
 {
@@ -1781,6 +1924,13 @@ set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
             enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_ndisstat_changed : NULL,
             enable ? self : NULL,
             NULL);
+
+        mm_port_serial_at_add_unsolicited_msg_handler (
+            port,
+            self->priv->hcsq_regex,
+            enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_hcsq_changed : NULL,
+            enable ? self : NULL,
+            NULL);
     }
 
     g_list_free_full (ports, (GDestroyNotify)g_object_unref);
@@ -3967,6 +4117,146 @@ modem_time_check_support (MMIfaceModemTime *self,
 }
 
 /*****************************************************************************/
+/* Check support (Signal interface) */
+
+static void
+hcsq_check_ready (MMBaseModem *_self,
+                  GAsyncResult *res,
+                  GTask *task)
+{
+    GError *error = NULL;
+    const gchar *response;
+
+    response = mm_base_modem_at_command_finish (_self, res, &error);
+    if (response)
+        g_task_return_boolean (task, TRUE);
+    else
+        g_task_return_error (task, error);
+
+    g_object_unref (task);
+}
+
+static gboolean
+signal_check_support_finish (MMIfaceModemSignal *self,
+                             GAsyncResult *res,
+                             GError **error)
+{
+    return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+signal_check_support (MMIfaceModemSignal *_self,
+                      GAsyncReadyCallback callback,
+                      gpointer user_data)
+{
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+    GTask *task;
+
+    task = g_task_new (self, NULL, callback, user_data);
+    mm_base_modem_at_command (MM_BASE_MODEM (self),
+                              "^HCSQ?",
+                              3,
+                              FALSE,
+                              (GAsyncReadyCallback)hcsq_check_ready,
+                              task);
+}
+
+/*****************************************************************************/
+/* Load extended signal information */
+
+static void
+detailed_signal_free (DetailedSignal *signal)
+{
+    g_clear_object (&signal->cdma);
+    g_clear_object (&signal->evdo);
+    g_clear_object (&signal->gsm);
+    g_clear_object (&signal->umts);
+    g_clear_object (&signal->lte);
+    g_slice_free (DetailedSignal, signal);
+}
+
+static gboolean
+signal_load_values_finish (MMIfaceModemSignal *self,
+                           GAsyncResult *res,
+                           MMSignal **cdma,
+                           MMSignal **evdo,
+                           MMSignal **gsm,
+                           MMSignal **umts,
+                           MMSignal **lte,
+                           GError **error)
+{
+    DetailedSignal *signals;
+
+    signals = g_task_propagate_pointer (G_TASK (res), error);
+    if (!signals)
+        return FALSE;
+
+    *cdma = signals->cdma ? g_object_ref (signals->cdma) : NULL;
+    *evdo = signals->evdo ? g_object_ref (signals->evdo) : NULL;
+    *gsm  = signals->gsm ? g_object_ref (signals->gsm) : NULL;
+    *umts = signals->umts ? g_object_ref (signals->umts) : NULL;
+    *lte  = signals->lte ? g_object_ref (signals->lte) : NULL;
+
+    detailed_signal_free (signals);
+    return TRUE;
+}
+
+static void
+hcsq_get_ready (MMBaseModem *_self,
+                GAsyncResult *res,
+                GTask *task)
+{
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+    DetailedSignal *signals;
+    GError *error = NULL;
+
+    /* Don't care about the response; it will have been parsed by the HCSQ
+     * unsolicited event handler and self->priv->detailed_signal will already
+     * be updated.
+     */
+    if (!mm_base_modem_at_command_finish (_self, res, &error)) {
+        mm_dbg ("^HCSQ failed: %s", error->message);
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+    signals = g_slice_new0 (DetailedSignal);
+    signals->cdma = self->priv->detailed_signal.cdma ? g_object_ref (self->priv->detailed_signal.cdma) : NULL;
+    signals->evdo = self->priv->detailed_signal.evdo ? g_object_ref (self->priv->detailed_signal.evdo) : NULL;
+    signals->gsm = self->priv->detailed_signal.gsm ? g_object_ref (self->priv->detailed_signal.gsm) : NULL;
+    signals->umts = self->priv->detailed_signal.umts ? g_object_ref (self->priv->detailed_signal.umts) : NULL;
+    signals->lte = self->priv->detailed_signal.lte ? g_object_ref (self->priv->detailed_signal.lte) : NULL;
+
+    g_task_return_pointer (task, signals, (GDestroyNotify)detailed_signal_free);
+    g_object_unref (task);
+}
+
+static void
+signal_load_values (MMIfaceModemSignal *_self,
+                    GCancellable *cancellable,
+                    GAsyncReadyCallback callback,
+                    gpointer user_data)
+{
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+    GTask *task;
+
+    mm_dbg ("loading extended signal information...");
+
+    task = g_task_new (self, cancellable, callback, user_data);
+
+    /* Clear any previous detailed signal values to get new ones */
+    detailed_signal_clear (&self->priv->detailed_signal);
+
+    mm_base_modem_at_command (MM_BASE_MODEM (self),
+                              "^HCSQ?",
+                              3,
+                              FALSE,
+                              (GAsyncReadyCallback)hcsq_get_ready,
+                              task);
+}
+
+/*****************************************************************************/
 /* Setup ports (Broadband modem class) */
 
 static void
@@ -4018,10 +4308,6 @@ set_ignored_unsolicited_events_handlers (MMBroadbandModemHuawei *self)
             NULL, NULL, NULL);
         mm_port_serial_at_add_unsolicited_msg_handler (
             port,
-            self->priv->hcsq_regex,
-            NULL, NULL, NULL);
-        mm_port_serial_at_add_unsolicited_msg_handler (
-            port,
             self->priv->pdpdeact_regex,
             NULL, NULL, NULL);
         mm_port_serial_at_add_unsolicited_msg_handler (
@@ -4152,7 +4438,7 @@ mm_broadband_modem_huawei_init (MMBroadbandModemHuawei *self)
                                            G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
     self->priv->stin_regex = g_regex_new ("\\r\\n\\^STIN:.+\\r\\n",
                                           G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
-    self->priv->hcsq_regex = g_regex_new ("\\r\\n\\^HCSQ:.+\\r+\\n",
+    self->priv->hcsq_regex = g_regex_new ("\\r\\n(\\^HCSQ:.+)\\r+\\n",
                                           G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
     self->priv->pdpdeact_regex = g_regex_new ("\\r\\n\\^PDPDEACT:.+\\r+\\n",
                                               G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
@@ -4210,6 +4496,16 @@ mm_broadband_modem_huawei_init (MMBroadbandModemHuawei *self)
 }
 
 static void
+dispose (GObject *object)
+{
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (object);
+
+    detailed_signal_clear (&self->priv->detailed_signal);
+
+    G_OBJECT_CLASS (mm_broadband_modem_huawei_parent_class)->dispose (object);
+}
+
+static void
 finalize (GObject *object)
 {
     MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (object);
@@ -4372,6 +4668,15 @@ iface_modem_voice_init (MMIfaceModemVoice *iface)
 }
 
 static void
+iface_modem_signal_init (MMIfaceModemSignal *iface)
+{
+    iface->check_support = signal_check_support;
+    iface->check_support_finish = signal_check_support_finish;
+    iface->load_values = signal_load_values;
+    iface->load_values_finish = signal_load_values_finish;
+}
+
+static void
 mm_broadband_modem_huawei_class_init (MMBroadbandModemHuaweiClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -4379,6 +4684,7 @@ mm_broadband_modem_huawei_class_init (MMBroadbandModemHuaweiClass *klass)
 
     g_type_class_add_private (object_class, sizeof (MMBroadbandModemHuaweiPrivate));
 
+    object_class->dispose = dispose;
     object_class->finalize = finalize;
 
     broadband_modem_class->setup_ports = setup_ports;
diff --git a/plugins/huawei/mm-modem-helpers-huawei.c b/plugins/huawei/mm-modem-helpers-huawei.c
index 0e0e046..d3f13c2 100644
--- a/plugins/huawei/mm-modem-helpers-huawei.c
+++ b/plugins/huawei/mm-modem-helpers-huawei.c
@@ -1329,3 +1329,74 @@ gboolean mm_huawei_parse_time_response (const gchar *response,
 
     return ret;
 }
+
+/*****************************************************************************/
+/* ^HCSQ response parser */
+
+gboolean
+mm_huawei_parse_hcsq_response (const gchar *response,
+                               MMModemAccessTechnology *out_act,
+                               guint *out_value1,
+                               guint *out_value2,
+                               guint *out_value3,
+                               guint *out_value4,
+                               guint *out_value5,
+                               GError **error)
+{
+    GRegex *r;
+    GMatchInfo *match_info = NULL;
+    GError *match_error = NULL;
+    gboolean ret = FALSE;
+    char *s;
+
+    r = g_regex_new ("\\^HCSQ:\\s*\"([a-zA-Z]*)\",(\\d+),?(\\d+)?,?(\\d+)?,?(\\d+)?,?(\\d+)?$", 0, 0, NULL);
+    g_assert (r != NULL);
+
+    if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) {
+        if (match_error) {
+            g_propagate_error (error, match_error);
+            g_prefix_error (error, "Could not parse ^HCSQ results: ");
+        } else {
+            g_set_error_literal (error,
+                                 MM_CORE_ERROR,
+                                 MM_CORE_ERROR_FAILED,
+                                 "Couldn't match ^HCSQ reply");
+        }
+        goto done;
+    }
+
+    /* Remember that g_match_info_get_match_count() includes match #0 */
+    if (g_match_info_get_match_count (match_info) < 3) {
+        g_set_error_literal (error,
+                             MM_CORE_ERROR,
+                             MM_CORE_ERROR_FAILED,
+                             "Not enough elements in ^HCSQ reply");
+        goto done;
+    }
+
+    if (out_act) {
+        s = g_match_info_fetch (match_info, 1);
+        *out_act = mm_string_to_access_tech (s);
+        g_free (s);
+    }
+
+    if (out_value1)
+        mm_get_uint_from_match_info (match_info, 2, out_value1);
+    if (out_value2)
+        mm_get_uint_from_match_info (match_info, 3, out_value2);
+    if (out_value3)
+        mm_get_uint_from_match_info (match_info, 4, out_value3);
+    if (out_value4)
+        mm_get_uint_from_match_info (match_info, 5, out_value4);
+    if (out_value5)
+        mm_get_uint_from_match_info (match_info, 6, out_value5);
+
+    ret = TRUE;
+
+done:
+    if (match_info)
+        g_match_info_free (match_info);
+    g_regex_unref (r);
+
+    return ret;
+}
diff --git a/plugins/huawei/mm-modem-helpers-huawei.h b/plugins/huawei/mm-modem-helpers-huawei.h
index 62019e8..b4c7ac7 100644
--- a/plugins/huawei/mm-modem-helpers-huawei.h
+++ b/plugins/huawei/mm-modem-helpers-huawei.h
@@ -139,4 +139,16 @@ gboolean mm_huawei_parse_time_response (const gchar *response,
                                         MMNetworkTimezone **tzp,
                                         GError **error);
 
+/*****************************************************************************/
+/* ^HCSQ response parser */
+
+gboolean mm_huawei_parse_hcsq_response (const gchar *response,
+                                        MMModemAccessTechnology *out_act,
+                                        guint *out_value1,
+                                        guint *out_value2,
+                                        guint *out_value3,
+                                        guint *out_value4,
+                                        guint *out_value5,
+                                        GError **error);
+
 #endif  /* MM_MODEM_HELPERS_HUAWEI_H */
diff --git a/plugins/huawei/tests/test-modem-helpers-huawei.c b/plugins/huawei/tests/test-modem-helpers-huawei.c
index bd0a8a6..13601c4 100644
--- a/plugins/huawei/tests/test-modem-helpers-huawei.c
+++ b/plugins/huawei/tests/test-modem-helpers-huawei.c
@@ -1192,6 +1192,66 @@ test_time (void)
 }
 
 /*****************************************************************************/
+/* Test ^HCSQ responses */
+
+typedef struct {
+    const gchar *str;
+    gboolean ret;
+    MMModemAccessTechnology act;
+    guint value1;
+    guint value2;
+    guint value3;
+    guint value4;
+    guint value5;
+} HcsqTest;
+
+static const HcsqTest hcsq_tests[] = {
+    { "^HCSQ:\"LTE\",30,19,66,0\r\n",  TRUE,  MM_MODEM_ACCESS_TECHNOLOGY_LTE,     30, 19,  66, 0, 0 },
+    { "^HCSQ: \"WCDMA\",30,30,58\r\n", TRUE,  MM_MODEM_ACCESS_TECHNOLOGY_UMTS,    30, 30,  58, 0, 0 },
+    { "^HCSQ: \"GSM\",36,255\r\n",     TRUE,  MM_MODEM_ACCESS_TECHNOLOGY_GSM,     36, 255,  0, 0, 0 },
+    { "^HCSQ: \"NOSERVICE\"\r\n",      FALSE, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN,  0,   0,  0, 0, 0 },
+    { NULL,                            FALSE, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN,  0,   0,  0, 0, 0 }
+};
+
+static void
+test_hcsq (void)
+{
+    guint i;
+
+    for (i = 0; hcsq_tests[i].str; i++) {
+        GError *error = NULL;
+        MMModemAccessTechnology act;
+        guint value1 = 0;
+        guint value2 = 0;
+        guint value3 = 0;
+        guint value4 = 0;
+        guint value5 = 0;
+        gboolean ret;
+
+        ret = mm_huawei_parse_hcsq_response (hcsq_tests[i].str,
+                                             &act,
+                                             &value1,
+                                             &value2,
+                                             &value3,
+                                             &value4,
+                                             &value5,
+                                             &error);
+        g_assert (ret == hcsq_tests[i].ret);
+        if (ret) {
+            g_assert_no_error (error);
+            g_assert_cmpint (hcsq_tests[i].act, ==, act);
+            g_assert_cmpint (hcsq_tests[i].value1, ==, value1);
+            g_assert_cmpint (hcsq_tests[i].value2, ==, value2);
+            g_assert_cmpint (hcsq_tests[i].value3, ==, value3);
+            g_assert_cmpint (hcsq_tests[i].value4, ==, value4);
+            g_assert_cmpint (hcsq_tests[i].value5, ==, value5);
+        } else
+            g_assert (error);
+        g_clear_error (&error);
+    }
+}
+
+/*****************************************************************************/
 
 void
 _mm_log (const char *loc,
@@ -1232,6 +1292,7 @@ int main (int argc, char **argv)
     g_test_add_func ("/MM/huawei/syscfgex/response", test_syscfgex_response);
     g_test_add_func ("/MM/huawei/nwtime", test_nwtime);
     g_test_add_func ("/MM/huawei/time", test_time);
+    g_test_add_func ("/MM/huawei/hcsq", test_hcsq);
 
     return g_test_run ();
 }
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 9f71b24..01d0c79 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -2089,6 +2089,7 @@ MMModemAccessTechnology
 mm_string_to_access_tech (const gchar *string)
 {
     MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+    gsize len;
 
     g_return_val_if_fail (string != NULL, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
 
@@ -2102,14 +2103,15 @@ mm_string_to_access_tech (const gchar *string)
     else if (strcasestr (string, "HSPA"))
         act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA;
 
-
     if (strcasestr (string, "HSUPA"))
         act |= MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
 
     if (strcasestr (string, "HSDPA"))
         act |= MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
 
-    if (strcasestr (string, "UMTS") || strcasestr (string, "3G"))
+    if (strcasestr (string, "UMTS") ||
+        strcasestr (string, "3G") ||
+        strcasestr (string, "WCDMA"))
         act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
 
     if (strcasestr (string, "EDGE"))
@@ -2133,6 +2135,17 @@ mm_string_to_access_tech (const gchar *string)
     if (strcasestr (string, "1xRTT") || strcasestr (string, "CDMA2000 1X"))
         act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
 
+    /* Check "EVDO" and "CDMA" as standalone strings since their characters
+     * are included in other strings too.
+     */
+    len = strlen (string);
+    if (strncmp (string, "EVDO", 4) && (len >= 4 && !isalnum (string[4])))
+        act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
+    if (strncmp (string, "CDMA", 4) && (len >= 4 && !isalnum (string[4])))
+        act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
+    if (strncmp (string, "CDMA-EVDO", 9) && (len >= 9 && !isalnum (string[9])))
+        act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT | MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
+
     return act;
 }
 
-- 
2.5.5


More information about the ModemManager-devel mailing list