modem: Allow to set current channel list

This adds support for setting the channels to override the boot up modem
defaults:

```
  busctl --system call org.freedesktop.ModemManager1 /org/freedesktop/ModemManager1/Modem/0 org.freedesktop.ModemManager1.Modem.CellBroadcast SetChannels 'a(uu)' 1 0 9999
  busctl --system get-property org.freedesktop.ModemManager1 /org/freedesktop/ModemManager1/Modem/0 org.freedesktop.ModemManager1.Modem.CellBroadcast Channels
  a(uu) 1 0 9999
```

Closes: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/934

Signed-off-by: Guido Günther <agx@sigxcpu.org>
This commit is contained in:
Guido Günther
2025-03-28 20:53:52 +00:00
committed by Dan Williams
parent d8135be6e2
commit 2878833f5c
4 changed files with 195 additions and 0 deletions
@@ -87,5 +87,27 @@
-->
<property name="CellBroadcasts" type="ao" access="read" />
<!--
SetChannels:
@channels: The list of channels
Set the list of channels to receive Cell Broadcasts for.
Since: 1.24
-->
<method name="SetChannels">
<arg name="channels" type="a(uu)" direction="in" />
</method>
<!--
Channels:
The list of channels that cell broadcast messages are
received for.
Since: 1.24
-->
<property name="Channels" type="a(uu)" access="read" />
</interface>
</node>
+62
View File
@@ -10603,6 +10603,66 @@ modem_cell_broadcast_create_cbm (MMIfaceModemCellBroadcast *self)
return mm_base_cbm_new (MM_BASE_MODEM (self));
}
/***********************************************************************************/
/* Get channels (CellBroadcast interface) */
static gboolean
modem_cell_broadcast_set_channels_finish (MMIfaceModemCellBroadcast *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
modem_cell_broadcast_set_channels_ready (MMBaseModem *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
if (!mm_base_modem_at_command_finish (self, res, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
modem_cell_broadcast_set_channels (MMIfaceModemCellBroadcast *self,
GArray *channels,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_autoptr (GString) cmd = g_string_new ("+CSCB=0,\"");
guint i;
task = g_task_new (self, NULL, callback, user_data);
for (i = 0; i < channels->len; i++) {
MMCellBroadcastChannels ch = g_array_index (channels, MMCellBroadcastChannels, i);
if (i > 0)
g_string_append_c (cmd, ',');
if (ch.start == ch.end)
g_string_append_printf (cmd, "%u", ch.start);
else
g_string_append_printf (cmd, "%u-%u", ch.start, ch.end);
}
g_string_append (cmd, "\",\"\"");
mm_obj_dbg (self, "Setting channels...");
mm_base_modem_at_command (
MM_BASE_MODEM (self),
cmd->str,
3,
FALSE,
(GAsyncReadyCallback)modem_cell_broadcast_set_channels_ready,
task);
}
/*********************************************************/
/* Check CellBroadcast support (CellBroadcast interface) */
@@ -14344,6 +14404,8 @@ iface_modem_cell_broadcast_init (MMIfaceModemCellBroadcastInterface *iface)
iface->setup_unsolicited_events_finish = modem_cell_broadcast_setup_cleanup_unsolicited_events_finish;
iface->cleanup_unsolicited_events = modem_cell_broadcast_cleanup_unsolicited_events;
iface->cleanup_unsolicited_events_finish = modem_cell_broadcast_setup_cleanup_unsolicited_events_finish;
iface->set_channels = modem_cell_broadcast_set_channels;
iface->set_channels_finish = modem_cell_broadcast_set_channels_finish;
iface->create_cbm = modem_cell_broadcast_create_cbm;
}
+102
View File
@@ -42,6 +42,102 @@ mm_iface_modem_cell_broadcast_bind_simple_status (MMIfaceModemCellBroadcast *sel
/*****************************************************************************/
typedef struct {
MmGdbusModemCellBroadcast *skeleton;
GDBusMethodInvocation *invocation;
MMIfaceModemCellBroadcast *self;
GArray *channels;
} HandleSetChannelsCellBroadcastContext;
static void
handle_set_channels_context_free (HandleSetChannelsCellBroadcastContext *ctx)
{
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
g_array_unref (ctx->channels);
g_slice_free (HandleSetChannelsCellBroadcastContext, ctx);
}
static void
set_channels_ready (MMIfaceModemCellBroadcast *self,
GAsyncResult *res,
HandleSetChannelsCellBroadcastContext *ctx)
{
GError *error = NULL;
if (!MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels_finish (self, res, &error))
mm_dbus_method_invocation_take_error (ctx->invocation, error);
else {
mm_gdbus_modem_cell_broadcast_set_channels (ctx->skeleton,
mm_common_cell_broadcast_channels_garray_to_variant (ctx->channels));
mm_gdbus_modem_cell_broadcast_complete_set_channels (ctx->skeleton, ctx->invocation);
}
handle_set_channels_context_free (ctx);
}
static void
handle_set_channels_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleSetChannelsCellBroadcastContext *ctx)
{
GError *error = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
handle_set_channels_context_free (ctx);
return;
}
/* Validate channels (either number or range) */
if (!mm_validate_cbs_channels (ctx->channels, &error)) {
mm_dbus_method_invocation_return_gerror (ctx->invocation, error);
handle_set_channels_context_free (ctx);
return;
}
/* Check if plugin implements it */
if (!MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels ||
!MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels_finish) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot set channels: not implemented");
handle_set_channels_context_free (ctx);
return;
}
/* Request to change channels */
mm_obj_info (self, "processing user request to set channels...");
MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels (ctx->self,
ctx->channels,
(GAsyncReadyCallback)set_channels_ready,
ctx);
}
static gboolean
handle_set_channels (MmGdbusModemCellBroadcast *skeleton,
GDBusMethodInvocation *invocation,
GVariant *channels,
MMIfaceModemCellBroadcast *self)
{
HandleSetChannelsCellBroadcastContext *ctx;
ctx = g_slice_new0 (HandleSetChannelsCellBroadcastContext);
ctx->skeleton = g_object_ref (skeleton);
ctx->invocation = g_object_ref (invocation);
ctx->self = g_object_ref (self);
ctx->channels = mm_common_cell_broadcast_channels_variant_to_garray (channels);
mm_base_modem_authorize (MM_BASE_MODEM (self),
invocation,
MM_AUTHORIZATION_DEVICE_CONTROL,
(GAsyncReadyCallback)handle_set_channels_auth_ready,
ctx);
return TRUE;
}
/*****************************************************************************/
typedef struct {
MmGdbusModemCellBroadcast *skeleton;
GDBusMethodInvocation *invocation;
@@ -315,6 +411,12 @@ interface_initialization_step (GTask *task)
case INITIALIZATION_STEP_LAST:
/* We are done without errors! */
/* Handle method invocations */
g_signal_connect (ctx->skeleton,
"handle-set-channels",
G_CALLBACK (handle_set_channels),
self);
g_signal_connect (ctx->skeleton,
"handle-delete",
G_CALLBACK (handle_delete),
+9
View File
@@ -76,6 +76,15 @@ struct _MMIfaceModemCellBroadcastInterface {
/* Create Cbm objects */
MMBaseCbm * (* create_cbm) (MMIfaceModemCellBroadcast *self);
/* Set channel list */
void (* set_channels) (MMIfaceModemCellBroadcast *self,
GArray *channels,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (* set_channels_finish) (MMIfaceModemCellBroadcast *self,
GAsyncResult *res,
GError **error);
};
/* Initialize CellBroadcast interface (async) */