aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dan@ioncontrol.co>2025-03-29 22:22:13 +0000
committerDan Williams <dan@ioncontrol.co>2025-03-29 22:22:13 +0000
commit45313ebef8ea0a7f9e0d501227798ff2d1dc4c4a (patch)
tree780cc4883e5b72adf09f5a49777466ac4061e6dd
parentab8c9b341856c7a1aae563d682683f6fcca1f3ba (diff)
parent51dd72601832620336e111cb2ea57f0af540778b (diff)
Merge request !1321 from 'cbm/channels-mmcli'
CellBroadcast: Add libmm-glib and mmcli support for setting channels https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1321 Closes #934
-rw-r--r--cli/mmcli-modem-cell-broadcast.c115
-rw-r--r--cli/mmcli-output.c2
-rw-r--r--cli/mmcli-output.h3
-rw-r--r--docs/man/mmcli.128
-rw-r--r--libmm-glib/mm-common-helpers.c114
-rw-r--r--libmm-glib/mm-common-helpers.h6
-rw-r--r--libmm-glib/mm-modem-cell-broadcast.c117
-rw-r--r--libmm-glib/mm-modem-cell-broadcast.h24
-rw-r--r--libmm-glib/tests/test-common-helpers.c90
9 files changed, 493 insertions, 6 deletions
diff --git a/cli/mmcli-modem-cell-broadcast.c b/cli/mmcli-modem-cell-broadcast.c
index 8121e8a5..2e6c975f 100644
--- a/cli/mmcli-modem-cell-broadcast.c
+++ b/cli/mmcli-modem-cell-broadcast.c
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
- * Copyright (C) 2024 Guido Günther <agx@sigxcpu.org>
+ * Copyright (C) 2024-2025 Guido Günther <agx@sigxcpu.org>
*/
#include "config.h"
@@ -49,8 +49,13 @@ static Context *ctx;
static gboolean status_flag;
static gboolean list_flag;
static gchar *delete_str;
+static gchar *channels_str;
static GOptionEntry entries[] = {
+ { "cell-broadcast-status", 0, 0, G_OPTION_ARG_NONE, &status_flag,
+ "Show cell broadcast status",
+ NULL
+ },
{ "cell-broadcast-list-cbm", 0, 0, G_OPTION_ARG_NONE, &list_flag,
"List cell broadcast messages available in a given modem",
NULL
@@ -59,6 +64,10 @@ static GOptionEntry entries[] = {
"Delete a cell broadcast message from a given modem",
"[PATH|INDEX]"
},
+ { "cell-broadcast-set-channels", 0, 0, G_OPTION_ARG_STRING, &channels_str,
+ "Set the channel list",
+ "[FIRST_CHANNEL-LAST_CHANNEL,FIRST_CHANNEL-LAST_CHANNEL...]"
+ },
{ NULL }
};
@@ -86,8 +95,10 @@ mmcli_modem_cell_broadcast_options_enabled (void)
if (checked)
return !!n_actions;
- n_actions = (list_flag +
- !!delete_str);
+ n_actions = (status_flag +
+ list_flag +
+ !!delete_str +
+ !!channels_str);
if (n_actions > 1) {
g_printerr ("error: too many Cell Broadcast actions requested\n");
@@ -156,6 +167,21 @@ output_cbm_info (MMCbm *cbm)
}
static void
+print_cell_broadcast_status (void)
+{
+ g_autofree MMCellBroadcastChannels *channels = NULL;
+ guint channels_len = 0;
+ gchar *str = NULL;
+
+ mm_modem_cell_broadcast_get_channels (ctx->modem_cell_broadcast, &channels, &channels_len);
+ if (channels)
+ str = mm_common_build_channels_string (channels, channels_len);
+
+ mmcli_output_string_take (MMC_F_CELL_BROADCAST_CHANNELS, str);
+ mmcli_output_dump ();
+}
+
+static void
list_process_reply (GList *result,
const GError *error)
{
@@ -238,6 +264,50 @@ get_cbm_to_delete_ready (GDBusConnection *connection,
}
static void
+set_channels_process_reply (gboolean result,
+ const GError *error)
+{
+ if (!result) {
+ g_printerr ("error: couldn't set channels: '%s'\n",
+ error ? error->message : "unknown error");
+ exit (EXIT_FAILURE);
+ }
+
+ g_print ("successfully set channels in the modem\n");
+}
+
+static void
+set_channels_ready (MMModemCellBroadcast *cell_broadcast,
+ GAsyncResult *result,
+ gpointer nothing)
+{
+ gboolean operation_result;
+ GError *error = NULL;
+
+ operation_result = mm_modem_cell_broadcast_set_channels_finish (cell_broadcast, result, &error);
+ set_channels_process_reply (operation_result, error);
+
+ mmcli_async_operation_done ();
+}
+
+static void
+parse_channels (MMCellBroadcastChannels **channels,
+ guint *n_channels)
+{
+ GError *error = NULL;
+
+ mm_common_get_cell_broadcast_channels_from_string (channels_str,
+ channels,
+ n_channels,
+ &error);
+ if (error) {
+ g_printerr ("error: couldn't parse list of channels: '%s'\n",
+ error->message);
+ exit (EXIT_FAILURE);
+ }
+}
+
+static void
get_modem_ready (GObject *source,
GAsyncResult *result,
gpointer none)
@@ -274,6 +344,21 @@ get_modem_ready (GObject *source,
return;
}
+ if (channels_str) {
+ g_autofree MMCellBroadcastChannels *channels = NULL;
+ guint n_channels;
+
+ parse_channels (&channels, &n_channels);
+ g_debug ("Asynchronously setting channels...");
+ mm_modem_cell_broadcast_set_channels (ctx->modem_cell_broadcast,
+ channels,
+ n_channels,
+ ctx->cancellable,
+ (GAsyncReadyCallback)set_channels_ready,
+ NULL);
+ return;
+ }
+
g_warn_if_reached ();
}
@@ -313,6 +398,13 @@ mmcli_modem_cell_broadcast_run_synchronous (GDBusConnection *connection)
ensure_modem_cell_broadcast ();
+ /* Request to get cell broadcst status? */
+ if (status_flag) {
+ g_debug ("Printing cell broadcast status...");
+ print_cell_broadcast_status ();
+ return;
+ }
+
/* Request to list the CBM? */
if (list_flag) {
GList *result;
@@ -351,5 +443,22 @@ mmcli_modem_cell_broadcast_run_synchronous (GDBusConnection *connection)
return;
}
+ /* Set channels */
+ if (channels_str) {
+ gboolean result;
+ g_autofree MMCellBroadcastChannels *channels = NULL;
+ guint n_channels;
+
+ parse_channels (&channels, &n_channels);
+ g_debug ("Synchronously setting channels...");
+ result = mm_modem_cell_broadcast_set_channels_sync (ctx->modem_cell_broadcast,
+ channels,
+ n_channels,
+ NULL,
+ &error);
+ set_channels_process_reply (result, error);
+ return;
+ }
+
g_warn_if_reached ();
}
diff --git a/cli/mmcli-output.c b/cli/mmcli-output.c
index 1884e906..440d6059 100644
--- a/cli/mmcli-output.c
+++ b/cli/mmcli-output.c
@@ -50,6 +50,7 @@ static SectionInfo section_infos[] = {
[MMC_S_MODEM_3GPP_USSD] = { "3GPP USSD" },
[MMC_S_MODEM_3GPP_PROFILE_MANAGER] = { "3GPP profile manager" },
[MMC_S_MODEM_CDMA] = { "CDMA" },
+ [MMC_S_MODEM_CELL_BROADCAST] = { "Cell Broadcast" },
[MMC_S_MODEM_SIM] = { "SIM" },
[MMC_S_MODEM_BEARER] = { "Bearer" },
[MMC_S_MODEM_TIME] = { "Time" },
@@ -167,6 +168,7 @@ static FieldInfo field_infos[] = {
[MMC_F_CDMA_REGISTRATION_CDMA1X] = { "modem.cdma.cdma1x-registration-state", "registration cdma1x", MMC_S_MODEM_CDMA, },
[MMC_F_CDMA_REGISTRATION_EVDO] = { "modem.cdma.evdo-registration-state", "registration evdo", MMC_S_MODEM_CDMA, },
[MMC_F_CDMA_ACTIVATION] = { "modem.cdma.activation-state", "activation", MMC_S_MODEM_CDMA, },
+ [MMC_F_CELL_BROADCAST_CHANNELS] = { "modem.cellbroadcast.channels", "channels", MMC_S_MODEM_CELL_BROADCAST, },
[MMC_F_SIM_PATH] = { "modem.generic.sim", "primary sim path", MMC_S_MODEM_SIM, },
[MMC_F_SIM_PRIMARY_SLOT] = { "modem.generic.primary-sim-slot", NULL, MMC_S_MODEM_SIM, },
[MMC_F_SIM_SLOT_PATHS] = { "modem.generic.sim-slots", "sim slot paths", MMC_S_MODEM_SIM, },
diff --git a/cli/mmcli-output.h b/cli/mmcli-output.h
index 8dde1412..a9f050d8 100644
--- a/cli/mmcli-output.h
+++ b/cli/mmcli-output.h
@@ -46,6 +46,7 @@ typedef enum {
MMC_S_MODEM_3GPP_USSD,
MMC_S_MODEM_3GPP_PROFILE_MANAGER,
MMC_S_MODEM_CDMA,
+ MMC_S_MODEM_CELL_BROADCAST,
MMC_S_MODEM_SIM,
MMC_S_MODEM_BEARER,
MMC_S_MODEM_TIME,
@@ -173,6 +174,8 @@ typedef enum {
MMC_F_CDMA_REGISTRATION_CDMA1X,
MMC_F_CDMA_REGISTRATION_EVDO,
MMC_F_CDMA_ACTIVATION,
+ /* CellBroadcast section */
+ MMC_F_CELL_BROADCAST_CHANNELS,
/* SIM section */
MMC_F_SIM_PATH,
MMC_F_SIM_PRIMARY_SLOT,
diff --git a/docs/man/mmcli.1 b/docs/man/mmcli.1
index 99a8fd4f..d15cb799 100644
--- a/docs/man/mmcli.1
+++ b/docs/man/mmcli.1
@@ -740,6 +740,24 @@ Use \fBSECONDS\fR for the timeout when performing operations with this
command. This option is useful when executing long running operations, like
\fB\-\-3gpp\-scan\fR.
+.SH CELL BROADCAST OPTIONS
+
+All cell broadcast options must be used with \fB\-\-modem\fR or \fB\-m\fR.
+
+.TP
+.B \-\-cell\-broadcast\-status
+Show the status of the cell broadcast support.
+.TP
+.B \-\-cell\-broadcast\-list\-cbm
+List cell broadcast messages available on a given modem.
+.TP
+.B \-\-cell\-broadcast\-delete\-cbm=[PATH|INDEX]
+Delete cell broadcast message at the given path or index
+.TP
+.B \-\-cell\-broadcast\-set\-channels=[CHANNELS]
+Set the list of channels on which cell broadcasts are received (e.g. \fB5370,5371-5372\fR)
+.RS 9
+
.SH EXAMPLES
.SS Send the PIN to the SIM card
@@ -988,6 +1006,16 @@ XTRA assistance data is usually valid for several days.
successfully setup location gathering
.Ed
+.SS Setting the Cell Broadcast channel list
+
+The channel list can be set as a comma separated list of channels or channel intervals:
+
+.Bd -literal -compact
+ $ sudo mmcli -m 0 \\
+ --cell-broadcast-set-channels=5370,5371,5373-5000
+ successfully set channels in the modem
+.Ed
+
.SS Key-Value output
Writing shell scripts that use mmcli to perform operations with the
diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c
index e249a2fc..12796429 100644
--- a/libmm-glib/mm-common-helpers.c
+++ b/libmm-glib/mm-common-helpers.c
@@ -174,6 +174,36 @@ mm_common_build_mode_combinations_string (const MMModemModeCombination *modes,
return g_string_free (str, FALSE);
}
+gchar *
+mm_common_build_channels_string (const MMCellBroadcastChannels *channels,
+ guint n_channels)
+{
+ gboolean first = TRUE;
+ GString *str;
+ guint i;
+
+ if (!channels || !n_channels)
+ return g_strdup ("none");
+
+ str = g_string_new ("");
+ for (i = 0; i < n_channels; i++) {
+ if (channels[i].start == channels[i].end) {
+ g_string_append_printf (str, "%s%u",
+ first ? "" : ",",
+ channels[i].start);
+ } else {
+ g_string_append_printf (str, "%s%u-%u",
+ first ? "" : ",",
+ channels[i].start, channels[i].end);
+ }
+
+ if (first)
+ first = FALSE;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
/******************************************************************************/
/* String to enums/flags parsers */
@@ -738,6 +768,90 @@ mm_common_get_profile_source_from_string (const gchar *str,
error);
}
+gboolean
+mm_common_get_cell_broadcast_channels_from_string (const gchar *str,
+ MMCellBroadcastChannels **channels,
+ guint *n_channels,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GArray *array;
+ g_auto(GStrv) channel_strings = NULL;
+
+ array = g_array_new (FALSE, FALSE, sizeof (MMCellBroadcastChannels));
+
+ channel_strings = g_strsplit (str, ",", -1);
+
+ if (channel_strings) {
+ guint i;
+
+ for (i = 0; channel_strings[i]; i++) {
+ char *startptr, *endptr;
+ gint64 start;
+
+ startptr = channel_strings[i];
+ start = g_ascii_strtoll (startptr, &endptr, 10);
+ if (startptr == endptr || start > G_MAXUINT16 || start < 0) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't parse '%s' as MMCellBroadcastChannel start value",
+ channel_strings[i]);
+ break;
+ }
+ if (*endptr == '\0') {
+ MMCellBroadcastChannels ch;
+
+ ch.start = start;
+ ch.end = start;
+ g_array_append_val (array, ch);
+ } else if (*endptr == '-') {
+ gint64 end;
+
+ startptr = endptr + 1;
+ end = g_ascii_strtoll (startptr, &endptr, 10);
+ if (startptr == endptr || end > G_MAXUINT16 || end < 0) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't parse '%s' as MMCellBroadcastChannel end value",
+ channel_strings[i]);
+ break;
+ }
+ if (*endptr == '\0') {
+ MMCellBroadcastChannels ch;
+
+ ch.start = start;
+ ch.end = end;
+ g_array_append_val (array, ch);
+ } else {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't parse '%s' as MMCellBroadcastChannel end value",
+ channel_strings[i]);
+ break;
+ }
+ } else {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't parse '%s' as MMCellBroadcastChannel value",
+ channel_strings[i]);
+ break;
+ }
+ }
+ }
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_array_free (array, TRUE);
+ *n_channels = 0;
+ *channels = NULL;
+ return FALSE;
+ }
+
+ *n_channels = array->len;
+ *channels = (MMCellBroadcastChannels *)g_array_free (array, FALSE);
+ return TRUE;
+}
+
/******************************************************************************/
/* MMModemPortInfo array management */
diff --git a/libmm-glib/mm-common-helpers.h b/libmm-glib/mm-common-helpers.h
index bea220e0..d3b2a0fb 100644
--- a/libmm-glib/mm-common-helpers.h
+++ b/libmm-glib/mm-common-helpers.h
@@ -46,6 +46,8 @@ gchar *mm_common_build_sms_storages_string (const MMSmsStorage *s
guint n_storages);
gchar *mm_common_build_mode_combinations_string (const MMModemModeCombination *modes,
guint n_modes);
+gchar *mm_common_build_channels_string (const MMCellBroadcastChannels *channels,
+ guint n_channels);
/******************************************************************************/
/* String to enums/flags parsers */
@@ -102,6 +104,10 @@ MMBearerAccessTypePreference mm_common_get_access_type_preference_from_string
GError **error);
MMBearerProfileSource mm_common_get_profile_source_from_string (const gchar *str,
GError **error);
+gboolean mm_common_get_cell_broadcast_channels_from_string (const gchar *str,
+ MMCellBroadcastChannels **channels,
+ guint *n_channels,
+ GError **error);
/******************************************************************************/
diff --git a/libmm-glib/mm-modem-cell-broadcast.c b/libmm-glib/mm-modem-cell-broadcast.c
index fe7fd829..60495f84 100644
--- a/libmm-glib/mm-modem-cell-broadcast.c
+++ b/libmm-glib/mm-modem-cell-broadcast.c
@@ -17,7 +17,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2024 Guido Günther <agx@sigxcpu.org>
+ * Copyright (C) 2024-2025 Guido Günther <agx@sigxcpu.org>
*/
#include <gio/gio.h>
@@ -43,6 +43,8 @@ G_DEFINE_TYPE (MMModemCellBroadcast, mm_modem_cell_broadcast, MM_GDBUS_TYPE_MODE
struct _MMModemCellBroadcastPrivate {
/* Common mutex to sync access */
GMutex mutex;
+
+ PROPERTY_ARRAY_DECLARE (channels)
};
/*****************************************************************************/
@@ -91,6 +93,11 @@ mm_modem_cell_broadcast_dup_path (MMModemCellBroadcast *self)
RETURN_NON_EMPTY_STRING (value);
}
+PROPERTY_ARRAY_DEFINE (channels,
+ ModemCellBroadcast, modem_cell_broadcast, MODEM_CELL_BROADCAST,
+ MMCellBroadcastChannels,
+ mm_common_cell_broadcast_channels_variant_to_garray)
+
/*****************************************************************************/
typedef struct {
@@ -406,11 +413,117 @@ mm_modem_cell_broadcast_delete_sync (MMModemCellBroadcast *self,
/*****************************************************************************/
+/**
+ * mm_modem_cell_broadcast_set_channels_finish
+ * @self: A #MMModemCellBroadcast.
+ * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
+ * mm_modem_cell_broadcast_set_channels()
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with mm_modem_cell_broadcast_set_channels().
+ *
+ * Returns: %TRUE if set default storage is success, %FALSE if @error is set.
+ *
+ * Since: 1.24
+ */
+gboolean
+mm_modem_cell_broadcast_set_channels_finish (MMModemCellBroadcast *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ g_return_val_if_fail (MM_IS_MODEM_CELL_BROADCAST (self), FALSE);
+
+ return mm_gdbus_modem_cell_broadcast_call_set_channels_finish (MM_GDBUS_MODEM_CELL_BROADCAST (self),
+ res,
+ error);
+}
+
+/**
+ * mm_modem_cell_broadcast_set_channels
+ * @self: A #MMModemCellBroadcast.
+ * @channels: The #MMCellbroadcastChannels to set
+ * @n_channels: The number of elements in `channels`
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied or
+ * %NULL
+ * @user_data: User data to pass to @callback.
+ *
+ * Asynchronously set the #MMCellbroadcastChannel s in the modem.
+ *
+ * When the operation is finished, @callback will be invoked in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * of the thread you are calling this method from. You can then call
+ * mm_modem_cell_broadcast_set_channels_finish() to get the result of the operation.
+ *
+ * See mm_modem_cell_broadcast_set_channels_sync() for the synchronous, blocking version
+ * of this method.
+ *
+ * Since: 1.24
+ */
+void
+mm_modem_cell_broadcast_set_channels (MMModemCellBroadcast *self,
+ const MMCellBroadcastChannels *channels,
+ guint n_channels,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVariant *channels_variant;
+
+ g_return_if_fail (MM_IS_MODEM_CELL_BROADCAST (self));
+
+ channels_variant = mm_common_cell_broadcast_channels_array_to_variant (channels, n_channels);
+ mm_gdbus_modem_cell_broadcast_call_set_channels (MM_GDBUS_MODEM_CELL_BROADCAST (self),
+ channels_variant,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * mm_modem_cell_broadcast_set_channels_sync
+ * @self: A #MMModemCellBroadcast.
+ * @channels: The #MMCellbroadcastChannels to set
+ * @n_channels: The number of elements in `channels`
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Asynchronously set the #MMCellbroadcastChannel s in the modem.
+ *
+ * The calling thread is blocked until a reply is received. See
+ * mm_modem_cell_broadcast_set_channels() for the asynchronous version of this method.
+ *
+ * Returns: %TRUE if the operation was successful, %FALSE if @error is set.
+ *
+ * Since: 1.24
+ */
+gboolean
+mm_modem_cell_broadcast_set_channels_sync (MMModemCellBroadcast *self,
+ const MMCellBroadcastChannels *channels,
+ guint n_channels,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *channels_variant;
+
+ g_return_val_if_fail (MM_IS_MODEM_CELL_BROADCAST (self), FALSE);
+
+ channels_variant = mm_common_cell_broadcast_channels_array_to_variant (channels, n_channels);
+ return mm_gdbus_modem_cell_broadcast_call_set_channels_sync (MM_GDBUS_MODEM_CELL_BROADCAST (self),
+ channels_variant,
+ cancellable,
+ error);
+}
+
+/*****************************************************************************/
+
static void
mm_modem_cell_broadcast_init (MMModemCellBroadcast *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_MODEM_CELL_BROADCAST, MMModemCellBroadcastPrivate);
g_mutex_init (&self->priv->mutex);
+
+ PROPERTY_INITIALIZE (channels, "channels")
}
static void
@@ -420,6 +533,8 @@ finalize (GObject *object)
g_mutex_clear (&self->priv->mutex);
+ PROPERTY_ARRAY_FINALIZE (channels)
+
G_OBJECT_CLASS (mm_modem_cell_broadcast_parent_class)->finalize (object);
}
diff --git a/libmm-glib/mm-modem-cell-broadcast.h b/libmm-glib/mm-modem-cell-broadcast.h
index a1049caf..9d9cafa3 100644
--- a/libmm-glib/mm-modem-cell-broadcast.h
+++ b/libmm-glib/mm-modem-cell-broadcast.h
@@ -68,6 +68,13 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMModemCellBroadcast, g_object_unref)
const gchar *mm_modem_cell_broadcast_get_path (MMModemCellBroadcast *self);
gchar *mm_modem_cell_broadcast_dup_path (MMModemCellBroadcast *self);
+gboolean mm_modem_cell_broadcast_get_channels (MMModemCellBroadcast *self,
+ MMCellBroadcastChannels **channels,
+ guint *n_storages);
+gboolean mm_modem_cell_broadcast_peek_channels (MMModemCellBroadcast *self,
+ const MMCellBroadcastChannels **channels,
+ guint *n_storages);
+
void mm_modem_cell_broadcast_list (MMModemCellBroadcast *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -92,6 +99,23 @@ gboolean mm_modem_cell_broadcast_delete_sync (MMModemCellBroadcast *self,
GCancellable *cancellable,
GError **error);
+gboolean mm_modem_cell_broadcast_set_channels_finish (MMModemCellBroadcast *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_modem_cell_broadcast_set_channels (MMModemCellBroadcast *self,
+ const MMCellBroadcastChannels *channels,
+ guint n_channels,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean mm_modem_cell_broadcast_set_channels_sync (MMModemCellBroadcast *self,
+ const MMCellBroadcastChannels *channels,
+ guint n_channels,
+ GCancellable *cancellable,
+ GError **error);
+
G_END_DECLS
#endif /* _MM_MODEM_CELL_BROADCAST_H_ */
diff --git a/libmm-glib/tests/test-common-helpers.c b/libmm-glib/tests/test-common-helpers.c
index b8923ab3..a84314ba 100644
--- a/libmm-glib/tests/test-common-helpers.c
+++ b/libmm-glib/tests/test-common-helpers.c
@@ -762,6 +762,28 @@ sms_storages_to_string (void)
}
static void
+cell_broadcast_channels_to_string (void)
+{
+ gchar *channels_str = NULL;
+ MMCellBroadcastChannels channels[] = {
+ { .start = 4383, .end = 4383 },
+ { .start = 4380, .end = 4382 }
+ };
+
+ channels_str = mm_common_build_channels_string (NULL, 0);
+ g_assert_cmpstr (channels_str, ==, "none");
+ g_clear_pointer (&channels_str, g_free);
+
+ channels_str = mm_common_build_channels_string (channels, 1);
+ g_assert_cmpstr (channels_str, ==, "4383");
+ g_clear_pointer (&channels_str, g_free);
+
+ channels_str = mm_common_build_channels_string (channels, 2);
+ g_assert_cmpstr (channels_str, ==, "4383,4380-4382");
+ g_clear_pointer (&channels_str, g_free);
+}
+
+static void
capabilities_from_string (void)
{
MMModemCapability capability = MM_MODEM_CAPABILITY_ANY;
@@ -1012,7 +1034,7 @@ call_direction_from_string (void)
call_direction = mm_common_get_call_direction_from_string ("incoming", &error);
g_assert_no_error (error);
- g_assert (call_direction == MM_CALL_DIRECTION_INCOMING);
+ g_assert (call_direction == MM_CALL_DIRECTION_INCOMING);
}
static void
@@ -1256,7 +1278,7 @@ access_type_preference_from_string (void)
access_type_preference = mm_common_get_access_type_preference_from_string ("3gpp-preferred", &error);
g_assert_no_error (error);
- g_assert (access_type_preference == MM_BEARER_ACCESS_TYPE_PREFERENCE_3GPP_PREFERRED);
+ g_assert (access_type_preference == MM_BEARER_ACCESS_TYPE_PREFERENCE_3GPP_PREFERRED);
}
static void
@@ -1275,6 +1297,68 @@ profile_source_from_string (void)
g_assert (profile_source == MM_BEARER_PROFILE_SOURCE_MODEM);
}
+static void
+cell_broadcast_channels_from_string (void)
+{
+ MMCellBroadcastChannels *channels = NULL;
+ guint n_channels = 0;
+ gboolean ret = FALSE;
+ GError *error = NULL;
+
+ ret = mm_common_get_cell_broadcast_channels_from_string ("not found", &channels, &n_channels, &error);
+ g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
+ g_assert_false (ret);
+ g_assert_cmpuint (n_channels, ==, 0);
+ g_assert_null (channels);
+ g_clear_error (&error);
+
+ ret = mm_common_get_cell_broadcast_channels_from_string ("4370", &channels, &n_channels, &error);
+ g_assert_no_error (error);
+ g_assert_true (ret);
+ g_assert_cmpuint (n_channels, ==, 1);
+ g_assert_cmpuint (channels[0].start, ==, 4370);
+ g_assert_cmpuint (channels[0].end, ==, 4370);
+ g_clear_pointer(&channels, g_free);
+
+ ret = mm_common_get_cell_broadcast_channels_from_string ("4370,4371-abc", &channels, &n_channels, &error);
+ g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
+ g_assert_false (ret);
+ g_assert_cmpuint (n_channels, ==, 0);
+ g_assert_null (channels);
+ g_clear_error (&error);
+
+ ret = mm_common_get_cell_broadcast_channels_from_string ("4370,,4371-5000", &channels, &n_channels, &error);
+ g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
+ g_assert_false (ret);
+ g_assert_cmpuint (n_channels, ==, 0);
+ g_assert_null (channels);
+ g_clear_error (&error);
+
+ ret = mm_common_get_cell_broadcast_channels_from_string ("4370,,-5000", &channels, &n_channels, &error);
+ g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
+ g_assert_false (ret);
+ g_assert_cmpuint (n_channels, ==, 0);
+ g_assert_null (channels);
+ g_clear_error (&error);
+
+ ret = mm_common_get_cell_broadcast_channels_from_string ("65537", &channels, &n_channels, &error);
+ g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
+ g_assert_false (ret);
+ g_assert_cmpuint (n_channels, ==, 0);
+ g_assert_null (channels);
+ g_clear_error (&error);
+
+ ret = mm_common_get_cell_broadcast_channels_from_string ("4370,4371-5000", &channels, &n_channels, &error);
+ g_assert_no_error (error);
+ g_assert_true (ret);
+ g_assert_cmpuint (n_channels, ==, 2);
+ g_assert_cmpuint (channels[0].start, ==, 4370);
+ g_assert_cmpuint (channels[0].end, ==, 4370);
+ g_assert_cmpuint (channels[1].start, ==, 4371);
+ g_assert_cmpuint (channels[1].end, ==, 5000);
+ g_clear_pointer(&channels, g_free);
+}
+
/**************************************************************/
int main (int argc, char **argv)
@@ -1328,6 +1412,7 @@ int main (int argc, char **argv)
g_test_add_func ("/MM/Common/StrConvTo/mode-combinations", mode_combinations_to_string);
g_test_add_func ("/MM/Common/StrConvTo/ports", ports_to_string);
g_test_add_func ("/MM/Common/StrConvTo/sms-storages", sms_storages_to_string);
+ g_test_add_func ("/MM/Common/StrConvTo/cb-channels", cell_broadcast_channels_to_string);
g_test_add_func ("/MM/Common/StrConvFrom/capabilities", capabilities_from_string);
g_test_add_func ("/MM/Common/StrConvFrom/modes", modes_from_string);
@@ -1354,6 +1439,7 @@ int main (int argc, char **argv)
g_test_add_func ("/MM/Common/StrConvFrom/3gpp_drx_cycle", _3gpp_drx_cycle_from_string);
g_test_add_func ("/MM/Common/StrConvFrom/access_type", access_type_preference_from_string);
g_test_add_func ("/MM/Common/StrConvFrom/profile_source", profile_source_from_string);
+ g_test_add_func ("/MM/Common/StrConvFrom/cb_channels", cell_broadcast_channels_from_string);
return g_test_run ();
}