add qmi-nmea placeholder (copy of qmicli)

This commit is contained in:
Daniel Barlow 2024-07-23 20:56:05 +01:00
parent b8aa0ae9b1
commit 1a0e19908a
35 changed files with 31110 additions and 0 deletions

View File

@ -39,6 +39,7 @@ in {
modemmanager-small = mm;
satellite = prev.satellite.override { modemmanager = mm; };
maps = final.callPackage ./pkgs/maps {};
qmi-nmea = final.callPackage ./pkgs/qmi-nmea {};
})
];

View File

@ -7,4 +7,5 @@ let
in {
inherit (nixos.config.system) toplevel;
inherit (nixos.config.mobile) outputs;
inherit (nixos) pkgs;
}

21
pkgs/qmi-nmea/Makefile Normal file
View File

@ -0,0 +1,21 @@
PREFIX?=/usr/local
CFLAGS=\
-DPACKAGE_VERSION=0.1 -I. \
$(shell $(PKG_CONFIG) --cflags qmi-glib) \
$(shell $(PKG_CONFIG) --cflags mbim-glib) \
$(shell $(PKG_CONFIG) --cflags glib-2.0)
LDFLAGS=\
$(shell $(PKG_CONFIG) --libs qmi-glib) \
$(shell $(PKG_CONFIG) --libs mbim-glib) \
$(shell $(PKG_CONFIG) --libs glib-2.0)
default: qmi-nmea
SRCS=qmi-nmea.c qmicli-atr.c qmicli-dms.c qmicli-dpm.c qmicli-dsd.c qmicli-fox.c qmicli-gas.c qmicli-gms.c qmicli-helpers.c qmicli-imsa.c qmicli-ims.c qmicli-imsp.c qmicli-link-management.c qmicli-loc.c qmicli-nas.c qmicli-pbm.c qmicli-pdc.c qmicli-qmiwwan.c qmicli-qos.c qmicli-sar.c qmicli-uim.c qmicli-voice.c qmicli-wda.c qmicli-wds.c qmicli-wms.c
qmi-nmea: $(patsubst %.c,%.o,$(SRCS))
install:
install -D -t $(PREFIX)/bin qmi-nmea

1
pkgs/qmi-nmea/config.h Normal file
View File

@ -0,0 +1 @@

16
pkgs/qmi-nmea/default.nix Normal file
View File

@ -0,0 +1,16 @@
{
stdenv,
libqmi,
libmbim,
glib,
pkg-config
}:
stdenv.mkDerivation {
name = "qmi-nmea";
src = ./.;
nativeBuildInputs = [ pkg-config ];
buildInputs = [ libqmi libmbim glib ];
PACKAGE_VERSION="1";
makeFlags = [ "PREFIX=${placeholder "out"}" ];
}

View File

@ -0,0 +1,16 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2023 Fabio Porcedda <fabio.porcedda@gmail.com>
*/
#ifndef _COMMON_QMI_COMMON_H_
#define _COMMON_QMI_COMMON_H_
#include <glib.h>
gchar *qmi_common_str_hex (gconstpointer mem,
gsize size,
gchar delimiter);
#endif /* _COMMON_QMI_COMMON_H_ */

1169
pkgs/qmi-nmea/qmi-nmea.c Normal file

File diff suppressed because it is too large Load Diff

155
pkgs/qmi-nmea/qmicli Normal file
View File

@ -0,0 +1,155 @@
# qmicli(1) completion -*- shell-script -*-
_qmicli()
{
local cur prev words cword split
_init_completion -s || return
case $prev in
-d|--device)
_filedir
return 0
;;
'--device-set-instance-id')
COMPREPLY=( $(compgen -W "[Instance-ID]" -- $cur) )
return 0
;;
'--device-open-net')
COMPREPLY=( $(compgen -W "[net-802-3|net-raw-ip|net-qos-header|net-no-qos-header]" -- $cur) )
return 0
;;
'--client-cid')
COMPREPLY=( $(compgen -W "[CID]" -- $cur) )
return 0
;;
'--dms-uim-set-pin-protection')
COMPREPLY=( $(compgen -W "[(PIN|PIN2),(disable|enable),(current-PIN)]" -- $cur) )
return 0
;;
'--dms-uim-verify-pin')
COMPREPLY=( $(compgen -W "[(PIN|PIN2),(current-PIN)]" -- $cur) )
return 0
;;
'--dms-uim-unblock-pin')
COMPREPLY=( $(compgen -W "[(PIN|PIN2),(PUK),(new-PIN)]" -- $cur) )
return 0
;;
'--dms-uim-change-pin')
COMPREPLY=( $(compgen -W "[(PIN|PIN2),(old-PIN),(new-PIN)]" -- $cur) )
return 0
;;
'--dms-uim-get-ck-status')
COMPREPLY=( $(compgen -W "[(pn|pu|pp|pc|pf)]" -- $cur) )
return 0
;;
'--dms-uim-set-ck-protection')
COMPREPLY=( $(compgen -W "[(pn|pu|pp|pc|pf),(disable),(key)]" -- $cur) )
return 0
;;
'--dms-uim-unblock-ck')
COMPREPLY=( $(compgen -W "[(pn|pu|pp|pc|pf),(key)]" -- $cur) )
return 0
;;
'--dms-set-operating-mode')
COMPREPLY=( $(compgen -W "[(Operating-Mode)]" -- $cur) )
return 0
;;
'--dms-activate-automatic')
COMPREPLY=( $(compgen -W "[Activation-Code]" -- $cur) )
return 0
;;
'--dms-activate-manual')
COMPREPLY=( $(compgen -W "[SPC,SID,MDN,MIN]" -- $cur) )
return 0
;;
'--dms-set-user-lock-state')
COMPREPLY=( $(compgen -W "[(disable|enable),(current-lock-code)]" -- $cur) )
return 0
;;
'--dms-set-user-lock-code')
COMPREPLY=( $(compgen -W "[(old-lock-code),(new-lock-code)]" -- $cur) )
return 0
;;
'--dms-write-user-data')
COMPREPLY=( $(compgen -W "[(User-data)]" -- $cur) )
return 0
;;
'--dms-restore-factory-defaults')
COMPREPLY=( $(compgen -W "[(Service-Programming-Code)]" -- $cur) )
return 0
;;
'--dms-validate-service-programming-code')
COMPREPLY=( $(compgen -W "[(Service-Programming-Code)]" -- $cur) )
return 0
;;
'--dms-select-stored-image')
COMPREPLY=( $(compgen -W "[modem#,pri#]" -- $cur) )
return 0
;;
'--dms-delete-stored-image')
COMPREPLY=( $(compgen -W "[modem#,pri#]" -- $cur) )
return 0
;;
'--nas-get-tx-rx-info')
COMPREPLY=( $(compgen -W "[(Radio-Interface)]" -- $cur) )
return 0
;;
'--nas-set-system-selection-preference')
COMPREPLY=( $(compgen -W "[cdma-1x|cdma-1xevdo|gsm|umts|lte|td-scdma]" -- $cur) )
return 0
;;
'--wds-start-network')
COMPREPLY=( $(compgen -W "[(APN),(PAP|CHAP|BOTH),(Username),(Password)]" -- $cur) )
return 0
;;
'--wds-stop-network')
COMPREPLY=( $(compgen -W "[Packet-data-handle]" -- $cur) )
return 0
;;
'--wds-get-profile-list')
COMPREPLY=( $(compgen -W "[3gpp|3gpp2]" -- $cur) )
return 0
;;
'--wds-get-default-settings')
COMPREPLY=( $(compgen -W "[3gpp|3gpp2]" -- $cur) )
return 0
;;
'--wds-bind-mux-data-port')
COMPREPLY=( $(compgen -W "[(MuxId),(Ep-Iface-Number)]" -- $cur) )
return 0
;;
'--wds-set-ip-family')
COMPREPLY=( $(compgen -W "[4|6]" -- $cur) )
return 0
;;
'--uim-read-transparent')
COMPREPLY=( $(compgen -W "[0xNNNN,0xNNNN,...]" -- $cur) )
return 0
;;
'--uim-get-file-attributes')
COMPREPLY=( $(compgen -W "[0xNNNN,0xNNNN,...]" -- $cur) )
return 0
;;
'--wda-set-data-format')
COMPREPLY=( $(compgen -W "[raw-ip|802-3]" -- $cur) )
return 0
;;
'-V'|'--version')
return 0
;;
'-h'|'--help'|'--help-all'|'--help-dms'|'--help-nas'|'--help-wds'|'--help-pbm'|'--help-uim'|'--help-wda')
return 0
;;
esac
$split && return 0
if [[ $cur == -* ]]; then
COMPREPLY=( $( compgen -W '$( _parse_help "$1" --help-all )' -- "$cur" ) )
[[ $COMPREPLY == *= ]] && compopt -o nospace
return 0
fi
} &&
complete -F _qmicli qmicli
# ex: ts=4 sw=4 et filetype=sh

413
pkgs/qmi-nmea/qmicli-atr.c Normal file
View File

