add qmi-nmea placeholder (copy of qmicli)
This commit is contained in:
parent
b8aa0ae9b1
commit
1a0e19908a
@ -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 {};
|
||||
})
|
||||
];
|
||||
|
||||
|
@ -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
21
pkgs/qmi-nmea/Makefile
Normal 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
1
pkgs/qmi-nmea/config.h
Normal file
@ -0,0 +1 @@
|
||||
|
16
pkgs/qmi-nmea/default.nix
Normal file
16
pkgs/qmi-nmea/default.nix
Normal 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"}" ];
|
||||
}
|
16
pkgs/qmi-nmea/qmi-common.h
Normal file
16
pkgs/qmi-nmea/qmi-common.h
Normal 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
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
155
pkgs/qmi-nmea/qmicli
Normal 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
413
pkgs/qmi-nmea/qmicli-atr.c
Normal 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
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
544
pkgs/qmi-nmea/qmicli-dpm.c
Normal 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
415
pkgs/qmi-nmea/qmicli-dsd.c
Normal 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
240
pkgs/qmi-nmea/qmicli-fox.c
Normal 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
499
pkgs/qmi-nmea/qmicli-gas.c
Normal 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
316
pkgs/qmi-nmea/qmicli-gms.c
Normal 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 */
|
985
pkgs/qmi-nmea/qmicli-helpers.c
Normal file
985
pkgs/qmi-nmea/qmicli-helpers.c
Normal 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;
|
||||
}
|
147
pkgs/qmi-nmea/qmicli-helpers.h
Normal file
147
pkgs/qmi-nmea/qmicli-helpers.h
Normal 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
283
pkgs/qmi-nmea/qmicli-ims.c
Normal 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
367
pkgs/qmi-nmea/qmicli-imsa.c
Normal 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, ®istration_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, ®istration_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
205
pkgs/qmi-nmea/qmicli-imsp.c
Normal 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 */
|
||||
|
386
pkgs/qmi-nmea/qmicli-link-management.c
Normal file
386
pkgs/qmi-nmea/qmicli-link-management.c
Normal 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
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
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
349
pkgs/qmi-nmea/qmicli-pbm.c
Normal 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
1475
pkgs/qmi-nmea/qmicli-pdc.c
Normal file
File diff suppressed because it is too large
Load Diff
193
pkgs/qmi-nmea/qmicli-qmiwwan.c
Normal file
193
pkgs/qmi-nmea/qmicli-qmiwwan.c
Normal 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
430
pkgs/qmi-nmea/qmicli-qos.c
Normal 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
295
pkgs/qmi-nmea/qmicli-sar.c
Normal 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
3452
pkgs/qmi-nmea/qmicli-uim.c
Normal file
File diff suppressed because it is too large
Load Diff
379
pkgs/qmi-nmea/qmicli-voice.c
Normal file
379
pkgs/qmi-nmea/qmicli-voice.c
Normal 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,
|
||||
¤t_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,
|
||||
¤t_preferred_voice_so_nam_id,
|
||||
¤t_preferred_voice_so_evrc_capability,
|
||||
¤t_preferred_voice_so_home_page_voice_service_option,
|
||||
¤t_preferred_voice_so_home_origination_voice_service_option,
|
||||
¤t_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,
|
||||
¤t_amr_status_gsm, ¤t_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,
|
||||
¤t_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,
|
||||
¤t_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
811
pkgs/qmi-nmea/qmicli-wda.c
Normal 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
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
566
pkgs/qmi-nmea/qmicli-wms.c
Normal 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
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
212
pkgs/qmi-nmea/qmicli.h
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user