MQTT: add JSON fixed size 1D array support. WIP. Parsing array still broken.
authorEdouard Tisserant <edouard@beremiz.fr>
Wed, 25 Sep 2024 11:10:33 +0200
changeset 4020 205d5379b35e
parent 4019 ad2b84071881
child 4021 07504d4c40ee
MQTT: add JSON fixed size 1D array support. WIP. Parsing array still broken.
mqtt/mqtt_client_gen.py
mqtt/mqtt_template.c
--- a/mqtt/mqtt_client_gen.py	Fri Sep 20 15:30:22 2024 +0200
+++ b/mqtt/mqtt_client_gen.py	Wed Sep 25 11:10:33 2024 +0200
@@ -430,56 +430,84 @@
             formatdict["retrieve"] += """
         READ_VALUE({c_loc_name}, {C_type})""".format(**locals())
 
-        def recurseJsonTypes(datatype, basetypes):
+        # collect all used type with their dependencies
+        basetypes=[]
+        arrays=set()
+        structures=set()
+        already_generated_types = set()
+
+        def recurseJsonTypes(datatype):
+            # append derivated type first so we can expect the list
+            # to be sorted with base types in last position
             basetypes.append(datatype)
-            # add derivated type first fo we can expect the list to be sorted
-            # with base types in last position
             infos = datatype_info_getter(datatype)
-            for element in infos["elements"]:
-                field_datatype = element["Type"]
-                if field_datatype not in MQTT_IEC_types:
-                    recurseJsonTypes(field_datatype, basetypes)
-
-        print(json_types)
-
-        # collect all type dependencies
-        basetypes=[]  # use a list to keep them ordered
+            print(infos)
+            element_type = infos["type"]
+            if element_type == "Structure":
+                structures.add(datatype)
+                for element in infos["elements"]:
+                    field_datatype = element["Type"]
+                    if field_datatype not in MQTT_IEC_types:
+                        recurseJsonTypes(field_datatype)
+            elif element_type == "Array":
+                arrays.add(datatype)
+                item_datatype = infos["base_type"]
+                if item_datatype not in MQTT_IEC_types:
+                    recurseJsonTypes(item_datatype)
+        def typeCategory(iec_type):
+            if field_iec_type in arrays:
+                return "ARRAY"
+            elif field_iec_type in structures:
+                return "OBJECT"
+            return "SIMPLE"
+
         for iec_type,_instances in json_types.items():
-            recurseJsonTypes(iec_type, basetypes)
-
-        done_types = set()
+            recurseJsonTypes(iec_type)
+
         # go backard to get most derivated type definition last
         # so that CPP can always find base type deinition before
         for iec_type in reversed(basetypes):
             # avoid repeating type definition
-            if iec_type in done_types:
+            if iec_type in already_generated_types:
                 continue
-            done_types.add(iec_type)
+            already_generated_types.add(iec_type)
 
             C_type = iec_type.upper()
             json_decl = "#define TYPE_" + C_type + "(_P, _A) \\\n"
 
             infos = datatype_info_getter(iec_type)
 
-            elements = infos["elements"]
-            last = len(elements) - 1
-            for idx, element in enumerate(elements):
-                field_iec_type = element["Type"]
+            element_type = infos["type"]
+            if element_type == "Structure":
+                elements = infos["elements"]
+                last = len(elements) - 1
+                for idx, element in enumerate(elements):
+                    field_iec_type = element["Type"]
+                    if type(field_iec_type) == tuple and field_iec_type[0] == "array":
+                        raise Exception("Inline arrays in structure are not supported. Please use a separate data type for array.")
+
+                    field_C_type = field_iec_type.upper()
+                    field_name = element["Name"]
+                    field_C_name = field_name.upper()
+                    decl_type = typeCategory(field_iec_type)
+
+                    json_decl += ("    _P##_" + decl_type + "(" + 
+                                  field_C_type + ", " + field_C_name + ", " + field_name + ", _A)" +
+                                  ("\n\n" if idx == last else " _P##_separator \\\n"))
+
+            elif element_type == "Array":
+                dimensions = infos["dimensions"]
+                if len(dimensions) > 1:
+                    raise Exception("Only 1 dimension arrays are supported")
+                count = int(dimensions[0][1]) - int(dimensions[0][0]) + 1
+                field_iec_type = infos["base_type"]
+                decl_type = typeCategory(field_iec_type)
                 field_C_type = field_iec_type.upper()
