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