diff options
Diffstat (limited to 'plugins/simtech/mm-broadband-modem-simtech.c')
-rw-r--r-- | plugins/simtech/mm-broadband-modem-simtech.c | 437 |
1 files changed, 359 insertions, 78 deletions
diff --git a/plugins/simtech/mm-broadband-modem-simtech.c b/plugins/simtech/mm-broadband-modem-simtech.c index feb08470..c08d5f4d 100644 --- a/plugins/simtech/mm-broadband-modem-simtech.c +++ b/plugins/simtech/mm-broadband-modem-simtech.c @@ -51,9 +51,17 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemSimtech, mm_broadband_modem_simtech, MM_ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init) G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_SIMTECH, shared_simtech_init)) +typedef enum { + FEATURE_SUPPORT_UNKNOWN, + FEATURE_NOT_SUPPORTED, + FEATURE_SUPPORTED +} FeatureSupport; + struct _MMBroadbandModemSimtechPrivate { - GRegex *cnsmod_regex; - GRegex *csq_regex; + FeatureSupport cnsmod_support; + FeatureSupport autocsq_support; + GRegex *cnsmod_regex; + GRegex *csq_regex; }; /*****************************************************************************/ @@ -214,7 +222,21 @@ modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self, } /*****************************************************************************/ -/* Enabling unsolicited events (3GPP interface) */ +/* Enable unsolicited events (3GPP interface) */ + +typedef enum { + ENABLE_UNSOLICITED_EVENTS_STEP_FIRST, + ENABLE_UNSOLICITED_EVENTS_STEP_PARENT, + ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_CNSMOD, + ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_CNSMOD, + ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_AUTOCSQ, + ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_AUTOCSQ, + ENABLE_UNSOLICITED_EVENTS_STEP_LAST, +} EnableUnsolicitedEventsStep; + +typedef struct { + EnableUnsolicitedEventsStep step; +} EnableUnsolicitedEventsContext; static gboolean modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self, @@ -224,35 +246,113 @@ modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self, return g_task_propagate_boolean (G_TASK (res), error); } +static void enable_unsolicited_events_context_step (GTask *task); + static void -own_enable_unsolicited_events_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) +autocsq_set_enabled_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) { - GError *error = NULL; + EnableUnsolicitedEventsContext *ctx; + GError *error = NULL; + gboolean csq_urcs_enabled = FALSE; - mm_base_modem_at_sequence_full_finish (self, res, NULL, &error); - if (error) - g_task_return_error (task, error); + ctx = g_task_get_task_data (task); + + if (!mm_base_modem_at_command_finish (self, res, &error)) { + mm_dbg ("Couldn't enable automatic signal quality reporting: %s", error->message); + g_error_free (error); + } else + csq_urcs_enabled = TRUE; + + /* Disable access technology polling if we can use the +CSQ URCs */ + g_object_set (self, + MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, csq_urcs_enabled, + NULL); + + /* go to next step */ + ctx->step++; + enable_unsolicited_events_context_step (task); +} + +static void +autocsq_test_ready (MMBaseModem *_self, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemSimtech *self; + EnableUnsolicitedEventsContext *ctx; + + self = MM_BROADBAND_MODEM_SIMTECH (_self); + ctx = g_task_get_task_data (task); + + if (!mm_base_modem_at_command_finish (_self, res, NULL)) + self->priv->autocsq_support = FEATURE_NOT_SUPPORTED; else - g_task_return_boolean (task, TRUE); - g_object_unref (task); + self->priv->autocsq_support = FEATURE_SUPPORTED; + + /* go to next step */ + ctx->step++; + enable_unsolicited_events_context_step (task); } -static const MMBaseModemAtCommand unsolicited_enable_sequence[] = { - /* Autoreport access technology changes */ - { "+CNSMOD=1", 20, FALSE, NULL }, - /* Autoreport CSQ (first arg), and only report when it changes (second arg) */ - { "+AUTOCSQ=1,1", 5, FALSE, NULL }, - { NULL } -}; +static void +cnsmod_set_enabled_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + EnableUnsolicitedEventsContext *ctx; + GError *error = NULL; + gboolean cnsmod_urcs_enabled = FALSE; + + ctx = g_task_get_task_data (task); + + if (!mm_base_modem_at_command_finish (self, res, &error)) { + mm_dbg ("Couldn't enable automatic access technology reporting: %s", error->message); + g_error_free (error); + } else + cnsmod_urcs_enabled = TRUE; + + /* Disable access technology polling if we can use the +CNSMOD URCs */ + g_object_set (self, + MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, cnsmod_urcs_enabled, + NULL); + + /* go to next step */ + ctx->step++; + enable_unsolicited_events_context_step (task); +} + +static void +cnsmod_test_ready (MMBaseModem *_self, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemSimtech *self; + EnableUnsolicitedEventsContext *ctx; + + self = MM_BROADBAND_MODEM_SIMTECH (_self); + ctx = g_task_get_task_data (task); + + if (!mm_base_modem_at_command_finish (_self, res, NULL)) + self->priv->cnsmod_support = FEATURE_NOT_SUPPORTED; + else + self->priv->cnsmod_support = FEATURE_SUPPORTED; + + /* go to next step */ + ctx->step++; + enable_unsolicited_events_context_step (task); +} static void parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self, GAsyncResult *res, GTask *task) { - GError *error = NULL; + EnableUnsolicitedEventsContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) { g_task_return_error (task, error); @@ -260,16 +360,91 @@ parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self, return; } - /* Our own enable now */ - mm_base_modem_at_sequence_full ( - MM_BASE_MODEM (self), - mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), - unsolicited_enable_sequence, - NULL, /* response_processor_context */ - NULL, /* response_processor_context_free */ - NULL, /* cancellable */ - (GAsyncReadyCallback)own_enable_unsolicited_events_ready, - task); + /* go to next step */ + ctx->step++; + enable_unsolicited_events_context_step (task); +} + +static void +enable_unsolicited_events_context_step (GTask *task) +{ + MMBroadbandModemSimtech *self; + EnableUnsolicitedEventsContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case ENABLE_UNSOLICITED_EVENTS_STEP_FIRST: + /* fall down to next step */ + ctx->step++; + + case ENABLE_UNSOLICITED_EVENTS_STEP_PARENT: + iface_modem_3gpp_parent->enable_unsolicited_events ( + MM_IFACE_MODEM_3GPP (self), + (GAsyncReadyCallback)parent_enable_unsolicited_events_ready, + task); + return; + + case ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_CNSMOD: + if (self->priv->cnsmod_support == FEATURE_SUPPORT_UNKNOWN) { + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+CNSMOD=?", + 3, + TRUE, + (GAsyncReadyCallback)cnsmod_test_ready, + task); + return; + } + /* fall down to next step */ + ctx->step++; + + case ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_CNSMOD: + if (self->priv->cnsmod_support == FEATURE_SUPPORTED) { + mm_base_modem_at_command (MM_BASE_MODEM (self), + /* Autoreport +CNSMOD when it changes */ + "+CNSMOD=1", + 20, + FALSE, + (GAsyncReadyCallback)cnsmod_set_enabled_ready, + task); + return; + } + /* fall down to next step */ + ctx->step++; + + case ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_AUTOCSQ: + if (self->priv->autocsq_support == FEATURE_SUPPORT_UNKNOWN) { + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+AUTOCSQ=?", + 3, + TRUE, + (GAsyncReadyCallback)autocsq_test_ready, + task); + return; + } + /* fall down to next step */ + ctx->step++; + + case ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_AUTOCSQ: + if (self->priv->autocsq_support == FEATURE_SUPPORTED) { + mm_base_modem_at_command (MM_BASE_MODEM (self), + /* Autoreport+ CSQ (first arg), and only report when it changes (second arg) */ + "+AUTOCSQ=1,1", + 20, + FALSE, + (GAsyncReadyCallback)autocsq_set_enabled_ready, + task); + return; + } + /* fall down to next step */ + ctx->step++; + + case ENABLE_UNSOLICITED_EVENTS_STEP_LAST: + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } } static void @@ -277,80 +452,173 @@ modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self, GAsyncReadyCallback callback, gpointer user_data) { - /* Chain up parent's enable */ - iface_modem_3gpp_parent->enable_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_enable_unsolicited_events_ready, - g_task_new (self, NULL, callback, user_data)); + EnableUnsolicitedEventsContext *ctx; + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + ctx = g_new (EnableUnsolicitedEventsContext, 1); + ctx->step = ENABLE_UNSOLICITED_EVENTS_STEP_FIRST; + g_task_set_task_data (task, ctx, g_free); + + enable_unsolicited_events_context_step (task); } /*****************************************************************************/ -/* Disabling unsolicited events (3GPP interface) */ +/* Disable unsolicited events (3GPP interface) */ + +typedef enum { + DISABLE_UNSOLICITED_EVENTS_STEP_FIRST, + DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_AUTOCSQ, + DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_CNSMOD, + DISABLE_UNSOLICITED_EVENTS_STEP_PARENT, + DISABLE_UNSOLICITED_EVENTS_STEP_LAST, +} DisableUnsolicitedEventsStep; + +typedef struct { + DisableUnsolicitedEventsStep step; +} DisableUnsolicitedEventsContext; static gboolean -modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) +modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } -static const MMBaseModemAtCommand unsolicited_disable_sequence[] = { - { "+CNSMOD=0", 3, FALSE, NULL }, - { "+AUTOCSQ=0", 3, FALSE, NULL }, - { NULL } -}; +static void disable_unsolicited_events_context_step (GTask *task); static void parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self, GAsyncResult *res, GTask *task) { - GError *error = NULL; + DisableUnsolicitedEventsContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); - if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) + if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) { g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); + g_object_unref (task); + return; + } + + /* go to next step */ + ctx->step++; + disable_unsolicited_events_context_step (task); } static void -own_disable_unsolicited_events_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) +cnsmod_set_disabled_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) { - GError *error = NULL; + DisableUnsolicitedEventsContext *ctx; + GError *error = NULL; - mm_base_modem_at_sequence_full_finish (self, res, NULL, &error); - if (error) { - g_task_return_error (task, error); + ctx = g_task_get_task_data (task); + + if (!mm_base_modem_at_command_finish (self, res, &error)) { + mm_dbg ("Couldn't disable automatic access technology reporting: %s", error->message); + g_error_free (error); + } + + /* go to next step */ + ctx->step++; + disable_unsolicited_events_context_step (task); +} + +static void +autocsq_set_disabled_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + DisableUnsolicitedEventsContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + + if (!mm_base_modem_at_command_finish (self, res, &error)) { + mm_dbg ("Couldn't disable automatic signal quality reporting: %s", error->message); + g_error_free (error); + } + + /* go to next step */ + ctx->step++; + disable_unsolicited_events_context_step (task); +} + +static void +disable_unsolicited_events_context_step (GTask *task) +{ + MMBroadbandModemSimtech *self; + DisableUnsolicitedEventsContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case DISABLE_UNSOLICITED_EVENTS_STEP_FIRST: + /* fall down to next step */ + ctx->step++; + + case DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_AUTOCSQ: + if (self->priv->autocsq_support == FEATURE_SUPPORTED) { + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+AUTOCSQ=0", + 20, + FALSE, + (GAsyncReadyCallback)autocsq_set_disabled_ready, + task); + return; + } + /* fall down to next step */ + ctx->step++; + + case DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_CNSMOD: + if (self->priv->cnsmod_support == FEATURE_SUPPORTED) { + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+CNSMOD=0", + 20, + FALSE, + (GAsyncReadyCallback)cnsmod_set_disabled_ready, + task); + return; + } + /* fall down to next step */ + ctx->step++; + + case DISABLE_UNSOLICITED_EVENTS_STEP_PARENT: + iface_modem_3gpp_parent->disable_unsolicited_events ( + MM_IFACE_MODEM_3GPP (self), + (GAsyncReadyCallback)parent_disable_unsolicited_events_ready, + task); + return; + + case DISABLE_UNSOLICITED_EVENTS_STEP_LAST: + g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - - /* Next, chain up parent's disable */ - 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) +modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self, + GAsyncReadyCallback callback, + gpointer user_data) { - /* Our own disable first */ - mm_base_modem_at_sequence_full ( - MM_BASE_MODEM (self), - mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), - unsolicited_disable_sequence, - NULL, /* response_processor_context */ - NULL, /* response_processor_context_free */ - NULL, /* cancellable */ - (GAsyncReadyCallback)own_disable_unsolicited_events_ready, - g_task_new (self, NULL, callback, user_data)); + DisableUnsolicitedEventsContext *ctx; + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + ctx = g_new (DisableUnsolicitedEventsContext, 1); + ctx->step = DISABLE_UNSOLICITED_EVENTS_STEP_FIRST; + g_task_set_task_data (task, ctx, g_free); + + disable_unsolicited_events_context_step (task); } /*****************************************************************************/ @@ -409,21 +677,31 @@ cnsmod_query_ready (MMBaseModem *self, } static void -load_access_technologies (MMIfaceModem *self, +load_access_technologies (MMIfaceModem *_self, GAsyncReadyCallback callback, gpointer user_data) { - GTask *task; + MMBroadbandModemSimtech *self; + GTask *task; + self = MM_BROADBAND_MODEM_SIMTECH (_self); task = g_task_new (self, NULL, callback, user_data); /* Launch query only for 3GPP modems */ - if (!mm_iface_modem_is_3gpp (self)) { + if (!mm_iface_modem_is_3gpp (_self)) { g_task_return_int (task, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); g_object_unref (task); return; } + g_assert (self->priv->cnsmod_support != FEATURE_SUPPORT_UNKNOWN); + if (self->priv->cnsmod_support == FEATURE_NOT_SUPPORTED) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Loading access technologies with +CNSMOD is not supported"); + g_object_unref (task); + return; + } + mm_base_modem_at_command ( MM_BASE_MODEM (self), "AT+CNSMOD?", @@ -942,6 +1220,9 @@ mm_broadband_modem_simtech_init (MMBroadbandModemSimtech *self) MM_TYPE_BROADBAND_MODEM_SIMTECH, MMBroadbandModemSimtechPrivate); + self->priv->cnsmod_support = FEATURE_SUPPORT_UNKNOWN; + self->priv->autocsq_support = FEATURE_SUPPORT_UNKNOWN; + self->priv->cnsmod_regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); self->priv->csq_regex = g_regex_new ("\\r\\n\\+CSQ:\\s*(\\d+),(\\d+)\\r\\n", |