mqtt/mqtt_client_gen.py
changeset 4012 6337c9c2c379
parent 4011 fdbb3c4ebbf6
child 4013 7f4226b2f867
--- a/mqtt/mqtt_client_gen.py	Thu Sep 05 15:55:46 2024 +0200
+++ b/mqtt/mqtt_client_gen.py	Fri Sep 13 14:26:55 2024 +0200
@@ -4,7 +4,7 @@
 import csv
 import functools
 from threading import Thread
-from collections import OrderedDict
+from collections import OrderedDict as OD
 
 import wx
 import wx.dataview as dv
@@ -336,12 +336,14 @@
                 for row in data:
                     writer.writerow([direction] + row)
 
-    def GenerateC(self, path, locstr, config):
+    def GenerateC(self, path, locstr, config, datatype_info_getter):
         c_template_filepath = paths.AbsNeighbourFile(__file__, "mqtt_template.c")
         c_template_file = open(c_template_filepath , 'rb')
         c_template = c_template_file.read()
         c_template_file.close()
 
+        json_types = OD()
+
         formatdict = dict(
             locstr          = locstr,
             uri             = config["URI"],
@@ -353,7 +355,8 @@
             init_pubsub     = "",
             retrieve        = "",
             publish         = "",
-            publish_changes = ""
+            publish_changes = "",
+            json_decl       = ""
         )
 
 
@@ -384,19 +387,22 @@
             if iec_type in MQTT_IEC_types:
                 C_type, iec_size_prefix = MQTT_IEC_types[iec_type]
                 c_loc_name = "__Q" + iec_size_prefix + locstr + "_" + str(iec_number)
+                encoding = "SIMPLE"
             else:
                 C_type = iec_type.upper();
                 c_loc_name = "__Q" + locstr + "_" + str(iec_number)
+                json_types.setdefault(iec_type,OD()).setdefault("OUTPUT",[]).append(c_loc_name)
+                encoding = "JSON"
 
 
             formatdict["decl"] += """
 DECL_VAR({iec_type}, {C_type}, {c_loc_name})""".format(**locals())
             formatdict["init_pubsub"] += """
-    INIT_PUBLICATION({Topic}, {QoS}, {C_type}, {c_loc_name}, {Retained})""".format(**locals())
+    INIT_PUBLICATION({encoding}, {Topic}, {QoS}, {C_type}, {c_loc_name}, {Retained})""".format(**locals())
             formatdict["publish"] += """
         WRITE_VALUE({c_loc_name}, {C_type})""".format(**locals())
             formatdict["publish_changes"] += """
-            PUBLISH_CHANGE({Topic}, {QoS}, {C_type}, {c_loc_name}, {Retained})""".format(**locals())
+            PUBLISH_CHANGE({encoding}, {Topic}, {QoS}, {C_type}, {c_loc_name}, {Retained})""".format(**locals())
 
         # inputs need to be sorted for bisection search 
         for row in sorted(self["input"]):
@@ -404,19 +410,80 @@
             if iec_type in MQTT_IEC_types:
                 C_type, iec_size_prefix = MQTT_IEC_types[iec_type]
                 c_loc_name = "__I" + iec_size_prefix + locstr + "_" + str(iec_number)
+                init_topic_call = "INIT_TOPIC"
             else:
                 C_type = iec_type.upper();
                 c_loc_name = "__I" + locstr + "_" + str(iec_number)
+                init_topic_call = "INIT_JSON_TOPIC"
+                json_types.setdefault(iec_type,OD()).setdefault("INPUT",[]).append(c_loc_name)
 
             formatdict["decl"] += """
 DECL_VAR({iec_type}, {C_type}, {c_loc_name})""".format(**locals())
             formatdict["topics"] += """
-    INIT_TOPIC({Topic}, {iec_type}, {c_loc_name})""".format(**locals())
+    {init_topic_call}({Topic}, {iec_type}, {c_loc_name})""".format(**locals())
             formatdict["init_pubsub"] += """
     INIT_SUBSCRIPTION({Topic}, {QoS})""".format(**locals())
             formatdict["retrieve"] += """
         READ_VALUE({c_loc_name}, {C_type})""".format(**locals())
 
+        def recurseJsonTypes(datatype, basetypes):
+            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
+        for iec_type,_instances in json_types.items():
+            recurseJsonTypes(iec_type, basetypes)
+
+        done_types = set()
+        # 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:
+                continue
+            done_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"]
+                field_C_type = field_iec_type.upper()
+                field_name = element["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_name + ", _A)"
+                if idx != last:
+                    json_decl += " _P##_separator \\"
+                else:
+                    json_decl += "\n"
+                json_decl += "\n"
+
+
+            formatdict["json_decl"] += json_decl
+
+        for iec_type, instances in json_types.items():
+            C_type = iec_type.upper()
+            for direction, instance_list in instances.items():
+                for c_loc_name in instance_list:
+                    formatdict["json_decl"] += "DECL_JSON_"+direction+"("+C_type+", "+c_loc_name+")\n"
+
         Ccode = c_template.format(**formatdict)
 
         return Ccode