@ -0,0 +1,413 @@
/* -*- 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 Daniele Palmas <dnlplm@gmail.com>
*/
#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_ATR
/* Context */
typedef struct {
QmiDevice *device;
QmiClientAtr *client;
GCancellable *cancellable;
guint timeout_id;
guint received_indication_id;
gboolean monitor;
} Context;
static Context *ctx;
/* Options */
static gchar *send_str;
static gchar *send_only_str;
static gboolean monitor_indications_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_ATR_SEND && defined HAVE_QMI_INDICATION_ATR_RECEIVED
{ "atr-send", 0, 0, G_OPTION_ARG_STRING, &send_str,
"Send an AT command and wait for the reply",
"[AT command]"
},
#endif
#if defined HAVE_QMI_MESSAGE_ATR_SEND
{ "atr-send-only", 0, 0, G_OPTION_ARG_STRING, &send_only_str,
"Send an AT command without waiting for the reply",
"[AT command]"
},
#endif
#if defined HAVE_QMI_MESSAGE_ATR_SEND && defined HAVE_QMI_INDICATION_ATR_RECEIVED
{ "atr-monitor", 0, 0, G_OPTION_ARG_NONE, &monitor_indications_flag,
"Watch for unsolicited indications",
NULL
},
#endif
{ "atr-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release an ATR client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_atr_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("atr",
"ATR options:",
"Show AT Relay Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_atr_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (!!send_str +
!!send_only_str +
monitor_indications_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many ATR actions requested\n");
exit (EXIT_FAILURE);
}
/* Actions that require receiving QMI indication messages must specify that
* indications are expected. */
if (!!send_str || monitor_indications_flag)
qmicli_expect_indications ();
checked = TRUE;
return !!n_actions;
}
static void
context_free (Context *context)
{
if (!context)
return;
if (context->timeout_id)
g_source_remove (context->timeout_id);
if (context->received_indication_id)
g_signal_handler_disconnect (context->client, context->received_indication_id);
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_ATR_SEND && defined HAVE_QMI_INDICATION_ATR_RECEIVED
/******************************************************************************/
/* Send */
static QmiMessageAtrSendInput *
send_input_create (const gchar *str)
{
QmiMessageAtrSendInput *input = NULL;
input = qmi_message_atr_send_input_new ();
qmi_message_atr_send_input_set_message (input, str, NULL);
return input;
}
static gboolean
send_timed_out (void)
{
ctx->timeout_id = 0;
g_printerr ("error: operation failed: timeout\n");
operation_shutdown (FALSE);
return G_SOURCE_REMOVE;
}
static gboolean
is_final_response (const gchar *reply)
{
/* The following regexes are taken from MM serial parser */
GRegexCompileFlags flags = G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW | G_REGEX_OPTIMIZE;
g_autoptr(GRegex) regex_ok = NULL;
g_autoptr(GRegex) regex_connect = NULL;
g_autoptr(GRegex) regex_cme_error = NULL;
g_autoptr(GRegex) regex_cms_error = NULL;
g_autoptr(GRegex) regex_unknown_error = NULL;
g_autoptr(GRegex) regex_connect_failed = NULL;
regex_ok = g_regex_new ("\\r\\nOK(\\r\\n)+", flags, 0, NULL);
regex_connect = g_regex_new ("\\r\\nCONNECT.*\\r\\n", flags, 0, NULL);
regex_cme_error = g_regex_new ("\\r\\n\\+CME ERROR*\\r\\n", flags, 0, NULL);
regex_cms_error = g_regex_new ("\\r\\n\\+CMS ERROR*\\r\\n", flags, 0, NULL);
regex_unknown_error = g_regex_new ("\\r\\n(ERROR)|(COMMAND NOT SUPPORT)\\r\\n", flags, 0, NULL);
regex_connect_failed = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n", flags, 0, NULL);
if (g_regex_match_full (regex_ok,
reply, strlen (reply),
0, 0, NULL, NULL) ||
g_regex_match_full (regex_unknown_error,
reply, strlen (reply),
0, 0, NULL, NULL) ||
g_regex_match_full (regex_cme_error,
reply, strlen (reply),
0, 0, NULL, NULL) ||
g_regex_match_full (regex_cms_error,
reply, strlen (reply),
0, 0, NULL, NULL) ||
g_regex_match_full (regex_connect,
reply, strlen (reply),
0, 0, NULL, NULL) ||
g_regex_match_full (regex_connect_failed,
reply, strlen (reply),
0, 0, NULL, NULL))
return TRUE;
return FALSE;
}
static void
indication_received (QmiClientAtr *client,
QmiIndicationAtrReceivedOutput *output)
{
const gchar *received;
g_autoptr(GError) error = NULL;
if (!qmi_indication_atr_received_output_get_message (output, &received, &error)) {
g_printerr ("error: couldn't get indication message: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (ctx->monitor) {
/* When monitoring we don't want to print final responses
* e.g. the initial ATE0 reply or the ones for the commands sent with
* atr-send-only using the same cid
* The comparison with "ATE0" is for avoid printing the echo of the
* mandatory initial command */
if (!is_final_response (received) && g_strcmp0 (received, "ATE0\r"))
g_print ("%s", received);
} else {
/* No need to print an additional '\n', since the indication already has '\r\n' */
g_print ("%s", received);
/* The reply can arrive with multiple indications, so we need to check if the
* indication has the final response */
if (is_final_response (received)) {
g_print ("Successfully received final response\n");
operation_shutdown (TRUE);
}
}
}
static void
monitoring_cancelled (GCancellable *cancellable)
{
operation_shutdown (TRUE);
}
static void
send_ready (QmiClientAtr *client,
GAsyncResult *res)
{
g_autoptr(QmiMessageAtrSendOutput) output = NULL;
g_autoptr(GError) error = NULL;
output = qmi_client_atr_send_finish (client, res, &error);
if (!output) {
g_printerr ("error: operation failed: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_atr_send_output_get_result (output, &error)) {
g_printerr ("error: couldn't send AT command: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (ctx->monitor) {
/* User can use Ctrl+C to cancel the monitoring at any time */
g_cancellable_connect (ctx->cancellable,
G_CALLBACK (monitoring_cancelled),
NULL,
NULL);
g_print ("Monitoring unsolicited indications: press Ctrl+C to stop\n");
} else
/* Wait for the response asynchronously: 120 seconds should be enough also
* for long-lasting commands (e.g. AT+COPS=?) */
ctx->timeout_id = g_timeout_add_seconds (120,
(GSourceFunc) send_timed_out,
NULL);
ctx->received_indication_id = g_signal_connect (ctx->client,
"received",
G_CALLBACK (indication_received),
NULL);
}
#endif /* HAVE_QMI_MESSAGE_ATR_SEND
* HAVE_QMI_INDICATION_ATR_RECEIVED */
#if defined HAVE_QMI_MESSAGE_ATR_SEND
/******************************************************************************/
/* Send and don't wait for the reply */
static void
send_only_ready (QmiClientAtr *client,
GAsyncResult *res)
{
g_autoptr(QmiMessageAtrSendOutput) output = NULL;
g_autoptr(GError) error = NULL;
output = qmi_client_atr_send_finish (client, res, &error);
if (!output) {
g_printerr ("error: operation failed: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_atr_send_output_get_result (output, &error)) {
g_printerr ("error: couldn't send AT command: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
g_print ("Successfully sent AT command\n");
operation_shutdown (TRUE);
}
static void
generic_send (const gchar *cmd,
GAsyncReadyCallback cb)
{
g_autofree gchar *at_cmd = NULL;
g_autoptr(QmiMessageAtrSendInput) input = NULL;
g_debug ("Asynchronously sending AT command...");
at_cmd = g_strconcat (cmd, "\r", NULL);
input = send_input_create (at_cmd);
if (!input) {
operation_shutdown (FALSE);
return;
}
qmi_client_atr_send (ctx->client,
input,
10,
ctx->cancellable,
cb,
NULL);
}
#endif /* HAVE_QMI_MESSAGE_ATR_SEND */
/******************************************************************************/
/* Common */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_atr_run (QmiDevice *device,
QmiClientAtr *client,
GCancellable *cancellable)
{
/* Initialize context */
ctx = g_slice_new0 (Context);
ctx->device = g_object_ref (device);
ctx->client = g_object_ref (client);
ctx->cancellable = g_object_ref (cancellable);
#if defined HAVE_QMI_MESSAGE_ATR_SEND && defined HAVE_QMI_INDICATION_ATR_RECEIVED
if (send_str) {
generic_send (send_str, (GAsyncReadyCallback)send_ready);
return;
}
if (monitor_indications_flag) {
/* To really open the AT communication and receive unsolicited
* indications it is mandatory to send an initial AT command.
* The command ATE0 has been chosen so that, if needed, commands
* can be sent by a different qmicli instance reusing the monitoring
* cid with --atr-send-only. This avoids also polluting the monitoring
* operation with the comands echo */
ctx->monitor = TRUE;
generic_send ("ATE0", (GAsyncReadyCallback)send_ready);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_ATR_SEND
if (send_only_str) {
generic_send (send_only_str, (GAsyncReadyCallback)send_only_ready);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_ATR */

5465
pkgs/qmi-nmea/qmicli-dms.c Normal file

File diff suppressed because it is too large Load Diff

544
pkgs/qmi-nmea/qmicli-dpm.c Normal file
View File

@ -0,0 +1,544 @@
/* -*- 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) 2021 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
#if defined HAVE_QMI_SERVICE_DPM
#define QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED -1
/* Context */
typedef struct {
QmiDevice *device;
QmiClientDpm *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gchar *open_port_str;
static gboolean close_port_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_DPM_OPEN_PORT
{ "dpm-open-port", 0, 0, G_OPTION_ARG_STRING, &open_port_str,
"Open port (allowed-keys: ctrl-ep-type, ctrl-ep-iface-number, ctrl-port-name, hw-data-ep-type, hw-data-ep-iface-number, hw-data-rx-id, hw-data-tx-id, sw-data-ep-type, sw-data-ep-iface-number, sw-data-port-name)",
"[\"key=value,...\"]"
},
#endif
#if defined HAVE_QMI_MESSAGE_DPM_CLOSE_PORT
{ "dpm-close-port", 0, 0, G_OPTION_ARG_NONE, &close_port_flag,
"Close port",
NULL
},
#endif
{ "dpm-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a DPM client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_dpm_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("dpm",
"DPM options:",
"Show Data Port Mapper Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_dpm_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (!!open_port_str +
close_port_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many DPM 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_DPM_OPEN_PORT
static void
open_port_ready (QmiClientDpm *client,
GAsyncResult *res)
{
g_autoptr(QmiMessageDpmOpenPortOutput) output = NULL;
g_autoptr(GError) error = NULL;
output = qmi_client_dpm_open_port_finish (client, res, &error);
if (!output) {
g_printerr ("error: operation failed: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_dpm_open_port_output_get_result (output, &error)) {
g_printerr ("error: couldn't open port: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
g_print ("Successfully opened the port\n");
operation_shutdown (TRUE);
}
typedef struct {
/* control port item building */
GArray *ctrl_ports;
QmiDataEndpointType ctrl_ep_type;
gint ctrl_ep_iface_number;
gchar *ctrl_port_name;
/* hw data port item building */
GArray *hw_data_ports;
QmiDataEndpointType hw_data_ep_type;
gint hw_data_ep_iface_number;
guint hw_data_rx_id;
guint hw_data_tx_id;
/* sw data port item building */
GArray *sw_data_ports;
QmiDataEndpointType sw_data_ep_type;
gint sw_data_ep_iface_number;
gchar *sw_data_port_name;
} OpenPortProperties;
static void
reset_ctrl_port_item (OpenPortProperties *props)
{
g_free (props->ctrl_port_name);
props->ctrl_port_name = NULL;
props->ctrl_ep_type = QMI_DATA_ENDPOINT_TYPE_UNKNOWN;
props->ctrl_ep_iface_number = QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED;
}
static void
ctrl_port_details_clear (QmiMessageDpmOpenPortInputControlPortsElement *details)
{
g_free (details->port_name);
}
static void
build_ctrl_port_item (OpenPortProperties *props)
{
if ((props->ctrl_ep_type != QMI_DATA_ENDPOINT_TYPE_UNKNOWN) &&
(props->ctrl_ep_iface_number != QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) &&
(props->ctrl_port_name != NULL)) {
QmiMessageDpmOpenPortInputControlPortsElement details;
details.port_name = g_strdup (props->ctrl_port_name);
details.endpoint_type = props->ctrl_ep_type;
details.interface_number = props->ctrl_ep_iface_number;
if (!props->ctrl_ports) {
props->ctrl_ports = g_array_new (FALSE, FALSE, sizeof (QmiMessageDpmOpenPortInputControlPortsElement));
g_array_set_clear_func (props->ctrl_ports, (GDestroyNotify)ctrl_port_details_clear);
}
g_array_append_val (props->ctrl_ports, details);
reset_ctrl_port_item (props);
}
}
static gboolean
check_unfinished_ctrl_port_item (OpenPortProperties *props,
GError **error)
{
if ((props->ctrl_ep_type != QMI_DATA_ENDPOINT_TYPE_UNKNOWN) ||
(props->ctrl_ep_iface_number != QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) ||
(props->ctrl_port_name != NULL)) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"error: unfinished ctrl port item");
return FALSE;
}
return TRUE;
}
static void
reset_hw_data_port_item (OpenPortProperties *props)
{
props->hw_data_rx_id = 0;
props->hw_data_tx_id = 0;
props->hw_data_ep_type = QMI_DATA_ENDPOINT_TYPE_UNKNOWN;
props->hw_data_ep_iface_number = QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED;
}
static void
build_hw_data_port_item (OpenPortProperties *props)
{
if ((props->hw_data_ep_type != QMI_DATA_ENDPOINT_TYPE_UNKNOWN) &&
(props->hw_data_ep_iface_number != QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) &&
(props->hw_data_rx_id != 0) &&
(props->hw_data_tx_id != 0)) {
QmiMessageDpmOpenPortInputHardwareDataPortsElement details;
details.rx_endpoint_number = props->hw_data_rx_id;
details.tx_endpoint_number = props->hw_data_tx_id;
details.endpoint_type = props->hw_data_ep_type;
details.interface_number = props->hw_data_ep_iface_number;
if (!props->hw_data_ports)
props->hw_data_ports = g_array_new (FALSE, FALSE, sizeof (QmiMessageDpmOpenPortInputHardwareDataPortsElement));
g_array_append_val (props->hw_data_ports, details);
reset_hw_data_port_item (props);
}
}
static gboolean
check_unfinished_hw_data_port_item (OpenPortProperties *props,
GError **error)
{
if ((props->hw_data_ep_type != QMI_DATA_ENDPOINT_TYPE_UNKNOWN) ||
(props->hw_data_ep_iface_number != QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) ||
(props->hw_data_rx_id != 0) ||
(props->hw_data_tx_id != 0)) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"error: unfinished hw data port item");
return FALSE;
}
return TRUE;
}
static void
reset_sw_data_port_item (OpenPortProperties *props)
{
g_free (props->sw_data_port_name);
props->sw_data_port_name = NULL;
props->sw_data_ep_type = QMI_DATA_ENDPOINT_TYPE_UNKNOWN;
props->sw_data_ep_iface_number = QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED;
}
static void
sw_data_port_details_clear (QmiMessageDpmOpenPortInputSoftwareDataPortsElement *details)
{
g_free (details->port_name);
}
static void
build_sw_data_port_item (OpenPortProperties *props)
{
if ((props->sw_data_ep_type != QMI_DATA_ENDPOINT_TYPE_UNKNOWN) &&
(props->sw_data_ep_iface_number != QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) &&
(props->sw_data_port_name != NULL)) {
QmiMessageDpmOpenPortInputSoftwareDataPortsElement details;
details.port_name = g_strdup (props->sw_data_port_name);
details.endpoint_type = props->sw_data_ep_type;
details.interface_number = props->sw_data_ep_iface_number;
if (!props->sw_data_ports) {
props->sw_data_ports = g_array_new (FALSE, FALSE, sizeof (QmiMessageDpmOpenPortInputSoftwareDataPortsElement));
g_array_set_clear_func (props->sw_data_ports, (GDestroyNotify)sw_data_port_details_clear);
}
g_array_append_val (props->sw_data_ports, details);
reset_sw_data_port_item (props);
}
}
static gboolean
check_unfinished_sw_data_port_item (OpenPortProperties *props,
GError **error)
{
if ((props->sw_data_ep_type != QMI_DATA_ENDPOINT_TYPE_UNKNOWN) ||
(props->sw_data_ep_iface_number != QMI_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) ||
(props->sw_data_port_name != NULL)) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"error: unfinished sw data port item");
return FALSE;
}
return TRUE;
}
static gboolean
open_port_properties_handle (const gchar *key,
const gchar *value,
GError **error,
gpointer user_data)
{
OpenPortProperties *props = (OpenPortProperties *)user_data;
if (!value || !value[0]) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"key '%s' requires a value", key);
return FALSE;
}
/* control port item */
if (g_ascii_strcasecmp (key, "ctrl-ep-type") == 0) {
if (!qmicli_read_data_endpoint_type_from_string (value, &(props->ctrl_ep_type))) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"Unrecognized Endpoint Type '%s'", value);
return FALSE;
}
build_ctrl_port_item (props);
return TRUE;
}
if (g_ascii_strcasecmp (key, "ctrl-ep-iface-number") == 0) {
props->ctrl_ep_iface_number = atoi (value);
build_ctrl_port_item (props);
return TRUE;
}
if (g_ascii_strcasecmp (key, "ctrl-port-name") == 0) {
g_clear_pointer (&props->ctrl_port_name, g_free);
props->ctrl_port_name = g_strdup (value);
build_ctrl_port_item (props);
return TRUE;
}
/* hw data port item */
if (g_ascii_strcasecmp (key, "hw-data-ep-type") == 0) {
if (!qmicli_read_data_endpoint_type_from_string (value, &(props->hw_data_ep_type))) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"Unrecognized Endpoint Type '%s'", value);
return FALSE;
}
build_hw_data_port_item (props);
return TRUE;
}
if (g_ascii_strcasecmp (key, "hw-data-ep-iface-number") == 0) {
props->hw_data_ep_iface_number = atoi (value);
build_hw_data_port_item (props);
return TRUE;
}
if (g_ascii_strcasecmp (key, "hw-data-rx-id") == 0) {
props->hw_data_rx_id = atoi (value);
build_hw_data_port_item (props);
return TRUE;
}
if (g_ascii_strcasecmp (key, "hw-data-tx-id") == 0) {
props->hw_data_tx_id = atoi (value);
build_hw_data_port_item (props);
return TRUE;
}
/* sw data port item */
if (g_ascii_strcasecmp (key, "sw-data-ep-type") == 0) {
if (!qmicli_read_data_endpoint_type_from_string (value, &(props->sw_data_ep_type))) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"Unrecognized Endpoint Type '%s'", value);
return FALSE;
}
build_sw_data_port_item (props);
return TRUE;
}
if (g_ascii_strcasecmp (key, "sw-data-ep-iface-number") == 0) {
props->sw_data_ep_iface_number = atoi (value);
build_sw_data_port_item (props);
return TRUE;
}
if (g_ascii_strcasecmp (key, "sw-data-port-name") == 0) {
g_clear_pointer (&props->sw_data_port_name, g_free);
props->sw_data_port_name = g_strdup (value);
build_sw_data_port_item (props);
return TRUE;
}
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"Unrecognized option '%s'", key);
return FALSE;
}
static gboolean
open_port_input_create (const gchar *str,
QmiMessageDpmOpenPortInput **out_input,
GError **error)
{
QmiMessageDpmOpenPortInput *input;
OpenPortProperties props = { 0 };
reset_ctrl_port_item (&props);
reset_hw_data_port_item (&props);
reset_sw_data_port_item (&props);
if (!qmicli_parse_key_value_string (str, error, open_port_properties_handle, &props))
return FALSE;
if (!check_unfinished_ctrl_port_item (&props, error) ||
!check_unfinished_hw_data_port_item (&props, error) ||
!check_unfinished_sw_data_port_item (&props, error))
return FALSE;
input = qmi_message_dpm_open_port_input_new ();
if (props.ctrl_ports) {
qmi_message_dpm_open_port_input_set_control_ports (input, props.ctrl_ports, NULL);
g_clear_pointer (&props.ctrl_ports, g_array_unref);
}
if (props.hw_data_ports) {
qmi_message_dpm_open_port_input_set_hardware_data_ports (input, props.hw_data_ports, NULL);
g_clear_pointer (&props.hw_data_ports, g_array_unref);
}
if (props.sw_data_ports) {
qmi_message_dpm_open_port_input_set_software_data_ports (input, props.sw_data_ports, NULL);
g_clear_pointer (&props.sw_data_ports, g_array_unref);
}
*out_input = input;
return TRUE;
}
#endif /* HAVE_QMI_MESSAGE_DPM_OPEN_PORT */
#if defined HAVE_QMI_MESSAGE_DPM_CLOSE_PORT
static void
close_port_ready (QmiClientDpm *client,
GAsyncResult *res)
{
g_autoptr(QmiMessageDpmClosePortOutput) output = NULL;
g_autoptr(GError) error = NULL;
output = qmi_client_dpm_close_port_finish (client, res, &error);
if (!output) {
g_printerr ("error: operation failed: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_dpm_close_port_output_get_result (output, &error)) {
g_printerr ("error: couldn't close port: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
g_print ("Successfully closeed the port\n");
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_DPM_CLOSE_PORT */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_dpm_run (QmiDevice *device,
QmiClientDpm *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_DPM_OPEN_PORT
if (open_port_str) {
g_autoptr(QmiMessageDpmOpenPortInput) input = NULL;
g_autoptr(GError) error = NULL;
if (!open_port_input_create (open_port_str, &input, &error)) {
g_printerr ("error: couldn't process input arguments: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
qmi_client_dpm_open_port (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)open_port_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_DPM_CLOSE_PORT
if (close_port_flag) {
qmi_client_dpm_close_port (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)close_port_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_DPM */

415
pkgs/qmi-nmea/qmicli-dsd.c Normal file
View File

@ -0,0 +1,415 @@
/* -*- 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) 2019 Aleksander Morgado <aleksander@aleksander.es>
* Copyright (c) 2022 Qualcomm Innovation Center, Inc.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
#if defined HAVE_QMI_SERVICE_DSD
#undef VALIDATE_MASK_NONE
#define VALIDATE_MASK_NONE(str) (str ? str : "none")
/* Context */
typedef struct {
QmiDevice *device;
QmiClientDsd *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gchar *get_apn_info_str;
static gchar *set_apn_type_str;
static gboolean get_system_status_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_DSD_GET_APN_INFO
{ "dsd-get-apn-info", 0, 0, G_OPTION_ARG_STRING, &get_apn_info_str,
"Gets the settings associated to a given APN type",
"[(type)]"
},
#endif
#if defined HAVE_QMI_MESSAGE_DSD_SET_APN_TYPE
{ "dsd-set-apn-type", 0, 0, G_OPTION_ARG_STRING, &set_apn_type_str,
"Sets the types associated to a given APN name",
"[(name), (type1|type2|type3...)]"
},
#endif
#if defined HAVE_QMI_MESSAGE_DSD_GET_SYSTEM_STATUS
{ "dsd-get-system-status", 0, 0, G_OPTION_ARG_NONE, &get_system_status_flag,
"Gets system status",
NULL
},
#endif
{ "dsd-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a DSD client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_dsd_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("dsd",
"DSD options:",
"Show Data System Determination options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_dsd_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (!!get_apn_info_str +
!!set_apn_type_str +
get_system_status_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many DSD 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_DSD_GET_APN_INFO
static void
get_apn_info_ready (QmiClientDsd *client,
GAsyncResult *res)
{
QmiMessageDsdGetApnInfoOutput *output;
GError *error = NULL;
const gchar *apn_name = NULL;
output = qmi_client_dsd_get_apn_info_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_dsd_get_apn_info_output_get_result (output, &error)) {
g_printerr ("error: couldn't get APN info: %s\n", error->message);
g_error_free (error);
qmi_message_dsd_get_apn_info_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("APN info found:\n");
if (qmi_message_dsd_get_apn_info_output_get_apn_name (output, &apn_name, NULL))
g_print ("APN name: %s\n", apn_name);
else
g_print ("APN name: n/a\n");
qmi_message_dsd_get_apn_info_output_unref (output);
operation_shutdown (TRUE);
}
static QmiMessageDsdGetApnInfoInput *
get_apn_info_input_create (const gchar *str)
{
QmiMessageDsdGetApnInfoInput *input = NULL;
GError *error = NULL;
QmiDsdApnType apn_type;
if (!qmicli_read_dsd_apn_type_from_string (str, &apn_type)) {
g_printerr ("error: couldn't parse input string as APN type: '%s'\n", str);
return NULL;
}
input = qmi_message_dsd_get_apn_info_input_new ();
if (!qmi_message_dsd_get_apn_info_input_set_apn_type (input, apn_type, &error)) {
g_printerr ("error: couldn't create input data bundle: '%s'\n",
error->message);
g_error_free (error);
qmi_message_dsd_get_apn_info_input_unref (input);
input = NULL;
}
return input;
}
#endif /* HAVE_QMI_MESSAGE_DSD_GET_APN_INFO */
#if defined HAVE_QMI_MESSAGE_DSD_SET_APN_TYPE
static void
set_apn_type_ready (QmiClientDsd *client,
GAsyncResult *res)
{
QmiMessageDsdSetApnTypeOutput *output;
GError *error = NULL;
output = qmi_client_dsd_set_apn_type_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_dsd_set_apn_type_output_get_result (output, &error)) {
g_printerr ("error: couldn't set APN type: %s\n", error->message);
g_error_free (error);
qmi_message_dsd_set_apn_type_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("APN type set\n");
qmi_message_dsd_set_apn_type_output_unref (output);
operation_shutdown (TRUE);
}
static QmiMessageDsdSetApnTypeInput *
set_apn_type_input_create (const gchar *str)
{
QmiMessageDsdSetApnTypeInput *input = NULL;
GError *error = NULL;
QmiDsdApnTypePreference apn_type_preference;
gchar **split;
split = g_strsplit_set (str, ",", 0);
if (g_strv_length (split) != 2) {
g_printerr ("input string requires 2 values, %u given: '%s'\n", g_strv_length (split), str);
g_strfreev (split);
return NULL;
}
g_strstrip (split[0]);
g_strstrip (split[1]);
if (!qmicli_read_dsd_apn_type_preference_from_string (split[1], &apn_type_preference)) {
g_printerr ("error: couldn't parse input string as APN type preference mask: '%s'\n", split[1]);
g_strfreev (split);
return NULL;
}
input = qmi_message_dsd_set_apn_type_input_new ();
if (!qmi_message_dsd_set_apn_type_input_set_apn_type (input, split[0], apn_type_preference, &error)) {
g_printerr ("error: couldn't create input data bundle: '%s'\n",
error->message);
g_error_free (error);
qmi_message_dsd_set_apn_type_input_unref (input);
input = NULL;
}
g_strfreev (split);
return input;
}
#endif /* HAVE_QMI_MESSAGE_DSD_SET_APN_TYPE */
#if defined HAVE_QMI_MESSAGE_DSD_GET_SYSTEM_STATUS
static void
get_system_status_ready (QmiClientDsd *client,
GAsyncResult *res)
{
QmiMessageDsdGetSystemStatusOutput *output;
GError *error = NULL;
GArray *available_systems = NULL;
guint i;
output = qmi_client_dsd_get_system_status_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_dsd_get_system_status_output_get_result (output, &error)) {
g_printerr ("error: couldn't get system status: %s\n", error->message);
g_error_free (error);
qmi_message_dsd_get_system_status_output_unref (output);
operation_shutdown (FALSE);
return;
}
qmi_message_dsd_get_system_status_output_get_available_systems (output, &available_systems, NULL);
if (!available_systems || !available_systems->len) {
g_print ("No available data system\n");
} else {
g_print ("Available data systems retrieved:\n");
for (i = 0; i < available_systems->len; i++) {
QmiMessageDsdGetSystemStatusOutputAvailableSystemsSystem *system;
g_autofree gchar *so_mask_str = NULL;
system = &g_array_index (available_systems, QmiMessageDsdGetSystemStatusOutputAvailableSystemsSystem, i);
so_mask_str = qmi_dsd_so_mask_build_string_from_mask ((QmiDsdSoMask)system->so_mask);
g_print ("System [%u]%s:\n"
"\tNetwork type: '%s'\n"
"\tRAT: '%s'\n"
"\tService option: '%s'\n",
i,
i > 0 ? "" : " (current preferred)",
qmi_dsd_data_system_network_type_get_string (system->technology),
qmi_dsd_radio_access_technology_get_string (system->rat),
VALIDATE_MASK_NONE (so_mask_str));
}
}
qmi_message_dsd_get_system_status_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_DSD_GET_SYSTEM_STATUS */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_dsd_run (QmiDevice *device,
QmiClientDsd *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_DSD_GET_APN_INFO
if (get_apn_info_str) {
QmiMessageDsdGetApnInfoInput *input;
g_debug ("Asynchronously getting APN info...");
input = get_apn_info_input_create (get_apn_info_str);
if (!input) {
operation_shutdown (FALSE);
return;
}
qmi_client_dsd_get_apn_info (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_apn_info_ready,
NULL);
qmi_message_dsd_get_apn_info_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_DSD_SET_APN_TYPE
if (set_apn_type_str) {
QmiMessageDsdSetApnTypeInput *input;
g_debug ("Asynchronously setting APN type...");
input = set_apn_type_input_create (set_apn_type_str);
if (!input) {
operation_shutdown (FALSE);
return;
}
qmi_client_dsd_set_apn_type (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)set_apn_type_ready,
NULL);
qmi_message_dsd_set_apn_type_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_DSD_GET_SYSTEM_STATUS
if (get_system_status_flag) {
g_debug ("Asynchronously getting system status...");
qmi_client_dsd_get_system_status (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_system_status_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_DSD */

240
pkgs/qmi-nmea/qmicli-fox.c Normal file
View File

@ -0,0 +1,240 @@
/* -*- 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) 2022 Freedom Liu <lk@linuxdev.top>
*/
#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_FOX
#undef VALIDATE_UNKNOWN
#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
/* Context */
typedef struct {
QmiDevice *device;
QmiClientFox *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gchar *get_firmware_version_str;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_FOX_GET_FIRMWARE_VERSION
{ "fox-get-firmware-version", 0, 0, G_OPTION_ARG_STRING, &get_firmware_version_str,
"Get firmware version",
"[firmware-mcfg-apps|firmware-mcfg|apps]"
},
#endif
{ "fox-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a FOX client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_fox_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("fox",
"FOX options:",
"Show Foxconn Modem Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_fox_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (!!get_firmware_version_str +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many FOX 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_FOX_GET_FIRMWARE_VERSION
static QmiMessageFoxGetFirmwareVersionInput *
get_firmware_version_input_create (const gchar *str)
{
QmiMessageFoxGetFirmwareVersionInput *input = NULL;
QmiFoxFirmwareVersionType type;
GError *error = NULL;
if (!qmicli_read_fox_firmware_version_type_from_string (str, &type)) {
g_printerr ("error: couldn't parse input firmware version type : '%s'\n", str);
return NULL;
}
input = qmi_message_fox_get_firmware_version_input_new ();
if (!qmi_message_fox_get_firmware_version_input_set_version_type (input, type, &error)) {
g_printerr ("error: couldn't create input data bundle: '%s'\n",
error->message);
g_error_free (error);
qmi_message_fox_get_firmware_version_input_unref (input);
return NULL;
}
return input;
}
static void
get_firmware_version_ready (QmiClientFox *client,
GAsyncResult *res)
{
const gchar *str = NULL;
QmiMessageFoxGetFirmwareVersionOutput *output;
GError *error = NULL;
output = qmi_client_fox_get_firmware_version_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_fox_get_firmware_version_output_get_result (output, &error)) {
g_printerr ("error: couldn't get firmware version: %s\n", error->message);
g_error_free (error);
qmi_message_fox_get_firmware_version_output_unref (output);
operation_shutdown (FALSE);
return;
}
qmi_message_fox_get_firmware_version_output_get_version (output, &str, NULL);
g_print ("[%s] Firmware version retrieved:\n"
"\tVersion: '%s'\n",
qmi_device_get_path_display (ctx->device),
VALIDATE_UNKNOWN (str));
qmi_message_fox_get_firmware_version_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_FOX_GET_FIRMWARE_VERSION */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_fox_run (QmiDevice *device,
QmiClientFox *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_FOX_GET_FIRMWARE_VERSION
if (get_firmware_version_str) {
QmiMessageFoxGetFirmwareVersionInput *input;
g_debug ("Asynchronously getting firmware version...");
input = get_firmware_version_input_create (get_firmware_version_str);
if (!input) {
operation_shutdown (FALSE);
return;
}
qmi_client_fox_get_firmware_version (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_firmware_version_ready,
NULL);
qmi_message_fox_get_firmware_version_input_unref (input);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_FOX */

499
pkgs/qmi-nmea/qmicli-gas.c Normal file
View File

@ -0,0 +1,499 @@
/* -*- 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) 2019 Andreas Kling <awesomekling@gmail.com>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include <qmi-common.h>
#include "qmicli.h"
#if defined HAVE_QMI_SERVICE_GAS
/* Context */
typedef struct {
QmiDevice *device;
QmiClientGas *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gboolean get_firmware_list_flag;
static gboolean get_active_firmware_flag;
static gint set_active_firmware_int = -1;
static gint set_usb_composition_int = -1;
static gboolean get_usb_composition_flag;
static gboolean get_ethernet_mac_address_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_GAS_DMS_SET_USB_COMPOSITION
{ "gas-dms-set-usb-composition", 0, 0, G_OPTION_ARG_INT, &set_usb_composition_int,
"Sets the USB composition",
"[pid]"
},
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_USB_COMPOSITION
{ "gas-dms-get-usb-composition", 0, 0, G_OPTION_ARG_NONE, &get_usb_composition_flag,
"Gets the current USB composition",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_FIRMWARE_LIST
{ "gas-dms-get-firmware-list", 0, 0, G_OPTION_ARG_NONE, &get_firmware_list_flag,
"Gets the list of stored firmware",
NULL
},
{ "gas-dms-get-active-firmware", 0, 0, G_OPTION_ARG_NONE, &get_active_firmware_flag,
"Gets the currently active firmware",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_SET_ACTIVE_FIRMWARE
{ "gas-dms-set-active-firmware", 0, 0, G_OPTION_ARG_INT, &set_active_firmware_int,
"Sets the active firmware index",
"[index]"
},
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_ETHERNET_PDU_MAC_ADDRESS
{ "gas-dms-get-ethernet-mac-address", 0, 0, G_OPTION_ARG_NONE, &get_ethernet_mac_address_flag,
"Gets the Ethernet PDU MAC address available in the modem",
NULL
},
#endif
{ "gas-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a GAS client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_gas_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("gas",
"GAS options:",
"Show General Application Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_gas_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = ((set_usb_composition_int >= 0) +
get_usb_composition_flag +
get_firmware_list_flag +
get_active_firmware_flag +
(set_active_firmware_int >= 0) +
get_ethernet_mac_address_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many GAS 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_GAS_DMS_SET_USB_COMPOSITION
static void
set_usb_composition_ready (QmiClientGas *client,
GAsyncResult *res)
{
QmiMessageGasDmsSetUsbCompositionOutput *output;
GError *error = NULL;
output = qmi_client_gas_dms_set_usb_composition_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_gas_dms_set_usb_composition_output_get_result (output, &error)) {
g_printerr ("error: unable to switch composition: %s\n", error->message);
g_error_free (error);
qmi_message_gas_dms_set_usb_composition_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully switched composition.\n",
qmi_device_get_path_display (ctx->device));
qmi_message_gas_dms_set_usb_composition_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_GAS_DMS_SET_USB_COMPOSITION */
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_USB_COMPOSITION
static void
get_usb_composition_ready (QmiClientGas *client,
GAsyncResult *res)
{
QmiMessageGasDmsGetUsbCompositionOutput *output;
GError *error = NULL;
guint32 composition;
output = qmi_client_gas_dms_get_usb_composition_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_gas_dms_get_usb_composition_output_get_result (output, &error)) {
g_printerr ("error: unable to get current composition: %s\n", error->message);
g_error_free (error);
qmi_message_gas_dms_get_usb_composition_output_unref (output);
operation_shutdown (FALSE);
return;
}
qmi_message_gas_dms_get_usb_composition_output_get_usb_composition (output, &composition, NULL);
g_print ("[%s] Current composition is 0x%x\n",
qmi_device_get_path_display (ctx->device),
composition);
qmi_message_gas_dms_get_usb_composition_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_GAS_DMS_GET_USB_COMPOSITION */
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_FIRMWARE_LIST
static void
print_firmware_listing (guint8 idx,
const gchar *name,
const gchar *version,
const gchar *pri_revision)
{
g_print ("Firmware #%u:\n"
"\tIndex: %u\n"
"\tName: %s\n"
"\tVersion: %s\n"
"\tPRI revision: %s\n",
idx,
idx,
name,
version,
pri_revision);
}
static void
get_firmware_list_ready (QmiClientGas *client,
GAsyncResult *res)
{
QmiMessageGasDmsGetFirmwareListOutput *output;
GError *error = NULL;
guint8 idx;
const gchar *name;
const gchar *version;
const gchar *pri_revision;
output = qmi_client_gas_dms_get_firmware_list_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_gas_dms_get_firmware_list_output_get_result (output, &error)) {
g_printerr ("error: couldn't get stored firmware list: %s\n", error->message);
g_error_free (error);
qmi_message_gas_dms_get_firmware_list_output_unref (output);
operation_shutdown (FALSE);
return;
}
if (qmi_message_gas_dms_get_firmware_list_output_get_stored_firmware_1 (output, &idx, &name, &version, &pri_revision, NULL))
print_firmware_listing (idx, name, version, pri_revision);
if (qmi_message_gas_dms_get_firmware_list_output_get_stored_firmware_2 (output, &idx, &name, &version, &pri_revision, NULL))
print_firmware_listing (idx, name, version, pri_revision);
if (qmi_message_gas_dms_get_firmware_list_output_get_stored_firmware_3 (output, &idx, &name, &version, &pri_revision, NULL))
print_firmware_listing (idx, name, version, pri_revision);
if (qmi_message_gas_dms_get_firmware_list_output_get_stored_firmware_4 (output, &idx, &name, &version, &pri_revision, NULL))
print_firmware_listing (idx, name, version, pri_revision);
qmi_message_gas_dms_get_firmware_list_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_GAS_DMS_GET_FIRMWARE_LIST */
#if defined HAVE_QMI_MESSAGE_GAS_DMS_SET_ACTIVE_FIRMWARE
static void
set_active_firmware_ready (QmiClientGas *client,
GAsyncResult *res)
{
QmiMessageGasDmsSetActiveFirmwareOutput *output;
GError *error = NULL;
output = qmi_client_gas_dms_set_active_firmware_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_gas_dms_set_active_firmware_output_get_result (output, &error)) {
g_printerr ("error: couldn't set active firmware list: %s\n", error->message);
g_error_free (error);
qmi_message_gas_dms_set_active_firmware_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("Successfully set the active firmware.\n");
qmi_message_gas_dms_set_active_firmware_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_GAS_DMS_SET_ACTIVE_FIRMWARE */
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_ETHERNET_PDU_MAC_ADDRESS
static void
print_mac_address (GArray *address)
{
g_autofree gchar *str = NULL;
str = qmi_common_str_hex (address->data, address->len, ':');
g_print ("%s\n", str);
}
static void
get_ethernet_pdu_mac_address_ready (QmiClientGas *client,
GAsyncResult *res)
{
g_autoptr(QmiMessageGasDmsGetEthernetPduMacAddressOutput) output;
g_autoptr(GError) error = NULL;
GArray *address;
output = qmi_client_gas_dms_get_ethernet_pdu_mac_address_finish (client, res, &error);
if (!output) {
g_printerr ("error: operation failed: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_gas_dms_get_ethernet_pdu_mac_address_output_get_result (output, &error)) {
g_printerr ("error: couldn't get Ethernet PDU MAC address: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (qmi_message_gas_dms_get_ethernet_pdu_mac_address_output_get_mac_address_0 (output, &address, &error)) {
g_print ("Ethernet MAC address 0: ");
print_mac_address (address);
} else {
g_printerr ("error: couldn't get Ethernet PDU MAC address 0: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (qmi_message_gas_dms_get_ethernet_pdu_mac_address_output_get_mac_address_1 (output, &address, NULL)) {
g_print ("Ethernet MAC address 1: ");
print_mac_address (address);
}
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_GAS_DMS_GET_ETHERNET_PDU_MAC_ADDRESS */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_gas_run (QmiDevice *device,
QmiClientGas *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_GAS_DMS_SET_USB_COMPOSITION
if (set_usb_composition_int >= 0) {
QmiMessageGasDmsSetUsbCompositionInput *input;
input = qmi_message_gas_dms_set_usb_composition_input_new ();
qmi_message_gas_dms_set_usb_composition_input_set_usb_composition (input, set_usb_composition_int, NULL);
qmi_message_gas_dms_set_usb_composition_input_set_endpoint_type (input, QMI_GAS_USB_COMPOSITION_ENDPOINT_TYPE_HSUSB, NULL);
qmi_message_gas_dms_set_usb_composition_input_set_composition_persistence (input, TRUE, NULL);
qmi_message_gas_dms_set_usb_composition_input_set_immediate_setting (input, FALSE, NULL);
qmi_message_gas_dms_set_usb_composition_input_set_reboot_after_setting (input, TRUE, NULL);
g_debug ("Asynchronously switching the USB composition...");
qmi_client_gas_dms_set_usb_composition (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)set_usb_composition_ready,
NULL);
qmi_message_gas_dms_set_usb_composition_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_USB_COMPOSITION
if (get_usb_composition_flag) {
g_debug ("Asynchronously getting the USB composition...");
qmi_client_gas_dms_get_usb_composition (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_usb_composition_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_FIRMWARE_LIST
if (get_firmware_list_flag || get_active_firmware_flag) {
QmiMessageGasDmsGetFirmwareListInput *input;
input = qmi_message_gas_dms_get_firmware_list_input_new ();
if (get_firmware_list_flag) {
g_debug ("Asynchronously getting full firmware list...");
qmi_message_gas_dms_get_firmware_list_input_set_mode (input, QMI_GAS_FIRMWARE_LISTING_MODE_ALL_FIRMWARE, NULL);
} else if (get_active_firmware_flag) {
g_debug ("Asynchronously getting active firmware list...");
qmi_message_gas_dms_get_firmware_list_input_set_mode (input, QMI_GAS_FIRMWARE_LISTING_MODE_ACTIVE_FIRMWARE, NULL);
} else
g_assert_not_reached ();
qmi_client_gas_dms_get_firmware_list (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_firmware_list_ready,
NULL);
qmi_message_gas_dms_get_firmware_list_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_SET_ACTIVE_FIRMWARE
if (set_active_firmware_int >= 0) {
QmiMessageGasDmsSetActiveFirmwareInput *input;
input = qmi_message_gas_dms_set_active_firmware_input_new ();
qmi_message_gas_dms_set_active_firmware_input_set_slot_index (input, set_active_firmware_int, NULL);
g_debug ("Asynchronously setting the active firmware index...");
qmi_client_gas_dms_set_active_firmware (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)set_active_firmware_ready,
NULL);
qmi_message_gas_dms_set_active_firmware_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_GAS_DMS_GET_ETHERNET_PDU_MAC_ADDRESS
if (get_ethernet_mac_address_flag) {
g_debug ("Asynchronously getting ethernet mac adress...");
qmi_client_gas_dms_get_ethernet_pdu_mac_address (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_ethernet_pdu_mac_address_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_GAS */

316
pkgs/qmi-nmea/qmicli-gms.c Normal file
View File

@ -0,0 +1,316 @@
/* -*- 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) 2020 Vladimir Podshivalov <vladimir.podshivalov@outlook.com>
*/
#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_GMS
/* Context */
typedef struct {
QmiDevice *device;
QmiClientGms *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gboolean get_value_flag;
static gchar *set_value_str;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_GMS_TEST_GET_VALUE
{ "gms-test-get-value", 0, 0, G_OPTION_ARG_NONE, &get_value_flag,
"Gets test value",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_GMS_TEST_SET_VALUE
{ "gms-test-set-value", 0, 0, G_OPTION_ARG_STRING, &set_value_str,
"Sets test value",
"[mandatory-value][,[optional-value]]"
},
#endif
{ "gms-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a GMS client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_gms_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("gms",
"GMS options:",
"Show General Modem Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_gms_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (get_value_flag +
!!set_value_str +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many GMS 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_GMS_TEST_GET_VALUE
static void
get_value_ready (QmiClientGms *client,
GAsyncResult *res)
{
QmiMessageGmsTestGetValueOutput *output;
GError *error = NULL;
guint8 test_mandatory_value;
guint8 test_optional_value;
output = qmi_client_gms_test_get_value_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_gms_test_get_value_output_get_result (output, &error)) {
g_printerr ("error: couldn't get stored test value: %s\n", error->message);
g_error_free (error);
qmi_message_gms_test_get_value_output_unref (output);
operation_shutdown (FALSE);
return;
}
if (qmi_message_gms_test_get_value_output_get_test_mandatory_value (output, &test_mandatory_value, NULL)) {
g_print ("Test mandatory value: %u\n", test_mandatory_value);
}
if (qmi_message_gms_test_get_value_output_get_test_optional_value (output, &test_optional_value, NULL)) {
g_print ("Test optional value: %u\n", test_optional_value);
}
qmi_message_gms_test_get_value_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_GMS_TEST_GET_VALUE */
#if defined HAVE_QMI_MESSAGE_GMS_TEST_SET_VALUE
static QmiMessageGmsTestSetValueInput *
set_value_input_create (const gchar *str)
{
QmiMessageGmsTestSetValueInput *input = NULL;
const gchar *mand_value_str = NULL;
const gchar *opt_value_str = NULL;
guint mand_value_int = 0;
guint opt_value_int = 0;
gchar **parts = NULL;
if (strchr (str, ',')) {
/* Both Mandatory Test Value and Optional Test Value were given */
parts = g_strsplit_set (str, ",", -1);
if (g_strv_length (parts) != 2) {
g_printerr ("error: failed to parse test value: '%s'\n", str);
goto out;
}
mand_value_str = parts[0];
opt_value_str = parts[1];
} else {
/* Only Mandatory Test Value was given */
mand_value_str = str;
}
g_assert (mand_value_str);
if (!qmicli_read_uint_from_string (mand_value_str, &mand_value_int) || (mand_value_int > G_MAXUINT8)) {
g_printerr ("error: failed to parse test mandatory value as 8bit value: '%s'\n", mand_value_str);
goto out;
}
if (opt_value_str && (!qmicli_read_uint_from_string (opt_value_str, &opt_value_int) || (opt_value_int > G_MAXUINT8))) {
g_printerr ("error: failed to parse test optional value as 8bit value: '%s'\n", opt_value_str);
goto out;
}
input = qmi_message_gms_test_set_value_input_new ();
qmi_message_gms_test_set_value_input_set_test_mandatory_value (input, (guint8) mand_value_int, NULL);
if (opt_value_str) {
qmi_message_gms_test_set_value_input_set_test_optional_value (input, (guint8) opt_value_int, NULL);
}
out:
g_strfreev (parts);
return input;
}
static void
set_value_ready (QmiClientGms *client,
GAsyncResult *res)
{
QmiMessageGmsTestSetValueOutput *output;
GError *error = NULL;
output = qmi_client_gms_test_set_value_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_gms_test_set_value_output_get_result (output, &error)) {
g_printerr ("error: couldn't set test value: %s\n", error->message);
g_error_free (error);
qmi_message_gms_test_set_value_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("Successfully set test value.\n");
qmi_message_gms_test_set_value_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_GMS_TEST_SET_VALUE */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_gms_run (QmiDevice *device,
QmiClientGms *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_GMS_TEST_GET_VALUE
if (get_value_flag) {
g_debug ("Asynchronously getting test value...");
qmi_client_gms_test_get_value (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_value_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_GMS_TEST_SET_VALUE
if (set_value_str) {
QmiMessageGmsTestSetValueInput *input;
g_debug ("Asynchronously setting test value...");
input = set_value_input_create (set_value_str);
if (!input) {
operation_shutdown (FALSE);
return;
}
qmi_client_gms_test_set_value (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)set_value_ready,
NULL);
qmi_message_gms_test_set_value_input_unref (input);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_GMS */

View File

@ -0,0 +1,985 @@
/* -*- 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) 2015 Velocloud Inc.
* Copyright (C) 2012-2019 Aleksander Morgado <aleksander@aleksander.es>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "qmicli-helpers.h"
#define QMICLI_ENUM_LIST_ITEM(TYPE,TYPE_UNDERSCORE,DESCR) \
gboolean \
qmicli_read_## TYPE_UNDERSCORE ##_from_string (const gchar *str, \
TYPE *out) \
{ \
GType type; \
GEnumClass *enum_class; \
GEnumValue *enum_value; \
\
type = qmi_## TYPE_UNDERSCORE ##_get_type (); \
enum_class = G_ENUM_CLASS (g_type_class_ref (type)); \
enum_value = g_enum_get_value_by_nick (enum_class, str); \
\
if (enum_value) \
*out = (TYPE)enum_value->value; \
else \
g_printerr ("error: invalid " DESCR " value given: '%s'\n", str); \
\
g_type_class_unref (enum_class); \
return !!enum_value; \
}
QMICLI_ENUM_LIST
#undef QMICLI_ENUM_LIST_ITEM
#define QMICLI_FLAGS_LIST_ITEM(TYPE,TYPE_UNDERSCORE,DESCR) \
gboolean \
qmicli_read_## TYPE_UNDERSCORE ##_from_string (const gchar *str, \
TYPE *out) \
{ \
GType type; \
GFlagsClass *flags_class; \
GFlagsValue *flags_value; \
gchar **items, **iter; \
gboolean success = TRUE; \
\
type = qmi_## TYPE_UNDERSCORE ##_get_type (); \
flags_class = G_FLAGS_CLASS (g_type_class_ref (type)); \
\
*out = 0; \
items = g_strsplit_set (str, "|", 0); \
for (iter = items; iter && *iter && success; iter++) { \
g_strstrip (*iter); \
if (!*iter[0]) \
continue; \
\
flags_value = g_flags_get_value_by_nick (flags_class, *iter); \
if (flags_value) { \
*out |= (TYPE)flags_value->value; \
} else { \
g_printerr ("error: unknown " DESCR " value given: '%s'\n", *iter); \
success = FALSE; \
} \
} \
\
g_strfreev (items); \
g_type_class_unref (flags_class); \
return success; \
}
QMICLI_FLAGS_LIST
#undef QMICLI_FLAGS_LIST_ITEM
/* For 64-bit flags we don't have GFlagsClass as they're aren't registered in the
* type system. Instead, we create a temporary array with all known flag names, and
* use it to match the input values given */
#define QMICLI_FLAGS64_LIST_ITEM(TYPE,TYPE_UNDERSCORE,DESCR) \
gboolean \
qmicli_read_## TYPE_UNDERSCORE ##_from_string (const gchar *str, \
TYPE *out) \
{ \
gchar *flag_names[64]; \
gchar **items, **iter; \
guint i; \
gboolean success = TRUE; \
\
for (i = 0; i < G_N_ELEMENTS (flag_names); i++) \
flag_names[i] = qmi_ ## TYPE_UNDERSCORE ## _build_string_from_mask (((guint64)1) << i); \
\
*out = 0; \
items = g_strsplit_set (str, "|", 0); \
for (iter = items; iter && *iter && success; iter++) { \
g_strstrip (*iter); \
if (!*iter[0]) \
continue; \
\
for (i = 0; i < G_N_ELEMENTS (flag_names); i++) { \
if (g_strcmp0 (*iter, flag_names[i]) == 0) { \
*out |= (TYPE)(((guint64)1) << i); \
break; \
} \
} \
if (i == G_N_ELEMENTS (flag_names)) { \
g_printerr ("error: unknown " DESCR " value given: '%s'\n", *iter); \
success = FALSE; \
} \
} \
\
for (i = 0; i < G_N_ELEMENTS (flag_names); i++) \
g_free (flag_names[i]); \
g_strfreev (items); \
return success; \
}
QMICLI_FLAGS64_LIST
#undef QMICLI_FLAGS64_LIST_ITEM
gchar *
qmicli_get_raw_data_printable (const GArray *data,
gsize max_line_length,
const gchar *line_prefix)
{
gsize i;
gsize j;
gsize k;
gsize new_str_length;
gchar *new_str;
gsize prefix_len;
guint n_lines;
gboolean is_new_line;
g_return_val_if_fail (max_line_length >= 3, NULL);
if (!data)
return g_strdup ("");
/* Get new string length. If input string has N bytes, we need:
* - 1 byte for last NUL char
* - 2N bytes for hexadecimal char representation of each byte...
* - N-1 bytes for the separator ':'
* So... a total of (1+2N+N-1) = 3N bytes are needed... */
new_str_length = 3 * data->len;
/* Effective max line length needs to be multiple of 3, we don't want to
* split in half a given byte representation */
while (max_line_length % 3 != 0)
max_line_length--;
/* Prefix len includes the newline character plus the length of the input
* prefix */
prefix_len = strlen (line_prefix) + 1;
/* We don't consider the last NUL byte when counting lines to generate */
n_lines = (new_str_length - 1) / max_line_length;
if ((new_str_length - 1) % max_line_length != 0)
n_lines++;
/* Build new str length expected when we prefix the string and we limit the
* line length */
new_str_length += (n_lines * prefix_len);
/* Allocate memory for new array and initialize contents to NUL */
new_str = g_malloc0 (new_str_length);
/* Print hexadecimal representation of each byte... */
is_new_line = TRUE;
for (i = 0, j = 0, k = 0; i < data->len; i++) {
if (is_new_line) {
strcpy (&new_str[j], line_prefix);
j += strlen (line_prefix);
is_new_line = FALSE;
}
/* Print character in output string... */
snprintf (&new_str[j], 3, "%02X", g_array_index (data, guint8, i));
j+=2;
k+=2;
if (i != (data->len - 1) ) {
new_str[j] = ':';
j++;
k++;
}
if (k % max_line_length == 0 ||
i == (data->len -1)) {
new_str[j] = '\n';
j++;
is_new_line = TRUE;
}
}
/* Set output string */
return new_str;
}
gchar *
qmicli_get_firmware_image_unique_id_printable (const GArray *unique_id)
{
gchar *unique_id_str;
guint i;
guint n_ascii = 0;
gboolean end = FALSE;
#define UNIQUE_ID_LEN 16
g_warn_if_fail (unique_id->len <= UNIQUE_ID_LEN);
unique_id_str = g_malloc0 (UNIQUE_ID_LEN + 1);
memcpy (unique_id_str, unique_id->data, UNIQUE_ID_LEN);
/* We want an ASCII string that, if finished before the 16 bytes,
* is suffixed with NUL bytes. */
for (i = 0; i < UNIQUE_ID_LEN; i++) {
/* If a byte isn't ASCII, stop */
if (unique_id_str[i] & 0x80)
break;
/* If string isn't finished yet... */
if (!end) {
/* String finished now */
if (unique_id_str[i] == '\0')
end = TRUE;
else
n_ascii++;
} else {
/* String finished but we then got
* another ASCII byte? not possible */
if (unique_id_str[i] != '\0')
break;
}
}
if (i == UNIQUE_ID_LEN && n_ascii > 0)
return unique_id_str;
#undef UNIQUE_ID_LEN
g_free (unique_id_str);
/* Get a raw hex string otherwise */
unique_id_str = qmicli_get_raw_data_printable (unique_id, 80, "");
unique_id_str[strlen (unique_id_str) - 1] = '\0'; /* remove EOL */
return unique_id_str;
}
gboolean
qmicli_read_dms_uim_pin_id_from_string (const gchar *str,
QmiDmsUimPinId *out)
{
if (!str || str[0] == '\0') {
g_printerr ("error: expected 'PIN' or 'PIN2', got: none\n");
return FALSE;
}
if (g_str_equal (str, "PIN")) {
*out = QMI_DMS_UIM_PIN_ID_PIN;
return TRUE;
}
if (g_str_equal (str, "PIN2")) {
*out = QMI_DMS_UIM_PIN_ID_PIN2;
return TRUE;
}
g_printerr ("error: expected 'PIN' or 'PIN2', got: '%s'\n", str);
return FALSE;
}
gboolean
qmicli_read_uim_pin_id_from_string (const gchar *str,
QmiUimPinId *out)
{
if (!str || str[0] == '\0') {
g_printerr ("error: expected 'PIN1', 'PIN2' or 'UPIN', got: none\n");
return FALSE;
}
if (g_str_equal (str, "PIN1")) {
*out = QMI_UIM_PIN_ID_PIN1;
return TRUE;
}
if (g_str_equal (str, "PIN2")) {
*out = QMI_UIM_PIN_ID_PIN2;
return TRUE;
}
if (g_str_equal (str, "UPIN")) {
*out = QMI_UIM_PIN_ID_UPIN;
return TRUE;
}
g_printerr ("error: expected 'PIN1', 'PIN2' or 'UPIN', got: '%s'\n", str);
return FALSE;
}
gboolean
qmicli_read_ssp_rat_options_from_string (const gchar *str,
QmiNasRatModePreference *out_mode_preference,
GArray **out_acquisition_order)
{
GType rat_mode_preference_type;
GFlagsClass *rat_mode_preference_flags_class;
GFlagsValue *rat_mode_preference_flags_value;
gboolean mode_preference_set = FALSE;
GType radio_interface_type;
GEnumClass *radio_interface_enum_class;
GEnumValue *radio_interface_enum_value;
gboolean acquisition_order_set = FALSE;
gboolean success = TRUE;
char **items, **iter;
rat_mode_preference_type = qmi_nas_rat_mode_preference_get_type ();
rat_mode_preference_flags_class = G_FLAGS_CLASS (g_type_class_ref (rat_mode_preference_type));
radio_interface_type = qmi_nas_radio_interface_get_type ();
radio_interface_enum_class = G_ENUM_CLASS (g_type_class_ref (radio_interface_type));
*out_mode_preference = 0;
*out_acquisition_order = g_array_new (FALSE, FALSE, sizeof (QmiNasRadioInterface));
items = g_strsplit_set (str, "|", 0);
for (iter = items; iter && *iter && success; iter++) {
if (!*iter[0])
continue;
/* Note: we can use the same nick names both for mode preference flags
* and acquistion order enums, which is very fortunate */
rat_mode_preference_flags_value = g_flags_get_value_by_nick (rat_mode_preference_flags_class, *iter);
if (rat_mode_preference_flags_value) {
*out_mode_preference |= (QmiNasRatModePreference)rat_mode_preference_flags_value->value;
mode_preference_set = TRUE;
} else {
g_printerr ("error: invalid rat mode pref value given: '%s'\n", *iter);
success = FALSE;
}
radio_interface_enum_value = g_enum_get_value_by_nick (radio_interface_enum_class, *iter);
if (radio_interface_enum_value) {
QmiNasRadioInterface value;
value = (QmiNasRadioInterface)(radio_interface_enum_value->value);
g_array_append_val (*out_acquisition_order, value);
acquisition_order_set = TRUE;
} else {
g_printerr ("error: invalid radio interface value given: '%s'\n", *iter);
success = FALSE;
}
}
if (!mode_preference_set)
g_printerr ("error: invalid rat mode pref input given: '%s'\n", str);
if (!acquisition_order_set)
g_printerr ("error: invalid rat mode pref input given: '%s'\n", str);
if (items)
g_strfreev (items);
g_type_class_unref (rat_mode_preference_flags_class);
g_type_class_unref (radio_interface_enum_class);
return success && (mode_preference_set || acquisition_order_set);;
}
static gboolean
parse_3gpp_mcc_mnc (const gchar *str,
guint16 *out_mcc,
guint16 *out_mnc,
gboolean *out_pcs_digit)
{
guint len;
guint i;
gchar aux[4];
guint16 tmp;
len = strlen (str);
if (len != 5 && len != 6)
return FALSE;
for (i = 0; i < len; i++) {
if (!g_ascii_isdigit (str[i]))
return FALSE;
}
memcpy (&aux[0], str, 3);
aux[3] = '\0';
tmp = atoi (aux);
if (tmp == 0)
return FALSE;
*out_mcc = tmp;
if (len == 5) {
memcpy (&aux[0], &str[3], 2);
aux[2] = '\0';
} else
memcpy (&aux[0], &str[3], 3);
*out_mnc = atoi (aux);
if (out_pcs_digit)
*out_pcs_digit = len == 6;
return TRUE;
}
gboolean
qmicli_read_ssp_net_options_from_string (const gchar *str,
QmiNasNetworkSelectionPreference *out,
guint16 *out_mcc,
guint16 *out_mnc)
{
GType type;
GEnumClass *enum_class;
GEnumValue *enum_value;
gchar *copy, *equals;
guint16 mcc = 0, mnc = 0;
copy = g_strdup (str);
equals = strchr (copy, '=');
if (equals) {
/* Parse MCC/MNC */
*equals++ = '\0';
if (!parse_3gpp_mcc_mnc (equals, &mcc, &mnc, NULL)) {
g_free (copy);
g_printerr ("error: invalid net selection MCC/MNC: '%s'\n", equals);
return FALSE;
}
}
type = qmi_nas_network_selection_preference_get_type ();
enum_class = G_ENUM_CLASS (g_type_class_ref (type));
enum_value = g_enum_get_value_by_nick (enum_class, copy);
if (enum_value) {
*out = (QmiNasNetworkSelectionPreference)enum_value->value;
*out_mcc = mcc;
*out_mnc = mnc;
} else
g_printerr ("error: invalid net selection preference value given: '%s'\n", copy);
g_free (copy);
g_type_class_unref (enum_class);
return !!enum_value;
}
gboolean
qmicli_read_parse_3gpp_mcc_mnc (const gchar *str,
guint16 *out_mcc,
guint16 *out_mnc,
gboolean *out_pcs_digit)
{
g_autofree gchar *copy = NULL;
guint16 mcc = 0, mnc = 0;
gboolean pcs_digit = FALSE;
copy = g_strdup (str);
if (!parse_3gpp_mcc_mnc (copy, &mcc, &mnc, &pcs_digit)) {
g_printerr ("error: invalid net selection MCC/MNC: '%s'\n", str);
return FALSE;
}
*out_mcc = mcc;
*out_mnc = mnc;
if (out_pcs_digit)
*out_pcs_digit = pcs_digit;
return TRUE;
}
gboolean
qmicli_read_enable_disable_from_string (const gchar *str,
gboolean *out)
{
if (!str || str[0] == '\0') {
g_printerr ("error: expected 'disable' or 'enable', got: none\n");
return FALSE;
}
if (g_str_equal (str, "disable")) {
*out = FALSE;
return TRUE;
}
if (g_str_equal (str, "enable")) {
*out = TRUE;
return TRUE;
}
g_printerr ("error: expected 'disable' or 'enable', got: '%s'\n", str);
return FALSE;
}
gboolean
qmicli_read_yes_no_from_string (const gchar *str,
gboolean *out)
{
if (!str || str[0] == '\0') {
g_printerr ("error: expected 'true', 'false', 'yes' or 'no', got: none\n");
return FALSE;
}
if ((g_strcasecmp (str, "yes") == 0) || (g_strcasecmp (str, "true") == 0)) {
*out = TRUE;
return TRUE;
}
if ((g_strcasecmp (str, "no") == 0) || (g_strcasecmp (str, "false") == 0)) {
*out = FALSE;
return TRUE;
}
g_printerr ("error: expected 'true', 'false', 'yes' or 'no', got: %s\n", str);
return FALSE;
}
gboolean
qmicli_read_non_empty_string (const gchar *str,
const gchar *description,
gchar **out)
{
if (!str || str[0] == '\0') {
g_printerr ("error: empty %s given\n", description);
return FALSE;
}
*out = (gchar *)str;
return TRUE;
}
gboolean
qmicli_read_raw_data_from_string (const gchar *str,
GArray **out)
{
GArray *array;
gsize i;
gsize str_len;
array = g_array_new (FALSE, FALSE, sizeof (guint8));
str_len = str ? strlen (str) : 0;
for (i = 0; i < str_len; i += 2) {
gint high, low;
guint8 value;
/* For easy processing, we just ignore the ':' chars, if any available */
if (str[i] == ':')
i++;
high = g_ascii_xdigit_value (str[i]);
if (high < 0 || high > 0xF) {
g_printerr ("error: invalid hex char found: '%c'\n", str[i]);
g_clear_pointer (&array, g_array_unref);
return FALSE;
}
if (!((i + 1) < str_len)) {
g_printerr ("unterminated byte found: '%c?'\n", str[i]);
g_clear_pointer (&array, g_array_unref);
return FALSE;
}
low = g_ascii_xdigit_value (str[i + 1]);
if (low < 0 || low > 0xF) {
g_printerr ("invalid hex char found: '%c'\n", str[i + 1]);
g_clear_pointer (&array, g_array_unref);
return FALSE;
}
value = (high << 4) | low;
g_array_append_val (array, value);
}
*out = array;
return TRUE;
}
gboolean
qmicli_read_firmware_id_from_string (const gchar *str,
QmiDmsFirmwareImageType *out_type,
guint *out_index)
{
const gchar *index_str;
if (g_str_has_prefix (str, "modem")) {
*out_type = QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM;
index_str = &str[5];
} else if (g_str_has_prefix (str, "pri")) {
*out_type = QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI;
index_str = &str[3];
} else {
g_printerr ("error: invalid firmware image type value given: '%s'\n", str);
return FALSE;
}
return qmicli_read_uint_from_string (index_str, out_index);
}
gboolean
qmicli_read_binary_array_from_string (const gchar *str,
GArray **out)
{
gsize i, j, len;
g_return_val_if_fail (out != NULL, FALSE);
g_return_val_if_fail (str, FALSE);
/* Ignore ':' digits in the binary string input */
for (len = 0, i = 0; str[i]; i++) {
if (str[i] == ':')
continue;
len++;
}
/* Length must be a multiple of 2 */
if (len & 1)
return FALSE;
*out = g_array_sized_new (FALSE, TRUE, sizeof (guint8), len >> 1);
g_array_set_size (*out, len >> 1);
i = 0;
j = 0;
while (str[i]) {
gint a, b;
while (str[i] == ':')
i++;
a = g_ascii_xdigit_value (str[i++]);
while (str[i] == ':')
i++;
b = g_ascii_xdigit_value (str[i++]);
if (a < 0 || b < 0) {
g_array_unref (*out);
return FALSE;
}
g_array_index (*out, guint8, j++) = (a << 4) | b;
}
return TRUE;
}
gboolean
qmicli_validate_device_open_flags (QmiDeviceOpenFlags mask)
{
if (!mask) {
g_printerr ("error: invalid device open flags given\n");
return FALSE;
}
if ((mask & QMI_DEVICE_OPEN_FLAGS_NET_802_3) &&
(mask & QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP)) {
g_printerr ("error: cannot give both 802.3 and raw-IP options\n");
return FALSE;
}
if ((mask & QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER) &&
(mask & QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER)) {
g_printerr ("error: cannot request both QoS and no-QoS headers\n");
return FALSE;
}
if ((mask & (QMI_DEVICE_OPEN_FLAGS_NET_802_3 | QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP)) &&
!(mask & (QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER | QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER))) {
g_printerr ("error: missing QoS or no-QoS header request\n");
return FALSE;
}
if ((mask & (QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER | QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER)) &&
!(mask & (QMI_DEVICE_OPEN_FLAGS_NET_802_3 | QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP))) {
g_printerr ("error: missing link protocol (802.3 or raw IP)\n");
return FALSE;
}
return TRUE;
}
gboolean
qmicli_read_authentication_from_string (const gchar *str,
QmiWdsAuthentication *out)
{
if (g_ascii_strcasecmp (str, "PAP") == 0)
*out = QMI_WDS_AUTHENTICATION_PAP;
else if (g_ascii_strcasecmp (str, "CHAP") == 0)
*out = QMI_WDS_AUTHENTICATION_CHAP;
else if (g_ascii_strcasecmp (str, "BOTH") == 0)
*out = (QMI_WDS_AUTHENTICATION_PAP | QMI_WDS_AUTHENTICATION_CHAP);
else if (!str[0] || g_ascii_strcasecmp (str, "NONE") == 0)
*out = QMI_WDS_AUTHENTICATION_NONE;
else
return FALSE;
return TRUE;
}
gboolean
qmicli_read_pdp_type_from_string (const gchar *str,
QmiWdsPdpType *out)
{
if (g_ascii_strcasecmp (str, "IP") == 0 || g_ascii_strcasecmp (str, "IPV4") == 0)
*out = QMI_WDS_PDP_TYPE_IPV4;
else if (g_ascii_strcasecmp (str, "PPP") == 0)
*out = QMI_WDS_PDP_TYPE_PPP;
else if (g_ascii_strcasecmp (str, "IPV6") == 0)
*out = (QMI_WDS_PDP_TYPE_IPV6);
else if (g_ascii_strcasecmp (str, "IPV4V6") == 0)
*out = QMI_WDS_PDP_TYPE_IPV4_OR_IPV6;
else
return FALSE;
return TRUE;
}
gboolean
qmicli_read_uint_from_string (const gchar *str,
guint *out)
{
gulong num;
if (!str || !str[0])
return FALSE;
for (num = 0; str[num]; num++) {
if (!g_ascii_isdigit (str[num]))
return FALSE;
}
errno = 0;
num = strtoul (str, NULL, 10);
if (!errno && num <= G_MAXUINT) {
*out = (guint)num;
return TRUE;
}
return FALSE;
}
gchar *
qmicli_get_supported_messages_list (const guint8 *data,
gsize len)
{
GString *str = NULL;
if (len > 0 && data) {
guint bytearray_i;
for (bytearray_i = 0; bytearray_i < len; bytearray_i++) {
guint bit_i;
for (bit_i = 0; bit_i < 8; bit_i++) {
if (data[bytearray_i] & (1 << bit_i)) {
if (!str)
str = g_string_new ("");
g_string_append_printf (str, "\t0x%04X\n", (guint16) (bit_i + (8 * bytearray_i)));
}
}
}
}
return (str ? g_string_free (str, FALSE) : g_strdup ("\tnone\n"));
}
/******************************************************************************/
typedef struct {
guint16 min;
guint16 max;
const gchar *name;
} EarfcnRange;
/* http://niviuk.free.fr/lte_band.php */
static const EarfcnRange earfcn_ranges[] = {
{ 0, 599, "E-UTRA band 1: 2100" },
{ 600, 1199, "E-UTRA band 2: 1900 PCS" },
{ 1200, 1949, "E-UTRA band 3: 1800+" },
{ 1950, 2399, "E-UTRA band 4: AWS-1" },
{ 2400, 2649, "E-UTRA band 5: 850" },
{ 2650, 2749, "E-UTRA band 6: UMTS only" },
{ 2750, 3449, "E-UTRA band 7: 2600" },
{ 3450, 3799, "E-UTRA band 8: 900" },
{ 3800, 4149, "E-UTRA band 9: 1800" },
{ 4150, 4749, "E-UTRA band 10: AWS-1+" },
{ 4750, 4999, "E-UTRA band 11: 1500 Lower" },
{ 5000, 5179, "E-UTRA band 12: 700 a" },
{ 5180, 5279, "E-UTRA band 13: 700 c" },
{ 5280, 5379, "E-UTRA band 14: 700 PS" },
{ 5730, 5849, "E-UTRA band 17: 700 b" },
{ 5850, 5999, "E-UTRA band 18: 800 Lower" },
{ 6000, 6149, "E-UTRA band 19: 800 Upper" },
{ 6150, 6449, "E-UTRA band 20: 800 DD" },
{ 6450, 6599, "E-UTRA band 21: 1500 Upper" },
{ 6600, 7399, "E-UTRA band 22: 3500" },
{ 7500, 7699, "E-UTRA band 23: 2000 S-band" },
{ 7700, 8039, "E-UTRA band 24: 1600 L-band" },
{ 8040, 8689, "E-UTRA band 25: 1900+" },
{ 8690, 9039, "E-UTRA band 26: 850+" },
{ 9040, 9209, "E-UTRA band 27: 800 SMR" },
{ 9210, 9659, "E-UTRA band 28: 700 APT" },
{ 9660, 9769, "E-UTRA band 29: 700 d" },
{ 9770, 9869, "E-UTRA band 30: 2300 WCS" },
{ 9870, 9919, "E-UTRA band 31: 450" },
{ 9920, 10359, "E-UTRA band 32: 1500 L-band" },
{ 36000, 36199, "E-UTRA band 33: TD 1900" },
{ 36200, 36349, "E-UTRA band 34: TD 2000" },
{ 36350, 36949, "E-UTRA band 35: TD PCS Lower" },
{ 36950, 37549, "E-UTRA band 36: TD PCS Upper" },
{ 37550, 37749, "E-UTRA band 37: TD PCS Center" },
{ 37750, 38249, "E-UTRA band 38: TD 2600" },
{ 38250, 38649, "E-UTRA band 39: TD 1900+" },
{ 38650, 39649, "E-UTRA band 40: TD 2300" },
{ 39650, 41589, "E-UTRA band 41: TD 2500" },
{ 41590, 43589, "E-UTRA band 42: TD 3500" },
{ 43590, 45589, "E-UTRA band 43: TD 3700" },
{ 45590, 46589, "E-UTRA band 44: TD 700" },
};
const char *
qmicli_earfcn_to_eutra_band_string (guint16 earfcn)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (earfcn_ranges); i++) {
if (earfcn <= earfcn_ranges[i].max && earfcn >= earfcn_ranges[i].min)
return earfcn_ranges[i].name;
}
return "unknown";
}
/* Expecting input as:
* key1=string,key2=true,key3=false...
* Strings may also be passed enclosed between double or single quotes, like:
* key1="this is a string", key2='and so is this'
*
* Based on libmbim's mbimcli_parse_key_value_string().
*/
gboolean
qmicli_parse_key_value_string (const gchar *str,
GError **error,
QmiParseKeyValueForeachFn callback,
gpointer user_data)
{
GError *inner_error = NULL;
gchar *dupstr, *p, *key, *key_end, *value, *value_end, quote;
g_return_val_if_fail (callback != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
/* Allow empty strings, we'll just return with success */
while (g_ascii_isspace (*str))
str++;
if (!str[0])
return TRUE;
dupstr = g_strdup (str);
p = dupstr;
while (TRUE) {
gboolean keep_iteration = FALSE;
/* Skip leading spaces */
while (g_ascii_isspace (*p))
p++;
/* Key start */
key = p;
if (!g_ascii_isalnum (*key)) {
inner_error = g_error_new (QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Key must start with alpha/num, starts with '%c'",
*key);
break;
}
/* Key end */
while (g_ascii_isalnum (*p) || (*p == '-') || (*p == '_'))
p++;
key_end = p;
if (key_end == key) {
inner_error = g_error_new (QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Couldn't find a proper key");
break;
}
/* Skip whitespaces, if any */
while (g_ascii_isspace (*p))
p++;
/* Equal sign must be here */
if (*p != '=') {
inner_error = g_error_new (QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Couldn't find equal sign separator");
break;
}
/* Skip the equal */
p++;
/* Skip whitespaces, if any */
while (g_ascii_isspace (*p))
p++;
/* Do we have a quote-enclosed string? */
if (*p == '\"' || *p == '\'') {
quote = *p;
/* Skip the quote */
p++;
/* Value start */
value = p;
/* Find the closing quote */
p = strchr (p, quote);
if (!p) {
inner_error = g_error_new (QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unmatched quotes in string value");
break;
}
/* Value end */
value_end = p;
/* Skip the quote */
p++;
} else {
/* Value start */
value = p;
/* Value end */
while ((*p != ',') && (*p != '\0') && !g_ascii_isspace (*p))
p++;
value_end = p;
}
/* Note that we allow value == value_end here */
/* Skip whitespaces, if any */
while (g_ascii_isspace (*p))
p++;
/* If a comma is found, we should keep the iteration */
if (*p == ',') {
/* skip the comma */
p++;
keep_iteration = TRUE;
}
/* Got key and value, prepare them and run the callback */
*value_end = '\0';
*key_end = '\0';
if (!callback (key, value, &inner_error, user_data)) {
/* We were told to abort */
break;
}
g_assert (!inner_error);
if (keep_iteration)
continue;
/* Check if no more key/value pairs expected */
if (*p == '\0')
break;
inner_error = g_error_new (QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unexpected content (%s) after value",
p);
break;
}
g_free (dupstr);
if (inner_error) {
g_propagate_error (error, inner_error);
return FALSE;
}
return TRUE;
}

View File

@ -0,0 +1,147 @@
/* -*- 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) 2015 Velocloud Inc.
* Copyright (C) 2012-2017 Aleksander Morgado <aleksander@aleksander.es>
*/
#include <glib.h>
#include <libqmi-glib.h>
#ifndef __QMICLI_HELPERS_H__
#define __QMICLI_HELPERS_H__
/* Common helpers to read enums from strings */
#define QMICLI_ENUM_LIST \
QMICLI_ENUM_LIST_ITEM (QmiDmsOperatingMode, dms_operating_mode, "operating mode") \
QMICLI_ENUM_LIST_ITEM (QmiDmsUimFacility, dms_uim_facility, "facility") \
QMICLI_ENUM_LIST_ITEM (QmiPdcConfigurationType, pdc_configuration_type, "configuration type") \
QMICLI_ENUM_LIST_ITEM (QmiNasRadioInterface, nas_radio_interface, "radio interface") \
QMICLI_ENUM_LIST_ITEM (QmiDeviceExpectedDataFormat, device_expected_data_format, "device expected data format") \
QMICLI_ENUM_LIST_ITEM (QmiWdaLinkLayerProtocol, wda_link_layer_protocol, "link layer protocol") \
QMICLI_ENUM_LIST_ITEM (QmiWdaDataAggregationProtocol, wda_data_aggregation_protocol, "data aggregation protocol") \
QMICLI_ENUM_LIST_ITEM (QmiDataEndpointType, data_endpoint_type, "data endpoint type") \
QMICLI_ENUM_LIST_ITEM (QmiWdsAutoconnectSetting, wds_autoconnect_setting, "autoconnect setting") \
QMICLI_ENUM_LIST_ITEM (QmiWdsAutoconnectSettingRoaming, wds_autoconnect_setting_roaming, "autoconnect setting roaming") \
QMICLI_ENUM_LIST_ITEM (QmiDmsBootImageDownloadMode, dms_boot_image_download_mode, "boot image download mode") \
QMICLI_ENUM_LIST_ITEM (QmiDmsHpDeviceMode, dms_hp_device_mode, "hp device mode") \
QMICLI_ENUM_LIST_ITEM (QmiDmsSwiUsbComposition, dms_swi_usb_composition, "swi usb composition") \
QMICLI_ENUM_LIST_ITEM (QmiDmsFoxconnDeviceMode, dms_foxconn_device_mode, "foxconn device mode") \
QMICLI_ENUM_LIST_ITEM (QmiDmsFoxconnFirmwareVersionType, dms_foxconn_firmware_version_type, "foxconn firmware version type") \
QMICLI_ENUM_LIST_ITEM (QmiUimSessionType, uim_session_type, "session type") \
QMICLI_ENUM_LIST_ITEM (QmiDsdApnType, dsd_apn_type, "apn type") \
QMICLI_ENUM_LIST_ITEM (QmiDmsMacType, dms_mac_type, "mac address type") \
QMICLI_ENUM_LIST_ITEM (QmiSarRfState, sar_rf_state, "sar rf state") \
QMICLI_ENUM_LIST_ITEM (QmiSioPort, sio_port, "sio port") \
QMICLI_ENUM_LIST_ITEM (QmiLocOperationMode, loc_operation_mode, "operation mode") \
QMICLI_ENUM_LIST_ITEM (QmiLocLockType, loc_lock_type, "lock type") \
QMICLI_ENUM_LIST_ITEM (QmiUimCardApplicationPersonalizationFeature, uim_card_application_personalization_feature, "personalization feature" ) \
QMICLI_ENUM_LIST_ITEM (QmiUimDepersonalizationOperation, uim_depersonalization_operation, "depersonalization operation" ) \
QMICLI_ENUM_LIST_ITEM (QmiWmsMessageType, wms_message_type, "message type" ) \
QMICLI_ENUM_LIST_ITEM (QmiWmsMessageClass, wms_message_class, "message class" ) \
QMICLI_ENUM_LIST_ITEM (QmiWmsStorageType, wms_storage_type, "storage type" ) \
QMICLI_ENUM_LIST_ITEM (QmiWmsReceiptAction, wms_receipt_action, "receipt action" ) \
QMICLI_ENUM_LIST_ITEM (QmiFoxFirmwareVersionType, fox_firmware_version_type, "fox firmware version type")
#define QMICLI_ENUM_LIST_ITEM(TYPE,TYPE_UNDERSCORE,DESCR) \
gboolean qmicli_read_## TYPE_UNDERSCORE ##_from_string (const gchar *str, TYPE *out);
QMICLI_ENUM_LIST
#undef QMICLI_ENUM_LIST_ITEM
/* Common helpers to read flags from strings */
#define QMICLI_FLAGS_LIST \
QMICLI_FLAGS_LIST_ITEM (QmiDeviceOpenFlags, device_open_flags, "device open flags") \
QMICLI_FLAGS_LIST_ITEM (QmiDeviceAddLinkFlags, device_add_link_flags, "device add link flags") \
QMICLI_FLAGS_LIST_ITEM (QmiLocNmeaType, loc_nmea_type, "NMEA type") \
QMICLI_FLAGS_LIST_ITEM (QmiNasPlmnAccessTechnologyIdentifier, nas_plmn_access_technology_identifier, "PLMN access technology")
#define QMICLI_FLAGS_LIST_ITEM(TYPE,TYPE_UNDERSCORE,DESCR) \
gboolean qmicli_read_## TYPE_UNDERSCORE ##_from_string (const gchar *str, TYPE *out);
QMICLI_FLAGS_LIST
#undef QMICLI_FLAGS_LIST_ITEM
/* Common helpers to read 64bit flags from strings */
#define QMICLI_FLAGS64_LIST \
QMICLI_FLAGS64_LIST_ITEM (QmiDsdApnTypePreference, dsd_apn_type_preference, "apn type preference") \
QMICLI_FLAGS64_LIST_ITEM (QmiWdsApnTypeMask, wds_apn_type_mask, "apn type mask")
#define QMICLI_FLAGS64_LIST_ITEM(TYPE,TYPE_UNDERSCORE,DESCR) \
gboolean qmicli_read_## TYPE_UNDERSCORE ##_from_string (const gchar *str, TYPE *out);
QMICLI_FLAGS64_LIST
#undef QMICLI_FLAGS64_LIST_ITEM
gchar *qmicli_get_raw_data_printable (const GArray *data,
gsize max_line_length,
const gchar *new_line_prefix);
gchar *qmicli_get_firmware_image_unique_id_printable (const GArray *unique_id);
gboolean qmicli_read_dms_uim_pin_id_from_string (const gchar *str,
QmiDmsUimPinId *out);
gboolean qmicli_read_uim_pin_id_from_string (const gchar *str,
QmiUimPinId *out);
gboolean qmicli_read_ssp_rat_options_from_string (const gchar *str,
QmiNasRatModePreference *out_mode_preference,
GArray **out_acquisition_order);
gboolean qmicli_read_ssp_net_options_from_string (const gchar *str,
QmiNasNetworkSelectionPreference *out_network_preference,
guint16 *out_network_mcc,
guint16 *out_network_mnc);
gboolean qmicli_read_parse_3gpp_mcc_mnc (const gchar *str,
guint16 *out_mcc,
guint16 *out_mnc,
gboolean *out_pcs_digit);
gboolean qmicli_read_enable_disable_from_string (const gchar *str,
gboolean *out);
gboolean qmicli_read_firmware_id_from_string (const gchar *str,
QmiDmsFirmwareImageType *out_type,
guint *out_index);
gboolean qmicli_read_binary_array_from_string (const gchar *str,
GArray **out);
gboolean qmicli_read_authentication_from_string (const gchar *str,
QmiWdsAuthentication *out);
gboolean qmicli_read_pdp_type_from_string (const gchar *str,
QmiWdsPdpType *out);
gboolean qmicli_read_non_empty_string (const gchar *str,
const gchar *description,
gchar **out);
gboolean qmicli_read_uint_from_string (const gchar *str,
guint *out);
gboolean qmicli_read_raw_data_from_string (const gchar *str,
GArray **out);
gboolean qmicli_read_yes_no_from_string (const gchar *str,
gboolean *out);
gchar *qmicli_get_supported_messages_list (const guint8 *data,
gsize len);
const char *qmicli_earfcn_to_eutra_band_string (guint16 earfcn);
gboolean qmicli_validate_device_open_flags (QmiDeviceOpenFlags mask);
typedef gboolean (*QmiParseKeyValueForeachFn) (const gchar *key,
const gchar *value,
GError **error,
gpointer user_data);
gboolean qmicli_parse_key_value_string (const gchar *str,
GError **error,
QmiParseKeyValueForeachFn callback,
gpointer user_data);
#endif /* __QMICLI_H__ */

283
pkgs/qmi-nmea/qmicli-ims.c Normal file
View File

@ -0,0 +1,283 @@
/* -*- 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_IMS
/* Context */
typedef struct {
QmiDevice *device;
QmiClientIms *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gint bind_flag = -1;
static gboolean get_services_enabled_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_IMS_BIND
{ "ims-bind", 0, 0, G_OPTION_ARG_INT, &bind_flag,
"Bind to IMS Settings (use with --client-no-release-cid)",
"[binding]"
},
#endif
#if defined HAVE_QMI_MESSAGE_IMS_GET_IMS_SERVICES_ENABLED_SETTING
{ "ims-get-ims-services-enabled-setting", 0, 0, G_OPTION_ARG_NONE, &get_services_enabled_flag,
"Get IMS Services Enabled Setting",
NULL
},
#endif
{ "ims-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a IMS client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL }
};
GOptionGroup *
qmicli_ims_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("ims",
"IMS options:",
"Show IP Multimedia Subsystem Settings Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_ims_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = ((bind_flag >= 0) +
get_services_enabled_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many IMS 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_IMS_BIND
static void
bind_ready (QmiClientIms *client,
GAsyncResult *res)
{
QmiMessageImsBindOutput *output;
g_autoptr(GError) error = NULL;
output = qmi_client_ims_bind_finish (client, res, &error);
if (!output) {
g_printerr ("error: operation failed: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_ims_bind_output_get_result (output, &error)) {
g_printerr ("error: couldn't bind to IMS Settings: %s\n", error->message);
qmi_message_ims_bind_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] IMS Settings bind successful\n", qmi_device_get_path_display (ctx->device));
qmi_message_ims_bind_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_IMS_BIND */
#if defined HAVE_QMI_MESSAGE_IMS_GET_IMS_SERVICES_ENABLED_SETTING
static void
get_services_enabled_ready (QmiClientIms *client,
GAsyncResult *res)
{
QmiMessageImsGetImsServicesEnabledSettingOutput *output;
gboolean service_voice_enabled;
gboolean service_vt_enabled;
gboolean service_voice_wifi_enabled;
gboolean service_ims_registration_enabled;
gboolean service_ut_enabled;
gboolean service_sms_enabled;
gboolean service_ussd_enabled;
GError *error = NULL;
output = qmi_client_ims_get_ims_services_enabled_setting_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_ims_get_ims_services_enabled_setting_output_get_result (output, &error)) {
g_printerr ("error: couldn't get IMS services enabled setting: %s\n", error->message);
g_error_free (error);
qmi_message_ims_get_ims_services_enabled_setting_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] IMS services:\n", qmi_device_get_path_display (ctx->device));
if (qmi_message_ims_get_ims_services_enabled_setting_output_get_ims_voice_service_enabled (output, &service_voice_enabled, NULL))
g_print ("\t Voice service enabled: %s\n", service_voice_enabled? "yes" : "no");
if (qmi_message_ims_get_ims_services_enabled_setting_output_get_ims_video_telephony_service_enabled (output, &service_vt_enabled, NULL))
g_print ("\tVideo Telephony service enabled: %s\n", service_vt_enabled? "yes" : "no");
if (qmi_message_ims_get_ims_services_enabled_setting_output_get_ims_voice_wifi_service_enabled (output, &service_voice_wifi_enabled, NULL))
g_print ("\t Voice WiFi service enabled: %s\n", service_voice_wifi_enabled? "yes" : "no");
if (qmi_message_ims_get_ims_services_enabled_setting_output_get_ims_registration_service_enabled (output, &service_ims_registration_enabled, NULL))
g_print ("\t IMS registration enabled: %s\n", service_ims_registration_enabled? "yes" : "no");
if (qmi_message_ims_get_ims_services_enabled_setting_output_get_ims_ut_service_enabled (output, &service_ut_enabled, NULL))
g_print ("\t UE to TAS service enabled: %s\n", service_ut_enabled? "yes" : "no");
if (qmi_message_ims_get_ims_services_enabled_setting_output_get_ims_sms_service_enabled (output, &service_sms_enabled, NULL))
g_print ("\t SMS service enabled: %s\n", service_sms_enabled? "yes" : "no");
if (qmi_message_ims_get_ims_services_enabled_setting_output_get_ims_ussd_service_enabled (output, &service_ussd_enabled, NULL))
g_print ("\t USSD service enabled: %s\n", service_ut_enabled? "yes" : "no");
qmi_message_ims_get_ims_services_enabled_setting_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_IMS_GET_IMS_SERVICES_ENABLED_SETTING */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_ims_run (QmiDevice *device,
QmiClientIms *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_IMS_BIND
if (bind_flag >= 0) {
QmiMessageImsBindInput *input;
input = qmi_message_ims_bind_input_new ();
qmi_message_ims_bind_input_set_binding (input, bind_flag, NULL);
g_debug ("Asynchronously binding to IMS settings service...");
qmi_client_ims_bind (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)bind_ready,
NULL);
qmi_message_ims_bind_input_unref (input);
return;
}
#endif /* HAVE_QMI_MESSAGE_IMS_BIND */
#if defined HAVE_QMI_MESSAGE_IMS_GET_IMS_SERVICES_ENABLED_SETTING
if (get_services_enabled_flag) {
g_debug ("Asynchronously getting services enabled setting...");
qmi_client_ims_get_ims_services_enabled_setting (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_services_enabled_ready,
NULL);
return;
}
#endif /* HAVE_QMI_MESSAGE_IMS_GET_IMS_SERVICES_ENABLED_SETTING */
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_IMS */

367
pkgs/qmi-nmea/qmicli-imsa.c Normal file
View File

@ -0,0 +1,367 @@
/* -*- 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_IMSA
/* Context */
typedef struct {
QmiDevice *device;
QmiClientImsa *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gint bind_flag = -1;
static gboolean get_ims_registration_status_flag;
static gboolean get_ims_services_status_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_IMSA_BIND
{ "imsa-bind", 0, 0, G_OPTION_ARG_INT, &bind_flag,
"Bind to IMSA (use with --client-no-release-cid)",
"[binding]"
},
#endif
#if defined HAVE_QMI_MESSAGE_IMSA_GET_IMS_REGISTRATION_STATUS
{ "imsa-get-ims-registration-status", 0, 0, G_OPTION_ARG_NONE, &get_ims_registration_status_flag,
"Get IMS registration status",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_IMSA_GET_IMS_SERVICES_STATUS
{ "imsa-get-ims-services-status", 0, 0, G_OPTION_ARG_NONE, &get_ims_services_status_flag,
"Get IMS services status",
NULL
},
#endif
{ "imsa-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a IMSA client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL }
};
GOptionGroup *
qmicli_imsa_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("imsa",
"IMSA options:",
"Show IP Multimedia Subsystem Application Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_imsa_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = ((bind_flag >= 0) +
get_ims_registration_status_flag +
get_ims_services_status_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many IMSA 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_IMSA_BIND
static void
bind_ready (QmiClientImsa *client,
GAsyncResult *res)
{
QmiMessageImsaBindOutput *output;
g_autoptr(GError) error = NULL;
output = qmi_client_imsa_bind_finish (client, res, &error);
if (!output) {
g_printerr ("error: operation failed: %s\n", error->message);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_imsa_bind_output_get_result (output, &error)) {
g_printerr ("error: couldn't bind to IMSA: %s\n", error->message);
qmi_message_imsa_bind_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] IMSA bind successful\n", qmi_device_get_path_display (ctx->device));
qmi_message_imsa_bind_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_IMSA_BIND */
#if defined HAVE_QMI_MESSAGE_IMSA_GET_IMS_REGISTRATION_STATUS
static void
get_ims_registration_status_ready (QmiClientImsa *client,
GAsyncResult *res)
{
QmiMessageImsaGetImsRegistrationStatusOutput *output;
QmiImsaImsRegistrationStatus registration_status;
QmiImsaRegistrationTechnology registration_technology;
GError *error = NULL;
output = qmi_client_imsa_get_ims_registration_status_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_imsa_get_ims_registration_status_output_get_result (output, &error)) {
g_printerr ("error: couldn't get IMS registration status: %s\n", error->message);
g_error_free (error);
qmi_message_imsa_get_ims_registration_status_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] IMS registration:\n", qmi_device_get_path_display (ctx->device));
if (qmi_message_imsa_get_ims_registration_status_output_get_ims_registration_status (output, &registration_status, NULL))
g_print ("\t Status: '%s'\n", qmi_imsa_ims_registration_status_get_string (registration_status));
if (qmi_message_imsa_get_ims_registration_status_output_get_ims_registration_technology (output, &registration_technology, NULL))
g_print ("\tTechnology: '%s'\n", qmi_imsa_registration_technology_get_string (registration_technology));
qmi_message_imsa_get_ims_registration_status_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_IMSA_GET_IMS_REGISTRATION_STATUS */
#if defined HAVE_QMI_MESSAGE_IMSA_GET_IMS_SERVICES_STATUS
static void
get_ims_services_status_ready (QmiClientImsa *client,
GAsyncResult *res)
{
QmiMessageImsaGetImsServicesStatusOutput *output;
QmiImsaServiceStatus service_sms_status;
QmiImsaRegistrationTechnology service_sms_technology;
QmiImsaServiceStatus service_voice_status;
QmiImsaRegistrationTechnology service_voice_technology;
QmiImsaServiceStatus service_vt_status;
QmiImsaRegistrationTechnology service_vt_technology;
QmiImsaServiceStatus service_ut_status;
QmiImsaRegistrationTechnology service_ut_technology;
QmiImsaServiceStatus service_vs_status;
QmiImsaRegistrationTechnology service_vs_technology;
GError *error = NULL;
output = qmi_client_imsa_get_ims_services_status_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_imsa_get_ims_services_status_output_get_result (output, &error)) {
g_printerr ("error: couldn't get IMS services status: %s\n", error->message);
g_error_free (error);
qmi_message_imsa_get_ims_services_status_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] IMS services:\n", qmi_device_get_path_display (ctx->device));
g_print ("\tSMS service\n");
if (qmi_message_imsa_get_ims_services_status_output_get_ims_sms_service_status (output, &service_sms_status, NULL))
g_print ("\t\t Status: '%s'\n", qmi_imsa_service_status_get_string (service_sms_status));
if (qmi_message_imsa_get_ims_services_status_output_get_ims_sms_service_registration_technology (output, &service_sms_technology, NULL))
g_print ("\t\tTechnology: '%s'\n", qmi_imsa_registration_technology_get_string (service_sms_technology));
g_print ("\tVoice service\n");
if (qmi_message_imsa_get_ims_services_status_output_get_ims_voice_service_status (output, &service_voice_status, NULL))
g_print ("\t\t Status: '%s'\n", qmi_imsa_service_status_get_string (service_voice_status));
if (qmi_message_imsa_get_ims_services_status_output_get_ims_voice_service_registration_technology (output, &service_voice_technology, NULL))
g_print ("\t\tTechnology: '%s'\n", qmi_imsa_registration_technology_get_string (service_voice_technology));
g_print ("\tVideo Telephony service\n");
if (qmi_message_imsa_get_ims_services_status_output_get_ims_video_telephony_service_status (output, &service_vt_status, NULL))
g_print ("\t\t Status: '%s'\n", qmi_imsa_service_status_get_string (service_vt_status));
if (qmi_message_imsa_get_ims_services_status_output_get_ims_video_telephony_service_registration_technology (output, &service_vt_technology, NULL))
g_print ("\t\tTechnology: '%s'\n", qmi_imsa_registration_technology_get_string (service_vt_technology));
g_print ("\tUE to TAS service\n");
if (qmi_message_imsa_get_ims_services_status_output_get_ims_ue_to_tas_service_status (output, &service_ut_status, NULL))
g_print ("\t\t Status: '%s'\n", qmi_imsa_service_status_get_string (service_ut_status));
if (qmi_message_imsa_get_ims_services_status_output_get_ims_ue_to_tas_service_registration_technology (output, &service_ut_technology, NULL))
g_print ("\t\tTechnology: '%s'\n", qmi_imsa_registration_technology_get_string (service_ut_technology));
g_print ("\tVideo Share service\n");
if (qmi_message_imsa_get_ims_services_status_output_get_ims_video_share_service_status (output, &service_vs_status, NULL))
g_print ("\t\t Status: '%s'\n", qmi_imsa_service_status_get_string (service_vs_status));
if (qmi_message_imsa_get_ims_services_status_output_get_ims_video_share_service_registration_technology (output, &service_vs_technology, NULL))
g_print ("\t\tTechnology: '%s'\n", qmi_imsa_registration_technology_get_string (service_vs_technology));
qmi_message_imsa_get_ims_services_status_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_IMSA_GET_IMS_SERVICES_STATUS */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_imsa_run (QmiDevice *device,
QmiClientImsa *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_IMSA_BIND
if (bind_flag >= 0) {
QmiMessageImsaBindInput *input;
input = qmi_message_imsa_bind_input_new ();
qmi_message_imsa_bind_input_set_binding (input, bind_flag, NULL);
g_debug ("Asynchronously binding to IMSA service...");
qmi_client_imsa_bind (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)bind_ready,
NULL);
qmi_message_imsa_bind_input_unref (input);
return;
}
#endif /* HAVE_QMI_MESSAGE_IMSA_BIND */
#if defined HAVE_QMI_MESSAGE_IMSA_GET_IMS_REGISTRATION_STATUS
if (get_ims_registration_status_flag) {
g_debug ("Asynchronously getting IMS registration status...");
qmi_client_imsa_get_ims_registration_status (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_ims_registration_status_ready,
NULL);
return;
}
#endif /* HAVE_QMI_MESSAGE_IMSA_GET_IMS_REGISTRATION_STATUS */
#if defined HAVE_QMI_MESSAGE_IMSA_GET_IMS_SERVICES_STATUS
if (get_ims_services_status_flag) {
g_debug ("Asynchronously getting IMS services status...");
qmi_client_imsa_get_ims_services_status (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_ims_services_status_ready,
NULL);
return;
}
#endif /* HAVE_QMI_MESSAGE_IMSA_GET_IMS_SERVICES_STATUS */
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_IMSA */

205
pkgs/qmi-nmea/qmicli-imsp.c Normal file
View File

@ -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 */

View File

@ -0,0 +1,386 @@
/* -*- 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) 2021 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
/* Options */
static gchar *link_list_str;
static gchar *link_add_str;
static gchar *link_delete_str;
static gchar *link_delete_all_str;
static GOptionEntry entries[] = {
{ "link-list", 0, 0, G_OPTION_ARG_STRING, &link_list_str,
"List links created from a given interface",
"[IFACE]"
},
{ "link-add", 0, 0, G_OPTION_ARG_STRING, &link_add_str,
"Create new network interface link",
"[iface=IFACE,prefix=PREFIX[,mux-id=N][,flags=FLAGS]]"
},
{ "link-delete", 0, 0, G_OPTION_ARG_STRING, &link_delete_str,
"Delete a given network interface link",
"[link-iface=IFACE][,[mux-id=N]]"
},
{ "link-delete-all", 0, 0, G_OPTION_ARG_STRING, &link_delete_all_str,
"Delete all network interface links from the given interface",
"[IFACE]"
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_link_management_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("link-management",
"Link management options:",
"Show link management specific options",
NULL, NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_link_management_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (!!link_list_str +
!!link_add_str +
!!link_delete_str +
!!link_delete_all_str);
if (n_actions > 1) {
g_printerr ("error: too many link management actions requested\n");
exit (EXIT_FAILURE);
}
checked = TRUE;
return !!n_actions;
}
/******************************************************************************/
static void
link_delete_all_ready (QmiDevice *dev,
GAsyncResult *res)
{
g_autoptr(GError) error = NULL;
if (!qmi_device_delete_all_links_finish (dev, res, &error))
g_printerr ("error: couldn't delete all links: %s\n", error->message);
else
g_print ("[%s] all links successfully deleted\n",
qmi_device_get_path_display (dev));
qmicli_async_operation_done (!error, FALSE);
}
static void
device_link_delete_all (QmiDevice *dev,
GCancellable *cancellable,
const gchar *iface)
{
qmi_device_delete_all_links (dev,
iface,
cancellable,
(GAsyncReadyCallback)link_delete_all_ready,
NULL);
}
typedef struct {
guint mux_id;
gchar *link_iface;
} DeleteLinkProperties;
static void
link_delete_ready (QmiDevice *dev,
GAsyncResult *res)
{
g_autoptr(GError) error = NULL;
if (!qmi_device_delete_link_finish (dev, res, &error))
g_printerr ("error: couldn't delete link: %s\n",
error->message);
else
g_print ("[%s] link successfully deleted\n",
qmi_device_get_path_display (dev));
qmicli_async_operation_done (!error, FALSE);
}
static gboolean
del_link_properties_handle (const gchar *key,
const gchar *value,
GError **error,
DeleteLinkProperties *props)
{
if (g_ascii_strcasecmp (key, "mux-id") == 0 && props->mux_id == QMI_DEVICE_MUX_ID_UNBOUND) {
if (!qmicli_read_uint_from_string (value, &props->mux_id)) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"invalid mux-id given: '%s'", value);
return FALSE;
}
return TRUE;
}
if (g_ascii_strcasecmp (key, "link-iface") == 0 && !props->link_iface) {
props->link_iface = g_strdup (value);
return TRUE;
}
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"unrecognized or duplicate option '%s'", key);
return FALSE;
}
static void
device_link_delete (QmiDevice *dev,
GCancellable *cancellable,
const gchar *del_settings)
{
g_autoptr(GError) error = NULL;
DeleteLinkProperties props = {
.mux_id = QMI_DEVICE_MUX_ID_UNBOUND,
.link_iface = NULL,
};
if (!qmicli_parse_key_value_string (del_settings,
&error,
(QmiParseKeyValueForeachFn)del_link_properties_handle,
&props)) {
g_printerr ("error: couldn't parse input add link settings: %s\n",
error->message);
qmicli_async_operation_done (FALSE, FALSE);
return;
}
if (!props.link_iface) {
g_printerr ("error: missing mandatory 'link-iface' setting\n");
qmicli_async_operation_done (FALSE, FALSE);
return;
}
if ((props.mux_id != QMI_DEVICE_MUX_ID_UNBOUND) &&
(props.mux_id < QMI_DEVICE_MUX_ID_MIN || props.mux_id > QMI_DEVICE_MUX_ID_MAX)) {
g_printerr ("error: mux id %u out of range [%u,%u]\n",
props.mux_id, QMI_DEVICE_MUX_ID_MIN, QMI_DEVICE_MUX_ID_MAX);
qmicli_async_operation_done (FALSE, FALSE);
return;
}
qmi_device_delete_link (dev,
props.link_iface,
props.mux_id,
cancellable,
(GAsyncReadyCallback)link_delete_ready,
NULL);
g_free (props.link_iface);
}
typedef struct {
guint mux_id;
gchar *iface;
gchar *prefix;
QmiDeviceAddLinkFlags flags;
} AddLinkProperties;
static void
link_add_ready (QmiDevice *dev,
GAsyncResult *res)
{
g_autoptr(GError) error = NULL;
g_autofree gchar *link_iface = NULL;
guint mux_id;
link_iface = qmi_device_add_link_with_flags_finish (dev, res, &mux_id, &error);
if (!link_iface)
g_printerr ("error: couldn't add link: %s\n",
error->message);
else
g_print ("[%s] link successfully added:\n"
" iface name: %s\n"
" mux-id: %u\n",
qmi_device_get_path_display (dev),
link_iface,
mux_id);
qmicli_async_operation_done (!error, FALSE);
}
static gboolean
add_link_properties_handle (const gchar *key,
const gchar *value,
GError **error,
AddLinkProperties *props)
{
if (g_ascii_strcasecmp (key, "mux-id") == 0 && props->mux_id == QMI_DEVICE_MUX_ID_AUTOMATIC) {
if (!qmicli_read_uint_from_string (value, &props->mux_id)) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"invalid mux-id given: '%s'", value);
return FALSE;
}
return TRUE;
}
if (g_ascii_strcasecmp (key, "iface") == 0 && !props->iface) {
props->iface = g_strdup (value);
return TRUE;
}
if (g_ascii_strcasecmp (key, "prefix") == 0 && !props->prefix) {
props->prefix = g_strdup (value);
return TRUE;
}
if (g_ascii_strcasecmp (key, "flags") == 0 && !props->flags) {
if (!qmicli_read_device_add_link_flags_from_string (value, &props->flags)) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"invalid flags given: '%s'", value);
return FALSE;
}
return TRUE;
}
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
"unrecognized or duplicate option '%s'", key);
return FALSE;
}
static void
device_link_add (QmiDevice *dev,
GCancellable *cancellable,
const gchar *add_settings)
{
g_autoptr(GError) error = NULL;
AddLinkProperties props = {
.mux_id = QMI_DEVICE_MUX_ID_AUTOMATIC,
.iface = NULL,
.prefix = NULL,
.flags = QMI_DEVICE_ADD_LINK_FLAGS_NONE,
};
if (!qmicli_parse_key_value_string (add_settings,
&error,
(QmiParseKeyValueForeachFn)add_link_properties_handle,
&props)) {
g_printerr ("error: couldn't parse input add link settings: %s\n",
error->message);
qmicli_async_operation_done (FALSE, FALSE);
return;
}
if (!props.iface) {
g_printerr ("error: missing mandatory 'iface' setting\n");
qmicli_async_operation_done (FALSE, FALSE);
return;
}
if (!props.prefix)
props.prefix = g_strdup_printf ("%s.", props.iface);
if ((props.mux_id != QMI_DEVICE_MUX_ID_AUTOMATIC) &&
(props.mux_id < QMI_DEVICE_MUX_ID_MIN || props.mux_id > QMI_DEVICE_MUX_ID_MAX)) {
g_printerr ("error: mux id %u out of range [%u,%u]\n",
props.mux_id, QMI_DEVICE_MUX_ID_MIN, QMI_DEVICE_MUX_ID_MAX);
qmicli_async_operation_done (FALSE, FALSE);
return;
}
qmi_device_add_link_with_flags (dev,
props.mux_id,
props.iface,
props.prefix,
props.flags,
cancellable,
(GAsyncReadyCallback)link_add_ready,
NULL);
g_free (props.iface);
g_free (props.prefix);
}
static void
device_link_list (QmiDevice *dev,
GCancellable *cancellable,
const gchar *iface)
{
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) links = NULL;
if (!qmi_device_list_links (dev, iface, &links, &error))
g_printerr ("error: couldn't list links: %s\n", error->message);
else {
guint i;
guint n_links;
n_links = (links ? links->len : 0);
g_print ("[%s] found %u links%s\n",
qmi_device_get_path_display (dev),
n_links,
n_links > 0 ? ":" : "");
for (i = 0; i < n_links; i++)
g_print (" [%u] %s\n", i, (const gchar *) g_ptr_array_index (links, i));
}
qmicli_async_operation_done (!error, FALSE);
}
/******************************************************************************/
/* Common */
void
qmicli_link_management_run (QmiDevice *dev,
GCancellable *cancellable)
{
if (link_list_str)
device_link_list (dev, cancellable, link_list_str);
else if (link_add_str)
device_link_add (dev, cancellable, link_add_str);
else if (link_delete_str)
device_link_delete (dev, cancellable, link_delete_str);
else if (link_delete_all_str)
device_link_delete_all (dev, cancellable, link_delete_all_str);
else
g_warn_if_reached ();
}

1593
pkgs/qmi-nmea/qmicli-loc.c Normal file

File diff suppressed because it is too large Load Diff

4790
pkgs/qmi-nmea/qmicli-nas.c Normal file

File diff suppressed because it is too large Load Diff

349
pkgs/qmi-nmea/qmicli-pbm.c Normal file
View File

@ -0,0 +1,349 @@
/* -*- 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) 2013-2017 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#if defined HAVE_QMI_SERVICE_PBM
#undef VALIDATE_MASK_NONE
#define VALIDATE_MASK_NONE(str) (str ? str : "none")
/* Context */
typedef struct {
QmiDevice *device;
QmiClientPbm *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gboolean get_all_capabilities_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_PBM_GET_ALL_CAPABILITIES
{ "pbm-get-all-capabilities", 0, 0, G_OPTION_ARG_NONE, &get_all_capabilities_flag,
"Get all phonebook capabilities",
NULL
},
#endif
{ "pbm-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a PBM client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_pbm_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("pbm",
"PBM options:",
"Show Phonebook Management options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_pbm_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (get_all_capabilities_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many PBM actions requested\n");
exit (EXIT_FAILURE);
}
checked = TRUE;
return !!n_actions;
}
static void
context_free (Context *context)
{
if (!context)
return;
if (context->client)
g_object_unref (context->client);
g_object_unref (context->cancellable);
g_object_unref (context->device);
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_PBM_GET_ALL_CAPABILITIES
static void
get_all_capabilities_ready (QmiClientPbm *client,
GAsyncResult *res)
{
GError *error = NULL;
QmiMessagePbmGetAllCapabilitiesOutput *output;
GArray *capability_basic_information = NULL;
GArray *group_capability = NULL;
GArray *additional_number_capability = NULL;
GArray *email_capability = NULL;
GArray *second_name_capability = NULL;
GArray *hidden_records_capability = NULL;
GArray *grouping_information_alpha_string_capability = NULL;
GArray *additional_number_alpha_string_capability = NULL;
guint i, j;
output = qmi_client_pbm_get_all_capabilities_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_pbm_get_all_capabilities_output_get_result (output, &error)) {
g_printerr ("error: couldn't get capabilities: %s\n", error->message);
g_error_free (error);
qmi_message_pbm_get_all_capabilities_output_unref (output);
operation_shutdown (FALSE);
return;
}
qmi_message_pbm_get_all_capabilities_output_get_capability_basic_information (output, &capability_basic_information, NULL);
qmi_message_pbm_get_all_capabilities_output_get_group_capability (output, &group_capability, NULL);
qmi_message_pbm_get_all_capabilities_output_get_additional_number_capability (output, &additional_number_capability, NULL);
qmi_message_pbm_get_all_capabilities_output_get_email_capability (output, &email_capability, NULL);
qmi_message_pbm_get_all_capabilities_output_get_second_name_capability (output, &second_name_capability, NULL);
qmi_message_pbm_get_all_capabilities_output_get_hidden_records_capability (output, &hidden_records_capability, NULL);
qmi_message_pbm_get_all_capabilities_output_get_grouping_information_alpha_string_capability (output, &grouping_information_alpha_string_capability, NULL);
qmi_message_pbm_get_all_capabilities_output_get_additional_number_alpha_string_capability (output, &additional_number_alpha_string_capability, NULL);
g_print ("[%s] Phonebook capabilities:%s\n",
qmi_device_get_path_display (ctx->device),
(capability_basic_information ||
group_capability ||
additional_number_capability ||
email_capability ||
second_name_capability ||
hidden_records_capability ||
grouping_information_alpha_string_capability ||
additional_number_alpha_string_capability) ? "" : " none");
if (capability_basic_information) {
g_print ("Capability basic information:\n");
for (i = 0; i < capability_basic_information->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputCapabilityBasicInformationElement *session;
session = &g_array_index (capability_basic_information,
QmiMessagePbmGetAllCapabilitiesOutputCapabilityBasicInformationElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
for (j = 0; j < session->phonebooks->len; j++) {
QmiMessagePbmGetAllCapabilitiesOutputCapabilityBasicInformationElementPhonebooksElement *phonebook;
g_autofree gchar *phonebook_type_str = NULL;
phonebook = &g_array_index (session->phonebooks,
QmiMessagePbmGetAllCapabilitiesOutputCapabilityBasicInformationElementPhonebooksElement,
j);
phonebook_type_str = qmi_pbm_phonebook_type_build_string_from_mask (phonebook->phonebook_type);
g_print ("\t\t[%s]:\n", VALIDATE_MASK_NONE (phonebook_type_str));
g_print ("\t\t\tUsed records: %" G_GUINT16_FORMAT "\n", phonebook->used_records);
g_print ("\t\t\tMaximum records: %" G_GUINT16_FORMAT "\n", phonebook->maximum_records);
g_print ("\t\t\tMaximum number length: %u\n", phonebook->maximum_number_length);
g_print ("\t\t\tMaximum name length: %u\n", phonebook->maximum_name_length);
}
}
}
if (group_capability) {
g_print ("Group capability:\n");
for (i = 0; i < group_capability->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputGroupCapabilityElement *session;
session = &g_array_index (group_capability,
QmiMessagePbmGetAllCapabilitiesOutputGroupCapabilityElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
g_print ("\t\tMaximum groups: %u\n", session->maximum_groups);
g_print ("\t\tMaximum group tag length: %u\n", session->maximum_group_tag_length);
}
}
if (additional_number_capability) {
g_print ("Additional number capability:\n");
for (i = 0; i < additional_number_capability->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputAdditionalNumberCapabilityElement *session;
session = &g_array_index (additional_number_capability,
QmiMessagePbmGetAllCapabilitiesOutputAdditionalNumberCapabilityElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
g_print ("\t\tMaximum additional numbers: %u\n", session->maximum_additional_numbers);
g_print ("\t\tMaximum additional number length: %u\n", session->maximum_additional_number_length);
g_print ("\t\tMaximum additional number tag length: %u\n", session->maximum_additional_number_tag_length);
}
}
if (email_capability) {
g_print ("Email capability:\n");
for (i = 0; i < email_capability->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputEmailCapabilityElement *session;
session = &g_array_index (email_capability,
QmiMessagePbmGetAllCapabilitiesOutputEmailCapabilityElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
g_print ("\t\tMaximum emails: %u\n", session->maximum_emails);
g_print ("\t\tMaximum email address length: %u\n", session->maximum_email_address_length);
}
}
if (second_name_capability) {
g_print ("Second name capability:\n");
for (i = 0; i < second_name_capability->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputSecondNameCapabilityElement *session;
session = &g_array_index (second_name_capability,
QmiMessagePbmGetAllCapabilitiesOutputSecondNameCapabilityElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
g_print ("\t\tMaximum second name length: %u\n", session->maximum_second_name_length);
}
}
if (hidden_records_capability) {
g_print ("Hidden records capability:\n");
for (i = 0; i < hidden_records_capability->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputHiddenRecordsCapabilityElement *session;
session = &g_array_index (hidden_records_capability,
QmiMessagePbmGetAllCapabilitiesOutputHiddenRecordsCapabilityElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
g_print ("\t\tSupported: %s\n", session->supported ? "yes" : "no");
}
}
if (grouping_information_alpha_string_capability) {
g_print ("Alpha string capability:\n");
for (i = 0; i < grouping_information_alpha_string_capability->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputGroupingInformationAlphaStringCapabilityElement *session;
session = &g_array_index (grouping_information_alpha_string_capability,
QmiMessagePbmGetAllCapabilitiesOutputGroupingInformationAlphaStringCapabilityElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
g_print ("\t\tMaximum records: %u\n", session->maximum_records);
g_print ("\t\tUsed records: %u\n", session->used_records);
g_print ("\t\tMaximum string length: %u\n", session->maximum_string_length);
}
}
if (additional_number_alpha_string_capability) {
g_print ("Additional number alpha string capability:\n");
for (i = 0; i < additional_number_alpha_string_capability->len; i++) {
QmiMessagePbmGetAllCapabilitiesOutputAdditionalNumberAlphaStringCapabilityElement *session;
session = &g_array_index (additional_number_alpha_string_capability,
QmiMessagePbmGetAllCapabilitiesOutputAdditionalNumberAlphaStringCapabilityElement,
i);
g_print ("\t[%s]:\n", qmi_pbm_session_type_get_string (session->session_type));
g_print ("\t\tMaximum records: %u\n", session->maximum_records);
g_print ("\t\tUsed records: %u\n", session->used_records);
g_print ("\t\tMaximum string length: %u\n", session->maximum_string_length);
}
}
qmi_message_pbm_get_all_capabilities_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_PBM_GET_ALL_CAPABILITIES */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_pbm_run (QmiDevice *device,
QmiClientPbm *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_PBM_GET_ALL_CAPABILITIES
if (get_all_capabilities_flag) {
g_debug ("Asynchronously getting phonebook capabilities...");
qmi_client_pbm_get_all_capabilities (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_all_capabilities_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_PBM */

1475
pkgs/qmi-nmea/qmicli-pdc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
/* -*- 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) 2021 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
/* Options */
static gboolean get_wwan_iface_flag;
static gboolean get_expected_data_format_flag;
static gchar *set_expected_data_format_str;
static GOptionEntry entries[] = {
{ "get-wwan-iface", 'w', 0, G_OPTION_ARG_NONE, &get_wwan_iface_flag,
"Get the associated WWAN iface name",
NULL
},
{ "get-expected-data-format", 'e', 0, G_OPTION_ARG_NONE, &get_expected_data_format_flag,
"Get the expected data format in the WWAN iface",
NULL
},
{ "set-expected-data-format", 'E', 0, G_OPTION_ARG_STRING, &set_expected_data_format_str,
"Set the expected data format in the WWAN iface",
"[802-3|raw-ip|qmap-pass-through]"
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_qmiwwan_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("qmiwwan",
"qmi_wwan specific options:",
"Show qmi_wwan driver specific options", NULL, NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_qmiwwan_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (get_wwan_iface_flag +
get_expected_data_format_flag +
!!set_expected_data_format_str);
if (n_actions > 1) {
g_printerr ("error: too many qmi_wwan specific actions requested\n");
exit (EXIT_FAILURE);
}
checked = TRUE;
return !!n_actions;
}
/******************************************************************************/
static gboolean
device_set_expected_data_format_cb (QmiDevice *dev)
{
QmiDeviceExpectedDataFormat expected;
GError *error = NULL;
if (!qmicli_read_device_expected_data_format_from_string (set_expected_data_format_str, &expected) ||
expected == QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN)
g_printerr ("error: invalid requested data format: %s", set_expected_data_format_str);
else if (!qmi_device_set_expected_data_format (dev, expected, &error)) {
g_printerr ("error: cannot set expected data format: %s\n", error->message);
g_error_free (error);
} else
g_print ("[%s] expected data format set to: %s\n",
qmi_device_get_path_display (dev),
qmi_device_expected_data_format_get_string (expected));
/* We're done now */
qmicli_async_operation_done (!error, FALSE);
g_object_unref (dev);
return FALSE;
}
static void
device_set_expected_data_format (QmiDevice *dev)
{
g_debug ("Setting expected WWAN data format this control port...");
g_idle_add ((GSourceFunc) device_set_expected_data_format_cb, g_object_ref (dev));
}
static gboolean
device_get_expected_data_format_cb (QmiDevice *dev)
{
QmiDeviceExpectedDataFormat expected;
GError *error = NULL;
expected = qmi_device_get_expected_data_format (dev, &error);
if (expected == QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN) {
g_printerr ("error: cannot get expected data format: %s\n", error->message);
g_error_free (error);
} else
g_print ("%s\n", qmi_device_expected_data_format_get_string (expected));
/* We're done now */
qmicli_async_operation_done (!error, FALSE);
g_object_unref (dev);
return FALSE;
}
static void
device_get_expected_data_format (QmiDevice *dev)
{
g_debug ("Getting expected WWAN data format this control port...");
g_idle_add ((GSourceFunc) device_get_expected_data_format_cb, g_object_ref (dev));
}
static gboolean
device_get_wwan_iface_cb (QmiDevice *dev)
{
const gchar *wwan_iface;
wwan_iface = qmi_device_get_wwan_iface (dev);
if (!wwan_iface)
g_printerr ("error: cannot get WWAN interface name\n");
else
g_print ("%s\n", wwan_iface);
/* We're done now */
qmicli_async_operation_done (!!wwan_iface, FALSE);
g_object_unref (dev);
return FALSE;
}
static void
device_get_wwan_iface (QmiDevice *dev)
{
g_debug ("Getting WWAN iface for this control port...");
g_idle_add ((GSourceFunc) device_get_wwan_iface_cb, g_object_ref (dev));
}
/******************************************************************************/
/* Common */
void
qmicli_qmiwwan_run (QmiDevice *device,
GCancellable *cancellable)
{
if (get_wwan_iface_flag)
device_get_wwan_iface (device);
else if (get_expected_data_format_flag)
device_get_expected_data_format (device);
else if (set_expected_data_format_str)
device_set_expected_data_format (device);
else
g_warn_if_reached ();
}

430
pkgs/qmi-nmea/qmicli-qos.c Normal file
View File

@ -0,0 +1,430 @@
/* -*- 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) 2018 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
#if defined HAVE_QMI_SERVICE_QOS
#undef VALIDATE_UNKNOWN
#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
/* Context */
typedef struct {
QmiDevice *device;
QmiClientQos *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gint get_flow_status_int = -1;
static gboolean get_network_status_flag;
static gint swi_read_data_stats_int = -1;
static gboolean reset_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_QOS_GET_FLOW_STATUS
{ "qos-get-flow-status", 0, 0, G_OPTION_ARG_INT, &get_flow_status_int,
"Get QoS flow status",
"[QoS ID]"
},
#endif
#if defined HAVE_QMI_MESSAGE_QOS_GET_NETWORK_STATUS
{ "qos-get-network-status", 0, 0, G_OPTION_ARG_NONE, &get_network_status_flag,
"Gets the network status",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_QOS_SWI_READ_DATA_STATS
{ "qos-swi-read-data-stats", 0, 0, G_OPTION_ARG_INT, &swi_read_data_stats_int,
"Read data stats (Sierra Wireless specific)",
"[APN ID]"
},
#endif
#if defined HAVE_QMI_MESSAGE_QOS_RESET
{ "qos-reset", 0, 0, G_OPTION_ARG_NONE, &reset_flag,
"Reset the service state",
NULL
},
#endif
{ "qos-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a QOS client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_qos_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("qos",
"QoS options:",
"Show Quality of Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_qos_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = ((get_flow_status_int >= 0) +
get_network_status_flag +
(swi_read_data_stats_int >= 0) +
reset_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many QoS 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_QOS_GET_FLOW_STATUS
static void
get_flow_status_ready (QmiClientQos *client,
GAsyncResult *res)
{
QmiMessageQosGetFlowStatusOutput *output;
GError *error = NULL;
QmiQosStatus flow_status;
output = qmi_client_qos_get_flow_status_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_qos_get_flow_status_output_get_result (output, &error)) {
g_printerr ("error: couldn't get QoS flow status: %s\n", error->message);
g_error_free (error);
qmi_message_qos_get_flow_status_output_unref (output);
operation_shutdown (FALSE);
return;
}
qmi_message_qos_get_flow_status_output_get_value (output, &flow_status, NULL);
g_print ("[%s] QoS flow status: %s\n",
qmi_device_get_path_display (ctx->device),
qmi_qos_status_get_string (flow_status));
qmi_message_qos_get_flow_status_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_QOS_GET_FLOW_STATUS */
#if defined HAVE_QMI_MESSAGE_QOS_GET_NETWORK_STATUS
static void
get_network_status_ready (QmiClientQos *client,
GAsyncResult *res)
{
QmiMessageQosGetNetworkStatusOutput *output;
GError *error = NULL;
gboolean qos_supported;
output = qmi_client_qos_get_network_status_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_qos_get_network_status_output_get_result (output, &error)) {
g_printerr ("error: couldn't get network status: %s\n", error->message);
g_error_free (error);
qmi_message_qos_get_network_status_output_unref (output);
operation_shutdown (FALSE);
return;
}
qmi_message_qos_get_network_status_output_get_qos_supported (output, &qos_supported, NULL);
g_print ("[%s] QoS %ssupported in network\n",
qmi_device_get_path_display (ctx->device),
qos_supported ? "" : "not ");
qmi_message_qos_get_network_status_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_QOS_GET_NETWORK_STATUS */
#if defined HAVE_QMI_MESSAGE_QOS_SWI_READ_DATA_STATS
static void
swi_read_data_stats_ready (QmiClientQos *client,
GAsyncResult *res)
{
QmiMessageQosSwiReadDataStatsOutput *output;
GError *error = NULL;
guint32 apn_id = 0;
guint32 apn_tx_packets = 0;
guint32 apn_tx_packets_dropped = 0;
guint32 apn_rx_packets = 0;
guint64 apn_tx_bytes = 0;
guint64 apn_tx_bytes_dropped = 0;
guint64 apn_rx_bytes = 0;
GArray *flow = NULL;
output = qmi_client_qos_swi_read_data_stats_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_qos_swi_read_data_stats_output_get_result (output, &error)) {
g_printerr ("error: couldn't read data stats: %s\n", error->message);
g_error_free (error);
qmi_message_qos_swi_read_data_stats_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] QoS data stats read\n",
qmi_device_get_path_display (ctx->device));
if (qmi_message_qos_swi_read_data_stats_output_get_apn (
output,
&apn_id,
&apn_tx_packets,
&apn_tx_packets_dropped,
&apn_rx_packets,
&apn_tx_bytes,
&apn_tx_bytes_dropped,
&apn_rx_bytes,
NULL)) {
g_print (" APN ID: %u\n", apn_id);
g_print (" TX packets: %u\n", apn_tx_packets);
g_print (" TX packets dropped: %u\n", apn_tx_packets_dropped);
g_print (" RX packets: %u\n", apn_rx_packets);
g_print (" TX bytes: %" G_GUINT64_FORMAT "\n", apn_tx_bytes);
g_print (" TX bytes dropped: %" G_GUINT64_FORMAT "\n", apn_tx_bytes_dropped);
g_print (" RX bytes: %" G_GUINT64_FORMAT "\n", apn_rx_bytes);
}
if (qmi_message_qos_swi_read_data_stats_output_get_flow (
output,
&flow,
NULL)) {
guint i;
for (i = 0; i < flow->len; i++) {
QmiMessageQosSwiReadDataStatsOutputFlowElement *element;
element = &g_array_index(flow, QmiMessageQosSwiReadDataStatsOutputFlowElement, i);
g_print (" Flow %u\n", i);
g_print (" Bearer ID: %u\n", element->bearer_id);
g_print (" TX packets: %u\n", element->tx_packets);
g_print (" TX packets dropped: %u\n", element->tx_packets_dropped);
g_print (" TX bytes: %" G_GUINT64_FORMAT "\n", element->tx_bytes);
g_print (" TX bytes dropped: %" G_GUINT64_FORMAT "\n", element->tx_bytes_dropped);
}
}
qmi_message_qos_swi_read_data_stats_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_QOS_SWI_READ_DATA_STATS */
#if defined HAVE_QMI_MESSAGE_QOS_RESET
static void
reset_ready (QmiClientQos *client,
GAsyncResult *res)
{
QmiMessageQosResetOutput *output;
GError *error = NULL;
output = qmi_client_qos_reset_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_qos_reset_output_get_result (output, &error)) {
g_printerr ("error: couldn't reset the QoS service: %s\n", error->message);
g_error_free (error);
qmi_message_qos_reset_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully performed QoS service reset\n",
qmi_device_get_path_display (ctx->device));
qmi_message_qos_reset_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_QOS_RESET */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_qos_run (QmiDevice *device,
QmiClientQos *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_QOS_GET_FLOW_STATUS
if (get_flow_status_int >= 0) {
QmiMessageQosGetFlowStatusInput *input;
input = qmi_message_qos_get_flow_status_input_new ();
qmi_message_qos_get_flow_status_input_set_qos_id (input, get_flow_status_int, NULL);
g_debug ("Asynchronously getting QoS flow status...");
qmi_client_qos_get_flow_status (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_flow_status_ready,
NULL);
qmi_message_qos_get_flow_status_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_QOS_GET_NETWORK_STATUS
if (get_network_status_flag) {
g_debug ("Asynchronously getting network status...");
qmi_client_qos_get_network_status (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_network_status_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_QOS_SWI_READ_DATA_STATS
if (swi_read_data_stats_int >= 0) {
QmiMessageQosSwiReadDataStatsInput *input;
input = qmi_message_qos_swi_read_data_stats_input_new ();
qmi_message_qos_swi_read_data_stats_input_set_apn_id (input, swi_read_data_stats_int, NULL);
g_debug ("Asynchronously reading data stats...");
qmi_client_qos_swi_read_data_stats (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)swi_read_data_stats_ready,
NULL);
qmi_message_qos_swi_read_data_stats_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_QOS_RESET
if (reset_flag) {
g_debug ("Asynchronously resetting QoS service...");
qmi_client_qos_reset (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)reset_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_QOS */

295
pkgs/qmi-nmea/qmicli-sar.c Normal file
View File

@ -0,0 +1,295 @@
/* -*- 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) 2020 Google Inc.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
#if defined HAVE_QMI_SERVICE_SAR
/* Context */
typedef struct {
QmiDevice *device;
QmiClientSar *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gchar *rf_set_state_str;
static gboolean rf_get_state_flag;
static gboolean noop_flag;
#undef VALIDATE_UNKNOWN
#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_SAR_RF_GET_STATE
{ "sar-rf-get-state", 0, 0, G_OPTION_ARG_NONE, &rf_get_state_flag,
"Get RF state",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_SAR_RF_SET_STATE
{ "sar-rf-set-state", 0, 0, G_OPTION_ARG_STRING, &rf_set_state_str,
"Set RF state.",
"[(state number)]"
},
#endif
{ "sar-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a SAR client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_sar_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("sar",
"SAR options:",
"Show Specific Absorption Rate options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_sar_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (!!rf_set_state_str +
rf_get_state_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many SAR actions requested\n");
exit (EXIT_FAILURE);
}
checked = TRUE;
return !!n_actions;
}
static void
context_free (Context *context)
{
if (!context)
return;
if (context->client)
g_object_unref (context->client);
g_object_unref (context->cancellable);
g_object_unref (context->device);
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_SAR_RF_GET_STATE
static void
rf_get_state_ready (QmiClientSar *client,
GAsyncResult *res)
{
QmiMessageSarRfGetStateOutput *output;
GError *error = NULL;
QmiSarRfState rf_state;
output = qmi_client_sar_rf_get_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_sar_rf_get_state_output_get_result (output, &error)) {
g_printerr ("error: couldn't get SAR RF state: %s\n", error->message);
g_error_free (error);
qmi_message_sar_rf_get_state_output_unref (output);
operation_shutdown (FALSE);
return;
}
qmi_message_sar_rf_get_state_output_get_state (output, &rf_state, NULL);
g_print ("[%s] Successfully got SAR RF state: %s\n",
qmi_device_get_path_display (ctx->device),
qmi_sar_rf_state_get_string (rf_state));
qmi_message_sar_rf_get_state_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_SAR_RF_GET_STATE */
#if defined HAVE_QMI_MESSAGE_SAR_RF_SET_STATE
static QmiMessageSarRfSetStateInput *
rf_set_state_input_create (const gchar *str)
{
QmiMessageSarRfSetStateInput *input = NULL;
QmiSarRfState rf_state;
if (qmicli_read_sar_rf_state_from_string (str, &rf_state)) {
GError *error = NULL;
input = qmi_message_sar_rf_set_state_input_new ();
if (!qmi_message_sar_rf_set_state_input_set_state (
input,
rf_state,
&error)) {
g_printerr ("error: couldn't create input data: '%s'\n",
error->message);
g_error_free (error);
qmi_message_sar_rf_set_state_input_unref (input);
input = NULL;
}
}
return input;
}
static void
rf_set_state_ready (QmiClientSar *client,
GAsyncResult *res)
{
QmiMessageSarRfSetStateOutput *output;
GError *error = NULL;
output = qmi_client_sar_rf_set_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_sar_rf_set_state_output_get_result (output, &error)) {
g_printerr ("error: couldn't set RF state: %s\n", error->message);
g_error_free (error);
qmi_message_sar_rf_set_state_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] RF state set successfully\n",
qmi_device_get_path_display (ctx->device));
qmi_message_sar_rf_set_state_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_SAR_RF_SET_STATE */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_sar_run (QmiDevice *device,
QmiClientSar *client,
GCancellable *cancellable)
{
/* Initialize context */
ctx = g_slice_new0 (Context);
ctx->device = g_object_ref (device);
ctx->client = g_object_ref (client);
ctx->cancellable = g_object_ref (cancellable);
#if defined HAVE_QMI_MESSAGE_SAR_RF_GET_STATE
if (rf_get_state_flag) {
g_debug ("Asynchronously getting RF power state...");
qmi_client_sar_rf_get_state (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback) rf_get_state_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_SAR_RF_SET_STATE
if (rf_set_state_str) {
QmiMessageSarRfSetStateInput *input;
g_debug ("Asynchronously setting RF power state...");
input = rf_set_state_input_create (rf_set_state_str);
if (!input) {
operation_shutdown (FALSE);
return;
}
qmi_client_sar_rf_set_state (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback) rf_set_state_ready,
NULL);
qmi_message_sar_rf_set_state_input_unref (input);
return;
}
#endif /* HAVE_QMI_MESSAGE_SAR_RF_SET_STATE */
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_SAR */

3452
pkgs/qmi-nmea/qmicli-uim.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,379 @@
/* -*- 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) 2014-2017 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
#if defined HAVE_QMI_SERVICE_VOICE
#undef VALIDATE_MASK_NONE
#define VALIDATE_MASK_NONE(str) (str ? str : "none")
/* Context */
typedef struct {
QmiDevice *device;
QmiClientVoice *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gboolean get_config_flag;
static gboolean get_supported_messages_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_VOICE_GET_CONFIG
{ "voice-get-config", 0, 0, G_OPTION_ARG_NONE, &get_config_flag,
"Get Voice service configuration",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_VOICE_GET_SUPPORTED_MESSAGES
{ "voice-get-supported-messages", 0, 0, G_OPTION_ARG_NONE, &get_supported_messages_flag,
"Get supported messages",
NULL
},
#endif
{ "voice-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a VOICE client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_voice_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("voice",
"VOICE options:",
"Show Voice Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_voice_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (get_config_flag +
get_supported_messages_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many VOICE actions requested\n");
exit (EXIT_FAILURE);
}
checked = TRUE;
return !!n_actions;
}
static void
context_free (Context *context)
{
if (!context)
return;
if (context->client)
g_object_unref (context->client);
g_object_unref (context->cancellable);
g_object_unref (context->device);
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_VOICE_GET_CONFIG
static void
get_config_ready (QmiClientVoice *client,
GAsyncResult *res)
{
QmiMessageVoiceGetConfigOutput *output;
GError *error = NULL;
QmiVoiceDomain current_voice_domain_preference;
QmiVoicePrivacy current_voice_privacy_preference;
gboolean current_amr_status_gsm;
QmiVoiceWcdmaAmrStatus current_amr_status_wcdma;
guint8 current_preferred_voice_so_nam_id;
gboolean current_preferred_voice_so_evrc_capability;
QmiVoiceServiceOption current_preferred_voice_so_home_page_voice_service_option;
QmiVoiceServiceOption current_preferred_voice_so_home_origination_voice_service_option;
QmiVoiceServiceOption current_preferred_voice_so_roaming_origination_voice_service_option;
QmiVoiceTtyMode current_tty_mode;
guint8 roam_timer_count_nam_id;
guint32 roam_timer_count_roam_timer;
guint8 air_timer_count_nam_id;
guint32 air_timer_count_air_timer;
gboolean auto_answer_status;
output = qmi_client_voice_get_config_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_voice_get_config_output_get_result (output, &error)) {
g_printerr ("error: couldn't get Voice configuration: %s\n", error->message);
g_error_free (error);
qmi_message_voice_get_config_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully retrieved Voice configuration:\n",
qmi_device_get_path_display (ctx->device));
if (qmi_message_voice_get_config_output_get_auto_answer_status (
output,
&auto_answer_status,
NULL))
g_print ("Auto Answer Status: '%s'",
auto_answer_status ? "enabled" : "disabled");
if (qmi_message_voice_get_config_output_get_air_timer_count (
output,
&air_timer_count_nam_id,
&air_timer_count_air_timer,
NULL))
g_print ("Air Timer Count:\n"
"\tNAM ID: '%u'"
"\tTimer: '%u'",
air_timer_count_nam_id,
air_timer_count_air_timer);
if (qmi_message_voice_get_config_output_get_roam_timer_count (
output,
&roam_timer_count_nam_id,
&roam_timer_count_roam_timer,
NULL))
g_print ("Roam Timer Count:\n"
"\tNAM ID: '%u'"
"\tTimer: '%u'",
roam_timer_count_nam_id,
roam_timer_count_roam_timer);
if (qmi_message_voice_get_config_output_get_current_tty_mode (
output,
&current_tty_mode,
NULL))
g_print ("Current TTY mode: '%s'",
qmi_voice_tty_mode_get_string (current_tty_mode));
if (qmi_message_voice_get_config_output_get_current_preferred_voice_so (
output,
&current_preferred_voice_so_nam_id,
&current_preferred_voice_so_evrc_capability,
&current_preferred_voice_so_home_page_voice_service_option,
&current_preferred_voice_so_home_origination_voice_service_option,
&current_preferred_voice_so_roaming_origination_voice_service_option,
NULL)) {
g_print ("Current Preferred Voice SO:\n"
"\tNAM ID: '%u'\n"
"\tEVRC capability: '%s'\n"
"\tHome Page Voice SO: '%s'\n"
"\tHome Origination Voice SO: '%s'\n"
"\tRoaming Origination Voice SO: '%s'\n",
current_preferred_voice_so_nam_id,
current_preferred_voice_so_evrc_capability ? "enabled" : "disabled",
qmi_voice_service_option_get_string (current_preferred_voice_so_home_page_voice_service_option),
qmi_voice_service_option_get_string (current_preferred_voice_so_home_origination_voice_service_option),
qmi_voice_service_option_get_string (current_preferred_voice_so_roaming_origination_voice_service_option));
}
if (qmi_message_voice_get_config_output_get_current_amr_status (
output,
&current_amr_status_gsm, &current_amr_status_wcdma,
NULL)) {
gchar *current_amr_status_wcdma_str;
current_amr_status_wcdma_str = qmi_voice_wcdma_amr_status_build_string_from_mask (current_amr_status_wcdma);
g_print ("AMR Status:\n"
"\tGSM: '%s'\n"
"\tWCDMA: '%s' (0x%04X)\n",
current_amr_status_gsm ? "enabled" : "disabled",
VALIDATE_MASK_NONE (current_amr_status_wcdma_str),
current_amr_status_wcdma);
g_free (current_amr_status_wcdma_str);
}
if (qmi_message_voice_get_config_output_get_current_voice_privacy_preference (
output,
&current_voice_privacy_preference,
NULL))
g_print ("Current Voice Privacy Preference: '%s'\n",
qmi_voice_privacy_get_string (current_voice_privacy_preference));
if (qmi_message_voice_get_config_output_get_current_voice_domain_preference (
output,
&current_voice_domain_preference,
NULL))
g_print ("Current Voice Domain Preference: '%s'\n",
qmi_voice_domain_get_string (current_voice_domain_preference));
qmi_message_voice_get_config_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_VOICE_GET_CONFIG */
#if defined HAVE_QMI_MESSAGE_VOICE_GET_SUPPORTED_MESSAGES
static void
get_supported_messages_ready (QmiClientVoice *client,
GAsyncResult *res)
{
QmiMessageVoiceGetSupportedMessagesOutput *output;
GError *error = NULL;
GArray *bytearray = NULL;
gchar *str;
output = qmi_client_voice_get_supported_messages_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_voice_get_supported_messages_output_get_result (output, &error)) {
g_printerr ("error: couldn't get supported VOICE messages: %s\n", error->message);
g_error_free (error);
qmi_message_voice_get_supported_messages_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully got supported VOICE messages:\n",
qmi_device_get_path_display (ctx->device));
qmi_message_voice_get_supported_messages_output_get_list (output, &bytearray, NULL);
str = qmicli_get_supported_messages_list (bytearray ? (const guint8 *)bytearray->data : NULL,
bytearray ? bytearray->len : 0);
g_print ("%s", str);
g_free (str);
qmi_message_voice_get_supported_messages_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_VOICE_GET_SUPPORTED_MESSAGES */
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_voice_run (QmiDevice *device,
QmiClientVoice *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_VOICE_GET_CONFIG
if (get_config_flag) {
QmiMessageVoiceGetConfigInput *input;
input = qmi_message_voice_get_config_input_new ();
qmi_message_voice_get_config_input_set_auto_answer (input, TRUE, NULL);
qmi_message_voice_get_config_input_set_air_timer (input, TRUE, NULL);
qmi_message_voice_get_config_input_set_roam_timer (input, TRUE, NULL);
qmi_message_voice_get_config_input_set_tty_mode (input, TRUE, NULL);
qmi_message_voice_get_config_input_set_preferred_voice_service_option (input, TRUE, NULL);
qmi_message_voice_get_config_input_set_amr_status (input, TRUE, NULL);
qmi_message_voice_get_config_input_set_preferred_voice_privacy (input, TRUE, NULL);
if (qmi_client_check_version (QMI_CLIENT (ctx->client), 2, 3))
qmi_message_voice_get_config_input_set_nam_index (input, TRUE, NULL);
if (qmi_client_check_version (QMI_CLIENT (ctx->client), 2, 9))
qmi_message_voice_get_config_input_set_voice_domain_preference (input, TRUE, NULL);
g_debug ("Asynchronously getting voice configuration...");
qmi_client_voice_get_config (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_config_ready,
NULL);
qmi_message_voice_get_config_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_VOICE_GET_SUPPORTED_MESSAGES
if (get_supported_messages_flag) {
g_debug ("Asynchronously getting supported voice messages...");
qmi_client_voice_get_supported_messages (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_supported_messages_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_VOICE */

811
pkgs/qmi-nmea/qmicli-wda.c Normal file
View File

@ -0,0 +1,811 @@
/* -*- 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) 2014-2017 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
#if defined HAVE_QMI_SERVICE_WDA
#define QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAMS_UNDEFINED 0xFFFFFFFF
#define QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAM_SIZE_UNDEFINED 0xFFFFFFFF
#define QMI_WDA_ENDPOINT_INTERFACE_NUMBER_UNDEFINED -1
/* Context */
typedef struct {
QmiDevice *device;
QmiClientWda *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gchar *set_data_format_str;
static gchar *get_data_format_str;
static gboolean get_data_format_flag;
static gboolean get_supported_messages_flag;
static gboolean noop_flag;
#if defined HAVE_QMI_MESSAGE_WDA_GET_DATA_FORMAT
static gboolean
parse_get_data_format (const gchar *option_name,
const gchar *value,
gpointer data,
GError **error)
{
get_data_format_flag = TRUE;
if (value && value[0])
get_data_format_str = g_strdup (value);
return TRUE;
}
#endif
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_WDA_SET_DATA_FORMAT
{ "wda-set-data-format", 0, 0, G_OPTION_ARG_STRING, &set_data_format_str,
"Set data format (allowed keys: link-layer-protocol (802-3|raw-ip), ul-protocol (disabled|tlp|qc-ncm|mbim|rndis|qmap|qmapv5), dl-protocol (disabled|tlp|qc-ncm|mbim|rndis|qmap|qmapv5), dl-datagram-max-size, dl-max-datagrams, ep-type (undefined|hsusb|pcie|embedded), ep-iface-number, ul-datagram-max-size, ul-max-datagrams)",
"[\"key=value,...\"]"
},
#endif
#if defined HAVE_QMI_MESSAGE_WDA_GET_DATA_FORMAT
{ "wda-get-data-format", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_get_data_format,
"Get data format (allowed keys: ep-type (undefined|hsusb|pcie|embedded), ep-iface-number); also allows empty key list",
"[\"key=value,...\"]"
},
#endif
#if defined HAVE_QMI_MESSAGE_WDA_GET_SUPPORTED_MESSAGES
{ "wda-get-supported-messages", 0, 0, G_OPTION_ARG_NONE, &get_supported_messages_flag,
"Get supported messages",
NULL
},
#endif
{ "wda-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a WDA client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_wda_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("wda",
"WDA options:",
"Show Wireless Data Administrative options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_wda_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (!!set_data_format_str +
get_data_format_flag +
get_supported_messages_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many WDA actions requested\n");
exit (EXIT_FAILURE);
}
checked = TRUE;
return !!n_actions;
}
static void
context_free (Context *context)
{
if (!context)
return;
if (context->client)
g_object_unref (context->client);
g_object_unref (context->cancellable);
g_object_unref (context->device);
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);
}
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
#if defined HAVE_QMI_MESSAGE_WDA_GET_DATA_FORMAT
typedef struct {
QmiDataEndpointType endpoint_type;
gint endpoint_iface_number;
} GetDataFormatProperties;
static gboolean
get_data_format_properties_handle (const gchar *key,
const gchar *value,
GError **error,
gpointer user_data)
{
GetDataFormatProperties *props = (GetDataFormatProperties *)user_data;
if (!value || !value[0]) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"key '%s' requires a value",
key);
return FALSE;
}
if (g_ascii_strcasecmp (key, "ep-type") == 0) {
if (!qmicli_read_data_endpoint_type_from_string (value, &(props->endpoint_type))) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unrecognized Endpoint Type '%s'",
value);
return FALSE;
}
return TRUE;
}
if (g_ascii_strcasecmp (key, "ep-iface-number") == 0) {
props->endpoint_iface_number = atoi (value);
return TRUE;
}
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unrecognized option '%s'",
key);
return FALSE;
}
static QmiMessageWdaGetDataFormatInput *
get_data_format_input_create (const gchar *str)
{
g_autoptr(QmiMessageWdaGetDataFormatInput) input = NULL;
g_autoptr(GError) error = NULL;
GetDataFormatProperties props = {
.endpoint_type = QMI_DATA_ENDPOINT_TYPE_UNDEFINED,
.endpoint_iface_number = QMI_WDA_ENDPOINT_INTERFACE_NUMBER_UNDEFINED,
};
input = qmi_message_wda_get_data_format_input_new ();
if (!qmicli_parse_key_value_string (str,
&error,
get_data_format_properties_handle,
&props)) {
g_printerr ("error: could not parse input string '%s'\n", error->message);
return NULL;
}
if ((props.endpoint_type == QMI_DATA_ENDPOINT_TYPE_UNDEFINED) ^
(props.endpoint_iface_number == QMI_WDA_ENDPOINT_INTERFACE_NUMBER_UNDEFINED)) {
g_printerr ("error: endpoint type and interface number must be both set or both unset\n");
return NULL;
}
if ((props.endpoint_type != QMI_DATA_ENDPOINT_TYPE_UNDEFINED) &&
(props.endpoint_iface_number != QMI_WDA_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) &&
!qmi_message_wda_get_data_format_input_set_endpoint_info (
input,
props.endpoint_type,
props.endpoint_iface_number,
&error)) {
g_printerr ("error: could not set peripheral endpoint id: %s\n", error->message);
return NULL;
}
return g_steal_pointer (&input);
}
static void
get_data_format_ready (QmiClientWda *client,
GAsyncResult *res)
{
QmiMessageWdaGetDataFormatOutput *output;
GError *error = NULL;
gboolean qos_format;
QmiWdaLinkLayerProtocol link_layer_protocol;
QmiWdaDataAggregationProtocol data_aggregation_protocol;
guint32 ndp_signature;
guint32 data_aggregation_max_size;
guint32 data_aggregation_max_datagrams;
output = qmi_client_wda_get_data_format_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_wda_get_data_format_output_get_result (output, &error)) {
g_printerr ("error: couldn't get data format: %s\n", error->message);
g_error_free (error);
qmi_message_wda_get_data_format_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully got data format\n",
qmi_device_get_path_display (ctx->device));
if (qmi_message_wda_get_data_format_output_get_qos_format (
output,
&qos_format,
NULL))
g_print (" QoS flow header: %s\n", qos_format ? "yes" : "no");
if (qmi_message_wda_get_data_format_output_get_link_layer_protocol (
output,
&link_layer_protocol,
NULL))
g_print (" Link layer protocol: '%s'\n",
qmi_wda_link_layer_protocol_get_string (link_layer_protocol));
if (qmi_message_wda_get_data_format_output_get_uplink_data_aggregation_protocol (
output,
&data_aggregation_protocol,
NULL))
g_print (" Uplink data aggregation protocol: '%s'\n",
qmi_wda_data_aggregation_protocol_get_string (data_aggregation_protocol));
if (qmi_message_wda_get_data_format_output_get_downlink_data_aggregation_protocol (
output,
&data_aggregation_protocol,
NULL))
g_print ("Downlink data aggregation protocol: '%s'\n",
qmi_wda_data_aggregation_protocol_get_string (data_aggregation_protocol));
if (qmi_message_wda_get_data_format_output_get_ndp_signature (
output,
&ndp_signature,
NULL))
g_print (" NDP signature: '%u'\n", ndp_signature);
if (qmi_message_wda_get_data_format_output_get_downlink_data_aggregation_max_datagrams (
output,
&data_aggregation_max_datagrams,
NULL))
g_print ("Downlink data aggregation max datagrams: '%u'\n", data_aggregation_max_datagrams);
if (qmi_message_wda_get_data_format_output_get_downlink_data_aggregation_max_size (
output,
&data_aggregation_max_size,
NULL))
g_print ("Downlink data aggregation max size: '%u'\n", data_aggregation_max_size);
qmi_message_wda_get_data_format_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_WDA_GET_DATA_FORMAT */
#if defined HAVE_QMI_MESSAGE_WDA_SET_DATA_FORMAT
static void
set_data_format_ready (QmiClientWda *client,
GAsyncResult *res)
{
QmiMessageWdaSetDataFormatOutput *output;
GError *error = NULL;
gboolean qos_format;
QmiWdaLinkLayerProtocol link_layer_protocol;
QmiWdaDataAggregationProtocol data_aggregation_protocol;
guint32 ndp_signature;
guint32 dl_data_aggregation_max_datagrams;
guint32 dl_data_aggregation_max_size;
guint32 ul_data_aggregation_max_datagrams;
guint32 ul_data_aggregation_max_size;
output = qmi_client_wda_set_data_format_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_wda_set_data_format_output_get_result (output, &error)) {
g_printerr ("error: couldn't set data format: %s\n", error->message);
g_error_free (error);
qmi_message_wda_set_data_format_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully set data format\n",
qmi_device_get_path_display (ctx->device));
if (qmi_message_wda_set_data_format_output_get_qos_format (
output,
&qos_format,
NULL))
g_print (" QoS flow header: %s\n", qos_format ? "yes" : "no");
if (qmi_message_wda_set_data_format_output_get_link_layer_protocol (
output,
&link_layer_protocol,
NULL))
g_print (" Link layer protocol: '%s'\n",
qmi_wda_link_layer_protocol_get_string (link_layer_protocol));
if (qmi_message_wda_set_data_format_output_get_uplink_data_aggregation_protocol (
output,
&data_aggregation_protocol,
NULL))
g_print (" Uplink data aggregation protocol: '%s'\n",
qmi_wda_data_aggregation_protocol_get_string (data_aggregation_protocol));
if (qmi_message_wda_set_data_format_output_get_downlink_data_aggregation_protocol (
output,
&data_aggregation_protocol,
NULL))
g_print (" Downlink data aggregation protocol: '%s'\n",
qmi_wda_data_aggregation_protocol_get_string (data_aggregation_protocol));
if (qmi_message_wda_set_data_format_output_get_ndp_signature (
output,
&ndp_signature,
NULL))
g_print (" NDP signature: '%u'\n", ndp_signature);
if (qmi_message_wda_set_data_format_output_get_downlink_data_aggregation_max_datagrams (
output,
&dl_data_aggregation_max_datagrams,
NULL))
g_print ("Downlink data aggregation max datagrams: '%u'\n", dl_data_aggregation_max_datagrams);
if (qmi_message_wda_set_data_format_output_get_downlink_data_aggregation_max_size (
output,
&dl_data_aggregation_max_size,
NULL))
g_print (" Downlink data aggregation max size: '%u'\n", dl_data_aggregation_max_size);
if (qmi_message_wda_set_data_format_output_get_uplink_data_aggregation_max_datagrams (
output,
&ul_data_aggregation_max_datagrams,
NULL))
g_print (" Uplink data aggregation max datagrams: '%u'\n", ul_data_aggregation_max_datagrams);
if (qmi_message_wda_set_data_format_output_get_uplink_data_aggregation_max_size (
output,
&ul_data_aggregation_max_size,
NULL))
g_print (" Uplink data aggregation max size: '%u'\n", ul_data_aggregation_max_size);
qmi_message_wda_set_data_format_output_unref (output);
operation_shutdown (TRUE);
}
typedef struct {
QmiWdaLinkLayerProtocol link_layer_protocol;
QmiWdaDataAggregationProtocol ul_protocol;
QmiWdaDataAggregationProtocol dl_protocol;
guint32 dl_datagram_max_size;
guint32 dl_max_datagrams;
QmiDataEndpointType endpoint_type;
gint endpoint_iface_number;
guint32 ul_datagram_max_size;
guint32 ul_max_datagrams;
} SetDataFormatProperties;
static gboolean
set_data_format_properties_handle (const gchar *key,
const gchar *value,
GError **error,
gpointer user_data)
{
SetDataFormatProperties *props = (SetDataFormatProperties *)user_data;
if (!value || !value[0]) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"key '%s' requires a value",
key);
return FALSE;
}
if (g_ascii_strcasecmp (key, "link-layer-protocol") == 0) {
if (!qmicli_read_wda_link_layer_protocol_from_string (value, &(props->link_layer_protocol))) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unrecognized Link Layer Protocol '%s'",
value);
return FALSE;
}
return TRUE;
}
if (g_ascii_strcasecmp (key, "ul-protocol") == 0) {
if (!qmicli_read_wda_data_aggregation_protocol_from_string (value, &(props->ul_protocol))) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unrecognized Data Aggregation Protocol '%s'",
value);
return FALSE;
}
return TRUE;
}
if (g_ascii_strcasecmp (key, "dl-protocol") == 0) {
if (!qmicli_read_wda_data_aggregation_protocol_from_string (value, &(props->dl_protocol))) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unrecognized Data Aggregation Protocol '%s'",
value);
return FALSE;
}
return TRUE;
}
if (g_ascii_strcasecmp (key, "dl-datagram-max-size") == 0) {
props->dl_datagram_max_size = atoi(value);
return TRUE;
}
if (g_ascii_strcasecmp (key, "dl-max-datagrams") == 0) {
props->dl_max_datagrams = atoi(value);
return TRUE;
}
if (g_ascii_strcasecmp (key, "ep-type") == 0) {
if (!qmicli_read_data_endpoint_type_from_string (value, &(props->endpoint_type))) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unrecognized Endpoint Type '%s'",
value);
return FALSE;
}
return TRUE;
}
if (g_ascii_strcasecmp (key, "ep-iface-number") == 0) {
props->endpoint_iface_number = atoi(value);
return TRUE;
}
if (g_ascii_strcasecmp (key, "ul-datagram-max-size") == 0) {
props->ul_datagram_max_size = atoi(value);
return TRUE;
}
if (g_ascii_strcasecmp (key, "ul-max-datagrams") == 0) {
props->ul_max_datagrams = atoi(value);
return TRUE;
}
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"Unrecognized option '%s'",
key);
return FALSE;
}
static QmiMessageWdaSetDataFormatInput *
set_data_format_input_create (const gchar *str)
{
QmiMessageWdaSetDataFormatInput *input = NULL;
GError *error = NULL;
SetDataFormatProperties props = {
.link_layer_protocol = QMI_WDA_LINK_LAYER_PROTOCOL_UNKNOWN,
.ul_protocol = QMI_WDA_DATA_AGGREGATION_PROTOCOL_DISABLED,
.dl_protocol = QMI_WDA_DATA_AGGREGATION_PROTOCOL_DISABLED,
.dl_datagram_max_size = QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAM_SIZE_UNDEFINED,
.dl_max_datagrams = QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAMS_UNDEFINED,
.endpoint_type = QMI_DATA_ENDPOINT_TYPE_UNDEFINED,
.endpoint_iface_number = QMI_WDA_ENDPOINT_INTERFACE_NUMBER_UNDEFINED,
.ul_datagram_max_size = QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAM_SIZE_UNDEFINED,
.ul_max_datagrams = QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAMS_UNDEFINED,
};
input = qmi_message_wda_set_data_format_input_new ();
/* New key=value format */
if (strchr (str, '=')) {
if (!qmicli_parse_key_value_string (str,
&error,
set_data_format_properties_handle,
&props)) {
g_printerr ("error: could not parse input string '%s'\n", error->message);
g_error_free (error);
goto error_out;
}
if (!qmi_message_wda_set_data_format_input_set_uplink_data_aggregation_protocol (
input,
props.ul_protocol,
&error)) {
g_printerr ("error: could not set Upload data aggregation protocol '%d': %s\n",
props.ul_protocol, error->message);
g_error_free (error);
goto error_out;
}
if (!qmi_message_wda_set_data_format_input_set_downlink_data_aggregation_protocol (
input,
props.dl_protocol,
&error)) {
g_printerr ("error: could not set Download data aggregation protocol '%d': %s\n",
props.dl_protocol, error->message);
g_error_free (error);
goto error_out;
}
if (props.dl_datagram_max_size != QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAM_SIZE_UNDEFINED &&
!qmi_message_wda_set_data_format_input_set_downlink_data_aggregation_max_size (
input,
props.dl_datagram_max_size,
&error)) {
g_printerr ("error: could not set Download data aggregation max size %d: %s\n",
props.dl_datagram_max_size, error->message);
g_error_free (error);
goto error_out;
}
if (props.dl_max_datagrams != QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAMS_UNDEFINED &&
!qmi_message_wda_set_data_format_input_set_downlink_data_aggregation_max_datagrams (
input,
props.dl_max_datagrams,
&error)) {
g_printerr ("error: could not set Download data aggregation max datagrams %d: %s\n",
props.dl_max_datagrams, error->message);
g_error_free (error);
goto error_out;
}
if ((props.endpoint_type == QMI_DATA_ENDPOINT_TYPE_UNDEFINED) ^
(props.endpoint_iface_number == QMI_WDA_ENDPOINT_INTERFACE_NUMBER_UNDEFINED)) {
g_printerr ("error: endpoint type and interface number must be both set or both unset\n");
goto error_out;
}
if ((props.endpoint_type != QMI_DATA_ENDPOINT_TYPE_UNDEFINED) &&
(props.endpoint_iface_number != QMI_WDA_ENDPOINT_INTERFACE_NUMBER_UNDEFINED) &&
!qmi_message_wda_set_data_format_input_set_endpoint_info (
input,
props.endpoint_type,
props.endpoint_iface_number,
&error)) {
g_printerr ("error: could not set peripheral endpoint id: %s\n", error->message);
g_error_free (error);
goto error_out;
}
if (props.ul_datagram_max_size != QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAM_SIZE_UNDEFINED &&
!qmi_message_wda_set_data_format_input_set_uplink_data_aggregation_max_size (
input,
props.ul_datagram_max_size,
&error)) {
g_printerr ("error: could not set Upload data aggregation max size %d: %s\n",
props.ul_datagram_max_size, error->message);
g_error_free (error);
goto error_out;
}
if (props.ul_max_datagrams != QMI_WDA_AGGREGATION_PROTOCOL_MAX_DATAGRAMS_UNDEFINED &&
!qmi_message_wda_set_data_format_input_set_uplink_data_aggregation_max_datagrams (
input,
props.ul_max_datagrams,
&error)) {
g_printerr ("error: could not set Upload data aggregation max datagrams %d: %s\n",
props.ul_max_datagrams, error->message);
g_error_free (error);
goto error_out;
}
}
/* Old non key=value format, like this:
* "[(raw-ip|802-3)]"
*/
else {
if (!qmicli_read_wda_link_layer_protocol_from_string (str, &(props.link_layer_protocol))) {
g_printerr ("Unrecognized Link Layer Protocol '%s'\n", str);
goto error_out;
}
}
if (props.link_layer_protocol == QMI_WDA_LINK_LAYER_PROTOCOL_UNKNOWN) {
g_printerr ("error: Link Layer Protocol value is missing\n");
goto error_out;
}
if (!qmi_message_wda_set_data_format_input_set_link_layer_protocol (
input,
props.link_layer_protocol,
&error)) {
g_printerr ("error: couldn't create input data bundle: '%s'\n",
error->message);
g_error_free (error);
goto error_out;
}
return input;
error_out:
qmi_message_wda_set_data_format_input_unref (input);
return NULL;
}
#endif /* HAVE_QMI_MESSAGE_WDA_SET_DATA_FORMAT */
#if defined HAVE_QMI_MESSAGE_WDA_GET_SUPPORTED_MESSAGES
static void
get_supported_messages_ready (QmiClientWda *client,
GAsyncResult *res)
{
QmiMessageWdaGetSupportedMessagesOutput *output;
GError *error = NULL;
GArray *bytearray = NULL;
gchar *str;
output = qmi_client_wda_get_supported_messages_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_wda_get_supported_messages_output_get_result (output, &error)) {
g_printerr ("error: couldn't get supported WDA messages: %s\n", error->message);
g_error_free (error);
qmi_message_wda_get_supported_messages_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully got supported WDA messages:\n",
qmi_device_get_path_display (ctx->device));
qmi_message_wda_get_supported_messages_output_get_list (output, &bytearray, NULL);
str = qmicli_get_supported_messages_list (bytearray ? (const guint8 *)bytearray->data : NULL,
bytearray ? bytearray->len : 0);
g_print ("%s", str);
g_free (str);
qmi_message_wda_get_supported_messages_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_WDA_GET_SUPPORTED_MESSAGES */
void
qmicli_wda_run (QmiDevice *device,
QmiClientWda *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_WDA_SET_DATA_FORMAT
if (set_data_format_str) {
QmiMessageWdaSetDataFormatInput *input;
input = set_data_format_input_create (set_data_format_str);
if (!input) {
operation_shutdown (FALSE);
return;
}
g_debug ("Asynchronously setting data format...");
qmi_client_wda_set_data_format (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)set_data_format_ready,
NULL);
qmi_message_wda_set_data_format_input_unref (input);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_WDA_GET_DATA_FORMAT
if (get_data_format_flag) {
g_autoptr(QmiMessageWdaGetDataFormatInput) input = NULL;
if (get_data_format_str) {
input = get_data_format_input_create (get_data_format_str);
if (!input) {
operation_shutdown (FALSE);
return;
}
}
g_debug ("Asynchronously getting data format...");
qmi_client_wda_get_data_format (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_data_format_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_WDA_GET_SUPPORTED_MESSAGES
if (get_supported_messages_flag) {
g_debug ("Asynchronously getting supported WDA messages...");
qmi_client_wda_get_supported_messages (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_supported_messages_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_WDA */

3751
pkgs/qmi-nmea/qmicli-wds.c Normal file

File diff suppressed because it is too large Load Diff

566
pkgs/qmi-nmea/qmicli-wms.c Normal file
View File

@ -0,0 +1,566 @@
/* -*- 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) 2015-2017 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include <libqmi-glib.h>
#include "qmicli.h"
#include "qmicli-helpers.h"
#if defined HAVE_QMI_SERVICE_WMS
#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
/* Context */
typedef struct {
QmiDevice *device;
QmiClientWms *client;
GCancellable *cancellable;
} Context;
static Context *ctx;
/* Options */
static gboolean get_supported_messages_flag;
static gboolean get_routes_flag;
static gchar *set_routes_str;
static gboolean reset_flag;
static gboolean noop_flag;
static GOptionEntry entries[] = {
#if defined HAVE_QMI_MESSAGE_WMS_GET_SUPPORTED_MESSAGES
{ "wms-get-supported-messages", 0, 0, G_OPTION_ARG_NONE, &get_supported_messages_flag,
"Get supported messages",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_WMS_GET_ROUTES
{ "wms-get-routes", 0, 0, G_OPTION_ARG_NONE, &get_routes_flag,
"Get SMS route information",
NULL
},
#endif
#if defined HAVE_QMI_MESSAGE_WMS_SET_ROUTES
{ "wms-set-routes", 0, 0, G_OPTION_ARG_STRING, &set_routes_str,
"Set SMS route information (keys: type, class, storage, receipt-action)",
"[\"key=value,...\"]"
},
#endif
#if defined HAVE_QMI_MESSAGE_WMS_RESET
{ "wms-reset", 0, 0, G_OPTION_ARG_NONE, &reset_flag,
"Reset the service state",
NULL
},
#endif
{ "wms-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
"Just allocate or release a WMS client. Use with `--client-no-release-cid' and/or `--client-cid'",
NULL
},
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
GOptionGroup *
qmicli_wms_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("wms",
"WMS options:",
"Show Wireless Messaging Service options",
NULL,
NULL);
g_option_group_add_entries (group, entries);
return group;
}
gboolean
qmicli_wms_options_enabled (void)
{
static guint n_actions = 0;
static gboolean checked = FALSE;
if (checked)
return !!n_actions;
n_actions = (get_supported_messages_flag +
get_routes_flag +
!!set_routes_str +
reset_flag +
noop_flag);
if (n_actions > 1) {
g_printerr ("error: too many WMS actions requested\n");
exit (EXIT_FAILURE);
}
checked = TRUE;
return !!n_actions;
}
static void
context_free (Context *context)
{
if (!context)
return;
if (context->client)
g_object_unref (context->client);
g_object_unref (context->cancellable);
g_object_unref (context->device);
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_WMS_GET_SUPPORTED_MESSAGES
static void
get_supported_messages_ready (QmiClientWms *client,
GAsyncResult *res)
{
QmiMessageWmsGetSupportedMessagesOutput *output;
GError *error = NULL;
GArray *bytearray = NULL;
gchar *str;
output = qmi_client_wms_get_supported_messages_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_wms_get_supported_messages_output_get_result (output, &error)) {
g_printerr ("error: couldn't get supported WMS messages: %s\n", error->message);
g_error_free (error);
qmi_message_wms_get_supported_messages_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully got supported WMS messages:\n",
qmi_device_get_path_display (ctx->device));
qmi_message_wms_get_supported_messages_output_get_list (output, &bytearray, NULL);
str = qmicli_get_supported_messages_list (bytearray ? (const guint8 *)bytearray->data : NULL,
bytearray ? bytearray->len : 0);
g_print ("%s", str);
g_free (str);
qmi_message_wms_get_supported_messages_output_unref (output);
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_WMS_GET_SUPPORTED_MESSAGES */
#if defined HAVE_QMI_MESSAGE_WMS_GET_ROUTES
static void
get_routes_ready (QmiClientWms *client,
GAsyncResult *res)
{
g_autoptr(QmiMessageWmsGetRoutesOutput) output = NULL;
GError *error = NULL;
GArray *route_list;
guint i;
output = qmi_client_wms_get_routes_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_wms_get_routes_output_get_result (output, &error)) {
g_printerr ("error: couldn't get SMS routes: %s\n", error->message);
g_error_free (error);
operation_shutdown (FALSE);
return;
}
if (!qmi_message_wms_get_routes_output_get_route_list (output, &route_list, &error)) {
g_printerr ("error: got invalid SMS routes: %s\n", error->message);
g_error_free (error);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Got %u SMS routes:\n", qmi_device_get_path_display (ctx->device),
route_list->len);
for (i = 0; i < route_list->len; i++) {
QmiMessageWmsGetRoutesOutputRouteListElement *route;
route = &g_array_index (route_list, QmiMessageWmsGetRoutesOutputRouteListElement, i);
g_print (" Route #%u:\n", i + 1);
g_print (" Message Type: %s\n", VALIDATE_UNKNOWN (qmi_wms_message_type_get_string (route->message_type)));
g_print (" Message Class: %s\n", VALIDATE_UNKNOWN (qmi_wms_message_class_get_string (route->message_class)));
g_print (" Storage Type: %s\n", VALIDATE_UNKNOWN (qmi_wms_storage_type_get_string (route->storage)));
g_print (" Receipt Action: %s\n", VALIDATE_UNKNOWN (qmi_wms_receipt_action_get_string (route->receipt_action)));
}
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_WMS_GET_ROUTES */
#if defined HAVE_QMI_MESSAGE_WMS_SET_ROUTES
typedef struct {
GArray *route_list;
gboolean message_type_set;
gboolean message_class_set;
gboolean storage_set;
gboolean receipt_action_set;
} SetRoutesContext;
static void
set_routes_context_init (SetRoutesContext *routes_ctx)
{
memset (routes_ctx, 0, sizeof(SetRoutesContext));
routes_ctx->route_list = g_array_new (FALSE, TRUE, sizeof (QmiMessageWmsSetRoutesInputRouteListElement));
}
static void
set_routes_context_destroy (SetRoutesContext *routes_ctx)
{
g_array_unref (routes_ctx->route_list);
}
static gboolean
set_route_properties_handle (const gchar *key,
const gchar *value,
GError **error,
gpointer user_data)
{
SetRoutesContext *routes_ctx = user_data;
QmiMessageWmsSetRoutesInputRouteListElement *cur_route;
gboolean ret = FALSE;
if (!value || !value[0]) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"key '%s' required a value",
key);
return FALSE;
}
if (!routes_ctx->message_type_set && !routes_ctx->message_class_set &&
!routes_ctx->storage_set && !routes_ctx->receipt_action_set) {
QmiMessageWmsSetRoutesInputRouteListElement new_elt;
memset (&new_elt, 0, sizeof (QmiMessageWmsSetRoutesInputRouteListElement));
g_array_append_val (routes_ctx->route_list, new_elt);
}
cur_route = &g_array_index (routes_ctx->route_list,
QmiMessageWmsSetRoutesInputRouteListElement,
routes_ctx->route_list->len - 1);
if (g_ascii_strcasecmp (key, "type") == 0 && !routes_ctx->message_type_set) {
if (!qmicli_read_wms_message_type_from_string (value, &cur_route->message_type)) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"unknown message type '%s'",
value);
return FALSE;
}
routes_ctx->message_type_set = TRUE;
ret = TRUE;
} else if (g_ascii_strcasecmp (key, "class") == 0 && !routes_ctx->message_class_set) {
if (!qmicli_read_wms_message_class_from_string (value, &cur_route->message_class)) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"unknown message class '%s'",
value);
return FALSE;
}
routes_ctx->message_class_set = TRUE;
ret = TRUE;
} else if (g_ascii_strcasecmp (key, "storage") == 0 && !routes_ctx->storage_set) {
if (!qmicli_read_wms_storage_type_from_string (value, &cur_route->storage)) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"unknown storage type '%s'",
value);
return FALSE;
}
routes_ctx->storage_set = TRUE;
ret = TRUE;
} else if (g_ascii_strcasecmp (key, "receipt-action") == 0 && !routes_ctx->receipt_action_set) {
if (!qmicli_read_wms_receipt_action_from_string (value, &cur_route->receipt_action)) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"unknown receipt action '%s'",
value);
return FALSE;
}
routes_ctx->receipt_action_set = TRUE;
ret = TRUE;
}
if (routes_ctx->message_type_set && routes_ctx->message_class_set &&
routes_ctx->storage_set && routes_ctx->receipt_action_set) {
/* We have a complete set of details for this route. Reset the context state. */
routes_ctx->message_type_set = FALSE;
routes_ctx->message_class_set = FALSE;
routes_ctx->storage_set = FALSE;
routes_ctx->receipt_action_set = FALSE;
}
if (!ret) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"unrecognized or duplicate option '%s'",
key);
}
return ret;
}
static QmiMessageWmsSetRoutesInput *
set_routes_input_create (const gchar *str,
GError **error)
{
g_autoptr(QmiMessageWmsSetRoutesInput) input = NULL;
SetRoutesContext routes_ctx;
GError *inner_error = NULL;
set_routes_context_init (&routes_ctx);
if (!qmicli_parse_key_value_string (str,
&inner_error,
set_route_properties_handle,
&routes_ctx)) {
g_propagate_prefixed_error (error,
inner_error,
"couldn't parse input string: ");
set_routes_context_destroy (&routes_ctx);
return NULL;
}
if (routes_ctx.route_list->len == 0) {
g_set_error_literal (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"route list was empty");
set_routes_context_destroy (&routes_ctx);
return NULL;
}
if (routes_ctx.message_type_set || routes_ctx.message_class_set ||
routes_ctx.storage_set || routes_ctx.receipt_action_set) {
g_set_error_literal (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_FAILED,
"final route was missing one or more options");
set_routes_context_destroy (&routes_ctx);
return NULL;
}
/* Create input */
input = qmi_message_wms_set_routes_input_new ();
if (!qmi_message_wms_set_routes_input_set_route_list (input, routes_ctx.route_list, &inner_error)) {
g_propagate_error (error, inner_error);
set_routes_context_destroy (&routes_ctx);
return NULL;
}
set_routes_context_destroy (&routes_ctx);
return g_steal_pointer (&input);
}
static void
set_routes_ready (QmiClientWms *client,
GAsyncResult *res)
{
g_autoptr(QmiMessageWmsSetRoutesOutput) output = NULL;
GError *error = NULL;
output = qmi_client_wms_set_routes_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_wms_set_routes_output_get_result (output, &error)) {
g_printerr ("error: couldn't set SMS routes: %s\n", error->message);
g_error_free (error);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully set SMS routes\n",
qmi_device_get_path_display (ctx->device));
operation_shutdown (TRUE);
}
#endif /* HAVE_QMI_MESSAGE_WMS_SET_ROUTES */
#if defined HAVE_QMI_MESSAGE_WMS_RESET
static void
reset_ready (QmiClientWms *client,
GAsyncResult *res)
{
QmiMessageWmsResetOutput *output;
GError *error = NULL;
output = qmi_client_wms_reset_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_wms_reset_output_get_result (output, &error)) {
g_printerr ("error: couldn't reset the WMS service: %s\n", error->message);
g_error_free (error);
qmi_message_wms_reset_output_unref (output);
operation_shutdown (FALSE);
return;
}
g_print ("[%s] Successfully performed WMS service reset\n",
qmi_device_get_path_display (ctx->device));
qmi_message_wms_reset_output_unref (output);
operation_shutdown (TRUE);
}
#endif
static gboolean
noop_cb (gpointer unused)
{
operation_shutdown (TRUE);
return FALSE;
}
void
qmicli_wms_run (QmiDevice *device,
QmiClientWms *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_WMS_GET_SUPPORTED_MESSAGES
if (get_supported_messages_flag) {
g_debug ("Asynchronously getting supported WMS messages...");
qmi_client_wms_get_supported_messages (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_supported_messages_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_WMS_GET_ROUTES
if (get_routes_flag) {
g_debug ("Asynchronously getting SMS routes...");
qmi_client_wms_get_routes (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)get_routes_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_WMS_SET_ROUTES
if (set_routes_str) {
g_autoptr(QmiMessageWmsSetRoutesInput) input = NULL;
GError *error = NULL;
input = set_routes_input_create (set_routes_str, &error);
if (!input) {
g_printerr ("Failed to set route: %s\n", error->message);
g_error_free (error);
operation_shutdown (FALSE);
return;
}
g_debug ("Asynchronously setting SMS routes...");
qmi_client_wms_set_routes (ctx->client,
input,
10,
ctx->cancellable,
(GAsyncReadyCallback)set_routes_ready,
NULL);
return;
}
#endif
#if defined HAVE_QMI_MESSAGE_WMS_RESET
if (reset_flag) {
g_debug ("Asynchronously resetting WMS service...");
qmi_client_wms_reset (ctx->client,
NULL,
10,
ctx->cancellable,
(GAsyncReadyCallback)reset_ready,
NULL);
return;
}
#endif
/* Just client allocate/release? */
if (noop_flag) {
g_idle_add (noop_cb, NULL);
return;
}
g_warn_if_reached ();
}
#endif /* HAVE_QMI_SERVICE_WMS */

1169
pkgs/qmi-nmea/qmicli.c Normal file

File diff suppressed because it is too large Load Diff

212
pkgs/qmi-nmea/qmicli.h Normal file
View File

@ -0,0 +1,212 @@
/* -*- 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) 2012-2017 Aleksander Morgado <aleksander@aleksander.es>
*/
#include <glib.h>
#include <libqmi-glib.h>
#ifndef __QMICLI_H__
#define __QMICLI_H__
/* Common */
void qmicli_async_operation_done (gboolean reported_operation_status,
gboolean skip_cid_release);
void qmicli_expect_indications (void);
/* qmi_wwan specific */
GOptionGroup *qmicli_qmiwwan_get_option_group (void);
gboolean qmicli_qmiwwan_options_enabled (void);
void qmicli_qmiwwan_run (QmiDevice *device,
GCancellable *cancellable);
/* link management */
GOptionGroup *qmicli_link_management_get_option_group (void);
gboolean qmicli_link_management_options_enabled (void);
void qmicli_link_management_run (QmiDevice *device,
GCancellable *cancellable);
#if defined HAVE_QMI_SERVICE_DMS
GOptionGroup *qmicli_dms_get_option_group (void);
gboolean qmicli_dms_options_enabled (void);
void qmicli_dms_run (QmiDevice *device,
QmiClientDms *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_WDS
GOptionGroup *qmicli_wds_get_option_group (void);
gboolean qmicli_wds_options_enabled (void);
void qmicli_wds_run (QmiDevice *device,
QmiClientWds *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_NAS
GOptionGroup *qmicli_nas_get_option_group (void);
gboolean qmicli_nas_options_enabled (void);
void qmicli_nas_run (QmiDevice *device,
QmiClientNas *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_PBM
GOptionGroup *qmicli_pbm_get_option_group (void);
gboolean qmicli_pbm_options_enabled (void);
void qmicli_pbm_run (QmiDevice *device,
QmiClientPbm *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_PDC
GOptionGroup *qmicli_pdc_get_option_group (void);
gboolean qmicli_pdc_options_enabled (void);
void qmicli_pdc_run (QmiDevice *device,
QmiClientPdc *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_UIM
GOptionGroup *qmicli_uim_get_option_group (void);
gboolean qmicli_uim_options_enabled (void);
void qmicli_uim_run (QmiDevice *device,
QmiClientUim *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_WMS
GOptionGroup *qmicli_wms_get_option_group (void);
gboolean qmicli_wms_options_enabled (void);
void qmicli_wms_run (QmiDevice *device,
QmiClientWms *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_WDA
GOptionGroup *qmicli_wda_get_option_group (void);
gboolean qmicli_wda_options_enabled (void);
void qmicli_wda_run (QmiDevice *device,
QmiClientWda *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_VOICE
GOptionGroup *qmicli_voice_get_option_group (void);
gboolean qmicli_voice_options_enabled (void);
void qmicli_voice_run (QmiDevice *device,
QmiClientVoice *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_LOC
GOptionGroup *qmicli_loc_get_option_group (void);
gboolean qmicli_loc_options_enabled (void);
void qmicli_loc_run (QmiDevice *device,
QmiClientLoc *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_QOS
GOptionGroup *qmicli_qos_get_option_group (void);
gboolean qmicli_qos_options_enabled (void);
void qmicli_qos_run (QmiDevice *device,
QmiClientQos *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_GAS
GOptionGroup *qmicli_gas_get_option_group (void);
gboolean qmicli_gas_options_enabled (void);
void qmicli_gas_run (QmiDevice *device,
QmiClientGas *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_GMS
GOptionGroup *qmicli_gms_get_option_group (void);
gboolean qmicli_gms_options_enabled (void);
void qmicli_gms_run (QmiDevice *device,
QmiClientGms *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_DSD
GOptionGroup *qmicli_dsd_get_option_group (void);
gboolean qmicli_dsd_options_enabled (void);
void qmicli_dsd_run (QmiDevice *device,
QmiClientDsd *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_SAR
GOptionGroup *qmicli_sar_get_option_group (void);
gboolean qmicli_sar_options_enabled (void);
void qmicli_sar_run (QmiDevice *device,
QmiClientSar *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_DPM
GOptionGroup *qmicli_dpm_get_option_group (void);
gboolean qmicli_dpm_options_enabled (void);
void qmicli_dpm_run (QmiDevice *device,
QmiClientDpm *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_FOX
GOptionGroup *qmicli_fox_get_option_group (void);
gboolean qmicli_fox_options_enabled (void);
void qmicli_fox_run (QmiDevice *device,
QmiClientFox *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_ATR
GOptionGroup *qmicli_atr_get_option_group (void);
gboolean qmicli_atr_options_enabled (void);
void qmicli_atr_run (QmiDevice *device,
QmiClientAtr *client,
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
#if defined HAVE_QMI_SERVICE_IMSA
GOptionGroup *qmicli_imsa_get_option_group (void);
gboolean qmicli_imsa_options_enabled (void);
void qmicli_imsa_run (QmiDevice *device,
QmiClientImsa *client,
GCancellable *cancellable);
#endif
#if defined HAVE_QMI_SERVICE_IMS
GOptionGroup *qmicli_ims_get_option_group (void);
gboolean qmicli_ims_options_enabled (void);
void qmicli_ims_run (QmiDevice *device,
QmiClientIms *client,
GCancellable *cancellable);
#endif
#endif /* __QMICLI_H__ */