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