]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/node.py
172236611b1e02ca317b3bc963b2621e7d6c46fd
[CanFestival-3.git] / objdictgen / node.py
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 import cPickle
25 from types import *
26 import re
27
28 """
29 Dictionary of translation between access symbol and their signification
30 """
31 AccessType = {"ro" : "Read Only", "wo" : "Write Only", "rw" : "Read/Write"}
32
33 BoolType = {True : "True", False : "False"} 
34 OptionType = {True : "Yes", False : "No"}
35
36 CustomisableTypes = [(0x02, 0), (0x03, 0), (0x04, 0), (0x05, 0), (0x06, 0), (0x07, 0),
37     (0x08, 0), (0x09, 1), (0x0A, 1), (0x0B, 1), (0x10, 0), (0x11, 0), (0x12, 0),
38     (0x13, 0), (0x14, 0), (0x15, 0), (0x16, 0), (0x18, 0), (0x19, 0), (0x1A, 0),
39     (0x1B, 0)]
40
41 DefaultParams = {"comment" : "", "save" : False}
42
43 #-------------------------------------------------------------------------------
44 #                      Dictionary Mapping and Organisation
45 #-------------------------------------------------------------------------------
46
47 """
48 Properties of entry structure in the Object Dictionary
49 """
50 OD_Subindex = 1             # Entry has at least one subindex
51 OD_MultipleSubindexes = 2   # Entry has more than one subindex
52 OD_IdenticalSubindexes = 4  # Subindexes of entry have the same description
53 OD_IdenticalIndexes = 8     # Entry has the same description on multiple indexes
54
55 """
56 Structures of entry in the Object Dictionary, sum of the properties described above
57 for all sorts of entries use in CAN Open specification
58 """
59 nosub = 0 # Entry without subindex (only for type declaration)
60 var = 1
61 array = 3
62 rec = 7
63 # Entries identical on multiple indexes
64 plurivar = 9
65 pluriarray = 11 # Example : PDO Parameters
66 plurirec = 15   # Example : PDO Mapping
67
68 """
69 MappingDictionary is the structure used for writing a good organised Object
70 Dictionary. It follows the specifications of the CANOpen standard.
71 Change the informations within it if there is a mistake. But don't modify the
72 organisation of this object, it will involve in a malfunction of the application.
73 """
74
75 MappingDictionary = {
76     0x0001 : {"name" : "BOOLEAN", "struct" : nosub, "size" : 1, "default" : False, "values" : []},
77     0x0002 : {"name" : "INTEGER8", "struct" : nosub, "size" : 8, "default" : 0, "values" : []},
78     0x0003 : {"name" : "INTEGER16", "struct" : nosub, "size" : 16, "default" : 0, "values" : []},
79     0x0004 : {"name" : "INTEGER32", "struct" : nosub, "size" : 32, "default" : 0, "values" : []},
80     0x0005 : {"name" : "UNSIGNED8", "struct" : nosub, "size" : 8, "default" : 0, "values" : []},
81     0x0006 : {"name" : "UNSIGNED16", "struct" : nosub, "size" : 16, "default" : 0, "values" : []},
82     0x0007 : {"name" : "UNSIGNED32", "struct" : nosub, "size" : 32, "default" : 0, "values" : []},
83     0x0008 : {"name" : "REAL32", "struct" : nosub, "size" : 32, "default" : 0.0, "values" : []},
84     0x0009 : {"name" : "VISIBLE_STRING", "struct" : nosub, "size" : 8, "default" : "", "values" : []},
85     0x000A : {"name" : "OCTET_STRING", "struct" : nosub, "size" : 8, "default" : "", "values" : []},
86     0x000B : {"name" : "UNICODE_STRING", "struct" : nosub, "size" : 16, "default" : "", "values" : []},
87 #    0x000C : {"name" : "TIME_OF_DAY", "struct" : nosub, "size" : 48, "default" : 0, "values" : []},
88 #    0x000D : {"name" : "TIME_DIFFERENCE", "struct" : nosub, "size" : 48, "default" : 0, "values" : []},
89     0x000F : {"name" : "DOMAIN", "struct" : nosub, "size" : 0, "default" : "", "values" : []},
90     0x0010 : {"name" : "INTEGER24", "struct" : nosub, "size" : 24, "default" : 0, "values" : []},
91     0x0011 : {"name" : "REAL64", "struct" : nosub, "size" : 64, "default" : 0.0, "values" : []},
92     0x0012 : {"name" : "INTEGER40", "struct" : nosub, "size" : 40, "default" : 0, "values" : []},
93     0x0013 : {"name" : "INTEGER48", "struct" : nosub, "size" : 48, "default" : 0, "values" : []},
94     0x0014 : {"name" : "INTEGER56", "struct" : nosub, "size" : 56, "default" : 0, "values" : []},
95     0x0015 : {"name" : "INTEGER64", "struct" : nosub, "size" : 64, "default" : 0, "values" : []},
96     0x0016 : {"name" : "UNSIGNED24", "struct" : nosub, "size" : 24, "default" : 0, "values" : []},
97     0x0018 : {"name" : "UNSIGNED40", "struct" : nosub, "size" : 40, "default" : 0, "values" : []},
98     0x0019 : {"name" : "UNSIGNED48", "struct" : nosub, "size" : 48, "default" : 0, "values" : []},
99     0x001A : {"name" : "UNSIGNED56", "struct" : nosub, "size" : 56, "default" : 0, "values" : []},
100     0x001B : {"name" : "UNSIGNED64", "struct" : nosub, "size" : 64, "default" : 0, "values" : []},
101     0x1000 : {"name" : "Device Type", "struct" : var, "need" : True, "values" : 
102                 [{"name" : "Device Type", "type" : 0x07, "access" : 'ro', "pdo" : False}]},
103     0x1001 : {"name" : "Error Register", "struct" : var,  "need" : True, "values" : 
104                 [{"name" : "Error Register", "type" : 0x05, "access": 'ro', "pdo" : True}]},
105     0x1002 : {"name" : "Manufacturer Status Register", "struct" : var, "need" : False,  "values" :
106                 [{"name" : "Manufacturer Status Register", "type" : 0x07, "access" : 'ro', "pdo" : True}]},
107     0x1003 : {"name" : "Pre-defined Error Field", "struct" : rec, "need" : False,  "values" :
108                 [{"name" : "Number of Errors", "type" : 0x05, "access" : 'rw', "pdo" : False},
109                  {"name" : "Standard Error Field", "type" : 0x07, "access" : 'ro', "pdo" : False, "nbmax" : 0xFE}]},
110     0x1005 : {"name" : "SYNC COB ID", "struct" : var, "need" : True, "callback" : True, "values" :
111                 [{"name" : "SYNC COB ID", "type" : 0x07, "access" : 'rw', "pdo" : False}]},
112     0x1006 : {"name" : "Communication / Cycle Period", "struct" : var, "need" : False, "callback" : True, "values" :
113                 [{"name" : "Communication Cycle Period", "type" : 0x07, "access" : 'rw', "pdo" : False}]},
114     0x1007 : {"name" : "Synchronous Window Length", "struct" : var, "need" : False, "values" :
115                 [{"name" : "Synchronous Window Length", "type" : 0x07, "access" : 'rw', "pdo" : False}]},
116     0x1008 : {"name" : "Manufacturer Device Name", "struct" : var, "need" : False, "values" :
117                 [{"name" : "Manufacturer Device Name", "type" : 0x09, "access" : 'ro', "pdo" : False}]},
118     0x1009 : {"name" : "Manufacturer Hardware Version", "struct" : var, "need" : False, "values" :
119                 [{"name" : "Manufacturer Hardware Version", "type" : 0x09, "access" : 'ro', "pdo" : False}]},
120     0x100A : {"name" : "Manufacturer Software Version", "struct" : var, "need" : False, "values" :
121                 [{"name" : "Manufacturer Software Version", "type" : 0x09, "access" : 'ro', "pdo" : False}]},
122     0x100C : {"name" : "Guard Time", "struct" : var, "need" : False, "values" :
123                 [{"name" : "Guard Time", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
124     0x100D : {"name" : "Life Time Factor", "struct" : var, "need" : False, "values" :
125                 [{"name" : "Life Time Factor", "type" : 0x05, "access" : 'rw', "pdo" : False}]},
126     0x1010 : {"name" : "Store parameters", "struct" : array, "need" : False, "values" :
127                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
128                  {"name" : "Save All Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
129                  {"name" : "Save Communication Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
130                  {"name" : "Save Application Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
131                  {"name" : "Save Manufacturer Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7C}]},
132     0x1011 : {"name" : "Restore Default Parameters", "struct" : array, "need" : False, "values" :
133                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
134                  {"name" : "Restore All Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
135                  {"name" : "Restore Communication Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
136                  {"name" : "Restore Application Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
137                  {"name" : "Restore Manufacturer Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7C}]},
138     0x1012 : {"name" : "TIME COB ID", "struct" : var, "need" : False, "values" :
139                 [{"name" : "TIME COB ID", "type" : 0x07, "access" : 'rw', "pdo" : False}]},
140     0x1013 : {"name" : "High Resolution Timestamp", "struct" : var, "need" : False, "values" :
141                 [{"name" : "High Resolution Time Stamp", "type" : 0x07, "access" : 'rw', "pdo" : True}]},
142     0x1014 : {"name" : "Emergency COB ID", "struct" : var, "need" : False, "values" :
143                 [{"name" : "Emergency COB ID", "type" : 0x07, "access" : 'rw', "pdo" : False}]},
144     0x1015 : {"name" : "Inhibit Time Emergency", "struct" : var, "need" : False, "values" :
145                 [{"name" : "Inhibit Time Emergency", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
146     0x1016 : {"name" : "Consumer Heartbeat Time", "struct" : rec, "need" : False, "values" :
147                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
148                  {"name" : "Consumer Heartbeat Time", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7F}]},
149     0x1017 : {"name" : "Producer Heartbeat Time", "struct" : var, "need" : False, "callback" : True, "values" :
150                 [{"name" : "Producer Heartbeat Time", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
151     0x1018 : {"name" : "Identity", "struct" : array, "need" : True, "values" :
152                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
153                  {"name" : "Vendor ID", "type" : 0x07, "access" : 'ro', "pdo" : False},
154                  {"name" : "Product Code", "type" : 0x07, "access" : 'ro', "pdo" : False},
155                  {"name" : "Revision Number", "type" : 0x07, "access" : 'ro', "pdo" : False},
156                  {"name" : "Serial Number", "type" : 0x07, "access" : 'ro', "pdo" : False}]},
157     0x1020 : {"name" : "Verify Configuration", "struct" : array, "need" : False, "values" :
158                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
159                  {"name" : "Configuration Date", "type" : 0x07, "access" : 'ro', "pdo" : False},
160                  {"name" : "Configuration Time", "type" : 0x07, "access" : 'ro', "pdo" : False}]},
161 #    0x1021 : {"name" : "Store EDS", "struct" : var, "need" : False, "values" :
162 #                [{"name" : "Store EDS", "type" : 0x0F, "access" : 'rw', "pdo" : False}]},
163 #    0x1022 : {"name" : "Storage Format", "struct" : var, "need" : False, "values" :
164 #                [{"name" : "Storage Format", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
165     0x1023 : {"name" : "OS Command", "struct" : array, "need" : False, "values" :
166                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
167                  {"name" : "Command", "type" : 0x0A, "access" : 'rw', "pdo" : False},
168                  {"name" : "Status", "type" : 0x05, "access" : 'ro', "pdo" : False},
169                  {"name" : "Reply", "type" : 0x0A, "access" : 'ro', "pdo" : False}]},
170     0x1024 : {"name" : "OS Command Mode", "struct" : var, "need" : False, "values" :
171                 [{"name" : "OS Command Mode", "type" : 0x05, "access" : 'wo', "pdo" : False}]},
172     0x1025 : {"name" : "OS Debugger Interface", "struct" : array, "need" : False, "values" :
173                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
174                  {"name" : "Command", "type" : 0x0A, "access" : 'rw', "pdo" : False},
175                  {"name" : "Status", "type" : 0x07, "access" : 'ro', "pdo" : False},
176                  {"name" : "Reply", "type" : 0x0A, "access" : 'ro', "pdo" : False}]},
177     0x1026 : {"name" : "OS Prompt", "struct" : array, "need" : False, "values" :
178                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
179                  {"name" : "StdIn", "type" : 0x05, "access" : 'wo', "pdo" : True},
180                  {"name" : "StdOut", "type" : 0x05, "access" : 'ro', "pdo" : True},
181                  {"name" : "StdErr", "type" : 0x05, "access" : 'ro', "pdo" : True}]},
182     0x1027 : {"name" : "Module List", "struct" : rec, "need" : False, "values" :
183                 [{"name" : "Number of Connected Modules", "type" : 0x05, "access" : 'ro', "pdo" : False},
184                  {"name" : "Module %d[(sub)]", "type" : 0x06, "access" : 'ro', "pdo" : False, "nbmax" : 0xFE}]},
185     0x1028 : {"name" : "Emergency Consumer", "struct" : rec, "need" : False, "values" :
186                 [{"name" : "Number of Consumed Emergency Objects", "type" : 0x05, "access" : 'ro', "pdo" : False},
187                  {"name" : "Emergency Consumer", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7E}]},
188     0x1029 : {"name" : "Error Behavior", "struct" : array, "need" : False, "values" :
189                 [{"name" : "Number of Error Classes", "type" : 0x05, "access" : 'ro', "pdo" : False},
190                  {"name" : "Communication Error", "type" : 0x05, "access" : 'rw', "pdo" : False},
191                  {"name" : "Device Profile", "type" : 0x05, "access" : 'rw', "pdo" : False, "nbmax" : 0xFE}]},
192     0x1200 : {"name" : "Server SDO Parameter", "struct" : array, "need" : False, "values" :
193                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
194                  {"name" : "COB ID Client to Server (Receive SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False},
195                  {"name" : "COB ID Server to Client (Transmit SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False}]},
196     0x1201 : {"name" : "Additional Server SDO %d Parameter[(idx)]", "struct" : pluriarray, "incr" : 1, "nbmax" : 0x7F, "need" : False, "values" :
197                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
198                  {"name" : "COB ID Client to Server (Receive SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False},
199                  {"name" : "COB ID Server to Client (Transmit SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False},
200                  {"name" : "Node ID of the SDO Client", "type" : 0x05, "access" : 'ro', "pdo" : False}]},
201     0x1280 : {"name" : "Client SDO %d Parameter[(idx)]", "struct" : pluriarray, "incr" : 1, "nbmax" : 0x100, "need" : False, "values" :
202                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
203                  {"name" : "COB ID Client to Server (Transmit SDO)", "type" : 0x07, "access" : 'rw', "pdo" : False},
204                  {"name" : "COB ID Server to Client (Receive SDO)", "type" : 0x07, "access" : 'rw', "pdo" : False},
205                  {"name" : "Node ID of the SDO Server", "type" : 0x04, "access" : 'rw', "pdo" : False}]},
206     0x1400 : {"name" : "Receive PDO %d Parameter[(idx)]", "struct" : pluriarray, "incr" : 1, "nbmax" : 0x200, "need" : False, "values" :
207                 [{"name" : "Highest SubIndex Supported", "type" : 0x05, "access" : 'ro', "pdo" : False},
208                  {"name" : "COB ID used by PDO", "type" : 0x07, "access" : 'rw', "pdo" : False, "default" : "{True:self.ID+(base+2)*0x100,False:0}[base<4]"},
209                  {"name" : "Transmission Type", "type" : 0x05, "access" : 'rw', "pdo" : False},
210                  {"name" : "Inhibit Time", "type" : 0x06, "access" : 'rw', "pdo" : False},
211                  {"name" : "Compatibility Entry", "type" : 0x05, "access" : 'rw', "pdo" : False},
212                  {"name" : "Event Timer", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
213     0x1600 : {"name" : "Receive PDO %d Mapping[(idx)]", "struct" : plurirec, "incr" : 1, "nbmax" : 0x200, "need" : False, "values" :
214                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'rw', "pdo" : False},
215                  {"name" : "PDO %d Mapping for an application object %d[(idx,sub)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x40}]},
216     0x1800 : {"name" : "Transmit PDO %d Parameter[(idx)]", "struct" : pluriarray, "incr" : 1, "nbmax" : 0x200, "need" : False, "callback" : True, "values" :
217                 [{"name" : "Highest SubIndex Supported", "type" : 0x05, "access" : 'ro', "pdo" : False},
218                  {"name" : "COB ID used by PDO", "type" : 0x07, "access" : 'rw', "pdo" : False, "default" : "{True:self.ID+(base+1)*0x100+0x80,False:0}[base<4]"},
219                  {"name" : "Transmission Type", "type" : 0x05, "access" : 'rw', "pdo" : False},
220                  {"name" : "Inhibit Time", "type" : 0x06, "access" : 'rw', "pdo" : False},
221                  {"name" : "Compatibility Entry", "type" : 0x05, "access" : 'rw', "pdo" : False},
222                  {"name" : "Event Timer", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
223     0x1A00 : {"name" : "Transmit PDO %d Mapping[(idx)]", "struct" : plurirec, "incr" : 1, "nbmax" : 0x200, "need" : False, "values" :
224                 [{"name" : "Number of Entries", "type" : 0x05, "access" : 'rw', "pdo" : False},
225                  {"name" : "PDO %d Mapping for a process data variable %d[(idx,sub)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x40}]},
226 }
227
228 #-------------------------------------------------------------------------------
229 #                         Search in a Mapping Dictionary
230 #-------------------------------------------------------------------------------
231
232 """
233 Return the index of the typename given by searching in mappingdictionary 
234 """
235 def FindTypeIndex(typename, mappingdictionary):
236     testdic = {}
237     for index, values in mappingdictionary.iteritems():
238         if index < 0x1000:
239             testdic[values["name"]] = index
240     if typename in testdic:
241         return testdic[typename]
242     return None
243
244 """
245 Return the name of the type by searching in mappingdictionary 
246 """
247 def FindTypeName(typeindex, mappingdictionary):
248     if typeindex < 0x1000 and typeindex in mappingdictionary:
249         return mappingdictionary[typeindex]["name"]
250     return None
251
252 """
253 Return the default value of the type by searching in mappingdictionary 
254 """
255 def FindTypeDefaultValue(typeindex, mappingdictionary):
256     if typeindex < 0x1000 and typeindex in mappingdictionary:
257         return mappingdictionary[typeindex]["default"]
258     return None
259
260 """
261 Return the list of types defined in mappingdictionary 
262 """
263 def FindTypeList(mappingdictionary):
264     list = []
265     for index in mappingdictionary.keys():
266         if index < 0x1000:
267             list.append(mappingdictionary[index]["name"])
268     return list
269
270 """
271 Return the name of an entry by searching in mappingdictionary 
272 """
273 def FindEntryName(index, mappingdictionary):
274     base_index = FindIndex(index, mappingdictionary)
275     if base_index:
276         infos = mappingdictionary[base_index]
277         if infos["struct"] & OD_IdenticalIndexes:
278             return StringFormat(infos["name"], (index - base_index) / infos["incr"] + 1, 0)
279         else:
280             return infos["name"]
281     return None
282
283 """
284 Return the informations of one entry by searching in mappingdictionary 
285 """
286 def FindEntryInfos(index, mappingdictionary):
287     base_index = FindIndex(index, mappingdictionary)
288     if base_index:
289         copy = mappingdictionary[base_index].copy()
290         if copy["struct"] & OD_IdenticalIndexes:
291             copy["name"] = StringFormat(copy["name"], (index - base_index) / copy["incr"] + 1, 0)
292         copy.pop("values")
293         return copy
294     return None
295
296 """
297 Return the informations of one subentry of an entry by searching in mappingdictionary 
298 """
299 def FindSubentryInfos(index, subIndex, mappingdictionary):
300     base_index = FindIndex(index, mappingdictionary)
301     if base_index:
302         struct = mappingdictionary[base_index]["struct"]
303         if struct & OD_Subindex:
304             if struct & OD_IdenticalSubindexes:
305                 if struct & OD_IdenticalIndexes:
306                     incr = mappingdictionary[base_index]["incr"]
307                 else:
308                     incr = 1
309                 if subIndex == 0:
310                     return mappingdictionary[base_index]["values"][0].copy()
311                 elif 0 < subIndex <= mappingdictionary[base_index]["values"][1]["nbmax"]:
312                     copy = mappingdictionary[base_index]["values"][1].copy()
313                     copy["name"] = StringFormat(copy["name"], (index - base_index) / incr + 1, subIndex)
314                     return copy
315             elif struct & OD_MultipleSubindexes and 0 <= subIndex < len(mappingdictionary[base_index]["values"]):
316                 return mappingdictionary[base_index]["values"][subIndex].copy()
317             elif subIndex == 0:
318                 return mappingdictionary[base_index]["values"][0].copy()
319     return None
320
321 """
322 Return the list of variables that can be mapped defined in mappingdictionary 
323 """
324 def FindMapVariableList(mappingdictionary, Node):
325     list = []
326     for index in mappingdictionary.iterkeys():
327         if Node.IsEntry(index):
328             for subIndex, values in enumerate(mappingdictionary[index]["values"]):
329                 if mappingdictionary[index]["values"][subIndex]["pdo"]:
330                     infos = Node.GetEntryInfos(mappingdictionary[index]["values"][subIndex]["type"])
331                     if mappingdictionary[index]["struct"] & OD_IdenticalSubindexes:
332                         values = Node.GetEntry(index)
333                         for i in xrange(len(values) - 1):
334                             list.append((index, i + 1, infos["size"], StringFormat(mappingdictionary[index]["values"][subIndex]["name"],1,i+1)))
335                     else:
336                         list.append((index, subIndex, infos["size"], mappingdictionary[index]["values"][subIndex]["name"]))
337     return list
338
339 """
340 Return the list of mandatory indexes defined in mappingdictionary 
341 """
342 def FindMandatoryIndexes(mappingdictionary):
343     list = []
344     for index in mappingdictionary.iterkeys():
345         if index >= 0x1000 and mappingdictionary[index]["need"]:
346             list.append(index)
347     return list
348
349 """
350 Return the index of the informations in the Object Dictionary in case of identical
351 indexes
352 """
353 def FindIndex(index, mappingdictionary):
354     if index in mappingdictionary:
355         return index
356     else:
357         listpluri = [idx for idx in mappingdictionary.keys() if mappingdictionary[idx]["struct"] & OD_IdenticalIndexes]
358         listpluri.sort()
359         for idx in listpluri:
360             nb_max = mappingdictionary[idx]["nbmax"]
361             incr = mappingdictionary[idx]["incr"]
362             if idx < index < idx + incr * nb_max and (index - idx)%incr == 0:
363                 return idx
364     return None
365
366 #-------------------------------------------------------------------------------
367 #                           Formating Name of an Entry
368 #-------------------------------------------------------------------------------
369
370 name_model = re.compile('(.*)\[(.*)\]')
371
372 """
373 Format the text given with the index and subindex defined
374 """
375 def StringFormat(text, idx, sub):
376     result = name_model.match(text)
377     if result:
378         format = result.groups()
379         return format[0]%eval(format[1])
380     else:
381         return text
382
383 #-------------------------------------------------------------------------------
384 #                          Definition of Node Object
385 #-------------------------------------------------------------------------------
386
387 """
388 Class recording the Object Dictionary entries. It checks at each modification
389 that the structure of the Object Dictionary stay coherent
390 """
391
392 class Node:
393     
394     def __init__(self, name = "", type = "slave", id = 0, description = "", profilename = "DS-301", profile = {}, specificmenu = []):
395         self.Name = name
396         self.Type = type
397         self.ID = id
398         self.Description = description
399         self.ProfileName = profilename
400         self.Profile = profile
401         self.SpecificMenu = specificmenu
402         self.Dictionary = {}
403         self.ParamsDictionary = {}
404         self.DS302 = {}
405         self.UserMapping = {}
406     
407     """
408     Return the node name
409     """
410     def GetNodeName(self):
411         return self.Name
412     
413     """
414     Define the node name
415     """
416     def SetNodeName(self, name):
417         self.Name = name
418
419     """
420     Return the node type ("master" or "slave")
421     """
422     def GetNodeType(self):
423         return self.Type
424     
425     """
426     Define the node type ("master" or "slave")
427     """
428     def SetNodeType(self, type):
429         self.Type = type
430
431     """
432     Return the node ID
433     """
434     def GetNodeID(self):
435         return self.ID
436     
437     """
438     Define the node ID
439     """
440     def SetNodeID(self, id):
441         self.ID = id
442
443     """
444     Return the node description
445     """
446     def GetNodeDescription(self):
447         if getattr(self, "Description", False):
448             return self.Description
449         else:
450             return ""
451     
452     """
453     Define the node description
454     """
455     def SetNodeDescription(self, description):
456         self.Description = description
457
458     """
459     Return the Specific Profile Name
460     """
461     def GetProfileName(self):
462         return self.ProfileName
463     
464     """
465     Define the Specific Profile Name
466     """
467     def SetProfileName(self, profilename):
468         self.ProfileName = profilename
469
470     """
471     Return the Specific Profile
472     """
473     def GetProfile(self):
474         return self.Profile
475     
476     """
477     Define the Specific Profile
478     """
479     def SetProfile(self, profile):
480         self.Profile = profile
481     
482     """
483     Define the DS-302 Profile
484     """
485     def SetDS302Profile(self, profile):
486         self.DS302 = profile
487     
488     """
489     Define the DS-302 Profile
490     """
491     def GetDS302Profile(self):
492         return self.DS302
493     
494     """
495     Return the Specific Menu Entries
496     """
497     def GetSpecificMenu(self):
498         return self.SpecificMenu
499     
500     """
501     Define the Specific Menu Entries
502     """
503     def SetSpecificMenu(self, specificmenu):
504         self.SpecificMenu = specificmenu
505     
506     """
507     Extend the Specific Menu Entries
508     """
509     
510     def ExtendSpecificMenu(self, specificmenu):
511         self.SpecificMenu.extend(specificmenu)
512     
513     """
514     Function which return the different Mappings available for this node
515     """
516     def GetMappings(self, userdefinedtoo = True):
517         if userdefinedtoo:
518             return [self.Profile, self.DS302, self.UserMapping]
519         else:
520             return [self.Profile, self.DS302]
521     
522     """
523     Add a new entry in the Object Dictionary
524     """
525     def AddEntry(self, index, subIndex = None, value = None):
526         if index not in self.Dictionary:
527             if not subIndex:
528                 self.Dictionary[index] = value
529                 return True
530             elif subIndex == 1:
531                 self.Dictionary[index] = [value]
532                 return True
533         elif subIndex > 1 and type(self.Dictionary[index]) == ListType and subIndex == len(self.Dictionary[index]) + 1:
534             self.Dictionary[index].append(value)
535             return True
536         return False
537
538     """
539     Warning ! Modifies an existing entry in the Object Dictionary. Can't add a new one.
540     """
541     def SetEntry(self, index, subIndex = None, value = None):
542         if index in self.Dictionary:
543             if not subIndex:
544                 if value != None:
545                     self.Dictionary[index] = value
546                 return True
547             elif type(self.Dictionary[index]) == ListType and 0 < subIndex <= len(self.Dictionary[index]):
548                 if value != None:
549                     self.Dictionary[index][subIndex - 1] = value
550                 return True
551         return False
552     
553     def SetParamsEntry(self, index, subIndex = None, comment = None, save = None, callback = None):
554         if not getattr(self, "ParamsDictionary", False):
555             self.ParamsDictionary = {}
556         if index in self.Dictionary:
557             if (comment != None or save != None or callback != None) and index not in self.ParamsDictionary:
558                 self.ParamsDictionary[index] = {}
559             if subIndex == None or type(self.Dictionary[index]) != ListType and subIndex == 0:
560                 if comment != None:
561                     self.ParamsDictionary[index]["comment"] = comment
562                 if save != None:
563                     self.ParamsDictionary[index]["save"] = save
564                 if callback != None:
565                     self.ParamsDictionary[index]["callback"] = callback
566                 return True
567             elif type(self.Dictionary[index]) == ListType and 0 <= subIndex <= len(self.Dictionary[index]):
568                 if (comment != None or save != None or callback != None) and subIndex not in self.ParamsDictionary[index]:
569                     self.ParamsDictionary[index][subIndex] = {}
570                 if comment != None:
571                     self.ParamsDictionary[index][subIndex]["comment"] = comment
572                 if save != None:
573                     self.ParamsDictionary[index][subIndex]["save"] = save
574                 return True
575         return False
576     
577     """
578     Removes an existing entry in the Object Dictionary. If a subIndex is specified
579     it will remove this subIndex only if it's the last of the index. If no subIndex
580     is specified it removes the whole index and subIndexes from the Object Dictionary.
581     """
582     def RemoveEntry(self, index, subIndex = None):
583         if not getattr(self, "ParamsDictionary", False):
584             self.ParamsDictionary = {}
585         if index in self.Dictionary:
586             if not subIndex:
587                 self.Dictionary.pop(index)
588                 if index in self.ParamsDictionary:
589                     self.ParamsDictionary.pop(index)
590                 return True
591             elif type(self.Dictionary[index]) == ListType and subIndex == len(self.Dictionary[index]):
592                 self.Dictionary[index].pop(subIndex - 1)
593                 if index in self.ParamsDictionary:
594                     if subIndex in self.ParamsDictionary[index]:
595                         self.ParamsDictionary[index].pop(subIndex)
596                     if len(self.ParamsDictionary[index]) == 0:
597                         self.ParamsDictionary.pop(index)
598                 if len(self.Dictionary[index]) == 0:
599                     self.Dictionary.pop(index)
600                     if index in self.ParamsDictionary:
601                         self.ParamsDictionary.pop(index)
602                 return True
603         return False
604     
605     """
606     Check if an entry exists in the Object Dictionary and returns the answer.
607     """
608     def IsEntry(self, index, subIndex = None):
609         if index in self.Dictionary:
610             if not subIndex:
611                 return True
612             return subIndex <= len(self.Dictionary[index])
613         return False
614     
615     """
616     Returns the value of the entry asked. If the entry has the value "count", it
617     returns the number of subIndex in the entry except the first.
618     """
619     def GetEntry(self, index, subIndex = None):
620         if index in self.Dictionary:
621             if subIndex == None:
622                 if type(self.Dictionary[index]) == ListType:
623                     values = [len(self.Dictionary[index])]
624                     for value in self.Dictionary[index]:
625                         values.append(self.CompileValue(value, index))
626                     return values
627                 else:
628                     return self.CompileValue(self.Dictionary[index], index)
629             elif subIndex == 0:
630                 if type(self.Dictionary[index]) == ListType:
631                     return len(self.Dictionary[index])
632                 else:
633                     return self.CompileValue(self.Dictionary[index], index)
634             elif type(self.Dictionary[index]) == ListType and 0 < subIndex <= len(self.Dictionary[index]):
635                 return self.CompileValue(self.Dictionary[index][subIndex - 1], index)
636         return None
637
638     """
639     Returns the value of the entry asked. If the entry has the value "count", it
640     returns the number of subIndex in the entry except the first.
641     """
642     def GetParamsEntry(self, index, subIndex = None):
643         if not getattr(self, "ParamsDictionary", False):
644             self.ParamsDictionary = {}
645         if index in self.Dictionary:
646             if subIndex == None:
647                 if type(self.Dictionary[index]) == ListType:
648                     if index in self.ParamsDictionary:
649                         result = []
650                         for i in xrange(len(self.Dictionary[index]) + 1):
651                             line = DefaultParams.copy()
652                             if i in self.ParamsDictionary[index]:
653                                 line.update(self.ParamsDictionary[index][i])
654                             result.append(line)
655                         return result
656                     else:
657                         return [DefaultParams.copy() for i in xrange(len(self.Dictionary[index]) + 1)]
658                 else:
659                     result = DefaultParams.copy()
660                     if index in self.ParamsDictionary:
661                         result.update(self.ParamsDictionary[index])
662                     return result
663             elif subIndex == 0 and type(self.Dictionary[index]) != ListType:
664                 result = DefaultParams.copy()
665                 if index in self.ParamsDictionary:
666                     result.update(self.ParamsDictionary[index])
667                 return result
668             elif type(self.Dictionary[index]) == ListType and 0 <= subIndex <= len(self.Dictionary[index]):
669                 result = DefaultParams.copy()
670                 if index in self.ParamsDictionary and subIndex in self.ParamsDictionary[index]:
671                     result.update(self.ParamsDictionary[index][subIndex])
672                 return result
673         return None
674
675     def HasEntryCallbacks(self, index):
676         if not getattr(self, "ParamsDictionary", False):
677             self.ParamsDictionary = {}
678         if index in self.Dictionary and index in self.ParamsDictionary and "callback" in self.ParamsDictionary[index]:
679             return self.ParamsDictionary[index]["callback"]
680         return False
681
682     """
683     Check if an entry exists in the User Mapping Dictionary and returns the answer.
684     """
685     def IsMappingEntry(self, index):
686         if index in self.UserMapping:
687             return True
688         return False
689
690     """
691     Add a new entry in the User Mapping Dictionary
692     """
693     def AddMappingEntry(self, index, subIndex = None, name = "Undefined", struct = 0, size = None, nbmax = None, default = None, values = None):
694         if index not in self.UserMapping:
695             if values == None:
696                 values = []
697             if subIndex == None:
698                 self.UserMapping[index] = {"name" : name, "struct" : struct, "need" : False, "values" : values}
699                 if size != None:
700                     self.UserMapping[index]["size"] = size
701                 if nbmax != None:
702                     self.UserMapping[index]["nbmax"] = nbmax
703                 if default != None:
704                     self.UserMapping[index]["default"] = default
705                 return True
706         elif subIndex != None and subIndex == len(self.UserMapping[index]["values"]):
707             if values == None:
708                 values = {}
709             self.UserMapping[index]["values"].append(values)
710             return True
711         return False
712
713     """
714     Warning ! Modifies an existing entry in the User Mapping Dictionary. Can't add a new one.
715     """
716     def SetMappingEntry(self, index, subIndex = None, name = None, struct = None, size = None, nbmax = None, default = None, values = None):
717         if index in self.UserMapping:
718             if subIndex == None:
719                 if name != None:
720                     self.UserMapping[index]["name"] = name
721                     if self.UserMapping[index]["struct"] & OD_IdenticalSubindexes:
722                         self.UserMapping[index]["values"][1]["name"] = name + " %d[(sub)]"
723                     elif not self.UserMapping[index]["struct"] & OD_MultipleSubindexes:
724                         self.UserMapping[index]["values"][0]["name"] = name
725                 if struct != None:
726                     self.UserMapping[index]["struct"] = struct
727                 if size != None:
728                     self.UserMapping[index]["size"] = size
729                 if nbmax != None:
730                     self.UserMapping[index]["nbmax"] = nbmax
731                 if default != None:
732                     self.UserMapping[index]["default"] = default
733                 if values != None:
734                     self.UserMapping[index]["values"] = values
735                 return True
736             elif 0 <= subIndex < len(self.UserMapping[index]["values"]) and values != None:
737                 self.UserMapping[index]["values"][subIndex].update(values)
738                 return True
739         return False
740     
741     """
742     Removes an existing entry in the User Mapping Dictionary. If a subIndex is specified
743     it will remove this subIndex only if it's the last of the index. If no subIndex
744     is specified it removes the whole index and subIndexes from the User Mapping Dictionary.
745     """
746     def RemoveMappingEntry(self, index, subIndex = None):
747         if index in self.UserMapping:
748             if subIndex == None:
749                 self.UserMapping.pop(index)
750                 return True
751             elif subIndex == len(self.UserMapping[index]["values"]) - 1:
752                 self.UserMapping[index]["values"].pop(subIndex)
753                 return True
754         return False
755
756     def RemoveMapVariable(self, index, subIndex = None):
757         model = index << 16
758         mask = 0xFFFF << 16
759         if subIndex:
760             model += subIndex << 8
761             mask = 0xFF << 8
762         for i in self.Dictionary.iterkeys():
763             if 0x1600 <= i <= 0x17FF or 0x1A00 <= i <= 0x1BFF:
764                 for j,value in enumerate(self.Dictionary[i]):
765                     if (value & mask) == model:
766                         self.Dictionary[i][j] = 0
767     
768     def UpdateMapVariable(self, index, subIndex, size):
769         model = index << 16
770         mask = 0xFFFF << 16
771         if subIndex:
772             model += subIndex << 8
773             mask = 0xFF << 8
774         for i in self.Dictionary.iterkeys():
775             if 0x1600 <= i <= 0x17FF or 0x1A00 <= i <= 0x1BFF:
776                 for j,value in enumerate(self.Dictionary[i]):
777                     if (value & mask) == model:
778                         self.Dictionary[i][j] = model + size
779     
780     def RemoveLine(self, index, max, incr = 1):
781         i = index
782         while i < max and self.IsEntry(i + incr):
783             self.Dictionary[i] = self.Dictionary[i + incr]
784             i += incr
785         self.Dictionary.pop(i)
786
787     def RemoveUserType(self, index):
788         type = self.GetEntry(index, 1)
789         for i in self.UserMapping:
790             for value in self.UserMapping[i]["values"]:
791                 if value["type"] == index:
792                     value["type"] = type
793         self.RemoveMappingEntry(index)
794         self.RemoveEntry(index)
795
796     """
797     Return a copy of the node
798     """
799     def Copy(self):
800         return cPickle.loads(cPickle.dumps(self))
801
802     """
803     Return a sorted list of indexes in Object Dictionary
804     """
805     def GetIndexes(self):
806         listindex = self.Dictionary.keys()
807         listindex.sort()
808         return listindex
809
810     """
811     Print the Dictionary values
812     """
813     def Print(self):
814         listindex = self.Dictionary.keys()
815         listindex.sort()
816         for index in listindex:
817             values = self.Dictionary[index]
818             if index != 0x1F22 and type(values) != IntType:
819                 values = [i for i in values]
820                 for i, value in enumerate(values):
821                     if type(value) == IntType:
822                         values[i] = "%X"%value
823                 values = "[" + ",".join(values) + "]"
824             print "%04X : %s"%(index, values)
825
826     def CompileValue(self, value, index):
827         if type(value) == StringType and value.find("self.ID") != -1:
828             base = self.GetBaseIndex(index)
829             try:
830                 return eval(value)
831             except:
832                 return 0
833         else:
834             return value
835
836 #-------------------------------------------------------------------------------
837 #                         Node Informations Functions
838 #-------------------------------------------------------------------------------
839
840     def GetBaseIndex(self, index):
841         for mapping in self.GetMappings():
842             result = FindIndex(index, mapping)
843             if result != None:
844                 return (index - result) / mapping[result].get("incr", 1)
845         result = FindIndex(index, MappingDictionary)
846         if result != None:
847             return (index - result) / MappingDictionary[result].get("incr", 1)
848         return 0
849
850     def GetCustomisedTypeValues(self, index):
851         values = self.GetEntry(index)
852         customisabletypes = self.GetCustomisableTypes()
853         return values, customisabletypes[values[1]][1]
854
855     def GetEntryName(self, index):
856         result = None
857         mappings = self.GetMappings()
858         i = 0
859         while not result and i < len(mappings):
860             result = FindEntryName(index, mappings[i])
861             i += 1
862         if result == None:
863             result = FindEntryName(index, MappingDictionary)
864         return result
865     
866     def GetEntryInfos(self, index):
867         result = None
868         mappings = self.GetMappings()
869         i = 0
870         while not result and i < len(mappings):
871             result = FindEntryInfos(index, mappings[i])
872             i += 1
873         if result == None:
874             result = FindEntryInfos(index, MappingDictionary)
875         return result
876     
877     def GetSubentryInfos(self, index, subIndex):
878         result = None
879         mappings = self.GetMappings()
880         i = 0
881         while not result and i < len(mappings):
882             result = FindSubentryInfos(index, subIndex, mappings[i])
883             if result:
884                 result["user_defined"] = i == len(mappings) - 1 and index >= 0x1000
885             i += 1
886         if result == None:
887             result = FindSubentryInfos(index, subIndex, MappingDictionary)
888             if result:
889                 result["user_defined"] = False
890         return result
891     
892     def GetTypeIndex(self, typename):
893         result = None
894         mappings = self.GetMappings()
895         i = 0
896         while not result and i < len(mappings):
897             result = FindTypeIndex(typename, mappings[i])
898             i += 1
899         if result == None:
900             result = FindTypeIndex(typename, MappingDictionary)
901         return result
902     
903     def GetTypeName(self, typeindex):
904         result = None
905         mappings = self.GetMappings()
906         i = 0
907         while not result and i < len(mappings):
908             result = FindTypeName(typeindex, mappings[i])
909             i += 1
910         if result == None:
911             result = FindTypeName(typeindex, MappingDictionary)
912         return result
913     
914     def GetTypeDefaultValue(self, typeindex):
915         result = None
916         mappings = self.GetMappings()
917         i = 0
918         while not result and i < len(mappings):
919             result = FindTypeDefaultValue(typeindex, mappings[i])
920             i += 1
921         if result == None:
922             result = FindTypeDefaultValue(typeindex, MappingDictionary)
923         return result
924     
925     def GetMapVariableList(self):
926         list = FindMapVariableList(MappingDictionary, self)
927         for mapping in self.GetMappings():
928             list.extend(FindMapVariableList(mapping, self))
929         list.sort()
930         return list
931     
932     def GetMandatoryIndexes(self, node = None):
933         list = FindMandatoryIndexes(MappingDictionary)
934         for mapping in self.GetMappings():
935             list.extend(FindMandatoryIndexes(mapping))
936         return list
937     
938     def GetCustomisableTypes(self):
939         dic = {}
940         for index, valuetype in CustomisableTypes:
941             name = self.GetTypeName(index)
942             dic[index] = [name, valuetype]
943         return dic
944
945 #-------------------------------------------------------------------------------
946 #                            Type and Map Variable Lists
947 #-------------------------------------------------------------------------------
948     
949     def GetTypeList(self):
950         list = FindTypeList(MappingDictionary)
951         for mapping in self.GetMappings():
952             list.extend(FindTypeList(mapping))
953         list.sort()
954         return ",".join(list)
955
956     """
957     Generate the list of variables that can be mapped for the current node
958     """
959     def GenerateMapList(self):
960         self.MapList = "None"
961         self.NameTranslation = {"None" : "00000000"}
962         self.MapTranslation = {"00000000" : "None"}
963         list = self.GetMapVariableList()
964         for index, subIndex, size, name in list:
965             self.MapList += ",%s"%name
966             map = "%04X%02X%02X"%(index,subIndex,size)
967             self.NameTranslation[name] = map
968             self.MapTranslation[map] = name
969
970     def GetMapValue(self, mapname):
971         if mapname == "None":
972             return 0
973         else:
974             list = self.GetMapVariableList()
975             for index, subIndex, size, name in list:
976                 if mapname == name:
977                     return (index << 16) + (subIndex << 8) + size
978             return None
979     
980     def GetMapName(self, value):
981         if value != 0:
982             index = value >> 16
983             subindex = (value >> 8) % (1 << 8)
984             result = self.GetSubentryInfos(index, subindex)
985             if result:
986                 return result["name"]
987         return "None"
988     
989     """
990     Return the list of variables that can be mapped for the current node
991     """
992     def GetMapList(self):
993         list = ["None"] + [name for index, subIndex, size, name in self.GetMapVariableList()]
994         return ",".join(list)