iface-modem-signal: implement support for SetupThresholds()

Also allow updating the per-access technology signal quality
information via indications.

Includes updates by Aleksander Morgado to fix coding style issues and
some other GTask related problems.
This commit is contained in:
Som_SP
2021-10-14 16:30:06 +02:00
committed by Aleksander Morgado
parent 925f0bae11
commit 92539fa71f
2 changed files with 274 additions and 43 deletions

View File

@@ -10,7 +10,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
* Copyright (C) 2013-2021 Aleksander Morgado <aleksander@aleksander.es>
* Copyright (C) 2021 Intel Corporation
*/
#include <ModemManager.h>
@@ -39,6 +40,61 @@ mm_iface_modem_signal_bind_simple_status (MMIfaceModemSignal *self,
/*****************************************************************************/
void
mm_iface_modem_signal_update (MMIfaceModemSignal *self,
MMSignal *cdma,
MMSignal *evdo,
MMSignal *gsm,
MMSignal *umts,
MMSignal *lte,
MMSignal *nr5g)
{
g_autoptr(GVariant) dict_cdma = NULL;
g_autoptr(GVariant) dict_evdo = NULL;
g_autoptr(GVariant) dict_gsm = NULL;
g_autoptr(GVariant) dict_umts = NULL;
g_autoptr(GVariant) dict_lte = NULL;
g_autoptr(GVariant) dict_nr5g = NULL;
g_autoptr(MmGdbusModemSignalSkeleton) skeleton = NULL;
g_object_get (self,
MM_IFACE_MODEM_SIGNAL_DBUS_SKELETON, &skeleton,
NULL);
if (!skeleton) {
mm_obj_warn (self, "cannot update extended signal information: couldn't get interface skeleton");
return;
}
if (cdma)
dict_cdma = mm_signal_get_dictionary (cdma);
mm_gdbus_modem_signal_set_cdma (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_cdma);
if (evdo)
dict_evdo = mm_signal_get_dictionary (evdo);
mm_gdbus_modem_signal_set_evdo (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_evdo);
if (gsm)
dict_gsm = mm_signal_get_dictionary (gsm);
mm_gdbus_modem_signal_set_gsm (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_gsm);
if (umts)
dict_umts = mm_signal_get_dictionary (umts);
mm_gdbus_modem_signal_set_umts (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_umts);
if (lte)
dict_lte = mm_signal_get_dictionary (lte);
mm_gdbus_modem_signal_set_lte (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_lte);
if (nr5g)
dict_nr5g = mm_signal_get_dictionary (nr5g);
mm_gdbus_modem_signal_set_nr5g (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_nr5g);
/* Flush right away */
g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (skeleton));
}
/*****************************************************************************/
typedef struct {
guint rate;
guint timeout_source;
@@ -77,18 +133,11 @@ load_values_ready (MMIfaceModemSignal *self,
{
g_autoptr(GError) error = NULL;
g_autoptr(MMSignal) cdma = NULL;
g_autoptr(GVariant) dict_cdma = NULL;
g_autoptr(MMSignal) evdo = NULL;
g_autoptr(GVariant) dict_evdo = NULL;
g_autoptr(MMSignal) gsm = NULL;
g_autoptr(GVariant) dict_gsm = NULL;
g_autoptr(MMSignal) umts = NULL;
g_autoptr(GVariant) dict_umts = NULL;
g_autoptr(MMSignal) lte = NULL;
g_autoptr(GVariant) dict_lte = NULL;
g_autoptr(MMSignal) nr5g = NULL;
g_autoptr(GVariant) dict_nr5g = NULL;
g_autoptr(MmGdbusModemSignalSkeleton) skeleton = NULL;
if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->load_values_finish (
self,
@@ -105,40 +154,7 @@ load_values_ready (MMIfaceModemSignal *self,
return;
}
g_object_get (self,
MM_IFACE_MODEM_SIGNAL_DBUS_SKELETON, &skeleton,
NULL);
if (!skeleton) {
mm_obj_warn (self, "cannot update extended signal information: couldn't get interface skeleton");
return;
}
if (cdma)
dict_cdma = mm_signal_get_dictionary (cdma);
mm_gdbus_modem_signal_set_cdma (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_cdma);
if (evdo)
dict_evdo = mm_signal_get_dictionary (evdo);
mm_gdbus_modem_signal_set_evdo (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_evdo);
if (gsm)
dict_gsm = mm_signal_get_dictionary (gsm);
mm_gdbus_modem_signal_set_gsm (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_gsm);
if (umts)
dict_umts = mm_signal_get_dictionary (umts);
mm_gdbus_modem_signal_set_umts (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_umts);
if (lte)
dict_lte = mm_signal_get_dictionary (lte);
mm_gdbus_modem_signal_set_lte (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_lte);
if (nr5g)
dict_nr5g = mm_signal_get_dictionary (nr5g);
mm_gdbus_modem_signal_set_nr5g (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_nr5g);
/* Flush right away */
g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (skeleton));
mm_iface_modem_signal_update (self, cdma, evdo, gsm, umts, lte, nr5g);
}
static gboolean
@@ -295,6 +311,196 @@ handle_setup (MmGdbusModemSignal *skeleton,
/*****************************************************************************/
typedef struct {
GDBusMethodInvocation *invocation;
MmGdbusModemSignal *skeleton;
MMIfaceModemSignal *self;
GVariant *settings;
guint32 rssi_threshold;
gboolean error_rate_threshold;
} HandleSetupThresholdsContext;
static void
handle_setup_thresholds_context_free (HandleSetupThresholdsContext *ctx)
{
g_object_unref (ctx->invocation);
g_object_unref (ctx->skeleton);
g_object_unref (ctx->self);
if (ctx->settings)
g_variant_unref (ctx->settings);
g_slice_free (HandleSetupThresholdsContext, ctx);
}
static void
setup_thresholds_ready (MMIfaceModemSignal *self,
GAsyncResult *res,
HandleSetupThresholdsContext *ctx)
{
GError *error = NULL;
if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds_finish (ctx->self, res, &error))
g_dbus_method_invocation_take_error (ctx->invocation, error);
else {
/* Update the property 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);
mm_gdbus_modem_signal_complete_setup_thresholds (ctx->skeleton, ctx->invocation);
}
handle_setup_thresholds_context_free (ctx);
}
static gboolean
select_new_threshold_settings (HandleSetupThresholdsContext *ctx,
GError **error)
{
GError *inner_error = NULL;
GVariantIter iter;
gchar *key;
GVariant *value;
if (!g_variant_is_of_type (ctx->settings, G_VARIANT_TYPE ("a{sv}"))) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Cannot get threshold settings from dictionary: "
"invalid variant type received");
return FALSE;
}
g_variant_iter_init (&iter, ctx->settings);
while (!inner_error && g_variant_iter_next (&iter, "{sv}", &key, &value)) {
if (g_str_equal (key, "rssi-threshold"))
ctx->rssi_threshold = g_variant_get_uint32 (value);
else if (g_str_equal (key, "error-rate-threshold"))
ctx->error_rate_threshold = g_variant_get_boolean (value);
else {
/* Set inner error, will stop the loop */
inner_error = g_error_new (MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Invalid settings dictionary, unexpected key '%s'",
key);
}
g_free (key);
g_variant_unref (value);
}
if (inner_error) {
g_propagate_error (error, inner_error);
return FALSE;
}
return TRUE;
}
static gboolean
check_threshold_settings (HandleSetupThresholdsContext *ctx,
GError **error)
{
MmGdbusModemSignal *skeleton;
MMModemState modem_state;
guint32 old_rssi_threshold;
gboolean old_error_threshold;
g_object_get (ctx->self,
MM_IFACE_MODEM_SIGNAL_DBUS_SKELETON, &skeleton,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
if (!skeleton) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Couldn't get signal interface skeleton");
return FALSE;
}
if (modem_state < MM_MODEM_STATE_ENABLING) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
"Modem in wrong state");
return FALSE;
}
/* Compare to old threshold values */
old_rssi_threshold = mm_gdbus_modem_signal_get_rssi_threshold(skeleton);
old_error_threshold = mm_gdbus_modem_signal_get_error_rate_threshold(skeleton);
/* Set older threshold values before reading dictionary. So that if only
* one value is passed then the other threshold will be maintained as set
* previously. */
ctx->rssi_threshold = old_rssi_threshold;
ctx->error_rate_threshold = old_error_threshold;
if (!select_new_threshold_settings (ctx, error))
return FALSE;
if ((ctx->rssi_threshold == old_rssi_threshold) && (ctx->error_rate_threshold == old_error_threshold)) {
/* Already there */
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"Same threshold settings already configured");
return FALSE;
}
return TRUE;
}
static void
handle_setup_thresholds_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleSetupThresholdsContext *ctx)
{
GError *error = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_setup_thresholds_context_free (ctx);
return;
}
if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds ||
!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds_finish) {
g_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot setup thresholds: operation not supported");
handle_setup_thresholds_context_free (ctx);
return;
}
if (!check_threshold_settings (ctx, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_setup_thresholds_context_free (ctx);
return;
}
MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (ctx->self)->setup_thresholds (
ctx->self,
ctx->rssi_threshold,
ctx->error_rate_threshold,
(GAsyncReadyCallback)setup_thresholds_ready,
ctx);
}
static gboolean
handle_setup_thresholds (MmGdbusModemSignal *skeleton,
GDBusMethodInvocation *invocation,
GVariant *settings,
MMIfaceModemSignal *self)
{
HandleSetupThresholdsContext *ctx;
ctx = g_slice_new0 (HandleSetupThresholdsContext);
ctx->invocation = g_object_ref (invocation);
ctx->skeleton = g_object_ref (skeleton);
ctx->self = g_object_ref (self);
ctx->settings = g_variant_ref (settings);
mm_base_modem_authorize (MM_BASE_MODEM (self),
invocation,
MM_AUTHORIZATION_DEVICE_CONTROL,
(GAsyncReadyCallback)handle_setup_thresholds_auth_ready,
ctx);
return TRUE;
}
/*****************************************************************************/
gboolean
mm_iface_modem_signal_disable_finish (MMIfaceModemSignal *self,
GAsyncResult *res,
@@ -481,6 +687,10 @@ interface_initialization_step (GTask *task)
"handle-setup",
G_CALLBACK (handle_setup),
self);
g_signal_connect (ctx->skeleton,
"handle-setup-thresholds",
G_CALLBACK (handle_setup_thresholds),
self);
/* Finally, export the new interface */
mm_gdbus_object_skeleton_set_modem_signal (MM_GDBUS_OBJECT_SKELETON (self),
MM_GDBUS_MODEM_SIGNAL (ctx->skeleton));

