iface-modem-signal: polling and thresholds only in effect if modem enabled

If the modem is disabled:
 * Polling is completely halted.
 * Thresholds are disabled.
 * The user is allowed to call Setup() or SetupThresholds() to change
   the settings, even if the actual polling or thresholds setup isn't
   in effect.

When the modem is enabled:
 * Polling will be started if there is a existing polling rate.
 * Thresholds will be setup based on the existing threshold settings.

Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/504
This commit is contained in:
Aleksander Morgado
2022-02-11 23:35:48 +01:00
parent 5d953bbe8d
commit 45102fcd60
2 changed files with 186 additions and 111 deletions

View File

@@ -15,7 +15,7 @@
This interface provides access to extended signal quality information. This interface provides access to extended signal quality information.
This interface will only be available once the modem is ready to be This interface will only be functional once the modem is ready to be
registered in the cellular network. 3GPP devices will require a valid registered in the cellular network. 3GPP devices will require a valid
unlocked SIM card before any of the features in the interface can be unlocked SIM card before any of the features in the interface can be
used. used.
@@ -27,6 +27,10 @@
Both Setup() and SetupThresholds() can also be used at the same time if Both Setup() and SetupThresholds() can also be used at the same time if
required, e.g. if they report different signal quality measurement types. required, e.g. if they report different signal quality measurement types.
The thresholds and polling setup will only be in effect if the modem is
in enabled state. Changing the settings with Setup() or SetupThresholds()
is also possible while in disabled state, though.
--> -->
<interface name="org.freedesktop.ModemManager1.Modem.Signal"> <interface name="org.freedesktop.ModemManager1.Modem.Signal">

View File

