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