View File

@@ -10,7 +10,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
* Copyright (C) 2013-2021 Aleksander Morgado <aleksander@aleksander.es>
* Copyright (C) 2021 Intel Corporation
*/
#ifndef MM_IFACE_MODEM_SIGNAL_H
@@ -56,6 +57,17 @@ struct _MMIfaceModemSignal {
MMSignal **lte,
MMSignal **nr5g,
GError **error);
/* Setup thresholds */
void (* setup_thresholds) (MMIfaceModemSignal *self,
guint32 rssi_threshold,
gboolean error_rate_threshold,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (* setup_thresholds_finish) (MMIfaceModemSignal *self,
GAsyncResult *res,
GError **error);
};
GType mm_iface_modem_signal_get_type (void);
@@ -94,4 +106,13 @@ void mm_iface_modem_signal_shutdown (MMIfaceModemSignal *self);
void mm_iface_modem_signal_bind_simple_status (MMIfaceModemSignal *self,
MMSimpleStatus *status);
/* Allow signal quality updates via indications */
void mm_iface_modem_signal_update (MMIfaceModemSignal *self,
MMSignal *cdma,
MMSignal *evdo,
MMSignal *gsm,
MMSignal *umts,
MMSignal *lte,
MMSignal *nr5g);
#endif /* MM_IFACE_MODEM_SIGNAL_H */