objdictgen/eds_utils.py
changeset 205 dac0f9b4e3f8
parent 182 988f2b302aa6
child 206 6787754b251b
--- a/objdictgen/eds_utils.py	Fri May 25 23:57:17 2007 +0200
+++ b/objdictgen/eds_utils.py	Mon May 28 18:08:24 2007 +0200
@@ -23,29 +23,41 @@
 
 
 import node
+from node import nosub, var, array, rec, plurivar, pluriarray, plurirec
 from sets import *
 from types import *
 from time import *
 import os,re
 
 # Regular expression for finding index section names
-index_model = re.compile('([0-9a-fA-F]{1,4})')
+index_model = re.compile('([0-9A-F]{1,4})')
 # Regular expression for finding subindex section names
-subindex_model = re.compile('([0-9a-fA-F]{1,4})sub([0-9a-fA-F]{1,2})')
+subindex_model = re.compile('([0-9A-F]{1,4})SUB([0-9A-F]{1,2})')
+
+# Regular expression for finding NodeXPresent keynames
+nodepresent_model = re.compile('NODE([0-9]{1,3})PRESENT')
+# Regular expression for finding NodeXName keynames
+nodename_model = re.compile('NODE([0-9]{1,3})NAME')
+# Regular expression for finding NodeXDCFName keynames
+nodedcfname_model = re.compile('NODE([0-9]{1,3})DCFNAME')
 
 # Dictionary for quickly translate boolean into integer value
 BOOL_TRANSLATE = {True : "1", False : "0"}
 
+# Dictionary for quickly translate eds access value into canfestival access value
+ACCESS_TRANSLATE = {"ro" : "ro", "wo" : "wo", "rw" : "rw", "rwr" : "rw", "rww" : "rw", "const" : "ro"}
+
 # Function for verifying data values
 is_integer = lambda x: type(x) == IntType
 is_string = lambda x: type(x) == StringType
+is_boolean = lambda x: x in (0, 1)
 
 # Define checking of value for each attribute
 ENTRY_ATTRIBUTES = {"SUBNUMBER" : is_integer, "PARAMETERNAME" : is_string, 
                     "OBJECTTYPE" : lambda x: x in (7, 8, 9), "DATATYPE" : is_integer, 
                     "LOWLIMIT" : is_integer, "HIGHLIMIT" : is_integer,
                     "ACCESSTYPE" : lambda x: x in ["ro","wo", "rw", "rwr", "rww", "const"],
-                    "DEFAULTVALUE" : lambda x: True, "PDOMAPPING" : lambda x: x in (0, 1),
+                    "DEFAULTVALUE" : lambda x: True, "PDOMAPPING" : is_boolean,
                     "OBJFLAGS" : is_integer}
 
 # Define entry parameters by entry ObjectType number
@@ -63,29 +75,29 @@
 # Function that search into Node Mappings the informations about an index or a subindex
 # and return the default value
 def GetDefaultValue(index, subIndex = None):
-    infos = Manager.GetEntryInfos(index, Node)
+    infos = Node.GetEntryInfos(index)
     if infos["struct"] & node.OD_MultipleSubindexes:
         # First case entry is a record
         if infos["struct"] & node.OD_IdenticalSubindexes:
-            subentry_infos = Manager.GetSubentryInfos(index, 1, Node)
+            subentry_infos = Node.GetSubentryInfos(index, 1)
         # Second case entry is an array
         else:
-            subentry_infos = Manager.GetSubentryInfos(index, subIndex, Node)
+            subentry_infos = Node.GetSubentryInfos(index, subIndex)
         # If a default value is defined for this subindex, returns it
         if "default" in subentry_infos:
             return subentry_infos["default"]
         # If not, returns the default value for the subindex type
         else:
-            return Manager.GetTypeDefaultValue(subentry_infos["type"], Node)
+            return Node.GetTypeDefaultValue(subentry_infos["type"])
     # Third case entry is a var
     else:
-        subentry_infos = Manager.GetSubentryInfos(index, 0, Node)
+        subentry_infos = Node.GetSubentryInfos(index, 0)
         # If a default value is defined for this subindex, returns it
         if "default" in subentry_infos:
             return subentry_infos["default"]
         # If not, returns the default value for the subindex type
         else:
-            return Manager.GetTypeDefaultValue(subentry_infos["type"], Node)
+            return Node.GetTypeDefaultValue(subentry_infos["type"])
     return None
 
 
@@ -100,18 +112,137 @@
                     "MANDATORYOBJECTS", "OPTIONALOBJECTS", "MANUFACTUREROBJECTS"]
 
 
+# Function that extract sections from a file and returns a dictionary of the informations
+def ExtractSections(file):
+    return [(blocktuple[0],                # EntryName : Assignements dict
+             blocktuple[-1].splitlines())  # all the lines
+             for blocktuple in [           # Split the eds files into
+             block.split("]")              # (EntryName,Assignements) tuple
+             for block in                  # for each blocks staring with '['
+             file.split("[")]
+             if blocktuple[0].isalnum()]   # if EntryName exists
+    
+
+# Function that parse an CPJ file and returns a dictionary of the informations
+def ParseCPJFile(filepath):
+    networks = []
+    # Read file text
+    cpj_file = open(filepath,'r').read()
+    sections = ExtractSections(cpj_file)
+    # Parse assignments for each section
+    for section_name, assignments in sections:
+        
+        # Verify that section name is TOPOLOGY 
+        if section_name.upper() in "TOPOLOGY":
+            
+            # Reset values for topology
+            topology = {"Name" : "", "Nodes" : {}}
+            
+            for assignment in assignments:
+                # Escape any comment
+                if assignment.startswith(";"):
+                    pass
+                # Verify that line is a valid assignment
+                elif assignment.find('=') > 0:
+                    # Split assignment into the two values keyname and value
+                    # Verify that there is only one '=' character in the line
+                    try:
+                        keyname, value = assignment.split("=")
+                    except:
+                        raise SyntaxError, "\"%s\" is not a valid EDS line"%assignment.strip()
+                    
+                    # keyname must be immediately followed by the "=" sign, so we
+                    # verify that there is no whitespace into keyname
+                    if keyname.isalnum():
+                        # value can be preceded and followed by whitespaces, so we escape them
+                        value = value.strip()
+                
+                        # First case, value starts with "0x", then it's an hexadecimal value
+                        if value.startswith("0x"):
+                            try:
+                                computed_value = int(value, 16)
+                            except:
+                                raise SyntaxError, "\"%s\" is not a valid value for attribute \"%s\" of section \"[%s]\""%(value, keyname, section_name)
+                        elif value.isdigit():
+                            # Second case, value is a number and starts with "0", then it's an octal value
+                            if value.startswith("0"):
+                                computed_value = int(value, 8)
+                            # Third case, value is a number and don't start with "0", then it's a decimal value
+                            else:
+                                computed_value = int(value)
+                        # In any other case, we keep string value
+                        else:
+                            computed_value = value
+                        
+                        # Search if the section name match any cpj expression
+                        nodepresent_result = nodepresent_model.match(keyname.upper())
+                        nodename_result = nodename_model.match(keyname.upper())
+                        nodedcfname_result = nodedcfname_model.match(keyname.upper())
+                        
+                        if keyname.upper() == "NETNAME":
+                            if not is_string(computed_value):
+                                raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name)
+                            topology["Name"] = computed_value
+                        elif keyname.upper() == "NODES":
+                            if not is_integer(computed_value):
+                                raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name)
+                            topology["Number"] = computed_value
+                        elif keyname.upper() == "EDSBASENAME":
+                            if not is_string(computed_value):
+                                raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name)
+                            topology["Path"] = computed_value
+                        elif nodepresent_result:
+                            if not is_boolean(computed_value):
+                                raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name)
+                            nodeid = int(nodepresent_result.groups()[0])
+                            if nodeid not in topology["Nodes"].keys():
+                                topology["Nodes"][nodeid] = {}
+                            topology["Nodes"][nodeid]["Present"] = computed_value
+                        elif nodename_result:
+                            if not is_string(value):
+                                raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name)
+                            nodeid = int(nodename_result.groups()[0])
+                            if nodeid not in topology["Nodes"].keys():
+                                topology["Nodes"][nodeid] = {}
+                            topology["Nodes"][nodeid]["Name"] = computed_value
+                        elif nodedcfname_result:
+                            if not is_string(computed_value):
+                                raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name)
+                            nodeid = int(nodedcfname_result.groups()[0])
+                            if nodeid not in topology["Nodes"].keys():
+                                topology["Nodes"][nodeid] = {}
+                            topology["Nodes"][nodeid]["DCFName"] = computed_value
+                        else:
+                            raise SyntaxError, "Keyname \"%s\" not recognised for section \"[%s]\""%(keyname, section_name)
+                        
+                # All lines that are not empty and are neither a comment neither not a valid assignment
+                elif assignment.strip() != "":
+                    raise SyntaxError, "\"%s\" is not a valid CPJ line"%assignment.strip()
+        
+            if "Number" not in topology.keys():
+                raise SyntaxError, "\"Nodes\" keyname in \"[%s]\" section is missing"%section_name
+        
+            if topology["Number"] != len(topology["Nodes"]):
+                raise SyntaxError, "\"Nodes\" value not corresponding to number of nodes defined"
+            
+            for nodeid, node in topology["Nodes"].items():
+                if "Present" not in node.keys():
+                    raise SyntaxError, "\"Node%dPresent\" keyname in \"[%s]\" section is missing"%(nodeid, section_name)
+            
+            networks.append(topology)
+            
+        # In other case, there is a syntax problem into CPJ file
+        else:
+            raise SyntaxError, "Section \"[%s]\" is unrecognized"%section_name
+    
+    return networks
+
 # Function that parse an EDS file and returns a dictionary of the informations
