summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-10-10 19:49:21 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-10-10 21:14:48 +0200
commit13b53c6a1d196101779de19af0e4000c87489030 (patch)
tree753d01527d6211616894aaa32e3c51e60d97592a
parent5e1507472d695a6add54ca257a0aef740ee434ec (diff)
libqmi-glib,qmi-codegen: timed out operations will issue an ABORT message
Messages can now be tagged with a special 'abort' keyword, so that whenever the message times out we issue a new ABORT command to cancel the specific timed out request. This support is currently only available for the NAS and WDS services, which are the ones supporting ABORT for their long-running operations.
-rw-r--r--build-aux/qmi-codegen/Client.py112
-rw-r--r--build-aux/qmi-codegen/Container.py47
-rw-r--r--build-aux/qmi-codegen/Field.py18
-rw-r--r--build-aux/qmi-codegen/Message.py10
-rw-r--r--data/qmi-service-nas.json15
-rw-r--r--data/qmi-service-wds.json15
-rw-r--r--libqmi-glib/generated/Makefile.am3
7 files changed, 179 insertions, 41 deletions
diff --git a/build-aux/qmi-codegen/Client.py b/build-aux/qmi-codegen/Client.py
index 5aa9478..06b5aa7 100644
--- a/build-aux/qmi-codegen/Client.py
+++ b/build-aux/qmi-codegen/Client.py
@@ -261,14 +261,20 @@ class Client:
Emits the async methods for each known request/response
"""
def __emit_methods(self, hfile, cfile, message_list):
- translations = { 'underscore' : utils.build_underscore_name(self.name),
- 'camelcase' : utils.build_camelcase_name (self.name) }
+ translations = { 'underscore' : utils.build_underscore_name(self.name),
+ 'camelcase' : utils.build_camelcase_name (self.name),
+ 'service_lowercase' : string.lower(self.service),
+ 'service_uppercase' : string.upper(self.service),
+ 'service_camelcase' : string.capwords(self.service) }
for message in message_list.list:
if message.type == 'Indication':
continue
+ if message.static:
+ continue
+
translations['message_name'] = message.name
translations['message_underscore'] = utils.build_underscore_name(message.name)
translations['message_fullname_underscore'] = utils.build_underscore_name(message.fullname)
@@ -306,11 +312,11 @@ class Client:
' * ${underscore}_${message_underscore}_finish:\n'
' * @self: a #${camelcase}.\n'
' * @res: the #GAsyncResult obtained from the #GAsyncReadyCallback passed to ${underscore}_${message_underscore}().\n'
- ' * @error: Return location for error or %%NULL.\n'
+ ' * @error: Return location for error or %NULL.\n'
' *\n'
' * Finishes an async operation started with ${underscore}_${message_underscore}().\n'
' *\n'
- ' * Returns: a #${output_camelcase}, or %%NULL if @error is set. The returned value should be freed with ${output_underscore}_unref().\n'
+ ' * Returns: a #${output_camelcase}, or %NULL if @error is set. The returned value should be freed with ${output_underscore}_unref().\n'
' */\n'
'${output_camelcase} *\n'
'${underscore}_${message_underscore}_finish (\n'
@@ -322,7 +328,35 @@ class Client:
' return NULL;\n'
'\n'
' return ${output_underscore}_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));\n'
- '}\n'
+ '}\n')
+
+ if message.abort:
+ template += (
+ '\n'
+ 'static void\n'
+ '${message_underscore}_abort_ready (\n'
+ ' QmiDevice *device,\n'
+ ' GAsyncResult *res)\n'
+ '{\n'
+ ' GError *error = NULL;\n'
+ ' QmiMessage *reply;\n'
+ ' QmiMessage${service_camelcase}AbortOutput *output;\n'
+ '\n'
+ ' reply = qmi_device_command_finish (device, res, &error);\n'
+ ' if (reply) {\n'
+ ' output = __qmi_message_${service_lowercase}_abort_response_parse (reply, &error);\n'
+ ' if (output)\n'
+ ' qmi_message_${service_lowercase}_abort_output_unref (output);\n'
+ ' qmi_message_unref (reply);\n'
+ ' }\n'
+ '\n'
+ ' if (error) {\n'
+ ' g_debug ("Operation to abort \'${message_name}\' failed: %s", error->message);\n'
+ ' g_error_free (error);\n'
+ ' }\n'
+ '}\n')
+
+ template += (
'\n'
'static void\n'
'${message_underscore}_ready (\n'
@@ -335,7 +369,47 @@ class Client:
' ${output_camelcase} *output;\n'
'\n'
' reply = qmi_device_command_finish (device, res, &error);\n'
- ' if (!reply) {\n'
+ ' if (!reply) {\n')
+
+ if message.abort:
+ template += (
+ ' if (g_error_matches (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TIMEOUT)) {\n'
+ ' QmiMessage *abort;\n'
+ ' GObject *self;\n'
+ ' guint16 transaction_id;\n'
+ ' QmiMessage${service_camelcase}AbortInput *input;\n'
+ '\n'
+ ' self = g_async_result_get_source_object (G_ASYNC_RESULT (simple));\n'
+ ' g_assert (self != NULL);\n'
+ '\n'
+ ' transaction_id = (guint16) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (simple),\n'
+ ' "transaction-id"));\n'
+ ' g_assert (transaction_id != 0);\n'
+ '\n'
+ ' input = qmi_message_${service_lowercase}_abort_input_new ();\n'
+ ' qmi_message_${service_lowercase}_abort_input_set_transaction_id (\n'
+ ' input,\n'
+ ' transaction_id,\n'
+ ' NULL);\n'
+ ' abort = __qmi_message_${service_lowercase}_abort_request_create (\n'
+ ' qmi_client_get_next_transaction_id (QMI_CLIENT (self)),\n'
+ ' qmi_client_get_cid (QMI_CLIENT (self)),\n'
+ ' input,\n'
+ ' NULL);\n'
+ ' g_assert (abort != NULL);\n'
+ ' qmi_device_command (device,\n'
+ ' abort,\n'
+ ' 30,\n'
+ ' NULL,\n'
+ ' (GAsyncReadyCallback)${message_underscore}_abort_ready,\n'
+ ' NULL);\n'
+ ' qmi_message_${service_lowercase}_abort_input_unref (input);\n'
+ ' qmi_message_unref (abort);\n'
+ ' g_object_unref (self);\n'
+ ' }\n'
+ '\n')
+
+ template += (
' g_simple_async_result_take_error (simple, error);\n'
' g_simple_async_result_complete (simple);\n'
' g_object_unref (simple);\n'
@@ -360,7 +434,7 @@ class Client:
' * @self: a #${camelcase}.\n'
' * @${input_doc}\n'
' * @timeout: maximum time to wait for the method to complete, in seconds.\n'
- ' * @cancellable: a #GCancellable or %%NULL.\n'
+ ' * @cancellable: a #GCancellable or %NULL.\n'
' * @callback: a #GAsyncReadyCallback to call when the request is satisfied.\n'
' * @user_data: user data to pass to @callback.\n'
' *\n'
@@ -372,8 +446,10 @@ class Client:
' */\n'
'void\n'
'${underscore}_${message_underscore} (\n'
- ' ${camelcase} *self,\n'
- ' %s,\n'
+ ' ${camelcase} *self,\n')
+ template += (
+ ' %s,\n' % input_arg_template)
+ template += (
' guint timeout,\n'
' GCancellable *cancellable,\n'
' GAsyncReadyCallback callback,\n'
@@ -382,14 +458,17 @@ class Client:
' GSimpleAsyncResult *result;\n'
' QmiMessage *request;\n'
' GError *error = NULL;\n'
+ ' guint16 transaction_id;\n'
'\n'
' result = g_simple_async_result_new (G_OBJECT (self),\n'
' callback,\n'
' user_data,\n'
' ${underscore}_${message_underscore});\n'
'\n'
+ ' transaction_id = qmi_client_get_next_transaction_id (QMI_CLIENT (self));\n'
+ '\n'
' request = __${message_fullname_underscore}_request_create (\n'
- ' qmi_client_get_next_transaction_id (QMI_CLIENT (self)),\n'
+ ' transaction_id,\n'
' qmi_client_get_cid (QMI_CLIENT (self)),\n'
' ${input_var},\n'
' &error);\n'
@@ -399,7 +478,16 @@ class Client:
' g_simple_async_result_complete_in_idle (result);\n'
' g_object_unref (result);\n'
' return;\n'
- ' }\n'
+ ' }\n')
+
+ if message.abort:
+ template += (
+ '\n'
+ ' g_object_set_data (G_OBJECT (result),\n'
+ ' "transaction-id",\n'
+ ' GUINT_TO_POINTER (transaction_id));\n')
+
+ template += (
'\n'
' qmi_device_command (QMI_DEVICE (qmi_client_peek_device (QMI_CLIENT (self))),\n'
' request,\n'
@@ -409,7 +497,7 @@ class Client:
' result);\n'
' qmi_message_unref (request);\n'
'}\n'
- '\n' % input_arg_template)
+ '\n')
cfile.write(string.Template(template).substitute(translations))
diff --git a/build-aux/qmi-codegen/Container.py b/build-aux/qmi-codegen/Container.py
index f15e6b1..d7488f1 100644
--- a/build-aux/qmi-codegen/Container.py
+++ b/build-aux/qmi-codegen/Container.py
@@ -33,7 +33,7 @@ class Container:
"""
Constructor
"""
- def __init__(self, prefix, container_type, dictionary, common_objects_dictionary):
+ def __init__(self, prefix, container_type, dictionary, common_objects_dictionary, static):
# The field container prefix usually contains the name of the Message,
# e.g. "Qmi Message Ctl Something"
self.prefix = prefix
@@ -48,6 +48,8 @@ class Container:
self.name = container_type
+ self.static = static
+
# Create the composed full name (prefix + name),
# e.g. "Qmi Message Ctl Something Output"
self.fullname = self.prefix + ' ' + self.name
@@ -88,9 +90,9 @@ class Container:
if field_dictionary['type'] == 'TLV':
if field_dictionary['format'] == 'struct' and \
field_dictionary['name'] == 'Result':
- self.fields.append(FieldResult(self.fullname, field_dictionary, common_objects_dictionary, container_type))
+ self.fields.append(FieldResult(self.fullname, field_dictionary, common_objects_dictionary, container_type, static))
else:
- self.fields.append(Field(self.fullname, field_dictionary, common_objects_dictionary, container_type))
+ self.fields.append(Field(self.fullname, field_dictionary, common_objects_dictionary, container_type, static))
"""
@@ -124,7 +126,7 @@ class Container:
' * using the provided API.\n'
' */\n'
'typedef struct _${camelcase} ${camelcase};\n'
- 'GType ${underscore}_get_type (void) G_GNUC_CONST;\n'
+ '${static}GType ${underscore}_get_type (void) G_GNUC_CONST;\n'
'#define ${type_macro} (${underscore}_get_type ())\n')
hfile.write(string.Template(template).substitute(translations))
@@ -159,17 +161,21 @@ class Container:
# Emit container core header
template = (
'\n'
- '${camelcase} *${underscore}_ref (${camelcase} *self);\n'
- 'void ${underscore}_unref (${camelcase} *self);\n')
+ '${static}${camelcase} *${underscore}_ref (${camelcase} *self);\n'
+ '${static}void ${underscore}_unref (${camelcase} *self);\n')
if self.readonly == False:
template += (
- '${camelcase} *${underscore}_new (void);\n')
- hfile.write(string.Template(template).substitute(translations))
+ '${static}${camelcase} *${underscore}_new (void);\n')
+
+ if self.static:
+ cfile.write(string.Template(template).substitute(translations))
+ else:
+ hfile.write(string.Template(template).substitute(translations))
# Emit container core source
template = (
'\n'
- 'GType\n'
+ '${static}GType\n'
'${underscore}_get_type (void)\n'
'{\n'
' static volatile gsize g_define_type_id__volatile = 0;\n'
@@ -194,7 +200,7 @@ class Container:
' *\n'
' * Returns: the new reference to @self.\n'
' */\n'
- '${camelcase} *\n'
+ '${static}${camelcase} *\n'
'${underscore}_ref (${camelcase} *self)\n'
'{\n'
' g_return_val_if_fail (self != NULL, NULL);\n'
@@ -210,7 +216,7 @@ class Container:
' * Atomically decrements the reference count of @self by one.\n'
' * If the reference count drops to 0, @self is completely disposed.\n'
' */\n'
- 'void\n'
+ '${static}void\n'
'${underscore}_unref (${camelcase} *self)\n'
'{\n'
' g_return_if_fail (self != NULL);\n'
@@ -241,7 +247,7 @@ class Container:
' *\n'
' * Returns: the newly created #${camelcase}. The returned value should be freed with ${underscore}_unref().\n'
' */\n'
- '${camelcase} *\n'
+ '${static}${camelcase} *\n'
'${underscore}_new (void)\n'
'{\n'
' ${camelcase} *self;\n'
@@ -259,12 +265,15 @@ class Container:
def emit(self, hfile, cfile):
translations = { 'name' : self.name,
'camelcase' : utils.build_camelcase_name (self.fullname),
- 'underscore' : utils.build_underscore_name (self.fullname) }
+ 'underscore' : utils.build_underscore_name (self.fullname),
+ 'static' : 'static ' if self.static else '' }
+
+ auxfile = cfile if self.static else hfile
if self.fields is None:
template = ('\n'
'/* Note: no fields in the ${name} container */\n')
- hfile.write(string.Template(template).substitute(translations))
+ auxfile.write(string.Template(template).substitute(translations))
cfile.write(string.Template(template).substitute(translations))
return
@@ -272,8 +281,8 @@ class Container:
# Emit field getter/setter
if self.fields is not None:
for field in self.fields:
- field.emit_types(hfile, cfile)
- self.__emit_types(hfile, cfile, translations)
+ field.emit_types(auxfile, cfile)
+ self.__emit_types(auxfile, cfile, translations)
# Emit TLV enums
self.__emit_tlv_ids_enum(cfile)
@@ -281,12 +290,12 @@ class Container:
# Emit fields
if self.fields is not None:
for field in self.fields:
- field.emit_getter(hfile, cfile)
+ field.emit_getter(auxfile, cfile)
if self.readonly == False:
- field.emit_setter(hfile, cfile)
+ field.emit_setter(auxfile, cfile)
# Emit the container core
- self.__emit_core(hfile, cfile, translations)
+ self.__emit_core(auxfile, cfile, translations)
"""
diff --git a/build-aux/qmi-codegen/Field.py b/build-aux/qmi-codegen/Field.py
index 1faff41..31005b3 100644
--- a/build-aux/qmi-codegen/Field.py
+++ b/build-aux/qmi-codegen/Field.py
@@ -32,7 +32,7 @@ class Field:
"""
Constructor
"""
- def __init__(self, prefix, dictionary, common_objects_dictionary, container_type):
+ def __init__(self, prefix, dictionary, common_objects_dictionary, container_type, static):
# The field prefix, usually the name of the Container,
# e.g. "Qmi Message Ctl Something Output"
self.prefix = prefix
@@ -46,6 +46,8 @@ class Field:
self.type = dictionary['type']
# The container type, which must be either "Input" or "Output"
self.container_type = container_type
+ # Whether the whole field is internally used only
+ self.static = static
# Create the composed full name (prefix + name),
# e.g. "Qmi Message Ctl Something Output Result"
@@ -105,12 +107,13 @@ class Field:
'variable_getter_imp' : variable_getter_imp,
'underscore' : utils.build_underscore_name(self.name),
'prefix_camelcase' : utils.build_camelcase_name(self.prefix),
- 'prefix_underscore' : utils.build_underscore_name(self.prefix) }
+ 'prefix_underscore' : utils.build_underscore_name(self.prefix),
+ 'static' : 'static ' if self.static else '' }
# Emit the getter header
template = (
'\n'
- 'gboolean ${prefix_underscore}_get_${underscore} (\n'
+ '${static}gboolean ${prefix_underscore}_get_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
'${variable_getter_dec}'
' GError **error);\n')
@@ -129,7 +132,7 @@ class Field:
' *\n'
' * Returns: %TRUE if the field is found, %FALSE otherwise.\n'
' */\n'
- 'gboolean\n'
+ '${static}gboolean\n'
'${prefix_underscore}_get_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
'${variable_getter_dec}'
@@ -168,12 +171,13 @@ class Field:
'variable_setter_imp' : variable_setter_imp,
'underscore' : utils.build_underscore_name(self.name),
'prefix_camelcase' : utils.build_camelcase_name(self.prefix),
- 'prefix_underscore' : utils.build_underscore_name(self.prefix) }
+ 'prefix_underscore' : utils.build_underscore_name(self.prefix),
+ 'static' : 'static ' if self.static else '' }
# Emit the setter header
template = (
'\n'
- 'gboolean ${prefix_underscore}_set_${underscore} (\n'
+ '${static}gboolean ${prefix_underscore}_set_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
'${variable_setter_dec}'
' GError **error);\n')
@@ -192,7 +196,7 @@ class Field:
' *\n'
' * Returns: %TRUE if @value was successfully set, %FALSE otherwise.\n'
' */\n'
- 'gboolean\n'
+ '${static}gboolean\n'
'${prefix_underscore}_set_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
'${variable_setter_dec}'
diff --git a/build-aux/qmi-codegen/Message.py b/build-aux/qmi-codegen/Message.py
index 57b33ef..5b35cf7 100644
--- a/build-aux/qmi-codegen/Message.py
+++ b/build-aux/qmi-codegen/Message.py
@@ -42,6 +42,8 @@ class Message:
self.type = dictionary['type']
# The version info, optional
self.version_info = dictionary['version'].split('.') if 'version' in dictionary else []
+ self.static = True if 'scope' in dictionary and dictionary['scope'] == 'library-only' else False
+ self.abort = True if 'abort' in dictionary and dictionary['abort'] == 'yes' else False
# The message prefix
self.prefix = 'Qmi ' + self.type
@@ -61,7 +63,8 @@ class Message:
self.output = Container(self.fullname,
'Output',
dictionary['output'] if 'output' in dictionary else None,
- common_objects_dictionary)
+ common_objects_dictionary,
+ self.static)
self.input = None
if self.type == 'Message':
@@ -72,7 +75,8 @@ class Message:
self.input = Container(self.fullname,
'Input',
dictionary['input'] if 'input' in dictionary else None,
- common_objects_dictionary)
+ common_objects_dictionary,
+ self.static)
"""
@@ -400,6 +404,8 @@ class Message:
Emit the sections
"""
def emit_sections(self, sfile):
+ if self.static:
+ return
translations = { 'hyphened' : utils.build_dashed_name (self.fullname),
'fullname_underscore' : utils.build_underscore_name(self.fullname),
diff --git a/data/qmi-service-nas.json b/data/qmi-service-nas.json
index e6b8e2b..c3b70ec 100644
--- a/data/qmi-service-nas.json
+++ b/data/qmi-service-nas.json
@@ -25,6 +25,21 @@
"output" : [ { "common-ref" : "Operation Result" } ] },
// *********************************************************************************
+ { "name" : "Abort",
+ "type" : "Message",
+ "service" : "NAS",
+ "id" : "0x0001",
+ "version" : "1.0",
+ // This magic tag allows us to avoid creating a method in the client
+ "scope" : "library-only",
+ "input" : [ { "name" : "Transaction ID",
+ "id" : "0x01",
+ "mandatory" : "yes",
+ "type" : "TLV",
+ "format" : "guint16" } ],
+ "output" : [ { "common-ref" : "Operation Result" } ] },
+
+ // *********************************************************************************
{ "name" : "Set Event Report",
"type" : "Message",
"service" : "NAS",
diff --git a/data/qmi-service-wds.json b/data/qmi-service-wds.json
index d0d64ef..081aa87 100644
--- a/data/qmi-service-wds.json
+++ b/data/qmi-service-wds.json
@@ -21,6 +21,21 @@
"output" : [ { "common-ref" : "Operation Result" } ] },
// *********************************************************************************
+ { "name" : "Abort",
+ "type" : "Message",
+ "service" : "WDS",
+ "id" : "0x0002",
+ "version" : "1.0",
+ // This magic tag allows us to avoid creating a method in the client
+ "scope" : "library-only",
+ "input" : [ { "name" : "Transaction ID",
+ "id" : "0x01",
+ "mandatory" : "yes",
+ "type" : "TLV",
+ "format" : "guint16" } ],
+ "output" : [ { "common-ref" : "Operation Result" } ] },
+
+ // *********************************************************************************
{ "name" : "Start Network",
"type" : "Message",
"service" : "WDS",
diff --git a/libqmi-glib/generated/Makefile.am b/libqmi-glib/generated/Makefile.am
index d984ce8..f7edabc 100644
--- a/libqmi-glib/generated/Makefile.am
+++ b/libqmi-glib/generated/Makefile.am
@@ -176,7 +176,8 @@ libqmi_glib_generated_la_CPPFLAGS = \
$(LIBQMI_GLIB_CFLAGS) \
-I$(top_srcdir) \
-I$(top_srcdir)/libqmi-glib \
- -DLIBQMI_GLIB_COMPILATION
+ -DLIBQMI_GLIB_COMPILATION \
+ -Wno-unused-function
libqmi_glib_generated_la_LIBADD = \
$(LIBQMI_GLIB_LIBS)