-                field_name = element["Name"]
-                field_C_name = field_name.upper()
-                if field_iec_type in MQTT_IEC_types:
-                    decl_type = "SIMPLE"
-                else:
-                    decl_type = "OBJECT"
-
-                json_decl += "    _P##_"+decl_type+"(" + field_C_type + ", " + field_C_name + ", " + field_name + ", _A)"
-                if idx != last:
-                    json_decl += " _P##_separator \\"
-                else:
-                    json_decl += "\n"
-                json_decl += "\n"
-
+                last = count - 1
+                for idx in range(count):
+                    json_decl += ("    _P##_ARRAY_" + decl_type + "(" +
+                                  field_C_type + ", " + repr(idx) + " , _A)" +
+                                  ("\n\n" if idx == last else " _P##_separator \\\n"))
 
             formatdict["json_decl"] += json_decl
 
--- a/mqtt/mqtt_template.c	Fri Sep 20 15:30:22 2024 +0200
+++ b/mqtt/mqtt_template.c	Wed Sep 25 11:10:33 2024 +0200
@@ -71,6 +71,9 @@
 
 #define printf_fmt_SIMPLE(C_type, C_name, name, _A) #name " : " printf_fmt_##C_type
 #define printf_fmt_OBJECT(C_type, C_name, name, _A) #name " : {{ " TYPE_##C_type(printf_fmt, _A) " }}"
+#define printf_fmt_ARRAY(C_type, C_name, name, _A) #name " : [ " TYPE_##C_type(printf_fmt, _A) " ]"
+#define printf_fmt_ARRAY_SIMPLE(C_type, index, _A) printf_fmt_##C_type
+#define printf_fmt_ARRAY_OBJECT(C_type, index, _A) "{{ " TYPE_##C_type(printf_fmt, _A) " }}"
 
 #define scanf_fmt_BOOL   "%B"
 #define scanf_fmt_SINT   "%hhd"
@@ -89,42 +92,51 @@
 
 #define scanf_fmt_SIMPLE(C_type, C_name, name, _A) #name " : " scanf_fmt_##C_type
 #define scanf_fmt_OBJECT(C_type, C_name, name, _A) #name " : {{ " TYPE_##C_type(scanf_fmt, _A) " }}"
-
-#define   scanf_arg_BOOL(name, data_ptr) &data_ptr->name
-#define   scanf_arg_SINT(name, data_ptr) &data_ptr->name
-#define  scanf_arg_USINT(name, data_ptr) &data_ptr->name
-#define    scanf_arg_INT(name, data_ptr) &data_ptr->name
-#define   scanf_arg_UINT(name, data_ptr) &data_ptr->name
-#define   scanf_arg_DINT(name, data_ptr) &data_ptr->name
-#define  scanf_arg_UDINT(name, data_ptr) &data_ptr->name
-#define   scanf_arg_LINT(name, data_ptr) &data_ptr->name
-#define  scanf_arg_ULINT(name, data_ptr) &data_ptr->name
-#define   scanf_arg_REAL(name, data_ptr) &data_ptr->name
-#define  scanf_arg_LREAL(name, data_ptr) &data_ptr->name
-#define scanf_arg_STRING(name, data_ptr) scan_string, &data_ptr->name 
+#define scanf_fmt_ARRAY(C_type, C_name, name, _A) #name " : [ " TYPE_##C_type(scanf_fmt, _A) " ]"
+#define scanf_fmt_ARRAY_SIMPLE(C_type, index, _A) scanf_fmt_##C_type
+#define scanf_fmt_ARRAY_OBJECT(C_type, index, _A) "{{ " TYPE_##C_type(scanf_fmt, _A) " }}"
+
+#define   scanf_arg_BOOL(arg) arg
+#define   scanf_arg_SINT(arg) arg
+#define  scanf_arg_USINT(arg) arg
+#define    scanf_arg_INT(arg) arg
+#define   scanf_arg_UINT(arg) arg
+#define   scanf_arg_DINT(arg) arg
+#define  scanf_arg_UDINT(arg) arg
+#define   scanf_arg_LINT(arg) arg
+#define  scanf_arg_ULINT(arg) arg
+#define   scanf_arg_REAL(arg) arg
+#define  scanf_arg_LREAL(arg) arg
+#define scanf_arg_STRING(arg) scan_string, arg
 
 #define scanf_args_separator ,
 
