|
1 #!/usr/bin/env python |
|
2 # -*- coding: utf-8 -*- |
|
3 |
|
4 #This file is part of CanFestival, a library implementing CanOpen Stack. |
|
5 # |
|
6 #Copyright (C): Edouard TISSERANT, Francis DUPIN and Laurent BESSARD |
|
7 # |
|
8 #See COPYING file for copyrights details. |
|
9 # |
|
10 #This library is free software; you can redistribute it and/or |
|
11 #modify it under the terms of the GNU Lesser General Public |
|
12 #License as published by the Free Software Foundation; either |
|
13 #version 2.1 of the License, or (at your option) any later version. |
|
14 # |
|
15 #This library is distributed in the hope that it will be useful, |
|
16 #but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
18 #Lesser General Public License for more details. |
|
19 # |
|
20 #You should have received a copy of the GNU Lesser General Public |
|
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 |
|
23 |
|
24 |
|
25 import node |
|
26 from sets import * |
|
27 from types import * |
|
28 from time import * |
|
29 import os,re |
|
30 |
|
31 # Regular expression for finding index section names |
|
32 index_model = re.compile('([0-9a-fA-F]{1,4})') |
|
33 # 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 |
|
36 # Dictionary for quickly translate boolean into integer value |
|
37 BOOL_TRANSLATE = {True : "1", False : "0"} |
|
38 |
|
39 # Function for verifying data values |
|
40 is_integer = lambda x: type(x) == IntType |
|
41 is_string = lambda x: type(x) == StringType |
|
42 |
|
43 # Define checking of value for each attribute |
|
44 ENTRY_ATTRIBUTES = {"SUBNUMBER" : is_integer, "PARAMETERNAME" : is_string, |
|
45 "OBJECTTYPE" : lambda x: x in (7, 8, 9), "DATATYPE" : is_integer, |
|
46 "LOWLIMIT" : is_integer, "HIGHLIMIT" : is_integer, |
|
47 "ACCESSTYPE" : lambda x: x in ["ro","wo", "rw", "rwr", "rww", "const"], |
|
48 "DEFAULTVALUE" : lambda x: True, "PDOMAPPING" : lambda x: x in (0, 1), |
|
49 "OBJFLAGS" : is_integer} |
|
50 |
|
51 # Define entry parameters by entry ObjectType number |
|
52 ENTRY_TYPES = {7 : {"name" : " VAR", |
|
53 "require" : ["PARAMETERNAME", "OBJECTTYPE", "DATATYPE", "ACCESSTYPE", "PDOMAPPING"], |
|
54 "optional" : ["LOWLIMIT", "HIGHLIMIT", "DEFAULTVALUE", "OBJFLAGS"]}, |
|
55 8 : {"name" : "n ARRAY", |
|
56 "require" : ["SUBNUMBER", "PARAMETERNAME", "OBJECTTYPE"], |
|
57 "optional" : ["OBJFLAGS"]}, |
|
58 9 : {"name" : " RECORD", |
|
59 "require" : ["SUBNUMBER", "PARAMETERNAME", "OBJECTTYPE"], |
|
60 "optional" : ["OBJFLAGS"]}} |
|
61 |
|
62 |
|
63 # Function that search into Node Mappings the informations about an index or a subindex |
|
64 # and return the default value |
|
65 def GetDefaultValue(index, subIndex = None): |
|
66 infos = Manager.GetEntryInfos(index, Node) |
|
67 if infos["struct"] & node.OD_MultipleSubindexes: |
|
68 # First case entry is a record |
|
69 if infos["struct"] & node.OD_IdenticalSubindexes: |
|
70 subentry_infos = Manager.GetSubentryInfos(index, 1, Node) |
|
71 # Second case entry is an array |
|
72 else: |
|
73 subentry_infos = Manager.GetSubentryInfos(index, subIndex, Node) |
|
74 # If a default value is defined for this subindex, returns it |
|
75 if "default" in subentry_infos: |
|
76 return subentry_infos["default"] |
|
77 # If not, returns the default value for the subindex type |
|
78 else: |
|
79 return Manager.GetTypeDefaultValue(subentry_infos["type"], Node) |
|
80 # Third case entry is a var |
|
81 else: |
|
82 subentry_infos = Manager.GetSubentryInfos(index, 0, Node) |
|
83 # If a default value is defined for this subindex, returns it |
|
84 if "default" in subentry_infos: |
|
85 return subentry_infos["default"] |
|
86 # If not, returns the default value for the subindex type |
|
87 else: |
|
88 return Manager.GetTypeDefaultValue(subentry_infos["type"], Node) |
|
89 return None |
|
90 |
|
91 |
|
92 #------------------------------------------------------------------------------- |
|
93 # Parse file |
|
94 #------------------------------------------------------------------------------- |
|
95 |
|
96 |
|
97 # List of section names that are not index and subindex and that we can meet in |
|
98 # an EDS file |
|
99 SECTION_KEYNAMES = ["FILEINFO", "DEVICEINFO", "DUMMYUSAGE", "COMMENTS", |
|
100 "MANDATORYOBJECTS", "OPTIONALOBJECTS", "MANUFACTUREROBJECTS"] |
|
101 |
|
102 |
|
103 # Function that parse an EDS file and returns a dictionary of the informations |
|
104 def ParseFile(filepath): |
|
105 eds_dict = {} |
|
106 # Read file text |
|
107 eds_file = open(filepath,'r').read() |
|
108 sections = [(blocktuple[0], # EntryName : Assignements dict |
|
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 |
|
116 # Parse assignments for each section |
|
117 for section_name, assignments in sections: |
|
118 # Reset values of entry |
|
119 values = {} |
|
120 |
|
121 # Search if the section name match an index or subindex expression |
|
122 index_result = index_model.match(section_name) |
|
123 subindex_result = subindex_model.match(section_name) |
|
124 |
|
125 # Compilation of the EDS information dictionary |
|
126 |
|
127 is_entry = False |
|
128 # First case, section name is in SECTION_KEYNAMES |
|
129 if section_name.upper() in SECTION_KEYNAMES: |
|
130 # Verify that entry is not already defined |
|
131 if section_name.upper() not in eds_dict: |
|
132 eds_dict[section_name.upper()] = values |
|
133 else: |
|
134 raise SyntaxError, "\"[%s]\" section is defined two times"%section_name |
|
135 # Second case, section name is a subindex name |
|
136 elif subindex_result: |
|
137 # Extract index and subindex number |
|
138 index, subindex = [int(value, 16) for value in subindex_result.groups()] |
|
139 # If index hasn't been referenced before, we add an entry into the dictionary |
|
140 # that will be updated later |
|
141 if index not in eds_dict: |
|
142 eds_dict[index] = {"subindexes" : {}} |
|
143 if subindex not in eds_dict[index]["subindexes"]: |
|
144 eds_dict[index]["subindexes"][subindex] = values |
|
145 else: |
|
146 raise SyntaxError, "\"[%s]\" section is defined two times"%section_name |
|
147 is_entry = True |
|
148 # Third case, section name is an index name |
|
149 elif index_result: |
|
150 # Extract index number |
|
151 index = int(index_result.groups()[0], 16) |
|
152 # If index hasn't been referenced before, we add an entry into the dictionary |
|
153 if index not in eds_dict: |
|
154 eds_dict[index] = values |
|
155 eds_dict[index]["subindexes"] = {} |
|
156 elif eds_dict[index].keys() == ["subindexes"]: |
|
157 values["subindexes"] = eds_dict[index]["subindexes"] |
|
158 eds_dict[index] = values |
|
159 else: |
|
160 raise SyntaxError, "\"[%s]\" section is defined two times"%section_name |
|
161 is_entry = True |
|
162 # In any other case, there is a syntax problem into EDS file |
|
163 else: |
|
164 raise SyntaxError, "Section \"[%s]\" is unrecognized"%section_name |
|
165 |
|
166 for assignment in assignments: |
|
167 # Escape any comment |
|
168 if assignment.startswith(";"): |
|
169 pass |
|
170 # Verify that line is a valid assignment |
|
171 elif assignment.find('=') > 0: |
|
172 # Split assignment into the two values keyname and value |
|
173 try: |
|
174 keyname, value = assignment.split("=") |
|
175 except: |
|
176 raise SyntaxError, "\"%s\" is not a valid EDS line"%assignment.strip() |
|
177 # keyname must be immediately followed by the "=" sign, so we |
|
178 # verify that there is no whitespace into keyname |
|
179 if keyname.isalnum(): |
|
180 # value can be preceded and followed by whitespaces, so we escape them |
|
181 value = value.strip() |
|
182 # First case, value starts with "$NODEID", then it's a formula |
|
183 if value.startswith("$NODEID"): |
|
184 try: |
|
185 computed_value = int(value.replace("$NODEID+", ""), 16) |
|
186 except: |
|
187 raise SyntaxError, "\"%s\" is not a valid formula for attribute \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
188 # Second case, value starts with "0x", then it's an hexadecimal value |
|
189 elif value.startswith("0x"): |
|
190 try: |
|
191 computed_value = int(value, 16) |
|
192 except: |
|
193 raise SyntaxError, "\"%s\" is not a valid value for attribute \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
194 elif value.isdigit(): |
|
195 # Third case, value is a number and starts with "0", then it's an octal value |
|
196 if value.startswith("0"): |
|
197 computed_value = int(value, 8) |
|
198 # Forth case, value is a number and don't start with "0", then it's a decimal value |
|
199 else: |
|
200 computed_value = int(value) |
|
201 # In any other case, we keep string value |
|
202 else: |
|
203 computed_value = value |
|
204 |
|
205 # Add value to values dictionary |
|
206 if computed_value != "": |
|
207 # If entry is an index or a subindex |
|
208 if is_entry: |
|
209 # Verify that keyname is a possible attribute |
|
210 if keyname.upper() not in ENTRY_ATTRIBUTES: |
|
211 raise SyntaxError, "Keyname \"%s\" not recognised for section \"[%s]\""%(keyname, section_name) |
|
212 # Verify that value is valid |
|
213 elif not ENTRY_ATTRIBUTES[keyname.upper()](computed_value): |
|
214 raise SyntaxError, "Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\""%(value, keyname, section_name) |
|
215 else: |
|
216 values[keyname.upper()] = computed_value |
|
217 else: |
|
218 values[keyname.upper()] = computed_value |
|
219 # All lines that are not empty and are neither a comment neither not a valid assignment |
|
220 elif assignment.strip() != "": |
|
221 raise SyntaxError, "\"%s\" is not a valid EDS line"%assignment.strip() |
|
222 |
|
223 # If entry is an index or a subindex |
|
224 if is_entry: |
|
225 # Verify that entry has an ObjectType |
|
226 if "OBJECTTYPE" in values.keys(): |
|
227 # Extract entry ObjectType |
|
228 objecttype = values["OBJECTTYPE"] |
|
229 # Extract parameters defined |
|
230 keys = Set(values.keys()) |
|
231 keys.discard("subindexes") |
|
232 # Extract possible parameters and parameters required |
|
233 possible = Set(ENTRY_TYPES[objecttype]["require"] + ENTRY_TYPES[objecttype]["optional"]) |
|
234 required = Set(ENTRY_TYPES[objecttype]["require"]) |
|
235 # Verify that parameters defined contains all the parameters required |
|
236 if not keys.issuperset(required): |
|
237 missing = required.difference(keys)._data.keys() |
|
238 if len(missing) > 1: |
|
239 attributes = "Attributes %s are"%", ".join(["\"%s\""%attribute for attribute in missing]) |
|
240 else: |
|
241 attributes = "Attribute \"%s\" is"%missing[0] |
|
242 raise SyntaxError, "Error on section \"[%s]\":\n%s required for a%s entry"%(section_name, attributes, ENTRY_TYPES[objecttype]["name"]) |
|
243 # Verify that parameters defined are all in the possible parameters |
|
244 if not keys.issubset(possible): |
|
245 unsupported = keys.difference(possible)._data.keys() |
|
246 if len(unsupported) > 1: |
|
247 attributes = "Attributes %s are"%", ".join(["\"%s\""%attribute for attribute in unsupported]) |
|
248 else: |
|
249 attributes = "Attribute \"%s\" is"%unsupported[0] |
|
250 raise SyntaxError, "Error on section \"[%s]\":\n%s unsupported for a%s entry"%(section_name, attributes, ENTRY_TYPES[objecttype]["name"]) |
|
251 else: |
|
252 raise SyntaxError, "Error on section \"[%s]\":\nAttribute OBJECTTYPE is required"%section_name |
|
253 |
|
254 return eds_dict |
|
255 |
|
256 |
|
257 # Function that write an EDS file after generate it's content |
|
258 def WriteFile(filepath, content): |
|
259 # Open file in write mode |
|
260 cfile = open(filepath,"w") |
|
261 # Write content |
|
262 cfile.write(content) |
|
263 # Close file |
|
264 cfile.close() |
|
265 |
|
266 |
|
267 # Function that generate the EDS file content for the current node in the manager |
|
268 def GenerateFileContent(filepath): |
|
269 # Dictionary of each index contents |
|
270 indexContents = {} |
|
271 |
|
272 # Extract local time |
|
273 current_time = localtime() |
|
274 # Extract node informations |
|
275 nodename, nodeid, nodetype, description = Manager.GetCurrentNodeInfos() |
|
276 |
|
277 # Compiling lists of indexes defined |
|
278 entries = [idx for name, idx in Manager.GetCurrentValidIndexes(0, 0xFFFF)] |
|
279 |
|
280 # Generate FileInfo section |
|
281 fileContent = "[FileInfo]\n" |
|
282 fileContent += "CreatedBy=CANFestival\n" |
|
283 fileContent += "Description=%s\n"%description |
|
284 fileContent += "CreationTime=%s"%strftime("%I:%M", current_time) |
|
285 # %p option of strftime seems not working, then generate AM/PM by hands |
|
286 if strftime("%I", current_time) == strftime("%H", current_time): |
|
287 fileContent += "AM\n" |
|
288 else: |
|
289 fileContent += "PM\n" |
|
290 fileContent += "CreationDate=%s\n"%strftime("%m-%d-%Y", current_time) |
|
291 fileContent += "FileName=%s\n"%os.path.split(filepath)[-1] |
|
292 fileContent += "FileVersion=1\n" |
|
293 fileContent += "FileRevision=1\n" |
|
294 fileContent += "EDSVersion=3.0\n" |
|
295 |
|
296 # Generate DeviceInfo section |
|
297 fileContent += "\n[DeviceInfo]\n" |
|
298 fileContent += "VendorName=CANFestival\n" |
|
299 # Use information typed by user in Identity entry |
|
300 fileContent += "VendorNumber=0x%8.8X\n"%Manager.GetCurrentEntry(0x1018, 1) |
|
301 fileContent += "ProductName=%s\n"%nodename |
|
302 fileContent += "ProductNumber=0x%8.8X\n"%Manager.GetCurrentEntry(0x1018, 2) |
|
303 fileContent += "RevisionNumber=0x%8.8X\n"%Manager.GetCurrentEntry(0x1018, 3) |
|
304 # CANFestival support all baudrates as soon as driver choosen support them |
|
305 fileContent += "BaudRate_10=1\n" |
|
306 fileContent += "BaudRate_20=1\n" |
|
307 fileContent += "BaudRate_50=1\n" |
|
308 fileContent += "BaudRate_125=1\n" |
|
309 fileContent += "BaudRate_250=1\n" |
|
310 fileContent += "BaudRate_500=1\n" |
|
311 fileContent += "BaudRate_800=1\n" |
|
312 fileContent += "BaudRate_1000=1\n" |
|
313 # Select BootUp type from the informations given by user |
|
314 fileContent += "SimpleBootUpMaster=%s\n"%BOOL_TRANSLATE[nodetype == "master"] |
|
315 fileContent += "SimpleBootUpSlave=%s\n"%BOOL_TRANSLATE[nodetype == "slave"] |
|
316 # CANFestival characteristics |
|
317 fileContent += "Granularity=8\n" |
|
318 fileContent += "DynamicChannelsSupported=0\n" |
|
319 fileContent += "CompactPDO=0\n" |
|
320 fileContent += "GroupMessaging=0\n" |
|
321 # Calculate receive and tranmit PDO numbers with the entry available |
|
322 fileContent += "NrOfRXPDO=%d\n"%len([idx for idx in entries if 0x1400 <= idx <= 0x15FF]) |
|
323 fileContent += "NrOfTXPDO=%d\n"%len([idx for idx in entries if 0x1400 <= idx <= 0x15FF]) |
|
324 # LSS not supported as soon as DS-302 was not fully implemented |
|
325 fileContent += "LSS_Supported=0\n" |
|
326 |
|
327 # Generate Dummy Usage section |
|
328 fileContent += "\n[DummyUsage]\n" |
|
329 fileContent += "Dummy0001=0\n" |
|
330 fileContent += "Dummy0002=1\n" |
|
331 fileContent += "Dummy0003=1\n" |
|
332 fileContent += "Dummy0004=1\n" |
|
333 fileContent += "Dummy0005=1\n" |
|
334 fileContent += "Dummy0006=1\n" |
|
335 fileContent += "Dummy0007=1\n" |
|
336 |
|
337 # Generate Comments section |
|
338 fileContent += "\n[Comments]\n" |
|
339 fileContent += "Lines=0\n" |
|
340 |
|
341 # List of entry by type (Mandatory, Optional or Manufacturer |
|
342 mandatories = [] |
|
343 optionals = [] |
|
344 manufacturers = [] |
|
345 |
|
346 # For each entry, we generate the entry section or sections if there is subindexes |
|
347 for entry in entries: |
|
348 # Extract infos and values for the entry |
|
349 entry_infos = Manager.GetEntryInfos(entry) |
|
350 values = Manager.GetCurrentEntry(entry) |
|
351 # Define section name |
|
352 text = "\n[%X]\n"%entry |
|
353 # If there is only one value, it's a VAR entry |
|
354 if type(values) != ListType: |
|
355 # Extract the informations of the first subindex |
|
356 subentry_infos = Manager.GetSubentryInfos(entry, 0) |
|
357 # Generate EDS informations for the entry |
|
358 text += "ParameterName=%s\n"%subentry_infos["name"] |
|
359 text += "ObjectType=0x7\n" |
|
360 text += "DataType=0x%4.4X\n"%subentry_infos["type"] |
|
361 text += "AccessType=%s\n"%subentry_infos["access"] |
|
362 text += "DefaultValue=%s\n"%values |
|
363 text += "PDOMapping=%s\n"%BOOL_TRANSLATE[subentry_infos["pdo"]] |
|
364 else: |
|
365 # Generate EDS informations for the entry |
|
366 text += "ParameterName=%s\n"%entry_infos["name"] |
|
367 if entry_infos["struct"] & node.OD_IdenticalSubindexes: |
|
368 text += "ObjectType=0x9\n" |
|
369 else: |
|
370 text += "ObjectType=0x8\n" |
|
371 |
|
372 # Generate EDS informations for subindexes of the entry in a separate text |
|
373 subtext = "" |
|
374 # Reset number of subindex defined |
|
375 nb_subentry = 0 |
|
376 for subentry, value in enumerate(values): |
|
377 # Extract the informations of each subindex |
|
378 subentry_infos = Manager.GetSubentryInfos(entry, subentry) |
|
379 # If entry is not for the compatibility, generate informations for subindex |
|
380 if subentry_infos["name"] != "Compatibility Entry": |
|
381 subtext += "\n[%Xsub%X]\n"%(entry, subentry) |
|
382 subtext += "ParameterName=%s\n"%subentry_infos["name"] |
|
383 subtext += "ObjectType=0x7\n" |
|
384 subtext += "DataType=0x%4.4X\n"%subentry_infos["type"] |
|
385 subtext += "AccessType=%s\n"%subentry_infos["access"] |
|
386 subtext += "DefaultValue=%s\n"%value |
|
387 subtext += "PDOMapping=%s\n"%BOOL_TRANSLATE[subentry_infos["pdo"]] |
|
388 # Increment number of subindex defined |
|
389 nb_subentry += 1 |
|
390 # Write number of subindex defined for the entry |
|
391 text += "SubNumber=%d\n"%nb_subentry |
|
392 # Write subindex definitions |
|
393 text += subtext |
|
394 |
|
395 # Then we add the entry in the right list |
|
396 |
|
397 # First case, entry is between 0x2000 and 0x5FFF, then it's a manufacturer entry |
|
398 if 0x2000 <= entry <= 0x5FFF: |
|
399 manufacturers.append(entry) |
|
400 # Second case, entry is required, then it's a mandatory entry |
|
401 elif entry_infos["need"]: |
|
402 mandatories.append(entry) |
|
403 # In any other case, it's an optional entry |
|
404 else: |
|
405 optionals.append(entry) |
|
406 # Save text of the entry in the dictiionary of contents |
|
407 indexContents[entry] = text |
|
408 |
|
409 # Before generate File Content we sort the entry list |
|
410 manufacturers.sort() |
|
411 mandatories.sort() |
|
412 optionals.sort() |
|
413 |
|
414 # Generate Definition of mandatory objects |
|
415 fileContent += "\n[MandatoryObjects]\n" |
|
416 fileContent += "SupportedObjects=%d\n"%len(mandatories) |
|
417 for idx, entry in enumerate(mandatories): |
|
418 fileContent += "%d=0x%4.4X\n"%(idx, entry) |
|
419 # Write mandatory entries |
|
420 for entry in mandatories: |
|
421 fileContent += indexContents[entry] |
|
422 |
|
423 # Generate Definition of optional objects |
|
424 fileContent += "\n[OptionalObjects]\n" |
|
425 fileContent += "SupportedObjects=%d\n"%len(optionals) |
|
426 for idx, entry in enumerate(optionals): |
|
427 fileContent += "%d=0x%4.4X\n"%(idx, entry) |
|
428 # Write optional entries |
|
429 for entry in optionals: |
|
430 fileContent += indexContents[entry] |
|
431 |
|
432 # Generate Definition of manufacturer objects |
|
433 fileContent += "\n[ManufacturerObjects]\n" |
|
434 fileContent += "SupportedObjects=%d\n"%len(manufacturers) |
|
435 for idx, entry in enumerate(manufacturers): |
|
436 fileContent += "%d=0x%4.4X\n"%(idx, entry) |
|
437 # Write manufacturer entries |
|
438 for entry in manufacturers: |
|
439 fileContent += indexContents[entry] |
|
440 |
|
441 # Return File Content |
|
442 return fileContent |
|
443 |
|
444 |
|
445 # Function that generates EDS file from current node edited |
|
446 def GenerateEDSFile(filepath, manager): |
|
447 global Manager |
|
448 Manager = manager |
|
449 try: |
|
450 # Generate file content |
|
451 content = GenerateFileContent(filepath) |
|
452 # Write file |
|
453 WriteFile(filepath, content) |
|
454 return None |
|
455 except ValueError, message: |
|
456 return "Unable to generate EDS file\n%s"%message |
|
457 |
|
458 |
|
459 # Function that generates Node from an EDS file |
|
460 def GenerateNode(filepath, manager, cwd): |
|
461 global Node |
|
462 global Manager |
|
463 Manager = manager |
|
464 # Create a new node |
|
465 Node = node.Node() |
|
466 try: |
|
467 # Parse file and extract dictionary of EDS entry |
|
468 eds_dict = ParseFile(filepath) |
|
469 # Extract Profile Number from Device Type entry |
|
470 ProfileNb = eds_dict[0x1000]["DEFAULTVALUE"] & 0x0000ffff |
|
471 # If profile is not DS-301 or DS-302 |
|
472 if ProfileNb not in [301, 302]: |
|
473 # Compile Profile name and path to .prf file |
|
474 ProfileName = "DS-%d"%ProfileNb |
|
475 ProfilePath = os.path.join(cwd, "config/%s.prf"%ProfileName) |
|
476 # Verify that profile is available |
|
477 if os.path.isfile(ProfilePath): |
|
478 try: |
|
479 # Load Profile |
|
480 execfile(ProfilePath) |
|
481 Node.SetProfileName(ProfileName) |
|
482 Node.SetProfile(Mapping) |
|
483 Node.SetSpecificMenu(AddMenuEntries) |
|
484 except: |
|
485 pass |
|
486 # Read all entries in the EDS dictionary |
|
487 for entry, values in eds_dict.items(): |
|
488 # All sections with a name in keynames are escaped |
|
489 if entry in SECTION_KEYNAMES: |
|
490 pass |
|
491 else: |
|
492 # Extract informations for the entry |
|
493 entry_infos = Manager.GetEntryInfos(entry, Node) |
|
494 |
|
495 # If no informations are available, then we write them |
|
496 if not entry_infos: |
|
497 # First case, entry is a VAR |
|
498 if values["OBJECTTYPE"] == 7: |
|
499 # Add mapping for entry |
|
500 Node.AddMappingEntry(entry, name = values["PARAMETERNAME"], struct = 1) |
|
501 # Add mapping for first subindex |
|
502 Node.AddMappingEntry(entry, 0, values = {"name" : values["PARAMETERNAME"], |
|
503 "type" : values["DATATYPE"], |
|
504 "access" : values["ACCESSTYPE"], |
|
505 "pdo" : values["PDOMAPPING"] == 1}) |
|
506 # Second case, entry is an ARRAY |
|
507 elif values["OBJECTTYPE"] == 8: |
|
508 # Extract maximum subindex number defined |
|
509 try: |
|
510 max_subindex = values["subindexes"][0]["DEFAULTVALUE"] |
|
511 except: |
|
512 raise SyntaxError, "Error on entry 0x%4.4X:\nSubindex 0 must be defined for an ARRAY entry"%entry |
|
513 # Add mapping for entry |
|
514 Node.AddMappingEntry(entry, name = values["PARAMETERNAME"], struct = 3) |
|
515 # Add mapping for first subindex |
|
516 Node.AddMappingEntry(entry, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False}) |
|
517 # Add mapping for other subindexes |
|
518 for subindex in xrange(1, int(max_subindex) + 1): |
|
519 # if subindex is defined |
|
520 if subindex in values["subindexes"]: |
|
521 Node.AddMappingEntry(entry, subindex, values = {"name" : values["subindexes"][subindex]["PARAMETERNAME"], |
|
522 "type" : values["subindexes"][subindex]["DATATYPE"], |
|
523 "access" : values["subindexes"][subindex]["ACCESSTYPE"], |
|
524 "pdo" : values["subindexes"][subindex]["PDOMAPPING"] == 1}) |
|
525 # if not, we add a mapping for compatibility |
|
526 else: |
|
527 Node.AddMappingEntry(entry, subindex, values = {"name" : "Compatibility Entry", "type" : 0x05, "access" : "rw", "pdo" : False}) |
|
528 # Third case, entry is an RECORD |
|
529 elif values["OBJECTTYPE"] == 9: |
|
530 # Verify that the first subindex is defined |
|
531 if 0 not in values["subindexes"]: |
|
532 raise SyntaxError, "Error on entry 0x%4.4X:\nSubindex 0 must be defined for a RECORD entry"%entry |
|
533 # Add mapping for entry |
|
534 Node.AddMappingEntry(entry, name = values["PARAMETERNAME"], struct = 7) |
|
535 # Add mapping for first subindex |
|
536 Node.AddMappingEntry(entry, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False}) |
|
537 # Verify that second subindex is defined |
|
538 if 1 in values: |
|
539 Node.AddMappingEntry(entry, 1, values = {"name" : values["PARAMETERNAME"] + " %d[(sub)]", |
|
540 "type" : values["subindexes"][1]["DATATYPE"], |
|
541 "access" : values["subindexes"][1]["ACCESSTYPE"], |
|
542 "pdo" : values["subindexes"][1]["PDOMAPPING"] == 1}) |
|
543 else: |
|
544 raise SyntaxError, "Error on entry 0x%4.4X:\nA RECORD entry must have at least 2 subindexes"%entry |
|
545 |
|
546 # Define entry for the new node |
|
547 |
|
548 # First case, entry is a VAR |
|
549 if values["OBJECTTYPE"] == 7: |
|
550 # Take default value if it is defined |
|
551 if "DEFAULTVALUE" in values: |
|
552 value = values["DEFAULTVALUE"] |
|
553 # Find default value for value type of the entry |
|
554 else: |
|
555 value = GetDefaultValue(entry) |
|
556 Node.AddEntry(entry, 0, value) |
|
557 # Second case, entry is an ARRAY or a RECORD |
|
558 elif values["OBJECTTYPE"] in (8, 9): |
|
559 # Verify that "Subnumber" attribute is defined and has a valid value |
|
560 if "SUBNUMBER" in values and values["SUBNUMBER"] > 0: |
|
561 # Extract maximum subindex number defined |
|
562 try: |
|
563 max_subindex = values["subindexes"][0]["DEFAULTVALUE"] |
|
564 except: |
|
565 raise SyntaxError, "Error on entry 0x%4.4X:\nSubindex 0 must be defined for an ARRAY or a RECORD entry"%entry |
|
566 # Define value for all subindexes except the first |
|
567 for subindex in xrange(1, int(max_subindex) + 1): |
|
568 # Take default value if it is defined and entry is defined |
|
569 if subindex in values["subindexes"] and "DEFAULTVALUE" in values["subindexes"][subindex]: |
|
570 value = values["subindexes"][subindex]["DEFAULTVALUE"] |
|
571 # Find default value for value type of the subindex |
|
572 else: |
|
573 value = GetDefaultValue(entry, subindex) |
|
574 Node.AddEntry(entry, subindex, value) |
|
575 else: |
|
576 raise SyntaxError, "Array or Record entry 0x%4.4X must have a \"SubNumber\" attribute"%entry |
|
577 return Node |
|
578 except SyntaxError, message: |
|
579 return "Unable to import EDS File\n%s"%message |
|
580 |
|
581 #------------------------------------------------------------------------------- |
|
582 # Main Function |
|
583 #------------------------------------------------------------------------------- |
|
584 |
|
585 if __name__ == '__main__': |
|
586 print ParseFile("examples/PEAK MicroMod.eds") |
|
587 |