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:

committed by
Aleksander Morgado

parent
925f0bae11
commit
92539fa71f
@@ -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));
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user