Adding support for defining specific global variables for ConfTreeNodes
authorLaurent Bessard
Thu, 15 Nov 2012 23:00:53 +0100
changeset 883 235a9ec83b95
parent 882 3c6ce0a5ab2c
child 884 e12228fd8773
Adding support for defining specific global variables for ConfTreeNodes
Fix bug when defining function block instances as global variables
ConfigTreeNode.py
PLCControler.py
PLCGenerator.py
ProjectController.py
--- a/ConfigTreeNode.py	Thu Nov 15 22:57:55 2012 +0100
+++ b/ConfigTreeNode.py	Thu Nov 15 23:00:53 2012 +0100
@@ -195,6 +195,18 @@
         shutil.copytree(src_CTNPath, self.CTNPath)
         return True
 
+    def CTNGlobalInstances(self):
+        """
+        @return: [(instance_name, instance_type),...]
+        """
+        return []
+    
+    def _GlobalInstances(self):
+        instances = self.CTNGlobalInstances()
+        for CTNChild in self.IECSortedChildren():
+            instances.extend(CTNChild._GlobalInstances())
+        return instances
+    
     def CTNGenerate_C(self, buildpath, locations):
         """
         Generate C code
--- a/PLCControler.py	Thu Nov 15 22:57:55 2012 +0100
+++ b/PLCControler.py	Thu Nov 15 23:00:53 2012 +0100
@@ -1476,6 +1476,32 @@
     def GetVariableLocationTree(self):
         return []
 
+    def GetConfNodeGlobalInstances(self):
+        return []
+
+    def GetConfigurationExtraVariables(self):
+        global_vars = []
+        for var_name, var_type in self.GetConfNodeGlobalInstances():
+            tempvar = plcopen.varListPlain_variable()
+            tempvar.setname(var_name)
+            
+            tempvartype = plcopen.dataType()
+            if var_type in self.GetBaseTypes():
+                if var_type == "STRING":
+                    var_type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
+                elif var_type == "WSTRING":
+                    var_type.setcontent({"name" : "wstring", "value" : plcopen.elementaryTypes_wstring()})
+                else:
+                    var_type.setcontent({"name" : var_type, "value" : None})
+            else:
+                tempderivedtype = plcopen.derivedTypes_derived()
+                tempderivedtype.setname(var_type)
+                tempvartype.setcontent({"name" : "derived", "value" : tempderivedtype})
+            tempvar.settype(tempvartype)
+            
+            global_vars.append(tempvar)
+        return global_vars
+
     # Function that returns the block definition associated to the block type given
     def GetBlockType(self, type, inputs = None, debug = False):
         result_blocktype = None
@@ -1723,6 +1749,8 @@
             if words[0] == "D":
                 infos = {}
                 datatype = project.getdataType(words[1])
+                if datatype is None:
+                    return None
                 basetype_content = datatype.baseType.getcontent()
                 if basetype_content["value"] is None or basetype_content["name"] in ["string", "wstring"]:
                     infos["type"] = "Directly"
--- a/PLCGenerator.py	Thu Nov 15 22:57:55 2012 +0100
+++ b/PLCGenerator.py	Thu Nov 15 23:00:53 2012 +0100
@@ -268,8 +268,17 @@
                   (configuration.getname(), (tagname, "name")),
                   ("\n", ())]
         var_number = 0
+        
+        varlists = [(varlist, varlist.getvariable()[:]) for varlist in configuration.getglobalVars()]
+        
+        extra_variables = self.Controler.GetConfigurationExtraVariables()
+        if len(extra_variables) > 0:
+            if len(varlists) == 0:
+                varlists = [(plcopen.interface_globalVars(), [])]
+            varlists[-1][1].extend(extra_variables)
+            
         # Generate any global variable in configuration
-        for varlist in configuration.getglobalVars():
+        for varlist, varlist_variables in varlists:
             variable_type = errorVarTypes.get("VAR_GLOBAL", "var_local")
             # Generate variable block with modifier
             config += [("  VAR_GLOBAL", ())]
@@ -281,7 +290,7 @@
                 config += [(" NON_RETAIN", (tagname, variable_type, (var_number, var_number + len(varlist.getvariable())), "non_retain"))]
             config += [("\n", ())]
             # Generate any variable of this block
-            for var in varlist.getvariable():
+            for var in varlist_variables:
                 vartype_content = var.gettype().getcontent()
                 if vartype_content["name"] == "derived":
                     var_type = vartype_content["value"].getname()
@@ -512,15 +521,24 @@
                         current_type = var_type
                         break
             while current_type is not None and len(parts) > 0:
-                tagname = self.ParentGenerator.Controler.ComputeDataTypeName(current_type)
-                infos = self.ParentGenerator.Controler.GetDataTypeInfos(tagname)
-                name = parts.pop(0)
-                current_type = None
-                if infos is not None and infos["type"] == "Structure":
-                    for element in infos["elements"]:
-                        if element["Name"] == name:
-                            current_type = element["Type"]
+                blocktype = self.ParentGenerator.Controler.GetBlockType(current_type)
+                if blocktype is not None:
+                    name = parts.pop(0)
+                    current_type = None
+                    for var_name, var_type, var_modifier in blocktype["inputs"] + blocktype["outputs"]:
+                        if var_name == name:
+                            current_type = var_type
                             break
+                else:
+                    tagname = self.ParentGenerator.Controler.ComputeDataTypeName(current_type)
+                    infos = self.ParentGenerator.Controler.GetDataTypeInfos(tagname)
+                    if infos is not None and infos["type"] == "Structure":
+                        name = parts.pop(0)
+                        current_type = None
+                        for element in infos["elements"]:
+                            if element["Name"] == name:
+                                current_type = element["Type"]
+                                break
         return current_type
     
     # Return connectors linked by a connection to the given connector
--- a/ProjectController.py	Thu Nov 15 22:57:55 2012 +0100
+++ b/ProjectController.py	Thu Nov 15 23:00:53 2012 +0100
@@ -503,7 +503,10 @@
                     # finally store into located variable list
                     locations.append(resdict)
         return locations
-        
+    
+    def GetConfNodeGlobalInstances(self):
+        return self._GlobalInstances()
+    
     def _Generate_SoftPLC(self):
         """
         Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C
