diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-01-22 15:54:05 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:14:56 +0100 |
commit | a6301ee0c461f5f9af800877d56fb3af6fc15d7b (patch) | |
tree | cad143f04018c079537c7e45c08de3ce881493e3 | |
parent | 8321bd5875a5aedb845d8b196ae6db75c3f769d2 (diff) |
cinterion: implement access technology loading logic
-rw-r--r-- | plugins/mm-broadband-modem-cinterion.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/plugins/mm-broadband-modem-cinterion.c b/plugins/mm-broadband-modem-cinterion.c index d518005e..1c9ef6eb 100644 --- a/plugins/mm-broadband-modem-cinterion.c +++ b/plugins/mm-broadband-modem-cinterion.c @@ -41,6 +41,9 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion, G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)); struct _MMBroadbandModemCinterionPrivate { + /* Flag to know if we should try AT^SIND or not to get psinfo */ + gboolean sind_psinfo; + /* Command to go into sleep mode */ gchar *sleep_mode_cmd; @@ -176,6 +179,248 @@ modem_power_down (MMIfaceModem *self, } /*****************************************************************************/ +/* ACCESS TECHNOLOGIES */ + +static gboolean +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)) + return FALSE; + + *access_technologies = (MMModemAccessTechnology) GPOINTER_TO_UINT ( + g_simple_async_result_get_op_res_gpointer ( + G_SIMPLE_ASYNC_RESULT (res))); + *mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY; + return TRUE; +} + +static MMModemAccessTechnology +get_access_technology_from_smong_gprs_status (const gchar *gprs_status, + GError **error) +{ + if (strlen (gprs_status) == 1) { + switch (gprs_status[0]) { + 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; + default: + break; + } + } + + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Couldn't get network capabilities, " + "invalid GPRS status value: '%s'", + gprs_status); + return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; +} + +static void +smong_query_ready (MMBroadbandModemCinterion *self, + GAsyncResult *res, + GSimpleAsyncResult *operation_result) +{ + 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; + } + + /* The AT^SMONG command returns a cell info table, where the second + * column identifies the "GPRS status", which is exactly what we want. + * So we'll try to read that second number in the values row. + * + * AT^SMONG + * GPRS Monitor + * BCCH G PBCCH PAT MCC MNC NOM TA RAC # Cell # + * 0776 1 - - 214 03 2 00 01 + * OK + */ + regex = g_regex_new (".*GPRS Monitor\\r\\n" + "BCCH\\s*G.*\\r\\n" + "(\\d*)\\s*(\\d*)\\s*", 0, 0, NULL); + if (g_regex_match_full (regex, response, strlen (response), 0, 0, &match_info, NULL)) { + gchar *gprs_status; + MMModemAccessTechnology act; + + gprs_status = g_match_info_fetch (match_info, 2); + act = get_access_technology_from_smong_gprs_status (gprs_status, &error); + g_free (gprs_status); + + if (error) + 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 (act), + NULL); + } + } else { + /* We'll reset here the flag to try to use SIND/psinfo the next time */ + self->priv->sind_psinfo = TRUE; + + g_simple_async_result_set_error (operation_result, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Couldn't get network capabilities, " + "invalid SMONG reply: '%s'", + response); + } + + g_match_info_free (match_info); + g_regex_unref (regex); + + g_simple_async_result_complete (operation_result); + g_object_unref (operation_result); +} + +static MMModemAccessTechnology +get_access_technology_from_psinfo (const gchar *psinfo, + GError **error) +{ + if (strlen (psinfo) == 1) { + switch (psinfo[0]) { + 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; + default: + break; + } + } + + 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; +} + +static void +sind_query_ready (MMBroadbandModemCinterion *self, + GAsyncResult *res, + GSimpleAsyncResult *operation_result) +{ + 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; + } + + /* 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); + } 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, + NULL, /* cancellable */ + (GAsyncReadyCallback)smong_query_ready, + operation_result); + } + + g_match_info_free (match_info); + g_regex_unref (regex); +} + +static void +load_access_technologies (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemCinterion *broadband = MM_BROADBAND_MODEM_CINTERION (self); + GSimpleAsyncResult *result; + + result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_access_technologies); + + if (broadband->priv->sind_psinfo) { + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "^SIND?", + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)sind_query_ready, + result); + return; + } + + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "^SMONG", + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)smong_query_ready, + result); +} + +/*****************************************************************************/ /* SUPPORTED MODES */ static MMModemMode @@ -348,6 +593,9 @@ mm_broadband_modem_cinterion_init (MMBroadbandModemCinterion *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), MM_TYPE_BROADBAND_MODEM_CINTERION, MMBroadbandModemCinterionPrivate); + + /* Set defaults */ + self->priv->sind_psinfo = TRUE; /* Initially, always try to get psinfo */ } static void @@ -365,6 +613,8 @@ iface_modem_init (MMIfaceModem *iface) { iface->load_supported_modes = load_supported_modes; iface->load_supported_modes_finish = load_supported_modes_finish; + iface->load_access_technologies = load_access_technologies; + iface->load_access_technologies_finish = load_access_technologies_finish; iface->setup_flow_control = setup_flow_control; iface->setup_flow_control_finish = setup_flow_control_finish; iface->modem_power_down = modem_power_down; |