]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/nodemanager.py
Fixed some comments in sdo.c
[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 == "float":
679                     try:
680                         node.SetEntry(index, subIndex, float(value))
681                     except:
682                         pass
683                 elif editor == "domain":
684                     try:
685                         if len(value) % 2 != 0:
686                             value = "0" + value
687                         value = value.decode('hex_codec')
688                         node.SetEntry(index, subIndex, value)
689                     except:
690                         pass
691                 elif editor == "dcf":
692                     node.SetEntry(index, subIndex, value)
693                 else:
694                     subentry_infos = self.GetSubentryInfos(index, subIndex)
695                     type = subentry_infos["type"]
696                     dic = {}
697                     for typeindex, typevalue in CustomisableTypes:
698                         dic[typeindex] = typevalue
699                     if type not in dic:
700                         type = node.GetEntry(type)[1]
701                     if dic[type] == 0:
702                         try:
703                             if value.startswith("$NODEID"):
704                                 value = "\"%s\""%value
705                             elif value.startswith("0x"):
706                                 value = int(value, 16)
707                             else:
708                                 value = int(value)
709                             node.SetEntry(index, subIndex, value)
710                         except:
711                             pass
712                     else:
713                         node.SetEntry(index, subIndex, value)
714             elif name in ["comment", "save"]:
715                 if editor == "option":
716                     value = value == "Yes"
717                 if name == "save":
718                     node.SetParamsEntry(index, subIndex, save = value)
719                 elif name == "comment":
720                     node.SetParamsEntry(index, subIndex, comment = value)
721             else:
722                 if editor == "type":
723                     value = self.GetTypeIndex(value)
724                     size = self.GetEntryInfos(value)["size"]
725                     node.UpdateMapVariable(index, subIndex, size)
726                 elif editor in ["access","raccess"]:
727                     dic = {}
728                     for abbrev,access in AccessType.iteritems():
729                         dic[access] = abbrev
730                     value = dic[value]
731                     if editor == "raccess" and not node.IsMappingEntry(index):
732                         entry_infos = self.GetEntryInfos(index)
733                         node.AddMappingEntry(index, name = entry_infos["name"], struct = 7)
734                         node.AddMappingEntry(index, 0, values = self.GetSubentryInfos(index, 0, False).copy())
735                         node.AddMappingEntry(index, 1, values = self.GetSubentryInfos(index, 1, False).copy())
736                 node.SetMappingEntry(index, subIndex, values = {name : value})
737             if not disable_buffer:
738                 self.BufferCurrentNode()
739             return None
740
741     def SetCurrentEntryName(self, index, name):
742         self.CurrentNode.SetMappingEntry(index, name=name)
743         self.BufferCurrentNode()
744
745     def SetCurrentUserType(self, index, type, min, max, length):
746         customisabletypes = self.GetCustomisableTypes()
747         values, valuetype = self.GetCustomisedTypeValues(index)
748         name, new_valuetype = customisabletypes[type]
749         size = self.GetEntryInfos(type)["size"]
750         default = self.GetTypeDefaultValue(type)
751         if new_valuetype == 0:
752             self.CurrentNode.SetMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default) 
753             if valuetype == 1:
754                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
755                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
756             self.CurrentNode.SetEntry(index, 1, type)
757             self.CurrentNode.SetEntry(index, 2, min)
758             if valuetype == 1:
759                 self.CurrentNode.AddEntry(index, 3, max)
760             else:
761                 self.CurrentNode.SetEntry(index, 3, max)
762         elif new_valuetype == 1:
763             self.CurrentNode.SetMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = size, default = default)
764             if valuetype == 0:
765                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
766                 self.CurrentNode.RemoveMappingEntry(index, 3)
767             self.CurrentNode.SetEntry(index, 1, type)
768             self.CurrentNode.SetEntry(index, 2, length)
769             if valuetype == 0:
770                 self.CurrentNode.RemoveEntry(index, 3)
771         self.BufferCurrentNode()
772
773 #-------------------------------------------------------------------------------
774 #                      Current Buffering Management Functions
775 #-------------------------------------------------------------------------------
776
777     def BufferCurrentNode(self):
778         self.UndoBuffers[self.NodeIndex].Buffering(self.CurrentNode.Copy())
779
780     def CurrentIsSaved(self):
781         return self.UndoBuffers[self.NodeIndex].IsCurrentSaved()
782
783     def OneFileHasChanged(self):
784         result = False
785         for buffer in self.UndoBuffers.values():
786             result |= not buffer.IsCurrentSaved()
787         return result
788
789     def GetBufferNumber(self):
790         return len(self.UndoBuffers)
791
792     def LoadCurrentPrevious(self):
793         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Previous().Copy()
794     
795     def LoadCurrentNext(self):
796         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Next().Copy()
797
798     def AddNodeBuffer(self, currentstate = None, issaved = False):
799         self.NodeIndex = GetNewId()
800         self.UndoBuffers[self.NodeIndex] = UndoBuffer(currentstate, issaved)
801         self.FilePaths[self.NodeIndex] = ""
802         self.FileNames[self.NodeIndex] = ""
803         return self.NodeIndex
804
805     def ChangeCurrentNode(self, index):
806         if index in self.UndoBuffers.keys():
807             self.NodeIndex = index
808             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
809     
810     def RemoveNodeBuffer(self, index):
811         self.UndoBuffers.pop(index)
812         self.FilePaths.pop(index)
813         self.FileNames.pop(index)
814     
815     def GetCurrentNodeIndex(self):
816         return self.NodeIndex
817     
818     def GetCurrentFilename(self):
819         return self.GetFilename(self.NodeIndex)
820     
821     def GetAllFilenames(self):
822         indexes = self.UndoBuffers.keys()
823         indexes.sort()
824         return [self.GetFilename(idx) for idx in indexes]
825     
826     def GetFilename(self, index):
827         if self.UndoBuffers[index].IsCurrentSaved():
828             return self.FileNames[index]
829         else:
830             return "~%s~"%self.FileNames[index]
831     
832     def SetCurrentFilePath(self, filepath):
833         self.FilePaths[self.NodeIndex] = filepath
834         if filepath == "":
835             self.LastNewIndex += 1
836             self.FileNames[self.NodeIndex] = "Unnamed%d"%self.LastNewIndex
837         else:
838             self.FileNames[self.NodeIndex] = os.path.splitext(os.path.basename(filepath))[0]
839                 
840     def GetCurrentFilePath(self):
841         if len(self.FilePaths) > 0:
842             return self.FilePaths[self.NodeIndex]
843         else:
844             return ""
845     
846     def GetCurrentBufferState(self):
847         first = self.UndoBuffers[self.NodeIndex].IsFirst()
848         last = self.UndoBuffers[self.NodeIndex].IsLast()
849         return not first, not last
850
851 #-------------------------------------------------------------------------------
852 #                         Profiles Management Functions
853 #-------------------------------------------------------------------------------
854
855     def GetCurrentCommunicationLists(self):
856         list = []
857         for index in MappingDictionary.iterkeys():
858             if 0x1000 <= index < 0x1200:
859                 list.append(index)
860         return self.GetProfileLists(MappingDictionary, list)
861     
862     def GetCurrentDS302Lists(self):
863         return self.GetSpecificProfileLists(self.CurrentNode.GetDS302Profile())
864     
865     def GetCurrentProfileLists(self):
866         return self.GetSpecificProfileLists(self.CurrentNode.GetProfile())
867     
868     def GetSpecificProfileLists(self, mappingdictionary):
869         validlist = []
870         exclusionlist = []
871         for name, list in self.CurrentNode.GetSpecificMenu():
872             exclusionlist.extend(list)
873         for index in mappingdictionary.iterkeys():
874             if index not in exclusionlist:
875                 validlist.append(index)
876         return self.GetProfileLists(mappingdictionary, validlist)
877     
878     def GetProfileLists(self, mappingdictionary, list):
879         dictionary = {}
880         current = []
881         for index in list:
882             dictionary[index] = (mappingdictionary[index]["name"], mappingdictionary[index]["need"])
883             if self.CurrentNode.IsEntry(index):
884                 current.append(index)
885         return dictionary, current
886
887     def GetCurrentNextMapIndex(self):
888         if self.CurrentNode:
889             index = 0x2000
890             while self.CurrentNode.IsEntry(index) and index < 0x5FFF:
891                 index += 1
892             if index < 0x6000:
893                 return index
894             else:
895                 return None
896
897     def CurrentDS302Defined(self):
898         if self.CurrentNode:
899             return len(self.CurrentNode.GetDS302Profile()) > 0
900         return False
901
902 #-------------------------------------------------------------------------------
903 #                         Node State and Values Functions
904 #-------------------------------------------------------------------------------
905     
906     def GetCurrentNodeName(self):
907         if self.CurrentNode:
908             return self.CurrentNode.GetNodeName()
909         else:
910             return ""
911
912     def GetCurrentNodeCopy(self):
913         if self.CurrentNode:
914             return self.CurrentNode.Copy()
915         else:
916             return None
917     
918     def GetCurrentNodeID(self, node = None):
919         if self.CurrentNode:
920             return self.CurrentNode.GetNodeID()
921         else:
922             return None
923
924     def GetCurrentNodeInfos(self):
925         name = self.CurrentNode.GetNodeName()
926         id = self.CurrentNode.GetNodeID()
927         type = self.CurrentNode.GetNodeType()
928         description = self.CurrentNode.GetNodeDescription()
929         return name, id, type, description
930     
931     def SetCurrentNodeInfos(self, name, id, type, description):
932         self.CurrentNode.SetNodeName(name)
933         self.CurrentNode.SetNodeID(id)
934         self.CurrentNode.SetNodeType(type)
935         self.CurrentNode.SetNodeDescription(description)
936         self.BufferCurrentNode()
937
938     def GetCurrentNodeDefaultStringSize(self):
939         if self.CurrentNode:
940             return self.CurrentNode.GetDefaultStringSize()
941         else:
942             return Node.DefaultStringSize
943     
944     def SetCurrentNodeDefaultStringSize(self, size):
945         if self.CurrentNode:
946             self.CurrentNode.SetDefaultStringSize(size)
947         else:
948             Node.DefaultStringSize = size
949
950     def GetCurrentProfileName(self):
951         if self.CurrentNode:
952             return self.CurrentNode.GetProfileName()
953         return ""
954
955     def IsCurrentEntry(self, index):
956         if self.CurrentNode:
957             return self.CurrentNode.IsEntry(index)
958         return False
959     
960     def GetCurrentEntry(self, index, subIndex = None, compute = True):
961         if self.CurrentNode:
962             return self.CurrentNode.GetEntry(index, subIndex, compute)
963         return None
964     
965     def GetCurrentParamsEntry(self, index, subIndex = None):
966         if self.CurrentNode:
967             return self.CurrentNode.GetParamsEntry(index, subIndex)
968         return None
969     
970     def GetCurrentValidIndexes(self, min, max):
971         validindexes = []
972         for index in self.CurrentNode.GetIndexes():
973             if min <= index <= max:
974                 validindexes.append((self.GetEntryName(index), index))
975         return validindexes
976         
977     def GetCurrentValidChoices(self, min, max):
978         validchoices = []
979         exclusionlist = []
980         for menu, indexes in self.CurrentNode.GetSpecificMenu():
981             exclusionlist.extend(indexes)
982             good = True
983             for index in indexes:
984                 good &= min <= index <= max
985             if good:
986                 validchoices.append((menu, None))
987         list = [index for index in MappingDictionary.keys() if index >= 0x1000]
988         profiles = self.CurrentNode.GetMappings(False)
989         for profile in profiles:
990             list.extend(profile.keys())
991         list.sort()
992         for index in list:
993             if min <= index <= max and not self.CurrentNode.IsEntry(index) and index not in exclusionlist:
994                 validchoices.append((self.GetEntryName(index), index))
995         return validchoices
996     
997     def HasCurrentEntryCallbacks(self, index):
998         if self.CurrentNode:
999             return self.CurrentNode.HasEntryCallbacks(index)
1000         return False
1001     
1002     def GetCurrentEntryValues(self, index):
1003         if self.CurrentNode:
1004             return self.GetNodeEntryValues(self.CurrentNode, index)
1005     
1006     def GetNodeEntryValues(self, node, index):
1007         if node and node.IsEntry(index):
1008             entry_infos = node.GetEntryInfos(index)
1009             data = []
1010             editors = []
1011             values = node.GetEntry(index, compute = False)
1012             params = node.GetParamsEntry(index)
1013             if type(values) == ListType:
1014                 for i, value in enumerate(values):
1015                     data.append({"value" : value})
1016                     data[-1].update(params[i])      
1017             else:
1018                 data.append({"value" : values})
1019                 data[-1].update(params)
1020             for i, dic in enumerate(data):
1021                 infos = node.GetSubentryInfos(index, i)
1022                 dic["subindex"] = "0x%02X"%i
1023                 dic["name"] = infos["name"]
1024                 dic["type"] = node.GetTypeName(infos["type"])
1025                 dic["access"] = AccessType[infos["access"]]
1026                 dic["save"] = OptionType[dic["save"]]
1027                 editor = {"subindex" : None, "save" : "option", "callback" : "option", "comment" : "string"}
1028                 if type(values) == ListType and i == 0:
1029                     editor["name"] = None
1030                     editor["type"] = None
1031                     if 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
1032                         editor["access"] = "raccess"
1033                     else:
1034                         editor["access"] = None
1035                     editor["value"] = None
1036                 else:
1037                     if infos["user_defined"]:
1038                         if entry_infos["struct"] & OD_IdenticalSubindexes:
1039                             editor["name"] = None
1040                             if i > 1:
1041                                 editor["type"] = None
1042                                 editor["access"] = None
1043                             else:
1044                                 editor["type"] = "type"
1045                                 editor["access"] = "access"
1046                         else:
1047                             if entry_infos["struct"] & OD_MultipleSubindexes:
1048                                 editor["name"] = "string"
1049                             else:
1050                                 editor["name"] = None
1051                             editor["type"] = "type"
1052                             editor["access"] = "access"
1053                     else:
1054                         editor["name"] = None
1055                         editor["type"] = None
1056                         editor["access"] = None
1057                     if index < 0x260:
1058                         editor["value"] = None
1059                         if i == 1:
1060                             dic["value"] = node.GetTypeName(dic["value"])
1061                     elif 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
1062                         editor["value"] = "map"
1063                         dic["value"] = node.GetMapName(dic["value"])
1064                     else:
1065                         if dic["type"].startswith("VISIBLE_STRING") or dic["type"].startswith("OCTET_STRING"):
1066                             editor["value"] = "string"
1067                         elif dic["type"] in ["TIME_OF_DAY","TIME_DIFFERENCE"]:
1068                             editor["value"] = "time"
1069                         elif dic["type"] == "DOMAIN":
1070                             if index == 0x1F22:
1071                                 editor["value"] = "dcf"
1072                             else:
1073                                 editor["value"] = "domain"
1074                             dic["value"] = dic["value"].encode('hex_codec')
1075                         elif dic["type"] == "BOOLEAN":
1076                             editor["value"] = "bool"
1077                             dic["value"] = BoolType[dic["value"]]
1078                         result = type_model.match(dic["type"])
1079                         if result:
1080                             values = result.groups()
1081                             if values[0] == "UNSIGNED":
1082                                 try:
1083                                     format = "0x%0" + str(int(values[1])/4) + "X"
1084                                     dic["value"] = format%dic["value"]
1085                                 except:
1086                                     pass
1087                                 editor["value"] = "string"
1088                             if values[0] == "INTEGER":
1089                                 editor["value"] = "number"
1090                             elif values[0] == "REAL":
1091                                 editor["value"] = "float"
1092                             elif values[0] in ["VISIBLE_STRING", "OCTET_STRING"]:
1093                                 editor["length"] = values[0]
1094                         result = range_model.match(dic["type"])
1095                         if result:
1096                             values = result.groups()
1097                             if values[0] in ["UNSIGNED", "INTEGER", "REAL"]:
1098                                 editor["min"] = values[2]
1099                                 editor["max"] = values[3]
1100                 editors.append(editor)
1101             return data, editors
1102         else:
1103             return None
1104
1105     def AddToDCF(self, node_id, index, subindex, size, value):
1106         if self.CurrentNode.IsEntry(0x1F22, node_id):
1107             dcf_value = self.CurrentNode.GetEntry(0x1F22, node_id)
1108             if dcf_value != "":
1109                 nbparams = BE_to_LE(dcf_value[:4])
1110             else:
1111                 nbparams = 0
1112             new_value = LE_to_BE(nbparams + 1, 4) + dcf_value[4:]
1113             new_value += LE_to_BE(index, 2) + LE_to_BE(subindex, 1) + LE_to_BE(size, 4) + LE_to_BE(value, size)
1114             self.CurrentNode.SetEntry(0x1F22, node_id, new_value)
1115
1116 #-------------------------------------------------------------------------------
1117 #                         Node Informations Functions
1118 #-------------------------------------------------------------------------------
1119
1120     def GetCustomisedTypeValues(self, index):
1121         if self.CurrentNode:
1122             values = self.CurrentNode.GetEntry(index)
1123             customisabletypes = self.GetCustomisableTypes()
1124             return values, customisabletypes[values[1]][1]
1125         else:
1126             return None, None
1127
1128     def GetEntryName(self, index):
1129         if self.CurrentNode:
1130             return self.CurrentNode.GetEntryName(index)
1131         else:
1132             return FindEntryName(index, MappingDictionary)
1133     
1134     def GetEntryInfos(self, index):
1135         if self.CurrentNode:
1136             return self.CurrentNode.GetEntryInfos(index)
1137         else:
1138             return FindEntryInfos(index, MappingDictionary)
1139     
1140     def GetSubentryInfos(self, index, subindex):
1141         if self.CurrentNode:
1142             return self.CurrentNode.GetSubentryInfos(index, subindex)
1143         else:
1144             result = FindSubentryInfos(index, subindex, MappingDictionary)
1145             if result:
1146                 result["user_defined"] = False
1147             return result
1148     
1149     def GetTypeIndex(self, typename):
1150         if self.CurrentNode:
1151             return self.CurrentNode.GetTypeIndex(typename)
1152         else:
1153             return FindTypeIndex(typename, MappingDictionary)
1154     
1155     def GetTypeName(self, typeindex):
1156         if self.CurrentNode:
1157             return self.CurrentNode.GetTypeName(typeindex)
1158         else:
1159             return FindTypeName(typeindex, MappingDictionary)
1160     
1161     def GetTypeDefaultValue(self, typeindex):
1162         if self.CurrentNode:
1163             return self.CurrentNode.GetTypeDefaultValue(typeindex)
1164         else:
1165             return FindTypeDefaultValue(typeindex, MappingDictionary)
1166     
1167     def GetMapVariableList(self):
1168         if self.CurrentNode:
1169             return self.CurrentNode.GetMapVariableList()
1170         else:
1171             return []
1172
1173     def GetMandatoryIndexes(self):
1174         if self.CurrentNode:
1175             return self.CurrentNode.GetMandatoryIndexes()
1176         else:
1177             return FindMandatoryIndexes(MappingDictionary)
1178     
1179     def GetCustomisableTypes(self):
1180         dic = {}
1181         for index, valuetype in CustomisableTypes:
1182             name = self.GetTypeName(index)
1183             dic[index] = [name, valuetype]
1184         return dic
1185     
1186     def GetCurrentSpecificMenu(self):
1187         if self.CurrentNode:
1188             return self.CurrentNode.GetSpecificMenu()
1189         return []
1190