@@ -35,10 +35,12 @@ static GQuark supported_quark;
static GQuark private_quark; static GQuark private_quark;
typedef struct { typedef struct {
/* polling-based reporting enabled */ /* interface enabled */
gboolean enabled;
/* polling-based reporting */
guint rate; guint rate;
guint timeout_source; guint timeout_source;
/* threshold-based reporting enabled */ /* threshold-based reporting */
guint rssi_threshold; guint rssi_threshold;
gboolean error_rate_threshold; gboolean error_rate_threshold;
} Private; } Private;
@@ -155,7 +157,7 @@ mm_iface_modem_signal_update (MMIfaceModemSignal *self,
Private *priv; Private *priv;
priv = get_private (self); priv = get_private (self);
if (!priv->rate && !priv->rssi_threshold && !priv->error_rate_threshold) { if (!priv->enabled || (!priv->rate && !priv->rssi_threshold && !priv->error_rate_threshold)) {
mm_obj_dbg (self, "skipping extended signal information update..."); mm_obj_dbg (self, "skipping extended signal information update...");
return; return;
} }
@@ -172,13 +174,14 @@ check_interface_reset (MMIfaceModemSignal *self)
priv = get_private (self); priv = get_private (self);
if (!priv->rate && !priv->rssi_threshold && !priv->error_rate_threshold) { if (!priv->enabled || (!priv->rate && !priv->rssi_threshold && !priv->error_rate_threshold)) {
mm_obj_dbg (self, "reseting extended signal information..."); mm_obj_dbg (self, "reseting extended signal information...");
mm_iface_modem_signal_update (self, NULL, NULL, NULL, NULL, NULL, NULL); internal_signal_update (self, NULL, NULL, NULL, NULL, NULL, NULL);
} }
} }
/*****************************************************************************/ /*****************************************************************************/
/* Polling setup management */
static void static void
load_values_ready (MMIfaceModemSignal *self, load_values_ready (MMIfaceModemSignal *self,
@@ -220,51 +223,96 @@ polling_context_cb (MMIfaceModemSignal *self)
return G_SOURCE_CONTINUE; return G_SOURCE_CONTINUE;
} }
static gboolean static void
polling_restart (MMIfaceModemSignal *self, polling_restart (MMIfaceModemSignal *self)
guint rate,
GError **error)
{ {
Private *priv; Private *priv;
gboolean polling_setup;
priv = get_private (self); priv = get_private (self);
polling_setup = (priv->enabled && priv->rate);
/* Update the rate in the interface if it changed */ mm_obj_dbg (self, "%s extended signal information polling: interface %s, rate %u seconds",
if (priv->rate != rate) { polling_setup ? "setting up" : "cleaning up",
g_autoptr(MmGdbusModemSignalSkeleton) skeleton = NULL; priv->enabled ? "enabled" : "disabled",
priv->rate);
g_object_get (self, /* Stop polling */
MM_IFACE_MODEM_SIGNAL_DBUS_SKELETON, &skeleton, if (!polling_setup) {
NULL);
if (!skeleton) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Couldn't get interface skeleton");
return FALSE;
}
mm_gdbus_modem_signal_set_rate (MM_GDBUS_MODEM_SIGNAL (skeleton), rate);
priv->rate = rate;
}
/* Polling disabled by user? */
if (rate == 0) {
mm_obj_dbg (self, "extended signal information polling disabled (rate: 0 seconds)");
if (priv->timeout_source) { if (priv->timeout_source) {
g_source_remove (priv->timeout_source); g_source_remove (priv->timeout_source);
priv->timeout_source = 0; priv->timeout_source = 0;
} }
check_interface_reset (self); return;
return TRUE;
} }
/* Restart polling */ /* Start/restart polling */
mm_obj_dbg (self, "extended signal information reporting enabled (rate: %u seconds)", rate);
if (priv->timeout_source) if (priv->timeout_source)
g_source_remove (priv->timeout_source); g_source_remove (priv->timeout_source);
priv->timeout_source = g_timeout_add_seconds (rate, (GSourceFunc) polling_context_cb, self); priv->timeout_source = g_timeout_add_seconds (priv->rate, (GSourceFunc) polling_context_cb, self);
/* Also launch right away */ /* Also launch right away */
polling_context_cb (self); polling_context_cb (self);
return TRUE; }
/*****************************************************************************/
/* Thresholds setup management */
static gboolean
thresholds_restart_finish (MMIfaceModemSignal *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
setup_thresholds_ready (MMIfaceModemSignal *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->setup_thresholds_finish (self, res, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
thresholds_restart (MMIfaceModemSignal *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
Private *priv;
gboolean threshold_setup;
task = g_task_new (self, NULL, callback, user_data);
if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->setup_thresholds ||
!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->setup_thresholds_finish) {
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
priv = get_private (self);
threshold_setup = (priv->enabled && (priv->rssi_threshold || priv->error_rate_threshold));
mm_obj_dbg (self, "%s extended signal information thresholds: interface %s, rssi threshold %u dBm, error rate threshold %s",
threshold_setup ? "setting up" : "cleaning up",
priv->enabled ? "enabled" : "disabled",
priv->rssi_threshold,
priv->error_rate_threshold ? "enabled" : "disabled");
MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->setup_thresholds (
self,
priv->rssi_threshold,
priv->error_rate_threshold,
(GAsyncReadyCallback)setup_thresholds_ready,
task);
} }
/*****************************************************************************/ /*****************************************************************************/
@@ -272,7 +320,6 @@ polling_restart (MMIfaceModemSignal *self,
typedef struct { typedef struct {
GDBusMethodInvocation *invocation; GDBusMethodInvocation *invocation;
MmGdbusModemSignal *skeleton; MmGdbusModemSignal *skeleton;
MMIfaceModemSignal *self;
guint rate; guint rate;
} HandleSetupContext; } HandleSetupContext;
@@ -281,18 +328,19 @@ handle_setup_context_free (HandleSetupContext *ctx)
{ {
g_object_unref (ctx->invocation); g_object_unref (ctx->invocation);
g_object_unref (ctx->skeleton); g_object_unref (ctx->skeleton);
g_object_unref (ctx->self);
g_slice_free (HandleSetupContext, ctx); g_slice_free (HandleSetupContext, ctx);
} }
static void static void
handle_setup_auth_ready (MMBaseModem *self, handle_setup_auth_ready (MMBaseModem *_self,
GAsyncResult *res, GAsyncResult *res,
HandleSetupContext *ctx) HandleSetupContext *ctx)
{ {
GError *error = NULL; MMIfaceModemSignal *self = MM_IFACE_MODEM_SIGNAL (_self);
GError *error = NULL;
Private *priv;
if (!mm_base_modem_authorize_finish (self, res, &error)) { if (!mm_base_modem_authorize_finish (_self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error); g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_setup_context_free (ctx); handle_setup_context_free (ctx);
return; return;
@@ -300,15 +348,17 @@ handle_setup_auth_ready (MMBaseModem *self,
if (mm_iface_modem_abort_invocation_if_state_not_reached (MM_IFACE_MODEM (self), if (mm_iface_modem_abort_invocation_if_state_not_reached (MM_IFACE_MODEM (self),
ctx->invocation, ctx->invocation,
MM_MODEM_STATE_ENABLED)) { MM_MODEM_STATE_DISABLED)) {
handle_setup_context_free (ctx); handle_setup_context_free (ctx);
return; return;
} }
if (!polling_restart (ctx->self, ctx->rate, &error)) priv = get_private (self);
g_dbus_method_invocation_take_error (ctx->invocation, error); priv->rate = ctx->rate;
else polling_restart (self);
mm_gdbus_modem_signal_complete_setup (ctx->skeleton, ctx->invocation); check_interface_reset (self);
mm_gdbus_modem_signal_set_rate (ctx->skeleton, ctx->rate);
mm_gdbus_modem_signal_complete_setup (ctx->skeleton, ctx->invocation);
handle_setup_context_free (ctx); handle_setup_context_free (ctx);
} }
@@ -320,10 +370,9 @@ handle_setup (MmGdbusModemSignal *skeleton,
{ {
HandleSetupContext *ctx; HandleSetupContext *ctx;
ctx = g_slice_new (HandleSetupContext); ctx = g_slice_new0 (HandleSetupContext);
ctx->invocation = g_object_ref (invocation); ctx->invocation = g_object_ref (invocation);
ctx->skeleton = g_object_ref (skeleton); ctx->skeleton = g_object_ref (skeleton);
ctx->self = g_object_ref (self);
ctx->rate = rate; ctx->rate = rate;
mm_base_modem_authorize (MM_BASE_MODEM (self), mm_base_modem_authorize (MM_BASE_MODEM (self),
@@ -339,10 +388,9 @@ handle_setup (MmGdbusModemSignal *skeleton,
typedef struct { typedef struct {
GDBusMethodInvocation *invocation; GDBusMethodInvocation *invocation;
MmGdbusModemSignal *skeleton; MmGdbusModemSignal *skeleton;
MMIfaceModemSignal *self;
GVariant *settings; GVariant *settings;
guint32 rssi_threshold; guint previous_rssi_threshold;
gboolean error_rate_threshold; gboolean previous_error_rate_threshold;
} HandleSetupThresholdsContext; } HandleSetupThresholdsContext;
static void static void
@@ -350,32 +398,29 @@ handle_setup_thresholds_context_free (HandleSetupThresholdsContext *ctx)
{ {
g_object_unref (ctx->invocation); g_object_unref (ctx->invocation);
g_object_unref (ctx->skeleton); g_object_unref (ctx->skeleton);
g_object_unref (ctx->self);
if (ctx->settings) if (ctx->settings)
g_variant_unref (ctx->settings); g_variant_unref (ctx->settings);
g_slice_free (HandleSetupThresholdsContext, ctx); g_slice_free (HandleSetupThresholdsContext, ctx);
} }
static void static void
setup_thresholds_ready (MMIfaceModemSignal *self, setup_thresholds_restart_ready (MMIfaceModemSignal *self,
GAsyncResult *res, GAsyncResult *res,
HandleSetupThresholdsContext *ctx) HandleSetupThresholdsContext *ctx)
{ {
GError *error = NULL; GError *error = NULL;
Private *priv; Private *priv;
priv = get_private (MM_IFACE_MODEM_SIGNAL (self)); priv = get_private (self);
if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds_finish (ctx->self, res, &error)) if (!thresholds_restart_finish (self, res, &error)) {
priv->rssi_threshold = ctx->previous_rssi_threshold;
priv->error_rate_threshold = ctx->previous_error_rate_threshold;
g_dbus_method_invocation_take_error (ctx->invocation, error); g_dbus_method_invocation_take_error (ctx->invocation, error);
else { } else {
/* Update the properties with the latest threshold setting */
mm_gdbus_modem_signal_set_rssi_threshold (ctx->skeleton, ctx->rssi_threshold);
mm_gdbus_modem_signal_set_error_rate_threshold (ctx->skeleton, ctx->error_rate_threshold);
priv->rssi_threshold = ctx->rssi_threshold;
priv->error_rate_threshold = ctx->error_rate_threshold;
check_interface_reset (self); check_interface_reset (self);
mm_gdbus_modem_signal_set_rssi_threshold (ctx->skeleton, priv->rssi_threshold);
mm_gdbus_modem_signal_set_error_rate_threshold (ctx->skeleton, priv->error_rate_threshold);
mm_gdbus_modem_signal_complete_setup_thresholds (ctx->skeleton, ctx->invocation); mm_gdbus_modem_signal_complete_setup_thresholds (ctx->skeleton, ctx->invocation);
} }
@@ -383,24 +428,27 @@ setup_thresholds_ready (MMIfaceModemSignal *self,
} }
static void static void
handle_setup_thresholds_auth_ready (MMBaseModem *self, handle_setup_thresholds_auth_ready (MMBaseModem *_self,
GAsyncResult *res, GAsyncResult *res,
HandleSetupThresholdsContext *ctx) HandleSetupThresholdsContext *ctx)
{ {
g_autoptr(MMSignalThresholdProperties) properties = NULL; g_autoptr(MMSignalThresholdProperties) properties = NULL;
MMIfaceModemSignal *self = MM_IFACE_MODEM_SIGNAL (_self);
GError *error = NULL; GError *error = NULL;
Private *priv; Private *priv;
guint new_rssi_threshold;
gboolean new_error_rate_threshold;
priv = get_private (MM_IFACE_MODEM_SIGNAL (self)); priv = get_private (self);
if (!mm_base_modem_authorize_finish (self, res, &error)) { if (!mm_base_modem_authorize_finish (_self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error); g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_setup_thresholds_context_free (ctx); handle_setup_thresholds_context_free (ctx);
return; return;
} }
if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds || if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->setup_thresholds ||
!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds_finish) { !MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->setup_thresholds_finish) {
g_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, g_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot setup thresholds: operation not supported"); "Cannot setup thresholds: operation not supported");
handle_setup_thresholds_context_free (ctx); handle_setup_thresholds_context_free (ctx);
@@ -409,7 +457,7 @@ handle_setup_thresholds_auth_ready (MMBaseModem *self,
if (mm_iface_modem_abort_invocation_if_state_not_reached (MM_IFACE_MODEM (self), if (mm_iface_modem_abort_invocation_if_state_not_reached (MM_IFACE_MODEM (self),
ctx->invocation, ctx->invocation,
MM_MODEM_STATE_ENABLED)) { MM_MODEM_STATE_DISABLED)) {
handle_setup_thresholds_context_free (ctx); handle_setup_thresholds_context_free (ctx);
return; return;
} }
@@ -420,31 +468,24 @@ handle_setup_thresholds_auth_ready (MMBaseModem *self,
handle_setup_thresholds_context_free (ctx); handle_setup_thresholds_context_free (ctx);
return; return;
} }
ctx->rssi_threshold = mm_signal_threshold_properties_get_rssi (properties); new_rssi_threshold = mm_signal_threshold_properties_get_rssi (properties);
ctx->error_rate_threshold = mm_signal_threshold_properties_get_error_rate (properties); new_error_rate_threshold = mm_signal_threshold_properties_get_error_rate (properties);
/* Already there? */ if ((new_rssi_threshold == priv->rssi_threshold) &&
if ((ctx->rssi_threshold == mm_gdbus_modem_signal_get_rssi_threshold (ctx->skeleton)) && (new_error_rate_threshold == priv->error_rate_threshold)) {
(ctx->error_rate_threshold == mm_gdbus_modem_signal_get_error_rate_threshold (ctx->skeleton))) {
mm_gdbus_modem_signal_complete_setup_thresholds (ctx->skeleton, ctx->invocation); mm_gdbus_modem_signal_complete_setup_thresholds (ctx->skeleton, ctx->invocation);
handle_setup_thresholds_context_free (ctx); handle_setup_thresholds_context_free (ctx);
return; return;
} }
/* Same settings? */ ctx->previous_rssi_threshold = priv->rssi_threshold;
if ((ctx->rssi_threshold == priv->rssi_threshold) && ctx->previous_error_rate_threshold = priv->error_rate_threshold;
(ctx->error_rate_threshold == priv->error_rate_threshold)) { priv->rssi_threshold = new_rssi_threshold;
mm_gdbus_modem_signal_complete_setup_thresholds (ctx->skeleton, ctx->invocation); priv->error_rate_threshold = new_error_rate_threshold;
handle_setup_thresholds_context_free (ctx);
return;
}
MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds ( thresholds_restart (self,
ctx->self, (GAsyncReadyCallback)setup_thresholds_restart_ready,
ctx->rssi_threshold, ctx);
ctx->error_rate_threshold,
(GAsyncReadyCallback)setup_thresholds_ready,
ctx);
} }
static gboolean static gboolean
@@ -458,7 +499,6 @@ handle_setup_thresholds (MmGdbusModemSignal *skeleton,
ctx = g_slice_new0 (HandleSetupThresholdsContext); ctx = g_slice_new0 (HandleSetupThresholdsContext);
ctx->invocation = g_object_ref (invocation); ctx->invocation = g_object_ref (invocation);
ctx->skeleton = g_object_ref (skeleton); ctx->skeleton = g_object_ref (skeleton);
ctx->self = g_object_ref (self);
ctx->settings = g_variant_ref (settings); ctx->settings = g_variant_ref (settings);
mm_base_modem_authorize (MM_BASE_MODEM (self), mm_base_modem_authorize (MM_BASE_MODEM (self),
@@ -469,6 +509,55 @@ handle_setup_thresholds (MmGdbusModemSignal *skeleton,
return TRUE; return TRUE;
} }
/*****************************************************************************/
/* Common enable/disable */
static gboolean
common_enable_disable_finish (MMIfaceModemSignal *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
enable_disable_thresholds_restart_ready (MMIfaceModemSignal *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
if (!thresholds_restart_finish (self, res, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
common_enable_disable (MMIfaceModemSignal *self,
gboolean enabled,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
Private *priv;
task = g_task_new (self, cancellable, callback, user_data);
priv = get_private (MM_IFACE_MODEM_SIGNAL (self));
priv->enabled = enabled;
check_interface_reset (self);
polling_restart (self);
thresholds_restart (self,
(GAsyncReadyCallback)enable_disable_thresholds_restart_ready,
task);
}
/*****************************************************************************/ /*****************************************************************************/
gboolean gboolean
@@ -476,7 +565,7 @@ mm_iface_modem_signal_disable_finish (MMIfaceModemSignal *self,
GAsyncResult *res, GAsyncResult *res,
GError **error) GError **error)
{ {
return g_task_propagate_boolean (G_TASK (res), error); return common_enable_disable_finish (self, res, error);
} }
void void
@@ -484,13 +573,7 @@ mm_iface_modem_signal_disable (MMIfaceModemSignal *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
GTask *task; common_enable_disable (self, FALSE, NULL, callback, user_data);
mm_iface_modem_signal_update (self, NULL, NULL, NULL, NULL, NULL, NULL);
task = g_task_new (self, NULL, callback, user_data);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
} }
/*****************************************************************************/ /*****************************************************************************/
@@ -500,7 +583,7 @@ mm_iface_modem_signal_enable_finish (MMIfaceModemSignal *self,
GAsyncResult *res, GAsyncResult *res,
GError **error) GError **error)
{ {
return g_task_propagate_boolean (G_TASK (res), error); return common_enable_disable_finish (self, res, error);
} }
void void
@@ -509,19 +592,7 @@ mm_iface_modem_signal_enable (MMIfaceModemSignal *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
GTask *task; common_enable_disable (self, TRUE, cancellable, callback, user_data);
GError *error = NULL;
Private *priv;
priv = get_private (self);
task = g_task_new (self, cancellable, callback, user_data);
/* same rate as we had before */
if (!polling_restart (self, priv->rate, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
} }
/*****************************************************************************/ /*****************************************************************************/