summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-05-09 20:29:21 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-07-03 16:08:53 +0200
commit4c17c33edd7e4dc8aac4e84371d8a6e8e19a4ce1 (patch)
tree6e452d0a344b2c561b94b5af3cd4762fa193fabe
parentc04af51eb260708cd36ed2cc7a97084da7d51e90 (diff)
downloadlibqmi-4c17c33edd7e4dc8aac4e84371d8a6e8e19a4ce1.tar.gz
codegen: new `qmi-codegen' build utility
It will try to generate message creator/parsers from a manually maintained JSON-encoded database.
-rw-r--r--.gitignore2
-rw-r--r--build-aux/Makefile.am3
-rw-r--r--build-aux/qmi-codegen/Client.py213
-rw-r--r--build-aux/qmi-codegen/Container.py249
-rw-r--r--build-aux/qmi-codegen/ContainerInput.py38
-rw-r--r--build-aux/qmi-codegen/ContainerOutput.py38
-rw-r--r--build-aux/qmi-codegen/Field.py225
-rw-r--r--build-aux/qmi-codegen/FieldArray.py111
-rw-r--r--build-aux/qmi-codegen/FieldBasic.py99
-rw-r--r--build-aux/qmi-codegen/FieldStruct.py121
-rw-r--r--build-aux/qmi-codegen/Makefile.am14
-rw-r--r--build-aux/qmi-codegen/Message.py180
-rw-r--r--build-aux/qmi-codegen/MessageList.py69
-rw-r--r--build-aux/qmi-codegen/Struct.py50
-rwxr-xr-xbuild-aux/qmi-codegen/qmi-codegen65
-rw-r--r--build-aux/qmi-codegen/utils.py148
-rw-r--r--configure.ac1
17 files changed, 1624 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index e972e696..5a3a095b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,5 @@ src/qmi-enum-types.c
cli/.deps
cli/.libs
cli/qmicli
+
+build-aux/qmi-codegen/*.pyc
diff --git a/build-aux/Makefile.am b/build-aux/Makefile.am
index 37dc9edb..b3696873 100644
--- a/build-aux/Makefile.am
+++ b/build-aux/Makefile.am
@@ -1,3 +1,2 @@
-SUBDIRS = templates
-
+SUBDIRS = templates qmi-codegen
diff --git a/build-aux/qmi-codegen/Client.py b/build-aux/qmi-codegen/Client.py
new file mode 100644
index 00000000..fa1bb16c
--- /dev/null
+++ b/build-aux/qmi-codegen/Client.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+from MessageList import MessageList
+import utils
+
+class Client:
+ def __init__(self, objects_dictionary):
+ self.name = None
+
+ # Loop items in the list, looking for the special 'Client' type
+ for object_dictionary in objects_dictionary:
+ if object_dictionary['type'] == 'Client':
+ self.name = object_dictionary['name']
+
+ # We NEED the Client field
+ if self.name is None:
+ raise ValueError('Missing Client field')
+
+
+ def __emit_class(self, hfile, cfile):
+ translations = { 'underscore' : utils.build_underscore_name(self.name),
+ 'no_prefix_underscore_upper' : string.upper(utils.build_underscore_name(self.name[4:])),
+ 'camelcase' : utils.build_camelcase_name (self.name) }
+
+ # Emit class header
+ template = (
+ '#define QMI_TYPE_${no_prefix_underscore_upper} (${underscore}_get_type ())\n'
+ '#define QMI_${no_prefix_underscore_upper}(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), QMI_TYPE_${no_prefix_underscore_upper}, ${camelcase}))\n'
+ '#define QMI_${no_prefix_underscore_upper}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), QMI_TYPE_${no_prefix_underscore_upper}, ${camelcase}Class))\n'
+ '#define QMI_IS_${no_prefix_underscore_upper}(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), QMI_TYPE_${no_prefix_underscore_upper}))\n'
+ '#define QMI_IS_${no_prefix_underscore_upper}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), QMI_TYPE_${no_prefix_underscore_upper}))\n'
+ '#define QMI_${no_prefix_underscore_upper}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), QMI_TYPE_${no_prefix_underscore_upper}, ${camelcase}Class))\n'
+ '\n'
+ 'typedef struct _${camelcase} ${camelcase};\n'
+ 'typedef struct _${camelcase}Class ${camelcase}Class;\n'
+ '\n'
+ 'struct _${camelcase} {\n'
+ ' QmiClient parent;\n'
+ ' gpointer priv_unused;\n'
+ '};\n'
+ '\n'
+ 'struct _${camelcase}Class {\n'
+ ' QmiClientClass parent;\n'
+ '};\n'
+ '\n'
+ 'GType ${underscore}_get_type (void);\n'
+ '\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ # Emit class source
+ template = (
+ '\n'
+ 'G_DEFINE_TYPE (${camelcase}, ${underscore}, QMI_TYPE_CLIENT);\n'
+ '\n'
+ 'static void\n'
+ '${underscore}_init (${camelcase} *self)\n'
+ '{\n'
+ '}\n'
+ '\n'
+ 'static void\n'
+ '${underscore}_class_init (${camelcase}Class *klass)\n'
+ '{\n'
+ '}\n'
+ '\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ def __emit_methods(self, hfile, cfile, message_list):
+ translations = { 'underscore' : utils.build_underscore_name(self.name),
+ 'camelcase' : utils.build_camelcase_name (self.name) }
+
+ for message in message_list.list:
+ translations['message_underscore'] = utils.build_underscore_name(message.name)
+ translations['message_fullname_underscore'] = utils.build_underscore_name(message.fullname)
+ translations['input_camelcase'] = utils.build_camelcase_name(message.input.fullname)
+ translations['output_camelcase'] = utils.build_camelcase_name(message.output.fullname)
+ translations['input_underscore'] = utils.build_underscore_name(message.input.fullname)
+ translations['output_underscore'] = utils.build_underscore_name(message.output.fullname)
+
+ if message.input.fields is None:
+ input_arg_template = 'gpointer unused'
+ translations['input_var'] = 'NULL'
+ else:
+ input_arg_template = '${input_camelcase} *input'
+ translations['input_var'] = 'input'
+ template = (
+ '\n'
+ 'void ${underscore}_${message_underscore} (\n'
+ ' ${camelcase} *self,\n'
+ ' %s,\n'
+ ' guint timeout,\n'
+ ' GCancellable *cancellable,\n'
+ ' GAsyncReadyCallback callback,\n'
+ ' gpointer user_data);\n'
+ '${output_camelcase} *${underscore}_${message_underscore}_finish (\n'
+ ' ${camelcase} *self,\n'
+ ' GAsyncResult *res,\n'
+ ' GError **error);\n' % input_arg_template)
+ hfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ '${output_camelcase} *\n'
+ '${underscore}_${message_underscore}_finish (\n'
+ ' ${camelcase} *self,\n'
+ ' GAsyncResult *res,\n'
+ ' GError **error)\n'
+ '{\n'
+ ' if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))\n'
+ ' return NULL;\n'
+ '\n'
+ ' return ${output_underscore}_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));\n'
+ '}\n'
+ '\n'
+ 'static void\n'
+ '${message_underscore}_ready (\n'
+ ' QmiDevice *device,\n'
+ ' GAsyncResult *res,\n'
+ ' GSimpleAsyncResult *simple)\n'
+ '{\n'
+ ' GError *error = NULL;\n'
+ ' QmiMessage *reply;\n'
+ ' ${output_camelcase} *output;\n'
+ '\n'
+ ' reply = qmi_device_command_finish (device, res, &error);\n'
+ ' if (!reply) {\n'
+ ' g_simple_async_result_take_error (simple, error);\n'
+ ' g_simple_async_result_complete (simple);\n'
+ ' g_object_unref (simple);\n'
+ ' return;\n'
+ ' }\n'
+ '\n'
+ ' /* Parse reply */\n'
+ ' output = ${message_fullname_underscore}_response_parse (reply, &error);\n'
+ ' if (!output)\n'
+ ' g_simple_async_result_take_error (simple, error);\n'
+ ' else\n'
+ ' g_simple_async_result_set_op_res_gpointer (simple,\n'
+ ' output,\n'
+ ' (GDestroyNotify)${output_underscore}_unref);\n'
+ ' g_simple_async_result_complete (simple);\n'
+ ' g_object_unref (simple);\n'
+ ' qmi_message_unref (reply);\n'
+ '}\n'
+ '\n'
+ 'void\n'
+ '${underscore}_${message_underscore} (\n'
+ ' ${camelcase} *self,\n'
+ ' %s,\n'
+ ' guint timeout,\n'
+ ' GCancellable *cancellable,\n'
+ ' GAsyncReadyCallback callback,\n'
+ ' gpointer user_data)\n'
+ '{\n'
+ ' GSimpleAsyncResult *result;\n'
+ ' QmiMessage *request;\n'
+ ' GError *error = NULL;\n'
+ '\n'
+ ' result = g_simple_async_result_new (G_OBJECT (self),\n'
+ ' callback,\n'
+ ' user_data,\n'
+ ' ${underscore}_${message_underscore});\n'
+ '\n'
+ ' request = ${message_fullname_underscore}_request_create (\n'
+ ' qmi_client_get_next_transaction_id (QMI_CLIENT (self)),\n'
+ ' qmi_client_get_cid (QMI_CLIENT (self)),\n'
+ ' ${input_var},\n'
+ ' &error);\n'
+ ' if (!request) {\n'
+ ' g_prefix_error (&error, "Couldn\'t create request message: ");\n'
+ ' g_simple_async_result_take_error (result, error);\n'
+ ' g_simple_async_result_complete_in_idle (result);\n'
+ ' g_object_unref (result);\n'
+ ' return;\n'
+ ' }\n'
+ '\n'
+ ' qmi_device_command (QMI_DEVICE (qmi_client_peek_device (QMI_CLIENT (self))),\n'
+ ' request,\n'
+ ' timeout,\n'
+ ' cancellable,\n'
+ ' (GAsyncReadyCallback)${message_underscore}_ready,\n'
+ ' result);\n'
+ ' qmi_message_unref (request);\n'
+ '}\n'
+ '\n' % input_arg_template)
+ cfile.write(string.Template(template).substitute(translations))
+
+ def emit(self, hfile, cfile, message_list):
+ # First, emit common class code
+ utils.add_separator(hfile, 'CLIENT', self.name);
+ utils.add_separator(cfile, 'CLIENT', self.name);
+ self.__emit_class(hfile, cfile)
+ self.__emit_methods(hfile, cfile, message_list)
diff --git a/build-aux/qmi-codegen/Container.py b/build-aux/qmi-codegen/Container.py
new file mode 100644
index 00000000..ac156914
--- /dev/null
+++ b/build-aux/qmi-codegen/Container.py
@@ -0,0 +1,249 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+import utils
+from FieldStruct import FieldStruct
+from FieldArray import FieldArray
+from FieldBasic import FieldBasic
+
+class Container:
+ """
+ The Container class takes care of handling collections of Input or
+ Output fields
+ """
+
+ def __init__(self, prefix, dictionary):
+ # The field container prefix usually contains the name of the Message,
+ # e.g. "Qmi Message Ctl Something"
+ self.prefix = prefix
+
+ # self.name needs to be set by the subclass
+ if self.name != 'Input' and self.name != 'Output':
+ raise ValueError('Cannot handle container \'%s\'' % self.name)
+
+ # Create the composed full name (prefix + name),
+ # e.g. "Qmi Message Ctl Something Output Result"
+ self.fullname = self.prefix + ' ' + self.name
+
+ self.fields = None
+ if dictionary is not None:
+ self.fields = []
+ for field_dictionary in dictionary:
+ if field_dictionary['format'] == 'array':
+ self.fields.append(FieldArray(self.fullname, field_dictionary))
+ elif field_dictionary['format'] == 'struct':
+ self.fields.append(FieldStruct(self.fullname, field_dictionary))
+ elif field_dictionary['format'] == 'guint8' or \
+ field_dictionary['format'] == 'guint16' or \
+ field_dictionary['format'] == 'guint32' or \
+ field_dictionary['format'] == 'gint8' or \
+ field_dictionary['format'] == 'gint16' or \
+ field_dictionary['format'] == 'gint32':
+ self.fields.append(FieldBasic(self.fullname, field_dictionary))
+ else:
+ raise ValueError('Cannot handle type \'%s\'' % field_dictionary['type'])
+
+
+ def __emit_tlv_ids_enum(self, f):
+ if self.fields is None:
+ return
+
+ translations = { 'enum_type' : utils.build_camelcase_name (self.fullname + ' TLV') }
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${enum_type}:\n')
+ f.write(string.Template(template).substitute(translations))
+
+ for tlv in self.fields:
+ translations['enum_name'] = tlv.id_enum_name
+ translations['enum_value'] = tlv.id
+ template = (
+ ' * @${enum_name}: TODO,\n')
+ f.write(string.Template(template).substitute(translations))
+
+ template = (
+ ' * TODO: comment enum\n'
+ ' */\n'
+ 'typedef enum {\n')
+ f.write(string.Template(template).substitute(translations))
+
+ for tlv in self.fields:
+ translations['enum_name'] = tlv.id_enum_name
+ translations['enum_value'] = tlv.id
+ template = (
+ ' ${enum_name} = ${enum_value},\n')
+ f.write(string.Template(template).substitute(translations))
+
+ template = (
+ '} ${enum_type};\n')
+ f.write(string.Template(template).substitute(translations))
+
+
+ def __emit_types(self, hfile, cfile, translations):
+ # Emit types header
+ template = (
+ '\n'
+ 'typedef struct _${camelcase} ${camelcase};\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ # Emit types source
+ template = (
+ '\n'
+ 'struct _${camelcase} {\n'
+ ' volatile gint ref_count;\n'
+ '\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ if self.fields is not None:
+ for field in self.fields:
+ translations['field_type'] = field.field_type
+ translations['field_variable_name'] = field.variable_name
+ translations['field_name'] = field.name
+ template = (
+ '\n'
+ ' /* ${field_name} */\n'
+ ' gboolean ${field_variable_name}_set;\n'
+ ' ${field_type} ${field_variable_name};\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ cfile.write(
+ '};\n')
+
+
+ def __emit_core(self, hfile, cfile, translations):
+ # Emit container core header
+ template = (
+ '\n'
+ '${camelcase} *${underscore}_ref (${camelcase} *self);\n'
+ 'void ${underscore}_unref (${camelcase} *self);\n')
+ if self.readonly == False:
+ template += (
+ '${camelcase} *${underscore}_new (void);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ # Emit container core source
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${underscore}_ref:\n'
+ ' * @self: a #${camelcase}.\n'
+ ' *\n'
+ ' * Atomically increments the reference count of @self by one.\n'
+ ' *\n'
+ ' * Returns: the new reference to @self.\n'
+ ' */\n'
+ '${camelcase} *\n'
+ '${underscore}_ref (${camelcase} *self)\n'
+ '{\n'
+ ' g_return_val_if_fail (self != NULL, NULL);\n'
+ '\n'
+ ' g_atomic_int_inc (&self->ref_count);\n'
+ ' return self;\n'
+ '}\n'
+ '\n'
+ '/**\n'
+ ' * ${underscore}_unref:\n'
+ ' * @self: a #${camelcase}.\n'
+ ' *\n'
+ ' * 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'
+ '${underscore}_unref (${camelcase} *self)\n'
+ '{\n'
+ ' g_return_if_fail (self != NULL);\n'
+ '\n'
+ ' if (g_atomic_int_dec_and_test (&self->ref_count)) {\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ if self.fields is not None:
+ for field in self.fields:
+ if field.dispose is not None:
+ translations['field_dispose'] = field.dispose
+ translations['field_variable_name'] = field.variable_name
+ template = (
+ ' ${field_dispose} (self->${field_variable_name});\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ ' g_slice_free (${camelcase}, self);\n'
+ ' }\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ # _new() is only generated if the container is not readonly
+ if self.readonly == True:
+ return
+
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${underscore}_new:\n'
+ ' *\n'
+ ' * Allocates a new ${camelcase}.\n'
+ ' *\n'
+ ' * Returns: the newly created ${camelcase}.\n'
+ ' */\n'
+ '${camelcase} *\n'
+ '${underscore}_new (void)\n'
+ '{\n'
+ ' return g_slice_new0 (${camelcase});\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ def __emit_fields (self, hfile, cfile):
+ # Emit field getter/setter
+ if self.fields is None:
+ return
+
+ for field in self.fields:
+ field.emit_types(hfile)
+ field.emit_getter(hfile, cfile)
+ if self.readonly == False:
+ field.emit_setter(hfile, cfile)
+
+
+ def emit(self, hfile, cfile):
+ translations = { 'name' : self.name,
+ 'camelcase' : utils.build_camelcase_name (self.fullname),
+ 'underscore' : utils.build_underscore_name (self.fullname) }
+
+ if self.fields is None:
+ template = ('\n'
+ '/* Note: no fields in the ${name} container */\n')
+ hfile.write(string.Template(template).substitute(translations))
+ cfile.write(string.Template(template).substitute(translations))
+ return
+
+ # Emit the container types
+ self.__emit_types(hfile, cfile, translations)
+
+ # Emit TLV enums
+ self.__emit_tlv_ids_enum(cfile)
+
+ # Emit fields
+ self.__emit_fields(hfile, cfile)
+
+ # Emit the container core
+ self.__emit_core(hfile, cfile, translations)
diff --git a/build-aux/qmi-codegen/ContainerInput.py b/build-aux/qmi-codegen/ContainerInput.py
new file mode 100644
index 00000000..2d5c34f3
--- /dev/null
+++ b/build-aux/qmi-codegen/ContainerInput.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+from Field import Field
+from Container import Container
+
+class ContainerInput(Container):
+ """
+ The ContainerInput class takes care of handling collections of Input
+ fields
+ """
+
+ def __init__(self, prefix, dictionary):
+
+ self.name = 'Input'
+ self.readonly = False
+
+ # Call the parent constructor
+ Container.__init__(self, prefix, dictionary)
diff --git a/build-aux/qmi-codegen/ContainerOutput.py b/build-aux/qmi-codegen/ContainerOutput.py
new file mode 100644
index 00000000..ccfc33cf
--- /dev/null
+++ b/build-aux/qmi-codegen/ContainerOutput.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+from Field import Field
+from Container import Container
+
+class ContainerOutput(Container):
+ """
+ The ContainerOutput class takes care of handling collections of Output
+ fields
+ """
+
+ def __init__(self, prefix, dictionary):
+
+ self.name = 'Output'
+ self.readonly = True
+
+ # Call the parent constructor
+ Container.__init__(self, prefix, dictionary)
diff --git a/build-aux/qmi-codegen/Field.py b/build-aux/qmi-codegen/Field.py
new file mode 100644
index 00000000..de26ae1b
--- /dev/null
+++ b/build-aux/qmi-codegen/Field.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+from Struct import Struct
+import utils
+
+class Field:
+ """
+ The Field class takes care of handling Input and Output TLVs
+ """
+
+ def __init__(self, prefix, dictionary):
+ # The field prefix, usually the name of the Container,
+ # e.g. "Qmi Message Ctl Something Output"
+ self.prefix = prefix
+ # The name of the specific field, e.g. "Result"
+ self.name = dictionary['name']
+ # The specific TLV ID
+ self.id = dictionary['id']
+ # Whether the field is to be considered mandatory in the message
+ self.mandatory = dictionary['mandatory']
+ # Specific format of the field
+ self.format = dictionary['format']
+ # The type, which must always be "TLV"
+ self.type = dictionary['type']
+ # Output Fields may have prerequisites
+ self.prerequisite = dictionary['prerequisite'] if 'prerequisite' in dictionary else None
+
+ # Strings containing how the given type is to be copied and disposed
+ self.copy = None
+ self.dispose = None
+ # The field type to be used in the generated code
+ self.field_type = None
+
+ # Create the composed full name (prefix + name),
+ # e.g. "Qmi Message Ctl Something Output Result"
+ self.fullname = self.prefix + ' ' + self.name
+
+ # Create the variable name within the Container
+ self.variable_name = 'arg_' + string.lower(utils.build_underscore_name(self.name))
+
+ # Create the ID enumeration name
+ self.id_enum_name = string.upper(utils.build_underscore_name(self.prefix + ' TLV ' + self.name))
+
+
+ def emit_types(self, hfile):
+ '''
+ Subclasses can implement the method to emit the required type
+ information
+ '''
+ pass
+
+
+ def emit_getter(self, hfile, cfile):
+ translations = { 'name' : self.name,
+ 'variable_name' : self.variable_name,
+ 'field_type' : self.field_type,
+ 'field_dispose_msg' : ' Dispose @value with ' + self.dispose + '() when no longer needed.' if self.dispose is not None else '',
+ 'field_copy' : self.copy if self.copy is not None else '',
+ 'underscore' : utils.build_underscore_name(self.name),
+ 'prefix_camelcase' : utils.build_camelcase_name(self.prefix),
+ 'prefix_underscore' : utils.build_underscore_name(self.prefix) }
+
+ # Emit the getter header
+ template = (
+ '\n'
+ 'gboolean ${prefix_underscore}_get_${underscore} (\n'
+ ' ${prefix_camelcase} *self,\n'
+ ' ${field_type} *value,\n'
+ ' GError **error);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ # Emit the getter source
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${prefix_underscore}_get_${underscore}:\n'
+ ' * @self: a ${prefix_camelcase}.\n'
+ ' * @value: a placeholder for the output value, or #NULL.\n'
+ ' * @error: a #GError.\n'
+ ' *\n'
+ ' * Get the \'${name}\' field from @self.\n'
+ ' *\n'
+ ' * Returns: #TRUE if the field is found and @value is set, #FALSE otherwise.${field_dispose_msg}\n'
+ ' */\n'
+ 'gboolean\n'
+ '${prefix_underscore}_get_${underscore} (\n'
+ ' ${prefix_camelcase} *self,\n'
+ ' ${field_type} *value,\n'
+ ' GError **error)\n'
+ '{\n'
+ ' g_return_val_if_fail (self != NULL, FALSE);\n'
+ '\n'
+ ' if (!self->${variable_name}_set) {\n'
+ ' g_set_error (error,\n'
+ ' QMI_CORE_ERROR,\n'
+ ' QMI_CORE_ERROR_TLV_NOT_FOUND,\n'
+ ' "Field \'${name}\' was not found in the message");\n'
+ ' return FALSE;\n'
+ ' }\n'
+ '\n'
+ ' if (value)\n'
+ ' *value = ${field_copy}(self->${variable_name});\n'
+ ' return TRUE;\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ def emit_setter(self, hfile, cfile):
+ translations = { 'name' : self.name,
+ 'variable_name' : self.variable_name,
+ 'field_type' : self.field_type,
+ 'field_dispose' : self.dispose + '(self->' + self_variable_name + ');\n' if self.dispose is not None else '',
+ 'field_copy' : self.copy if self.copy is not None else '',
+ 'underscore' : utils.build_underscore_name(self.name),
+ 'prefix_camelcase' : utils.build_camelcase_name(self.prefix),
+ 'prefix_underscore' : utils.build_underscore_name(self.prefix) }
+
+ # Emit the setter header
+ template = (
+ '\n'
+ 'gboolean ${prefix_underscore}_set_${underscore} (\n'
+ ' ${prefix_camelcase} *self,\n'
+ ' ${field_type} value,\n'
+ ' GError **error);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ # Emit the setter source
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${prefix_underscore}_set_${underscore}:\n'
+ ' * @self: a ${prefix_camelcase}.\n'
+ ' * @value: the value to set.\n'
+ ' * @error: a #GError.\n'
+ ' *\n'
+ ' * Set the \'${name}\' field in the message.\n'
+ ' *\n'
+ ' * Returns: #TRUE if @value was successfully set, #FALSE otherwise.\n'
+ ' */\n'
+ 'gboolean\n'
+ '${prefix_underscore}_set_${underscore} (\n'
+ ' ${prefix_camelcase} *self,\n'
+ ' ${field_type} value,\n'
+ ' GError **error)\n'
+ '{\n'
+ ' g_return_val_if_fail (self != NULL, FALSE);\n'
+ '\n'
+ ' ${field_dispose}'
+ ' self->${variable_name}_set = TRUE;\n'
+ ' self->${variable_name} = value;\n'
+ '\n'
+ ' return TRUE;\n'
+ '}\n'
+ '\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ def emit_input_mandatory_check(self, f, line_prefix):
+ if self.mandatory == 'yes':
+ translations = { 'name' : self.name,
+ 'variable_name' : self.variable_name,
+ 'lp' : line_prefix }
+
+ template = (
+ '\n'
+ '${lp}if (!input || !input->${variable_name}_set) {\n'
+ '${lp} g_set_error (error,\n'
+ '${lp} QMI_CORE_ERROR,\n'
+ '${lp} QMI_CORE_ERROR_INVALID_ARGS,\n'
+ '${lp} "Missing mandatory TLV \'${name}\'");\n'
+ '${lp} qmi_message_unref (self);\n'
+ '${lp} return NULL;\n'
+ '${lp}}\n')
+
+ f.write(string.Template(template).substitute(translations))
+
+ def emit_input_tlv_add(self, f, line_prefix):
+ '''
+ Subclasses can implement the method to emit the required TLV adding
+ '''
+ pass
+
+
+ def emit_output_prerequisite_check(self, f, line_prefix):
+ translations = { 'lp' : line_prefix }
+ template = None
+ if self.prerequisite is not None:
+ translations['prerequisite_field'] = utils.build_underscore_name(self.prerequisite['field'])
+ translations['prerequisite_operation'] = self.prerequisite['operation']
+ translations['prerequisite_value'] = self.prerequisite['value']
+ template = (
+ '${lp}/* Prerequisite.... */\n'
+ '${lp}if (!(self->arg_${prerequisite_field} ${prerequisite_operation} ${prerequisite_value}))\n'
+ '${lp} break;\n')
+ else:
+ template = (
+ '${lp}/* No Prerequisites for field */\n')
+ f.write(string.Template(template).substitute(translations))
+
+
+ def emit_output_tlv_get(self, f, line_prefix):
+ '''
+ Subclasses can implement the method to emit the required TLV retrieval
+ '''
+ pass
diff --git a/build-aux/qmi-codegen/FieldArray.py b/build-aux/qmi-codegen/FieldArray.py
new file mode 100644
index 00000000..f0139430
--- /dev/null
+++ b/build-aux/qmi-codegen/FieldArray.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+import utils
+from Struct import Struct
+from Field import Field
+
+class FieldArray(Field):
+ """
+ The FieldArray class takes care of handling 'array' format based
+ Input and Output TLVs
+ """
+
+ def __init__(self, prefix, dictionary):
+ # Call the parent constructor
+ Field.__init__(self, prefix, dictionary)
+
+ if dictionary['array-element']['format'] != 'struct':
+ raise ValueError('Cannot handle arrays of format \'%s\'' % dictionary['array-element']['format'])
+
+ # Set a struct as content
+ self.array_element = Struct(utils.build_camelcase_name (self.fullname +
+ ' ' +
+ dictionary['array-element']['name']),
+ dictionary['array-element']['contents'])
+
+ # We'll use standard GArrays
+ self.field_type = 'GArray *';
+ # The array needs to get disposed
+ self.dispose = 'g_array_unref'
+
+
+ def emit_types(self, f):
+ '''
+ Emit the type for the struct used as array element
+ '''
+ self.array_element.emit(f)
+
+
+ def emit_input_tlv_add(self, cfile, line_prefix):
+ # TODO
+ raise ValueError('Array as input not implemented yet')
+
+ def emit_output_tlv_get(self, f, line_prefix):
+ translations = { 'name' : self.name,
+ 'container_underscore' : utils.build_underscore_name (self.prefix),
+ 'array_element_type' : self.array_element.name,
+ 'tlv_id' : self.id_enum_name,
+ 'variable_name' : self.variable_name,
+ 'lp' : line_prefix,
+ 'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
+
+ template = (
+ '\n'
+ '${lp}guint i;\n'
+ '${lp}guint8 buffer[1024];\n'
+ '${lp}guint16 buffer_len = 1024;\n'
+ '${lp}${array_element_type} *item;\n'
+ '\n'
+ '${lp}if (qmi_message_tlv_get_varlen (message,\n'
+ '${lp} ${tlv_id},\n'
+ '${lp} &buffer_len,\n'
+ '${lp} buffer,\n'
+ '${lp} ${error})) {\n'
+ '${lp} guint8 nitems = buffer[0];\n'
+ '\n'
+ '${lp} self->${variable_name}_set = TRUE;\n'
+ '${lp} self->${variable_name} = g_array_sized_new (FALSE, FALSE, sizeof (${array_element_type}), nitems);\n'
+ '${lp} for (i = 0, item = (${array_element_type} *)&buffer[1]; i < nitems; i++, item++) {\n')
+ f.write(string.Template(template).substitute(translations))
+
+ for struct_field in self.array_element.members:
+ f.write('%s %s;\n' % (line_prefix,
+ utils.he_from_le ('item->' + utils.build_underscore_name(struct_field['name']),
+ 'item->' + utils.build_underscore_name(struct_field['name']),
+ struct_field['type'])))
+
+ template = (
+ '${lp} g_array_insert_val (self->${variable_name}, i, *item);\n'
+ '${lp} }\n')
+
+ if self.mandatory == 'yes':
+ template += (
+ '${lp}} else {\n'
+ '${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
+ '${lp} ${container_underscore}_unref (self);\n'
+ '${lp} return NULL;\n'
+ '${lp}}\n')
+ else:
+ template += (
+ '${lp}}\n')
+ f.write(string.Template(template).substitute(translations))
diff --git a/build-aux/qmi-codegen/FieldBasic.py b/build-aux/qmi-codegen/FieldBasic.py
new file mode 100644
index 00000000..9905c713
--- /dev/null
+++ b/build-aux/qmi-codegen/FieldBasic.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+import utils
+from Field import Field
+
+class FieldBasic(Field):
+ """
+ The FieldBasic class takes care of handling Input and Output TLVs based
+ on basic types (e.g. integers)
+ """
+
+ def __init__(self, prefix, dictionary):
+
+ # Call the parent constructor
+ Field.__init__(self, prefix, dictionary)
+
+ # The field type to be used in the generated code is the same as the one
+ # given in the database
+ self.field_type = self.format;
+
+ def emit_input_tlv_add(self, cfile, line_prefix):
+ translations = { 'name' : self.name,
+ 'tlv_id' : self.id_enum_name,
+ 'field_type' : self.field_type,
+ 'set_variable' : utils.le_from_he ('input->' + self.variable_name, 'tmp', self.field_type),
+ 'lp' : line_prefix }
+
+ template = (
+ '${lp}/* Try to add the \'${name}\' TLV */\n'
+ '${lp}{\n'
+ '${lp} ${field_type} tmp;\n'
+ '\n'
+ '${lp} ${set_variable};\n'
+ '\n'
+ '${lp} if (!qmi_message_tlv_add (self,\n'
+ '${lp} (guint8)${tlv_id},\n'
+ '${lp} sizeof (tmp),\n'
+ '${lp} &tmp,\n'
+ '${lp} error)) {\n'
+ '${lp} g_prefix_error (error, \"Couldn\'t set the ${name} TLV: \");\n'
+ '${lp} qmi_message_unref (self);\n'
+ '${lp} return NULL;\n'
+ '${lp} }\n'
+ '${lp}}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ def emit_output_tlv_get(self, f, line_prefix):
+ translations = { 'name' : self.name,
+ 'container_underscore' : utils.build_underscore_name (self.prefix),
+ 'tlv_id' : self.id_enum_name,
+ 'variable_name' : self.variable_name,
+ 'lp' : line_prefix,
+ 'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
+
+ template = (
+ '${lp}if (qmi_message_tlv_get (message,\n'
+ '${lp} ${tlv_id},\n'
+ '${lp} sizeof (self->${variable_name}),\n'
+ '${lp} &self->${variable_name},\n'
+ '${lp} ${error})) {\n'
+ '${lp} self->${variable_name}_set = TRUE;\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ cfile.write('%s %s;\n' % (line_prefix,
+ utils.le_from_he ('self->' + self.variable_name,
+ 'self->' + self.variable_name,
+ self.field_type)))
+ if self.mandatory is 'yes':
+ template = (
+ '${lp}} else {\n'
+ '${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
+ '${lp} ${container_underscore}_unref (self);\n'
+ '${lp} return NULL;\n'
+ '${lp}}\n')
+ else:
+ template = (
+ '${lp}}\n')
+ cfile.write(string.Template(template).substitute(translations))
diff --git a/build-aux/qmi-codegen/FieldStruct.py b/build-aux/qmi-codegen/FieldStruct.py
new file mode 100644
index 00000000..fc18fd36
--- /dev/null
+++ b/build-aux/qmi-codegen/FieldStruct.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+import utils
+from Struct import Struct
+from Field import Field
+
+class FieldStruct(Field):
+ """
+ The FieldStruct class takes care of handling 'struct' format based
+ Input and Output TLVs
+ """
+
+ def __init__(self, prefix, dictionary):
+ # Call the parent constructor
+ Field.__init__(self, prefix, dictionary)
+
+ # The field type will be the given struct name
+ self.field_type = utils.build_camelcase_name(self.fullname)
+
+ # Set a struct as content
+ self.contents = Struct(self.field_type,
+ dictionary['contents'])
+
+
+ def emit_types(self, f):
+ '''
+ Emit the Struct type info
+ '''
+ self.contents.emit(f)
+
+
+ def emit_input_tlv_add(self, cfile, line_prefix):
+ translations = { 'name' : self.name,
+ 'tlv_id' : self.id_enum_name,
+ 'field_type' : self.field_type,
+ 'variable_name' : self.variable_name,
+ 'lp' : line_prefix }
+
+ template = (
+ '${lp}/* Try to add the \'${name}\' TLV */\n'
+ '${lp}{\n'
+ '${lp} ${field_type} tmp;\n'
+ '\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ # uint32 and uint16 fields need to be converted to host-endianness
+ for struct_field in self.contents.members:
+ cfile.write('%s %s;\n' % (line_prefix,
+ utils.le_from_he ('input->' + self.variable_name + '.' + utils.build_underscore_name(struct_field['name']),
+ 'tmp.' + utils.build_underscore_name(struct_field['name']),
+ struct_field['type'])))
+
+ template = (
+ '\n'
+ '${lp} if (!qmi_message_tlv_add (self,\n'
+ '${lp} (guint8)${tlv_id},\n'
+ '${lp} sizeof (tmp),\n'
+ '${lp} &tmp,\n'
+ '${lp} error)) {\n'
+ '${lp} g_prefix_error (error, \"Couldn\'t set the ${name} TLV: \");\n'
+ '${lp} qmi_message_unref (self);\n'
+ '${lp} return NULL;\n'
+ '${lp} }\n'
+ '${lp}}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ def emit_output_tlv_get(self, f, line_prefix):
+ translations = { 'name' : self.name,
+ 'container_underscore' : utils.build_underscore_name (self.prefix),
+ 'field_type' : self.field_type,
+ 'tlv_id' : self.id_enum_name,
+ 'variable_name' : self.variable_name,
+ 'lp' : line_prefix,
+ 'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
+
+ template = (
+ '${lp}if (qmi_message_tlv_get (message,\n'
+ '${lp} ${tlv_id},\n'
+ '${lp} sizeof (self->${variable_name}),\n'
+ '${lp} &self->${variable_name},\n'
+ '${lp} ${error})) {\n'
+ '${lp} self->${variable_name}_set = TRUE;\n')
+ f.write(string.Template(template).substitute(translations))
+
+ for struct_field in self.contents.members:
+ f.write('%s %s;\n' % (line_prefix,
+ utils.he_from_le ('self->' + self.variable_name + '.' + utils.build_underscore_name(struct_field['name']),
+ 'self->' + self.variable_name + '.' + utils.build_underscore_name(struct_field['name']),
+ struct_field['type'])))
+ if self.mandatory is 'yes':
+ template = (
+ '${lp}} else {\n'
+ '${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
+ '${lp} ${container_underscore}_unref (self);\n'
+ '${lp} return NULL;\n'
+ '${lp}}\n')
+ else:
+ template = (
+ '${lp}}\n')
+ f.write(string.Template(template).substitute(translations))
diff --git a/build-aux/qmi-codegen/Makefile.am b/build-aux/qmi-codegen/Makefile.am
new file mode 100644
index 00000000..f6df6c8e
--- /dev/null
+++ b/build-aux/qmi-codegen/Makefile.am
@@ -0,0 +1,14 @@
+
+EXTRA_DIST = \
+ Client.py \
+ MessageList.py \
+ Message.py \
+ Container.py \
+ ContainerInput.py \
+ ContainerOutput.py \
+ Field.py \
+ FieldArray.py \
+ FieldStruct.py \
+ FieldBasic.py \
+ utils.py \
+ qmi-codegen
diff --git a/build-aux/qmi-codegen/Message.py b/build-aux/qmi-codegen/Message.py
new file mode 100644
index 00000000..04157046
--- /dev/null
+++ b/build-aux/qmi-codegen/Message.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+import utils
+from ContainerOutput import ContainerOutput
+from ContainerInput import ContainerInput
+
+class Message:
+ def __init__(self, dictionary):
+ # The message prefix
+ self.prefix = 'Qmi Message'
+ # The message service, e.g. "Ctl"
+ self.service = dictionary['service']
+ # The name of the specific message, e.g. "Something"
+ self.name = dictionary['name']
+ # The specific message ID
+ self.id = dictionary['id']
+ # The type, which must always be 'Message'
+ self.type = dictionary['type']
+
+ # Create the composed full name (prefix + service + name),
+ # e.g. "Qmi Message Ctl Something Output Result"
+ self.fullname = self.prefix + ' ' + self.service + ' ' + self.name
+
+ # Create the ID enumeration name
+ self.id_enum_name = string.upper(utils.build_underscore_name(self.fullname))
+
+ # Build output container.
+ # Every defined message will have its own output container, which
+ # will generate a new Output type and public getters for each output
+ # field
+ self.output = ContainerOutput(self.fullname,
+ dictionary['output'])
+
+ # Build input container.
+ # Every defined message will have its own input container, which
+ # will generate a new Input type and public getters for each input
+ # field
+ self.input = ContainerInput(self.fullname,
+ dictionary['input'] if 'input' in dictionary else None)
+
+
+ def __emit_request_creator(self, hfile, cfile):
+ translations = { 'service' : self.service,
+ 'container' : utils.build_camelcase_name (self.input.fullname),
+ 'underscore' : utils.build_underscore_name (self.fullname),
+ 'message_id' : self.id_enum_name }
+
+ input_arg_template = 'gpointer unused' if self.input.fields is None else '${container} *input'
+ template = (
+ '\n'
+ 'QmiMessage *${underscore}_request_create (\n'
+ ' guint8 transaction_id,\n'
+ ' guint8 cid,\n'
+ ' %s,\n'
+ ' GError **error);\n' % input_arg_template)
+ hfile.write(string.Template(template).substitute(translations))
+
+ # Emit message creator
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${underscore}_request_create:\n'
+ ' */\n'
+ 'QmiMessage *\n'
+ '${underscore}_request_create (\n'
+ ' guint8 transaction_id,\n'
+ ' guint8 cid,\n'
+ ' %s,\n'
+ ' GError **error)\n'
+ '{\n'
+ ' QmiMessage *self;\n'
+ '\n'
+ ' self = qmi_message_new (QMI_SERVICE_${service},\n'
+ ' cid,\n'
+ ' transaction_id,\n'
+ ' ${message_id});\n'
+ '\n' % input_arg_template)
+ cfile.write(string.Template(template).substitute(translations))
+
+ if self.input.fields is not None:
+ for field in self.input.fields:
+ field.emit_input_mandatory_check(cfile, ' ')
+ field.emit_input_tlv_add(cfile, ' ')
+
+ cfile.write(
+ ' return self;\n'
+ '}\n')
+
+
+ def __emit_response_parser(self, hfile, cfile):
+ translations = { 'name' : self.name,
+ 'container' : utils.build_camelcase_name (self.output.fullname),
+ 'container_underscore' : utils.build_underscore_name (self.output.fullname),
+ 'underscore' : utils.build_underscore_name (self.fullname),
+ 'message_id' : self.id_enum_name }
+
+ template = (
+ '\n'
+ '${container} *${underscore}_response_parse (\n'
+ ' QmiMessage *message,\n'
+ ' GError **error);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${underscore}_response_parse:\n'
+ ' * @message: a #QmiMessage response.\n'
+ ' * @error: a #GError.\n'
+ ' *\n'
+ ' * Parse the \'${name}\' response.\n'
+ ' *\n'
+ ' * Returns: a #${container} which should be disposed with ${container_underscore}_unref(), or #NULL if @error is set.\n'
+ ' */\n'
+ '${container} *\n'
+ '${underscore}_response_parse (\n'
+ ' QmiMessage *message,\n'
+ ' GError **error)\n'
+ '{\n'
+ ' ${container} *self;\n'
+ '\n'
+ ' g_return_val_if_fail (qmi_message_get_message_id (message) == ${message_id}, NULL);\n'
+ '\n'
+ ' self = g_slice_new0 (${container});\n'
+ ' self->ref_count = 1;\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ for field in self.output.fields:
+ cfile.write(
+ '\n'
+ ' do {\n')
+ field.emit_output_prerequisite_check(cfile, ' ')
+ cfile.write(
+ '\n'
+ ' {\n')
+ field.emit_output_tlv_get(cfile, ' ')
+ cfile.write(
+ '\n'
+ ' }\n')
+ cfile.write(
+ ' } while (0);\n')
+ cfile.write(
+ '\n'
+ ' return self;\n'
+ '}\n')
+
+
+ def emit(self, hfile, cfile):
+ utils.add_separator(hfile, 'REQUEST/RESPONSE', self.fullname);
+ utils.add_separator(cfile, 'REQUEST/RESPONSE', self.fullname);
+
+ hfile.write('\n/* --- Input -- */\n');
+ cfile.write('\n/* --- Input -- */\n');
+ self.input.emit(hfile, cfile)
+ self.__emit_request_creator (hfile, cfile)
+
+ hfile.write('\n/* --- Output -- */\n');
+ cfile.write('\n/* --- Output -- */\n');
+ self.output.emit(hfile, cfile)
+ self.__emit_response_parser (hfile, cfile)
diff --git a/build-aux/qmi-codegen/MessageList.py b/build-aux/qmi-codegen/MessageList.py
new file mode 100644
index 00000000..784100bb
--- /dev/null
+++ b/build-aux/qmi-codegen/MessageList.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+from Message import Message
+import utils
+
+class MessageList:
+ def __init__(self, objects_dictionary):
+ self.list = []
+ self.message_id_enum_name = None
+
+ # Loop items in the list, creating Message objects for the messages
+ # and looking for the special 'Message-ID-Enum' type
+ for object_dictionary in objects_dictionary:
+ if object_dictionary['type'] == 'Message':
+ message = Message(object_dictionary)
+ self.list.append(message)
+ elif object_dictionary['type'] == 'Message-ID-Enum':
+ self.message_id_enum_name = object_dictionary['name']
+
+ # We NEED the Message-ID-Enum field
+ if self.message_id_enum_name is None:
+ raise ValueError('Missing Message-ID-Enum field')
+
+
+ def emit_message_ids_enum(self, f):
+ translations = { 'enum_type' : utils.build_camelcase_name (self.message_id_enum_name) }
+ template = (
+ '\n'
+ 'typedef enum {\n')
+ for message in self.list:
+ translations['enum_name'] = message.id_enum_name
+ translations['enum_value'] = message.id
+ enum_template = (
+ ' ${enum_name} = ${enum_value},\n')
+ template += string.Template(enum_template).substitute(translations)
+
+ template += (
+ '} ${enum_type};\n'
+ '\n')
+ f.write(string.Template(template).substitute(translations))
+
+
+ def emit(self, hfile, cfile):
+ # First, emit the message IDs enum
+ self.emit_message_ids_enum(cfile)
+
+ # Then, emit all message handlers
+ for message in self.list:
+ message.emit(hfile, cfile)
diff --git a/build-aux/qmi-codegen/Struct.py b/build-aux/qmi-codegen/Struct.py
new file mode 100644
index 00000000..fd3dad9a
--- /dev/null
+++ b/build-aux/qmi-codegen/Struct.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+import utils
+
+class Struct:
+
+ def __init__(self, name, members):
+ # The struct type name, e.g. QmiTheStruct
+ self.name = name
+ # The struct members, a dictionary of 'type'+'name' pairs
+ self.members = members
+
+
+ # Emits the definition of the struct
+ def emit(self, f):
+ translations = { 'name' : self.name }
+ template = (
+ '\n'
+ 'typedef struct _${name} {\n')
+ f.write(string.Template(template).substitute(translations))
+
+ for var in self.members:
+ translations['variable_type'] = var['type']
+ translations['variable_name'] = utils.build_underscore_name(var['name'])
+ template = (
+ ' ${variable_type} ${variable_name};\n')
+ f.write(string.Template(template).substitute(translations))
+
+ template = ('} __attribute__((__packed__)) ${name};\n\n')
+ f.write(string.Template(template).substitute(translations))
diff --git a/build-aux/qmi-codegen/qmi-codegen b/build-aux/qmi-codegen/qmi-codegen
new file mode 100755
index 00000000..aa113a89
--- /dev/null
+++ b/build-aux/qmi-codegen/qmi-codegen
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import os
+import sys
+import json
+
+from Client import Client
+from MessageList import MessageList
+import utils
+
+# Setup inputs
+if len(sys.argv) != 3:
+ print "Usage: qmi-codegen <path to database.json> <path to output>"
+ sys.exit(1)
+
+database_file_path = sys.argv[1]
+base_output_path = sys.argv[2]
+
+output_file_c = open(base_output_path + ".c", 'w')
+output_file_h = open(base_output_path + ".h", 'w')
+
+# Load database file contents
+database_file = open(sys.argv[1])
+database_file_contents = database_file.read()
+database_file.close()
+
+# Add common stuff to the output files
+utils.add_copyright(output_file_c);
+utils.add_copyright(output_file_h);
+utils.add_header_start(output_file_h, os.path.basename(base_output_path))
+utils.add_source_start(output_file_c, os.path.basename(base_output_path))
+
+# Get our message collection
+object_list_json = json.loads(database_file_contents)
+message_list = MessageList(object_list_json)
+
+# Emit the message creation/parsing code
+message_list.emit(output_file_h, output_file_c)
+
+# Build our own client
+client = Client(object_list_json)
+client.emit(output_file_h, output_file_c, message_list)
+
+utils.add_header_stop(output_file_h, os.path.basename(base_output_path))
+
+output_file_c.close()
+output_file_h.close()
diff --git a/build-aux/qmi-codegen/utils.py b/build-aux/qmi-codegen/utils.py
new file mode 100644
index 00000000..5c14f5b1
--- /dev/null
+++ b/build-aux/qmi-codegen/utils.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program 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 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+#
+
+import string
+
+def add_copyright(f):
+ f.write("\n"
+ "/* GENERATED CODE... DO NOT EDIT */\n"
+ "\n"
+ "/*\n"
+ " * This library is free software; you can redistribute it and/or\n"
+ " * modify it under the terms of the GNU Lesser General Public\n"
+ " * License as published by the Free Software Foundation; either\n"
+ " * version 2 of the License, or (at your option) any later version.\n"
+ " *\n"
+ " * This library is distributed in the hope that it will be useful,\n"
+ " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
+ " * Lesser General Public License for more details.\n"
+ " *\n"
+ " * You should have received a copy of the GNU Lesser General Public\n"
+ " * License along with this library; if not, write to the\n"
+ " * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n"
+ " * Boston, MA 02110-1301 USA.\n"
+ " *\n"
+ " * Copyright (C) 2012 Lanedo GmbH\n"
+ " */\n"
+ "\n");
+
+def build_header_guard(output_name):
+ return "__LIBQMI_GLIB_" + string.upper(string.replace (output_name, '-', '_')) + "__"
+
+def add_header_start(f, output_name):
+ template = string.Template (
+ "\n"
+ "#ifndef ${guard}\n"
+ "#define ${guard}\n"
+ "\n"
+ "#include <glib.h>\n"
+ "#include <glib-object.h>\n"
+ "#include <gio/gio.h>\n"
+ "\n"
+ "#include \"qmi-enum-types.h\"\n"
+ "#include \"qmi-message.h\"\n"
+ "#include \"qmi-client.h\"\n"
+ "\n"
+ "G_BEGIN_DECLS\n"
+ "\n")
+ f.write(template.substitute(guard = build_header_guard(output_name)))
+
+def add_header_stop(f, output_name):
+ template = string.Template (
+ "\n"
+ "G_END_DECLS\n"
+ "\n"
+ "#endif /* ${guard} */\n")
+ f.write(template.substitute(guard = build_header_guard(output_name)))
+
+#def add_global_include(f, header):
+# template = string.Template (
+# "\n"
+# "#include <${header}>\n")
+# f.write(template.substitute(header = header))
+#
+#def add_local_include(f, header):
+# template = string.Template (
+# "\n"
+# "#include \"${header}\"\n")
+# f.write(template.substitute(header = header))
+
+
+def add_source_start(f, output_name):
+ template = string.Template (
+ "\n"
+ "#include \"${name}.h\"\n"
+ "#include \"qmi-error-types.h\"\n"
+ "#include \"qmi-device.h\"\n"
+ '\n'
+ '#define QMI_STATUS_SUCCESS 0x0000\n'
+ '#define QMI_STATUS_FAILURE 0x0001\n'
+ "\n")
+ f.write(template.substitute(name = output_name))
+
+
+def add_separator(f, separator_type, separator_name):
+ template = string.Template (
+ "\n"
+ "/*****************************************************************************/\n"
+ "/* ${type}: ${name} */\n"
+ "\n")
+ f.write(template.substitute(type = separator_type,
+ name = separator_name))
+
+def build_underscore_name(name):
+ return string.lower(string.replace (name, ' ', '_'))
+
+def build_camelcase_name(name):
+ return string.replace(string.capwords(name), ' ', '')
+
+
+#def emit_struct_type(f, struct_type, dictionary):
+# translations = { 'struct_type' : struct_type }
+# template = (
+# '\n'
+# 'typedef struct _${struct_type} {\n')
+# f.write(string.Template(template).substitute(translations))
+# for var in dictionary['contents']:
+# translations['variable_type'] = var['type']
+# translations['variable_name'] = build_underscore_name(var['name'])
+# template = (
+# ' ${variable_type} ${variable_name};\n')
+# f.write(string.Template(template).substitute(translations))
+# template = ('} __attribute__((__packed__)) ${struct_type};\n\n')
+# f.write(string.Template(template).substitute(translations))
+
+
+def he_from_le(input_variable, output_variable, variable_type):
+ if variable_type == 'guint16':
+ return '%s = GUINT16_FROM_LE (%s)' % (output_variable, input_variable)
+ elif variable_type == 'guint32':
+ return '%s = GUINT32_FROM_LE (%s)' % (output_variable, input_variable)
+ if variable_type == 'gint16':
+ return '%s = GINT16_FROM_LE (%s)' % (output_variable, input_variable)
+ elif variable_type == 'gint32':
+ return '%s = GINT32_FROM_LE (%s)' % (output_variable, input_variable)
+ else:
+ return '%s = %s' % (output_variable, input_variable)
+
+
+def le_from_he(input_variable, output_variable, variable_type):
+ return he_from_le(input_variable, output_variable, variable_type)
diff --git a/configure.ac b/configure.ac
index 41960267..f1c1f784 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,6 +48,7 @@ AC_SUBST(GLIB_MKENUMS)
AC_CONFIG_FILES([Makefile
build-aux/Makefile
build-aux/templates/Makefile
+ build-aux/qmi-codegen/Makefile
src/Makefile
cli/Makefile
utils/Makefile])