-def ParseFile(filepath):
+def ParseEDSFile(filepath):
     eds_dict = {}
     # Read file text
     eds_file = open(filepath,'r').read()
-    sections = [(blocktuple[0],                # EntryName : Assignements dict
-                 blocktuple[-1].splitlines())  # all the lines
-                 for blocktuple in [           # Split the eds files into
-                 block.split("]")              # (EntryName,Assignements) tuple
-                 for block in                  # for each blocks staring with '['
-                 eds_file.split("[")]
-                 if blocktuple[0].isalnum()]   # if EntryName exists
+    sections = ExtractSections(eds_file)
     
     # Parse assignments for each section
     for section_name, assignments in sections:
@@ -119,8 +250,8 @@
         values = {}
         
         # Search if the section name match an index or subindex expression
-        index_result = index_model.match(section_name)
-        subindex_result = subindex_model.match(section_name)
+        index_result = index_model.match(section_name.upper())
+        subindex_result = subindex_model.match(section_name.upper())
         
         # Compilation of the EDS information dictionary
         
@@ -170,6 +301,7 @@
             # Verify that line is a valid assignment
             elif assignment.find('=') > 0:
                 # Split assignment into the two values keyname and value
+                # Verify that there is only one '=' character in the line
                 try:
                     keyname, value = assignment.split("=")
                 except:
@@ -182,7 +314,8 @@
                     # First case, value starts with "$NODEID", then it's a formula
                     if value.startswith("$NODEID"):
                         try:
-                            computed_value = int(value.replace("$NODEID+", ""), 16)
+                            test = int(value.replace("$NODEID+", ""), 16)
+                            computed_value = value.replace("$NODEID", "self.ID")
                         except:
                             raise SyntaxError, "\"%s\" is not a valid formula for attribute \"%s\" of section \"[%s]\""%(value, keyname, section_name)
                     # Second case, value starts with "0x", then it's an hexadecimal value
@@ -320,7 +453,7 @@
     fileContent += "GroupMessaging=0\n"
     # Calculate receive and tranmit PDO numbers with the entry available
     fileContent += "NrOfRXPDO=%d\n"%len([idx for idx in entries if 0x1400 <= idx <= 0x15FF])
-    fileContent += "NrOfTXPDO=%d\n"%len([idx for idx in entries if 0x1400 <= idx <= 0x15FF])
+    fileContent += "NrOfTXPDO=%d\n"%len([idx for idx in entries if 0x1800 <= idx <= 0x19FF])
     # LSS not supported as soon as DS-302 was not fully implemented
     fileContent += "LSS_Supported=0\n"
     
@@ -455,17 +588,31 @@
     except ValueError, message:
         return "Unable to generate EDS file\n%s"%message
     