@@ -697,15 +700,23 @@
                     self._ProgramList.append(attrs)
         
                 # second section contains all variables
+                config_FBs = {}
                 for line in ListGroup[1]:
                     # Split and Maps each field to dictionnary entries
                     attrs = dict(zip(VariablesListAttributeName,line.strip().split(';')))
                     # Truncate "C_path" to remove conf an ressources names
                     parts = attrs["C_path"].split(".",2)
                     if len(parts) > 2:
-                        attrs["C_path"] = '__'.join(parts[1:])
+                        config_FB = config_FBs.get(tuple(parts[:2]))
+                        if config_FB:
+                            parts = [config_FB] + parts[2:]
+                            attrs["C_path"] = '.'.join(parts)
+                        else: 
+                            attrs["C_path"] = '__'.join(parts[1:])
                     else:
                         attrs["C_path"] = '__'.join(parts)
+                        if attrs["vartype"] == "FB":
+                            config_FBs[tuple(parts)] = attrs["C_path"]
                     # Push this dictionnary into result.
                     self._VariablesList.append(attrs)
                     # Fill in IEC<->C translation dicts
@@ -741,18 +752,19 @@
                "IN":"extern __IEC_%(type)s_p %(C_path)s;",
                "MEM":"extern __IEC_%(type)s_p %(C_path)s;",
                "OUT":"extern __IEC_%(type)s_p %(C_path)s;",
-               "VAR":"extern __IEC_%(type)s_t %(C_path)s;"}[v["vartype"]]%v 
-               for v in self._VariablesList if v["vartype"] != "FB" and v["C_path"].find('.')<0]),
+               "VAR":"extern __IEC_%(type)s_t %(C_path)s;",
+               "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v 
+               for v in self._VariablesList if v["C_path"].find('.')<0]),
            "for_each_variable_do_code":"\n".join([
-               {"EXT":"    (*fp)((void*)&%(C_path)s,%(type)s_P_ENUM);\n",
-                "IN":"    (*fp)((void*)&%(C_path)s,%(type)s_P_ENUM);\n",
-                "MEM":"    (*fp)((void*)&%(C_path)s,%(type)s_O_ENUM);\n",
-                "OUT":"    (*fp)((void*)&%(C_path)s,%(type)s_O_ENUM);\n",
-                "VAR":"    (*fp)((void*)&%(C_path)s,%(type)s_ENUM);\n"}[v["vartype"]]%v
+               {"EXT":"    (*fp)((void*)&(%(C_path)s),%(type)s_P_ENUM);\n",
+                "IN":"    (*fp)((void*)&(%(C_path)s),%(type)s_P_ENUM);\n",
+                "MEM":"    (*fp)((void*)&(%(C_path)s),%(type)s_O_ENUM);\n",
+                "OUT":"    (*fp)((void*)&(%(C_path)s),%(type)s_O_ENUM);\n",
+                "VAR":"    (*fp)((void*)&(%(C_path)s),%(type)s_ENUM);\n"}[v["vartype"]]%v
                 for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ]),
            "find_variable_case_code":"\n".join([
                "    case %(num)s:\n"%v+
-               "        *varp = (void*)&%(C_path)s;\n"%v+
+               "        *varp = (void*)&(%(C_path)s);\n"%v+
                {"EXT":"        return %(type)s_P_ENUM;\n",
                 "IN":"        return %(type)s_P_ENUM;\n",
                 "MEM":"        return %(type)s_O_ENUM;\n",