-#define scanf_args_SIMPLE(C_type, C_name, name, data_ptr) scanf_arg_##C_type(C_name, data_ptr)
+#define scanf_args_SIMPLE(C_type, C_name, name, data_ptr) scanf_arg_##C_type(&data_ptr->C_name)
 #define scanf_args_OBJECT(C_type, C_name, name, data_ptr) TYPE_##C_type(scanf_args, (&data_ptr->C_name))
-
-#define   printf_arg_BOOL(name, data_ptr) data_ptr->name
-#define   printf_arg_SINT(name, data_ptr) data_ptr->name
-#define  printf_arg_USINT(name, data_ptr) data_ptr->name
-#define    printf_arg_INT(name, data_ptr) data_ptr->name
-#define   printf_arg_UINT(name, data_ptr) data_ptr->name
-#define   printf_arg_DINT(name, data_ptr) data_ptr->name
-#define  printf_arg_UDINT(name, data_ptr) data_ptr->name
-#define   printf_arg_LINT(name, data_ptr) data_ptr->name
-#define  printf_arg_ULINT(name, data_ptr) data_ptr->name
-#define   printf_arg_REAL(name, data_ptr) data_ptr->name
-#define  printf_arg_LREAL(name, data_ptr) data_ptr->name
-#define printf_arg_STRING(name, data_ptr) data_ptr->name.len, data_ptr->name.body 
+#define scanf_args_ARRAY(C_type, C_name, name, data_ptr) TYPE_##C_type(scanf_args, data_ptr->C_name.table)
+#define scanf_args_ARRAY_SIMPLE(C_type, index, data_ptr) scanf_arg_##C_type(&data_ptr[index])
+#define scanf_args_ARRAY_OBJECT(C_type, index, data_ptr) TYPE_##C_type(scanf_args, (&data_ptr[index]))
+
+#define   printf_arg_BOOL(arg) arg
+#define   printf_arg_SINT(arg) arg
+#define  printf_arg_USINT(arg) arg
+#define    printf_arg_INT(arg) arg
+#define   printf_arg_UINT(arg) arg
+#define   printf_arg_DINT(arg) arg
+#define  printf_arg_UDINT(arg) arg
+#define   printf_arg_LINT(arg) arg
+#define  printf_arg_ULINT(arg) arg
+#define   printf_arg_REAL(arg) arg
+#define  printf_arg_LREAL(arg) arg
+#define printf_arg_STRING(arg) arg.len, arg.body 
 
 #define printf_args_separator ,
 
-#define printf_args_SIMPLE(C_type, C_name, name, data_ptr) printf_arg_##C_type(C_name, data_ptr)
+#define printf_args_SIMPLE(C_type, C_name, name, data_ptr) printf_arg_##C_type(data_ptr->C_name)
 #define printf_args_OBJECT(C_type, C_name, name, data_ptr) TYPE_##C_type(printf_args, (&data_ptr->C_name))
+#define printf_args_ARRAY(C_type, C_name, name, data_ptr) TYPE_##C_type(printf_args, (&data_ptr->C_name.table))
+#define printf_args_ARRAY_SIMPLE(C_type, index, data_ptr) printf_arg_##C_type(data_ptr[index])
+#define printf_args_ARRAY_OBJECT(C_type, index, data_ptr) TYPE_##C_type(printf_args, (data_ptr[index]))
 
 static void scan_string(const char *str, int len, void *user_data) {{
 	IEC_STRING *iecstr = (IEC_STRING*)user_data;