diff options
author | Dylan Van Assche <me@dylanvanassche.be> | 2023-01-01 16:17:12 +0100 |
---|---|---|
committer | Dylan Van Assche <me@dylanvanassche.be> | 2023-08-12 17:20:39 +0200 |
commit | d092dc5d001e586bd24687d7864fad7c0023855d (patch) | |
tree | d75d269048e30e67ec1deda1de18944d538b4fc8 | |
parent | 4c92bc8f50e7fc1182666e5865330e05e88c850d (diff) |
libqmi-glib,qmicli: implement IMSP service
IMSP service is already known by libqmi but without any implementation.
Add the Get Enabler State method to retrieve the IMS registation status.
IMS is split up in multiple services: IMS, IMSA, IMSP, IMSVT, and
IMSRTP. Other IMS services will be added in other patches.
-rw-r--r-- | data/qmi-service-imsp.json | 29 | ||||
-rw-r--r-- | docs/reference/libqmi-glib/libqmi-glib-common.sections | 14 | ||||
-rw-r--r-- | docs/reference/libqmi-glib/libqmi-glib-docs.xml | 10 | ||||
-rw-r--r-- | src/libqmi-glib/generated/meson.build | 3 | ||||
-rw-r--r-- | src/libqmi-glib/libqmi-glib.h | 3 | ||||
-rw-r--r-- | src/libqmi-glib/meson.build | 1 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-device.c | 7 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-enums-imsp.h | 58 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-message.c | 5 | ||||
-rw-r--r-- | src/qmicli/meson.build | 1 | ||||
-rw-r--r-- | src/qmicli/qmicli-imsp.c | 205 | ||||
-rw-r--r-- | src/qmicli/qmicli.c | 18 | ||||
-rw-r--r-- | src/qmicli/qmicli.h | 8 |
13 files changed, 358 insertions, 4 deletions
diff --git a/data/qmi-service-imsp.json b/data/qmi-service-imsp.json new file mode 100644 index 0000000..2be24c5 --- /dev/null +++ b/data/qmi-service-imsp.json @@ -0,0 +1,29 @@ +[ + // ********************************************************************************* + { "name" : "IMSP", + "type" : "Service" }, + + // ********************************************************************************* + { "name" : "QMI Client IMSP", + "type" : "Client", + "since" : "1.34" }, + + // ********************************************************************************* + { "name" : "QMI Message IMSP", + "type" : "Message-ID-Enum" }, + + // ********************************************************************************* + { "name" : "Get Enabler State", + "type" : "Message", + "service" : "IMSP", + "id" : "0x0024", + "since" : "1.34", + "output" : [ { "common-ref" : "Operation Result" }, + { "name" : "Enabler State", + "id" : "0x10", + "type" : "TLV", + "since" : "1.34", + "format" : "guint32", + "public-format" : "QmiImspEnablerState", + "prerequisites" : [ { "common-ref" : "Success" } ] } ] } +] diff --git a/docs/reference/libqmi-glib/libqmi-glib-common.sections b/docs/reference/libqmi-glib/libqmi-glib-common.sections index 39aa532..426eb01 100644 --- a/docs/reference/libqmi-glib/libqmi-glib-common.sections +++ b/docs/reference/libqmi-glib/libqmi-glib-common.sections @@ -31,6 +31,7 @@ HAVE_QMI_SERVICE_WDS HAVE_QMI_SERVICE_WMS HAVE_QMI_SERVICE_DPM HAVE_QMI_SERVICE_FOX +HAVE_QMI_SERVICE_IMSP </SECTION> <SECTION> @@ -1334,6 +1335,19 @@ qmi_fox_firmware_version_type_get_type </SECTION> <SECTION> +<FILE>qmi-enums-imsp</FILE> +<TITLE>IMSP enumerations and flags</TITLE> +QmiImspEnablerState +<SUBSECTION Methods> +qmi_imsp_enabler_state_get_string +<SUBSECTION Private> +qmi_imsp_enabler_state_build_string_from_mask +<SUBSECTION Standard> +QMI_TYPE_IMSP_ENABLER_STATE +qmi_imsp_enabler_state_get_type +</SECTION> + +<SECTION> <FILE>qmi-errors</FILE> <TITLE>Errors</TITLE> QmiCoreError diff --git a/docs/reference/libqmi-glib/libqmi-glib-docs.xml b/docs/reference/libqmi-glib/libqmi-glib-docs.xml index 5d3c3a6..a647808 100644 --- a/docs/reference/libqmi-glib/libqmi-glib-docs.xml +++ b/docs/reference/libqmi-glib/libqmi-glib-docs.xml @@ -588,6 +588,16 @@ </chapter> <chapter> + <title>IP Multimedia Subsystem Presence Service (IMSP)</title> + <xi:include href="xml/qmi-client-imsp.xml"/> + <xi:include href="xml/qmi-enums-imsp.xml"/> + <section> + <title>IMSP Requests</title> + <xi:include href="xml/qmi-message-imsp-get-enabler-state.xml"/> + </section> + </chapter> + + <chapter> <title>Compatibility with older versions</title> <xi:include href="xml/qmi-compat.xml"/> </chapter> diff --git a/src/libqmi-glib/generated/meson.build b/src/libqmi-glib/generated/meson.build index 4e946e9..cd6dbfd 100644 --- a/src/libqmi-glib/generated/meson.build +++ b/src/libqmi-glib/generated/meson.build @@ -68,7 +68,7 @@ gen_headers += custom_target( python, qmi_mkenums, '--enums-only', - '--fhead', '#ifndef __LIBQMI_GLIB_ENUM_TYPES_H__\n#define __LIBQMI_GLIB_ENUM_TYPES_H__\n#include "qmi-enums.h"\n#include "qmi-enums-wds.h"\n#include "qmi-enums-dms.h"\n#include "qmi-enums-nas.h"\n#include "qmi-enums-wms.h"\n#include "qmi-enums-pds.h"\n#include "qmi-enums-pdc.h"\n#include "qmi-enums-pbm.h"\n#include "qmi-enums-uim.h"\n#include "qmi-enums-sar.h"\n#include "qmi-enums-oma.h"\n#include "qmi-enums-wda.h"\n#include "qmi-enums-voice.h"\n#include "qmi-enums-loc.h"\n#include "qmi-enums-qos.h"\n#include "qmi-enums-gas.h"\n#include "qmi-enums-dsd.h"\n#include "qmi-enums-fox.h"\n#include "qmi-device.h"\n', + '--fhead', '#ifndef __LIBQMI_GLIB_ENUM_TYPES_H__\n#define __LIBQMI_GLIB_ENUM_TYPES_H__\n#include "qmi-enums.h"\n#include "qmi-enums-wds.h"\n#include "qmi-enums-dms.h"\n#include "qmi-enums-nas.h"\n#include "qmi-enums-wms.h"\n#include "qmi-enums-pds.h"\n#include "qmi-enums-pdc.h"\n#include "qmi-enums-pbm.h"\n#include "qmi-enums-uim.h"\n#include "qmi-enums-sar.h"\n#include "qmi-enums-oma.h"\n#include "qmi-enums-wda.h"\n#include "qmi-enums-voice.h"\n#include "qmi-enums-loc.h"\n#include "qmi-enums-qos.h"\n#include "qmi-enums-gas.h"\n#include "qmi-enums-dsd.h"\n#include "qmi-enums-fox.h"\n#include "qmi-enums-imsp.h"\n#include "qmi-device.h"\n', '--template', files(templates_dir / enum_types + '.h.template'), '--ftail', '#endif /* __LIBQMI_GLIB_ENUM_TYPES_H__ */\n', '@INPUT@'], @@ -240,6 +240,7 @@ services = [ 'dms', 'dpm', 'dsd', + 'imsp', 'fox', 'gas', 'gms', diff --git a/src/libqmi-glib/libqmi-glib.h b/src/libqmi-glib/libqmi-glib.h index 9193de2..55900a9 100644 --- a/src/libqmi-glib/libqmi-glib.h +++ b/src/libqmi-glib/libqmi-glib.h @@ -101,6 +101,9 @@ #include "qmi-atr.h" +#include "qmi-enums-imsp.h" +#include "qmi-imsp.h" + /* generated */ #include "qmi-error-types.h" #include "qmi-enum-types.h" diff --git a/src/libqmi-glib/meson.build b/src/libqmi-glib/meson.build index 84c8e63..08ce861 100644 --- a/src/libqmi-glib/meson.build +++ b/src/libqmi-glib/meson.build @@ -12,6 +12,7 @@ qmi_enums_headers = files( 'qmi-enums-dsd.h', 'qmi-enums-fox.h', 'qmi-enums-gas.h', + 'qmi-enums-imsp.h', 'qmi-enums-loc.h', 'qmi-enums-nas.h', 'qmi-enums-oma.h', diff --git a/src/libqmi-glib/qmi-device.c b/src/libqmi-glib/qmi-device.c index 4c1fea0..b323b5c 100644 --- a/src/libqmi-glib/qmi-device.c +++ b/src/libqmi-glib/qmi-device.c @@ -58,6 +58,7 @@ #include "qmi-dpm.h" #include "qmi-fox.h" #include "qmi-atr.h" +#include "qmi-imsp.h" #include "qmi-utils.h" #include "qmi-helpers.h" #include "qmi-error-types.h" @@ -1319,6 +1320,11 @@ qmi_device_allocate_client (QmiDevice *self, ctx->client_type = QMI_TYPE_CLIENT_ATR; #endif break; + case QMI_SERVICE_IMSP: +#if defined HAVE_QMI_SERVICE_IMSP + ctx->client_type = QMI_TYPE_CLIENT_IMSP; +#endif + break; case QMI_SERVICE_UNKNOWN: g_assert_not_reached (); @@ -1341,7 +1347,6 @@ qmi_device_allocate_client (QmiDevice *self, case QMI_SERVICE_RFSA: case QMI_SERVICE_CSVT: case QMI_SERVICE_QCMAP: - case QMI_SERVICE_IMSP: case QMI_SERVICE_IMSVT: case QMI_SERVICE_IMSA: case QMI_SERVICE_COEX: diff --git a/src/libqmi-glib/qmi-enums-imsp.h b/src/libqmi-glib/qmi-enums-imsp.h new file mode 100644 index 0000000..781f0c9 --- /dev/null +++ b/src/libqmi-glib/qmi-enums-imsp.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * libqmi-glib -- GLib/GIO based library to control QMI devices + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2023 Dylan Van Assche <me@dylanvanassche.be> + */ + +#ifndef _LIBQMI_GLIB_QMI_ENUMS_IMSP_H_ +#define _LIBQMI_GLIB_QMI_ENUMS_IMSP_H_ + +#if !defined (__LIBQMI_GLIB_H_INSIDE__) && !defined (LIBQMI_GLIB_COMPILATION) +#error "Only <libqmi-glib.h> can be included directly." +#endif + +/** + * SECTION: qmi-enums-imsp + * @title: IMSP enumerations and flags + * @short_description: Enumerations and flags in the IMSP service. + * + * This section defines enumerations and flags used in the IMSP service + * interface. + */ + +/** + * QmiImspEnablerState: + * @QMI_IMSP_ENABLER_STATE_UNINITIALIZED: IMS is not initialized yet. + * @QMI_IMSP_ENABLER_STATE_INITIALIZED: IMS is initialized, but not registered yet with the network IMS service. + * @QMI_IMSP_ENABLER_STATE_AIRPLANE: IMS is initialized but device is in airplane mode. + * @QMI_IMSP_ENABLER_STATE_REGISTERED: IMS is initialized and registered. + * + * IMS Presence enabler state. + * + * Since: 1.34 + */ +typedef enum { /*< since=1.34 >*/ + QMI_IMSP_ENABLER_STATE_UNINITIALIZED = 0x01, + QMI_IMSP_ENABLER_STATE_INITIALIZED = 0x02, + QMI_IMSP_ENABLER_STATE_AIRPLANE = 0x03, + QMI_IMSP_ENABLER_STATE_REGISTERED = 0x04, +} QmiImspEnablerState; + +#endif /* _LIBQMI_GLIB_QMI_ENUMS_IMSP_H_ */ + diff --git a/src/libqmi-glib/qmi-message.c b/src/libqmi-glib/qmi-message.c index 1f09360..c036276 100644 --- a/src/libqmi-glib/qmi-message.c +++ b/src/libqmi-glib/qmi-message.c @@ -1737,6 +1737,10 @@ qmi_message_get_printable_full (QmiMessage *self, #if defined HAVE_QMI_SERVICE_ATR contents = __qmi_message_atr_get_printable (self, context, line_prefix); #endif + case QMI_SERVICE_IMSP: +#if defined HAVE_QMI_SERVICE_IMSP + contents = __qmi_message_imsp_get_printable (self, context, line_prefix); +#endif break; case QMI_SERVICE_UNKNOWN: @@ -1761,7 +1765,6 @@ qmi_message_get_printable_full (QmiMessage *self, case QMI_SERVICE_RFSA: case QMI_SERVICE_CSVT: case QMI_SERVICE_QCMAP: - case QMI_SERVICE_IMSP: case QMI_SERVICE_IMSVT: case QMI_SERVICE_IMSA: case QMI_SERVICE_COEX: diff --git a/src/qmicli/meson.build b/src/qmicli/meson.build index 47efe05..d1a7a06 100644 --- a/src/qmicli/meson.build +++ b/src/qmicli/meson.build @@ -19,6 +19,7 @@ sources = files( 'qmicli-dms.c', 'qmicli-dpm.c', 'qmicli-dsd.c', + 'qmicli-imsp.c', 'qmicli-fox.c', 'qmicli-gas.c', 'qmicli-gms.c', diff --git a/src/qmicli/qmicli-imsp.c b/src/qmicli/qmicli-imsp.c new file mode 100644 index 0000000..52dedfd --- /dev/null +++ b/src/qmicli/qmicli-imsp.c @@ -0,0 +1,205 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * qmicli -- Command line interface to control QMI devices + * + * 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. + * + * 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) 2023 Dylan Van Assche <me@dylanvanassche.be> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <locale.h> +#include <string.h> +#include <assert.h> + +#include <glib.h> +#include <gio/gio.h> + +#include <libqmi-glib.h> + +#include "qmicli.h" +#include "qmicli-helpers.h" + +#if defined HAVE_QMI_SERVICE_IMSP + +/* Context */ +typedef struct { + QmiDevice *device; + QmiClientImsp *client; + GCancellable *cancellable; +} Context; +static Context *ctx; + +/* Options */ +static gboolean get_enabler_state_flag; +static gboolean noop_flag; + +static GOptionEntry entries[] = { +#if defined HAVE_QMI_MESSAGE_IMSP_GET_ENABLER_STATE + { "imsp-get-enabler-state", 0, 0, G_OPTION_ARG_NONE, &get_enabler_state_flag, + "Get IMSP enabler state", + NULL + }, +#endif + { "imsp-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag, + "Just allocate or release a IMSP client. Use with `--client-no-release-cid' and/or `--client-cid'", + NULL + }, + { NULL } +}; + +GOptionGroup * +qmicli_imsp_get_option_group (void) +{ + GOptionGroup *group; + + group = g_option_group_new ("imsp", + "IMSP options:", + "Show IP Multimedia Subsystem Presence Service options", + NULL, + NULL); + g_option_group_add_entries (group, entries); + + return group; +} + +gboolean +qmicli_imsp_options_enabled (void) +{ + static guint n_actions = 0; + static gboolean checked = FALSE; + + if (checked) + return !!n_actions; + + n_actions = (get_enabler_state_flag + + noop_flag); + + if (n_actions > 1) { + g_printerr ("error: too many IMSP actions requested\n"); + exit (EXIT_FAILURE); + } + + checked = TRUE; + return !!n_actions; +} + +static void +context_free (Context *context) +{ + if (!context) + return; + + if (context->cancellable) + g_object_unref (context->cancellable); + if (context->device) + g_object_unref (context->device); + if (context->client) + g_object_unref (context->client); + g_slice_free (Context, context); +} + +static void +operation_shutdown (gboolean operation_status) +{ + /* Cleanup context and finish async operation */ + context_free (ctx); + qmicli_async_operation_done (operation_status, FALSE); +} + +#if defined HAVE_QMI_MESSAGE_IMSP_GET_ENABLER_STATE + +static void +get_enabler_state_ready (QmiClientImsp *client, + GAsyncResult *res) +{ + QmiMessageImspGetEnablerStateOutput *output; + QmiImspEnablerState enabler_state; + GError *error = NULL; + + output = qmi_client_imsp_get_enabler_state_finish (client, res, &error); + if (!output) { + g_printerr ("error: operation failed: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + + if (!qmi_message_imsp_get_enabler_state_output_get_result (output, &error)) { + g_printerr ("error: couldn't get enabler state: %s\n", error->message); + g_error_free (error); + qmi_message_imsp_get_enabler_state_output_unref (output); + operation_shutdown (FALSE); + return; + } + + g_print ("[%s] IMSP enabler state retrieved:\n", qmi_device_get_path_display (ctx->device)); + + if (qmi_message_imsp_get_enabler_state_output_get_enabler_state (output, &enabler_state, NULL)) { + g_print ("\tRegistration status: '%s'\n", + qmi_imsp_enabler_state_get_string (enabler_state)); + } + + qmi_message_imsp_get_enabler_state_output_unref (output); + operation_shutdown (TRUE); +} + +#endif /* HAVE_QMI_MESSAGE_IMSP_GET_ENABLER_STATE */ + +static gboolean +noop_cb (gpointer unused) +{ + operation_shutdown (TRUE); + return FALSE; +} + +void +qmicli_imsp_run (QmiDevice *device, + QmiClientImsp *client, + GCancellable *cancellable) +{ + /* Initialize context */ + ctx = g_slice_new (Context); + ctx->device = g_object_ref (device); + ctx->client = g_object_ref (client); + ctx->cancellable = g_object_ref (cancellable); + +#if defined HAVE_QMI_MESSAGE_IMSP_GET_ENABLER_STATE + if (get_enabler_state_flag) { + g_debug ("Asynchronously getting enabler state..."); + + qmi_client_imsp_get_enabler_state (ctx->client, + NULL, + 10, + ctx->cancellable, + (GAsyncReadyCallback)get_enabler_state_ready, + NULL); + return; + } +#endif /* HAVE_QMI_MESSAGE_IMSP_GET_ENABLER_STATE */ + + /* Just client allocate/release? */ + if (noop_flag) { + g_idle_add (noop_cb, NULL); + return; + } + + g_warn_if_reached (); +} + +#endif /* HAVE_QMI_SERVICE_IMSP */ + diff --git a/src/qmicli/qmicli.c b/src/qmicli/qmicli.c index b978b10..b1288b1 100644 --- a/src/qmicli/qmicli.c +++ b/src/qmicli/qmicli.c @@ -483,6 +483,13 @@ allocate_client_ready (QmiDevice *dev, #else break; #endif + case QMI_SERVICE_IMSP: +#if defined HAVE_QMI_SERVICE_IMSP + qmicli_imsp_run (dev, QMI_CLIENT_IMSP (client), cancellable); + return; +#else + break; +#endif case QMI_SERVICE_UNKNOWN: case QMI_SERVICE_CTL: case QMI_SERVICE_AUTH: @@ -503,7 +510,6 @@ allocate_client_ready (QmiDevice *dev, case QMI_SERVICE_RFSA: case QMI_SERVICE_CSVT: case QMI_SERVICE_QCMAP: - case QMI_SERVICE_IMSP: case QMI_SERVICE_IMSVT: case QMI_SERVICE_IMSA: case QMI_SERVICE_COEX: @@ -947,6 +953,13 @@ parse_actions (void) } #endif +#if defined HAVE_QMI_SERVICE_IMSP + if (qmicli_imsp_options_enabled ()) { + service = QMI_SERVICE_IMSP; + actions_enabled++; + } +#endif + /* Cannot mix actions from different services */ if (actions_enabled > 1) { g_printerr ("error: cannot execute multiple actions of different services\n"); @@ -1026,6 +1039,9 @@ int main (int argc, char **argv) #if defined HAVE_QMI_SERVICE_ATR g_option_context_add_group (context, qmicli_atr_get_option_group ()); #endif +#if defined HAVE_QMI_SERVICE_IMSP + g_option_context_add_group (context, qmicli_imsp_get_option_group ()); +#endif g_option_context_add_group (context, qmicli_link_management_get_option_group ()); g_option_context_add_group (context, qmicli_qmiwwan_get_option_group ()); g_option_context_add_main_entries (context, main_entries, NULL); diff --git a/src/qmicli/qmicli.h b/src/qmicli/qmicli.h index e5cc928..6c418d6 100644 --- a/src/qmicli/qmicli.h +++ b/src/qmicli/qmicli.h @@ -185,4 +185,12 @@ void qmicli_atr_run (QmiDevice *device, GCancellable *cancellable); #endif +#if defined HAVE_QMI_SERVICE_IMSP +GOptionGroup *qmicli_imsp_get_option_group (void); +gboolean qmicli_imsp_options_enabled (void); +void qmicli_imsp_run (QmiDevice *device, + QmiClientImsp *client, + GCancellable *cancellable); +#endif + #endif /* __QMICLI_H__ */ |