[PATCH v2 1/4] iface-modem: consolidate signal quality and access tech polling
Aleksander Morgado
aleksander at aleksander.es
Tue Jun 6 13:26:56 UTC 2017
On 30/05/17 20:09, Aleksander Morgado wrote:
> Plugins have two ways to update signal quality and access technology
> values: via unsolicited messages or via polling periodically.
>
> Instead of keeping separate contexts for polling signal quality and
> access technology values, we setup a common timeout to trigger
> both. This allows us to simplify in which case the explicit update is
> required, whenever one is needed to be explicitly updated, the other
> one should also be.
>
> The logic now also allows plugins to return an UNSUPPORTED error in
> either load_signal_quality() and/or load_access_technologies() to tell
> the interface logic that the polling of the specific item shouldn't be
> performed (e.g. if the updates are expected via unsolicited messages).
>
> If both signal quality and access technology polling is flagged as
> disabled, we totally disable the polling logic internally.
>
> The new SignalCheckContext is bound to the lifetime of the object so
> that we can keep the value of the supported flags until the object is
> destroyed.
> ---
Pushed to git master.
> plugins/cinterion/mm-broadband-modem-cinterion.c | 8 +-
> src/mm-iface-modem-3gpp.c | 7 +-
> src/mm-iface-modem.c | 589 ++++++++++++-----------
> src/mm-iface-modem.h | 6 +-
> 4 files changed, 312 insertions(+), 298 deletions(-)
>
> diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c
> index 186bf80b..d829fe15 100644
> --- a/plugins/cinterion/mm-broadband-modem-cinterion.c
> +++ b/plugins/cinterion/mm-broadband-modem-cinterion.c
> @@ -853,8 +853,8 @@ allowed_access_technology_update_ready (MMBroadbandModemCinterion *self,
> if (error)
> g_task_return_error (task, error);
> else {
> - /* Request immediate access tech update */
> - mm_iface_modem_refresh_access_technologies (MM_IFACE_MODEM (self));
> + /* Request immediate signal update */
> + mm_iface_modem_refresh_signal (MM_IFACE_MODEM (self));
> g_task_return_boolean (task, TRUE);
> }
> g_object_unref (task);
> @@ -1140,8 +1140,8 @@ scfg_set_ready (MMBaseModem *self,
> /* Let the error be critical */
> g_simple_async_result_take_error (operation_result, error);
> else {
> - /* Request immediate access tech update */
> - mm_iface_modem_refresh_access_technologies (MM_IFACE_MODEM (self));
> + /* Request immediate signal update */
> + mm_iface_modem_refresh_signal (MM_IFACE_MODEM (self));
> g_simple_async_result_set_op_res_gboolean (operation_result, TRUE);
> }
>
> diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c
> index 8b93550a..bcd12e85 100644
> --- a/src/mm-iface-modem-3gpp.c
> +++ b/src/mm-iface-modem-3gpp.c
> @@ -307,8 +307,11 @@ run_registration_checks_ready (MMIfaceModem3gpp *self,
> current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY ||
> current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED ||
> current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) {
> - /* Request immediate access tech update */
> - mm_iface_modem_refresh_access_technologies (MM_IFACE_MODEM (ctx->self));
> + /* Request immediate access tech and signal update: we may have changed
> + * from home to roaming or viceversa, both registered states, so there
> + * wouldn't be an explicit refresh triggered from the modem interface as
> + * the modem never got un-registered during the sequence. */
> + mm_iface_modem_refresh_signal (MM_IFACE_MODEM (ctx->self));
> mm_dbg ("Modem is currently registered in a 3GPP network");
> g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> register_in_network_context_complete_and_free (ctx);
> diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
> index ecb351a0..223f2785 100644
> --- a/src/mm-iface-modem.c
> +++ b/src/mm-iface-modem.c
> @@ -29,21 +29,20 @@
> #include "mm-log.h"
> #include "mm-context.h"
>
> -#define SIGNAL_QUALITY_RECENT_TIMEOUT_SEC 60
> -#define SIGNAL_QUALITY_INITIAL_CHECK_TIMEOUT_SEC 3
> -#define SIGNAL_QUALITY_CHECK_TIMEOUT_SEC 30
> -#define ACCESS_TECHNOLOGIES_CHECK_TIMEOUT_SEC 30
> +#define SIGNAL_QUALITY_RECENT_TIMEOUT_SEC 60
>
> -#define STATE_UPDATE_CONTEXT_TAG "state-update-context-tag"
> -#define SIGNAL_QUALITY_UPDATE_CONTEXT_TAG "signal-quality-update-context-tag"
> -#define SIGNAL_QUALITY_CHECK_CONTEXT_TAG "signal-quality-check-context-tag"
> -#define ACCESS_TECHNOLOGIES_CHECK_CONTEXT_TAG "access-technologies-check-context-tag"
> -#define RESTART_INITIALIZE_IDLE_TAG "restart-initialize-tag"
> +#define SIGNAL_CHECK_INITIAL_RETRIES 5
> +#define SIGNAL_CHECK_INITIAL_TIMEOUT_SEC 3
> +#define SIGNAL_CHECK_TIMEOUT_SEC 30
> +
> +#define STATE_UPDATE_CONTEXT_TAG "state-update-context-tag"
> +#define SIGNAL_QUALITY_UPDATE_CONTEXT_TAG "signal-quality-update-context-tag"
> +#define SIGNAL_CHECK_CONTEXT_TAG "signal-check-context-tag"
> +#define RESTART_INITIALIZE_IDLE_TAG "restart-initialize-tag"
>
> static GQuark state_update_context_quark;
> static GQuark signal_quality_update_context_quark;
> -static GQuark signal_quality_check_context_quark;
> -static GQuark access_technologies_check_context_quark;
> +static GQuark signal_check_context_quark;
> static GQuark restart_initialize_idle_quark;
>
> /*****************************************************************************/
> @@ -943,152 +942,6 @@ mm_iface_modem_update_access_technologies (MMIfaceModem *self,
> /*****************************************************************************/
>
> typedef struct {
> - guint timeout_source;
> - gboolean running;
> -} AccessTechnologiesCheckContext;
> -
> -static void
> -access_technologies_check_context_free (AccessTechnologiesCheckContext *ctx)
> -{
> - if (ctx->timeout_source)
> - g_source_remove (ctx->timeout_source);
> - g_free (ctx);
> -}
> -
> -static void
> -access_technologies_check_ready (MMIfaceModem *self,
> - GAsyncResult *res)
> -{
> - GError *error = NULL;
> - MMModemAccessTechnology access_technologies = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
> - guint mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY;
> - AccessTechnologiesCheckContext *ctx;
> -
> - if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies_finish (
> - self,
> - res,
> - &access_technologies,
> - &mask,
> - &error)) {
> - /* Ignore issues when the operation is unsupported, don't even log */
> - if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED))
> - mm_dbg ("Couldn't refresh access technologies: '%s'", error->message);
> - g_error_free (error);
> - } else
> - mm_iface_modem_update_access_technologies (self, access_technologies, mask);
> -
> - /* Remove the running tag. Note that the context may have been removed by
> - * mm_iface_modem_shutdown when this function is invoked as a callback of
> - * load_access_technologies. */
> - ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_context_quark);
> - if (ctx)
> - ctx->running = FALSE;
> -}
> -
> -static gboolean
> -periodic_access_technologies_check (MMIfaceModem *self)
> -{
> - AccessTechnologiesCheckContext *ctx;
> -
> - ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_context_quark);
> -
> - /* Only launch a new one if not one running already OR if the last one run
> - * was more than 15s ago. */
> - if (!ctx->running) {
> - ctx->running = TRUE;
> - MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies (
> - self,
> - (GAsyncReadyCallback)access_technologies_check_ready,
> - NULL);
> - }
> -
> - return G_SOURCE_CONTINUE;
> -}
> -
> -void
> -mm_iface_modem_refresh_access_technologies (MMIfaceModem *self)
> -{
> - AccessTechnologiesCheckContext *ctx;
> -
> - if (G_UNLIKELY (!access_technologies_check_context_quark))
> - access_technologies_check_context_quark = (g_quark_from_static_string (
> - ACCESS_TECHNOLOGIES_CHECK_CONTEXT_TAG));
> -
> - ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_context_quark);
> - if (!ctx)
> - return;
> -
> - /* Re-set timeout */
> - if (ctx->timeout_source)
> - g_source_remove (ctx->timeout_source);
> - ctx->timeout_source = g_timeout_add_seconds (ACCESS_TECHNOLOGIES_CHECK_TIMEOUT_SEC,
> - (GSourceFunc)periodic_access_technologies_check,
> - self);
> -
> - /* Get first access technology value */
> - periodic_access_technologies_check (self);
> -}
> -
> -static void
> -periodic_access_technologies_check_disable (MMIfaceModem *self)
> -{
> - if (G_UNLIKELY (!access_technologies_check_context_quark))
> - access_technologies_check_context_quark = (g_quark_from_static_string (
> - ACCESS_TECHNOLOGIES_CHECK_CONTEXT_TAG));
> -
> - /* Clear access technology */
> - mm_iface_modem_update_access_technologies (self,
> - MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN,
> - MM_MODEM_ACCESS_TECHNOLOGY_ANY);
> -
> - /* Overwriting the data will free the previous context */
> - g_object_set_qdata (G_OBJECT (self),
> - access_technologies_check_context_quark,
> - NULL);
> -
> - mm_dbg ("Periodic access technology checks disabled");
> -}
> -
> -static void
> -periodic_access_technologies_check_enable (MMIfaceModem *self)
> -{
> - AccessTechnologiesCheckContext *ctx;
> -
> - if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies ||
> - !MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies_finish) {
> - /* If loading access technology not supported, don't even bother setting up
> - * a timeout */
> - return;
> - }
> -
> - if (G_UNLIKELY (!access_technologies_check_context_quark))
> - access_technologies_check_context_quark = (g_quark_from_static_string (
> - ACCESS_TECHNOLOGIES_CHECK_CONTEXT_TAG));
> -
> - ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_context_quark);
> -
> - /* If context is already there, we're already enabled */
> - if (ctx) {
> - periodic_access_technologies_check (self);
> - return;
> - }
> -
> - /* Create context and keep it as object data */
> - mm_dbg ("Periodic access technology checks enabled");
> - ctx = g_new0 (AccessTechnologiesCheckContext, 1);
> - g_object_set_qdata_full (G_OBJECT (self),
> - access_technologies_check_context_quark,
> - ctx,
> - (GDestroyNotify)access_technologies_check_context_free);
> -
> - /* Get first and setup timeout */
> - mm_iface_modem_refresh_access_technologies (self);
> -}
> -
> -/*****************************************************************************/
> -
> -typedef struct {
> - time_t last_update;
> guint recent_timeout_source;
> } SignalQualityUpdateContext;
>
> @@ -1100,20 +953,6 @@ signal_quality_update_context_free (SignalQualityUpdateContext *ctx)
> g_free (ctx);
> }
>
> -static time_t
> -get_last_signal_quality_update_time (MMIfaceModem *self)
> -{
> - SignalQualityUpdateContext *ctx;
> -
> - if (G_UNLIKELY (!signal_quality_update_context_quark))
> - signal_quality_update_context_quark = (g_quark_from_static_string (
> - SIGNAL_QUALITY_UPDATE_CONTEXT_TAG));
> -
> - ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_update_context_quark);
> -
> - return (ctx ? ctx->last_update : 0);
> -}
> -
> static gboolean
> expire_signal_quality (MMIfaceModem *self)
> {
> @@ -1187,9 +1026,6 @@ update_signal_quality (MMIfaceModem *self,
> (GDestroyNotify)signal_quality_update_context_free);
> }
>
> - /* Keep current timestamp */
> - ctx->last_update = time (NULL);
> -
> /* Note: we always set the new value, even if the signal quality level
> * is the same, in order to provide an up to date 'recent' flag.
> * The only exception being if 'expire' is FALSE; in that case we assume
> @@ -1229,142 +1065,336 @@ mm_iface_modem_update_signal_quality (MMIfaceModem *self,
> }
>
> /*****************************************************************************/
> +/* Signal info (quality and access technology) polling */
> +
> +typedef enum {
> + SIGNAL_CHECK_STEP_NONE,
> + SIGNAL_CHECK_STEP_FIRST,
> + SIGNAL_CHECK_STEP_SIGNAL_QUALITY,
> + SIGNAL_CHECK_STEP_ACCESS_TECHNOLOGIES,
> + SIGNAL_CHECK_STEP_LAST,
> +} SignalCheckStep;
>
> typedef struct {
> - guint interval;
> - guint initial_retries;
> - guint timeout_source;
> - gboolean running;
> -} SignalQualityCheckContext;
> + gboolean enabled;
> + guint interval;
> + guint initial_retries;
> + guint timeout_source;
> +
> + /* Values polled in this iteration */
> + guint signal_quality;
> + MMModemAccessTechnology access_technologies;
> + guint access_technologies_mask;
> +
> + /* If both these are unset we'll automatically stop polling */
> + gboolean signal_quality_polling_supported;
> + gboolean access_technology_polling_supported;
> +
> + /* Steps triggered when polling active */
> + SignalCheckStep running_step;
> +} SignalCheckContext;
>
> static void
> -signal_quality_check_context_free (SignalQualityCheckContext *ctx)
> +signal_check_context_free (SignalCheckContext *ctx)
> {
> if (ctx->timeout_source)
> g_source_remove (ctx->timeout_source);
> - g_free (ctx);
> + g_slice_free (SignalCheckContext, ctx);
> +}
> +
> +static SignalCheckContext *
> +get_signal_check_context (MMIfaceModem *self)
> +{
> + SignalCheckContext *ctx;
> +
> + if (G_UNLIKELY (!signal_check_context_quark))
> + signal_check_context_quark = (g_quark_from_static_string (
> + SIGNAL_CHECK_CONTEXT_TAG));
> +
> + ctx = g_object_get_qdata (G_OBJECT (self), signal_check_context_quark);
> + if (!ctx) {
> + /* Create context and attach it to the object */
> + ctx = g_slice_new0 (SignalCheckContext);
> + ctx->running_step = SIGNAL_CHECK_STEP_NONE;
> +
> + /* Initially assume supported if load_access_technologies() is
> + * implemented. If the plugin reports an UNSUPPORTED error we'll clear
> + * this flag and no longer poll. */
> + ctx->access_technology_polling_supported = (MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies &&
> + MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies_finish);
> +
> + /* Initially assume supported if load_signal_quality() is
> + * implemented. If the plugin reports an UNSUPPORTED error we'll clear
> + * this flag and no longer poll. */
> + ctx->signal_quality_polling_supported = (MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality &&
> + MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish);
> +
> + g_object_set_qdata_full (G_OBJECT (self), signal_check_context_quark,
> + ctx, (GDestroyNotify) signal_check_context_free);
> + }
> +
> + g_assert (ctx);
> + return ctx;
> }
>
> -static gboolean periodic_signal_quality_check (MMIfaceModem *self);
> +static void periodic_signal_check_disable (MMIfaceModem *self,
> + gboolean clear);
> +static gboolean periodic_signal_check_cb (MMIfaceModem *self);
> +static void peridic_signal_check_step (MMIfaceModem *self);
> +
> +static void
> +access_technologies_check_ready (MMIfaceModem *self,
> + GAsyncResult *res)
> +{
> + GError *error = NULL;
> + SignalCheckContext *ctx;
> +
> + ctx = get_signal_check_context (self);
> +
> + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies_finish (
> + self,
> + res,
> + &ctx->access_technologies,
> + &ctx->access_technologies_mask,
> + &error)) {
> + /* Did the plugin report that polling access technology is unsupported? */
> + if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {
> + mm_dbg ("Polling to refresh access technologies is unsupported");
> + ctx->access_technology_polling_supported = FALSE;
> + } else
> + mm_dbg ("Couldn't refresh access technologies: '%s'", error->message);
> + g_error_free (error);
> + }
> + /* We may have been disabled while this command was running. */
> + else if (ctx->enabled)
> + mm_iface_modem_update_access_technologies (self, ctx->access_technologies, ctx->access_technologies_mask);
> +
> + /* Go on */
> + ctx->running_step++;
> + peridic_signal_check_step (self);
> +}
>
> static void
> signal_quality_check_ready (MMIfaceModem *self,
> GAsyncResult *res)
> {
> - GError *error = NULL;
> - guint signal_quality;
> - SignalQualityCheckContext *ctx;
> + GError *error = NULL;
> + SignalCheckContext *ctx;
> +
> + ctx = get_signal_check_context (self);
>
> - signal_quality = MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish (self,
> - res,
> - &error);
> + ctx->signal_quality = MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish (self, res, &error);
> if (error) {
> - mm_dbg ("Couldn't refresh signal quality: '%s'", error->message);
> + /* Did the plugin report that polling signal quality is unsupported? */
> + if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {
> + mm_dbg ("Polling to refresh signal quality is unsupported");
> + ctx->signal_quality_polling_supported = FALSE;
> + } else
> + mm_dbg ("Couldn't refresh signal quality: '%s'", error->message);
> g_error_free (error);
> - } else
> - update_signal_quality (self, signal_quality, TRUE);
> -
> - /* Remove the running tag. Note that the context may have been removed by
> - * mm_iface_modem_shutdown when this function is invoked as a callback of
> - * load_signal_quality. */
> - ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_check_context_quark);
> - if (ctx) {
> - if (ctx->interval == SIGNAL_QUALITY_INITIAL_CHECK_TIMEOUT_SEC &&
> - (signal_quality != 0 || --ctx->initial_retries == 0)) {
> - ctx->interval = SIGNAL_QUALITY_CHECK_TIMEOUT_SEC;
> - if (ctx->timeout_source) {
> - mm_dbg ("Periodic signal quality checks rescheduled (interval = %ds)", ctx->interval);
> - g_source_remove(ctx->timeout_source);
> - ctx->timeout_source = g_timeout_add_seconds (ctx->interval,
> - (GSourceFunc)periodic_signal_quality_check,
> - self);
> + }
> + /* We may have been disabled while this command was running. */
> + else if (ctx->enabled)
> + update_signal_quality (self, ctx->signal_quality, TRUE);
> +
> + /* Go on */
> + ctx->running_step++;
> + peridic_signal_check_step (self);
> +}
> +
> +static void
> +peridic_signal_check_step (MMIfaceModem *self)
> +{
> + SignalCheckContext *ctx;
> +
> + ctx = get_signal_check_context (self);
> +
> + switch (ctx->running_step) {
> + case SIGNAL_CHECK_STEP_NONE:
> + g_assert_not_reached ();
> +
> + case SIGNAL_CHECK_STEP_FIRST:
> + /* Fall down to next step */
> + ctx->running_step++;
> +
> + case SIGNAL_CHECK_STEP_SIGNAL_QUALITY:
> + if (ctx->enabled && ctx->signal_quality_polling_supported) {
> + MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality (
> + self, (GAsyncReadyCallback)signal_quality_check_ready, NULL);
> + return;
> + }
> + /* Fall down to next step */
> + ctx->running_step++;
> +
> + case SIGNAL_CHECK_STEP_ACCESS_TECHNOLOGIES:
> + if (ctx->enabled && ctx->access_technology_polling_supported) {
> + MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies (
> + self, (GAsyncReadyCallback)access_technologies_check_ready, NULL);
> + return;
> + }
> + /* Fall down to next step */
> + ctx->running_step++;
> +
> + case SIGNAL_CHECK_STEP_LAST:
> + /* Flag as sequence finished */
> + ctx->running_step = SIGNAL_CHECK_STEP_NONE;
> +
> + /* If we have been disabled while we were running the steps, we don't
> + * do anything else. */
> + if (!ctx->enabled) {
> + mm_dbg ("Periodic signal checks not rescheduled: disabled");
> + return;
> + }
> +
> + /* If both tasks are unsupported, implicitly disable. Do NOT clear the
> + * values, because if we're told they are unsupported it may be that
> + * they're really updated via unsolicited messages. */
> + if (!ctx->access_technology_polling_supported && !ctx->signal_quality_polling_supported) {
> + mm_dbg ("Periodic signal checks not supported");
> + periodic_signal_check_disable (self, FALSE);
> + return;
> + }
> +
> + /* Schedule when we poll next time.
> + * Initially we poll at a higher frequency until we get valid signal
> + * quality and access technology values. As soon as we get them, OR if
> + * we made too many retries at a high frequency, we fallback to the
> + * slower polling. */
> + if (ctx->interval == SIGNAL_CHECK_INITIAL_TIMEOUT_SEC) {
> + gboolean signal_quality_ready;
> + gboolean access_technology_ready;
> +
> + /* Signal quality is ready if unsupported or if we got a valid
> + * value reported */
> + signal_quality_ready = (!ctx->signal_quality_polling_supported || (ctx->signal_quality != 0));
> + /* Access technology is ready if unsupported or if we got a valid
> + * value reported */
> + access_technology_ready = (!ctx->access_technology_polling_supported ||
> + ((ctx->access_technologies & ctx->access_technologies_mask) != MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN));
> +
> + if (signal_quality_ready && access_technology_ready) {
> + mm_dbg ("Initial signal quality and access technology ready: fallback to default frequency");
> + ctx->interval = SIGNAL_CHECK_TIMEOUT_SEC;
> + } else if (--ctx->initial_retries == 0) {
> + mm_dbg ("Too many periodic signal checks at high frequency: fallback to default frequency");
> + ctx->interval = SIGNAL_CHECK_TIMEOUT_SEC;
> }
> }
> - ctx->running = FALSE;
> +
> + mm_dbg ("Periodic signal quality checks scheduled in %ds", ctx->interval);
> + g_assert (!ctx->timeout_source);
> + ctx->timeout_source = g_timeout_add_seconds (ctx->interval, (GSourceFunc) periodic_signal_check_cb, self);
> + return;
> }
> }
>
> static gboolean
> -periodic_signal_quality_check (MMIfaceModem *self)
> +periodic_signal_check_cb (MMIfaceModem *self)
> {
> - SignalQualityCheckContext *ctx;
> + SignalCheckContext *ctx;
>
> - ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_check_context_quark);
> + ctx = get_signal_check_context (self);
> + g_assert (ctx->enabled);
>
> - /* Only launch a new one if not one running already OR if the last one run
> - * was more than 15s ago. */
> - if (!ctx->running ||
> - (time (NULL) - get_last_signal_quality_update_time (self) > (ctx->interval / 2))) {
> - ctx->running = TRUE;
> - MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality (
> - self,
> - (GAsyncReadyCallback)signal_quality_check_ready,
> - NULL);
> - }
> + /* Start the sequence */
> + ctx->running_step = SIGNAL_CHECK_STEP_FIRST;
> + ctx->signal_quality = 0;
> + ctx->access_technologies = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
> + ctx->access_technologies_mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY;
> + peridic_signal_check_step (self);
>
> - return G_SOURCE_CONTINUE;
> + /* Remove the timeout and clear the source id */
> + if (ctx->timeout_source)
> + ctx->timeout_source = 0;
> + return G_SOURCE_REMOVE;
> }
>
> -static void
> -periodic_signal_quality_check_disable (MMIfaceModem *self)
> +void
> +mm_iface_modem_refresh_signal (MMIfaceModem *self)
> {
> - if (G_UNLIKELY (!signal_quality_check_context_quark))
> - signal_quality_check_context_quark = (g_quark_from_static_string (
> - SIGNAL_QUALITY_CHECK_CONTEXT_TAG));
> + SignalCheckContext *ctx;
> +
> + /* Don't refresh polling if we're not enabled */
> + ctx = get_signal_check_context (self);
> + if (!ctx->enabled) {
> + mm_dbg ("Periodic signal check refresh ignored: checks not enabled");
> + return;
> + }
>
> - /* Clear signal quality */
> - update_signal_quality (self, 0, FALSE);
> + /* Don't refresh if we're already doing it */
> + if (ctx->running_step != SIGNAL_CHECK_STEP_NONE) {
> + mm_dbg ("Periodic signal check refresh ignored: check already running");
> + return;
> + }
> +
> + mm_dbg ("Periodic signal check refresh requested");
> +
> + /* Remove the scheduled timeout as we're going to refresh
> + * right away */
> + if (ctx->timeout_source) {
> + g_source_remove (ctx->timeout_source);
> + ctx->timeout_source = 0;
> + }
>
> - /* Overwriting the data will free the previous context */
> - g_object_set_qdata (G_OBJECT (self),
> - signal_quality_check_context_quark,
> - NULL);
> + /* Reset refresh rate and initial retries when we're asked to refresh signal
> + * so that we poll at a higher frequency */
> + ctx->interval = SIGNAL_CHECK_INITIAL_TIMEOUT_SEC;
> + ctx->initial_retries = SIGNAL_CHECK_INITIAL_RETRIES;
>
> - mm_dbg ("Periodic signal quality checks disabled");
> + /* Start sequence */
> + periodic_signal_check_cb (self);
> }
>
> static void
> -periodic_signal_quality_check_enable (MMIfaceModem *self)
> +periodic_signal_check_disable (MMIfaceModem *self,
> + gboolean clear)
> {
> - SignalQualityCheckContext *ctx;
> + SignalCheckContext *ctx;
>
> - if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality ||
> - !MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish) {
> - /* If loading signal quality not supported, don't even bother setting up
> - * a timeout */
> + ctx = get_signal_check_context (self);
> + if (!ctx->enabled)
> return;
> +
> + /* Clear access technology and signal quality */
> + if (clear) {
> + update_signal_quality (self, 0, FALSE);
> + mm_iface_modem_update_access_technologies (self,
> + MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN,
> + MM_MODEM_ACCESS_TECHNOLOGY_ANY);
> }
>
> - if (G_UNLIKELY (!signal_quality_check_context_quark))
> - signal_quality_check_context_quark = (g_quark_from_static_string (
> - SIGNAL_QUALITY_CHECK_CONTEXT_TAG));
> + /* Remove scheduled timeout */
> + if (ctx->timeout_source) {
> + g_source_remove (ctx->timeout_source);
> + ctx->timeout_source = 0;
> + }
> +
> + ctx->enabled = FALSE;
> + mm_dbg ("Periodic signal checks disabled");
> +}
> +
> +static void
> +periodic_signal_check_enable (MMIfaceModem *self)
> +{
> + SignalCheckContext *ctx;
>
> - ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_check_context_quark);
> + ctx = get_signal_check_context (self);
>
> - /* If context is already there, we're already enabled */
> - if (ctx) {
> - periodic_signal_quality_check (self);
> + /* If polling access technology and signal quality not supported, don't even
> + * bother trying. */
> + if (!ctx->signal_quality_polling_supported && !ctx->access_technology_polling_supported) {
> + mm_dbg ("Not enabling periodic signal checks: unsupported");
> return;
> }
>
> - /* Create context and keep it as object data */
> - ctx = g_new0 (SignalQualityCheckContext, 1);
> - /* Schedule the signal quality check using a shorter period, up to 5
> - * periods, initially until a non-zero signal quality value is obtained
> - * and then switch back to the normal period. */
> - ctx->interval = SIGNAL_QUALITY_INITIAL_CHECK_TIMEOUT_SEC;
> - ctx->initial_retries = 5;
> - mm_dbg ("Periodic signal quality checks enabled (interval = %ds)", ctx->interval);
> - ctx->timeout_source = g_timeout_add_seconds (ctx->interval,
> - (GSourceFunc)periodic_signal_quality_check,
> - self);
> - g_object_set_qdata_full (G_OBJECT (self),
> - signal_quality_check_context_quark,
> - ctx,
> - (GDestroyNotify)signal_quality_check_context_free);
> + /* Log and flag as enabled */
> + if (!ctx->enabled) {
> + mm_dbg ("Periodic signal checks enabled");
> + ctx->enabled = TRUE;
> + }
>
> - /* Get first signal quality value */
> - periodic_signal_quality_check (self);
> + /* And refresh, which will trigger the first check at high frequency*/
> + mm_iface_modem_refresh_signal (self);
> }
>
> /*****************************************************************************/
> @@ -1456,18 +1486,12 @@ __iface_modem_update_state_internal (MMIfaceModem *self,
>
> /* If we go to a registered/connected state (from unregistered), setup
> * signal quality and access technologies periodic retrieval */
> - if (new_state >= MM_MODEM_STATE_REGISTERED &&
> - old_state < MM_MODEM_STATE_REGISTERED) {
> - periodic_signal_quality_check_enable (self);
> - periodic_access_technologies_check_enable (self);
> - }
> + if (new_state >= MM_MODEM_STATE_REGISTERED && old_state < MM_MODEM_STATE_REGISTERED)
> + periodic_signal_check_enable (self);
> /* If we go from a registered/connected state to unregistered,
> * cleanup signal quality retrieval */
> - else if (old_state >= MM_MODEM_STATE_REGISTERED &&
> - new_state < MM_MODEM_STATE_REGISTERED) {
> - periodic_signal_quality_check_disable (self);
> - periodic_access_technologies_check_disable (self);
> - }
> + else if (old_state >= MM_MODEM_STATE_REGISTERED && new_state < MM_MODEM_STATE_REGISTERED)
> + periodic_signal_check_disable (self, TRUE);
> }
>
> if (skeleton)
> @@ -4906,14 +4930,9 @@ mm_iface_modem_initialize (MMIfaceModem *self,
> void
> mm_iface_modem_shutdown (MMIfaceModem *self)
> {
> - /* Remove SignalQualityCheckContext object to make sure any pending
> - * invocation of periodic_signal_quality_check is cancelled before
> - * SignalQualityUpdateContext is removed (as signal_quality_check_ready may
> - * call update_signal_quality). */
> - if (G_LIKELY (signal_quality_check_context_quark))
> - g_object_set_qdata (G_OBJECT (self),
> - signal_quality_check_context_quark,
> - NULL);
> + /* Make sure signal polling is disabled. No real need to clear values, as
> + * we're shutting down the interface anyway. */
> + periodic_signal_check_disable (self, FALSE);
>
> /* Remove SignalQualityUpdateContext object to make sure any pending
> * invocation of expire_signal_quality is canceled before the DBus skeleton
> @@ -4923,14 +4942,6 @@ mm_iface_modem_shutdown (MMIfaceModem *self)
> signal_quality_update_context_quark,
> NULL);
>
> - /* Remove AccessTechnologiesCheckContext object to make sure any pending
> - * invocation of periodic_access_technologies_check is canceled before the
> - * DBus skeleton is removed. */
> - if (G_LIKELY (access_technologies_check_context_quark))
> - g_object_set_qdata (G_OBJECT (self),
> - access_technologies_check_context_quark,
> - NULL);
> -
> /* Remove running restart initialization idle, if any */
> if (G_LIKELY (restart_initialize_idle_quark))
> g_object_set_qdata (G_OBJECT (self),
> diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
> index 517c651d..17ded5bc 100644
> --- a/src/mm-iface-modem.h
> +++ b/src/mm-iface-modem.h
> @@ -444,13 +444,13 @@ void mm_iface_modem_update_access_technologies (MMIfaceModem *self,
> MMModemAccessTechnology access_tech,
> guint32 mask);
>
> -/* Allow requesting to refresh access tech */
> -void mm_iface_modem_refresh_access_technologies (MMIfaceModem *self);
> -
> /* Allow updating signal quality */
> void mm_iface_modem_update_signal_quality (MMIfaceModem *self,
> guint signal_quality);
>
> +/* Allow requesting to refresh signal via polling */
> +void mm_iface_modem_refresh_signal (MMIfaceModem *self);
> +
> /* Allow setting allowed modes */
> void mm_iface_modem_set_current_modes (MMIfaceModem *self,
> MMModemMode allowed,
> --
> 2.13.0
>
--
Aleksander
https://aleksander.es
More information about the ModemManager-devel
mailing list