]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/nodemanager.py
Modifying gen_cfile.py for generating C file from a node as data rather than a manager
[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(self.CurrentNode.Copy(), False)
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(self.CurrentNode.Copy(), False)
310             self.SetCurrentFilePath("")
311             return index
312         else:
313             return result
314     
315     """
316     Export to an eds file and store it in a new buffer if no node edited
317     """
318     def ExportCurrentToEDSFile(self, filepath):
319         return eds_utils.GenerateEDSFile(filepath, self)
320     
321     """
322     Build the C definition of Object Dictionary for current node 
323     """
324     def ExportCurrentToCFile(self, filepath):
325         if self.CurrentNode:
326             return gen_cfile.GenerateFile(filepath, self.CurrentNode)
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, node = None):
337         if node == None:
338             disable_buffer = True
339             node = self.CurrentNode  
340         else:
341             disable_buffer = False
342         # Informations about entry
343         length = node.GetEntry(index, 0)
344         infos = node.GetEntryInfos(index)
345         subentry_infos = node.GetSubentryInfos(index, 1)
346         # Get default value for subindex
347         if "default" in subentry_infos:
348             default = subentry_infos["default"]
349         else:
350             default = self.GetTypeDefaultValue(subentry_infos["type"])   
351         # First case entry is record
352         if infos["struct"] & OD_IdenticalSubindexes: 
353             for i in xrange(1, min(number,subentry_infos["nbmax"]-length) + 1):
354                 node.AddEntry(index, length + i, default)
355             if not disable_buffer:
356                 self.BufferCurrentNode()
357             return None
358         # Second case entry is array, only possible for manufacturer specific
359         elif infos["struct"] & OD_MultipleSubindexes and 0x2000 <= index <= 0x5FFF:
360             values = {"name" : "Undefined", "type" : 5, "access" : "rw", "pdo" : True}
361             for i in xrange(1, min(number,0xFE-length) + 1):
362                 node.AddMappingEntry(index, length + i, values = values.copy())
363                 node.AddEntry(index, length + i, 0)
364             if not disable_buffer:
365                 self.BufferCurrentNode()
366             return None
367             
368
369     """
370     Remove the specified number of subentry for the given entry. Verify that total
371     number of subentry (except 0) isn't less than 1
372     """
373     def RemoveSubentriesFromCurrent(self, index, number):
374         # Informations about entry
375         infos = self.GetEntryInfos(index)
376         length = self.CurrentNode.GetEntry(index, 0)
377         # Entry is a record, or is an array of manufacturer specific
378         if infos["struct"] & OD_IdenticalSubindexes or 0x2000 <= index <= 0x5FFF and infos["struct"] & OD_IdenticalSubindexes:
379             for i in xrange(min(number, length - 1)):
380                 self.RemoveCurrentVariable(index, length - i)
381             self.BufferCurrentNode()
382
383     """
384     Add a SDO Server to current node
385     """
386     def AddSDOServerToCurrent(self):
387         # An SDO Server is already defined at index 0x1200
388         if self.CurrentNode.IsEntry(0x1200):
389             indexlist = [self.GetLineFromIndex(0x1201)]
390             if None not in indexlist:
391                 self.ManageEntriesOfCurrent(indexlist, [])
392         # Add an SDO Server at index 0x1200
393         else:
394             self.ManageEntriesOfCurrent([0x1200], [])
395         
396     """
397     Add a SDO Server to current node
398     """
399     def AddSDOClientToCurrent(self):
400         indexlist = [self.GetLineFromIndex(0x1280)]
401         if None not in indexlist:
402             self.ManageEntriesOfCurrent(indexlist, [])
403
404     """
405     Add a Transmit PDO to current node
406     """
407     def AddPDOTransmitToCurrent(self):
408         indexlist = [self.GetLineFromIndex(0x1800),self.GetLineFromIndex(0x1A00)]
409         if None not in indexlist:
410             self.ManageEntriesOfCurrent(indexlist, [])
411         
412     """
413     Add a Receive PDO to current node
414     """
415     def AddPDOReceiveToCurrent(self):
416         indexlist = [self.GetLineFromIndex(0x1400),self.GetLineFromIndex(0x1600)]
417         if None not in indexlist:
418             self.ManageEntriesOfCurrent(indexlist, [])
419
420     """
421     Add a list of entries defined in profile for menu item selected to current node
422     """
423     def AddSpecificEntryToCurrent(self, menuitem):
424         indexlist = []
425         for menu, indexes in self.CurrentNode.GetSpecificMenu():
426             if menuitem == menu:
427                 for index in indexes:
428                     indexlist.append(self.GetLineFromIndex(index))
429         if None not in indexlist:
430             self.ManageEntriesOfCurrent(indexlist, [])
431
432     """
433     Search the first index available for a pluri entry from base_index
434     """
435     def GetLineFromIndex(self, base_index):
436         found = False
437         index = base_index
438         infos = self.GetEntryInfos(base_index)
439         while index < base_index + infos["incr"]*infos["nbmax"] and not found:
440             if not self.CurrentNode.IsEntry(index):
441                 found = True
442             else:
443                 index += infos["incr"]
444         if found:
445             return index
446         return None
447     
448     """
449     Add entries specified in addinglist and remove entries specified in removinglist
450     """
451     def ManageEntriesOfCurrent(self, addinglist, removinglist, node = None):
452         if node == None:
453             disable_buffer = True
454             node = self.CurrentNode
455         else:
456             disable_buffer = False
457         # Add all the entries in addinglist
458         for index in addinglist:
459             infos = self.GetEntryInfos(index)
460             if infos["struct"] & OD_MultipleSubindexes:
461                 # First case entry is a record
462                 if infos["struct"] & OD_IdenticalSubindexes:
463                     subentry_infos = self.GetSubentryInfos(index, 1)
464                     if "default" in subentry_infos:
465                         default = subentry_infos["default"]
466                     else:
467                         default = self.GetTypeDefaultValue(subentry_infos["type"])
468                     node.AddEntry(index, 1, default)
469                 # Second case entry is a record
470                 else:
471                     i = 1
472                     subentry_infos = self.GetSubentryInfos(index, i)
473                     while subentry_infos:
474                         if "default" in subentry_infos:
475                             default = subentry_infos["default"]
476                         else:
477                             default = self.GetTypeDefaultValue(subentry_infos["type"])
478                         node.AddEntry(index, i, default)
479                         i += 1
480                         subentry_infos = self.GetSubentryInfos(index, i)
481             # Third case entry is a record
482             else:
483                 subentry_infos = self.GetSubentryInfos(index, 0)
484                 if "default" in subentry_infos:
485                     default = subentry_infos["default"]
486                 else:
487                     default = self.GetTypeDefaultValue(subentry_infos["type"])
488                 node.AddEntry(index, 0, default)
489         # Remove all the entries in removinglist
490         for index in removinglist:
491             self.RemoveCurrentVariable(index)
492         if not disable_buffer:
493             self.BufferCurrentNode()
494         return None
495
496
497     """
498     Remove an entry from current node. Analize the index to perform the correct
499     method
500     """
501     def RemoveCurrentVariable(self, index, subIndex = None):
502         Mappings = self.CurrentNode.GetMappings()
503         if index < 0x1000 and subIndex == None:
504             type = self.CurrentNode.GetEntry(index, 1)
505             for i in Mappings[-1]:
506                 for value in Mappings[-1][i]["values"]:
507                     if value["type"] == index:
508                         value["type"] = type
509             self.CurrentNode.RemoveMappingEntry(index)
510             self.CurrentNode.RemoveEntry(index)
511         elif index == 0x1200 and subIndex == None:
512             self.CurrentNode.RemoveEntry(0x1200)
513         elif 0x1201 <= index <= 0x127F and subIndex == None:
514             self.CurrentNode.RemoveLine(index, 0x127F)
515         elif 0x1280 <= index <= 0x12FF and subIndex == None:
516             self.CurrentNode.RemoveLine(index, 0x12FF)
517         elif 0x1400 <= index <= 0x15FF or 0x1600 <= index <= 0x17FF and subIndex == None:
518             if 0x1600 <= index <= 0x17FF and subIndex == None:
519                 index -= 0x200
520             self.CurrentNode.RemoveLine(index, 0x15FF)
521             self.CurrentNode.RemoveLine(index + 0x200, 0x17FF)
522         elif 0x1800 <= index <= 0x19FF or 0x1A00 <= index <= 0x1BFF and subIndex == None:
523             if 0x1A00 <= index <= 0x1BFF:
524                 index -= 0x200
525             self.CurrentNode.RemoveLine(index, 0x19FF)
526             self.CurrentNode.RemoveLine(index + 0x200, 0x1BFF)
527         else:
528             found = False
529             for menu,list in self.CurrentNode.GetSpecificMenu():
530                 for i in list:
531                     iinfos = self.GetEntryInfos(i)
532                     indexes = [i + incr * iinfos["incr"] for incr in xrange(iinfos["nbmax"])] 
533                     if index in indexes:
534                         found = True
535                         diff = index - i
536                         for j in list:
537                             jinfos = self.GetEntryInfos(j)
538                             self.CurrentNode.RemoveLine(j + diff, j + jinfos["incr"]*jinfos["nbmax"], jinfos["incr"])
539             self.CurrentNode.RemoveMapVariable(index, subIndex)
540             if not found:
541                 infos = self.GetEntryInfos(index)
542                 if not infos["need"]:
543                     self.CurrentNode.RemoveEntry(index, subIndex)
544             if index in Mappings[-1]:
545                 self.CurrentNode.RemoveMappingEntry(index, subIndex)
546
547     def AddMapVariableToCurrent(self, index, name, struct, number, node = None):
548         if 0x2000 <= index <= 0x5FFF:
549             if node == None:
550                 disable_buffer = True
551                 node = self.CurrentNode
552             else:
553                 disable_buffer = False
554             if not node.IsEntry(index):
555                 node.AddMappingEntry(index, name = name, struct = struct)
556                 if struct == var:
557                     values = {"name" : name, "type" : 0x05, "access" : "rw", "pdo" : True}
558                     node.AddMappingEntry(index, 0, values = values)
559                     node.AddEntry(index, 0, 0)
560                 else:
561                     values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False}
562                     node.AddMappingEntry(index, 0, values = values)
563                     if struct == rec:
564                         values = {"name" : name + " %d[(sub)]", "type" : 0x05, "access" : "rw", "pdo" : True, "nbmax" : 0xFE}
565                         node.AddMappingEntry(index, 1, values = values)
566                         for i in xrange(number):
567                             node.AddEntry(index, i + 1, 0)
568                     else:
569                         for i in xrange(number):
570                             values = {"name" : "Undefined", "type" : 0x05, "access" : "rw", "pdo" : True}
571                             node.AddMappingEntry(index, i + 1, values = values)
572                             node.AddEntry(index, i + 1, 0)
573                 if not disable_buffer:
574                     self.BufferCurrentNode()
575                 return None
576             else:
577                 return "Index 0x%04X already defined!"%index
578         else:
579             return "Index 0x%04X isn't a valid index for Map Variable!"%index
580
581     def AddUserTypeToCurrent(self, type, min, max, length):
582         index = 0xA0
583         while index < 0x100 and self.CurrentNode.IsEntry(index):
584             index += 1
585         if index < 0x100:
586             customisabletypes = self.GetCustomisableTypes()
587             name, valuetype = customisabletypes[type]
588             size = self.GetEntryInfos(type)["size"]
589             default = self.GetTypeDefaultValue(type)
590             if valuetype == 0:
591                 self.CurrentNode.AddMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default)
592                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False})
593                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x05, "access" : "ro", "pdo" : False})
594                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
595                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
596                 self.CurrentNode.AddEntry(index, 1, type)
597                 self.CurrentNode.AddEntry(index, 2, min)
598                 self.CurrentNode.AddEntry(index, 3, max)
599             elif valuetype == 1:
600                 self.CurrentNode.AddMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = length * size, default = default)
601                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False})
602                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x05, "access" : "ro", "pdo" : False})
603                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x05, "access" : "ro", "pdo" : False})
604                 self.CurrentNode.AddEntry(index, 1, type)
605                 self.CurrentNode.AddEntry(index, 2, length)
606             self.BufferCurrentNode()
607             return None
608         else:
609             return "Too many User Types have already been defined!"
610
611 #-------------------------------------------------------------------------------
612 #                      Modify Entry and Mapping Functions
613 #-------------------------------------------------------------------------------
614
615     def SetCurrentEntryCallbacks(self, index, value):
616         if self.CurrentNode and self.CurrentNode.IsEntry(index):
617             entry_infos = self.GetEntryInfos(index)
618             if "callback" not in entry_infos:
619                 self.CurrentNode.SetParamsEntry(index, None, callback = value)
620                 self.BufferCurrentNode()
621
622     def SetCurrentEntry(self, index, subIndex, value, name, editor, node = None):
623         
624         if node == None:
625                 disable_buffer = True
626                 node = self.CurrentNode
627         else:
628             disable_buffer = False
629         if node and node.IsEntry(index):
630             if name == "value":
631                 if editor == "map":
632                     value = node.GetMapValue(value)
633                     if value:
634                         node.SetEntry(index, subIndex, value)
635                 elif editor == "bool":
636                     value = value == "True"
637                     node.SetEntry(index, subIndex, value)
638                 elif editor == "time":
639                     node.SetEntry(index, subIndex, value)
640                 elif editor == "number":
641                     try:
642                         node.SetEntry(index, subIndex, int(value))
643                     except:
644                         pass
645                 elif editor == "domain":
646                     try:
647                         if len(value) % 2 != 0:
648                             value = "0" + value
649                         value = value.decode('hex_codec')
650                         node.SetEntry(index, subIndex, value)
651                     except:
652                         pass
653                 else:
654                     subentry_infos = self.GetSubentryInfos(index, subIndex)
655                     type = subentry_infos["type"]
656                     dic = {}
657                     for typeindex, typevalue in CustomisableTypes:
658                         dic[typeindex] = typevalue
659                     if type not in dic:
660                         type = node.GetEntry(type)[1]
661                     if dic[type] == 0:
662                         try:
663                             if value.startswith("0x"):
664                                 value = int(value, 16)
665                             else:
666                                 value = int(value)
667                             node.SetEntry(index, subIndex, value)
668                         except:
669                             pass
670                     else:
671                         node.SetEntry(index, subIndex, value)
672             elif name in ["comment", "save"]:
673                 if editor == "option":
674                     value = value == "Yes"
675                 if name == "save":
676                     node.SetParamsEntry(index, subIndex, save = value)
677                 elif name == "comment":
678                     node.SetParamsEntry(index, subIndex, comment = value)
679             else:
680                 if editor == "type":
681                     value = self.GetTypeIndex(value)
682                     size = self.GetEntryInfos(value)["size"]
683                     node.UpdateMapVariable(index, subIndex, size)
684                 elif editor in ["access","raccess"]:
685                     dic = {}
686                     for abbrev,access in AccessType.iteritems():
687                         dic[access] = abbrev
688                     value = dic[value]
689                     if editor == "raccess" and not node.IsMappingEntry(index):
690                         entry_infos = self.GetEntryInfos(index)
691                         node.AddMappingEntry(index, name = entry_infos["name"], struct = 7)
692                         node.AddMappingEntry(index, 0, values = self.GetSubentryInfos(index, 0, False).copy())
693                         node.AddMappingEntry(index, 1, values = self.GetSubentryInfos(index, 1, False).copy())
694                 node.SetMappingEntry(index, subIndex, values = {name : value})
695             if not disable_buffer:
696                 self.BufferCurrentNode()
697             return None
698
699     def SetCurrentEntryName(self, index, name):
700         self.CurrentNode.SetMappingEntry(index, name=name)
701         self.BufferCurrentNode()
702
703     def SetCurrentUserType(self, index, type, min, max, length):
704         customisabletypes = self.GetCustomisableTypes()
705         values, valuetype = self.GetCustomisedTypeValues(index)
706         name, new_valuetype = customisabletypes[type]
707         size = self.GetEntryInfos(type)["size"]
708         default = self.GetTypeDefaultValue(type)
709         if new_valuetype == 0:
710             self.CurrentNode.SetMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default) 
711             if valuetype == 1:
712                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
713                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
714             self.CurrentNode.SetEntry(index, 1, type)
715             self.CurrentNode.SetEntry(index, 2, min)
716             if valuetype == 1:
717                 self.CurrentNode.AddEntry(index, 3, max)
718             else:
719                 self.CurrentNode.SetEntry(index, 3, max)
720         elif new_valuetype == 1:
721             self.CurrentNode.SetMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = size, default = default)
722             if valuetype == 0:
723                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
724                 self.CurrentNode.RemoveMappingEntry(index, 3)
725             self.CurrentNode.SetEntry(index, 1, type)
726             self.CurrentNode.SetEntry(index, 2, length)
727             if valuetype == 0:
728                 self.CurrentNode.RemoveEntry(index, 3)
729         self.BufferCurrentNode()
730
731 #-------------------------------------------------------------------------------
732 #                      Current Buffering Management Functions
733 #-------------------------------------------------------------------------------
734
735     def BufferCurrentNode(self):
736         self.UndoBuffers[self.NodeIndex].Buffering(self.CurrentNode.Copy())
737
738     def CurrentIsSaved(self):
739         return self.UndoBuffers[self.NodeIndex].IsCurrentSaved()
740
741     def OneFileHasChanged(self):
742         result = False
743         for buffer in self.UndoBuffers.values():
744             result |= not buffer.IsCurrentSaved()
745         return result
746
747     def GetBufferNumber(self):
748         return len(self.UndoBuffers)
749
750     def LoadCurrentPrevious(self):
751         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Previous().Copy()
752     
753     def LoadCurrentNext(self):
754         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Next().Copy()
755
756     def AddNodeBuffer(self, currentstate = None, issaved = False):
757         self.NodeIndex = GetNewId()
758         self.UndoBuffers[self.NodeIndex] = UndoBuffer(currentstate, issaved)
759         self.FilePaths[self.NodeIndex] = ""
760         self.FileNames[self.NodeIndex] = ""
761         return self.NodeIndex
762
763     def ChangeCurrentNode(self, index):
764         if index in self.UndoBuffers.keys():
765             self.NodeIndex = index
766             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
767     
768     def RemoveNodeBuffer(self, index):
769         self.UndoBuffers.pop(index)
770         self.FilePaths.pop(index)
771         self.FileNames.pop(index)
772     
773     def GetCurrentNodeIndex(self):
774         return self.NodeIndex
775     
776     def GetCurrentFilename(self):
777         return self.GetFilename(self.NodeIndex)
778     
779     def GetAllFilenames(self):
780         indexes = self.UndoBuffers.keys()
781         indexes.sort()
782         return [self.GetFilename(idx) for idx in indexes]
783     
784     def GetFilename(self, index):
785         if self.UndoBuffers[index].IsCurrentSaved():
786             return self.FileNames[index]
787         else:
788             return "~%s~"%self.FileNames[index]
789     
790     def SetCurrentFilePath(self, filepath):
791         self.FilePaths[self.NodeIndex] = filepath
792         if filepath == "":
793             self.LastNewIndex += 1
794             self.FileNames[self.NodeIndex] = "Unnamed%d"%self.LastNewIndex
795         else:
796             self.FileNames[self.NodeIndex] = os.path.splitext(os.path.basename(filepath))[0]
797                 
798     def GetCurrentFilePath(self):
799         if len(self.FilePaths) > 0:
800             return self.FilePaths[self.NodeIndex]
801         else:
802             return ""
803     
804     def GetCurrentBufferState(self):
805         first = self.UndoBuffers[self.NodeIndex].IsFirst()
806         last = self.UndoBuffers[self.NodeIndex].IsLast()
807         return not first, not last
808
809 #-------------------------------------------------------------------------------
810 #                         Profiles Management Functions
811 #-------------------------------------------------------------------------------
812
813     def GetCurrentCommunicationLists(self):
814         list = []
815         for index in MappingDictionary.iterkeys():
816             if 0x1000 <= index < 0x1200:
817                 list.append(index)
818         return self.GetProfileLists(MappingDictionary, list)
819     
820     def GetCurrentDS302Lists(self):
821         return self.GetSpecificProfileLists(self.CurrentNode.GetDS302Profile())
822     
823     def GetCurrentProfileLists(self):
824         return self.GetSpecificProfileLists(self.CurrentNode.GetProfile())
825     
826     def GetSpecificProfileLists(self, mappingdictionary):
827         validlist = []
828         exclusionlist = []
829         for name, list in self.CurrentNode.GetSpecificMenu():
830             exclusionlist.extend(list)
831         for index in mappingdictionary.iterkeys():
832             if index not in exclusionlist:
833                 validlist.append(index)
834         return self.GetProfileLists(mappingdictionary, validlist)
835     
836     def GetProfileLists(self, mappingdictionary, list):
837         dictionary = {}
838         current = []
839         for index in list:
840             dictionary[index] = (mappingdictionary[index]["name"], mappingdictionary[index]["need"])
841             if self.CurrentNode.IsEntry(index):
842                 current.append(index)
843         return dictionary, current
844
845     def GetCurrentNextMapIndex(self):
846         if self.CurrentNode:
847             index = 0x2000
848             while self.CurrentNode.IsEntry(index) and index < 0x5FFF:
849                 index += 1
850             if index < 0x6000:
851                 return index
852             else:
853                 return None
854
855     def CurrentDS302Defined(self):
856         if self.CurrentNode:
857             return len(self.CurrentNode.GetDS302Profile()) > 0
858         return False
859
860 #-------------------------------------------------------------------------------
861 #                         Node State and Values Functions
862 #-------------------------------------------------------------------------------
863     
864     def GetCurrentNodeName(self):
865         if self.CurrentNode:
866             return self.CurrentNode.GetNodeName()
867         else:
868             return ""
869
870     def GetCurrentNodeCopy(self):
871         if self.CurrentNode:
872             return self.CurrentNode.Copy()
873         else:
874             return None
875     
876     def GetCurrentNodeID(self, node = None):
877         if self.CurrentNode:
878             return self.CurrentNode.GetNodeID()
879         else:
880             return None
881
882     def GetCurrentNodeInfos(self):
883         name = self.CurrentNode.GetNodeName()
884         id = self.CurrentNode.GetNodeID()
885         type = self.CurrentNode.GetNodeType()
886         description = self.CurrentNode.GetNodeDescription()
887         return name, id, type, description
888         
889     def SetCurrentNodeInfos(self, name, id, type, description):
890         self.CurrentNode.SetNodeName(name)
891         self.CurrentNode.SetNodeID(id)
892         self.CurrentNode.SetNodeType(type)
893         self.CurrentNode.SetNodeDescription(description)
894         self.BufferCurrentNode()
895
896     def GetCurrentProfileName(self):
897         if self.CurrentNode:
898             return self.CurrentNode.GetProfileName()
899         return ""
900
901     def IsCurrentEntry(self, index):
902         if self.CurrentNode:
903             return self.CurrentNode.IsEntry(index)
904         return False
905     
906     def GetCurrentEntry(self, index, subIndex = None):
907         if self.CurrentNode:
908             return self.CurrentNode.GetEntry(index, subIndex)
909         return None
910     
911     def GetCurrentParamsEntry(self, index, subIndex = None):
912         if self.CurrentNode:
913             return self.CurrentNode.GetParamsEntry(index, subIndex)
914         return None
915     
916     def GetCurrentValidIndexes(self, min, max):
917         validindexes = []
918         for index in self.CurrentNode.GetIndexes():
919             if min <= index <= max:
920                 validindexes.append((self.GetEntryName(index), index))
921         return validindexes
922         
923     def GetCurrentValidChoices(self, min, max):
924         validchoices = []
925         exclusionlist = []
926         for menu, indexes in self.CurrentNode.GetSpecificMenu():
927             exclusionlist.extend(indexes)
928             good = True
929             for index in indexes:
930                 good &= min <= index <= max
931             if good:
932                 validchoices.append((menu, None))
933         list = [index for index in MappingDictionary.keys() if index >= 0x1000]
934         profiles = self.CurrentNode.GetMappings(False)
935         for profile in profiles:
936             list.extend(profile.keys())
937         list.sort()
938         for index in list:
939             if min <= index <= max and not self.CurrentNode.IsEntry(index) and index not in exclusionlist:
940                 validchoices.append((self.GetEntryName(index), index))
941         return validchoices
942     
943     def HasCurrentEntryCallbacks(self, index):
944         if self.CurrentNode:
945             return self.CurrentNode.HasEntryCallbacks(index)
946         return False
947     
948     def GetCurrentEntryValues(self, index):
949         if self.CurrentNode:
950             return self.GetNodeEntryValues(self.CurrentNode, index)
951     
952     def GetNodeEntryValues(self, node, index):
953         if node and node.IsEntry(index):
954             entry_infos = node.GetEntryInfos(index)
955             data = []
956             editors = []
957             values = node.GetEntry(index)
958             params = node.GetParamsEntry(index)
959             if type(values) == ListType:
960                 for i, value in enumerate(values):
961                     data.append({"value" : value})
962                     data[-1].update(params[i])      
963             else:
964                 data.append({"value" : values})
965                 data[-1].update(params)
966             for i, dic in enumerate(data):
967                 infos = node.GetSubentryInfos(index, i)
968                 dic["subindex"] = "0x%02X"%i
969                 dic["name"] = infos["name"]
970                 dic["type"] = node.GetTypeName(infos["type"])
971                 dic["access"] = AccessType[infos["access"]]
972                 dic["save"] = OptionType[dic["save"]]
973                 editor = {"subindex" : None, "save" : "option", "callback" : "option", "comment" : "string"}
974                 if type(values) == ListType and i == 0:
975                     editor["name"] = None
976                     editor["type"] = None
977                     if 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
978                         editor["access"] = "raccess"
979                     else:
980                         editor["access"] = None
981                     editor["value"] = None
982                 else:
983                     if infos["user_defined"]:
984                         if entry_infos["struct"] & OD_IdenticalSubindexes:
985                             editor["name"] = None
986                             if i > 1:
987                                 editor["type"] = None
988                                 editor["access"] = None
989                             else:
990                                 editor["type"] = "type"
991                                 editor["access"] = "access"
992                         else:
993                             if entry_infos["struct"] & OD_MultipleSubindexes:
994                                 editor["name"] = "string"
995                             else:
996                                 editor["name"] = None
997                             editor["type"] = "type"
998                             editor["access"] = "access"
999                     else:
1000                         editor["name"] = None
1001                         editor["type"] = None
1002                         editor["access"] = None
1003                     if index < 0x260:
1004                         editor["value"] = None
1005                         if i == 1:
1006                             dic["value"] = node.GetTypeName(dic["value"])
1007                     elif 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
1008                         editor["value"] = "map"
1009                         dic["value"] = node.GetMapName(dic["value"])
1010                     else:
1011                         if dic["type"].startswith("VISIBLE_STRING"):
1012                             editor["value"] = "string"
1013                         elif dic["type"] in ["TIME_OF_DAY","TIME_DIFFERENCE"]:
1014                             editor["value"] = "time"
1015                         elif dic["type"] == "DOMAIN":
1016                             editor["value"] = "domain"
1017                             dic["value"] = dic["value"].encode('hex_codec')
1018                         elif dic["type"] == "BOOLEAN":
1019                             editor["value"] = "bool"
1020                             dic["value"] = BoolType[dic["value"]]
1021                         result = type_model.match(dic["type"])
1022                         if result:
1023                             values = result.groups()
1024                             if values[0] == "UNSIGNED":
1025                                 format = "0x%0" + str(int(values[1])/4) + "X"
1026                                 dic["value"] = format%dic["value"]
1027                                 editor["value"] = "string"
1028                             if values[0] == "INTEGER":
1029                                 editor["value"] = "number"
1030                             elif values[0] == "REAL":
1031                                 editor["value"] = "float"
1032                             elif values[0] == "VISIBLE_STRING":
1033                                 editor["length"] = values[0]
1034                         result = range_model.match(dic["type"])
1035                         if result:
1036                             values = result.groups()
1037                             if values[0] in ["UNSIGNED", "INTEGER", "REAL"]:
1038                                 editor["min"] = values[2]
1039                                 editor["max"] = values[3]
1040                 editors.append(editor)
1041             return data, editors
1042         else:
1043             return None
1044
1045 #-------------------------------------------------------------------------------
1046 #                         Node Informations Functions
1047 #-------------------------------------------------------------------------------
1048
1049     def GetCustomisedTypeValues(self, index):
1050         if self.CurrentNode:
1051             values = self.CurrentNode.GetEntry(index)
1052             customisabletypes = self.GetCustomisableTypes()
1053             return values, customisabletypes[values[1]][1]
1054         else:
1055             return None, None
1056
1057     def GetEntryName(self, index):
1058         if self.CurrentNode:
1059             return self.CurrentNode.GetEntryName(index)
1060         else:
1061             return FindEntryName(index, MappingDictionary)
1062     
1063     def GetEntryInfos(self, index):
1064         if self.CurrentNode:
1065             return self.CurrentNode.GetEntryInfos(index)
1066         else:
1067             return FindEntryInfos(index, MappingDictionary)
1068     
1069     def GetSubentryInfos(self, index, subindex):
1070         if self.CurrentNode:
1071             return self.CurrentNode.GetSubentryInfos(index, subindex)
1072         else:
1073             result = FindSubentryInfos(index, subindex, MappingDictionary)
1074             if result:
1075                 result["user_defined"] = False
1076             return result
1077     
1078     def GetTypeIndex(self, typename):
1079         if self.CurrentNode:
1080             return self.CurrentNode.GetTypeIndex(typename)
1081         else:
1082             return FindTypeIndex(typename, MappingDictionary)
1083     
1084     def GetTypeName(self, typeindex):
1085         if self.CurrentNode:
1086             return self.CurrentNode.GetTypeName(typeindex)
1087         else:
1088             return FindTypeName(typeindex, MappingDictionary)
1089     
1090     def GetTypeDefaultValue(self, typeindex):
1091         if self.CurrentNode:
1092             return self.CurrentNode.GetTypeDefaultValue(typeindex)
1093         else:
1094             return FindTypeDefaultValue(typeindex, MappingDictionary)
1095     
1096     def GetMapVariableList(self):
1097         if self.CurrentNode:
1098             return self.CurrentNode.GetMapVariableList()
1099         else:
1100             return []
1101
1102     def GetMandatoryIndexes(self):
1103         if self.CurrentNode:
1104             return self.CurrentNode.GetMandatoryIndexes()
1105         else:
1106             return FindMandatoryIndexes(MappingDictionary)
1107     
1108     def GetCustomisableTypes(self):
1109         dic = {}
1110         for index, valuetype in CustomisableTypes:
1111             name = self.GetTypeName(index)
1112             dic[index] = [name, valuetype]
1113         return dic
1114     
1115     def GetCurrentSpecificMenu(self):
1116         if self.CurrentNode:
1117             return self.CurrentNode.GetSpecificMenu()
1118         return []
1119