]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/nodemanager.py
add auto-mapping tool (config_utils)
[CanFestival-3.git] / objdictgen / nodemanager.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 from gnosis.xml.pickle import *
25 from gnosis.xml.pickle.util import setParanoia
26 setParanoia(0)
27
28 from node import *
29 import eds_utils, gen_cfile
30
31 from types import *
32 import os, re
33
34 UndoBufferLength = 20
35
36 type_model = re.compile('([\_A-Z]*)([0-9]*)')
37 range_model = re.compile('([\_A-Z]*)([0-9]*)\[([\-0-9]*)-([\-0-9]*)\]')
38
39 # ID for the file viewed
40 CurrentID = 0
41
42 # Returns a new id
43 def GetNewId():
44     global CurrentID
45     CurrentID += 1
46     return CurrentID
47
48 """
49 Class implementing a buffer of changes made on the current editing Object Dictionary
50 """
51
52 class UndoBuffer:
53
54     """
55     Constructor initialising buffer
56     """
57     def __init__(self, currentstate, issaved = False):
58         self.Buffer = []
59         self.CurrentIndex = -1
60         self.MinIndex = -1
61         self.MaxIndex = -1
62         # if current state is defined
63         if currentstate:
64             self.CurrentIndex = 0
65             self.MinIndex = 0
66             self.MaxIndex = 0
67         # Initialising buffer with currentstate at the first place
68         for i in xrange(UndoBufferLength):
69             if i == 0:
70                 self.Buffer.append(currentstate)
71             else:
72                 self.Buffer.append(None)
73         # Initialising index of state saved
74         if issaved:
75             self.LastSave = 0
76         else:
77             self.LastSave = -1
78     
79     """
80     Add a new state in buffer
81     """
82     def Buffering(self, currentstate):
83         self.CurrentIndex = (self.CurrentIndex + 1) % UndoBufferLength
84         self.Buffer[self.CurrentIndex] = currentstate
85         # Actualising buffer limits
86         self.MaxIndex = self.CurrentIndex
87         if self.MinIndex == self.CurrentIndex:
88             # If the removed state was the state saved, there is no state saved in the buffer
89             if self.LastSave == self.MinIndex:
90                 self.LastSave = -1
91             self.MinIndex = (self.MinIndex + 1) % UndoBufferLength
92         self.MinIndex = max(self.MinIndex, 0)
93     
94     """
95     Return current state of buffer
96     """
97     def Current(self):
98         return self.Buffer[self.CurrentIndex]
99     
100     """
101     Change current state to previous in buffer and return new current state
102     """
103     def Previous(self):
104         if self.CurrentIndex != self.MinIndex:
105             self.CurrentIndex = (self.CurrentIndex - 1) % UndoBufferLength
106             return self.Buffer[self.CurrentIndex]
107         return None
108     
109     """
110     Change current state to next in buffer and return new current state
111     """
112     def Next(self):
113         if self.CurrentIndex != self.MaxIndex:
114             self.CurrentIndex = (self.CurrentIndex + 1) % UndoBufferLength
115             return self.Buffer[self.CurrentIndex]
116         return None
117     
118     """
119     Return True if current state is the first in buffer
120     """
121     def IsFirst(self):
122         return self.CurrentIndex == self.MinIndex
123     
124     """
125     Return True if current state is the last in buffer
126     """
127     def IsLast(self):
128         return self.CurrentIndex == self.MaxIndex
129
130     """
131     Note that current state is saved
132     """
133     def CurrentSaved(self):
134         self.LastSave = self.CurrentIndex
135         
136     """
137     Return True if current state is saved
138     """
139     def IsCurrentSaved(self):
140         return self.LastSave == self.CurrentIndex
141
142
143
144 """
145 Class which control the operations made on the node and answer to view requests
146 """
147
148 class NodeManager:
149
150     """
151     Constructor
152     """
153     def __init__(self, cwd):
154         self.LastNewIndex = 0
155         self.FilePaths = {}
156         self.FileNames = {}
157         self.NodeIndex = None
158         self.CurrentNode = None
159         self.ScriptDirectory = cwd
160         self.UndoBuffers = {}
161
162 #-------------------------------------------------------------------------------
163 #                         Type and Map Variable Lists
164 #-------------------------------------------------------------------------------
165     
166     """
167     Return the list of types defined for the current node
168     """
169     def GetCurrentTypeList(self):
170         if self.CurrentNode:
171             return self.CurrentNode.GetTypeList()
172         else:
173             return ""
174
175     """
176     Return the list of variables that can be mapped for the current node
177     """
178     def GetCurrentMapList(self):
179         if self.CurrentNode:
180             return self.CurrentNode.GetMapList()
181         else:
182             return ""
183
184 #-------------------------------------------------------------------------------
185 #                        Create Load and Save Functions
186 #-------------------------------------------------------------------------------
187
188     """
189     Create a new node and add a new buffer for storing it
190     """
191     def CreateNewNode(self, name, id, type, description, profile, filepath, NMT, options):
192         # Create a new node
193         node = Node()
194         # Try to load profile given
195         result = self.LoadProfile(profile, filepath, node)
196         if not result:
197             # if success, initialising node
198             self.CurrentNode = node
199             self.CurrentNode.SetNodeName(name)
200             self.CurrentNode.SetNodeID(id)
201             self.CurrentNode.SetNodeType(type)
202             self.CurrentNode.SetNodeDescription(description)
203             AddIndexList = self.GetMandatoryIndexes()
204             if NMT == "NodeGuarding":
205                 AddIndexList.extend([0x100C, 0x100D])
206             elif NMT == "Heartbeat":
207                 AddIndexList.append(0x1017)
208             for option in options:
209                 if option == "DS302":
210                     DS302Path = os.path.join(self.ScriptDirectory, "config/DS-302.prf")
211                     # Charging DS-302 profile if choosen by user
212                     if os.path.isfile(DS302Path):
213                         try:
214                             execfile(DS302Path)
215                             self.CurrentNode.SetDS302Profile(Mapping)
216                             self.CurrentNode.ExtendSpecificMenu(AddMenuEntries)
217                         except:
218                             return "Problem with DS-302! Syntax Error."
219                     else:
220                         return "Couldn't find DS-302 in 'config' folder!"
221                 elif option == "GenSYNC":
222                     AddIndexList.extend([0x1005, 0x1006])
223                 elif option == "Emergency":
224                     AddIndexList.append(0x1014)
225                 elif option == "SaveConfig":
226                     AddIndexList.extend([0x1010, 0x1011, 0x1020])
227                 elif option == "StoreEDS":
228                     AddIndexList.extend([0x1021, 0x1022])
229             # Add a new buffer 
230             index = self.AddNodeBuffer()
231             self.SetCurrentFilePath("")
232             # Add Mandatory indexes
233             self.ManageEntriesOfCurrent(AddIndexList, [])
234             return index
235         else:
236             return result
237     
238     """
239     Load a profile in node
240     """
241     def LoadProfile(self, profile, filepath, node):
242         if profile != "None":
243             # Try to charge the profile given
244             try:
245                 execfile(filepath)
246                 node.SetProfileName(profile)
247                 node.SetProfile(Mapping)
248                 node.SetSpecificMenu(AddMenuEntries)
249                 return None
250             except:
251                 return "Syntax Error\nBad OD Profile file!."
252         else:
253             # Default profile
254             node.SetProfileName("None")
255             node.SetProfile({})
256             node.SetSpecificMenu([])
257             return None
258
259     """
260     Open a file and store it in a new buffer
261     """
262     def OpenFileInCurrent(self, filepath):
263         # Open and load file
264         file = open(filepath, "r")
265         node = load(file)
266         file.close()
267         self.CurrentNode = node
268         # Add a new buffer and defining current state
269         index = self.AddNodeBuffer(self.CurrentNode.Copy(), True)
270         self.SetCurrentFilePath(filepath)
271         return index
272
273     """
274     Save current node in  a file
275     """
276     def SaveCurrentInFile(self, filepath = None):
277         # if no filepath given, verify if current node has a filepath defined
278         if not filepath:
279             filepath = self.GetCurrentFilePath()
280             if filepath == "":
281                 return False
282         # Save node in file
283         file = open(filepath, "w")
284         dump(self.CurrentNode, file)
285         file.close()
286         self.SetCurrentFilePath(filepath)
287         # Update saved state in buffer
288         self.UndoBuffers[self.NodeIndex].CurrentSaved()
289         return True
290
291     """
292     Close current state
293     """
294     def CloseCurrent(self, ignore = False):
295         # Verify if it's not forced that the current node is saved before closing it
296         if self.UndoBuffers[self.NodeIndex].IsCurrentSaved() or ignore:
297             self.RemoveNodeBuffer(self.NodeIndex)
298             return True
299         return False
300
301     """
302     Import an eds file and store it in a new buffer if no node edited
303     """
304     def ImportCurrentFromEDSFile(self, filepath):
305         # Generate node from definition in a xml file
306         result = eds_utils.GenerateNode(filepath, self.ScriptDirectory)
307         if isinstance(result, Node):
308             self.CurrentNode = result
309             index = self.AddNodeBuffer()
310             self.SetCurrentFilePath("")
311             self.BufferCurrentNode()
312             return index
313         else:
314             return result
315     
316     """
317     Export to an eds file and store it in a new buffer if no node edited
318     """
319     def ExportCurrentToEDSFile(self, filepath):
320         return eds_utils.GenerateEDSFile(filepath, self)
321     
322     """
323     Build the C definition of Object Dictionary for current node 
324     """
325     def ExportCurrentToCFile(self, filepath):
326         return gen_cfile.GenerateFile(filepath, self)
327
328 #-------------------------------------------------------------------------------
329 #                        Add Entries to Current Functions
330 #-------------------------------------------------------------------------------
331
332     """
333     Add the specified number of subentry for the given entry. Verify that total
334     number of subentry (except 0) doesn't exceed nbmax defined
335     """
336     def AddSubentriesToCurrent(self, index, number):
337         # Informations about entry
338         length = self.CurrentNode.GetEntry(index, 0)
339         infos = self.GetEntryInfos(index)
340         subentry_infos = self.GetSubentryInfos(index, 1)
341         # Get default value for subindex
342         if "default" in subentry_infos:
343             default = subentry_infos["default"]
344         else:
345             default = self.GetTypeDefaultValue(subentry_infos["type"])   
346         # First case entry is record
347         if infos["struct"] & OD_IdenticalSubindexes:
348             for i in xrange(1, min(number,subentry_infos["nbmax"]-length) + 1):
349                 self.CurrentNode.AddEntry(index, length + i, default)
350             self.BufferCurrentNode()
351         # Second case entry is array, only possible for manufacturer specific
352         elif infos["struct"] & OD_MultipleSubindexes and 0x2000 <= index <= 0x5FFF:
353             values = {"name" : "Undefined", "type" : 5, "access" : "rw", "pdo" : True}
354             for i in xrange(1, min(number,0xFE-length) + 1):
355                 self.CurrentNode.AddMappingEntry(index, length + i, values = values.copy())
356                 self.CurrentNode.AddEntry(index, length + i, 0)
357             self.BufferCurrentNode()
358
359     """
360     Remove the specified number of subentry for the given entry. Verify that total
361     number of subentry (except 0) isn't less than 1
362     """
363     def RemoveSubentriesFromCurrent(self, index, number):
364         # Informations about entry
365         infos = self.GetEntryInfos(index)
366         length = self.CurrentNode.GetEntry(index, 0)
367         # Entry is a record, or is an array of manufacturer specific
368         if infos["struct"] & OD_IdenticalSubindexes or 0x2000 <= index <= 0x5FFF and infos["struct"] & OD_IdenticalSubindexes:
369             for i in xrange(min(number, length - 1)):
370                 self.RemoveCurrentVariable(index, length - i)
371             self.BufferCurrentNode()
372
373     """
374     Add a SDO Server to current node
375     """
376     def AddSDOServerToCurrent(self):
377         # An SDO Server is already defined at index 0x1200
378         if self.CurrentNode.IsEntry(0x1200):
379             indexlist = [self.GetLineFromIndex(0x1201)]
380             if None not in indexlist:
381                 self.ManageEntriesOfCurrent(indexlist, [])
382         # Add an SDO Server at index 0x1200
383         else:
384             self.ManageEntriesOfCurrent([0x1200], [])
385         
386     """
387     Add a SDO Server to current node
388     """
389     def AddSDOClientToCurrent(self):
390         indexlist = [self.GetLineFromIndex(0x1280)]
391         if None not in indexlist:
392             self.ManageEntriesOfCurrent(indexlist, [])
393
394     """
395     Add a Transmit PDO to current node
396     """
397     def AddPDOTransmitToCurrent(self):
398         indexlist = [self.GetLineFromIndex(0x1800),self.GetLineFromIndex(0x1A00)]
399         if None not in indexlist:
400             self.ManageEntriesOfCurrent(indexlist, [])
401         
402     """
403     Add a Receive PDO to current node
404     """
405     def AddPDOReceiveToCurrent(self):
406         indexlist = [self.GetLineFromIndex(0x1400),self.GetLineFromIndex(0x1600)]
407         if None not in indexlist:
408             self.ManageEntriesOfCurrent(indexlist, [])
409
410     """
411     Add a list of entries defined in profile for menu item selected to current node
412     """
413     def AddSpecificEntryToCurrent(self, menuitem):
414         indexlist = []
415         for menu, indexes in self.CurrentNode.GetSpecificMenu():
416             if menuitem == menu:
417                 for index in indexes:
418                     indexlist.append(self.GetLineFromIndex(index))
419         if None not in indexlist:
420             self.ManageEntriesOfCurrent(indexlist, [])
421
422     """
423     Search the first index available for a pluri entry from base_index
424     """
425     def GetLineFromIndex(self, base_index):
426         found = False
427         index = base_index
428         infos = self.GetEntryInfos(base_index)
429         while index < base_index + infos["incr"]*infos["nbmax"] and not found:
430             if not self.CurrentNode.IsEntry(index):
431                 found = True
432             else:
433                 index += infos["incr"]
434         if found:
435             return index
436         return None
437     
438     """
439     Add entries specified in addinglist and remove entries specified in removinglist
440     """
441     def ManageEntriesOfCurrent(self, addinglist, removinglist):
442         # Add all the entries in addinglist
443         for index in addinglist:
444             infos = self.GetEntryInfos(index)
445             if infos["struct"] & OD_MultipleSubindexes:
446                 # First case entry is a record
447                 if infos["struct"] & OD_IdenticalSubindexes:
448                     subentry_infos = self.GetSubentryInfos(index, 1)
449                     if "default" in subentry_infos:
450                         default = subentry_infos["default"]
451                     else:
452                         default = self.GetTypeDefaultValue(subentry_infos["type"])
453                     self.CurrentNode.AddEntry(index, 1, default)
454                 # Second case entry is a record
455                 else:
456                     i = 1
457                     subentry_infos = self.GetSubentryInfos(index, i)
458                     while subentry_infos:
459                         if "default" in subentry_infos:
460                             default = subentry_infos["default"]
461                         else:
462                             default = self.GetTypeDefaultValue(subentry_infos["type"])
463                         self.CurrentNode.AddEntry(index, i, default)
464                         i += 1
465                         subentry_infos = self.GetSubentryInfos(index, i)
466             # Third case entry is a record
467             else:
468                 subentry_infos = self.GetSubentryInfos(index, 0)
469                 if "default" in subentry_infos:
470                     default = subentry_infos["default"]
471                 else:
472                     default = self.GetTypeDefaultValue(subentry_infos["type"])
473                 self.CurrentNode.AddEntry(index, 0, default)
474         # Remove all the entries in removinglist
475         for index in removinglist:
476             self.RemoveCurrentVariable(index)
477         self.BufferCurrentNode()
478
479
480     """
481     Remove an entry from current node. Analize the index to perform the correct
482     method
483     """
484     def RemoveCurrentVariable(self, index, subIndex = None):
485         Mappings = self.CurrentNode.GetMappings()
486         if index < 0x1000 and subIndex == None:
487             type = self.CurrentNode.GetEntry(index, 1)
488             for i in Mappings[-1]:
489                 for value in Mappings[-1][i]["values"]:
490                     if value["type"] == index:
491                         value["type"] = type
492             self.CurrentNode.RemoveMappingEntry(index)
493             self.CurrentNode.RemoveEntry(index)
494         elif index == 0x1200 and subIndex == None:
495             self.CurrentNode.RemoveEntry(0x1200)
496         elif 0x1201 <= index <= 0x127F and subIndex == None:
497             self.CurrentNode.RemoveLine(index, 0x127F)
498         elif 0x1280 <= index <= 0x12FF and subIndex == None:
499             self.CurrentNode.RemoveLine(index, 0x12FF)
500         elif 0x1400 <= index <= 0x15FF or 0x1600 <= index <= 0x17FF and subIndex == None:
501             if 0x1600 <= index <= 0x17FF and subIndex == None:
502                 index -= 0x200
503             self.CurrentNode.RemoveLine(index, 0x15FF)
504             self.CurrentNode.RemoveLine(index + 0x200, 0x17FF)
505         elif 0x1800 <= index <= 0x19FF or 0x1A00 <= index <= 0x1BFF and subIndex == None:
506             if 0x1A00 <= index <= 0x1BFF:
507                 index -= 0x200
508             self.CurrentNode.RemoveLine(index, 0x19FF)
509             self.CurrentNode.RemoveLine(index + 0x200, 0x1BFF)
510         else:
511             found = False
512             for menu,list in self.CurrentNode.GetSpecificMenu():
513                 for i in list:
514                     iinfos = self.GetEntryInfos(i)
515                     indexes = [i + incr * iinfos["incr"] for incr in xrange(iinfos["nbmax"])] 
516                     if index in indexes:
517                         found = True
518                         diff = index - i
519                         for j in list:
520                             jinfos = self.GetEntryInfos(j)
521                             self.CurrentNode.RemoveLine(j + diff, j + jinfos["incr"]*jinfos["nbmax"], jinfos["incr"])
522             self.CurrentNode.RemoveMapVariable(index, subIndex)
523             if not found:
524                 infos = self.GetEntryInfos(index)
525                 if not infos["need"]:
526                     self.CurrentNode.RemoveEntry(index, subIndex)
527             if index in Mappings[-1]:
528                 self.CurrentNode.RemoveMappingEntry(index, subIndex)
529
530     def AddMapVariableToCurrent(self, index, name, struct, number):
531         if 0x2000 <= index <= 0x5FFF:
532             if not self.CurrentNode.IsEntry(index):
533                 self.CurrentNode.AddMappingEntry(index, name = name, struct = struct)
534                 if struct == var:
535                     values = {"name" : name, "type" : 0x05, "access" : "rw", "pdo" : True}
536                     self.CurrentNode.AddMappingEntry(index, 0, values = values)
537                     self.CurrentNode.AddEntry(index, 0, 0)
538                 else:
539                     values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False}
540                     self.CurrentNode.AddMappingEntry(index, 0, values = values)
541                     if struct == rec:
542                         values = {"name" : name + " %d[(sub)]", "type" : 0x05, "access" : "rw", "pdo" : True, "nbmax" : 0xFE}
543                         self.CurrentNode.AddMappingEntry(index, 1, values = values)
544                         for i in xrange(number):
545                             self.CurrentNode.AddEntry(index, i + 1, 0)
546                     else:
547                         for i in xrange(number):
548                             values = {"name" : "Undefined", "type" : 0x05, "access" : "rw", "pdo" : True}
549                             self.CurrentNode.AddMappingEntry(index, i + 1, values = values)
550                             self.CurrentNode.AddEntry(index, i + 1, 0)
551                 self.BufferCurrentNode()
552                 return None
553             else:
554                 return "Index 0x%04X already defined!"%index
555         else:
556             return "Index 0x%04X isn't a valid index for Map Variable!"%index
557
558     def AddUserTypeToCurrent(self, type, min, max, length):
559         index = 0xA0
560         while index < 0x100 and self.CurrentNode.IsEntry(index):
561             index += 1
562         if index < 0x100:
563             customisabletypes = self.GetCustomisableTypes()
564             name, valuetype = customisabletypes[type]
565             size = self.GetEntryInfos(type)["size"]
566             default = self.GetTypeDefaultValue(type)
567             if valuetype == 0:
568                 self.CurrentNode.AddMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default)
569                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False})
570                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x05, "access" : "ro", "pdo" : False})
571                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
572                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
573                 self.CurrentNode.AddEntry(index, 1, type)
574                 self.CurrentNode.AddEntry(index, 2, min)
575                 self.CurrentNode.AddEntry(index, 3, max)
576             elif valuetype == 1:
577                 self.CurrentNode.AddMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = length * size, default = default)
578                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False})
579                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x05, "access" : "ro", "pdo" : False})
580                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x05, "access" : "ro", "pdo" : False})
581                 self.CurrentNode.AddEntry(index, 1, type)
582                 self.CurrentNode.AddEntry(index, 2, length)
583             self.BufferCurrentNode()
584             return None
585         else:
586             return "Too many User Types have already been defined!"
587
588 #-------------------------------------------------------------------------------
589 #                      Modify Entry and Mapping Functions
590 #-------------------------------------------------------------------------------
591
592     def SetCurrentEntryCallbacks(self, index, value):
593         if self.CurrentNode and self.CurrentNode.IsEntry(index):
594             entry_infos = self.GetEntryInfos(index)
595             if "callback" not in entry_infos:
596                 self.CurrentNode.SetParamsEntry(index, None, callback = value)
597                 self.BufferCurrentNode()
598
599     def ResetCurrentDefaultValue(self, index, subIndex):
600         subentry_infos = self.GetSubentryInfos(index, subIndex)
601         if "default" in subentry_infos:
602             default = subentry_infos["default"]
603         else:
604             default = self.GetTypeDefaultValue(subentry_infos["type"])
605         self.CurrentNode.SetEntry(index, subIndex, default)
606         
607
608     def SetCurrentEntry(self, index, subIndex, value, name, editor):
609         if self.CurrentNode and self.CurrentNode.IsEntry(index):
610             if name == "value":
611                 if editor == None:
612                     self.CurrentNode.SetEntry(index, subIndex, value)
613                 elif editor == "map":
614                     value = self.CurrentNode.GetMapValue(value)
615                     if value:
616                         self.CurrentNode.SetEntry(index, subIndex, value)
617                 elif editor == "bool":
618                     value = value == "True"
619                     self.CurrentNode.SetEntry(index, subIndex, value)
620                 elif editor == "time":
621                     self.CurrentNode.SetEntry(index, subIndex, value)
622                 elif editor == "number":
623                     try:
624                         self.CurrentNode.SetEntry(index, subIndex, int(value))
625                     except:
626                         pass
627                 elif editor == "domain":
628                     try:
629                         if len(value) % 2 != 0:
630                             value = "0" + value
631                         value = value.decode('hex_codec')
632                         self.CurrentNode.SetEntry(index, subIndex, value)
633                     except:
634                         pass
635                 else:
636                     subentry_infos = self.GetSubentryInfos(index, subIndex)
637                     type = subentry_infos["type"]
638                     dic = {}
639                     for typeindex, typevalue in CustomisableTypes:
640                         dic[typeindex] = typevalue
641                     if type not in dic:
642                         type = self.CurrentNode.GetEntry(type)[1]
643                     if dic[type] == 0:
644                         try:
645                             if value.startswith("0x"):
646                                 value = int(value, 16)
647                             else:
648                                 value = int(value)
649                             self.CurrentNode.SetEntry(index, subIndex, value)
650                         except:
651                             pass
652                     else:
653                         self.CurrentNode.SetEntry(index, subIndex, value)
654             elif name in ["comment", "save"]:
655                 if editor == "option":
656                     value = value == "Yes"
657                 if name == "save":
658                     self.CurrentNode.SetParamsEntry(index, subIndex, save = value)
659                 elif name == "comment":
660                     self.CurrentNode.SetParamsEntry(index, subIndex, comment = value)
661             else:
662                 if editor == "type":
663                     value = self.GetTypeIndex(value)
664                     size = self.GetEntryInfos(value)["size"]
665                     self.CurrentNode.UpdateMapVariable(index, subIndex, size)
666                 elif editor in ["access","raccess"]:
667                     dic = {}
668                     for abbrev,access in AccessType.iteritems():
669                         dic[access] = abbrev
670                     value = dic[value]
671                     if editor == "raccess" and not self.CurrentNode.IsMappingEntry(index):
672                         entry_infos = self.GetEntryInfos(index)
673                         self.CurrentNode.AddMappingEntry(index, name = entry_infos["name"], struct = 7)
674                         self.CurrentNode.AddMappingEntry(index, 0, values = self.GetSubentryInfos(index, 0, False).copy())
675                         self.CurrentNode.AddMappingEntry(index, 1, values = self.GetSubentryInfos(index, 1, False).copy())
676                 self.CurrentNode.SetMappingEntry(index, subIndex, values = {name : value})
677             self.BufferCurrentNode()
678
679     def SetCurrentEntryName(self, index, name):
680         self.CurrentNode.SetMappingEntry(index, name=name)
681         self.BufferCurrentNode()
682
683     def SetCurrentUserType(self, index, type, min, max, length):
684         customisabletypes = self.GetCustomisableTypes()
685         values, valuetype = self.GetCustomisedTypeValues(index)
686         name, new_valuetype = customisabletypes[type]
687         size = self.GetEntryInfos(type)["size"]
688         default = self.GetTypeDefaultValue(type)
689         if new_valuetype == 0:
690             self.CurrentNode.SetMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default) 
691             if valuetype == 1:
692                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
693                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
694             self.CurrentNode.SetEntry(index, 1, type)
695             self.CurrentNode.SetEntry(index, 2, min)
696             if valuetype == 1:
697                 self.CurrentNode.AddEntry(index, 3, max)
698             else:
699                 self.CurrentNode.SetEntry(index, 3, max)
700         elif new_valuetype == 1:
701             self.CurrentNode.SetMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = size, default = default)
702             if valuetype == 0:
703                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
704                 self.CurrentNode.RemoveMappingEntry(index, 3)
705             self.CurrentNode.SetEntry(index, 1, type)
706             self.CurrentNode.SetEntry(index, 2, length)
707             if valuetype == 0:
708                 self.CurrentNode.RemoveEntry(index, 3)
709         self.BufferCurrentNode()
710
711 #-------------------------------------------------------------------------------
712 #                      Current Buffering Management Functions
713 #-------------------------------------------------------------------------------
714
715     def BufferCurrentNode(self):
716         self.UndoBuffers[self.NodeIndex].Buffering(self.CurrentNode.Copy())
717
718     def CurrentIsSaved(self):
719         return self.UndoBuffers[self.NodeIndex].IsCurrentSaved()
720
721     def OneFileHasChanged(self):
722         result = False
723         for buffer in self.UndoBuffers.values():
724             result |= not buffer.IsCurrentSaved()
725         return result
726
727     def GetBufferNumber(self):
728         return len(self.UndoBuffers)
729
730     def LoadCurrentPrevious(self):
731         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Previous().Copy()
732     
733     def LoadCurrentNext(self):
734         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Next().Copy()
735
736     def AddNodeBuffer(self, currentstate = None, issaved = False):
737         self.NodeIndex = GetNewId()
738         self.UndoBuffers[self.NodeIndex] = UndoBuffer(currentstate, issaved)
739         self.FilePaths[self.NodeIndex] = ""
740         self.FileNames[self.NodeIndex] = ""
741         return self.NodeIndex
742
743     def ChangeCurrentNode(self, index):
744         if index in self.UndoBuffers.keys():
745             self.NodeIndex = index
746             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
747     
748     def RemoveNodeBuffer(self, index):
749         self.UndoBuffers.pop(index)
750         self.FilePaths.pop(index)
751         self.FileNames.pop(index)
752     
753     def GetCurrentNodeIndex(self):
754         return self.NodeIndex
755     
756     def GetCurrentNode(self):
757         if self.NodeIndex:
758             return self.CurrentNode
759         return None
760     
761     def GetCurrentFilename(self):
762         return self.GetFilename(self.NodeIndex)
763     
764     def GetAllFilenames(self):
765         indexes = self.UndoBuffers.keys()
766         indexes.sort()
767         return [self.GetFilename(idx) for idx in indexes]
768     
769     def GetFilename(self, index):
770         if self.UndoBuffers[index].IsCurrentSaved():
771             return self.FileNames[index]
772         else:
773             return "~%s~"%self.FileNames[index]
774     
775     def SetCurrentFilePath(self, filepath):
776         self.FilePaths[self.NodeIndex] = filepath
777         if filepath == "":
778             self.LastNewIndex += 1
779             self.FileNames[self.NodeIndex] = "Unnamed%d"%self.LastNewIndex
780         else:
781             self.FileNames[self.NodeIndex] = os.path.splitext(os.path.basename(filepath))[0]
782                 
783     def GetCurrentFilePath(self):
784         if len(self.FilePaths) > 0:
785             return self.FilePaths[self.NodeIndex]
786         else:
787             return ""
788     
789     def GetCurrentBufferState(self):
790         first = self.UndoBuffers[self.NodeIndex].IsFirst()
791         last = self.UndoBuffers[self.NodeIndex].IsLast()
792         return not first, not last
793
794 #-------------------------------------------------------------------------------
795 #                         Profiles Management Functions
796 #-------------------------------------------------------------------------------
797
798     def GetCurrentCommunicationLists(self):
799         list = []
800         for index in MappingDictionary.iterkeys():
801             if 0x1000 <= index < 0x1200:
802                 list.append(index)
803         return self.GetProfileLists(MappingDictionary, list)
804     
805     def GetCurrentDS302Lists(self):
806         return self.GetSpecificProfileLists(self.CurrentNode.GetDS302Profile())
807     
808     def GetCurrentProfileLists(self):
809         return self.GetSpecificProfileLists(self.CurrentNode.GetProfile())
810     
811     def GetSpecificProfileLists(self, mappingdictionary):
812         validlist = []
813         exclusionlist = []
814         for name, list in self.CurrentNode.GetSpecificMenu():
815             exclusionlist.extend(list)
816         for index in mappingdictionary.iterkeys():
817             if index not in exclusionlist:
818                 validlist.append(index)
819         return self.GetProfileLists(mappingdictionary, validlist)
820     
821     def GetProfileLists(self, mappingdictionary, list):
822         dictionary = {}
823         current = []
824         for index in list:
825             dictionary[index] = (mappingdictionary[index]["name"], mappingdictionary[index]["need"])
826             if self.CurrentNode.IsEntry(index):
827                 current.append(index)
828         return dictionary, current
829
830     def GetCurrentNextMapIndex(self):
831         if self.CurrentNode:
832             index = 0x2000
833             while self.CurrentNode.IsEntry(index) and index < 0x5FFF:
834                 index += 1
835             if index < 0x6000:
836                 return index
837             else:
838                 return None
839
840     def CurrentDS302Defined(self):
841         if self.CurrentNode:
842             return len(self.CurrentNode.GetDS302Profile()) > 0
843         return False
844
845 #-------------------------------------------------------------------------------
846 #                         Node State and Values Functions
847 #-------------------------------------------------------------------------------
848     
849     def GetCurrentNodeName(self):
850         if self.CurrentNode:
851             return self.CurrentNode.GetNodeName()
852         else:
853             return ""
854
855     def GetCurrentNodeID(self):
856         if self.CurrentNode:
857             return self.CurrentNode.GetNodeID()
858         else:
859             return None
860
861     def GetCurrentNodeInfos(self):
862         name = self.CurrentNode.GetNodeName()
863         id = self.CurrentNode.GetNodeID()
864         type = self.CurrentNode.GetNodeType()
865         description = self.CurrentNode.GetNodeDescription()
866         return name, id, type, description
867         
868     def SetCurrentNodeInfos(self, name, id, type, description):
869         self.CurrentNode.SetNodeName(name)
870         self.CurrentNode.SetNodeID(id)
871         self.CurrentNode.SetNodeType(type)
872         self.CurrentNode.SetNodeDescription(description)
873         self.BufferCurrentNode()
874
875     def GetCurrentProfileName(self):
876         if self.CurrentNode:
877             return self.CurrentNode.GetProfileName()
878         return ""
879
880     def IsCurrentEntry(self, index):
881         if self.CurrentNode:
882             return self.CurrentNode.IsEntry(index)
883         return False
884     
885     def GetCurrentEntry(self, index, subIndex = None):
886         if self.CurrentNode:
887             return self.CurrentNode.GetEntry(index, subIndex)
888         return None
889     
890     def GetCurrentParamsEntry(self, index, subIndex = None):
891         if self.CurrentNode:
892             return self.CurrentNode.GetParamsEntry(index, subIndex)
893         return None
894     
895     def GetCurrentValidIndexes(self, min, max):
896         validindexes = []
897         for index in self.CurrentNode.GetIndexes():
898             if min <= index <= max:
899                 validindexes.append((self.GetEntryName(index), index))
900         return validindexes
901         
902     def GetCurrentValidChoices(self, min, max):
903         validchoices = []
904         exclusionlist = []
905         for menu, indexes in self.CurrentNode.GetSpecificMenu():
906             exclusionlist.extend(indexes)
907             good = True
908             for index in indexes:
909                 good &= min <= index <= max
910             if good:
911                 validchoices.append((menu, None))
912         list = [index for index in MappingDictionary.keys() if index >= 0x1000]
913         profiles = self.CurrentNode.GetMappings(False)
914         for profile in profiles:
915             list.extend(profile.keys())
916         list.sort()
917         for index in list:
918             if min <= index <= max and not self.CurrentNode.IsEntry(index) and index not in exclusionlist:
919                 validchoices.append((self.GetEntryName(index), index))
920         return validchoices
921     
922     def HasCurrentEntryCallbacks(self, index):
923         if self.CurrentNode and self.CurrentNode.IsEntry(index):
924             entry_infos = self.GetEntryInfos(index)
925             if "callback" in entry_infos:
926                 return entry_infos["callback"]
927             return self.CurrentNode.HasEntryCallbacks(index)
928         return False
929     
930     def GetCurrentEntryValues(self, index):
931         if self.CurrentNode:
932             return self.GetNodeEntryValues(self.CurrentNode, index)
933     
934     def GetNodeEntryValues(self, node, index):
935         if node and node.IsEntry(index):
936             entry_infos = node.GetEntryInfos(index)
937             data = []
938             editors = []
939             values = node.GetEntry(index)
940             params = node.GetParamsEntry(index)
941             if type(values) == ListType:
942                 for i, value in enumerate(values):
943                     data.append({"value" : value})
944                     data[-1].update(params[i])      
945             else:
946                 data.append({"value" : values})
947                 data[-1].update(params)
948             for i, dic in enumerate(data):
949                 infos = node.GetSubentryInfos(index, i)
950                 dic["subindex"] = "0x%02X"%i
951                 dic["name"] = infos["name"]
952                 dic["type"] = node.GetTypeName(infos["type"])
953                 dic["access"] = AccessType[infos["access"]]
954                 dic["save"] = OptionType[dic["save"]]
955                 editor = {"subindex" : None, "save" : "option", "callback" : "option", "comment" : "string"}
956                 if type(values) == ListType and i == 0:
957                     editor["name"] = None
958                     editor["type"] = None
959                     if 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
960                         editor["access"] = "raccess"
961                     else:
962                         editor["access"] = None
963                     editor["value"] = None
964                 else:
965                     if infos["user_defined"]:
966                         if entry_infos["struct"] & OD_IdenticalSubindexes:
967                             editor["name"] = None
968                             if i > 1:
969                                 editor["type"] = None
970                                 editor["access"] = None
971                             else:
972                                 editor["type"] = "type"
973                                 editor["access"] = "access"
974                         else:
975                             if entry_infos["struct"] & OD_MultipleSubindexes:
976                                 editor["name"] = "string"
977                             else:
978                                 editor["name"] = None
979                             editor["type"] = "type"
980                             editor["access"] = "access"
981                     else:
982                         editor["name"] = None
983                         editor["type"] = None
984                         editor["access"] = None
985                     if index < 0x260:
986                         editor["value"] = None
987                         if i == 1:
988                             dic["value"] = node.GetTypeName(dic["value"])
989                     elif 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
990                         editor["value"] = "map"
991                         dic["value"] = node.GetMapName(dic["value"])
992                     else:
993                         if dic["type"].startswith("VISIBLE_STRING"):
994                             editor["value"] = "string"
995                         elif dic["type"] in ["TIME_OF_DAY","TIME_DIFFERENCE"]:
996                             editor["value"] = "time"
997                         elif dic["type"] == "DOMAIN":
998                             editor["value"] = "domain"
999                             dic["value"] = dic["value"].encode('hex_codec')
1000                         elif dic["type"] == "BOOLEAN":
1001                             editor["value"] = "bool"
1002                             dic["value"] = BoolType[dic["value"]]
1003                         result = type_model.match(dic["type"])
1004                         if result:
1005                             values = result.groups()
1006                             if values[0] == "UNSIGNED":
1007                                 format = "0x%0" + str(int(values[1])/4) + "X"
1008                                 dic["value"] = format%dic["value"]
1009                                 editor["value"] = "string"
1010                             if values[0] == "INTEGER":
1011                                 editor["value"] = "number"
1012                             elif values[0] == "REAL":
1013                                 editor["value"] = "float"
1014                             elif values[0] == "VISIBLE_STRING":
1015                                 editor["length"] = values[0]
1016                         result = range_model.match(dic["type"])
1017                         if result:
1018                             values = result.groups()
1019                             if values[0] in ["UNSIGNED", "INTEGER", "REAL"]:
1020                                 editor["min"] = values[2]
1021                                 editor["max"] = values[3]
1022                 editors.append(editor)
1023             return data, editors
1024         else:
1025             return None
1026
1027 #-------------------------------------------------------------------------------
1028 #                         Node Informations Functions
1029 #-------------------------------------------------------------------------------
1030
1031     def GetCustomisedTypeValues(self, index):
1032         if self.CurrentNode:
1033             values = self.CurrentNode.GetEntry(index)
1034             customisabletypes = self.GetCustomisableTypes()
1035             return values, customisabletypes[values[1]][1]
1036         else:
1037             return None, None
1038
1039     def GetEntryName(self, index):
1040         if self.CurrentNode:
1041             return self.CurrentNode.GetEntryName(index)
1042         else:
1043             return FindEntryName(index, MappingDictionary)
1044     
1045     def GetEntryInfos(self, index):
1046         if self.CurrentNode:
1047             return self.CurrentNode.GetEntryInfos(index)
1048         else:
1049             return FindEntryInfos(index, MappingDictionary)
1050     
1051     def GetSubentryInfos(self, index, subindex):
1052         if self.CurrentNode:
1053             return self.CurrentNode.GetSubentryInfos(index, subindex)
1054         else:
1055             result = FindSubentryInfos(index, subindex, MappingDictionary)
1056             if result:
1057                 result["user_defined"] = False
1058             return result
1059     
1060     def GetTypeIndex(self, typename):
1061         if self.CurrentNode:
1062             return self.CurrentNode.GetTypeIndex(typename)
1063         else:
1064             return FindTypeIndex(typename, MappingDictionary)
1065     
1066     def GetTypeName(self, typeindex):
1067         if self.CurrentNode:
1068             return self.CurrentNode.GetTypeName(typeindex)
1069         else:
1070             return FindTypeName(typeindex, MappingDictionary)
1071     
1072     def GetTypeDefaultValue(self, typeindex):
1073         if self.CurrentNode:
1074             return self.CurrentNode.GetTypeDefaultValue(typeindex)
1075         else:
1076             return FindTypeDefaultValue(typeindex, MappingDictionary)
1077     
1078     def GetMapVariableList(self):
1079         if self.CurrentNode:
1080             return self.CurrentNode.GetMapVariableList()
1081         else:
1082             return []
1083
1084     def GetMandatoryIndexes(self, node = None):
1085         if self.CurrentNode:
1086             return self.CurrentNode.GetMandatoryIndexes()
1087         else:
1088             return FindMandatoryIndexes(MappingDictionary)
1089     
1090     def GetCustomisableTypes(self):
1091         dic = {}
1092         for index, valuetype in CustomisableTypes:
1093             name = self.GetTypeName(index)
1094             dic[index] = [name, valuetype]
1095         return dic
1096     
1097     def GetCurrentSpecificMenu(self):
1098         if self.CurrentNode:
1099             return self.CurrentNode.GetSpecificMenu()
1100         return []
1101