aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/mm-broadband-modem-cinterion.c250
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;