[PATCH] libmm-glib: add MMPco for handling raw PCO data

Aleksander Morgado aleksander at aleksander.es
Tue Aug 14 07:48:24 UTC 2018


Hey,

>
> Before submitting further patches, I just want to make sure the MMPco
> gobject implemented in this patch is what you're looking for. MMPco will
> be mostly kept in GList (unless you prefer another gobject).
>
> If this is the right API to be in libmm-glib, I'll submit a few
> follow-up patches to integrate the rest of the PCO support. Otherwise, I
> can move it to src/ instead.
>

It looks good to me. We should probably wait to have all remaining
patches ready before integrating this one, though. How about you
re-suggest this one in a MR along with the remainining ones?

Cheers!

>
>
>  docs/reference/libmm-glib/libmm-glib-docs.xml |   4 +
>  .../libmm-glib/libmm-glib-sections.txt        |  28 ++
>  libmm-glib/Makefile.am                        |   3 +
>  libmm-glib/libmm-glib.h                       |   1 +
>  libmm-glib/mm-pco.c                           | 256 ++++++++++++++++++
>  libmm-glib/mm-pco.h                           |  85 ++++++
>  6 files changed, 377 insertions(+)
>  create mode 100644 libmm-glib/mm-pco.c
>  create mode 100644 libmm-glib/mm-pco.h
>
> diff --git a/docs/reference/libmm-glib/libmm-glib-docs.xml b/docs/reference/libmm-glib/libmm-glib-docs.xml
> index 4b0a564c..80b3ce57 100644
> --- a/docs/reference/libmm-glib/libmm-glib-docs.xml
> +++ b/docs/reference/libmm-glib/libmm-glib-docs.xml
> @@ -129,6 +129,10 @@
>          <title>Voice support</title>
>          <xi:include href="xml/mm-modem-voice.xml"/>
>        </section>
> +      <section>
> +        <title>PCO support</title>
> +        <xi:include href="xml/mm-pco.xml"/>
> +      </section>
>      </chapter>
>
>      <chapter>
> diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt
> index bfa57f1c..01a5de27 100644
> --- a/docs/reference/libmm-glib/libmm-glib-sections.txt
> +++ b/docs/reference/libmm-glib/libmm-glib-sections.txt
> @@ -1308,6 +1308,34 @@ MM_TYPE_CALL_PROPERTIES
>  mm_call_properties_get_type
>  </SECTION>
>
> +<SECTION>
> +<FILE>mm-pco</FILE>
> +<TITLE>MMPco</TITLE>
> +MMPco
> +<SUBSECTION New>
> +mm_pco_new
> +<SUBSECTION GettersSetters>
> +mm_pco_get_session_id
> +mm_pco_is_complete
> +mm_pco_get_data
> +<SUBSECTION Private>
> +mm_pco_from_variant
> +mm_pco_to_variant
> +mm_pco_set_session_id
> +mm_pco_set_complete
> +mm_pco_set_data
> +<SUBSECTION Standard>
> +MMPcoClass
> +MMPcoPrivate
> +MM_IS_PCO
> +MM_IS_PCO_CLASS
> +MM_PCO
> +MM_PCO_CLASS
> +MM_PCO_GET_CLASS
> +MM_TYPE_PCO
> +mm_pco_get_type
> +</SECTION>
> +
>  <SECTION>
>  <FILE>mm-enums-types</FILE>
>  <TITLE>Flags and Enumerations</TITLE>
> diff --git a/libmm-glib/Makefile.am b/libmm-glib/Makefile.am
> index 7d554ad0..4c890592 100644
> --- a/libmm-glib/Makefile.am
> +++ b/libmm-glib/Makefile.am
> @@ -83,6 +83,8 @@ libmm_glib_la_SOURCES = \
>         mm-signal.c \
>         mm-kernel-event-properties.h \
>         mm-kernel-event-properties.c \
> +       mm-pco.h \
> +       mm-pco.c \
>         $(NULL)
>
>  libmm_glib_la_CPPFLAGS = \
> @@ -152,6 +154,7 @@ include_HEADERS = \
>         mm-cdma-manual-activation-properties.h \
>         mm-signal.h \
>         mm-kernel-event-properties.h \
> +       mm-pco.h \
>         $(NULL)
>
>  CLEANFILES =
> diff --git a/libmm-glib/libmm-glib.h b/libmm-glib/libmm-glib.h
> index 81175ca9..d45a6b12 100644
> --- a/libmm-glib/libmm-glib.h
> +++ b/libmm-glib/libmm-glib.h
> @@ -78,6 +78,7 @@
>  #include <mm-cdma-manual-activation-properties.h>
>  #include <mm-signal.h>
>  #include <mm-kernel-event-properties.h>
> +#include <mm-pco.h>
>
>  /* generated */
>  #include <mm-errors-types.h>
> diff --git a/libmm-glib/mm-pco.c b/libmm-glib/mm-pco.c
> new file mode 100644
> index 00000000..21390b84
> --- /dev/null
> +++ b/libmm-glib/mm-pco.c
> @@ -0,0 +1,256 @@
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details:
> + *
> + * Copyright 2018 Google LLC.
> + */
> +
> +#include <string.h>
> +#include <glib.h>
> +
> +#include "mm-enums-types.h"
> +#include "mm-errors-types.h"
> +#include "mm-common-helpers.h"
> +#include "mm-pco.h"
> +
> +/**
> + * SECTION: mm-pco
> + * @title: MMPco
> + * @short_description: Helper object to handle 3GPP PCO.
> + *
> + * The #MMPco is an object handling the raw 3GPP Protocol Configuration Options
> + * (PCO) that the modem has received from the network.
> + *
> + * This object is retrieved with either mm_modem_3gpp_get_pco() or
> + * mm_modem_3gpp_get_pco_sync().
> + */
> +
> +G_DEFINE_TYPE (MMPco, mm_pco, G_TYPE_OBJECT);
> +
> +struct _MMPcoPrivate {
> +    /* Session ID, signature 'u' */
> +    guint32 session_id;
> +    /* Flag indicating if the PCO data is complete or partial, signature 'b' */
> +    gboolean is_complete;
> +    /* Raw PCO data, signature 'ay' */
> +    GBytes *data;
> +};
> +
> +/*****************************************************************************/
> +
> +static GBytes *
> +_g_variant_get_bytes (GVariant *variant)
> +{
> +    GByteArray *byte_array;
> +    guint num_bytes;
> +    GVariantIter iter;
> +    GVariant *value;
> +
> +    g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE ("ay")));
> +
> +    num_bytes = g_variant_n_children (variant);
> +    if (num_bytes == 0)
> +        return NULL;
> +
> +    byte_array = g_byte_array_sized_new (num_bytes);
> +
> +    g_variant_iter_init (&iter, variant);
> +    while (g_variant_iter_loop (&iter, "y", &value)) {
> +        guint8 byte;
> +
> +        byte = g_variant_get_byte (value);
> +        g_byte_array_append (byte_array, &byte, sizeof (byte));
> +    }
> +
> +    return g_byte_array_free_to_bytes (byte_array);
> +}
> +
> +/*****************************************************************************/
> +
> +/**
> + * mm_pco_get_session_id:
> + * @self: a #MMPco.
> + *
> + * Gets the session ID associated with the PCO.
> + *
> + * Returns: the session ID.
> + */
> +guint32
> +mm_pco_get_session_id (MMPco *self)
> +{
> +    g_return_val_if_fail (MM_IS_PCO (self), G_MAXUINT32);
> +
> +    return self->priv->session_id;
> +}
> +
> +void
> +mm_pco_set_session_id (MMPco *self,
> +                       guint32 session_id)
> +{
> +    g_return_if_fail (MM_IS_PCO (self));
> +
> +    self->priv->session_id = session_id;
> +}
> +
> +/*****************************************************************************/
> +
> +/**
> + * mm_pco_is_complete:
> + * @self: a #MMPco.
> + *
> + * Gets the complete flag that indicates whether the PCO data contains the
> + * complete PCO structure received from the network.
> + *
> + * Returns: %TRUE if the PCO data contains the complete PCO structure, %FALSE otherwise.
> + */
> +gboolean
> +mm_pco_is_complete (MMPco *self)
> +{
> +    g_return_val_if_fail (MM_IS_PCO (self), FALSE);
> +
> +    return self->priv->is_complete;
> +}
> +
> +void
> +mm_pco_set_complete (MMPco *self,
> +                     gboolean is_complete)
> +{
> +    g_return_if_fail (MM_IS_PCO (self));
> +
> +    self->priv->is_complete = is_complete;
> +}
> +
> +/*****************************************************************************/
> +
> +/**
> + * mm_pco_get_data:
> + * @self: a #MMPco.
> + *
> + * Gets the PCO data in raw bytes.
> + *
> + * Returns: (transfer none): the PCO data.
> + */
> +GBytes *
> +mm_pco_get_data (MMPco *self)
> +{
> +    g_return_val_if_fail (MM_IS_PCO (self), NULL);
> +
> +    return self->priv->data;
> +}
> +
> +void
> +mm_pco_set_data (MMPco *self,
> +                 GBytes *data)
> +{
> +    g_return_if_fail (MM_IS_PCO (self));
> +
> +    g_bytes_unref (self->priv->data);
> +
> +    self->priv->data = data ? g_bytes_ref (data) : NULL;
> +}
> +
> +/*****************************************************************************/
> +
> +MMPco *
> +mm_pco_from_variant (GVariant *variant,
> +                     GError **error)
> +{
> +    MMPco *pco;
> +
> +    pco = mm_pco_new ();
> +    if (!variant)
> +        return pco;
> +
> +    if (!g_variant_is_of_type (variant, G_VARIANT_TYPE ("(ubay)"))) {
> +        g_set_error (error,
> +                     MM_CORE_ERROR,
> +                     MM_CORE_ERROR_INVALID_ARGS,
> +                     "Cannot create PCO from variant: "
> +                     "invalid variant type received");
> +        g_object_unref (pco);
> +        return NULL;
> +    }
> +
> +    pco->priv->session_id = g_variant_get_uint32 (variant);
> +    pco->priv->is_complete = g_variant_get_boolean (variant);
> +
> +    g_bytes_unref (pco->priv->data);
> +    pco->priv->data = _g_variant_get_bytes (variant);
> +
> +    return pco;
> +}
> +
> +/*****************************************************************************/
> +
> +GVariant *
> +mm_pco_to_variant (MMPco *self)
> +{
> +    GVariantBuilder builder;
> +    gsize i, pco_data_size;
> +    const guint8 *pco_data;
> +
> +    /* Allow NULL */
> +    if (!self)
> +        return NULL;
> +
> +    g_return_val_if_fail (MM_IS_PCO (self), NULL);
> +
> +    g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ubay)"));
> +
> +    g_variant_builder_add (&builder, "u", self->priv->session_id);
> +    g_variant_builder_add (&builder, "b", self->priv->is_complete);
> +
> +    g_variant_builder_open (&builder, G_VARIANT_TYPE ("ay"));
> +    if (self->priv->data) {
> +        pco_data = g_bytes_get_data (self->priv->data, &pco_data_size);
> +        for (i = 0; i < pco_data_size; ++i)
> +            g_variant_builder_add (&builder, "y", pco_data[i]);
> +    }
> +    g_variant_builder_close (&builder);
> +
> +    return g_variant_ref_sink (g_variant_builder_end (&builder));
> +}
> +
> +/*****************************************************************************/
> +
> +MMPco *
> +mm_pco_new (void)
> +{
> +    return (MM_PCO (g_object_new (MM_TYPE_PCO, NULL)));
> +}
> +
> +static void
> +mm_pco_init (MMPco *self)
> +{
> +    self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_PCO, MMPcoPrivate);
> +
> +    self->priv->session_id = G_MAXUINT32;
> +}
> +
> +static void
> +finalize (GObject *object)
> +{
> +    MMPco *self = MM_PCO (object);
> +
> +    g_bytes_unref (self->priv->data);
> +
> +    G_OBJECT_CLASS (mm_pco_parent_class)->finalize (object);
> +}
> +
> +static void
> +mm_pco_class_init (MMPcoClass *klass)
> +{
> +    GObjectClass *object_class = G_OBJECT_CLASS (klass);
> +
> +    g_type_class_add_private (object_class, sizeof (MMPcoPrivate));
> +
> +    object_class->finalize = finalize;
> +}
> diff --git a/libmm-glib/mm-pco.h b/libmm-glib/mm-pco.h
> new file mode 100644
> index 00000000..85a221b9
> --- /dev/null
> +++ b/libmm-glib/mm-pco.h
> @@ -0,0 +1,85 @@
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details:
> + *
> + * Copyright 2018 Google LLC.
> + */
> +
> +#ifndef MM_PCO_H
> +#define MM_PCO_H
> +
> +#if !defined (__LIBMM_GLIB_H_INSIDE__) && !defined (LIBMM_GLIB_COMPILATION)
> +#error "Only <libmm-glib.h> can be included directly."
> +#endif
> +
> +#include <ModemManager.h>
> +#include <glib-object.h>
> +
> +G_BEGIN_DECLS
> +
> +#define MM_TYPE_PCO            (mm_pco_get_type ())
> +#define MM_PCO(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PCO, MMPco))
> +#define MM_PCO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  MM_TYPE_PCO, MMPcoClass))
> +#define MM_IS_PCO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PCO))
> +#define MM_IS_PCO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  MM_TYPE_PCO))
> +#define MM_PCO_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  MM_TYPE_PCO, MMPcoClass))
> +
> +typedef struct _MMPco MMPco;
> +typedef struct _MMPcoClass MMPcoClass;
> +typedef struct _MMPcoPrivate MMPcoPrivate;
> +
> +/**
> + * MMPco:
> + *
> + * The #MMPco structure contains private data and should only be accessed
> + * using the provided API.
> + */
> +struct _MMPco {
> +    /*< private >*/
> +    GObject parent;
> +    MMPcoPrivate *priv;
> +};
> +
> +struct _MMPcoClass {
> +    /*< private >*/
> +    GObjectClass parent;
> +};
> +
> +GType mm_pco_get_type (void);
> +
> +
> +guint32   mm_pco_get_session_id (MMPco *self);
> +gboolean  mm_pco_is_complete    (MMPco *self);
> +GBytes   *mm_pco_get_data       (MMPco *self);
> +
> +/*****************************************************************************/
> +/* ModemManager/libmm-glib/mmcli specific methods */
> +
> +#if defined (_LIBMM_INSIDE_MM) ||    \
> +    defined (_LIBMM_INSIDE_MMCLI) || \
> +    defined (LIBMM_GLIB_COMPILATION)
> +
> +MMPco    *mm_pco_new            (void);
> +MMPco    *mm_pco_from_variant   (GVariant *variant,
> +                                 GError **error);
> +GVariant *mm_pco_to_variant     (MMPco *self);
> +void      mm_pco_set_session_id (MMPco *self,
> +                                 guint32 session_id);
> +void      mm_pco_set_complete   (MMPco *self,
> +                                 gboolean is_complete);
> +void      mm_pco_set_data       (MMPco *self,
> +                                 GBytes *data);
> +
> +#endif
> +
> +G_END_DECLS
> +
> +#endif /* MM_PCO_H */
> --
> 2.18.0.597.ga71716f1ad-goog
>



-- 
Aleksander
https://aleksander.es


More information about the ModemManager-devel mailing list