diff -r 44ce74232ccb -r dac0f9b4e3f8 objdictgen/eds_utils.py --- 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") +