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 from xml.parsers import expat |
|
25 |
|
26 import node |
|
27 from node import * |
|
28 |
|
29 maxObjects = 8 |
|
30 |
|
31 currentPDOIndex = 0 |
|
32 currentBitsMapped = 0 |
|
33 currentMaxObjects = 0 |
|
34 currentNbMappedObjects = 0 |
|
35 |
|
36 nextPdoIndex = {"rx":0x1400,"tx":0x1800} |
|
37 |
|
38 valid_elements = ["node","heartbeat_consumers","sdo_clients","pdo","mapped_object", |
|
39 "pdo_param","pdo_receive","pdo_transmit","mapped_variable","mapped_table", |
|
40 "mapped_string_variable","mapped_string_table"] |
|
41 |
|
42 #------------------------------------------------------------------------------- |
|
43 # Callback method of parse |
|
44 #------------------------------------------------------------------------------- |
|
45 |
|
46 def StartElement(name, attrs): |
|
47 if name in valid_elements: |
|
48 if name == "node": |
|
49 startNode(attrs) |
|
50 elif name == "heartbeat_consumers": |
|
51 startHeartBeatConsumers(attrs) |
|
52 elif name == "sdo_clients": |
|
53 startSdoClients(attrs) |
|
54 elif name in ["pdo_param","pdo_receive","pdo_transmit"]: |
|
55 raise ValueError, """!!! The XML grammar has changed. |
|
56 Please, open your xml file, delete the tags pdo_param, pdo_receive and pdo_transmit. |
|
57 Use instead the tag pdo for each pdo to create, and (optional) use the tag mapped_object (menu pdo/map and object ...).""" |
|
58 elif name == "pdo": |
|
59 startPdo(attrs) |
|
60 elif name == "mapped_object": |
|
61 startMappedObject(attrs) |
|
62 elif name == "mapped_variable": |
|
63 startMappedVariable(attrs) |
|
64 elif name == "mapped_table": |
|
65 startMappedTable(attrs) |
|
66 elif name == "mapped_string_variable": |
|
67 startMappedVariable(attrs) |
|
68 elif name == "mapped_string_table": |
|
69 startMappedTable(attrs) |
|
70 |
|
71 def EndElement(name): |
|
72 if name in valid_elements: |
|
73 if name == "node": |
|
74 stopNode() |
|
75 |
|
76 def CharacterData(data): |
|
77 pass |
|
78 |
|
79 #------------------------------------------------------------------------------- |
|
80 # Creation of Node |
|
81 #------------------------------------------------------------------------------- |
|
82 |
|
83 def startNode(attrs): |
|
84 name = attrs["name"] |
|
85 Node.SetNodeName(name) |
|
86 |
|
87 if "node_id" in attrs and len(attrs["node_id"]) > 0: |
|
88 node_id = eval(attrs["node_id"]) |
|
89 else: |
|
90 node_id = 0x01 # We define here a default node_id. |
|
91 Node.SetNodeID(node_id) |
|
92 |
|
93 typeNode = attrs["type_node"] |
|
94 Node.SetNodeType(typeNode) |
|
95 |
|
96 if "device_type_1000" in attrs: |
|
97 device_type = eval(attrs["device_type_1000"]) |
|
98 else: |
|
99 device_type = 0 |
|
100 Node.AddEntry(0x1000, 0, device_type) |
|
101 Node.AddEntry(0x1001, 0, 0) |
|
102 Node.AddEntry(0x1005, 0, 0x00000080) |
|
103 Node.AddEntry(0x1006, 0, 0) |
|
104 Node.AddEntry(0x1007, 0, 0) |
|
105 |
|
106 if "manufacturer_device_name_1008" in attrs: |
|
107 manufacturer_device_name = attrs["manufacturer_device_name_1008"] |
|
108 else: |
|
109 manufacturer_device_name = "" |
|
110 Node.AddEntry(0x1008, 0, manufacturer_device_name) |
|
111 |
|
112 if "manufacturer_hardware_version_1009" in attrs: |
|
113 manufacturer_hardware_version = attrs["manufacturer_hardware_version_1009"] |
|
114 else: |
|
115 manufacturer_hardware_version = "__DATE__" |
|
116 Node.AddEntry(0x1009, 0, manufacturer_hardware_version) |
|
117 |
|
118 if "manufacturer_software_version_100A" in attrs: |
|
119 manufacturer_software_version = attrs["manufacturer_software_version_100A"] |
|
120 else: |
|
121 manufacturer_software_version = 0 |
|
122 Node.AddEntry(0x100A, 0, manufacturer_software_version) |
|
123 |
|
124 if "vendor_id_1018" in attrs: |
|
125 vendor_id = eval(attrs["vendor_id_1018"]) |
|
126 else: |
|
127 vendor_id = 0 |
|
128 if "product_code_1018" in attrs: |
|
129 product_code = eval(attrs["product_code_1018"]) |
|
130 else: |
|
131 product_code = 0 |
|
132 if "revision_number_1018" in attrs: |
|
133 revision_number = eval(attrs["revision_number_1018"]) |
|
134 else: |
|
135 revision_number = 0 |
|
136 if "serial_number_1018" in attrs: |
|
137 serial_number = eval(attrs["serial_number_1018"]) |
|
138 else: |
|
139 serial_number = 0 |
|
140 Node.AddEntry(0x1018, 1, vendor_id) |
|
141 Node.AddEntry(0x1018, 2, product_code) |
|
142 Node.AddEntry(0x1018, 3, revision_number) |
|
143 Node.AddEntry(0x1018, 4, serial_number) |
|
144 |
|
145 def stopNode(): |
|
146 heartBeatProducer() |
|
147 sdoServer() |
|
148 |
|
149 #------------------------------------------------------------------------------- |
|
150 # Creation of PDO in Object Dictionary |
|
151 #------------------------------------------------------------------------------- |
|
152 |
|
153 def startPdo(attrs): |
|
154 global currentPdoIndex |
|
155 global currentMaxObjects |
|
156 global currentNbMappedObjects |
|
157 global currentBitsMapped |
|
158 global maxObjects |
|
159 |
|
160 cobId = 0 |
|
161 transmissionType = 253 # Default is on request. Why not ? |
|
162 |
|
163 # Find the type of the PDO and search the index of the last added |
|
164 type = attrs["type_rx_tx"] |
|
165 index = nextPdoIndex[type] |
|
166 |
|
167 # If the index of the PDO is define, verify that it has a good index |
|
168 if "index_communication_parameter" in attrs: |
|
169 index = eval(attrs["index_communication_parameter"]) |
|
170 if type == "rx" and not 0x1400 <= index <= 0x15FF: |
|
171 raise ValueError, """!!! Abort because Index PDO receive : 0x%04X not valid. |
|
172 Valid index is 0x1400 ... 0x15FF"""%index |
|
173 if type == "tx" and not 0x1800 <= index <= 0x19FF: |
|
174 raise ValueError, """!!! Abort because Index PDO transmit : 0x%04X not valid. |
|
175 Valid index is 0x1800 ... 0x19FF"""%index |
|
176 |
|
177 # Extract the PDO communication parameters |
|
178 if "cob_id" == attrs: |
|
179 cobId = eval(attrs["cob_id"]) |
|
180 if "max_objects_in_pdo" == attrs: |
|
181 maxObjects = eval(attrs["max_objects_in_pdo"]) |
|
182 if "transmission_type" in attrs: |
|
183 transmissionType = eval(attrs["transmission_type"]) |
|
184 |
|
185 if Node.IsEntry(index): |
|
186 raise ValueError, """!!! Abort because the PDO at index : 0x%04X have been already defined."""%index |
|
187 |
|
188 # Communication parameters |
|
189 Node.AddEntry(index, 1, cobId) |
|
190 Node.AddEntry(index, 2, transmissionType) |
|
191 |
|
192 # Mapping parameters |
|
193 mapping_index = index + 0x200 |
|
194 for i in xrange(1, maxObjects + 1): |
|
195 Node.AddEntry(mapping_index, i, 0x0) |
|
196 |
|
197 currentPdoIndex = index |
|
198 currentMaxObjects = maxObjects |
|
199 currentBitsMapped = 0 |
|
200 currentNbMappedObjects = 0 |
|
201 |
|
202 nextPdoIndex[type] = index + 1 |
|
203 |
|
204 def startMappedObject(attrs): |
|
205 global currentPdoIndex |
|
206 global currentMaxObjects |
|
207 global currentNbMappedObjects |
|
208 global currentBitsMapped |
|
209 |
|
210 index = currentPdoIndex |
|
211 mapping_index = index + 0x200 |
|
212 |
|
213 indexObject = eval(attrs["index"]) |
|
214 subIndexObject = eval(attrs["sub_index"]) |
|
215 sizeInBitsObject = eval(attrs["size_in_bits"]) |
|
216 |
|
217 if currentMaxObjects == 0: |
|
218 raise ValueError, """!!! Abort because of a bogue for mapped object (defined at index 0x%04X, subIndex 0x%025X) |
|
219 in PDO. index : 0x%04X is undefined."""%(indexObject,subindexObject,mapping_index) |
|
220 if currentNbMappedObjects >= currentMaxObjects: |
|
221 raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X) |
|
222 in PDO index 0x%04X. max objects (%d) reached."""%(IndexObject,subIndexObject,mapping_index,pdo[mapping_index]["maxObjects"]) |
|
223 if currentBitsMapped + sizeInBitsObject > 64: |
|
224 raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X) |
|
225 in PDO index 0x%04X. No room to put %d bits in the PDO."""%(IndexObject,subIndexObject,mapping_index,sizeInBitsObject) |
|
226 |
|
227 value = eval("0x%04X%02X%02X"%(indexObject,subIndexObject,sizeInBitsObject)) |
|
228 Node.SetEntry(mapping_index, currentNbMappedObjects + 1, value) |
|
229 |
|
230 currentNbMappedObjects += 1 |
|
231 currentBitsMapped += sizeInBitsObject |
|
232 |
|
233 #------------------------------------------------------------------------------- |
|
234 # Creation of mapped variable and table |
|
235 #------------------------------------------------------------------------------- |
|
236 |
|
237 def startMappedVariable(attrs): |
|
238 name = attrs["name"] |
|
239 index = eval(attrs["index"]) |
|
240 subIndex = eval(attrs["sub_index"]) |
|
241 |
|
242 if "size_in_bits" in attrs: |
|
243 size = eval(attrs["size_in_bits"]) # Numeric variable |
|
244 if "type" in attrs: |
|
245 type = attrs["type"] |
|
246 if (type == "UNS"): |
|
247 type = "UNSIGNED" |
|
248 else: # Default type |
|
249 type = "UNSIGNED" |
|
250 typename = "%s%d"%(type,size) |
|
251 |
|
252 type_index = Manager.GetTypeIndex(typename, False) |
|
253 if type_index == None: |
|
254 raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unrecognized type : %s"""%(name,index,subIndex,typename) |
|
255 |
|
256 # Begin ValueRange support |
|
257 if "min_value" in attrs or "max_value" in attrs: |
|
258 if "min_value" in attrs and "max_value" in attrs: |
|
259 minValue = eval(attrs["min_value"]) |
|
260 maxValue = eval(attrs["max_value"]) |
|
261 if (minValue > maxValue): |
|
262 raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : error in value-range : min > max"""%(name,index,subIndex) |
|
263 else: |
|
264 raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : You have defined only a min or a max value. \nIf you define one, you must define both."""%(name,index,subIndex) |
|
265 |
|
266 type_index = findRangeType(type_index, minValue, maxValue) |
|
267 if type_index == None: |
|
268 raise ValueError, """!!! Sorry, too many different value range have been defined""" |
|
269 # End ValueRange support |
|
270 |
|
271 if "size_in_byte" in attrs: |
|
272 size = eval(attrs["size_in_byte"]) # String variable |
|
273 type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size) |
|
274 if type_index == None: |
|
275 raise ValueError, """!!! Sorry, too many different string length have been defined""" |
|
276 |
|
277 if "access" in attrs: |
|
278 access = attrs["access"].lower() |
|
279 else: |
|
280 access = "rw" # default value |
|
281 |
|
282 if index < 0x2000 or index > 0xBFFF: |
|
283 raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Variable can't be defined using this index-subindex."""%(name,index,subIndex) |
|
284 |
|
285 if subIndex == 0: |
|
286 Node.AddMappingEntry(index, name = name, struct = 1) |
|
287 elif subIndex == 1: |
|
288 Node.AddMappingEntry(index, struct = 3) |
|
289 Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) |
|
290 result = Node.AddMappingEntry(index, subIndex, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True}) |
|
291 |
|
292 if result: |
|
293 Node.AddEntry(index, subIndex, 0) |
|
294 else: |
|
295 raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unable to map"""%(name,index,subIndex) |
|
296 |
|
297 def startMappedTable(attrs): |
|
298 name = attrs["name"] |
|
299 number_elements = eval(attrs["number_elements"]) |
|
300 index = eval(attrs["index"]) |
|
301 |
|
302 if "size_in_bits" in attrs: |
|
303 size = eval(attrs["size_in_bits"]) # Numeric variable |
|
304 if "type" in attrs: |
|
305 type = attrs["type"] |
|
306 if (type == "UNS"): |
|
307 type = "UNSIGNED" |
|
308 else: # Default type |
|
309 type = "UNSIGNED" |
|
310 typename = "%s%d"%(type,size) |
|
311 |
|
312 type_index = Manager.GetTypeIndex(typename, False) |
|
313 if type_index == None: |
|
314 raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Unrecognized type : %s"""%(name,index,typename) |
|
315 |
|
316 # Begin ValueRange support |
|
317 if "min_value" in attrs or "max_value" in attrs: |
|
318 if "min_value" in attrs and "max_value" in attrs: |
|
319 minValue = eval(attrs["min_value"]) |
|
320 maxValue = eval(attrs["max_value"]) |
|
321 if (minValue > maxValue): |
|
322 raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : error in value-range : min > max"""%(name,index) |
|
323 else: |
|
324 raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : You have defined only a min or a max value. \nIf you define one, you must define both."""%(name,index) |
|
325 |
|
326 type_index = findRangeType(type_index, minValue, maxValue) |
|
327 if type_index == None: |
|
328 raise ValueError, """!!! Sorry, too many different value range have been defined""" |
|
329 # End ValueRange support |
|
330 |
|
331 if "size_in_byte" in attrs: |
|
332 size = eval(attrs["size_in_byte"]) # String variable |
|
333 type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size) |
|
334 if type_index == None: |
|
335 raise ValueError, """!!! Sorry, too many different string length have been defined""" |
|
336 |
|
337 if "access" in attrs: |
|
338 access = attrs["access"].lower() |
|
339 else: |
|
340 access = "rw" # default value |
|
341 |
|
342 if index < 0x2000 or index > 0xBFFF: |
|
343 raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Variable can't be defined using this index-subindex."""%(name,index) |
|
344 |
|
345 result = Node.AddMappingEntry(index, name = name, struct = 7) |
|
346 if not result: |
|
347 raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Unable to map because a variable or a table is using this index"""%(name,index) |
|
348 Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) |
|
349 Node.AddMappingEntry(index, 1, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True, "nbmax" : number_elements}) |
|
350 |
|
351 for subIndex in xrange(1,number_elements+1): |
|
352 Node.AddEntry(index, subIndex, 0) |
|
353 |
|
354 def findRangeType(type, minValue, maxValue): |
|
355 index = 0xA0 |
|
356 while index < 0x100 and Node.IsEntry(index): |
|
357 current_type = Node.GetEntry(index, 1) |
|
358 if current_type == type: |
|
359 current_minValue = Node.GetEntry(index, 2) |
|
360 current_maxValue = Node.GetEntry(index, 3) |
|
361 if current_minValue == minValue and current_maxValue == maxValue: |
|
362 return index |
|
363 index += 1 |
|
364 if index < 0x100: |
|
365 infos = Manager.GetEntryInfos(type, False) |
|
366 name = "%s[%d-%d]"%(infos["name"], minValue, maxValue) |
|
367 Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"]) |
|
368 Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) |
|
369 Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False}) |
|
370 Node.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False}) |
|
371 Node.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False}) |
|
372 Node.AddEntry(index, 1, type) |
|
373 Node.AddEntry(index, 2, minValue) |
|
374 Node.AddEntry(index, 3, maxValue) |
|
375 return index |
|
376 return None |
|
377 |
|
378 def findStringType(type, length): |
|
379 index = 0xA0 |
|
380 while index < 0x100 and Node.IsEntry(index): |
|
381 current_type = Node.GetEntry(index, 1) |
|
382 if current_type == type: |
|
383 current_length = Node.GetEntry(index, 2) |
|
384 if current_length == length: |
|
385 return index |
|
386 index += 1 |
|
387 if index < 0x100: |
|
388 infos = Manager.GetEntryInfos(type, False) |
|
389 name = "%s%d"%(Manager.GetTypeName(type), length) |
|
390 Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"]) |
|
391 Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) |
|
392 Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False}) |
|
393 Node.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False}) |
|
394 Node.AddEntry(index, 1, type) |
|
395 Node.AddEntry(index, 2, length) |
|
396 return index |
|
397 return None |
|
398 |
|
399 #------------------------------------------------------------------------------- |
|
400 # Creation HeartBeat Producer & Consumers |
|
401 #------------------------------------------------------------------------------- |
|
402 |
|
403 def heartBeatProducer(): |
|
404 Node.AddEntry(0x1017, 0, 0) |
|
405 |
|
406 def startHeartBeatConsumers(attrs): |
|
407 nombre = eval(attrs["nombre"]) |
|
408 for i in xrange(nombre): |
|
409 Node.AddEntry(0x1016, i + 1, 0) |
|
410 |
|
411 #------------------------------------------------------------------------------- |
|
412 # Creation of SDO Server & Clients |
|
413 #------------------------------------------------------------------------------- |
|
414 |
|
415 def sdoServer(): |
|
416 Node.AddEntry(0x1200, 1, 0x600 + Node.GetNodeID()) |
|
417 Node.AddEntry(0x1200, 2, 0x580 + Node.GetNodeID()) |
|
418 |
|
419 def startSdoClients(attrs): |
|
420 nombre = eval(attrs["nombre"]) |
|
421 for i in xrange(nombre): |
|
422 Node.AddEntry(0x1280 + i, 1, 0x600) |
|
423 Node.AddEntry(0x1280 + i, 2, 0x580) |
|
424 Node.AddEntry(0x1280 + i, 3, 0) |
|
425 |
|
426 #------------------------------------------------------------------------------- |
|
427 # Parse file with Saxe |
|
428 #------------------------------------------------------------------------------- |
|
429 |
|
430 def ParseFile(filepath): |
|
431 xmlfile = open(filepath,"r") |
|
432 Parser = expat.ParserCreate() |
|
433 Parser.StartElementHandler = StartElement |
|
434 Parser.EndElementHandler = EndElement |
|
435 Parser.CharacterDataHandler = CharacterData |
|
436 ParserStatus = Parser.ParseFile(xmlfile) |
|
437 xmlfile.close() |
|
438 |
|
439 def GenerateNode(filepath, manager): |
|
440 global Node |
|
441 global Manager |
|
442 Manager = manager |
|
443 Node = node.Node() |
|
444 ParseFile(filepath) |
|
445 return Node |
|
446 |
|
447 #------------------------------------------------------------------------------- |
|
448 # Main Function |
|
449 #------------------------------------------------------------------------------- |
|
450 |
|
451 if __name__ == '__main__': |
|
452 ParseFile("test.xml") |
|
453 |
|