+# Function that generate the CPJ file content for the nodelist
+def GenerateCPJContent(nodelist):
+    nodes = nodelist.SlaveNodes.keys()
+    nodes.sort()
+    
+    fileContent = "[TOPOLOGY]\n"
+    fileContent += "NetName=%s\n"%nodelist.GetNetworkName()
+    fileContent += "Nodes=0x%2.2X\n"%len(nodes)
+    
+    for nodeid in nodes:
+        fileContent += "Node%dPresent=0x01\n"%nodeid
+        fileContent += "Node%dName=%s\n"%(nodeid, nodelist.SlaveNodes[nodeid]["Name"])
+        fileContent += "Node%dDCFName=%s\n"%(nodeid, nodelist.SlaveNodes[nodeid]["EDS"])
+        
+    fileContent += "EDSBaseName=eds\n"
+    return fileContent
 
 # Function that generates Node from an EDS file
-def GenerateNode(filepath, manager, cwd):
+def GenerateNode(filepath, cwd, nodeID = 0):
     global Node
-    global Manager
-    Manager = manager
     # Create a new node
-    Node = node.Node()
+    Node = node.Node(id = nodeID)
     try:
         # Parse file and extract dictionary of EDS entry
-        eds_dict = ParseFile(filepath)
+        eds_dict = ParseEDSFile(filepath)
         # Extract Profile Number from Device Type entry
         ProfileNb = eds_dict[0x1000]["DEFAULTVALUE"] & 0x0000ffff
         # If profile is not DS-301 or DS-302
@@ -490,7 +637,7 @@
                 pass
             else:
                 # Extract informations for the entry
-                entry_infos = Manager.GetEntryInfos(entry, Node)
+                entry_infos = Node.GetEntryInfos(entry)
                 
                 # If no informations are available, then we write them
                 if not entry_infos:
@@ -501,7 +648,7 @@
                         # Add mapping for first subindex
                         Node.AddMappingEntry(entry, 0, values = {"name" : values["PARAMETERNAME"], 
                                                                  "type" : values["DATATYPE"], 
-                                                                 "access" : values["ACCESSTYPE"], 
+                                                                 "access" : ACCESS_TRANSLATE[values["ACCESSTYPE"]], 
                                                                  "pdo" : values["PDOMAPPING"] == 1})
                     # Second case, entry is an ARRAY
                     elif values["OBJECTTYPE"] == 8:
@@ -520,7 +667,7 @@
                             if subindex in values["subindexes"]:
                                 Node.AddMappingEntry(entry, subindex, values = {"name" : values["subindexes"][subindex]["PARAMETERNAME"], 
                                                                                 "type" : values["subindexes"][subindex]["DATATYPE"], 
-                                                                                "access" : values["subindexes"][subindex]["ACCESSTYPE"], 
+                                                                                "access" : ACCESS_TRANSLATE[values["subindexes"][subindex]["ACCESSTYPE"]], 
                                                                                 "pdo" : values["subindexes"][subindex]["PDOMAPPING"] == 1})
                             # if not, we add a mapping for compatibility 
                             else:
@@ -538,7 +685,7 @@
                         if 1 in values:
                             Node.AddMappingEntry(entry, 1, values = {"name" : values["PARAMETERNAME"] + " %d[(sub)]", 
                                                                      "type" : values["subindexes"][1]["DATATYPE"], 
-                                                                     "access" : values["subindexes"][1]["ACCESSTYPE"], 
+                                                                     "access" : ACCESS_TRANSLATE[values["subindexes"][1]["ACCESSTYPE"]], 
                                                                      "pdo" : values["subindexes"][1]["PDOMAPPING"] == 1})
                         else:
                             raise SyntaxError, "Error on entry 0x%4.4X:\nA RECORD entry must have at least 2 subindexes"%entry
@@ -576,12 +723,12 @@
                         raise SyntaxError, "Array or Record entry 0x%4.4X must have a \"SubNumber\" attribute"%entry
         return Node
     except SyntaxError, message:
-        return "Unable to import EDS File\n%s"%message
+        return "Unable to import EDS file\n%s"%message
 
 #-------------------------------------------------------------------------------
 #                             Main Function
 #-------------------------------------------------------------------------------
 
 if __name__ == '__main__':
-    print ParseFile("examples/PEAK MicroMod.eds")
-
+    print ParseEDSFile("examples/PEAK MicroMod.eds")
+