21 #License along with this library; if not, write to the Free Software |
21 #License along with this library; if not, write to the Free Software |
22 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 |
23 |
24 |
24 |
25 import node |
25 import node |
|
26 from node import nosub, var, array, rec, plurivar, pluriarray, plurirec |
26 from sets import * |
27 from sets import * |
27 from types import * |
28 from types import * |
28 from time import * |
29 from time import * |
29 import os,re |
30 import os,re |
30 |
31 |
31 # Regular expression for finding index section names |
32 # Regular expression for finding index section names |
32 index_model = re.compile('([0-9a-fA-F]{1,4})') |
33 index_model = re.compile('([0-9A-F]{1,4})') |
33 # Regular expression for finding subindex section names |
34 # Regular expression for finding subindex section names |
34 subindex_model = re.compile('([0-9a-fA-F]{1,4})sub([0-9a-fA-F]{1,2})') |
35 subindex_model = re.compile('([0-9A-F]{1,4})SUB([0-9A-F]{1,2})') |
|
36 |
|
37 # Regular expression for finding NodeXPresent keynames |
|
38 nodepresent_model = re.compile('NODE([0-9]{1,3})PRESENT') |
|
39 # Regular expression for finding NodeXName keynames |
|
40 nodename_model = re.compile('NODE([0-9]{1,3})NAME') |
|
41 # Regular expression for finding NodeXDCFName keynames |
|
42 nodedcfname_model = re.compile('NODE([0-9]{1,3})DCFNAME') |
35 |
43 |
36 # Dictionary for quickly translate boolean into integer value |
44 # Dictionary for quickly translate boolean into integer value |
37 BOOL_TRANSLATE = {True : "1", False : "0"} |
45 BOOL_TRANSLATE = {True : "1", False : "0"} |
|
46 |
|
47 # Dictionary for quickly translate eds access value into canfestival access value |
|
48 ACCESS_TRANSLATE = {"ro" : "ro", "wo" : "wo", "rw" : "rw", "rwr" : "rw", "rww" : "rw", "const" : "ro"} |
38 |
49 |
39 # Function for verifying data values |
50 # Function for verifying data values |
40 is_integer = lambda x: type(x) == IntType |
51 is_integer = lambda x: type(x) == IntType |
41 is_string = lambda x: type(x) == StringType |
52 is_string = lambda x: type(x) == StringType |
|
53 is_boolean = lambda x: x in (0, 1) |
42 |
54 |
43 # Define checking of value for each attribute |
55 # Define checking of value for each attribute |
44 ENTRY_ATTRIBUTES = {"SUBNUMBER" : is_integer, "PARAMETERNAME" : is_string, |
56 ENTRY_ATTRIBUTES = {"SUBNUMBER" : is_integer, "PARAMETERNAME" : is_string, |
45 "OBJECTTYPE" : lambda x: x in (7, 8, 9), "DATATYPE" : is_integer, |
57 "OBJECTTYPE" : lambda x: x in (7, 8, 9), "DATATYPE" : is_integer, |
46 "LOWLIMIT" : is_integer, "HIGHLIMIT" : is_integer, |
58 "LOWLIMIT" : is_integer, "HIGHLIMIT" : is_integer, |
47 "ACCESSTYPE" : lambda x: x in ["ro","wo", "rw", "rwr", "rww", "const"], |
59 "ACCESSTYPE" : lambda x: x in ["ro","wo", "rw", "rwr", "rww", "const"], |
48 "DEFAULTVALUE" : lambda x: True, "PDOMAPPING" : lambda x: x in (0, 1), |
60 "DEFAULTVALUE" : lambda x: True, "PDOMAPPING" : is_boolean, |
49 "OBJFLAGS" : is_integer} |
61 "OBJFLAGS" : is_integer} |
50 |
62 |
51 # Define entry parameters by entry ObjectType number |
63 # Define entry parameters by entry ObjectType number |
52 ENTRY_TYPES = {7 : {"name" : " VAR", |
64 ENTRY_TYPES = {7 : {"name" : " VAR", |
53 "require" : ["PARAMETERNAME", "OBJECTTYPE", "DATATYPE", "ACCESSTYPE", "PDOMAPPING"], |
65 "require" : ["PARAMETERNAME", "OBJECTTYPE", "DATATYPE", "ACCESSTYPE", "PDOMAPPING"], |
61 |
73 |
62 |
74 |
63 # Function that search into Node Mappings the informations about an index or a subindex |
75 # Function that search into Node Mappings the informations about an index or a subindex |
64 # and return the default value |
76 # and return the default value |
65 def GetDefaultValue(index, subIndex = None): |
77 def GetDefaultValue(index, subIndex = None): |
66 infos = Manager.GetEntryInfos(index, Node) |
78 infos = Node.GetEntryInfos(index) |
67 if infos["struct"] & node.OD_MultipleSubindexes: |
79 if infos["struct"] & node.OD_MultipleSubindexes: |
68 # First case entry is a record |
80 # First case entry is a record |
69 if infos["struct"] & node.OD_IdenticalSubindexes: |
81 if infos["struct"] & node.OD_IdenticalSubindexes: |
70 subentry_infos = Manager.GetSubentryInfos(index, 1, Node) |
82 subentry_infos = Node.GetSubentryInfos(index, 1) |
71 # Second case entry is an array |
83 # Second case entry is an array |
72 else: |
84 else: |
73 subentry_infos = Manager.GetSubentryInfos(index, subIndex, Node) |
85 subentry_infos = Node.GetSubentryInfos(index, subIndex) |
74 # If a default value is defined for this subindex, returns it |
86 # If a default value is defined for this subindex, returns it |
75 if "default" in subentry_infos: |
87 if "default" in subentry_infos: |
76 return subentry_infos["default"] |
88 return subentry_infos["default"] |
77 # If not, returns the default value for the subindex type |
89 # If not, returns the default value for the subindex type |
78 else: |
90 else: |
79 return Manager.GetTypeDefaultValue(subentry_infos["type"], Node) |
91 return Node.GetTypeDefaultValue(subentry_infos["type"]) |
80 # Third case entry is a var |
92 # Third case entry is a var |
81 else: |
93 else: |
82 subentry_infos = Manager.GetSubentryInfos(index, 0, Node) |
94 subentry_infos = Node.GetSubentryInfos(index, 0) |
83 # If a default value is defined for this subindex, returns it |
95 # If a default value is defined for this subindex, returns it |
84 if "default" in subentry_infos: |
96 if "default" in subentry_infos: |
85 return subentry_infos["default"] |
97 return subentry_infos["default"] |
86 # If not, returns the default value for the subindex type |
98 # If not, returns the default value for the subindex type |
87 else: |
99 else: |
88 return Manager.GetTypeDefaultValue(subentry_infos["type"], Node) |
100 return Node.GetTypeDefaultValue(subentry_infos["type"]) |
89 return None |
101 return None |
90 |
102 |
91 |
103 |
92 #------------------------------------------------------------------------------- |
104 #------------------------------------------------------------------------------- |
93 # Parse file |
105 # Parse file |
98 # an EDS file |
110 # an EDS file |
99 SECTION_KEYNAMES = ["FILEINFO", "DEVICEINFO", "DUMMYUSAGE", "COMMENTS", |
111 SECTION_KEYNAMES = ["FILEINFO", "DEVICEINFO", "DUMMYUSAGE", "COMMENTS", |
100 "MANDATORYOBJECTS", "OPTIONALOBJECTS", "MANUFACTUREROBJECTS"] |
112 "MANDATORYOBJECTS", "OPTIONALOBJECTS", "MANUFACTUREROBJECTS"] |
101 |
113 |
102 |
114 |
|
115 # Function that extract sections from a file and returns a dictionary of the informations |
|
116 def ExtractSections(file): |
|
117 return [(blocktuple[0], # EntryName : Assignements dict |
|
118 blocktuple[-1].splitlines()) # all the lines |
|
119 for blocktuple in [ # Split the eds files into |
|
120 block.split("]") # (EntryName,Assignements) tuple |
|
121 for block in # for each blocks staring with '[' |
|
122 file.split("[")] |
|
123 if blocktuple[0].isalnum()] # if EntryName exists |
|
124 |
|
125 |
|
126 # Function that parse an CPJ file and returns a dictionary of the informations |
|
127 def ParseCPJFile(filepath): |
|
128 networks = [] |
|
129 # Read file text |
|
130 cpj_file = open(filepath,'r').read() |
|
131 sections = ExtractSections(cpj_file) |
|
132 # Parse assignments for each section |
|
133 for section_name, assignments in sections: |
|
134 |
|
135 # Verify that section name is TOPOLOGY |
|
136 if section_name.upper() in "TOPOLOGY": |
|
137 |
|
138 # Reset values for topology |
|
139 topology = {"Name" : "", "Nodes" : {}} |
|
140 |
|
141 for assignment in assignments: |
|
142 # Escape any comment |
|
143 if assignment.startswith(";"): |
|
144 pass |
|
145 # Verify that line is a valid assignment |
|
146 elif assignment.find('=') > 0: |
|
147 # Split assignment into the two values keyname and value |
|
148 # Verify that there is only one '=' character in the line |
|
149 try: |
|
150 keyname, value = assignment.split("=") |
|
151 except: |
|
152 raise SyntaxError, "\"%s\" is not a valid EDS line"%assignment.strip() |
|
153 |
|
154 # keyname must be immediately followed by the "=" sign, so we |
|
155 # verify that there is no whitespace into keyname |
|
156 if keyname.isalnum(): |
|
157 # value can be preceded and followed by whitespaces, so we escape them |
|
158 value = value.strip() |
|
159 |
|
160 # First case, value starts with "0x", then it's an hexadecimal value |
|
161 if value.startswith("0x"): |
|
162 try: |
|
163 computed_value = int(value, 16) |
|
164 except: |
|
165 raise SyntaxError, "\"%s\" is not a valid value for attribute \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
166 elif value.isdigit(): |
|
167 # Second case, value is a number and starts with "0", then it's an octal value |
|
168 if value.startswith("0"): |
|
169 computed_value = int(value, 8) |
|
170 # Third case, value is a number and don't start with "0", then it's a decimal value |
|
171 else: |
|
172 computed_value = int(value) |
|
173 # In any other case, we keep string value |
|
174 else: |
|
175 computed_value = value |
|
176 |
|
177 # Search if the section name match any cpj expression |
|
178 nodepresent_result = nodepresent_model.match(keyname.upper()) |
|
179 nodename_result = nodename_model.match(keyname.upper()) |
|
180 nodedcfname_result = nodedcfname_model.match(keyname.upper()) |
|
181 |
|
182 if keyname.upper() == "NETNAME": |
|
183 if not is_string(computed_value): |
|
184 raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
185 topology["Name"] = computed_value |
|
186 elif keyname.upper() == "NODES": |
|
187 if not is_integer(computed_value): |
|
188 raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
189 topology["Number"] = computed_value |
|
190 elif keyname.upper() == "EDSBASENAME": |
|
191 if not is_string(computed_value): |
|
192 raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
193 topology["Path"] = computed_value |
|
194 elif nodepresent_result: |
|
195 if not is_boolean(computed_value): |
|
196 raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
197 nodeid = int(nodepresent_result.groups()[0]) |
|
198 if nodeid not in topology["Nodes"].keys(): |
|
199 topology["Nodes"][nodeid] = {} |
|
200 topology["Nodes"][nodeid]["Present"] = computed_value |
|
201 elif nodename_result: |
|
202 if not is_string(value): |
|
203 raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
204 nodeid = int(nodename_result.groups()[0]) |
|
205 if nodeid not in topology["Nodes"].keys(): |
|
206 topology["Nodes"][nodeid] = {} |
|
207 topology["Nodes"][nodeid]["Name"] = computed_value |
|
208 elif nodedcfname_result: |
|
209 if not is_string(computed_value): |
|
210 raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
211 nodeid = int(nodedcfname_result.groups()[0]) |
|
212 if nodeid not in topology["Nodes"].keys(): |
|
213 topology["Nodes"][nodeid] = {} |
|
214 topology["Nodes"][nodeid]["DCFName"] = computed_value |
|
215 else: |
|
216 raise SyntaxError, "Keyname \"%s\" not recognised for section \"[%s]\""%(keyname, section_name) |
|
217 |
|
218 # All lines that are not empty and are neither a comment neither not a valid assignment |
|
219 elif assignment.strip() != "": |
|
220 raise SyntaxError, "\"%s\" is not a valid CPJ line"%assignment.strip() |
|
221 |
|
222 if "Number" not in topology.keys(): |
|
223 raise SyntaxError, "\"Nodes\" keyname in \"[%s]\" section is missing"%section_name |
|
224 |
|
225 if topology["Number"] != len(topology["Nodes"]): |
|
226 raise SyntaxError, "\"Nodes\" value not corresponding to number of nodes defined" |
|
227 |
|
228 for nodeid, node in topology["Nodes"].items(): |
|
229 if "Present" not in node.keys(): |
|
230 raise SyntaxError, "\"Node%dPresent\" keyname in \"[%s]\" section is missing"%(nodeid, section_name) |
|
231 |
|
232 networks.append(topology) |
|
233 |
|
234 # In other case, there is a syntax problem into CPJ file |
|
235 else: |
|
236 raise SyntaxError, "Section \"[%s]\" is unrecognized"%section_name |
|
237 |
|
238 return networks |
|
239 |
103 # Function that parse an EDS file and returns a dictionary of the informations |
240 # Function that parse an EDS file and returns a dictionary of the informations |
104 def ParseFile(filepath): |
241 def ParseEDSFile(filepath): |
105 eds_dict = {} |
242 eds_dict = {} |
106 # Read file text |
243 # Read file text |
107 eds_file = open(filepath,'r').read() |
244 eds_file = open(filepath,'r').read() |
108 sections = [(blocktuple[0], # EntryName : Assignements dict |
245 sections = ExtractSections(eds_file) |
109 blocktuple[-1].splitlines()) # all the lines |
|
110 for blocktuple in [ # Split the eds files into |
|
111 block.split("]") # (EntryName,Assignements) tuple |
|
112 for block in # for each blocks staring with '[' |
|
113 eds_file.split("[")] |
|
114 if blocktuple[0].isalnum()] # if EntryName exists |
|
115 |
246 |
116 # Parse assignments for each section |
247 # Parse assignments for each section |
117 for section_name, assignments in sections: |
248 for section_name, assignments in sections: |
118 # Reset values of entry |
249 # Reset values of entry |
119 values = {} |
250 values = {} |
120 |
251 |
121 # Search if the section name match an index or subindex expression |
252 # Search if the section name match an index or subindex expression |
122 index_result = index_model.match(section_name) |
253 index_result = index_model.match(section_name.upper()) |
123 subindex_result = subindex_model.match(section_name) |
254 subindex_result = subindex_model.match(section_name.upper()) |
124 |
255 |
125 # Compilation of the EDS information dictionary |
256 # Compilation of the EDS information dictionary |
126 |
257 |
127 is_entry = False |
258 is_entry = False |
128 # First case, section name is in SECTION_KEYNAMES |
259 # First case, section name is in SECTION_KEYNAMES |
453 WriteFile(filepath, content) |
586 WriteFile(filepath, content) |
454 return None |
587 return None |
455 except ValueError, message: |
588 except ValueError, message: |
456 return "Unable to generate EDS file\n%s"%message |
589 return "Unable to generate EDS file\n%s"%message |
457 |
590 |
|
591 # Function that generate the CPJ file content for the nodelist |
|
592 def GenerateCPJContent(nodelist): |
|
593 nodes = nodelist.SlaveNodes.keys() |
|
594 nodes.sort() |
|
595 |
|
596 fileContent = "[TOPOLOGY]\n" |
|
597 fileContent += "NetName=%s\n"%nodelist.GetNetworkName() |
|
598 fileContent += "Nodes=0x%2.2X\n"%len(nodes) |
|
599 |
|
600 for nodeid in nodes: |
|
601 fileContent += "Node%dPresent=0x01\n"%nodeid |
|
602 fileContent += "Node%dName=%s\n"%(nodeid, nodelist.SlaveNodes[nodeid]["Name"]) |
|
603 fileContent += "Node%dDCFName=%s\n"%(nodeid, nodelist.SlaveNodes[nodeid]["EDS"]) |
|
604 |
|
605 fileContent += "EDSBaseName=eds\n" |
|
606 return fileContent |
458 |
607 |
459 # Function that generates Node from an EDS file |
608 # Function that generates Node from an EDS file |
460 def GenerateNode(filepath, manager, cwd): |
609 def GenerateNode(filepath, cwd, nodeID = 0): |
461 global Node |
610 global Node |
462 global Manager |
|
463 Manager = manager |
|
464 # Create a new node |
611 # Create a new node |
465 Node = node.Node() |
612 Node = node.Node(id = nodeID) |
466 try: |
613 try: |
467 # Parse file and extract dictionary of EDS entry |
614 # Parse file and extract dictionary of EDS entry |
468 eds_dict = ParseFile(filepath) |
615 eds_dict = ParseEDSFile(filepath) |
469 # Extract Profile Number from Device Type entry |
616 # Extract Profile Number from Device Type entry |
470 ProfileNb = eds_dict[0x1000]["DEFAULTVALUE"] & 0x0000ffff |
617 ProfileNb = eds_dict[0x1000]["DEFAULTVALUE"] & 0x0000ffff |
471 # If profile is not DS-301 or DS-302 |
618 # If profile is not DS-301 or DS-302 |
472 if ProfileNb not in [301, 302]: |
619 if ProfileNb not in [301, 302]: |
473 # Compile Profile name and path to .prf file |
620 # Compile Profile name and path to .prf file |
488 # All sections with a name in keynames are escaped |
635 # All sections with a name in keynames are escaped |
489 if entry in SECTION_KEYNAMES: |
636 if entry in SECTION_KEYNAMES: |
490 pass |
637 pass |
491 else: |
638 else: |
492 # Extract informations for the entry |
639 # Extract informations for the entry |
493 entry_infos = Manager.GetEntryInfos(entry, Node) |
640 entry_infos = Node.GetEntryInfos(entry) |
494 |
641 |
495 # If no informations are available, then we write them |
642 # If no informations are available, then we write them |
496 if not entry_infos: |
643 if not entry_infos: |
497 # First case, entry is a VAR |
644 # First case, entry is a VAR |
498 if values["OBJECTTYPE"] == 7: |
645 if values["OBJECTTYPE"] == 7: |
499 # Add mapping for entry |
646 # Add mapping for entry |
500 Node.AddMappingEntry(entry, name = values["PARAMETERNAME"], struct = 1) |
647 Node.AddMappingEntry(entry, name = values["PARAMETERNAME"], struct = 1) |
501 # Add mapping for first subindex |
648 # Add mapping for first subindex |
502 Node.AddMappingEntry(entry, 0, values = {"name" : values["PARAMETERNAME"], |
649 Node.AddMappingEntry(entry, 0, values = {"name" : values["PARAMETERNAME"], |
503 "type" : values["DATATYPE"], |
650 "type" : values["DATATYPE"], |
504 "access" : values["ACCESSTYPE"], |
651 "access" : ACCESS_TRANSLATE[values["ACCESSTYPE"]], |
505 "pdo" : values["PDOMAPPING"] == 1}) |
652 "pdo" : values["PDOMAPPING"] == 1}) |
506 # Second case, entry is an ARRAY |
653 # Second case, entry is an ARRAY |
507 elif values["OBJECTTYPE"] == 8: |
654 elif values["OBJECTTYPE"] == 8: |
508 # Extract maximum subindex number defined |
655 # Extract maximum subindex number defined |
509 try: |
656 try: |
518 for subindex in xrange(1, int(max_subindex) + 1): |
665 for subindex in xrange(1, int(max_subindex) + 1): |
519 # if subindex is defined |
666 # if subindex is defined |
520 if subindex in values["subindexes"]: |
667 if subindex in values["subindexes"]: |
521 Node.AddMappingEntry(entry, subindex, values = {"name" : values["subindexes"][subindex]["PARAMETERNAME"], |
668 Node.AddMappingEntry(entry, subindex, values = {"name" : values["subindexes"][subindex]["PARAMETERNAME"], |
522 "type" : values["subindexes"][subindex]["DATATYPE"], |
669 "type" : values["subindexes"][subindex]["DATATYPE"], |
523 "access" : values["subindexes"][subindex]["ACCESSTYPE"], |
670 "access" : ACCESS_TRANSLATE[values["subindexes"][subindex]["ACCESSTYPE"]], |
524 "pdo" : values["subindexes"][subindex]["PDOMAPPING"] == 1}) |
671 "pdo" : values["subindexes"][subindex]["PDOMAPPING"] == 1}) |
525 # if not, we add a mapping for compatibility |
672 # if not, we add a mapping for compatibility |
526 else: |
673 else: |
527 Node.AddMappingEntry(entry, subindex, values = {"name" : "Compatibility Entry", "type" : 0x05, "access" : "rw", "pdo" : False}) |
674 Node.AddMappingEntry(entry, subindex, values = {"name" : "Compatibility Entry", "type" : 0x05, "access" : "rw", "pdo" : False}) |
528 # Third case, entry is an RECORD |
675 # Third case, entry is an RECORD |