From 8419ed5ce0dbae37ecc67307a51c866db2a3b378 Mon Sep 17 00:00:00 2001 From: Aliaksandr Barouski Date: Thu, 7 Jul 2016 15:47:20 -0700 Subject: [PATCH] Added calls for configure hp4120 LTE modem --- data/Makefile.am | 1 + data/qmi-service-pdc.json | 364 +++++ docs/reference/libqmi-glib/Makefile.am | 1 + .../libqmi-glib/libqmi-glib-common.sections | 12 + docs/reference/libqmi-glib/libqmi-glib-docs.xml | 32 + src/libqmi-glib/generated/Makefile.am | 16 +- src/libqmi-glib/libqmi-glib.h | 3 + src/libqmi-glib/qmi-device.c | 5 + src/libqmi-glib/qmi-enums-pdc.h | 54 + src/libqmi-glib/qmi-message.c | 4 + src/qmicli/Makefile.am | 1 + src/qmicli/qmicli-helpers.c | 105 ++ src/qmicli/qmicli-helpers.h | 8 + src/qmicli/qmicli-pdc.c | 1407 ++++++++++++++++++++ src/qmicli/qmicli.c | 11 + src/qmicli/qmicli.h | 7 + 16 files changed, 2030 insertions(+), 1 deletion(-) create mode 100644 data/qmi-service-pdc.json create mode 100644 src/libqmi-glib/qmi-enums-pdc.h create mode 100644 src/qmicli/qmicli-pdc.c diff --git a/data/Makefile.am b/data/Makefile.am index 0d74955..9c4b99b 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -7,6 +7,7 @@ EXTRA_DIST = \ qmi-service-wds.json \ qmi-service-nas.json \ qmi-service-wms.json \ + qmi-service-pdc.json \ qmi-service-pds.json \ qmi-service-pbm.json \ qmi-service-uim.json \ diff --git a/data/qmi-service-pdc.json b/data/qmi-service-pdc.json new file mode 100644 index 0000000..99ef2ce --- /dev/null +++ b/data/qmi-service-pdc.json @@ -0,0 +1,364 @@ +[ + // ********************************************************************************* + { "name" : "PDC", + "type" : "Service" }, + + // ********************************************************************************* + { "name" : "QMI Client PDC", + "type" : "Client" }, + + // ********************************************************************************* + { "name" : "QMI Message PDC", + "type" : "Message-ID-Enum" }, + + // ********************************************************************************* + { "name" : "QMI Indication PDC", + "type" : "Indication-ID-Enum" }, + + // ********************************************************************************* + { "common-ref" : "Config Type", + "name" : "Config Type", + "id" : "0x1", + "mandatory" : "yes", + "type" : "TLV", + "format" : "guint32", + "public-format" : "QmiPdcConfigurationType" }, + + { "common-ref" : "Indication Result", + "name" : "Indication Result", + "id" : "0x01", + "mandatory" : "yes", + "type" : "TLV", + "format" : "guint16" }, + + // ********************************************************************************* + { "common-ref" : "Config Type And Id", + "name" : "Type With Id", + "fullname" : "Qmi Config Type And Id", + "id" : "0x01", + "mandatory" : "yes", + "type" : "TLV", + "format" : "struct", + "contents" : [ { "name" : "Config Type", + "format" : "guint32", + "public-format" : "QmiPdcConfigurationType"}, + { "name" : "Id", + "format" : "array", + "array-element" : { "format" : "guint8" }} ]}, + + // ********************************************************************************* + { "common-ref" : "Token", + "name" : "Token", + "id" : "0x10", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint32"}, + + // ********************************************************************************* + { "name" : "Reset", + "type" : "Message", + "service" : "PDC", + "id" : "0x0000", + "version" : "1.15", + "output" : [ { "common-ref" : "Operation Result" } ] }, + + // ********************************************************************************* + { "name" : "Register", + "type" : "Message", + "service" : "PDC", + "id" : "0x20", + "version" : "1.15", + "input" : [ { "name" : "EnableReporting", + "id" : "0x10", + "mandatory" : "yes", + "type" : "TLV", + "format" : "guint8", + "public-format" : "gboolean"}], + "output" : [ { "common-ref" : "Operation Result" } ] }, + + // ********************************************************************************* + { "name" : "Config Change", + "type" : "Message", + "service" : "PDC", + "id" : "0x21", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type And Id" } ], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Config Type And Id"}] }, + + // ********************************************************************************* + { "name" : "Get Selected Config", + "type" : "Message", + "service" : "PDC", + "id" : "0x22", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type"}, + { "common-ref" : "Token"}], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token"}]}, + + { "name" : "Get Selected Config", + "type" : "Indication", + "service" : "PDC", + "id" : "0x22", + "version" : "1.15", + "output" : [ { "common-ref" : "Token"}, + { "common-ref" : "Indication Result"}, + { "name" : "Active Id", + "id" : "0x11", + "mandatory" : "no", + "type" : "TLV", + "format" : "array", + "array-element" : { "format" : "guint8" } }, + { "name" : "Pending Id", + "id" : "0x12", + "mandatory" : "no", + "type" : "TLV", + "format" : "array", + "array-element" : { "format" : "guint8" } }]}, + + // ********************************************************************************* + { "name" : "Set Selected Config", + "type" : "Message", + "service" : "PDC", + "id" : "0x23", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type And Id" }, + { "common-ref" : "Token" }], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token"}] }, + + { "name" : "Set Selected Config", + "type" : "Indication", + "service" : "PDC", + "id" : "0x23", + "version" : "1.15", + "output" : [ { "common-ref" : "Indication Result" }, + { "common-ref" : "Token"}] }, + + // ********************************************************************************* + { "name" : "List Configs", + "type" : "Message", + "service" : "PDC", + "id" : "0x24", + "version" : "1.15", + "input" : [ { "common-ref" : "Token" }, + { "name" : "Config Type", + "id" : "0x11", + "mandatory" : "yes", + "type" : "TLV", + "format" : "guint32", + "public-format" : "QmiPdcConfigurationType" }], + "output" : [ { "common-ref" : "Operation Result" } ] }, + + { "name" : "List Configs", + "type" : "Indication", + "service" : "PDC", + "id" : "0x24", + "output" : [ { "common-ref" : "Token" }, + { "common-ref" : "Indication Result"}, + { "name" : "Configs", + "id" : "0x11", + "mandatory" : "no", + "type" : "TLV", + "format" : "array", + "size-prefix-format" : "guint8", + "array-element" : { "name" : "Element", + "format" : "struct", + "contents" : [ { "name" : "Config Type", + "format" : "guint32", + "public-format" : "QmiPdcConfigurationType" }, + { "name" : "Id", + "format" : "array", + "array-element" : { "format" : "guint8" }}]}}]}, + + // ********************************************************************************* + { "name" : "Delete Config", + "type" : "Message", + "service" : "PDC", + "id" : "0x25", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type" }, + { "common-ref" : "Token" }, + { "name" : "Id", + "id" : "0x11", + "mandatory" : "yes", + "type" : "TLV", + "format" : "array", + "array-element" : { "format" : "guint8" }}], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token"}] }, + + // ********************************************************************************* + { "name" : "Load Config", + "type" : "Message", + "service" : "PDC", + "id" : "0x26", + "version" : "1.15", + "input" : [ { "name" : "Config Chunk", + "id" : "0x1", + "mandatory" : "yes", + "type" : "TLV", + "format" : "sequence", + "contents" : [ { "name" : "Type", + "format" : "guint32", + "public-format" : "QmiPdcConfigurationType"}, + { "name" : "Id", + "format" : "array", + "array-element" : { "format" : "guint8" }}, + { "name" : "Total Size", + "format" : "guint32" }, + { "name" : "Chunk", + "format" : "array", + "size-prefix-format" : "guint16", + "array-element" : { "format" : "guint8" }}]}, + { "common-ref" : "Token"}], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token"}] }, + + { "name" : "Load Config", + "type" : "Indication", + "service" : "PDC", + "id" : "0x26", + "version" : "1.15", + "output" : [ { "common-ref" : "Token"}, + { "common-ref" : "Indication Result"}, + { "name" : "Received", + "id" : "0x11", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint32" }, + { "name" : "Remaining Size", + "id" : "0x12", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint32" }, + { "name" : "Frame Reset", + "id" : "0x13", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint8", + "public-format" : "gboolean" } + ] }, + + // ********************************************************************************* + { "name" : "Activate Config", + "type" : "Message", + "service" : "PDC", + "id" : "0x27", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type" }, + { "common-ref" : "Token" }], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token" }] }, + + { "name" : "Activate Config", + "type" : "Indication", + "service" : "PDC", + "id" : "0x27", + "version" : "1.15", + "output" : [ { "common-ref" : "Indication Result" }, + { "common-ref" : "Token" }] }, + + // ********************************************************************************* + { "name" : "Get Config Info", + "type" : "Message", + "service" : "PDC", + "id" : "0x28", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type And Id" }, + { "common-ref" : "Token"}], + "output" : [ { "common-ref" : "Operation Result" } ] }, + + { "name" : "Get Config Info", + "type" : "Indication", + "service" : "PDC", + "id" : "0x28", + "version" : "1.15", + "output" : [ { "common-ref" : "Token"}, + { "common-ref" : "Indication Result"}, + { "name" : "Total Size", + "id" : "0x11", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint32" }, + { "name" : "Description", + "id" : "0x12", + "mandatory" : "no", + "type" : "TLV", + "format" : "string", + "size-prefix-format" : "guint8"}, + { "name" : "Version", + "id" : "0x13", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint32" } + ] }, + + // ********************************************************************************* + { "name" : "Get Config Limits", + "type" : "Message", + "service" : "PDC", + "id" : "0x29", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type" }, + { "common-ref" : "Token" }], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token" }, + { "name" : "Maximum Size", + "id" : "0x11", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint64" }, + { "name" : "Current Size", + "id" : "0x12", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint64" }] }, + + // ********************************************************************************* + { "name" : "Get Default Config Info", + "type" : "Message", + "service" : "PDC", + "id" : "0x2A", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type" }, + { "common-ref" : "Token" }], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token" }, + { "name" : "Version", + "id" : "0x11", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint32" }, + { "name" : "Total Size", + "id" : "0x12", + "mandatory" : "no", + "type" : "TLV", + "format" : "guint32" }, + { "name" : "Description", + "id" : "0x13", + "mandatory" : "no", + "type" : "TLV", + "format" : "string" } + ] }, + + // ********************************************************************************* + { "name" : "Deactivate Config", + "type" : "Message", + "service" : "PDC", + "id" : "0x2B", + "version" : "1.15", + "input" : [ { "common-ref" : "Config Type" }, + { "common-ref" : "Token" }], + "output" : [ { "common-ref" : "Operation Result" }, + { "common-ref" : "Token" }] }, + + { "name" : "Deactivate Config", + "type" : "Indication", + "service" : "PDC", + "id" : "0x2B", + "version" : "1.15", + "output" : [ { "common-ref" : "Indication Result" }, + { "common-ref" : "Token" }] } +] diff --git a/docs/reference/libqmi-glib/Makefile.am b/docs/reference/libqmi-glib/Makefile.am index deb5e8b..6f5cfd1 100644 --- a/docs/reference/libqmi-glib/Makefile.am +++ b/docs/reference/libqmi-glib/Makefile.am @@ -12,6 +12,7 @@ ALL_SECTIONS = \ $(top_builddir)/src/libqmi-glib/generated/qmi-nas.sections \ $(top_builddir)/src/libqmi-glib/generated/qmi-wds.sections \ $(top_builddir)/src/libqmi-glib/generated/qmi-wms.sections \ + $(top_builddir)/src/libqmi-glib/generated/qmi-pdc.sections \ $(top_builddir)/src/libqmi-glib/generated/qmi-pds.sections \ $(top_builddir)/src/libqmi-glib/generated/qmi-pbm.sections \ $(top_builddir)/src/libqmi-glib/generated/qmi-uim.sections \ diff --git a/docs/reference/libqmi-glib/libqmi-glib-common.sections b/docs/reference/libqmi-glib/libqmi-glib-common.sections index 9f8c013..62e4b3e 100644 --- a/docs/reference/libqmi-glib/libqmi-glib-common.sections +++ b/docs/reference/libqmi-glib/libqmi-glib-common.sections @@ -694,6 +694,18 @@ qmi_wms_transfer_indication_get_type
+qmi-enums-pdc +QmiPdcConfigurationType + +qmi_pdc_configuration_type_get_string + +qmi_pdc_configuration_type_build_string_from_mask + +QMI_TYPE_PDC_CONFIGURATION_TYPE +qmi_pdc_configuration_type_get_type +
+ +
qmi-enums-pds QmiPdsOperationMode QmiPdsPositionSessionStatus diff --git a/docs/reference/libqmi-glib/libqmi-glib-docs.xml b/docs/reference/libqmi-glib/libqmi-glib-docs.xml index d4daf86..4a1eaef 100644 --- a/docs/reference/libqmi-glib/libqmi-glib-docs.xml +++ b/docs/reference/libqmi-glib/libqmi-glib-docs.xml @@ -212,6 +212,38 @@ + Persistent Device Configuration (PDC) + + +
+ PDC Indications + + + + + + + +
+
+ PDC Requests + + + + + + + + + + + + + +
+
+ + Position Determination Service (PDS) diff --git a/src/libqmi-glib/generated/Makefile.am b/src/libqmi-glib/generated/Makefile.am index 2eda73b..23c7259 100644 --- a/src/libqmi-glib/generated/Makefile.am +++ b/src/libqmi-glib/generated/Makefile.am @@ -12,6 +12,7 @@ GENERATED_H = \ qmi-wds.h \ qmi-wms.h \ qmi-pds.h \ + qmi-pdc.h \ qmi-pbm.h \ qmi-uim.h \ qmi-oma.h \ @@ -30,6 +31,7 @@ GENERATED_C = \ qmi-wds.c \ qmi-wms.c \ qmi-pds.c \ + qmi-pdc.c \ qmi-pbm.c \ qmi-uim.c \ qmi-oma.c \ @@ -43,6 +45,7 @@ GENERATED_SECTIONS = \ qmi-wds.sections \ qmi-wms.sections \ qmi-pds.sections \ + qmi-pdc.sections \ qmi-pbm.sections \ qmi-uim.sections \ qmi-oma.sections \ @@ -76,6 +79,7 @@ ENUMS = \ $(top_srcdir)/src/libqmi-glib/qmi-enums-dms.h \ $(top_srcdir)/src/libqmi-glib/qmi-enums-nas.h \ $(top_srcdir)/src/libqmi-glib/qmi-enums-wms.h \ + $(top_srcdir)/src/libqmi-glib/qmi-enums-pdc.h \ $(top_srcdir)/src/libqmi-glib/qmi-enums-pds.h \ $(top_srcdir)/src/libqmi-glib/qmi-enums-pbm.h \ $(top_srcdir)/src/libqmi-glib/qmi-enums-uim.h \ @@ -85,7 +89,7 @@ ENUMS = \ $(top_srcdir)/src/libqmi-glib/qmi-device.h qmi-enum-types.h: $(ENUMS) $(top_srcdir)/build-aux/templates/qmi-enum-types-template.h $(AM_V_GEN) $(GLIB_MKENUMS) \ - --fhead "#ifndef __LIBQMI_GLIB_ENUM_TYPES_H__\n#define __LIBQMI_GLIB_ENUM_TYPES_H__\n#include \"qmi-enums.h\"\n#include \"qmi-enums-wds.h\"\n#include \"qmi-enums-dms.h\"\n#include \"qmi-enums-nas.h\"\n#include \"qmi-enums-wms.h\"\n#include \"qmi-enums-pds.h\"\n#include \"qmi-enums-pbm.h\"\n#include \"qmi-enums-uim.h\"\n#include \"qmi-enums-oma.h\"\n#include \"qmi-enums-wda.h\"\n#include \"qmi-enums-voice.h\"\n#include \"qmi-device.h\"\n" \ + --fhead "#ifndef __LIBQMI_GLIB_ENUM_TYPES_H__\n#define __LIBQMI_GLIB_ENUM_TYPES_H__\n#include \"qmi-enums.h\"\n#include \"qmi-enums-wds.h\"\n#include \"qmi-enums-dms.h\"\n#include \"qmi-enums-nas.h\"\n#include \"qmi-enums-wms.h\"\n#include \"qmi-enums-pds.h\"\n#include \"qmi-enums-pdc.h\"\n#include \"qmi-enums-pbm.h\"\n#include \"qmi-enums-uim.h\"\n#include \"qmi-enums-oma.h\"\n#include \"qmi-enums-wda.h\"\n#include \"qmi-enums-voice.h\"\n#include \"qmi-device.h\"\n" \ --template $(top_srcdir)/build-aux/templates/qmi-enum-types-template.h \ --ftail "#endif /* __LIBQMI_GLIB_ENUM_TYPES_H__ */\n" \ $(ENUMS) > $@ @@ -187,6 +191,16 @@ qmi-pds.h qmi-pds.c qmi-pds.sections: $(top_srcdir)/data/qmi-service-pds.json $( --include $(top_srcdir)/data/qmi-common.json \ --output qmi-pds +# PDC service +qmi-pdc.h qmi-pdc.c qmi-pdc.sections: $(top_srcdir)/data/qmi-service-pdc.json $(top_srcdir)/build-aux/qmi-codegen/*.py $(top_srcdir)/build-aux/qmi-codegen/qmi-codegen + $(AM_V_GEN) \ + rm -f qmi-pdc.h && \ + rm -f qmi-pdc.c && \ + $(top_srcdir)/build-aux/qmi-codegen/qmi-codegen \ + --input $(top_srcdir)/data/qmi-service-pdc.json \ + --include $(top_srcdir)/data/qmi-common.json \ + --output qmi-pdc + # PBM service qmi-pbm.h qmi-pbm.c qmi-pbm.sections: $(top_srcdir)/data/qmi-service-pbm.json $(top_srcdir)/build-aux/qmi-codegen/*.py $(top_srcdir)/build-aux/qmi-codegen/qmi-codegen $(AM_V_GEN) \ diff --git a/src/libqmi-glib/libqmi-glib.h b/src/libqmi-glib/libqmi-glib.h index 12f9974..f954342 100644 --- a/src/libqmi-glib/libqmi-glib.h +++ b/src/libqmi-glib/libqmi-glib.h @@ -55,6 +55,9 @@ #include "qmi-enums-pds.h" #include "qmi-pds.h" +#include "qmi-enums-pdc.h" +#include "qmi-pdc.h" + #include "qmi-enums-pbm.h" #include "qmi-pbm.h" diff --git a/src/libqmi-glib/qmi-device.c b/src/libqmi-glib/qmi-device.c index c4abbbc..54ce8e7 100644 --- a/src/libqmi-glib/qmi-device.c +++ b/src/libqmi-glib/qmi-device.c @@ -39,6 +39,7 @@ #include "qmi-wds.h" #include "qmi-nas.h" #include "qmi-wms.h" +#include "qmi-pdc.h" #include "qmi-pds.h" #include "qmi-pbm.h" #include "qmi-uim.h" @@ -1153,6 +1154,10 @@ qmi_device_allocate_client (QmiDevice *self, ctx->client_type = QMI_TYPE_CLIENT_PDS; break; + case QMI_SERVICE_PDC: + ctx->client_type = QMI_TYPE_CLIENT_PDC; + break; + case QMI_SERVICE_PBM: ctx->client_type = QMI_TYPE_CLIENT_PBM; break; diff --git a/src/libqmi-glib/qmi-enums-pdc.h b/src/libqmi-glib/qmi-enums-pdc.h new file mode 100644 index 0000000..a3ae19e --- /dev/null +++ b/src/libqmi-glib/qmi-enums-pdc.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * libqmi-glib -- GLib/GIO based library to control QMI devices + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2012 Google Inc. + */ + +#ifndef _LIBQMI_GLIB_QMI_ENUMS_PDC_H_ +#define _LIBQMI_GLIB_QMI_ENUMS_PDC_H_ + +#if !defined (__LIBQMI_GLIB_H_INSIDE__) && !defined (LIBQMI_GLIB_COMPILATION) +#error "Only can be included directly." +#endif + +/** + * SECTION: qmi-enums-pdc + * @title: PDC enumerations and flags + * + * This section defines enumerations and flags used in the PDC service + * interface. + */ + +/*****************************************************************************/ +/* Helper enums for the 'QMI PDC' calls */ + +/** + * QmiPdcConfigurationType: + * @QMI_PDC_CONFIGURATION_TYPE_PLATFORM: Platform + * @QMI_PDC_CONFIGURATION_TYPE_SOFTWARE: Software + * + * Configuration type for change/load configuration. + */ +typedef enum { + QMI_PDC_CONFIGURATION_TYPE_PLATFORM = 0, + QMI_PDC_CONFIGURATION_TYPE_SOFTWARE = 1, +} QmiPdcConfigurationType; + + +#endif /* _LIBQMI_GLIB_QMI_ENUMS_PDC_H_ */ diff --git a/src/libqmi-glib/qmi-message.c b/src/libqmi-glib/qmi-message.c index 2f58432..23afa29 100644 --- a/src/libqmi-glib/qmi-message.c +++ b/src/libqmi-glib/qmi-message.c @@ -45,6 +45,7 @@ #include "qmi-wds.h" #include "qmi-nas.h" #include "qmi-wms.h" +#include "qmi-pdc.h" #include "qmi-pds.h" #include "qmi-pbm.h" #include "qmi-uim.h" @@ -2147,6 +2148,9 @@ qmi_message_get_printable (QmiMessage *self, case QMI_SERVICE_WMS: contents = __qmi_message_wms_get_printable (self, line_prefix); break; + case QMI_SERVICE_PDC: + contents = __qmi_message_pdc_get_printable (self, line_prefix); + break; case QMI_SERVICE_PDS: contents = __qmi_message_pds_get_printable (self, line_prefix); break; diff --git a/src/qmicli/Makefile.am b/src/qmicli/Makefile.am index 9583b41..90d0e53 100644 --- a/src/qmicli/Makefile.am +++ b/src/qmicli/Makefile.am @@ -20,6 +20,7 @@ qmicli_SOURCES = \ qmicli-wds.c \ qmicli-nas.c \ qmicli-pbm.c \ + qmicli-pdc.c \ qmicli-uim.c \ qmicli-wms.c \ qmicli-wda.c \ diff --git a/src/qmicli/qmicli-helpers.c b/src/qmicli/qmicli-helpers.c index 5443cad..801e7fd 100644 --- a/src/qmicli/qmicli-helpers.c +++ b/src/qmicli/qmicli-helpers.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "qmicli-helpers.h" @@ -315,6 +316,64 @@ qmicli_read_firmware_id_from_string (const gchar *str, } gboolean +qmicli_read_binary_array_from_string (const gchar *str, + GArray **out) { + char a; + gsize i,len; + if (!str) return FALSE; + + if((len = strlen(str)) & 1) return FALSE; + + *out = g_array_sized_new(FALSE, TRUE, 1, len >> 1); + g_array_set_size(*out, len >> 1); + + for (i = 0; i < len; i++) { + a = toupper(str[i]); + if (!isxdigit(a)) + break; + if (isdigit(a)) { + a -= '0'; + } else { + a = a - 'A' + 10; + } + + if (i & 1) { + g_array_index(*out, gchar, i >> 1) |= a; + } else { + g_array_index(*out, gchar, i >> 1) = a<<4; + } + } + if (i < len) { + g_free(out); + out = NULL; + } + + return TRUE; +} + + +gboolean +qmicli_read_pdc_configuration_type_from_string (const gchar *str, + QmiPdcConfigurationType *out) +{ + GType type; + GEnumClass *enum_class; + GEnumValue *enum_value; + + type = qmi_pdc_configuration_type_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 = (QmiPdcConfigurationType)enum_value->value; + else + g_printerr ("error: invalid configuration type value given: '%s'\n", str); + + g_type_class_unref (enum_class); + return !!enum_value; +} + +gboolean qmicli_read_radio_interface_from_string (const gchar *str, QmiNasRadioInterface *out) { @@ -522,6 +581,52 @@ qmicli_read_uint_from_string (const gchar *str, return FALSE; } +gboolean +qmicli_read_uint16_from_string (const gchar *str, + guint16 *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_MAXUINT16) { + *out = (guint16)num; + return TRUE; + } + return FALSE; +} + +gboolean +qmicli_read_uint8_from_string (const gchar *str, + guint8 *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_MAXUINT8) { + *out = (guint8)num; + return TRUE; + } + return FALSE; +} + gchar * qmicli_get_supported_messages_list (const guint8 *data, gsize len) diff --git a/src/qmicli/qmicli-helpers.h b/src/qmicli/qmicli-helpers.h index 1a2a78c..0bf9e76 100644 --- a/src/qmicli/qmicli-helpers.h +++ b/src/qmicli/qmicli-helpers.h @@ -45,6 +45,10 @@ gboolean qmicli_read_enable_disable_from_string (const gchar *str, 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_pdc_configuration_type_from_string (const gchar *str, + QmiPdcConfigurationType *out); gboolean qmicli_read_radio_interface_from_string (const gchar *str, QmiNasRadioInterface *out); gboolean qmicli_read_net_open_flags_from_string (const gchar *str, @@ -65,6 +69,10 @@ gboolean qmicli_read_non_empty_string (const gchar *str, gchar **out); gboolean qmicli_read_uint_from_string (const gchar *str, guint *out); +gboolean qmicli_read_uint16_from_string (const gchar *str, + guint16 *out); +gboolean qmicli_read_uint8_from_string (const gchar *str, + guint8 *out); gboolean qmicli_read_yes_no_from_string (const gchar *str, gboolean *out); diff --git a/src/qmicli/qmicli-pdc.c b/src/qmicli/qmicli-pdc.c new file mode 100644 index 0000000..caa2386 --- /dev/null +++ b/src/qmicli/qmicli-pdc.c @@ -0,0 +1,1407 @@ +/* -*- 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 . + * + * Copyright (C) 2013-2015 Aleksander Morgado + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "qmicli.h" +#include "qmicli-helpers.h" + +#define LOAD_CONFIG_CHUNK_SIZE 0x400 + +/* Info about config */ +typedef struct { + GArray *id; + QmiPdcConfigurationType config_type; + guint32 token; + guint32 version; + gchar *description; + guint32 total_size; +} ConfigInfo; + +/* Info about loading config */ +typedef struct { + GMappedFile *mapped_file; + GArray *checksum; + gsize offset; +} LoadConfigFileData; + +/* Context */ +typedef struct { + QmiDevice *device; + QmiClientPdc *client; + GCancellable *cancellable; + + /* local data */ + GArray *config_list; + gint configs_loaded; + GArray *active_config_id; + GArray *pending_config_id; + gboolean ids_loaded; + guint list_configs_indication_id; + guint get_selected_config_indication_id; + + LoadConfigFileData *load_config_file_data; + guint load_config_indication_id; + guint get_config_info_indication_id; + + guint set_selected_config_indication_id; + guint activate_config_indication_id; + guint deactivate_config_indication_id; + + guint token; +} Context; +static Context *ctx; + +/* Options */ +static gchar *list_configs_str; +static gchar *delete_config_str; +static gchar *activate_config_str; +static gchar *deactivate_config_str; +static gchar *load_config_str; +static gboolean noop_flag; + +static GOptionEntry entries[] = { + {"pdc-list-configs", 0, 0, G_OPTION_ARG_STRING, &list_configs_str, + "List all configs", + "[(platform|software)]"}, + {"pdc-delete-config", 0, 0, G_OPTION_ARG_STRING, &delete_config_str, + "Delete config", + "[(platform|software),ConfigId]"}, + {"pdc-activate-config", 0, 0, G_OPTION_ARG_STRING, &activate_config_str, + "Activate config", + "[(platform|software),ConfigId]"}, + {"pdc-deactivate-config", 0, 0, G_OPTION_ARG_STRING, &deactivate_config_str, + "Deactivate config", + "[(platform|software),ConfigId]"}, + {"pdc-load-config", 0, 0, G_OPTION_ARG_STRING, &load_config_str, + "Load config to device", + "[Path to config]"}, + {"pdc-noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag, + "Just allocate or release a PDC client. Use with `--client-no-release-cid' and/or `--client-cid'", + NULL}, + {NULL} +}; + +GOptionGroup * +qmicli_pdc_get_option_group ( + void) +{ + GOptionGroup *group; + + group = g_option_group_new ("pdc", + "PDC options", + "Show platform device configurations options", NULL, NULL); + g_option_group_add_entries (group, entries); + + return group; +} + +gboolean +qmicli_pdc_options_enabled ( + void) +{ + static guint n_actions = 0; + static gboolean checked = FALSE; + + if (checked) + return !!n_actions; + + n_actions = !!list_configs_str + + !!delete_config_str + + !!activate_config_str + !!deactivate_config_str + !!load_config_str + noop_flag; + + if (n_actions > 1) { + g_printerr ("error: too many PDC actions requested\n"); + exit (EXIT_FAILURE); + } + + checked = TRUE; + return !!n_actions; +} + +static Context * +context_new ( + QmiDevice * device, + QmiClientPdc * client, + GCancellable * cancellable) +{ + Context *context; + + context = g_slice_new (Context); + context->device = g_object_ref (device); + context->client = g_object_ref (client); + context->cancellable = g_object_ref (cancellable); + + context->config_list = NULL; + context->configs_loaded = 0; + context->active_config_id = NULL; + context->pending_config_id = NULL; + context->ids_loaded = FALSE; + context->list_configs_indication_id = 0; + context->get_selected_config_indication_id = 0; + + context->load_config_file_data = NULL; + context->load_config_indication_id = 0; + context->get_config_info_indication_id = 0; + + context->set_selected_config_indication_id = 0; + context->activate_config_indication_id = 0; + context->deactivate_config_indication_id = 0; + + context->token = 0; + return context; +} + +static void +context_free ( + Context * context) +{ + int i; + ConfigInfo *current_config; + + if (!context) + return; + + if (context->config_list) { + for (i = 0; i < context->config_list->len; i++) { + current_config = &g_array_index (context->config_list, ConfigInfo, i); + if (current_config->description) + g_free (current_config->description); + if (current_config->id) + g_array_unref (current_config->id); + } + g_array_unref (context->config_list); + g_signal_handler_disconnect (context->client, context->list_configs_indication_id); + g_signal_handler_disconnect (context->client, context->get_config_info_indication_id); + g_signal_handler_disconnect (context->client, context->get_selected_config_indication_id); + } + if (context->load_config_file_data) { + g_array_unref (context->load_config_file_data->checksum); + g_mapped_file_unref (context->load_config_file_data->mapped_file); + g_slice_free (LoadConfigFileData, context->load_config_file_data); + g_signal_handler_disconnect (context->client, context->load_config_indication_id); + } + if (context->client) + g_object_unref (context->client); + if (context->set_selected_config_indication_id) { + g_signal_handler_disconnect (context->client, context->set_selected_config_indication_id); + } + if (context->activate_config_indication_id) { + g_signal_handler_disconnect (context->client, context->activate_config_indication_id); + } + if (context->deactivate_config_indication_id) { + g_signal_handler_disconnect (context->client, context->deactivate_config_indication_id); + } + 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); + ctx = NULL; + qmicli_async_operation_done (operation_status); +} + +/**************************************************************************************** + * List configs + ****************************************************************************************/ +static const char * +printable_config_type ( + QmiPdcConfigurationType type) +{ + if (type == QMI_PDC_CONFIGURATION_TYPE_PLATFORM) { + return "Platform"; + } else if (type == QMI_PDC_CONFIGURATION_TYPE_SOFTWARE) { + return "Software"; + } else { + return "Unknown"; + } +} + +static char * +printable_id ( + GArray * id) +{ + if (!id) { + return g_strdup ("Id is NULL?"); + } else if (id->len == 0) { + return g_strdup ("Id is empty"); + } else { + GString *printable; + int i; + + printable = g_string_new (""); + for (i = 0; i < id->len; i++) { + guint8 ch = g_array_index (id, guint8, i); + + g_string_append_printf (printable, "%02hhX", ch); + } + return g_string_free (printable, FALSE); + } +} + +static gboolean +is_array_equals ( + GArray * a, + GArray * b) +{ + int i; + + if (a == NULL && b == NULL) { + return TRUE; + } else if (a == NULL || b == NULL) { + return FALSE; + } else if (a->len != b->len) { + return FALSE; + } + for (i = 0; i < a->len; i++) { + if (g_array_index (a, guint8, i) != g_array_index (b, guint8, i)) { + return FALSE; + } + } + + return TRUE; +} + +static const +char *status_string ( + GArray * id) +{ + if (!id) { + return "UNKNOWN"; + } else if (is_array_equals (id, ctx->active_config_id)) { + return "Active"; + } else if (is_array_equals (id, ctx->pending_config_id)) { + return "Pending"; + } + return "Inactive"; +} + +static void +print_configs ( + GArray * configs) +{ + ConfigInfo *current_config = NULL; + int i; + + g_printf ("CONFIGS: %d\n", ctx->config_list->len); + for (i = 0; i < ctx->config_list->len; i++) { + char *id_str; + + current_config = &g_array_index (ctx->config_list, ConfigInfo, i); + + g_printf ("START_CONFIG\n"); + g_printf ("Config Index : %i\n", i); + g_printf ("Description : %s\n", current_config->description); + g_printf ("Type : %s\n", printable_config_type (current_config->config_type)); + g_printf ("Size : %u\n", current_config->total_size); + g_printf ("Status : %s\n", status_string (current_config->id)); + g_printf ("Version : 0x%x\n", current_config->version); + id_str = printable_id (current_config->id); + g_printf ("ID : %s\n", id_str); + g_free (id_str); + g_printf ("END_CONFIG\n\n"); + + } +} + +static void +get_config_info_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcGetConfigInfoOutput *output; + + output = qmi_client_pdc_get_config_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_pdc_get_config_info_output_get_result (output, &error)) { + g_printerr ("error: couldn't get config info: %s\n", error->message); + g_error_free (error); + qmi_message_pdc_get_config_info_output_unref (output); + operation_shutdown (FALSE); + return; + } + + qmi_message_pdc_get_config_info_output_unref (output); +} + +static void +get_config_info_ready_indication ( + QmiClientPdc * client, + QmiIndicationPdcGetConfigInfoOutput * output) +{ + GError *error = NULL; + ConfigInfo *current_config = NULL; + guint32 token; + const gchar *description; + int i; + guint16 error_code; + + if (!qmi_indication_pdc_get_config_info_output_get_indication_result (output, + &error_code, &error)) { + g_printerr ("error: couldn't get config info: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't get config info: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + operation_shutdown (FALSE); + return; + } + + if (!qmi_indication_pdc_get_config_info_output_get_token (output, &token, &error)) { + g_printerr ("error: couldn't get config info: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + + for (i = 0; i < ctx->config_list->len; i++) { + current_config = &g_array_index (ctx->config_list, ConfigInfo, i); + if (current_config->token == token) + break; + } + + if (!qmi_indication_pdc_get_config_info_output_get_total_size (output, + ¤t_config->total_size, + &error) || + !qmi_indication_pdc_get_config_info_output_get_version (output, + ¤t_config->version, + &error) || + !qmi_indication_pdc_get_config_info_output_get_description (output, &description, &error)) { + g_printerr ("error: couldn't get config info: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + current_config->description = g_strdup (description); + + ctx->configs_loaded++; + if (ctx->configs_loaded == ctx->config_list->len && ctx->ids_loaded) { + print_configs (ctx->config_list); + operation_shutdown (TRUE); + } +} + +static void +list_configs_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcListConfigsOutput *output; + + output = qmi_client_pdc_list_configs_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_pdc_list_configs_output_get_result (output, &error)) { + g_printerr ("error: couldn't list configs: %s\n", error->message); + g_error_free (error); + qmi_message_pdc_list_configs_output_unref (output); + operation_shutdown (FALSE); + return; + } + + qmi_message_pdc_list_configs_output_unref (output); +} + +static void +list_configs_ready_indication ( + QmiClientPdc * client, + QmiIndicationPdcListConfigsOutput * output) +{ + GError *error = NULL; + GArray *configs = NULL; + int i; + guint16 error_code; + + if (!qmi_indication_pdc_list_configs_output_get_indication_result (output, &error_code, &error)) { + g_printerr ("error: couldn't list configs: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't list config: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + operation_shutdown (FALSE); + return; + } + + if (!qmi_indication_pdc_list_configs_output_get_configs (output, &configs, &error)) { + g_printerr ("error: couldn't list configs: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + + ctx->config_list = g_array_sized_new (FALSE, TRUE, sizeof (ConfigInfo), configs->len); + g_array_set_size (ctx->config_list, configs->len); + for (i = 0; i < configs->len; i++) { + ConfigInfo *current_info; + QmiIndicationPdcListConfigsOutputConfigsElement *element; + QmiConfigTypeAndId type_with_id; + QmiMessagePdcGetConfigInfoInput *input; + guint32 token = ctx->token++; + + element = &g_array_index (configs, QmiIndicationPdcListConfigsOutputConfigsElement, i); + + current_info = &g_array_index (ctx->config_list, ConfigInfo, i); + + input = qmi_message_pdc_get_config_info_input_new (); + current_info->token = token; + current_info->id = g_array_ref (element->id); + current_info->config_type = element->config_type; + type_with_id.config_type = element->config_type; + type_with_id.id = current_info->id; + g_printerr ("Fetching config type: %d\n", current_info->config_type); + if (!qmi_message_pdc_get_config_info_input_set_type_with_id (input, &type_with_id, &error)) { + g_printerr ("error: couldn't set type with id: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + if (!qmi_message_pdc_get_config_info_input_set_token (input, token, &error)) { + g_printerr ("error: couldn't set token: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + + qmi_client_pdc_get_config_info (ctx->client, + input, + 10, + ctx->cancellable, + (GAsyncReadyCallback) get_config_info_ready, NULL); + + } + + g_print ("Loaded configs: %d\n", ctx->config_list->len); + if (ctx->configs_loaded == ctx->config_list->len && ctx->ids_loaded) { + print_configs (ctx->config_list); + operation_shutdown (TRUE); + } +} + +static void +get_selected_config_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcGetSelectedConfigOutput *output; + + output = qmi_client_pdc_get_selected_config_finish (client, res, &error); + + if (!qmi_message_pdc_get_selected_config_output_get_result (output, &error)) { + g_printerr ("error: couldn't get selected config: %s\n", error->message); + g_error_free (error); + qmi_message_pdc_get_selected_config_output_unref (output); + operation_shutdown (FALSE); + return; + } + + qmi_message_pdc_get_selected_config_output_unref (output); +} + +static void +get_selected_config_ready_indication ( + QmiClientPdc * client, + QmiIndicationPdcGetSelectedConfigOutput * output) +{ + GArray *pending_id = NULL; + GArray *active_id = NULL; + GError *error = NULL; + guint16 error_code; + + if (!qmi_indication_pdc_get_selected_config_output_get_indication_result (output, + &error_code, + &error)) { + g_printerr ("error: couldn't get selected config: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't get selected config: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + } + + qmi_indication_pdc_get_selected_config_output_get_pending_id (output, &pending_id, NULL); + qmi_indication_pdc_get_selected_config_output_get_active_id (output, &active_id, NULL); + if (active_id) { + ctx->active_config_id = g_array_ref (active_id); + } + if (pending_id) { + ctx->pending_config_id = g_array_ref (pending_id); + } + + ctx->ids_loaded = TRUE; + if (ctx->configs_loaded == ctx->config_list->len && ctx->ids_loaded) { + print_configs (ctx->config_list); + operation_shutdown (TRUE); + } +} + +static void +activate_config_ready_indication ( + QmiClientPdc * client, + QmiIndicationPdcActivateConfigOutput * output) +{ + GError *error = NULL; + guint16 error_code; + + if (!qmi_indication_pdc_activate_config_output_get_indication_result (output, + &error_code, &error)) { + g_printerr ("error: couldn't activate config: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't activate config: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + operation_shutdown (FALSE); + } + + operation_shutdown (TRUE); +} + +static void +deactivate_config_ready_indication ( + QmiClientPdc * client, + QmiIndicationPdcDeactivateConfigOutput * output) +{ + GError *error = NULL; + guint16 error_code; + + if (!qmi_indication_pdc_deactivate_config_output_get_indication_result (output, + &error_code, &error)) { + g_printerr ("error: couldn't deactivate config: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't deactivate config: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + operation_shutdown (FALSE); + } + + operation_shutdown (TRUE); +} + +static QmiMessagePdcListConfigsInput * +list_configs_input_create ( + const gchar * str) +{ + QmiMessagePdcListConfigsInput *input = NULL; + QmiPdcConfigurationType configType; + + if (qmicli_read_pdc_configuration_type_from_string (str, &configType)) { + GError *error = NULL; + + input = qmi_message_pdc_list_configs_input_new (); + if (!qmi_message_pdc_list_configs_input_set_config_type (input, configType, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_list_configs_input_unref (input); + input = NULL; + } + if (!qmi_message_pdc_list_configs_input_set_token (input, ctx->token++, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_list_configs_input_unref (input); + input = NULL; + } + + } + + return input; +} + +/**************************************************************************************** + * Activate and deactivate configs + ****************************************************************************************/ +static QmiConfigTypeAndId * +parse_type_and_id ( + const gchar * str) +{ + GArray *id = NULL; + int num_parts; + gchar **substrings = g_strsplit (str, ",", -1); + QmiPdcConfigurationType config_type; + QmiConfigTypeAndId *result = NULL; + + for (num_parts = 0; substrings[num_parts]; num_parts++) ; + if (num_parts != 2) { + g_printerr ("Expected 2 parameters, but found: '%d'\n", num_parts); + g_strfreev (substrings); + return NULL; + } + + if (!qmicli_read_pdc_configuration_type_from_string (substrings[0], &config_type)) { + g_printerr ("Incorrect id specified: %s\n", substrings[0]); + g_strfreev (substrings); + return NULL; + } + + if (!qmicli_read_binary_array_from_string (substrings[1], &id)) { + g_printerr ("Incorrect config type specified: %s\n", substrings[1]); + g_strfreev (substrings); + return NULL; + } + + result = g_slice_new0 (QmiConfigTypeAndId); + if (!result) { + g_printerr ("Error allocating QmiConfigTypeAndId\n"); + g_strfreev (substrings); + g_array_unref (id); + return NULL; + } + result->config_type = config_type; + result->id = id; + + return result; +} + +static QmiMessagePdcGetSelectedConfigInput * +get_selected_config_input_create ( + const gchar * str) +{ + QmiMessagePdcGetSelectedConfigInput *input = NULL; + QmiPdcConfigurationType configType; + + if (qmicli_read_pdc_configuration_type_from_string (str, &configType)) { + GError *error = NULL; + + input = qmi_message_pdc_get_selected_config_input_new (); + if (!qmi_message_pdc_get_selected_config_input_set_config_type (input, configType, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_get_selected_config_input_unref (input); + input = NULL; + } + if (!qmi_message_pdc_get_selected_config_input_set_token (input, ctx->token++, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_get_selected_config_input_unref (input); + input = NULL; + } + + } + + return input; +} + +static QmiMessagePdcDeleteConfigInput * +delete_config_input_create ( + const gchar * str) +{ + QmiMessagePdcDeleteConfigInput *input = NULL; + QmiConfigTypeAndId *type_and_id; + + type_and_id = parse_type_and_id (str); + + if (type_and_id) { + GError *error = NULL; + + input = qmi_message_pdc_delete_config_input_new (); + if (!qmi_message_pdc_delete_config_input_set_config_type (input, + type_and_id->config_type, + &error) || + !qmi_message_pdc_delete_config_input_set_token (input, + ctx->token++, + &error) || + !qmi_message_pdc_delete_config_input_set_id (input, type_and_id->id, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + g_free (type_and_id); + qmi_message_pdc_delete_config_input_unref (input); + input = NULL; + } + g_slice_free (QmiConfigTypeAndId, type_and_id); + } + + return input; +} + +static void +delete_config_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcDeleteConfigOutput *output; + + output = qmi_client_pdc_delete_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_pdc_delete_config_output_get_result (output, &error)) { + g_printerr ("error: couldn't delete config: %s\n", error->message); + g_error_free (error); + qmi_message_pdc_delete_config_output_unref (output); + operation_shutdown (FALSE); + return; + } + + operation_shutdown (TRUE); + qmi_message_pdc_delete_config_output_unref (output); +} + +static QmiMessagePdcActivateConfigInput * +activate_config_input_create ( + const gchar * str) +{ + QmiMessagePdcActivateConfigInput *input = NULL; + QmiConfigTypeAndId *type_and_id; + + type_and_id = parse_type_and_id (str); + + if (type_and_id) { + GError *error = NULL; + + input = qmi_message_pdc_activate_config_input_new (); + if (!qmi_message_pdc_activate_config_input_set_config_type (input, + type_and_id->config_type, + &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_activate_config_input_unref (input); + g_free (type_and_id); + input = NULL; + } + if (!qmi_message_pdc_activate_config_input_set_token (input, ctx->token++, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_activate_config_input_unref (input); + g_free (type_and_id); + input = NULL; + } + } + + return input; +} + +static void +activate_config_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcActivateConfigOutput *output; + + output = qmi_client_pdc_activate_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_pdc_activate_config_output_get_result (output, &error)) { + g_printerr ("error: couldn't activate config: %s\n", error->message); + g_error_free (error); + qmi_message_pdc_activate_config_output_unref (output); + operation_shutdown (FALSE); + return; + } + + qmi_message_pdc_activate_config_output_unref (output); +} + +static void +deactivate_config_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcDeactivateConfigOutput *output; + + output = qmi_client_pdc_deactivate_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_pdc_deactivate_config_output_get_result (output, &error)) { + g_printerr ("error: couldn't activate config: %s\n", error->message); + g_error_free (error); + qmi_message_pdc_deactivate_config_output_unref (output); + operation_shutdown (FALSE); + return; + } + + qmi_message_pdc_deactivate_config_output_unref (output); +} + +static void +set_selected_config_ready_indication_activation ( + QmiClientPdc * client, + QmiIndicationPdcSetSelectedConfigOutput * output) +{ + GError *error = NULL; + QmiMessagePdcActivateConfigInput *input; + guint16 error_code; + + if (!qmi_indication_pdc_set_selected_config_output_get_indication_result (output, + &error_code, + &error)) { + g_printerr ("error: couldn't set selected config: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't set selected config: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + operation_shutdown (FALSE); + return; + } + + input = activate_config_input_create (activate_config_str); + if (!input) { + operation_shutdown (FALSE); + return; + } + qmi_client_pdc_activate_config (ctx->client, + input, + 10, + ctx->cancellable, + (GAsyncReadyCallback) activate_config_ready, NULL); + qmi_message_pdc_activate_config_input_unref (input); +} + +static void +set_selected_config_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcSetSelectedConfigOutput *output; + + output = qmi_client_pdc_set_selected_config_finish (client, res, &error); + + if (!output) { + g_printerr ("error: operation failed: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + + qmi_message_pdc_set_selected_config_output_unref (output); +} + +static QmiMessagePdcDeactivateConfigInput * +deactivate_config_input_create ( + const gchar * str) +{ + QmiMessagePdcDeactivateConfigInput *input = NULL; + QmiConfigTypeAndId *type_and_id; + + type_and_id = parse_type_and_id (str); + + if (type_and_id) { + GError *error = NULL; + + input = qmi_message_pdc_deactivate_config_input_new (); + if (!qmi_message_pdc_deactivate_config_input_set_config_type (input, + type_and_id->config_type, + &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_deactivate_config_input_unref (input); + g_free (type_and_id); + input = NULL; + } + if (!qmi_message_pdc_deactivate_config_input_set_token (input, ctx->token++, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_deactivate_config_input_unref (input); + g_free (type_and_id); + input = NULL; + } + } + + return input; +} + +static void +set_selected_config_ready_indication_deactivation ( + QmiClientPdc * client, + QmiIndicationPdcSetSelectedConfigOutput * output) +{ + GError *error = NULL; + QmiMessagePdcDeactivateConfigInput *input; + guint16 error_code; + + if (!qmi_indication_pdc_set_selected_config_output_get_indication_result (output, + &error_code, + &error)) { + g_printerr ("error: couldn't set selected config: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't set selected config: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + operation_shutdown (FALSE); + return; + } + + input = deactivate_config_input_create (activate_config_str); + if (!input) { + operation_shutdown (FALSE); + return; + } + qmi_client_pdc_deactivate_config (ctx->client, + input, + 10, + ctx->cancellable, + (GAsyncReadyCallback) deactivate_config_ready, NULL); + qmi_message_pdc_deactivate_config_input_unref (input); +} + +static QmiMessagePdcSetSelectedConfigInput * +set_selected_config_input_create ( + const gchar * str) +{ + QmiMessagePdcSetSelectedConfigInput *input = NULL; + QmiConfigTypeAndId *type_and_id; + + type_and_id = parse_type_and_id (str); + + if (type_and_id) { + GError *error = NULL; + + input = qmi_message_pdc_set_selected_config_input_new (); + if (!qmi_message_pdc_set_selected_config_input_set_type_with_id (input, + type_and_id, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + g_free (type_and_id); + qmi_message_pdc_set_selected_config_input_unref (input); + input = NULL; + } + if (!qmi_message_pdc_set_selected_config_input_set_token (input, ctx->token++, &error)) { + g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message); + g_error_free (error); + g_free (type_and_id); + qmi_message_pdc_set_selected_config_input_unref (input); + input = NULL; + } + + } + + return input; +} + +/**************************************************************************************** + * Load config + ****************************************************************************************/ + +static LoadConfigFileData * +load_config_file_from_string ( + const gchar * str) +{ + GError *error = NULL; + GMappedFile *mapped_file; + LoadConfigFileData *data; + guchar *file_contents; + GChecksum *checksum; + gsize file_size; + gsize hash_size; + + if (!(mapped_file = g_mapped_file_new (str, FALSE, &error))) { + g_printerr ("error: couldn't map config file: '%s'\n", error->message); + g_error_free (error); + return NULL; + } + + if (!(file_contents = (guchar *) g_mapped_file_get_contents (mapped_file))) { + g_printerr ("error: couldn't get file content\n"); + g_mapped_file_unref (mapped_file); + return NULL; + } + file_size = g_mapped_file_get_length (mapped_file); + hash_size = g_checksum_type_get_length (G_CHECKSUM_SHA1); + g_info ("File opened: %lu, %lu", file_size, hash_size); + checksum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (checksum, file_contents, file_size); + + data = g_slice_new (LoadConfigFileData); + data->mapped_file = mapped_file; + data->checksum = g_array_sized_new (FALSE, FALSE, sizeof (guint8), hash_size); + g_array_set_size (data->checksum, hash_size); + data->offset = 0; + g_checksum_get_digest (checksum, &g_array_index (data->checksum, guint8, 0), &hash_size); + g_info ("Checksum: %lu, %lu", file_size, hash_size); + + return data; +} + +static QmiMessagePdcLoadConfigInput * +load_config_input_create_chunk ( + LoadConfigFileData * config_file) +{ + QmiMessagePdcLoadConfigInput *input = NULL; + + if (config_file) { + GError *error = NULL; + GArray *chunk; + gsize full_size; + gsize chunk_size; + guchar *file_content; + + input = qmi_message_pdc_load_config_input_new (); + if (!qmi_message_pdc_load_config_input_set_token (input, ctx->token++, &error)) { + g_printerr ("error: couldn't set token: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_load_config_input_unref (input); + input = NULL; + } + + chunk = g_array_new (FALSE, FALSE, 1); + full_size = g_mapped_file_get_length (config_file->mapped_file); + chunk_size = config_file->offset + LOAD_CONFIG_CHUNK_SIZE > full_size ? + full_size - config_file->offset : LOAD_CONFIG_CHUNK_SIZE; + file_content = (guchar *) g_mapped_file_get_contents (config_file->mapped_file); + g_array_append_vals (chunk, file_content + config_file->offset, chunk_size); + g_print ("Uploaded %lu of %lu\n", config_file->offset, full_size); + + if (!qmi_message_pdc_load_config_input_set_config_chunk (input, + QMI_PDC_CONFIGURATION_TYPE_SOFTWARE, + config_file->checksum, + g_mapped_file_get_length + (config_file->mapped_file), chunk, + &error)) { + g_printerr ("error: couldn't set chunk: '%s'\n", error->message); + g_error_free (error); + qmi_message_pdc_load_config_input_unref (input); + input = NULL; + } else { + config_file->offset += chunk_size; + } + } + return input; +} + +static QmiMessagePdcLoadConfigInput * +load_config_input_create ( + const gchar * str) +{ + LoadConfigFileData *config_file; + QmiMessagePdcLoadConfigInput *input = NULL; + + if ((config_file = load_config_file_from_string (str))) { + if ((input = load_config_input_create_chunk (config_file))) { + ctx->load_config_file_data = config_file; + } + } + + return input; +} + +static void +load_config_ready ( + QmiClientPdc * client, + GAsyncResult * res) +{ + GError *error = NULL; + QmiMessagePdcLoadConfigOutput *output; + + output = qmi_client_pdc_load_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_pdc_load_config_output_get_result (output, &error)) { + g_printerr ("error: couldn't load config: %s\n", error->message); + g_error_free (error); + qmi_message_pdc_load_config_output_unref (output); + operation_shutdown (FALSE); + return; + } + + qmi_message_pdc_load_config_output_unref (output); +} + +static void +load_config_ready_indication ( + QmiClientPdc * client, + QmiIndicationPdcLoadConfigOutput * output) +{ + GError *error = NULL; + QmiMessagePdcLoadConfigInput *input; + gboolean frame_reset; + guint32 remaining_size; + guint16 error_code; + + if (!qmi_indication_pdc_load_config_output_get_indication_result (output, &error_code, &error)) { + g_printerr ("error: couldn't load config: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } else if (error_code != 0) { + g_printerr ("error: couldn't load config: %s\n", + qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + operation_shutdown (FALSE); + return; + } + + if (qmi_indication_pdc_load_config_output_get_frame_reset (output, &frame_reset, &error)) { + if (frame_reset) { + g_printerr ("error: frame reset requested\n"); + operation_shutdown (FALSE); + return; + } + } else { + g_error_free (error); + error = NULL; + } + + if (!qmi_indication_pdc_load_config_output_get_remaining_size (output, &remaining_size, &error)) { + g_printerr ("error: couldn't load config: %s\n", error->message); + g_error_free (error); + operation_shutdown (FALSE); + return; + } + + g_print ("Remaining %d\n", remaining_size); + if (remaining_size > 0) { + g_print ("Loading next\n"); + input = load_config_input_create_chunk (ctx->load_config_file_data); + if (!input) { + g_printerr ("Input is null\n"); + operation_shutdown (FALSE); + return; + } + qmi_client_pdc_load_config (ctx->client, + input, + 10, + ctx->cancellable, + (GAsyncReadyCallback) load_config_ready, NULL); + qmi_message_pdc_load_config_input_unref (input); + } else { + operation_shutdown (TRUE); + } +} + +/**************************************************************************************** + * Common logic + ****************************************************************************************/ + +static gboolean +noop_cb ( + gpointer unused) +{ + operation_shutdown (TRUE); + return FALSE; +} + +void +qmicli_pdc_run ( + QmiDevice * device, + QmiClientPdc * client, + GCancellable * cancellable) +{ + /* Initialize context */ + ctx = context_new (device, client, cancellable); + + /* Request to get all configs */ + if (list_configs_str) { + QmiMessagePdcListConfigsInput *input; + QmiMessagePdcGetSelectedConfigInput *get_selected_config_input; + + g_debug ("Listing configs asynchroniously..."); + ctx->list_configs_indication_id = g_signal_connect (client, + "list-configs", + G_CALLBACK + (list_configs_ready_indication), NULL); + ctx->get_selected_config_indication_id = + g_signal_connect (client, "get-selected-config", + G_CALLBACK (get_selected_config_ready_indication), NULL); + ctx->get_config_info_indication_id = + g_signal_connect (client, "get-config-info", + G_CALLBACK (get_config_info_ready_indication), NULL); + input = list_configs_input_create (list_configs_str); + if (!input) { + operation_shutdown (FALSE); + return; + } + get_selected_config_input = get_selected_config_input_create (list_configs_str); + if (!get_selected_config_input) { + operation_shutdown (FALSE); + return; + } + + qmi_client_pdc_list_configs (ctx->client, + input, + 10, + ctx->cancellable, + (GAsyncReadyCallback) list_configs_ready, NULL); + qmi_message_pdc_list_configs_input_unref (input); + + qmi_client_pdc_get_selected_config (ctx->client, + get_selected_config_input, + 10, + ctx->cancellable, + (GAsyncReadyCallback) get_selected_config_ready, NULL); + qmi_message_pdc_get_selected_config_input_unref (get_selected_config_input); + return; + } + + /* Request to delete config */ + if (delete_config_str) { + QmiMessagePdcDeleteConfigInput *input; + + g_debug ("Deleting config asynchroniously..."); + input = delete_config_input_create (delete_config_str); + if (!input) { + operation_shutdown (FALSE); + return; + } + qmi_client_pdc_delete_config (ctx->client, + input, + 10, + ctx->cancellable, + (GAsyncReadyCallback) delete_config_ready, NULL); + qmi_message_pdc_delete_config_input_unref (input); + return; + } + + /* Request to activate config */ + if (activate_config_str) { + QmiMessagePdcSetSelectedConfigInput *input; + + g_debug ("Activating config asynchroniously..."); + input = set_selected_config_input_create (activate_config_str); + if (!input) { + operation_shutdown (FALSE); + return; + } + ctx->set_selected_config_indication_id = + g_signal_connect (client, + "set-selected-config", + G_CALLBACK (set_selected_config_ready_indication_activation), NULL); + ctx->activate_config_indication_id = g_signal_connect (client, + "activate-config", + G_CALLBACK + (activate_config_ready_indication), + NULL); + qmi_client_pdc_set_selected_config (ctx->client, input, 10, ctx->cancellable, + (GAsyncReadyCallback) set_selected_config_ready, NULL); + qmi_message_pdc_set_selected_config_input_unref (input); + return; + } + + /* Request to deactivate config */ + if (deactivate_config_str) { + QmiMessagePdcSetSelectedConfigInput *input; + + g_debug ("Deactivating config asynchroniously..."); + input = set_selected_config_input_create (activate_config_str); + if (!input) { + operation_shutdown (FALSE); + return; + } + ctx->set_selected_config_indication_id = + g_signal_connect (client, + "set-selected-config", + G_CALLBACK (set_selected_config_ready_indication_deactivation), NULL); + ctx->deactivate_config_indication_id = g_signal_connect (client, + "deactivate-config", + G_CALLBACK + (deactivate_config_ready_indication), + NULL); + qmi_client_pdc_set_selected_config (ctx->client, input, 10, ctx->cancellable, + (GAsyncReadyCallback) set_selected_config_ready, NULL); + qmi_message_pdc_set_selected_config_input_unref (input); + return; + } + + if (load_config_str) { + QmiMessagePdcLoadConfigInput *input; + + g_debug ("Loading config asynchroniously..."); + input = load_config_input_create (load_config_str); + if (!input) { + operation_shutdown (FALSE); + return; + } + ctx->load_config_indication_id = g_signal_connect (client, + "load-config", + G_CALLBACK + (load_config_ready_indication), NULL); + qmi_client_pdc_load_config (ctx->client, input, 10, ctx->cancellable, + (GAsyncReadyCallback) load_config_ready, NULL); + qmi_message_pdc_load_config_input_unref (input); + return; + } + + /* Just client allocate/release? */ + if (noop_flag) { + g_idle_add (noop_cb, NULL); + return; + } + + g_warn_if_reached (); +} diff --git a/src/qmicli/qmicli.c b/src/qmicli/qmicli.c index 85c2faa..a7902bf 100644 --- a/src/qmicli/qmicli.c +++ b/src/qmicli/qmicli.c @@ -321,6 +321,9 @@ allocate_client_ready (QmiDevice *dev, case QMI_SERVICE_PBM: qmicli_pbm_run (dev, QMI_CLIENT_PBM (client), cancellable); return; + case QMI_SERVICE_PDC: + qmicli_pdc_run (dev, QMI_CLIENT_PDC (client), cancellable); + return; case QMI_SERVICE_UIM: qmicli_uim_run (dev, QMI_CLIENT_UIM (client), cancellable); return; @@ -653,6 +656,12 @@ parse_actions (void) actions_enabled++; } + /* PDC options? */ + if (qmicli_pdc_options_enabled ()) { + service = QMI_SERVICE_PDC; + actions_enabled++; + } + /* UIM options? */ if (qmicli_uim_options_enabled ()) { service = QMI_SERVICE_UIM; @@ -713,6 +722,8 @@ int main (int argc, char **argv) g_option_context_add_group (context, qmicli_pbm_get_option_group ()); g_option_context_add_group (context, + qmicli_pdc_get_option_group ()); + g_option_context_add_group (context, qmicli_uim_get_option_group ()); g_option_context_add_group (context, qmicli_wms_get_option_group ()); diff --git a/src/qmicli/qmicli.h b/src/qmicli/qmicli.h index 6ba7ec9..2cc7d28 100644 --- a/src/qmicli/qmicli.h +++ b/src/qmicli/qmicli.h @@ -54,6 +54,13 @@ void qmicli_pbm_run (QmiDevice *device, QmiClientPbm *client, GCancellable *cancellable); +/* PBM group */ +GOptionGroup *qmicli_pdc_get_option_group (void); +gboolean qmicli_pdc_options_enabled (void); +void qmicli_pdc_run (QmiDevice *device, + QmiClientPdc *client, + GCancellable *cancellable); + /* UIM group */ GOptionGroup *qmicli_uim_get_option_group (void); gboolean qmicli_uim_options_enabled (void); -- 2.8.0.rc3.226.g39d4020