--- a/ConfigTree.py Tue May 08 16:31:12 2012 +0200
+++ b/ConfigTree.py Tue May 08 17:08:45 2012 +0200
@@ -4,7 +4,7 @@
import os,sys,traceback
import time
-import confnodes
+import features
import types
import shutil
from xml.dom import minidom
@@ -752,7 +752,7 @@
"""
# For root object, available Children Types are modules of the confnode packages.
- CTNChildrenTypes = [(n, CTNClassFactory(c), d) for n,d,h,c in confnodes.catalog]
+ CTNChildrenTypes = [(n, CTNClassFactory(c), d) for n,d,h,c in features.catalog]
XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
@@ -1054,7 +1054,7 @@
return children
def ConfNodePath(self):
- return os.path.join(os.path.split(__file__)[0], "confnodes")
+ return os.path.split(__file__)[0]
def CTNPath(self, CTNName=None):
return self.ProjectPath
@@ -1480,13 +1480,12 @@
self.ResetIECProgramsAndVariables()
# Generate C code and compilation params from confnode hierarchy
- self.logger.write(_("Generating confnodes C code\n"))
try:
self.LocationCFilesAndCFLAGS, self.LDFLAGS, ExtraFiles = self._Generate_C(
buildpath,
self.PLCGeneratedLocatedVars)
except Exception, exc:
- self.logger.write_error(_("ConfNodes code generation failed !\n"))
+ self.logger.write_error(_("Runtime extensions C code generation failed !\n"))
self.logger.write_error(traceback.format_exc())
self.ResetBuildMD5()
return False
--- a/LPCBeremiz.py Tue May 08 16:31:12 2012 +0200
+++ b/LPCBeremiz.py Tue May 08 17:08:45 2012 +0200
@@ -67,8 +67,8 @@
havecanfestival = False
try:
- from confnodes.canfestival import RootClass as CanOpenRootClass
- from confnodes.canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
+ from canfestival import RootClass as CanOpenRootClass
+ from canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
havecanfestival = True
except:
havecanfestival = False
@@ -77,7 +77,7 @@
#-------------------------------------------------------------------------------
# CANFESTIVAL CONFNODE HACK
#-------------------------------------------------------------------------------
-# from confnodes.canfestival import canfestival
+# from canfestival import canfestival
# class LPC_canfestival_config:
# def getCFLAGS(self, *args):
# return ""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/c_ext/.cvsignore Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,1 @@
+*.pyc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/c_ext/CFileEditor.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,967 @@
+import keyword
+
+import wx
+import wx.grid
+import wx.stc as stc
+import wx.lib.buttons
+
+from controls import CustomGrid, CustomTable, EditorPanel
+
+if wx.Platform == '__WXMSW__':
+ faces = { 'times': 'Times New Roman',
+ 'mono' : 'Courier New',
+ 'helv' : 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size' : 10,
+ 'size2': 8,
+ }
+else:
+ faces = { 'times': 'Times',
+ 'mono' : 'Courier',
+ 'helv' : 'Helvetica',
+ 'other': 'new century schoolbook',
+ 'size' : 12,
+ 'size2': 10,
+ }
+
+
+def AppendMenu(parent, help, id, kind, text):
+ if wx.VERSION >= (2, 6, 0):
+ parent.Append(help=help, id=id, kind=kind, text=text)
+ else:
+ parent.Append(helpString=help, id=id, kind=kind, item=text)
+
+
+[ID_CPPEDITOR,
+] = [wx.NewId() for _init_ctrls in range(1)]
+
+CPP_KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class",
+ "const", "const_cast", "continue", "default", "delete", "do", "double",
+ "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
+ "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
+ "namespace", "new", "operator", "private", "protected", "public", "register",
+ "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
+ "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
+ "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
+ "void", "volatile", "wchar_t", "while"]
+
+def GetCursorPos(old, new):
+ old_length = len(old)
+ new_length = len(new)
+ common_length = min(old_length, new_length)
+ i = 0
+ for i in xrange(common_length):
+ if old[i] != new[i]:
+ break
+ if old_length < new_length:
+ if common_length > 0 and old[i] != new[i]:
+ return i + new_length - old_length
+ else:
+ return i + new_length - old_length + 1
+ elif old_length > new_length or i < min(old_length, new_length) - 1:
+ if common_length > 0 and old[i] != new[i]:
+ return i
+ else:
+ return i + 1
+ else:
+ return None
+
+class CppEditor(stc.StyledTextCtrl):
+
+ fold_symbols = 3
+
+ def __init__(self, parent, name, window, controler):
+ stc.StyledTextCtrl.__init__(self, parent, ID_CPPEDITOR, wx.DefaultPosition,
+ wx.Size(0, 0), 0)
+
+ self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
+ self.SetMarginWidth(1, 25)
+
+ self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
+ self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
+
+ self.SetLexer(stc.STC_LEX_CPP)
+ self.SetKeyWords(0, " ".join(CPP_KEYWORDS))
+
+ self.SetProperty("fold", "1")
+ self.SetProperty("tab.timmy.whinge.level", "1")
+ self.SetMargins(0,0)
+
+ self.SetViewWhiteSpace(False)
+ #self.SetBufferedDraw(False)
+ #self.SetViewEOL(True)
+ #self.SetEOLMode(stc.STC_EOL_CRLF)
+ #self.SetUseAntiAliasing(True)
+
+ self.SetEdgeMode(stc.STC_EDGE_BACKGROUND)
+ self.SetEdgeColumn(78)
+
+ # Setup a margin to hold fold markers
+ #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
+ self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
+ self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
+ self.SetMarginSensitive(2, True)
+ self.SetMarginWidth(2, 12)
+
+ if self.fold_symbols == 0:
+ # Arrow pointing right for contracted folders, arrow pointing down for expanded
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
+
+ elif self.fold_symbols == 1:
+ # Plus for contracted folders, minus for expanded
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
+
+ elif self.fold_symbols == 2:
+ # Like a flattened tree control using circular headers and curved joins
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040")
+
+ elif self.fold_symbols == 3:
+ # Like a flattened tree control using square headers
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080")
+
+
+ self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
+ self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
+
+ # Make some styles, The lexer defines what each style is used for, we
+ # just have to define what each style looks like. This set is adapted from
+ # Scintilla sample property files.
+
+ # Global default styles for all languages
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
+ self.StyleClearAll() # Reset all to be like the default
+
+ # Global default styles for all languages
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
+ self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
+ self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
+ self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
+ self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
+
+ self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060')
+ self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060')
+ self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060')
+ self.StyleSetSpec(stc.STC_C_NUMBER, 'fore:#0076AE')
+ self.StyleSetSpec(stc.STC_C_WORD, 'bold,fore:#800056')
+ self.StyleSetSpec(stc.STC_C_STRING, 'fore:#2a00ff')
+ self.StyleSetSpec(stc.STC_C_PREPROCESSOR, 'bold,fore:#800056')
+ self.StyleSetSpec(stc.STC_C_OPERATOR, 'bold')
+ self.StyleSetSpec(stc.STC_C_STRINGEOL, 'back:#FFD5FF')
+
+ # register some images for use in the AutoComplete box.
+ #self.RegisterImage(1, images.getSmilesBitmap())
+ self.RegisterImage(1,
+ wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16)))
+ self.RegisterImage(2,
+ wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
+ self.RegisterImage(3,
+ wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
+
+ # Indentation size
+ self.SetTabWidth(2)
+ self.SetUseTabs(0)
+
+ self.Controler = controler
+ self.ParentWindow = window
+
+ self.DisableEvents = True
+ self.Name = name
+ self.CurrentAction = None
+
+ self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE)
+
+ self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_CPPEDITOR)
+ self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+ self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_CPPEDITOR)
+
+ def OnModification(self, event):
+ if not self.DisableEvents:
+ mod_type = event.GetModificationType()
+ if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO):
+ if mod_type&wx.stc.STC_MOD_BEFOREINSERT:
+ if self.CurrentAction == None:
+ self.StartBuffering()
+ elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
+ self.Controler.EndBuffering()
+ self.StartBuffering()
+ self.CurrentAction = ("Add", event.GetPosition())
+ wx.CallAfter(self.RefreshModel)
+ elif mod_type&wx.stc.STC_MOD_BEFOREDELETE:
+ if self.CurrentAction == None:
+ self.StartBuffering()
+ elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
+ self.Controler.EndBuffering()
+ self.StartBuffering()
+ self.CurrentAction = ("Delete", event.GetPosition())
+ wx.CallAfter(self.RefreshModel)
+ event.Skip()
+
+ def OnDoDrop(self, event):
+ self.ResetBuffer()
+ wx.CallAfter(self.RefreshModel)
+ event.Skip()
+
+ # Buffer the last model state
+ def RefreshBuffer(self):
+ self.Controler.BufferCFile()
+ if self.ParentWindow is not None:
+ self.ParentWindow.RefreshTitle()
+ self.ParentWindow.RefreshFileMenu()
+ self.ParentWindow.RefreshEditMenu()
+ self.ParentWindow.RefreshPageTitles()
+
+ def StartBuffering(self):
+ self.Controler.StartBuffering()
+ if self.ParentWindow is not None:
+ self.ParentWindow.RefreshTitle()
+ self.ParentWindow.RefreshFileMenu()
+ self.ParentWindow.RefreshEditMenu()
+ self.ParentWindow.RefreshPageTitles()
+
+ def ResetBuffer(self):
+ if self.CurrentAction != None:
+ self.Controler.EndBuffering()
+ self.CurrentAction = None
+
+ def RefreshView(self):
+ self.ResetBuffer()
+ self.DisableEvents = True
+ old_cursor_pos = self.GetCurrentPos()
+ old_text = self.GetText()
+ new_text = self.Controler.GetPartText(self.Name)
+ self.SetText(new_text)
+ new_cursor_pos = GetCursorPos(old_text, new_text)
+ if new_cursor_pos != None:
+ self.GotoPos(new_cursor_pos)
+ else:
+ self.GotoPos(old_cursor_pos)
+ self.ScrollToColumn(0)
+ self.EmptyUndoBuffer()
+ self.DisableEvents = False
+
+ self.Colourise(0, -1)
+
+ def DoGetBestSize(self):
+ return self.ParentWindow.GetPanelBestSize()
+
+ def RefreshModel(self):
+ self.Controler.SetPartText(self.Name, self.GetText())
+
+ def OnKeyPressed(self, event):
+ if self.CallTipActive():
+ self.CallTipCancel()
+ key = event.GetKeyCode()
+
+ if key == 32 and event.ControlDown():
+ pos = self.GetCurrentPos()
+
+ # Tips
+ if event.ShiftDown():
+ pass
+## self.CallTipSetBackground("yellow")
+## self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
+## 'show some suff, maybe parameters..\n\n'
+## 'fubar(param1, param2)')
+ # Code completion
+ else:
+ self.AutoCompSetIgnoreCase(False) # so this needs to match
+
+ # Images are specified with a appended "?type"
+ self.AutoCompShow(0, " ".join([word + "?1" for word in CPP_KEYWORDS]))
+ else:
+ event.Skip()
+
+ def OnKillFocus(self, event):
+ self.AutoCompCancel()
+ event.Skip()
+
+ def OnUpdateUI(self, evt):
+ # check for matching braces
+ braceAtCaret = -1
+ braceOpposite = -1
+ charBefore = None
+ caretPos = self.GetCurrentPos()
+
+ if caretPos > 0:
+ charBefore = self.GetCharAt(caretPos - 1)
+ styleBefore = self.GetStyleAt(caretPos - 1)
+
+ # check before
+ if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos - 1
+
+ # check after
+ if braceAtCaret < 0:
+ charAfter = self.GetCharAt(caretPos)
+ styleAfter = self.GetStyleAt(caretPos)
+
+ if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos
+
+ if braceAtCaret >= 0:
+ braceOpposite = self.BraceMatch(braceAtCaret)
+
+ if braceAtCaret != -1 and braceOpposite == -1:
+ self.BraceBadLight(braceAtCaret)
+ else:
+ self.BraceHighlight(braceAtCaret, braceOpposite)
+ #pt = self.PointFromPosition(braceOpposite)
+ #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
+ #print pt
+ #self.Refresh(False)
+
+
+ def OnMarginClick(self, evt):
+ # fold and unfold as needed
+ if evt.GetMargin() == 2:
+ if evt.GetShift() and evt.GetControl():
+ self.FoldAll()
+ else:
+ lineClicked = self.LineFromPosition(evt.GetPosition())
+
+ if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
+ if evt.GetShift():
+ self.SetFoldExpanded(lineClicked, True)
+ self.Expand(lineClicked, True, True, 1)
+ elif evt.GetControl():
+ if self.GetFoldExpanded(lineClicked):
+ self.SetFoldExpanded(lineClicked, False)
+ self.Expand(lineClicked, False, True, 0)
+ else:
+ self.SetFoldExpanded(lineClicked, True)
+ self.Expand(lineClicked, True, True, 100)
+ else:
+ self.ToggleFold(lineClicked)
+
+
+ def FoldAll(self):
+ lineCount = self.GetLineCount()
+ expanding = True
+
+ # find out if we are folding or unfolding
+ for lineNum in range(lineCount):
+ if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
+ expanding = not self.GetFoldExpanded(lineNum)
+ break
+
+ lineNum = 0
+
+ while lineNum < lineCount:
+ level = self.GetFoldLevel(lineNum)
+ if level & stc.STC_FOLDLEVELHEADERFLAG and \
+ (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+
+ if expanding:
+ self.SetFoldExpanded(lineNum, True)
+ lineNum = self.Expand(lineNum, True)
+ lineNum = lineNum - 1
+ else:
+ lastChild = self.GetLastChild(lineNum, -1)
+ self.SetFoldExpanded(lineNum, False)
+
+ if lastChild > lineNum:
+ self.HideLines(lineNum+1, lastChild)
+
+ lineNum = lineNum + 1
+
+
+
+ def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
+ lastChild = self.GetLastChild(line, level)
+ line = line + 1
+
+ while line <= lastChild:
+ if force:
+ if visLevels > 0:
+ self.ShowLines(line, line)
+ else:
+ self.HideLines(line, line)
+ else:
+ if doExpand:
+ self.ShowLines(line, line)
+
+ if level == -1:
+ level = self.GetFoldLevel(line)
+
+ if level & stc.STC_FOLDLEVELHEADERFLAG:
+ if force:
+ if visLevels > 1:
+ self.SetFoldExpanded(line, True)
+ else:
+ self.SetFoldExpanded(line, False)
+
+ line = self.Expand(line, doExpand, force, visLevels-1)
+
+ else:
+ if doExpand and self.GetFoldExpanded(line):
+ line = self.Expand(line, True, force, visLevels-1)
+ else:
+ line = self.Expand(line, False, force, visLevels-1)
+ else:
+ line = line + 1
+
+ return line
+
+ def Cut(self):
+ self.ResetBuffer()
+ self.DisableEvents = True
+ self.CmdKeyExecute(wx.stc.STC_CMD_CUT)
+ self.DisableEvents = False
+ self.RefreshModel()
+ self.RefreshBuffer()
+
+ def Copy(self):
+ self.CmdKeyExecute(wx.stc.STC_CMD_COPY)
+
+ def Paste(self):
+ self.ResetBuffer()
+ self.DisableEvents = True
+ self.CmdKeyExecute(wx.stc.STC_CMD_PASTE)
+ self.DisableEvents = False
+ self.RefreshModel()
+ self.RefreshBuffer()
+
+
+#-------------------------------------------------------------------------------
+# Helper for VariablesGrid values
+#-------------------------------------------------------------------------------
+
+class VariablesTable(CustomTable):
+
+ def GetValue(self, row, col):
+ if row < self.GetNumberRows():
+ if col == 0:
+ return row + 1
+ else:
+ return str(self.data[row].get(self.GetColLabelValue(col, False), ""))
+
+ def _updateColAttrs(self, grid):
+ """
+ wxGrid -> update the column attributes to add the
+ appropriate renderer given the column name.
+
+ Otherwise default to the default renderer.
+ """
+
+ typelist = None
+ accesslist = None
+ for row in range(self.GetNumberRows()):
+ for col in range(self.GetNumberCols()):
+ editor = None
+ renderer = None
+ colname = self.GetColLabelValue(col, False)
+
+ if colname == "Name":
+ editor = wx.grid.GridCellTextEditor()
+ elif colname == "Class":
+ editor = wx.grid.GridCellChoiceEditor()
+ editor.SetParameters("input,memory,output")
+ elif colname == "Type":
+ pass
+ else:
+ grid.SetReadOnly(row, col, True)
+
+ grid.SetCellEditor(row, col, editor)
+ grid.SetCellRenderer(row, col, renderer)
+
+ grid.SetCellBackgroundColour(row, col, wx.WHITE)
+ self.ResizeRow(grid, row)
+
+
+[ID_VARIABLESEDITOR, ID_VARIABLESEDITORVARIABLESGRID,
+ ID_VARIABLESEDITORADDVARIABLEBUTTON, ID_VARIABLESEDITORDELETEVARIABLEBUTTON,
+ ID_VARIABLESEDITORUPVARIABLEBUTTON, ID_VARIABLESEDITORDOWNVARIABLEBUTTON
+] = [wx.NewId() for _init_ctrls in range(6)]
+
+class VariablesEditor(wx.Panel):
+
+ if wx.VERSION < (2, 6, 0):
+ def Bind(self, event, function, id = None):
+ if id is not None:
+ event(self, id, function)
+ else:
+ event(self, function)
+
+ def _init_coll_MainSizer_Growables(self, parent):
+ parent.AddGrowableCol(0)
+ parent.AddGrowableRow(0)
+
+ def _init_coll_MainSizer_Items(self, parent):
+ parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
+ parent.AddSizer(self.ButtonsSizer, 0, border=0, flag=wx.GROW)
+
+ def _init_coll_ButtonsSizer_Growables(self, parent):
+ parent.AddGrowableCol(0)
+ parent.AddGrowableRow(0)
+
+ def _init_coll_ButtonsSizer_Items(self, parent):
+ parent.AddWindow(self.AddVariableButton, 0, border=0, flag=wx.ALIGN_RIGHT)
+ parent.AddWindow(self.DeleteVariableButton, 0, border=0, flag=0)
+ parent.AddWindow(self.UpVariableButton, 0, border=0, flag=0)
+ parent.AddWindow(self.DownVariableButton, 0, border=0, flag=0)
+
+ def _init_sizers(self):
+ self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=4)
+ self.ButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
+
+ self._init_coll_MainSizer_Growables(self.MainSizer)
+ self._init_coll_MainSizer_Items(self.MainSizer)
+ self._init_coll_ButtonsSizer_Growables(self.ButtonsSizer)
+ self._init_coll_ButtonsSizer_Items(self.ButtonsSizer)
+
+ self.SetSizer(self.MainSizer)
+
+ def _init_ctrls(self, prnt):
+ wx.Panel.__init__(self, id=ID_VARIABLESEDITOR, name='', parent=prnt,
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.VariablesGrid = CustomGrid(id=ID_VARIABLESEDITORVARIABLESGRID,
+ name='VariablesGrid', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(-1, -1), style=wx.VSCROLL)
+ if wx.VERSION >= (2, 5, 0):
+ self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
+ self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
+ self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
+ else:
+ wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange)
+ wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
+ wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown)
+
+ self.AddVariableButton = wx.Button(id=ID_VARIABLESEDITORADDVARIABLEBUTTON, label='Add Variable',
+ name='AddVariableButton', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(122, 32), style=0)
+
+ self.DeleteVariableButton = wx.Button(id=ID_VARIABLESEDITORDELETEVARIABLEBUTTON, label='Delete Variable',
+ name='DeleteVariableButton', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(122, 32), style=0)
+
+ self.UpVariableButton = wx.Button(id=ID_VARIABLESEDITORUPVARIABLEBUTTON, label='^',
+ name='UpVariableButton', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(32, 32), style=0)
+
+ self.DownVariableButton = wx.Button(id=ID_VARIABLESEDITORDOWNVARIABLEBUTTON, label='v',
+ name='DownVariableButton', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(32, 32), style=0)
+
+ self._init_sizers()
+
+ def __init__(self, parent, window, controler):
+ self._init_ctrls(parent)
+
+ self.ParentWindow = window
+ self.Controler = controler
+
+ self.VariablesDefaultValue = {"Name" : "", "Class" : "input", "Type" : ""}
+ self.Table = VariablesTable(self, [], ["#", "Name", "Class", "Type"])
+ self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
+ self.ColSizes = [40, 200, 150, 150]
+ self.VariablesGrid.SetTable(self.Table)
+ self.VariablesGrid.SetButtons({"Add": self.AddVariableButton,
+ "Delete": self.DeleteVariableButton,
+ "Up": self.UpVariableButton,
+ "Down": self.DownVariableButton})
+
+ def _AddVariable(new_row):
+ self.Table.InsertRow(new_row, self.VariablesDefaultValue.copy())
+ self.RefreshModel()
+ self.RefreshView()
+ return new_row
+ setattr(self.VariablesGrid, "_AddRow", _AddVariable)
+
+ def _DeleteVariable(row):
+ self.Table.RemoveRow(row)
+ self.RefreshModel()
+ self.RefreshView()
+ setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
+
+ def _MoveVariable(row, move):
+ new_row = self.Table.MoveRow(row, move)
+ if new_row != row:
+ self.RefreshModel()
+ self.RefreshView()
+ return new_row
+ setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
+
+ self.VariablesGrid.SetRowLabelSize(0)
+ for col in range(self.Table.GetNumberCols()):
+ attr = wx.grid.GridCellAttr()
+ attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
+ self.VariablesGrid.SetColAttr(col, attr)
+ self.VariablesGrid.SetColSize(col, self.ColSizes[col])
+ self.Table.ResetView(self.VariablesGrid)
+
+ def RefreshModel(self):
+ self.Controler.SetVariables(self.Table.GetData())
+ self.RefreshBuffer()
+
+ # Buffer the last model state
+ def RefreshBuffer(self):
+ self.Controler.BufferCFile()
+ self.ParentWindow.RefreshTitle()
+ self.ParentWindow.RefreshFileMenu()
+ self.ParentWindow.RefreshEditMenu()
+ self.ParentWindow.RefreshPageTitles()
+
+ def RefreshView(self):
+ self.Table.SetData(self.Controler.GetVariables())
+ self.Table.ResetView(self.VariablesGrid)
+ self.VariablesGrid.RefreshButtons()
+
+ def DoGetBestSize(self):
+ return self.ParentWindow.GetPanelBestSize()
+
+ def OnVariablesGridCellChange(self, event):
+ self.RefreshModel()
+ wx.CallAfter(self.RefreshView)
+ event.Skip()
+
+ def OnVariablesGridEditorShown(self, event):
+ row, col = event.GetRow(), event.GetCol()
+ if self.Table.GetColLabelValue(col) == "Type":
+ type_menu = wx.Menu(title='')
+ base_menu = wx.Menu(title='')
+ for base_type in self.Controler.GetBaseTypes():
+ new_id = wx.NewId()
+ AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type)
+ self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id)
+ type_menu.AppendMenu(wx.NewId(), "Base Types", base_menu)
+ datatype_menu = wx.Menu(title='')
+ for datatype in self.Controler.GetDataTypes(basetypes=False, only_locatables=True):
+ new_id = wx.NewId()
+ AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
+ self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
+ type_menu.AppendMenu(wx.NewId(), "User Data Types", datatype_menu)
+ rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col))
+
+ self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize())
+ type_menu.Destroy()
+ event.Veto()
+ else:
+ event.Skip()
+
+ def GetVariableTypeFunction(self, base_type):
+ def VariableTypeFunction(event):
+ row = self.VariablesGrid.GetGridCursorRow()
+ self.Table.SetValueByName(row, "Type", base_type)
+ self.Table.ResetView(self.VariablesGrid)
+ self.RefreshModel()
+ self.RefreshView()
+ event.Skip()
+ return VariableTypeFunction
+
+ def OnVariablesGridCellLeftClick(self, event):
+ if event.GetCol() == 0:
+ row = event.GetRow()
+ num = 0
+ if self.Table.GetValueByName(row, "Class") == "input":
+ dir = "%I"
+ for i in xrange(row):
+ if self.Table.GetValueByName(i, "Class") == "input":
+ num += 1
+ elif self.Table.GetValueByName(row, "Class") == "memory":
+ dir = "%M"
+ for i in xrange(row):
+ if self.Table.GetValueByName(i, "Class") == "memory":
+ num += 1
+ else:
+ dir = "%Q"
+ for i in xrange(row):
+ if self.Table.GetValueByName(i, "Class") == "output":
+ num += 1
+ data_type = self.Table.GetValueByName(row, "Type")
+ var_name = self.Table.GetValueByName(row, "Name")
+ base_location = ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation()))
+ location = "%s%s%s.%d"%(dir, self.Controler.GetSizeOfType(data_type), base_location, num)
+ data = wx.TextDataObject(str((location, "location", data_type, var_name, "")))
+ dragSource = wx.DropSource(self.VariablesGrid)
+ dragSource.SetData(data)
+ dragSource.DoDragDrop()
+ event.Skip()
+
+
+#-------------------------------------------------------------------------------
+# SVGUIEditor Main Frame Class
+#-------------------------------------------------------------------------------
+
+CFILE_PARTS = [
+ ("Includes", CppEditor),
+ ("Variables", VariablesEditor),
+ ("Globals", CppEditor),
+ ("Init", CppEditor),
+ ("CleanUp", CppEditor),
+ ("Retrieve", CppEditor),
+ ("Publish", CppEditor),
+]
+
+#----------------------------------------------------------------------
+# different icons for the collapsed/expanded states.
+# Taken from standard Windows XP collapsed/expanded states.
+#----------------------------------------------------------------------
+
+def GetCollapsedIconData():
+ return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
+\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
+\x00\x01\x8eIDAT8\x8d\xa5\x93-n\xe4@\x10\x85?g\x03\n6lh)\xc4\xd2\x12\xc3\x81\
+\xd6\xa2I\x90\x154\xb9\x81\x8f1G\xc8\x11\x16\x86\xcd\xa0\x99F\xb3A\x91\xa1\
+\xc9J&\x96L"5lX\xcc\x0bl\xf7v\xb2\x7fZ\xa5\x98\xebU\xbdz\xf5\\\x9deW\x9f\xf8\
+H\\\xbfO|{y\x9dT\x15P\x04\x01\x01UPUD\x84\xdb/7YZ\x9f\xa5\n\xce\x97aRU\x8a\
+\xdc`\xacA\x00\x04P\xf0!0\xf6\x81\xa0\xf0p\xff9\xfb\x85\xe0|\x19&T)K\x8b\x18\
+\xf9\xa3\xe4\xbe\xf3\x8c^#\xc9\xd5\n\xa8*\xc5?\x9a\x01\x8a\xd2b\r\x1cN\xc3\
+\x14\t\xce\x97a\xb2F0Ks\xd58\xaa\xc6\xc5\xa6\xf7\xdfya\xe7\xbdR\x13M2\xf9\
+\xf9qKQ\x1fi\xf6-\x00~T\xfac\x1dq#\x82,\xe5q\x05\x91D\xba@\xefj\xba1\xf0\xdc\
+zzW\xcff&\xb8,\x89\xa8@Q\xd6\xaaf\xdfRm,\xee\xb1BDxr#\xae\xf5|\xddo\xd6\xe2H\
+\x18\x15\x84\xa0q@]\xe54\x8d\xa3\xedf\x05M\xe3\xd8Uy\xc4\x15\x8d\xf5\xd7\x8b\
+~\x82\x0fh\x0e"\xb0\xad,\xee\xb8c\xbb\x18\xe7\x8e;6\xa5\x89\x04\xde\xff\x1c\
+\x16\xef\xe0p\xfa>\x19\x11\xca\x8d\x8d\xe0\x93\x1b\x01\xd8m\xf3(;x\xa5\xef=\
+\xb7w\xf3\x1d$\x7f\xc1\xe0\xbd\xa7\xeb\xa0(,"Kc\x12\xc1+\xfd\xe8\tI\xee\xed)\
+\xbf\xbcN\xc1{D\x04k\x05#\x12\xfd\xf2a\xde[\x81\x87\xbb\xdf\x9cr\x1a\x87\xd3\
+0)\xba>\x83\xd5\xb97o\xe0\xaf\x04\xff\x13?\x00\xd2\xfb\xa9`z\xac\x80w\x00\
+\x00\x00\x00IEND\xaeB`\x82'
+
+def GetCollapsedIconBitmap():
+ return wx.BitmapFromImage(GetCollapsedIconImage())
+
+def GetCollapsedIconImage():
+ import cStringIO
+ stream = cStringIO.StringIO(GetCollapsedIconData())
+ return wx.ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def GetExpandedIconData():
+ return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
+\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
+\x00\x01\x9fIDAT8\x8d\x95\x93\xa1\x8e\xdc0\x14EO\xb2\xc4\xd0\xd2\x12\xb7(mI\
+\xa4%V\xd1lQT4[4-\x9a\xfe\xc1\xc2|\xc6\xc2~BY\x83:A3E\xd3\xa0*\xa4\xd2\x90H!\
+\x95\x0c\r\r\x1fK\x81g\xb2\x99\x84\xb4\x0fY\xd6\xbb\xc7\xf7>=\'Iz\xc3\xbcv\
+\xfbn\xb8\x9c\x15 \xe7\xf3\xc7\x0fw\xc9\xbc7\x99\x03\x0e\xfbn0\x99F+\x85R\
+\x80RH\x10\x82\x08\xde\x05\x1ef\x90+\xc0\xe1\xd8\ryn\xd0Z-\\A\xb4\xd2\xf7\
+\x9e\xfbwoF\xc8\x088\x1c\xbbae\xb3\xe8y&\x9a\xdf\xf5\xbd\xe7\xfem\x84\xa4\
+\x97\xccYf\x16\x8d\xdb\xb2a]\xfeX\x18\xc9s\xc3\xe1\x18\xe7\x94\x12cb\xcc\xb5\
+\xfa\xb1l8\xf5\x01\xe7\x84\xc7\xb2Y@\xb2\xcc0\x02\xb4\x9a\x88%\xbe\xdc\xb4\
+\x9e\xb6Zs\xaa74\xadg[6\x88<\xb7]\xc6\x14\x1dL\x86\xe6\x83\xa0\x81\xba\xda\
+\x10\x02x/\xd4\xd5\x06\r\x840!\x9c\x1fM\x92\xf4\x86\x9f\xbf\xfe\x0c\xd6\x9ae\
+\xd6u\x8d \xf4\xf5\x165\x9b\x8f\x04\xe1\xc5\xcb\xdb$\x05\x90\xa97@\x04lQas\
+\xcd*7\x14\xdb\x9aY\xcb\xb8\\\xe9E\x10|\xbc\xf2^\xb0E\x85\xc95_\x9f\n\xaa/\
+\x05\x10\x81\xce\xc9\xa8\xf6><G\xd8\xed\xbbA)X\xd9\x0c\x01\x9a\xc6Q\x14\xd9h\
+[\x04\xda\xd6c\xadFkE\xf0\xc2\xab\xd7\xb7\xc9\x08\x00\xf8\xf6\xbd\x1b\x8cQ\
+\xd8|\xb9\x0f\xd3\x9a\x8a\xc7\x08\x00\x9f?\xdd%\xde\x07\xda\x93\xc3{\x19C\
+\x8a\x9c\x03\x0b8\x17\xe8\x9d\xbf\x02.>\x13\xc0n\xff{PJ\xc5\xfdP\x11""<\xbc\
+\xff\x87\xdf\xf8\xbf\xf5\x17FF\xaf\x8f\x8b\xd3\xe6K\x00\x00\x00\x00IEND\xaeB\
+`\x82'
+
+def GetExpandedIconBitmap():
+ return wx.BitmapFromImage(GetExpandedIconImage())
+
+def GetExpandedIconImage():
+ import cStringIO
+ stream = cStringIO.StringIO(GetExpandedIconData())
+ return wx.ImageFromStream(stream)
+
+class FoldPanelCaption(wx.lib.buttons.GenBitmapTextToggleButton):
+
+ def GetBackgroundBrush(self, dc):
+ colBg = self.GetBackgroundColour()
+ brush = wx.Brush(colBg, wx.SOLID)
+ if self.style & wx.BORDER_NONE:
+ myAttr = self.GetDefaultAttributes()
+ parAttr = self.GetParent().GetDefaultAttributes()
+ myDef = colBg == myAttr.colBg
+ parDef = self.GetParent().GetBackgroundColour() == parAttr.colBg
+ if myDef and parDef:
+ if wx.Platform == "__WXMAC__":
+ brush.MacSetTheme(1) # 1 == kThemeBrushDialogBackgroundActive
+ elif wx.Platform == "__WXMSW__":
+ if self.DoEraseBackground(dc):
+ brush = None
+ elif myDef and not parDef:
+ colBg = self.GetParent().GetBackgroundColour()
+ brush = wx.Brush(colBg, wx.SOLID)
+ return brush
+
+ def DrawLabel(self, dc, width, height, dx=0, dy=0):
+ bmp = self.bmpLabel
+ if bmp is not None: # if the bitmap is used
+ if self.bmpDisabled and not self.IsEnabled():
+ bmp = self.bmpDisabled
+ if self.bmpFocus and self.hasFocus:
+ bmp = self.bmpFocus
+ if self.bmpSelected and not self.up:
+ bmp = self.bmpSelected
+ bw,bh = bmp.GetWidth(), bmp.GetHeight()
+ hasMask = bmp.GetMask() is not None
+ else:
+ bw = bh = 0 # no bitmap -> size is zero
+
+ dc.SetFont(self.GetFont())
+ if self.IsEnabled():
+ dc.SetTextForeground(self.GetForegroundColour())
+ else:
+ dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+
+ label = self.GetLabel()
+ tw, th = dc.GetTextExtent(label) # size of text
+
+ if bmp is not None:
+ dc.DrawBitmap(bmp, width - bw - 2, (height-bh)/2, hasMask) # draw bitmap if available
+
+ dc.DrawText(label, 2, (height-th)/2) # draw the text
+
+ dc.SetPen(wx.Pen(self.GetForegroundColour()))
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
+ dc.DrawRectangle(0, 0, width, height)
+
+[ID_CFILEEDITOR, ID_CFILEEDITORMAINSPLITTER,
+ ID_CFILEEDITORCFILETREE, ID_CFILEEDITORPARTSOPENED,
+] = [wx.NewId() for _init_ctrls in range(4)]
+
+class CFileEditor(EditorPanel):
+
+ def _init_Editor(self, prnt):
+ self.Editor = wx.Panel(id=ID_CFILEEDITOR, parent=prnt, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.Panels = {}
+ self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2 * len(CFILE_PARTS) + 1, vgap=0)
+ self.MainSizer.AddGrowableCol(0)
+
+ for idx, (name, panel_class) in enumerate(CFILE_PARTS):
+ button_id = wx.NewId()
+ button = FoldPanelCaption(id=button_id, name='FoldPanelCaption_%s' % name,
+ label=name, bitmap=GetCollapsedIconBitmap(), parent=self.Editor, pos=wx.Point(0, 0),
+ size=wx.Size(0, 20), style=wx.NO_BORDER|wx.ALIGN_LEFT)
+ button.SetBitmapSelected(GetExpandedIconBitmap())
+ button.Bind(wx.EVT_BUTTON, self.GenPanelButtonCallback(name), id=button_id)
+ self.MainSizer.AddWindow(button, 0, border=0, flag=wx.TOP|wx.GROW)
+
+ if panel_class == VariablesEditor:
+ panel = VariablesEditor(self.Editor, self.ParentWindow, self.Controler)
+ else:
+ panel = panel_class(self.Editor, name, self.ParentWindow, self.Controler)
+ self.MainSizer.AddWindow(panel, 0, border=0, flag=wx.BOTTOM|wx.GROW)
+ panel.Hide()
+
+ self.Panels[name] = {"button": button, "panel": panel, "expanded": False, "row": 2 * idx + 1}
+
+ self.Spacer = wx.Panel(self.Editor, -1)
+ self.SpacerExpanded = True
+ self.MainSizer.AddWindow(self.Spacer, 0, border=0, flag=wx.GROW)
+
+ self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS))
+
+ self.Editor.SetSizer(self.MainSizer)
+
+ def __init__(self, parent, controler, window):
+ EditorPanel.__init__(self, parent, "", window, controler)
+
+ img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
+ self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
+
+ def __del__(self):
+ self.Controler.OnCloseEditor(self)
+
+ def GetTitle(self):
+ fullname = self.Controler.CTNFullName()
+ if not self.Controler.CFileIsSaved():
+ return "~%s~" % fullname
+ return fullname
+
+ def GetBufferState(self):
+ return self.Controler.GetBufferState()
+
+ def Undo(self):
+ self.Controler.LoadPrevious()
+ self.RefreshView()
+
+ def Redo(self):
+ self.Controler.LoadNext()
+ self.RefreshView()
+
+ def HasNoModel(self):
+ return False
+
+ def RefreshView(self):
+ for infos in self.Panels.itervalues():
+ infos["panel"].RefreshView()
+
+ def GenPanelButtonCallback(self, name):
+ def PanelButtonCallback(event):
+ self.TogglePanel(name)
+ return PanelButtonCallback
+
+ def ExpandPanel(self, name):
+ infos = self.Panels.get(name, None)
+ if infos is not None and not infos["expanded"]:
+ infos["expanded"] = True
+ infos["button"].SetToggle(True)
+ infos["panel"].Show()
+ self.MainSizer.AddGrowableRow(infos["row"])
+
+ self.RefreshSizerLayout()
+
+ def CollapsePanel(self, name):
+ infos = self.Panels.get(name, None)
+ if infos is not None and infos["expanded"]:
+ infos["expanded"] = False
+ infos["button"].SetToggle(False)
+ infos["panel"].Hide()
+ self.MainSizer.RemoveGrowableRow(infos["row"])
+
+ self.RefreshSizerLayout()
+
+ def TogglePanel(self, name):
+ infos = self.Panels.get(name, None)
+ if infos is not None:
+ infos["expanded"] = not infos["expanded"]
+ infos["button"].SetToggle(infos["expanded"])
+ if infos["expanded"]:
+ infos["panel"].Show()
+ self.MainSizer.AddGrowableRow(infos["row"])
+ else:
+ infos["panel"].Hide()
+ self.MainSizer.RemoveGrowableRow(infos["row"])
+
+ self.RefreshSizerLayout()
+
+ def RefreshSizerLayout(self):
+ expand_spacer = True
+ for infos in self.Panels.itervalues():
+ expand_spacer = expand_spacer and not infos["expanded"]
+
+ if self.SpacerExpanded != expand_spacer:
+ self.SpacerExpanded = expand_spacer
+ if expand_spacer:
+ self.Spacer.Show()
+ self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS))
+ else:
+ self.Spacer.Hide()
+ self.MainSizer.RemoveGrowableRow(2 * len(CFILE_PARTS))
+
+ self.MainSizer.Layout()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/c_ext/README Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,1 @@
+C extension
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/c_ext/__init__.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,1 @@
+from c_ext import *
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/c_ext/c_ext.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,315 @@
+import wx
+import os
+from xml.dom import minidom
+import cPickle
+
+from xmlclass import *
+
+from ConfigTree import ConfigTreeNode, opjimg
+from CFileEditor import CFileEditor
+from PLCControler import PLCControler, UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
+
+CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd"))
+
+TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
+ "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L",
+ "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"}
+
+class _Cfile:
+ XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="CExtension">
+ <xsd:complexType>
+ <xsd:attribute name="CFLAGS" type="xsd:string" use="required"/>
+ <xsd:attribute name="LDFLAGS" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ """
+ EditorType = CFileEditor
+
+ def __init__(self):
+ filepath = self.CFileName()
+
+ self.CFile = CFileClasses["CFile"]()
+ if os.path.isfile(filepath):
+ xmlfile = open(filepath, 'r')
+ tree = minidom.parse(xmlfile)
+ xmlfile.close()
+
+ for child in tree.childNodes:
+ if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "CFile":
+ self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"])
+ self.CreateCFileBuffer(True)
+ else:
+ self.CreateCFileBuffer(False)
+ self.OnCTNSave()
+
+ def CFileName(self):
+ return os.path.join(self.CTNPath(), "cfile.xml")
+
+ def GetBaseTypes(self):
+ return self.GetCTRoot().GetBaseTypes()
+
+ def GetDataTypes(self, basetypes = False, only_locatables = False):
+ return self.GetCTRoot().GetDataTypes(basetypes=basetypes, only_locatables=only_locatables)
+
+ def GetSizeOfType(self, type):
+ return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None)
+
+ def SetVariables(self, variables):
+ self.CFile.variables.setvariable([])
+ for var in variables:
+ variable = CFileClasses["variables_variable"]()
+ variable.setname(var["Name"])
+ variable.settype(var["Type"])
+ variable.setclass(var["Class"])
+ self.CFile.variables.appendvariable(variable)
+
+ def GetVariables(self):
+ datas = []
+ for var in self.CFile.variables.getvariable():
+ datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()})
+ return datas
+
+ def GetVariableLocationTree(self):
+ '''See ConfigTreeNode.GetVariableLocationTree() for a description.'''
+
+ current_location = ".".join(map(str, self.GetCurrentLocation()))
+
+ vars = []
+ input = memory = output = 0
+ for var in self.CFile.variables.getvariable():
+ var_size = self.GetSizeOfType(var.gettype())
+ var_location = ""
+ if var.getclass() == "input":
+ var_class = LOCATION_VAR_INPUT
+ if var_size is not None:
+ var_location = "%%I%s%s.%d"%(var_size, current_location, input)
+ input += 1
+ elif var.getclass() == "memory":
+ var_class = LOCATION_VAR_INPUT
+ if var_size is not None:
+ var_location = "%%M%s%s.%d"%(var_size, current_location, memory)
+ memory += 1
+ else:
+ var_class = LOCATION_VAR_OUTPUT
+ if var_size is not None:
+ var_location = "%%Q%s%s.%d"%(var_size, current_location, output)
+ output += 1
+ vars.append({"name": var.getname(),
+ "type": var_class,
+ "size": var_size,
+ "IEC_type": var.gettype(),
+ "var_name": var.getname(),
+ "location": var_location,
+ "description": "",
+ "children": []})
+
+ return {"name": self.BaseParams.getName(),
+ "type": LOCATION_CONFNODE,
+ "location": self.GetFullIEC_Channel(),
+ "children": vars}
+
+ def SetPartText(self, name, text):
+ if name == "Includes":
+ self.CFile.includes.settext(text)
+ elif name == "Globals":
+ self.CFile.globals.settext(text)
+ elif name == "Init":
+ self.CFile.initFunction.settext(text)
+ elif name == "CleanUp":
+ self.CFile.cleanUpFunction.settext(text)
+ elif name == "Retrieve":
+ self.CFile.retrieveFunction.settext(text)
+ elif name == "Publish":
+ self.CFile.publishFunction.settext(text)
+
+ def GetPartText(self, name):
+ if name == "Includes":
+ return self.CFile.includes.gettext()
+ elif name == "Globals":
+ return self.CFile.globals.gettext()
+ elif name == "Init":
+ return self.CFile.initFunction.gettext()
+ elif name == "CleanUp":
+ return self.CFile.cleanUpFunction.gettext()
+ elif name == "Retrieve":
+ return self.CFile.retrieveFunction.gettext()
+ elif name == "Publish":
+ return self.CFile.publishFunction.gettext()
+ return ""
+
+ ConfNodeMethods = [
+ {"bitmap" : os.path.join("images", "EditCfile"),
+ "name" : _("Edit C File"),
+ "tooltip" : _("Edit C File"),
+ "method" : "_OpenView"},
+ ]
+
+ def CTNTestModified(self):
+ return self.ChangesToSave or not self.CFileIsSaved()
+
+ def OnCTNSave(self):
+ filepath = self.CFileName()
+
+ text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ extras = {"xmlns":"http://www.w3.org/2001/XMLSchema",
+ "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
+ "xsi:schemaLocation" : "cext_xsd.xsd"}
+ text += self.CFile.generateXMLText("CFile", 0, extras)
+
+ xmlfile = open(filepath,"w")
+ xmlfile.write(text.encode("utf-8"))
+ xmlfile.close()
+
+ self.MarkCFileAsSaved()
+ return True
+
+ def CTNGenerate_C(self, buildpath, locations):
+ """
+ Generate C code
+ @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5)
+ @param locations: List of complete variables locations \
+ [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
+ "NAME" : name of the variable (generally "__IW0_1_2" style)
+ "DIR" : direction "Q","I" or "M"
+ "SIZE" : size "X", "B", "W", "D", "L"
+ "LOC" : tuple of interger for IEC location (0,1,2,...)
+ }, ...]
+ @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
+ """
+ current_location = self.GetCurrentLocation()
+ # define a unique name for the generated C file
+ location_str = "_".join(map(str, current_location))
+
+ text = "/* Code generated by Beremiz c_ext confnode */\n\n"
+
+ # Adding includes
+ text += "/* User includes */\n"
+ text += self.CFile.includes.gettext()
+ text += "\n"
+
+ text += """/* Beremiz c_ext confnode includes */
+#ifdef _WINDOWS_H
+ #include "iec_types.h"
+#else
+ #include "iec_std_lib.h"
+#endif
+
+"""
+
+ # Adding variables
+ vars = []
+ inputs = memories = outputs = 0
+ for variable in self.CFile.variables.variable:
+ var = {"Name" : variable.getname(), "Type" : variable.gettype()}
+ if variable.getclass() == "input":
+ var["location"] = "__I%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, inputs)
+ inputs += 1
+ elif variable.getclass() == "memory":
+ var["location"] = "__M%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, memories)
+ memories += 1
+ else:
+ var["location"] = "__Q%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, outputs)
+ outputs += 1
+ vars.append(var)
+ text += "/* Beremiz c_ext confnode user variables definition */\n"
+ base_types = self.GetCTRoot().GetBaseTypes()
+ for var in vars:
+ if var["Type"] in base_types:
+ prefix = "IEC_"
+ else:
+ prefix = ""
+ text += "%s%s beremiz%s;\n"%(prefix, var["Type"], var["location"])
+ text += "%s%s *%s = &beremiz%s;\n"%(prefix, var["Type"], var["location"], var["location"])
+ text += "/* User variables reference */\n"
+ for var in vars:
+ text += "#define %s beremiz%s\n"%(var["Name"], var["location"])
+ text += "\n"
+
+ # Adding user global variables and routines
+ text += "/* User internal user variables and routines */\n"
+ text += self.CFile.globals.gettext()
+
+ # Adding Beremiz confnode functions
+ text += "/* Beremiz confnode functions */\n"
+ text += "int __init_%s(int argc,char **argv)\n{\n"%location_str
+ text += self.CFile.initFunction.gettext()
+ text += " return 0;\n"
+ text += "\n}\n\n"
+
+ text += "void __cleanup_%s(void)\n{\n"%location_str
+ text += self.CFile.cleanUpFunction.gettext()
+ text += "\n}\n\n"
+
+ text += "void __retrieve_%s(void)\n{\n"%location_str
+ text += self.CFile.retrieveFunction.gettext()
+ text += "\n}\n\n"
+
+ text += "void __publish_%s(void)\n{\n"%location_str
+ text += self.CFile.publishFunction.gettext()
+ text += "\n}\n\n"
+
+ Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str)
+ cfile = open(Gen_Cfile_path,'w')
+ cfile.write(text)
+ cfile.close()
+
+ matiec_flags = '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath())
+
+ return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True
+
+
+#-------------------------------------------------------------------------------
+# Current Buffering Management Functions
+#-------------------------------------------------------------------------------
+
+ """
+ Return a copy of the cfile model
+ """
+ def Copy(self, model):
+ return cPickle.loads(cPickle.dumps(model))
+
+ def CreateCFileBuffer(self, saved):
+ self.Buffering = False
+ self.CFileBuffer = UndoBuffer(cPickle.dumps(self.CFile), saved)
+
+ def BufferCFile(self):
+ self.CFileBuffer.Buffering(cPickle.dumps(self.CFile))
+
+ def StartBuffering(self):
+ self.Buffering = True
+
+ def EndBuffering(self):
+ if self.Buffering:
+ self.CFileBuffer.Buffering(cPickle.dumps(self.CFile))
+ self.Buffering = False
+
+ def MarkCFileAsSaved(self):
+ self.EndBuffering()
+ self.CFileBuffer.CurrentSaved()
+
+ def CFileIsSaved(self):
+ return self.CFileBuffer.IsCurrentSaved() and not self.Buffering
+
+ def LoadPrevious(self):
+ self.EndBuffering()
+ self.CFile = cPickle.loads(self.CFileBuffer.Previous())
+
+ def LoadNext(self):
+ self.CFile = cPickle.loads(self.CFileBuffer.Next())
+
+ def GetBufferState(self):
+ first = self.CFileBuffer.IsFirst() and not self.Buffering
+ last = self.CFileBuffer.IsLast()
+ return not first, not last
+
+class RootClass:
+
+ CTNChildrenTypes = [("C_File",_Cfile, "C file")]
+
+ def CTNGenerate_C(self, buildpath, locations):
+ return [],"",False
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/c_ext/cext_xsd.xsd Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<xsd:schema targetNamespace="cext_xsd.xsd"
+ xmlns:cext="cext_xsd.xsd"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xsd:element name="CFile">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="includes" type="cext:CCode"/>
+ <xsd:element name="variables">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="variable" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ <xsd:attribute name="type" type="xsd:string" use="required"/>
+ <xsd:attribute name="class" use="required">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="input"/>
+ <xsd:enumeration value="memory"/>
+ <xsd:enumeration value="output"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="globals" type="cext:CCode"/>
+ <xsd:element name="initFunction" type="cext:CCode"/>
+ <xsd:element name="cleanUpFunction" type="cext:CCode"/>
+ <xsd:element name="retrieveFunction" type="cext:CCode"/>
+ <xsd:element name="publishFunction" type="cext:CCode"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="CCode">
+ <xsd:annotation>
+ <xsd:documentation>Formatted text according to parts of XHTML 1.1</xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:any namespace="http://www.w3.org/1999/xhtml" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+</xsd:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/.cvsignore Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,1 @@
+*.pyc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/NetworkEditor.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,122 @@
+import os, sys
+base_folder = os.path.split(sys.path[0])[0]
+CanFestivalPath = os.path.join(base_folder, "CanFestival-3")
+
+import wx
+
+from subindextable import EditingPanel
+from networkedit import NetworkEditorTemplate
+from controls import EditorPanel
+
+[ID_NETWORKEDITOR,
+] = [wx.NewId() for _init_ctrls in range(1)]
+
+[ID_NETWORKEDITORCONFNODEMENUADDSLAVE, ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE,
+ ID_NETWORKEDITORCONFNODEMENUMASTER,
+] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(3)]
+
+[ID_NETWORKEDITORMASTERMENUNODEINFOS, ID_NETWORKEDITORMASTERMENUDS301PROFILE,
+ ID_NETWORKEDITORMASTERMENUDS302PROFILE, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE,
+ ID_NETWORKEDITORMASTERMENUADD,
+] = [wx.NewId() for _init_coll_MasterMenu_Items in range(5)]
+
+[ID_NETWORKEDITORADDMENUSDOSERVER, ID_NETWORKEDITORADDMENUSDOCLIENT,
+ ID_NETWORKEDITORADDMENUPDOTRANSMIT, ID_NETWORKEDITORADDMENUPDORECEIVE,
+ ID_NETWORKEDITORADDMENUMAPVARIABLE, ID_NETWORKEDITORADDMENUUSERTYPE,
+] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
+
+class NetworkEditor(EditorPanel, NetworkEditorTemplate):
+
+ ID = ID_NETWORKEDITOR
+
+ def _init_coll_MainSizer_Items(self, parent):
+ parent.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW|wx.ALL)
+
+ def _init_coll_MainSizer_Growables(self, parent):
+ parent.AddGrowableCol(0)
+ parent.AddGrowableRow(0)
+
+ def _init_sizers(self):
+ self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0)
+
+ self._init_coll_MainSizer_Items(self.MainSizer)
+ self._init_coll_MainSizer_Growables(self.MainSizer)
+
+ self.Editor.SetSizer(self.MainSizer)
+
+ def _init_Editor(self, prnt):
+ self.Editor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ NetworkEditorTemplate._init_ctrls(self, self.Editor)
+
+ self._init_sizers()
+
+ def __init__(self, parent, controler, window):
+ EditorPanel.__init__(self, parent, "", window, controler)
+ NetworkEditorTemplate.__init__(self, controler, window, False)
+
+ img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
+ self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
+
+ self.RefreshNetworkNodes()
+ self.RefreshBufferState()
+
+ def __del__(self):
+ self.Controler.OnCloseEditor(self)
+
+ def GetConfNodeMenuItems(self):
+ add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_NETWORKEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)),
+ (wx.ITEM_NORMAL, (_('SDO Client'), ID_NETWORKEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)),
+ (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_NETWORKEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)),
+ (wx.ITEM_NORMAL, (_('PDO Receive'), ID_NETWORKEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)),
+ (wx.ITEM_NORMAL, (_('Map Variable'), ID_NETWORKEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)),
+ (wx.ITEM_NORMAL, (_('User Type'), ID_NETWORKEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))]
+
+ profile = self.Manager.GetCurrentProfileName()
+ if profile not in ("None", "DS-301"):
+ other_profile_text = _("%s Profile") % profile
+ add_menu.append((wx.ITEM_SEPARATOR, None))
+ for text, indexes in self.Manager.GetCurrentSpecificMenu():
+ add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text))))
+ else:
+ other_profile_text = _('Other Profile')
+
+ master_menu = [(wx.ITEM_NORMAL, (_('Node infos'), ID_NETWORKEDITORMASTERMENUNODEINFOS, '', self.OnNodeInfosMenu)),
+ (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_NETWORKEDITORMASTERMENUDS301PROFILE, '', self.OnCommunicationMenu)),
+ (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_NETWORKEDITORMASTERMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)),
+ (wx.ITEM_NORMAL, (other_profile_text, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)),
+ (wx.ITEM_SEPARATOR, None),
+ (add_menu, (_('Add'), ID_NETWORKEDITORMASTERMENUADD))]
+
+ return [(wx.ITEM_NORMAL, (_('Add slave'), ID_NETWORKEDITORCONFNODEMENUADDSLAVE, '', self.OnAddSlaveMenu)),
+ (wx.ITEM_NORMAL, (_('Remove slave'), ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, '', self.OnRemoveSlaveMenu)),
+ (wx.ITEM_SEPARATOR, None),
+ (master_menu, (_('Master'), ID_NETWORKEDITORCONFNODEMENUMASTER))]
+
+ def RefreshMainMenu(self):
+ pass
+
+ def RefreshConfNodeMenu(self, confnode_menu):
+ confnode_menu.Enable(ID_NETWORKEDITORCONFNODEMENUMASTER, self.NetworkNodes.GetSelection() == 0)
+
+ def GetTitle(self):
+ fullname = self.Controler.CTNFullName()
+ if not self.Manager.CurrentIsSaved():
+ return "~%s~" % fullname
+ return fullname
+
+ def RefreshView(self):
+ self.RefreshCurrentIndexList()
+
+ def RefreshBufferState(self):
+ NetworkEditorTemplate.RefreshBufferState(self)
+ self.ParentWindow.RefreshTitle()
+ self.ParentWindow.RefreshFileMenu()
+ self.ParentWindow.RefreshEditMenu()
+ self.ParentWindow.RefreshPageTitles()
+
+ def OnNodeSelectedChanged(self, event):
+ NetworkEditorTemplate.OnNodeSelectedChanged(self, event)
+ wx.CallAfter(self.ParentWindow.RefreshConfNodeMenu)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/README Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,1 @@
+CANOpen
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/SlaveEditor.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,83 @@
+import os, sys
+base_folder = os.path.split(sys.path[0])[0]
+CanFestivalPath = os.path.join(base_folder, "CanFestival-3")
+
+import wx
+
+from subindextable import EditingPanel
+from nodeeditor import NodeEditorTemplate
+from controls import EditorPanel
+
+[ID_SLAVEEDITORCONFNODEMENUNODEINFOS, ID_SLAVEEDITORCONFNODEMENUDS301PROFILE,
+ ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE,
+ ID_SLAVEEDITORCONFNODEMENUADD,
+] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(5)]
+
+[ID_SLAVEEDITORADDMENUSDOSERVER, ID_SLAVEEDITORADDMENUSDOCLIENT,
+ ID_SLAVEEDITORADDMENUPDOTRANSMIT, ID_SLAVEEDITORADDMENUPDORECEIVE,
+ ID_SLAVEEDITORADDMENUMAPVARIABLE, ID_SLAVEEDITORADDMENUUSERTYPE,
+] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
+
+class SlaveEditor(EditorPanel, NodeEditorTemplate):
+
+ def _init_Editor(self, prnt):
+ self.Editor = EditingPanel(prnt, self, self.Controler, self.Editable)
+
+ def __init__(self, parent, controler, window, editable=True):
+ self.Editable = editable
+ EditorPanel.__init__(self, parent, "", window, controler)
+ NodeEditorTemplate.__init__(self, controler, window, False)
+
+ img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
+ self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
+
+ def __del__(self):
+ self.Controler.OnCloseEditor(self)
+
+ def GetConfNodeMenuItems(self):
+ if self.Editable:
+ add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_SLAVEEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)),
+ (wx.ITEM_NORMAL, (_('SDO Client'), ID_SLAVEEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)),
+ (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_SLAVEEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)),
+ (wx.ITEM_NORMAL, (_('PDO Receive'), ID_SLAVEEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)),
+ (wx.ITEM_NORMAL, (_('Map Variable'), ID_SLAVEEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)),
+ (wx.ITEM_NORMAL, (_('User Type'), ID_SLAVEEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))]
+
+ profile = self.Controler.GetCurrentProfileName()
+ if profile not in ("None", "DS-301"):
+ other_profile_text = _("%s Profile") % profile
+ add_menu.append((wx.ITEM_SEPARATOR, None))
+ for text, indexes in self.Manager.GetCurrentSpecificMenu():
+ add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text))))
+ else:
+ other_profile_text = _('Other Profile')
+
+ return [(wx.ITEM_NORMAL, (_('Node infos'), ID_SLAVEEDITORCONFNODEMENUNODEINFOS, '', self.OnNodeInfosMenu)),
+ (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_SLAVEEDITORCONFNODEMENUDS301PROFILE, '', self.OnCommunicationMenu)),
+ (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)),
+ (wx.ITEM_NORMAL, (other_profile_text, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)),
+ (wx.ITEM_SEPARATOR, None),
+ (add_menu, (_('Add'), ID_SLAVEEDITORCONFNODEMENUADD))]
+ return []
+
+ def RefreshConfNodeMenu(self, confnode_menu):
+ confnode_menu.Enable(ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, False)
+
+ def GetTitle(self):
+ fullname = self.Controler.CTNFullName()
+ if not self.Controler.CurrentIsSaved():
+ return "~%s~" % fullname
+ return fullname
+
+ def RefreshView(self):
+ self.Editor.RefreshIndexList()
+
+ def RefreshCurrentIndexList(self):
+ self.RefreshView()
+
+ def RefreshBufferState(self):
+ self.ParentWindow.RefreshTitle()
+ self.ParentWindow.RefreshFileMenu()
+ self.ParentWindow.RefreshEditMenu()
+ self.ParentWindow.RefreshPageTitles()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/__init__.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,1 @@
+from canfestival import *
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/canfestival.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,484 @@
+import os, sys
+base_folder = os.path.split(sys.path[0])[0]
+CanFestivalPath = os.path.join(base_folder, "CanFestival-3")
+sys.path.append(os.path.join(CanFestivalPath, "objdictgen"))
+
+from nodelist import NodeList
+from nodemanager import NodeManager
+import config_utils, gen_cfile, eds_utils
+from networkedit import networkedit
+from objdictedit import objdictedit
+import canfestival_config as local_canfestival_config
+from ConfigTree import ConfigTreeNode
+from commondialogs import CreateNodeDialog
+import wx
+
+from SlaveEditor import SlaveEditor
+from NetworkEditor import NetworkEditor
+
+from gnosis.xml.pickle import *
+from gnosis.xml.pickle.util import setParanoia
+setParanoia(0)
+
+if wx.Platform == '__WXMSW__':
+ DEFAULT_SETTINGS = {
+ "CAN_Driver": "can_tcp_win32",
+ "CAN_Device": "127.0.0.1",
+ "CAN_Baudrate": "125K",
+ "Slave_NodeId": 2,
+ "Master_NodeId": 1,
+ }
+else:
+ DEFAULT_SETTINGS = {
+ "CAN_Driver": "../CanFestival-3/drivers/can_socket/libcanfestival_can_socket.so",
+ "CAN_Device": "vcan0",
+ "CAN_Baudrate": "125K",
+ "Slave_NodeId": 2,
+ "Master_NodeId": 1,
+ }
+
+#--------------------------------------------------
+# SLAVE
+#--------------------------------------------------
+
+class _SlaveCTN(NodeManager):
+ XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="CanFestivalSlaveNode">
+ <xsd:complexType>
+ <xsd:attribute name="CAN_Device" type="xsd:string" use="optional" default="%(CAN_Device)s"/>
+ <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
+ <xsd:attribute name="NodeId" type="xsd:string" use="optional" default="%(Slave_NodeId)d"/>
+ <xsd:attribute name="Sync_Align" type="xsd:integer" use="optional" default="0"/>
+ <xsd:attribute name="Sync_Align_Ratio" use="optional" default="50">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="1"/>
+ <xsd:maxInclusive value="99"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ """ % DEFAULT_SETTINGS
+
+ EditorType = SlaveEditor
+
+ def __init__(self):
+ # TODO change netname when name change
+ NodeManager.__init__(self)
+ odfilepath = self.GetSlaveODPath()
+ if(os.path.isfile(odfilepath)):
+ self.OpenFileInCurrent(odfilepath)
+ else:
+ self.FilePath = ""
+ dialog = CreateNodeDialog(None, wx.OK)
+ dialog.Type.Enable(False)
+ dialog.GenSYNC.Enable(False)
+ if dialog.ShowModal() == wx.ID_OK:
+ name, id, nodetype, description = dialog.GetValues()
+ profile, filepath = dialog.GetProfile()
+ NMT = dialog.GetNMTManagement()
+ options = dialog.GetOptions()
+ self.CreateNewNode(name, # Name - will be changed at build time
+ id, # NodeID - will be changed at build time
+ "slave", # Type
+ description,# description
+ profile, # profile
+ filepath, # prfile filepath
+ NMT, # NMT
+ options) # options
+ else:
+ self.CreateNewNode("SlaveNode", # Name - will be changed at build time
+ 0x00, # NodeID - will be changed at build time
+ "slave", # Type
+ "", # description
+ "None", # profile
+ "", # prfile filepath
+ "heartbeat", # NMT
+ []) # options
+ dialog.Destroy()
+ self.OnCTNSave()
+
+ def GetSlaveODPath(self):
+ return os.path.join(self.CTNPath(), 'slave.od')
+
+ def GetCanDevice(self):
+ return self.CanFestivalSlaveNode.getCan_Device()
+
+ def _OpenView(self):
+ ConfigTreeNode._OpenView(self)
+ if self._View is not None:
+ self._View.SetBusId(self.GetCurrentLocation())
+
+ ConfNodeMethods = [
+ {"bitmap" : os.path.join("images", "NetworkEdit"),
+ "name" : "Edit slave",
+ "tooltip" : "Edit CanOpen slave with ObjdictEdit",
+ "method" : "_OpenView"},
+ ]
+
+ def OnCTNClose(self):
+ if self._View:
+ self._View.Close()
+
+ def CTNTestModified(self):
+ return self.ChangesToSave or self.OneFileHasChanged()
+
+ def OnCTNSave(self):
+ return self.SaveCurrentInFile(self.GetSlaveODPath())
+
+ def SetParamsAttribute(self, path, value):
+ result = ConfigTreeNode.SetParamsAttribute(self, path, value)
+
+ # Filter IEC_Channel and Name, that have specific behavior
+ if path == "BaseParams.IEC_Channel" and self._View is not None:
+ self._View.SetBusId(self.GetCurrentLocation())
+
+ return result
+
+ def CTNGenerate_C(self, buildpath, locations):
+ """
+ Generate C code
+ @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5)
+ @param locations: List of complete variables locations \
+ [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
+ "NAME" : name of the variable (generally "__IW0_1_2" style)
+ "DIR" : direction "Q","I" or "M"
+ "SIZE" : size "X", "B", "W", "D", "L"
+ "LOC" : tuple of interger for IEC location (0,1,2,...)
+ }, ...]
+ @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
+ """
+ current_location = self.GetCurrentLocation()
+ # define a unique name for the generated C file
+ prefix = "_".join(map(str, current_location))
+ Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix )
+ # Create a new copy of the model
+ slave = self.GetCurrentNodeCopy()
+ slave.SetNodeName("OD_%s"%prefix)
+ # allow access to local OD from Slave PLC
+ pointers = config_utils.LocalODPointers(locations, current_location, slave)
+ res = gen_cfile.GenerateFile(Gen_OD_path, slave, pointers)
+ if res :
+ raise Exception, res
+ res = eds_utils.GenerateEDSFile(os.path.join(buildpath, "Slave_%s.eds"%prefix), slave)
+ if res :
+ raise Exception, res
+ return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False
+
+ def LoadPrevious(self):
+ self.LoadCurrentPrevious()
+
+ def LoadNext(self):
+ self.LoadCurrentNext()
+
+ def GetBufferState(self):
+ return self.GetCurrentBufferState()
+
+#--------------------------------------------------
+# MASTER
+#--------------------------------------------------
+
+class MiniNodeManager(NodeManager):
+
+ def __init__(self, parent, filepath, fullname):
+ NodeManager.__init__(self)
+
+ self.OpenFileInCurrent(filepath)
+
+ self.Parent = parent
+ self.Fullname = fullname
+
+ def OnCloseEditor(self, view):
+ self.Parent.OnCloseEditor(view)
+
+ def CTNFullName(self):
+ return self.Fullname
+
+ def GetBufferState(self):
+ return self.GetCurrentBufferState()
+
+class _NodeListCTN(NodeList):
+ XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="CanFestivalNode">
+ <xsd:complexType>
+ <xsd:attribute name="CAN_Device" type="xsd:string" use="optional" default="%(CAN_Device)s"/>
+ <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
+ <xsd:attribute name="NodeId" type="xsd:string" use="optional" default="%(Master_NodeId)d"/>
+ <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ """ % DEFAULT_SETTINGS
+
+ EditorType = NetworkEditor
+
+ def __init__(self):
+ manager = NodeManager()
+ NodeList.__init__(self, manager)
+ self.LoadProject(self.CTNPath())
+ self.SetNetworkName(self.BaseParams.getName())
+
+ def GetCanDevice(self):
+ return self.CanFestivalNode.getCan_Device()
+
+ def SetParamsAttribute(self, path, value):
+ result = ConfigTreeNode.SetParamsAttribute(self, path, value)
+
+ # Filter IEC_Channel and Name, that have specific behavior
+ if path == "BaseParams.IEC_Channel" and self._View is not None:
+ self._View.SetBusId(self.GetCurrentLocation())
+ elif path == "BaseParams.Name":
+ self.SetNetworkName(value)
+
+ return result
+
+ def _OpenView(self):
+ ConfigTreeNode._OpenView(self)
+ if self._View is not None:
+ self._View.SetBusId(self.GetCurrentLocation())
+
+ _GeneratedView = None
+ def _ShowMasterGenerated(self):
+ if self._GeneratedView is None:
+ buildpath = self._getBuildPath()
+ # Eventually create build dir
+ if not os.path.exists(buildpath):
+ self.GetCTRoot().logger.write_error(_("Error: No PLC built\n"))
+ return
+
+ masterpath = os.path.join(buildpath, "MasterGenerated.od")
+ if not os.path.exists(masterpath):
+ self.GetCTRoot().logger.write_error(_("Error: No Master generated\n"))
+ return
+
+ app_frame = self.GetCTRoot().AppFrame
+
+ manager = MiniNodeManager(self, masterpath, self.CTNFullName() + ".generated_master")
+ self._GeneratedView = SlaveEditor(app_frame.TabsOpened, manager, app_frame, False)
+
+ app_frame.EditProjectElement(self._GeneratedView, "MasterGenerated")
+
+ def _CloseGenerateView(self):
+ if self._GeneratedView is not None:
+ app_frame = self.GetCTRoot().AppFrame
+ if app_frame is not None:
+ app_frame.DeletePage(self._GeneratedView)
+
+ ConfNodeMethods = [
+ {"bitmap" : os.path.join("images", "NetworkEdit"),
+ "name" : _("Edit network"),
+ "tooltip" : _("Edit CanOpen Network with NetworkEdit"),
+ "method" : "_OpenView"},
+ {"bitmap" : os.path.join("images", "ShowMaster"),
+ "name" : _("Show Master"),
+ "tooltip" : _("Show Master generated by config_utils"),
+ "method" : "_ShowMasterGenerated"}
+ ]
+
+ def OnCloseEditor(self, view):
+ ConfigTreeNode.OnCloseEditor(self, view)
+ if self._GeneratedView == view:
+ self._GeneratedView = None
+
+ def OnCTNClose(self):
+ ConfigTreeNode.OnCTNClose(self)
+ self._CloseGenerateView()
+ return True
+
+ def CTNTestModified(self):
+ return self.ChangesToSave or self.HasChanged()
+
+ def OnCTNSave(self):
+ self.SetRoot(self.CTNPath())
+ return self.SaveProject() is None
+
+ def CTNGenerate_C(self, buildpath, locations):
+ """
+ Generate C code
+ @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5)
+ @param locations: List of complete variables locations \
+ [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
+ "NAME" : name of the variable (generally "__IW0_1_2" style)
+ "DIR" : direction "Q","I" or "M"
+ "SIZE" : size "X", "B", "W", "D", "L"
+ "LOC" : tuple of interger for IEC location (0,1,2,...)
+ }, ...]
+ @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
+ """
+ self._CloseGenerateView()
+ current_location = self.GetCurrentLocation()
+ # define a unique name for the generated C file
+ prefix = "_".join(map(str, current_location))
+ Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix )
+ # Create a new copy of the model with DCF loaded with PDO mappings for desired location
+ try:
+ master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix)
+ except config_utils.PDOmappingException, e:
+ raise Exception, e.message
+ # Do generate C file.
+ res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers)
+ if res :
+ raise Exception, res
+
+ file = open(os.path.join(buildpath, "MasterGenerated.od"), "w")
+ dump(master, file)
+ file.close()
+
+ return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False
+
+ def LoadPrevious(self):
+ self.Manager.LoadCurrentPrevious()
+
+ def LoadNext(self):
+ self.Manager.LoadCurrentNext()
+
+ def GetBufferState(self):
+ return self.Manager.GetCurrentBufferState()
+
+class RootClass:
+ XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="CanFestivalInstance">
+ <xsd:complexType>
+ <xsd:attribute name="CAN_Driver" type="xsd:string" use="optional" default="%(CAN_Driver)s"/>
+ <xsd:attribute name="Debug_mode" type="xsd:boolean" use="optional" default="false"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ """ % DEFAULT_SETTINGS
+
+ CTNChildrenTypes = [("CanOpenNode",_NodeListCTN, "CanOpen Master"),
+ ("CanOpenSlave",_SlaveCTN, "CanOpen Slave")]
+ def GetParamsAttributes(self, path = None):
+ infos = ConfigTreeNode.GetParamsAttributes(self, path = None)
+ for element in infos:
+ if element["name"] == "CanFestivalInstance":
+ for child in element["children"]:
+ if child["name"] == "CAN_Driver":
+ DLL_LIST= getattr(local_canfestival_config,"DLL_LIST",None)
+ if DLL_LIST is not None:
+ child["type"] = DLL_LIST
+ return infos
+
+ def GetCanDriver(self):
+ can_driver = self.CanFestivalInstance.getCAN_Driver()
+ if sys.platform == 'win32':
+ if self.CanFestivalInstance.getDebug_mode() and os.path.isfile(os.path.join("%s"%(can_driver + '_DEBUG.dll'))):
+ can_driver += '_DEBUG.dll'
+ else:
+ can_driver += '.dll'
+ return can_driver
+
+ def CTNGenerate_C(self, buildpath, locations):
+
+ format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())),
+ "candriver" : self.GetCanDriver(),
+ "nodes_includes" : "",
+ "board_decls" : "",
+ "nodes_init" : "",
+ "nodes_open" : "",
+ "nodes_stop" : "",
+ "nodes_close" : "",
+ "nodes_send_sync" : "",
+ "nodes_proceed_sync" : "",
+ "slavebootups" : "",
+ "slavebootup_register" : "",
+ "post_sync" : "",
+ "post_sync_register" : "",
+ }
+ for child in self.IECSortedChildren():
+ childlocstr = "_".join(map(str,child.GetCurrentLocation()))
+ nodename = "OD_%s" % childlocstr
+
+ # Try to get Slave Node
+ child_data = getattr(child, "CanFestivalSlaveNode", None)
+ if child_data is None:
+ # Not a slave -> master
+ child_data = getattr(child, "CanFestivalNode")
+ # Apply sync setting
+ format_dict["nodes_init"] += 'NODE_MASTER_INIT(%s, %s)\n '%(
+ nodename,
+ child_data.getNodeId())
+ if child_data.getSync_TPDOs():
+ format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n '%(nodename)
+ format_dict["nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n '%(nodename)
+
+ # initialize and declare node boot status variables for post_SlaveBootup lookup
+ SlaveIDs = child.GetSlaveIDs()
+ if len(SlaveIDs) == 0:
+ # define post_SlaveBootup lookup functions
+ format_dict["slavebootups"] += (
+ "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n"%(nodename))
+ else:
+ for id in SlaveIDs:
+ format_dict["slavebootups"] += (
+ "int %s_slave_%d_booted = 0;\n"%(nodename, id))
+ # define post_SlaveBootup lookup functions
+ format_dict["slavebootups"] += (
+ "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"%(nodename)+
+ " switch(nodeId){\n")
+ # one case per declared node, mark node as booted
+ for id in SlaveIDs:
+ format_dict["slavebootups"] += (
+ " case %d:\n"%(id)+
+ " %s_slave_%d_booted = 1;\n"%(nodename, id)+
+ " break;\n")
+ format_dict["slavebootups"] += (
+ " default:\n"+
+ " break;\n"+
+ " }\n"+
+ " if( ")
+ # expression to test if all declared nodes booted
+ format_dict["slavebootups"] += " && ".join(["%s_slave_%d_booted"%(nodename, id) for id in SlaveIDs])
+ format_dict["slavebootups"] += " )\n" + (
+ " Master_post_SlaveBootup(d,nodeId);\n"+
+ "}\n")
+ # register previously declared func as post_SlaveBootup callback for that node
+ format_dict["slavebootup_register"] += (
+ "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n"%(nodename,nodename))
+ else:
+ # Slave node
+ align = child_data.getSync_Align()
+ align_ratio=child_data.getSync_Align_Ratio()
+ if align > 0:
+ format_dict["post_sync"] += (
+ "static int %s_CalCount = 0;\n"%(nodename)+
+ "static void %s_post_sync(CO_Data* d){\n"%(nodename)+
+ " if(%s_CalCount < %d){\n"%(nodename, align)+
+ " %s_CalCount++;\n"%(nodename)+
+ " align_tick(-1);\n"+
+ " }else{\n"+
+ " align_tick(%d);\n"%(align_ratio)+
+ " }\n"+
+ "}\n")
+ format_dict["post_sync_register"] += (
+ "%s_Data.post_sync = %s_post_sync;\n"%(nodename,nodename))
+ format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n '%(
+ nodename,
+ child_data.getNodeId())
+
+ # Include generated OD headers
+ format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename)
+ # Declare CAN channels according user filled config
+ format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n'%(
+ nodename,
+ child.GetCanDevice(),
+ child_data.getCAN_Baudrate())
+ format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename)
+ format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename)
+ format_dict["nodes_stop"] += 'NODE_STOP(%s)\n '%(nodename)
+
+ filename = os.path.join(os.path.split(__file__)[0],"cf_runtime.c")
+ cf_main = open(filename).read() % format_dict
+ cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict)
+ f = open(cf_main_path,'w')
+ f.write(cf_main)
+ f.close()
+
+ return [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/cf_runtime.c Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,150 @@
+
+#include "canfestival.h"
+
+/* CanFestival nodes generated OD headers*/
+%(nodes_includes)s
+
+#define BOARD_DECL(nodename, busname, baudrate)\
+ s_BOARD nodename##Board = {busname, baudrate};
+
+/* CAN channels declaration */
+%(board_decls)s
+
+/* Keep track of init level to cleanup correctly */
+static int init_level=0;
+/* Retrieve PLC cycle time */
+extern int common_ticktime__;
+
+/* Called once all NetworkEdit declares slaves have booted*/
+static void Master_post_SlaveBootup(CO_Data* d, UNS8 nodeId)
+{
+ /* Put the master in operational mode */
+ setState(d, Operational);
+
+ /* Ask slave node to go in operational mode */
+ masterSendNMTstateChange (d, 0, NMT_Start_Node);
+}
+
+/* Per master node slavebootup callbacks. Checks that
+ * every node have booted before calling Master_post_SlaveBootup */
+%(slavebootups)s
+
+/* One slave node post_sync callback.
+ * Used to align PLC tick-time on CANopen SYNC
+ */
+%(post_sync)s
+
+#define NODE_FORCE_SYNC(nodename) \
+ /* Artificially force sync state to 1 so that it is not started */\
+ nodename##_Data.CurrentCommunicationState.csSYNC = -1;\
+ /* Force sync period to common_ticktime__ so that other node can read it*/\
+ *nodename##_Data.COB_ID_Sync = 0x40000080;\
+ *nodename##_Data.Sync_Cycle_Period = common_ticktime__ * 1000;
+
+#define NODE_INIT(nodename, nodeid) \
+ /* Defining the node Id */\
+ setNodeId(&nodename##_Data, nodeid);\
+ /* init */\
+ setState(&nodename##_Data, Initialisation);
+
+#define NODE_MASTER_INIT(nodename, nodeid) \
+ NODE_FORCE_SYNC(nodename) \
+ NODE_INIT(nodename, nodeid)
+
+#define NODE_SLAVE_INIT(nodename, nodeid) \
+ NODE_INIT(nodename, nodeid)
+
+void InitNodes(CO_Data* d, UNS32 id)
+{
+ %(slavebootup_register)s
+ %(post_sync_register)s
+ %(nodes_init)s
+}
+
+#define NODE_STOP(nodename) \
+ if(init_level-- > 0)\
+ {\
+ masterSendNMTstateChange(&nodename##_Data, 0, NMT_Reset_Node);\
+ setState(&nodename##_Data, Stopped);\
+ }
+
+void Exit(CO_Data* d, UNS32 id)
+{
+ %(nodes_stop)s
+}
+
+#define NODE_CLOSE(nodename) \
+ if(init_level_c-- > 0)\
+ {\
+ canClose(&nodename##_Data);\
+ }
+
+void __cleanup_%(locstr)s(void)
+{
+ // Stop timer thread
+ if(init_level-- > 0){
+ int init_level_c = init_level;
+ StopTimerLoop(&Exit);
+ %(nodes_close)s
+ }
+
+ TimerCleanup();
+}
+
+#ifndef stderr
+#define fprintf(...)
+#define fflush(...)
+#endif
+
+#define NODE_OPEN(nodename)\
+ if(!canOpen(&nodename##Board,&nodename##_Data)){\
+ fprintf(stderr,"Cannot open CAN intefrace %%s at speed %%s\n for CANopen node \"" #nodename "\"",nodename##Board.busname, nodename##Board.baudrate);\
+ fflush(stderr);\
+ return -1;\
+ }\
+ init_level++;
+
+/*************************** INIT *****************************************/
+int __init_%(locstr)s(int argc,char **argv)
+{
+#ifndef NOT_USE_DYNAMIC_LOADING
+ if( !LoadCanDriver("%(candriver)s") ){
+ fprintf(stderr, "Cannot load CAN interface library for CanFestival (%(candriver)s)\n");\
+ fflush(stderr);\
+ return -1;\
+ }
+#endif
+
+ TimerInit();
+
+ %(nodes_open)s
+
+ // Start timer thread
+ StartTimerLoop(&InitNodes);
+ init_level++;
+ return 0;
+}
+
+#define NODE_SEND_SYNC(nodename)\
+ sendSYNCMessage(&nodename##_Data);
+
+void __retrieve_%(locstr)s(void)
+{
+ /* Locks the stack, so that no changes occurs while PLC access variables
+ * TODO : implement buffers to avoid such a big lock
+ * */
+ EnterMutex();
+ /* Send Sync */
+ %(nodes_send_sync)s
+}
+
+#define NODE_PROCEED_SYNC(nodename)\
+ proceedSYNC(&nodename##_Data);
+
+void __publish_%(locstr)s(void)
+{
+ /* Process sync event */
+ %(nodes_proceed_sync)s
+ LeaveMutex();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/config_utils.py Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,737 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#This file is part of Beremiz, a Integrated Development Environment for
+#programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
+#
+#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
+#
+#See COPYING file for copyrights details.
+#
+#This library is free software; you can redistribute it and/or
+#modify it under the terms of the GNU General Public
+#License as published by the Free Software Foundation; either
+#version 2.1 of the License, or (at your option) any later version.
+#
+#This library is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+#General Public License for more details.
+#
+#You should have received a copy of the GNU General Public
+#License along with this library; if not, write to the Free Software
+#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from types import *
+
+# Translation between IEC types and Can Open types
+IECToCOType = {"BOOL":0x01, "SINT":0x02, "INT":0x03,"DINT":0x04,"LINT":0x10,
+ "USINT":0x05,"UINT":0x06,"UDINT":0x07,"ULINT":0x1B,"REAL":0x08,
+ "LREAL":0x11,"STRING":0x09,"BYTE":0x05,"WORD":0x06,"DWORD":0x07,
+ "LWORD":0x1B,"WSTRING":0x0B}
+
+# Constants for PDO types
+RPDO = 1
+TPDO = 2
+
+SlavePDOType = {"I" : TPDO, "Q" : RPDO}
+InvertPDOType = {RPDO : TPDO, TPDO : RPDO}
+PDOTypeBaseIndex = {RPDO : 0x1400, TPDO : 0x1800}
+PDOTypeBaseCobId = {RPDO : 0x200, TPDO : 0x180}
+
+VariableIncrement = 0x100
+VariableStartIndex = {TPDO : 0x2000, RPDO : 0x4000}
+VariableDirText = {TPDO : "__I", RPDO : "__Q"}
+VariableTypeOffset = dict(zip(["","X","B","W","D","L"], range(6)))
+
+TrashVariables = [(1, 0x01), (8, 0x05), (16, 0x06), (32, 0x07), (64, 0x1B)]
+
+#-------------------------------------------------------------------------------
+# Specific exception for PDO mapping errors
+#-------------------------------------------------------------------------------
+
+class PDOmappingException(Exception):
+ pass
+
+
+def LE_to_BE(value, size):
+ """
+ Convert Little Endian to Big Endian
+ @param value: value expressed in integer
+ @param size: number of bytes generated
+ @return: a string containing the value converted
+ """
+
+ data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
+ list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
+ list_car.reverse()
+ return "".join([chr(int(car, 16)) for car in list_car])
+
+
+def GetNodePDOIndexes(node, type, parameters = False):
+ """
+ Find the PDO indexes of a node
+ @param node: node
+ @param type: type of PDO searched (RPDO or TPDO or both)
+ @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
+ @return: a list of indexes found
+ """
+
+ indexes = []
+ if type & RPDO:
+ indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF])
+ if type & TPDO:
+ indexes.extend([idx for idx in node.GetIndexes() if 0x1800 <= idx <= 0x19FF])
+ if not parameters:
+ return [idx + 0x200 for idx in indexes]
+ else:
+ return indexes
+
+
+def SearchNodePDOMapping(loc_infos, node):
+ """
+ Find the PDO indexes of a node
+ @param node: node
+ @param type: type of PDO searched (RPDO or TPDO or both)
+ @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
+ @return: a list of indexes found
+ """
+
+ model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8)
+
+ for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]):
+ values = node.GetEntry(PDOidx)
+ if values != None:
+ for subindex, mapping in enumerate(values):
+ if subindex != 0 and mapping & 0xFFFFFF00 == model:
+ return PDOidx, subindex
+ return None
+
+
+def GeneratePDOMappingDCF(idx, cobid, transmittype, pdomapping):
+ """
+ Build concise DCF value for configuring a PDO
+ @param idx: index of PDO parameters
+ @param cobid: PDO generated COB ID
+ @param transmittype : PDO transmit type
+ @param pdomapping: list of PDO mappings
+ @return: a tuple of value and number of parameters to add to DCF
+ """
+
+ # Create entry for RPDO or TPDO parameters and Disable PDO
+ dcfdata = LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x80000000 + cobid, 4)
+ # Set Transmit type synchrone
+ dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x02, 1) + LE_to_BE(0x01, 4) + LE_to_BE(transmittype, 1)
+ # Re-Enable PDO
+ # ---- INDEX ----- --- SUBINDEX ---- ----- SIZE ------ ------ DATA ------
+ dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(cobid, 4)
+ nbparams = 3
+ if len(pdomapping) > 0:
+ dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(0x00, 1) + LE_to_BE(0x01, 4) + LE_to_BE(len(pdomapping), 1)
+ nbparams += 1
+ # Map Variables
+ for subindex, (name, loc_infos) in enumerate(pdomapping):
+ value = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) + loc_infos["size"]
+ dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(subindex + 1, 1) + LE_to_BE(0x04, 4) + LE_to_BE(value, 4)
+ nbparams += 1
+ return dcfdata, nbparams
+
+class ConciseDCFGenerator:
+
+ def __init__(self, nodelist, nodename):
+ # Dictionary of location informations classed by name
+ self.IECLocations = {}
+ # Dictionary of location that have not been mapped yet
+ self.LocationsNotMapped = {}
+ # Dictionary of location informations classed by name
+ self.MasterMapping = {}
+ # List of COB IDs available
+ self.ListCobIDAvailable = range(0x180, 0x580)
+ # Dictionary of mapping value where unexpected variables are stored
+ self.TrashVariables = {}
+ # Dictionary of pointed variables
+ self.PointedVariables = {}
+
+ self.NodeList = nodelist
+ self.Manager = self.NodeList.Manager
+ self.MasterNode = self.Manager.GetCurrentNodeCopy()
+ self.MasterNode.SetNodeName(nodename)
+ self.PrepareMasterNode()
+
+ def GetPointedVariables(self):
+ return self.PointedVariables
+
+ def RemoveUsedNodeCobId(self, node):
+ """
+ Remove all PDO COB ID used by the given node from the list of available COB ID
+ @param node: node
+ @return: a tuple of number of RPDO and TPDO for the node
+ """
+
+ # Get list of all node TPDO and RPDO indexes
+ nodeRpdoIndexes = GetNodePDOIndexes(node, RPDO, True)
+ nodeTpdoIndexes = GetNodePDOIndexes(node, TPDO, True)
+
+ # Mark all the COB ID of the node already mapped PDO as not available
+ for PdoIdx in nodeRpdoIndexes + nodeTpdoIndexes:
+ pdo_cobid = node.GetEntry(PdoIdx, 0x01)
+ # Extract COB ID, if PDO isn't active
+ if pdo_cobid > 0x600 :
+ pdo_cobid -= 0x80000000
+ # Remove COB ID from the list of available COB ID
+ if pdo_cobid in self.ListCobIDAvailable:
+ self.ListCobIDAvailable.remove(pdo_cobid)
+
+ return len(nodeRpdoIndexes), len(nodeTpdoIndexes)
+
+
+ def PrepareMasterNode(self):
+ """
+ Add mandatory entries for DCF generation into MasterNode.
+ """
+
+ # Adding DCF entry into Master node
+ if not self.MasterNode.IsEntry(0x1F22):
+ self.MasterNode.AddEntry(0x1F22, 1, "")
+ self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode)
+
+ # Adding trash mappable variables for unused mapped datas
+ idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID()
+ # Add an entry for storing unexpected all variable
+ self.Manager.AddMapVariableToCurrent(idxTrashVariables, self.MasterNode.GetNodeName()+"_trashvariables", 3, len(TrashVariables), self.MasterNode)
+ for subidx, (size, typeidx) in enumerate(TrashVariables):
+ # Add a subentry for storing unexpected variable of this size
+ self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode)
+ self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode)
+ # Store the mapping value for this entry
+ self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size
+
+ RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode)
+
+ # Store the indexes of the first RPDO and TPDO available for MasterNode
+ self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber}
+
+ # Prepare MasterNode with all nodelist slaves
+ for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()):
+ node = nodeinfos["Node"]
+ node.SetNodeID(nodeid)
+
+ RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node)
+
+ # Get Slave's default SDO server parameters
+ RSDO_cobid = node.GetEntry(0x1200,0x01)
+ if not RSDO_cobid:
+ RSDO_cobid = 0x600 + nodeid
+ TSDO_cobid = node.GetEntry(0x1200,0x02)
+ if not TSDO_cobid:
+ TSDO_cobid = 0x580 + nodeid
+
+ # Configure Master's SDO parameters entries
+ self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode)
+ self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid)
+ self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid)
+ self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid)
+
+
+ def GetMasterNode(self):
+ """
+ Return MasterNode.
+ """
+ return self.MasterNode
+
+ def AddParamsToDCF(self, nodeid, data, nbparams):
+ """
+ Add entry to DCF, for the requested nodeID
+ @param nodeid: id of the slave (int)
+ @param data: data to add to slave DCF (string)
+ @param nbparams: number of params added to slave DCF (int)
+ """
+ # Get current DCF for slave
+ nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid)
+
+ # Extract data and number of params in current DCF
+ if nodeDCF != None and nodeDCF != '':
+ tmpnbparams = [i for i in nodeDCF[:4]]
+ tmpnbparams.reverse()
+ nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
+ data = nodeDCF[4:] + data
+
+ # Build new DCF
+ dcf = LE_to_BE(nbparams, 0x04) + data
+ # Set new DCF for slave
+ self.MasterNode.SetEntry(0x1F22, nodeid, dcf)
+
+ def GetEmptyPDO(self, nodeid, pdotype, start_index=None):
+ """
+ Search a not configured PDO for a slave
+ @param node: the slave node object
+ @param pdotype: type of PDO to generated (RPDO or TPDO)
+ @param start_index: Index where search must start (default: None)
+ @return tuple of PDO index, COB ID and number of subindex defined
+ """
+ # If no start_index defined, start with PDOtype base index
+ if start_index is None:
+ index = PDOTypeBaseIndex[pdotype]
+ else:
+ index = start_index
+
+ # Search for all PDO possible index until find a configurable PDO
+ # starting from start_index
+ while index < PDOTypeBaseIndex[pdotype] + 0x200:
+ values = self.NodeList.GetSlaveNodeEntry(nodeid, index + 0x200)
+ if values != None and values[0] > 0:
+ # Check that all subindex upper than 0 equal 0 => configurable PDO
+ if reduce(lambda x, y: x and y, map(lambda x: x == 0, values[1:]), True):
+ cobid = self.NodeList.GetSlaveNodeEntry(nodeid, index, 1)
+ # If no COB ID defined in PDO, generate a new one (not used)
+ if cobid == 0:
+ if len(self.ListCobIDAvailable) == 0:
+ return None
+ # Calculate COB ID from standard values
+ if index < PDOTypeBaseIndex[pdotype] + 4:
+ cobid = PDOTypeBaseCobId[pdotype] + 0x100 * (index - PDOTypeBaseIndex[pdotype]) + nodeid
+ if cobid not in self.ListCobIDAvailable:
+ cobid = self.ListCobIDAvailable.pop(0)
+ return index, cobid, values[0]
+ index += 1
+ return None
+
+ def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs):
+ """
+ Record a new mapping request for a slave, and add related slave config to the DCF
+ @param nodeid: id of the slave (int)
+ @param pdotype: type of PDO to generated (RPDO or TPDO)
+ @param pdomapping: list od variables to map with PDO
+ """
+ # Add an entry to MasterMapping
+ self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype],
+ "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]}
+
+ # Return the data to add to DCF
+ if sync_TPDOs:
+ return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping)
+ else:
+ return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping)
+ return 0, ""
+
+ def GenerateDCF(self, locations, current_location, sync_TPDOs):
+ """
+ Generate Concise DCF of MasterNode for the locations list given
+ @param locations: list of locations to be mapped
+ @param current_location: tuple of the located prefixes not to be considered
+ @param sync_TPDOs: indicate if TPDO must be synchronous
+ """
+
+ #-------------------------------------------------------------------------------
+ # Verify that locations correspond to real slave variables
+ #-------------------------------------------------------------------------------
+
+ # Get list of locations check if exists and mappables -> put them in IECLocations
+ for location in locations:
+ COlocationtype = IECToCOType[location["IEC_TYPE"]]
+ name = location["NAME"]
+ if name in self.IECLocations:
+ if self.IECLocations[name]["type"] != COlocationtype:
+ raise PDOmappingException, _("Type conflict for location \"%s\"") % name
+ else:
+ # Get only the part of the location that concern this node
+ loc = location["LOC"][len(current_location):]
+ # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
+ if len(loc) not in (2, 3, 4):
+ raise PDOmappingException, _("Bad location size : %s") % str(loc)
+ elif len(loc) == 2:
+ continue
+
+ direction = location["DIR"]
+
+ sizelocation = location["SIZE"]
+
+ # Extract and check nodeid
+ nodeid, index, subindex = loc[:3]
+
+ # Check Id is in slave node list
+ if nodeid not in self.NodeList.SlaveNodes.keys():
+ raise PDOmappingException, _("Non existing node ID : %d (variable %s)") % (nodeid,name)
+
+ # Get the model for this node (made from EDS)
+ node = self.NodeList.SlaveNodes[nodeid]["Node"]
+
+ # Extract and check index and subindex
+ if not node.IsEntry(index, subindex):
+ raise PDOmappingException, _("No such index/subindex (%x,%x) in ID : %d (variable %s)") % (index,subindex,nodeid,name)
+
+ # Get the entry info
+ subentry_infos = node.GetSubentryInfos(index, subindex)
+
+ # If a PDO mappable
+ if subentry_infos and subentry_infos["pdo"]:
+ if sizelocation == "X" and len(loc) > 3:
+ numbit = loc[3]
+ elif sizelocation != "X" and len(loc) > 3:
+ raise PDOmappingException, _("Cannot set bit offset for non bool '%s' variable (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex)
+ else:
+ numbit = None
+
+ if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype:
+ raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name)
+
+ typeinfos = node.GetEntryInfos(COlocationtype)
+ self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction],
+ "nodeid": nodeid, "index": index,"subindex": subindex,
+ "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation}
+ else:
+ raise PDOmappingException, _("Not PDO mappable variable : '%s' (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex)
+
+ #-------------------------------------------------------------------------------
+ # Search for locations already mapped
+ #-------------------------------------------------------------------------------
+
+ for name, locationinfos in self.IECLocations.items():
+ node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"]
+
+ # Search if slave has a PDO mapping this locations
+ result = SearchNodePDOMapping(locationinfos, node)
+ if result != None:
+ index, subindex = result
+ # Get COB ID of the PDO
+ cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1)
+
+ # Add PDO to MasterMapping
+ if cobid not in self.MasterMapping.keys():
+ # Verify that PDO transmit type is conform to sync_TPDOs
+ transmittype = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2)
+ if sync_TPDOs and transmittype != 0x01 or transmittype != 0xFF:
+ if sync_TPDOs:
+ # Change TransmitType to SYNCHRONE
+ data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0x01, [])
+ else:
+ # Change TransmitType to ASYCHRONE
+ data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, [])
+
+ # Add entry to slave dcf to change transmit type of
+ self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams)
+
+ mapping = [None]
+ values = node.GetEntry(index)
+ # Store the size of each entry mapped in PDO
+ for value in values[1:]:
+ if value != 0:
+ mapping.append(value % 0x100)
+ self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping}
+
+ # Indicate that this PDO entry must be saved
+ if locationinfos["bit"] is not None:
+ if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType):
+ self.MasterMapping[cobid]["mapping"][subindex] = [1] * self.MasterMapping[cobid]["mapping"][subindex]
+ if locationinfos["bit"] < len(self.MasterMapping[cobid]["mapping"][subindex]):
+ self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name)
+ else:
+ self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name)
+
+ else:
+ # Add location to those that haven't been mapped yet
+ if locationinfos["nodeid"] not in self.LocationsNotMapped.keys():
+ self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []}
+ self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos))
+
+ #-------------------------------------------------------------------------------
+ # Build concise DCF for the others locations
+ #-------------------------------------------------------------------------------
+
+ for nodeid, locations in self.LocationsNotMapped.items():
+ node = self.NodeList.SlaveNodes[nodeid]["Node"]
+
+ # Initialize number of params and data to add to node DCF
+ nbparams = 0
+ dataparams = ""
+
+ # Generate the best PDO mapping for each type of PDO
+ for pdotype in (TPDO, RPDO):
+ if len(locations[pdotype]) > 0:
+ pdosize = 0
+ pdomapping = []
+ result = self.GetEmptyPDO(nodeid, pdotype)
+ if result is None:
+ raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid
+ pdoindex, pdocobid, pdonbparams = result
+ for name, loc_infos in locations[pdotype]:
+ pdosize += loc_infos["size"]
+ # If pdo's size > 64 bits
+ if pdosize > 64 or len(pdomapping) >= pdonbparams:
+ # Generate a new PDO Mapping
+ data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs)
+ dataparams += data
+ nbparams += nbaddedparams
+ pdosize = loc_infos["size"]
+ pdomapping = [(name, loc_infos)]
+ result = self.GetEmptyPDO(nodeid, pdotype, pdoindex + 1)
+ if result is None:
+ raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid
+ pdoindex, pdocobid, pdonbparams = result
+ else:
+ pdomapping.append((name, loc_infos))
+ # If there isn't locations yet but there is still a PDO to generate
+ if len(pdomapping) > 0:
+ # Generate a new PDO Mapping
+ data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs)
+ dataparams += data
+ nbparams += nbaddedparams
+
+ # Add number of params and data to node DCF
+ self.AddParamsToDCF(nodeid, dataparams, nbparams)
+
+ #-------------------------------------------------------------------------------
+ # Master Node Configuration
+ #-------------------------------------------------------------------------------
+
+ # Generate Master's Configuration from informations stored in MasterMapping
+ for cobid, pdo_infos in self.MasterMapping.items():
+ # Get next PDO index in MasterNode for this PDO type
+ current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]]
+
+ # Search if there is already a PDO in MasterNode with this cob id
+ for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True):
+ if self.MasterNode.GetEntry(idx, 1) == cobid:
+ current_idx = idx
+
+ # Add a PDO to MasterNode if not PDO have been found
+ if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]:
+ addinglist = [current_idx, current_idx + 0x200]
+ self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode)
+ self.MasterNode.SetEntry(current_idx, 0x01, cobid)
+
+ # Increment the number of PDO for this PDO type
+ self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1
+
+ # Change the transmit type of the PDO
+ if sync_TPDOs:
+ self.MasterNode.SetEntry(current_idx, 0x02, 0x01)
+ else:
+ self.MasterNode.SetEntry(current_idx, 0x02, 0xFF)
+
+ mapping = []
+ for item in pdo_infos["mapping"]:
+ if isinstance(item, ListType):
+ mapping.extend(item)
+ else:
+ mapping.append(item)
+
+ # Add some subentries to PDO mapping if there is not enough
+ if len(mapping) > 1:
+ self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(mapping) - 1, self.MasterNode)
+
+ # Generate MasterNode's PDO mapping
+ for subindex, variable in enumerate(mapping):
+ if subindex == 0:
+ continue
+ new_index = False
+
+ if isinstance(variable, (IntType, LongType)):
+ # If variable is an integer then variable is unexpected
+ self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable])
+ else:
+ typeidx, varname = variable
+ variable_infos = self.IECLocations[varname]
+
+ # Calculate base index for storing variable
+ mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \
+ VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \
+ variable_infos["nodeid"]
+
+ # Generate entry name
+ indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]],
+ variable_infos["sizelocation"],
+ '_'.join(map(str,current_location)),
+ variable_infos["nodeid"])
+
+ # Search for an entry that has an empty subindex
+ while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
+ # Entry doesn't exist
+ if not self.MasterNode.IsEntry(mapvariableidx):
+ # Add entry to MasterNode
+ self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode)
+ new_index = True
+ nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
+ else:
+ # Get Number of subentries already defined
+ nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
+ # if entry is full, go to next entry possible or stop now
+ if nbsubentries == 0xFF:
+ mapvariableidx += 8 * VariableIncrement
+ else:
+ break
+
+ # Verify that a not full entry has been found
+ if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
+ # Generate subentry name
+ if variable_infos["bit"] != None:
+ subindexname = "%(index)d_%(subindex)d_%(bit)d"%variable_infos
+ else:
+ subindexname = "%(index)d_%(subindex)d"%variable_infos
+ # If entry have just been created, no subentry have to be added
+ if not new_index:
+ self.Manager.AddSubentriesToCurrent(mapvariableidx, 1, self.MasterNode)
+ nbsubentries += 1
+ # Add informations to the new subentry created
+ self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname})
+ self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx})
+
+ # Set value of the PDO mapping
+ typeinfos = self.Manager.GetEntryInfos(typeidx)
+ if typeinfos != None:
+ value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"]
+ self.MasterNode.SetEntry(current_idx + 0x200, subindex, value)
+
+ # Add variable to pointed variables
+ self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s"%(indexname, subindexname)
+
+def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename):
+ """
+ Fills a CanFestival network editor model, with DCF with requested PDO mappings.
+ @param locations: List of complete variables locations \
+ [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
+ "NAME" : name of the variable (generally "__IW0_1_2" style)
+ "DIR" : direction "Q","I" or "M"
+ "SIZE" : size "X", "B", "W", "D", "L"
+ "LOC" : tuple of interger for IEC location (0,1,2,...)
+ }, ...]
+ @param nodelist: CanFestival network editor model
+ @return: a modified copy of the given CanFestival network editor model
+ """
+
+ dcfgenerator = ConciseDCFGenerator(nodelist, nodename)
+ dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs)
+ masternode,pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables()
+ # allow access to local OD from Master PLC
+ pointers.update(LocalODPointers(locations, current_location, masternode))
+ return masternode,pointers
+
+def LocalODPointers(locations, current_location, slave):
+ IECLocations = {}
+ pointers = {}
+ for location in locations:
+ COlocationtype = IECToCOType[location["IEC_TYPE"]]
+ name = location["NAME"]
+ if name in IECLocations:
+ if IECLocations[name] != COlocationtype:
+ raise PDOmappingException, _("Type conflict for location \"%s\"") % name
+ else:
+ # Get only the part of the location that concern this node
+ loc = location["LOC"][len(current_location):]
+ # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
+ if len(loc) not in (2, 3, 4):
+ raise PDOmappingException, _("Bad location size : %s") % str(loc)
+ elif len(loc) != 2:
+ continue
+
+ # Extract and check nodeid
+ index, subindex = loc[:2]
+
+ # Extract and check index and subindex
+ if not slave.IsEntry(index, subindex):
+ raise PDOmappingException, _("No such index/subindex (%x,%x) (variable %s)") % (index, subindex, name)
+
+ # Get the entry info
+ subentry_infos = slave.GetSubentryInfos(index, subindex)
+ if subentry_infos["type"] != COlocationtype:
+ raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name)
+
+ IECLocations[name] = COlocationtype
+ pointers[(index, subindex)] = name
+ return pointers
+
+if __name__ == "__main__":
+ import os, sys, getopt
+
+ def usage():
+ print """
+Usage of config_utils.py test :
+
+ %s [options]
+
+Options:
+ --help (-h)
+ Displays help informations for config_utils
+
+ --reset (-r)
+ Reset the reference result of config_utils test.
+ Use with caution. Be sure that config_utils
+ is currently working properly.
+"""%sys.argv[0]
+
+ # Boolean that indicate if reference result must be redefined
+ reset = False
+
+ # Extract command options
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hr", ["help","reset"])
+ except getopt.GetoptError:
+ # print help information and exit:
+ usage()
+ sys.exit(2)
+
+ # Test each option
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif o in ("-r", "--reset"):
+ reset = True
+
+ # Extract workspace base folder
+ base_folder = sys.path[0]
+ for i in xrange(3):
+ base_folder = os.path.split(base_folder)[0]
+ # Add CanFestival folder to search pathes
+ sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
+
+ from nodemanager import *
+ from nodelist import *
+
+ # Open the test nodelist contained into test_config folder
+ manager = NodeManager()
+ nodelist = NodeList(manager)
+ result = nodelist.LoadProject("test_config")
+
+ # List of locations, we try to map for test
+ locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)},
+ {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)},
+ {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_3","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,3)},
+ {"IEC_TYPE":"INT","NAME":"__QW0_1_64_25617_2","DIR":"Q","SIZE":"W","LOC":(0,1,64,25617,1)},
+ {"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24578_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24578,1)},
+ {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_1","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,1)},
+ {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_2","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,2)},
+ {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)},
+ {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)},
+ {"IEC_TYPE":"UDINT","NAME":"__ID0_1_4096_0","DIR":"I","SIZE":"D","LOC":(0,1,4096,0)}]
+
+ # Generate MasterNode configuration
+ try:
+ masternode, pointedvariables = GenerateConciseDCF(locations, (0, 1), nodelist, True, "TestNode")
+ except ValueError, message:
+ print "%s\nTest Failed!"%message
+ sys.exit()
+
+ import pprint
+ # Get Text corresponding to MasterNode
+ result_node = masternode.PrintString()
+ result_vars = pprint.pformat(pointedvariables)
+ result = result_node + "\n********POINTERS*********\n" + result_vars + "\n"
+
+ # If reset has been choosen
+ if reset:
+ # Write Text into reference result file
+ testfile = open("test_config/result.txt", "w")
+ testfile.write(result)
+ testfile.close()
+
+ print "Reset Successful!"
+ else:
+ import os
+
+ testfile = open("test_config/result_tmp.txt", "w")
+ testfile.write(result)
+ testfile.close()
+
+ os.system("diff test_config/result.txt test_config/result_tmp.txt")
+ os.remove("test_config/result_tmp.txt")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/test_config/eds/PEAK MicroMod.eds Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,1289 @@
+[FileInfo]
+CreatedBy=ESAcademy
+ModifiedBy=ESAcademy
+Description=PEAK MicroMod CANopenIA Generic
+CreationTime=09:41PM
+CreationDate=05-05-2003
+ModificationTime=05:05PM
+ModificationDate=03-23-2005
+FileName=C:\CANopenCT\Tests\PEAK MicroMod.eds
+FileVersion=1
+FileRevision=1
+EDSVersion=4
+
+[DeviceInfo]
+VendorName=PEAK System Technik
+VendorNumber=0x00000175
+ProductName=PEAK MicroMod CANopenIA Generic
+ProductNumber=0x00100000
+RevisionNumber=0x00010001
+OrderCode=na
+BaudRate_10=0
+BaudRate_20=0
+BaudRate_50=1
+BaudRate_125=1
+BaudRate_250=1
+BaudRate_500=1
+BaudRate_800=1
+BaudRate_1000=1
+SimpleBootUpMaster=0
+SimpleBootUpSlave=1
+Granularity=0
+DynamicChannelsSupported=0
+CompactPDO=0
+GroupMessaging=0
+NrOfRXPDO=4
+NrOfTXPDO=4
+LSS_Supported=0
+
+[DummyUsage]
+Dummy0001=0
+Dummy0002=0
+Dummy0003=0
+Dummy0004=0
+Dummy0005=1
+Dummy0006=1
+Dummy0007=1
+
+[Comments]
+Lines=0
+
+[MandatoryObjects]
+SupportedObjects=3
+1=0x1000
+2=0x1001
+3=0x1018
+
+[1000]
+ParameterName=Device Type
+ObjectType=0x7
+DataType=0x0007
+AccessType=ro
+DefaultValue=0x000F0191
+PDOMapping=0
+
+[1001]
+ParameterName=Error Register
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=0
+PDOMapping=0
+
+[1018]
+ParameterName=Identity Object
+ObjectType=0x9
+SubNumber=4
+
+[1018sub0]
+ParameterName=number of entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=3
+PDOMapping=0
+
+[1018sub1]
+ParameterName=Vendor ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=ro
+DefaultValue=0x00000175
+PDOMapping=0
+
+[1018sub2]
+ParameterName=Product Code
+ObjectType=0x7
+DataType=0x0007
+AccessType=ro
+DefaultValue=0x00100000
+PDOMapping=0
+
+[1018sub3]
+ParameterName=Revision number
+ObjectType=0x7
+DataType=0x0007
+AccessType=ro
+DefaultValue=0x00010001
+PDOMapping=0
+
+[OptionalObjects]
+SupportedObjects=41
+1=0x1002
+2=0x1005
+3=0x1008
+4=0x1009
+5=0x100A
+6=0x100C
+7=0x100D
+8=0x1010
+9=0x1011
+10=0x1016
+11=0x1017
+12=0x1020
+13=0x1400
+14=0x1401
+15=0x1402
+16=0x1403
+17=0x1600
+18=0x1601
+19=0x1602
+20=0x1603
+21=0x1800
+22=0x1801
+23=0x1802
+24=0x1803
+25=0x1A00
+26=0x1A01
+27=0x1A02
+28=0x1A03
+29=0x1F50
+30=0x6000
+31=0x6002
+32=0x6200
+33=0x6202
+34=0x6206
+35=0x6207
+36=0x6401
+37=0x6411
+38=0x6423
+39=0x6426
+40=0x6443
+41=0x6444
+
+[1002]
+ParameterName=PEAK Status Register
+ObjectType=0x7
+DataType=0x0007
+AccessType=ro
+PDOMapping=0
+
+[1005]
+ParameterName=COB-ID SYNC
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x00000080
+PDOMapping=0
+
+[1008]
+ParameterName=Manufacturer Device Name
+ObjectType=0x7
+DataType=0x0009
+AccessType=const
+PDOMapping=0
+
+[1009]
+ParameterName=Manufacturer Hardware Version
+ObjectType=0x7
+DataType=0x0009
+AccessType=const
+PDOMapping=0
+
+[100a]
+ParameterName=Manufacturer Software Version
+ObjectType=0x7
+DataType=0x0009
+AccessType=const
+PDOMapping=0
+
+[100c]
+ParameterName=Guard Time
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[100d]
+ParameterName=Life Time Factor
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0x00
+PDOMapping=0
+
+[1010]
+ParameterName=Store Parameter Field
+ObjectType=0x8
+SubNumber=2
+
+[1010sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[1010sub1]
+ParameterName=Save all Parameters
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+PDOMapping=0
+
+[1011]
+ParameterName=Restore Default Parameters
+ObjectType=0x8
+SubNumber=2
+
+[1011sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[1011sub1]
+ParameterName=Restore all Default Parameters
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+PDOMapping=0
+
+[1016]
+ParameterName=Consumer Heartbeat Time
+ObjectType=0x8
+SubNumber=4
+
+[1016sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=3
+PDOMapping=0
+LowLimit=0x1
+
+[1016sub1]
+ParameterName=Consumer Heartbeat Time
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1016sub2]
+ParameterName=Consumer Heartbeat Time
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1016sub3]
+ParameterName=Consumer Heartbeat Time
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1017]
+ParameterName=Producer Heartbeat Time
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1020]
+ParameterName=Verify Configuration
+ObjectType=0x8
+SubNumber=3
+
+[1020sub0]
+ParameterName=Number of entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=2
+PDOMapping=0
+
+[1020sub1]
+ParameterName=Configuration date
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+PDOMapping=0
+
+[1020sub2]
+ParameterName=Configuration time
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+PDOMapping=0
+
+[1400]
+ParameterName=Receive PDO Communication Parameter
+ObjectType=0x9
+SubNumber=3
+
+[1400sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=2
+PDOMapping=0
+
+[1400sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x200
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1400sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1401]
+ParameterName=Receive PDO Communication Parameter
+ObjectType=0x9
+SubNumber=3
+
+[1401sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=2
+PDOMapping=0
+
+[1401sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x300
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1401sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1402]
+ParameterName=Receive PDO Communication Parameter
+ObjectType=0x9
+SubNumber=3
+
+[1402sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=2
+PDOMapping=0
+LowLimit=0x02
+HighLimit=0x05
+
+[1402sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x80000400
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1402sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1403]
+ParameterName=Receive PDO Communication Parameter
+ObjectType=0x9
+SubNumber=3
+
+[1403sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=2
+PDOMapping=0
+LowLimit=0x02
+HighLimit=0x05
+
+[1403sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x80000500
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1403sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1600]
+ParameterName=Receive PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=2
+
+[1600sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=1
+PDOMapping=0
+
+[1600sub1]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x62000108
+PDOMapping=0
+
+[1601]
+ParameterName=Receive PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=5
+
+[1601sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=4
+PDOMapping=0
+
+[1601sub1]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64110110
+PDOMapping=0
+
+[1601sub2]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64110210
+PDOMapping=0
+
+[1601sub3]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64110310
+PDOMapping=0
+
+[1601sub4]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64110410
+PDOMapping=0
+
+[1602]
+ParameterName=Receive PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=1
+
+[1602sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1603]
+ParameterName=Receive PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=1
+
+[1603sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1800]
+ParameterName=Transmit PDO Communication Parameter
+ObjectType=0x9
+SubNumber=5
+
+[1800sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=5
+PDOMapping=0
+LowLimit=0x02
+HighLimit=0x05
+
+[1800sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x180
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1800sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1800sub3]
+ParameterName=Inhibit Time
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0x0000
+PDOMapping=0
+
+[1800sub5]
+ParameterName=Event Timer
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1801]
+ParameterName=Transmit PDO Communication Parameter
+ObjectType=0x9
+SubNumber=5
+
+[1801sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=5
+PDOMapping=0
+LowLimit=0x02
+HighLimit=0x05
+
+[1801sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x280
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1801sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1801sub3]
+ParameterName=Inhibit Time
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0x0000
+PDOMapping=0
+
+[1801sub5]
+ParameterName=Event Timer
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1802]
+ParameterName=Transmit PDO Communication Parameter
+ObjectType=0x9
+SubNumber=5
+
+[1802sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=5
+PDOMapping=0
+LowLimit=0x02
+HighLimit=0x05
+
+[1802sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x380
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1802sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1802sub3]
+ParameterName=Inhibit Time
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0x0000
+PDOMapping=0
+
+[1802sub5]
+ParameterName=Event Timer
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1803]
+ParameterName=Transmit PDO Communication Parameter
+ObjectType=0x9
+SubNumber=5
+
+[1803sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=5
+PDOMapping=0
+LowLimit=0x02
+HighLimit=0x05
+
+[1803sub1]
+ParameterName=COB-ID
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=$NODEID+0x80000480
+PDOMapping=0
+LowLimit=0x00000001
+HighLimit=0xFFFFFFFF
+
+[1803sub2]
+ParameterName=Transmission Type
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=255
+PDOMapping=0
+
+[1803sub3]
+ParameterName=Inhibit Time
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0x0000
+PDOMapping=0
+
+[1803sub5]
+ParameterName=Event Timer
+ObjectType=0x7
+DataType=0x0006
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1a00]
+ParameterName=Transmit PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=2
+
+[1a00sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=1
+PDOMapping=0
+
+[1a00sub1]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x60000108
+PDOMapping=0
+
+[1a01]
+ParameterName=Transmit PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=5
+
+[1a01sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=4
+PDOMapping=0
+
+[1a01sub1]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010110
+PDOMapping=0
+
+[1a01sub2]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010210
+PDOMapping=0
+
+[1a01sub3]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010310
+PDOMapping=0
+
+[1a01sub4]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010410
+PDOMapping=0
+
+[1a02]
+ParameterName=Transmit PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=5
+
+[1a02sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=4
+PDOMapping=0
+
+[1a02sub1]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010510
+PDOMapping=0
+
+[1a02sub2]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010610
+PDOMapping=0
+
+[1a02sub3]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010710
+PDOMapping=0
+
+[1a02sub4]
+ParameterName=PDO Mapping Entry
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0x64010810
+PDOMapping=0
+
+[1a03]
+ParameterName=Transmit PDO Mapping Parameter
+ObjectType=0x9
+SubNumber=1
+
+[1a03sub0]
+ParameterName=Number of Entries
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[1f50]
+ParameterName=Download Program Data
+ObjectType=0x8
+SubNumber=2
+
+[1f50sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=3
+PDOMapping=0
+
+[1f50sub3]
+ParameterName=Download Program Data - HW Settings
+ObjectType=0x7
+DataType=0x000F
+AccessType=rw
+PDOMapping=0
+
+[6000]
+ParameterName=Read Digital Input 8-bit
+ObjectType=0x8
+SubNumber=2
+
+[6000sub0]
+ParameterName=Number of Elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[6000sub1]
+ParameterName=DigInput8_1
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+PDOMapping=1
+
+[6002]
+ParameterName=Polarity Digital Input
+ObjectType=0x8
+SubNumber=2
+
+[6002sub0]
+ParameterName=Number of Elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[6002sub1]
+ParameterName=Polarity8_1
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6200]
+ParameterName=Write Digital Output 8-bit
+ObjectType=0x8
+SubNumber=2
+
+[6200sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[6200sub1]
+ParameterName=DigOutput8_1
+ObjectType=0x7
+DataType=0x0005
+AccessType=rww
+PDOMapping=1
+
+[6202]
+ParameterName=Polarity Digital Output
+ObjectType=0x8
+SubNumber=2
+
+[6202sub0]
+ParameterName=Number of Elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[6202sub1]
+ParameterName=Polarity8_1
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6206]
+ParameterName=Error Mode Digital Output
+ObjectType=0x8
+SubNumber=2
+
+[6206sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[6206sub1]
+ParameterName=Error Mode 1
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6207]
+ParameterName=Error Value Digital Output
+ObjectType=0x8
+SubNumber=2
+
+[6207sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=1
+PDOMapping=0
+
+[6207sub1]
+ParameterName=Error Value 1
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6401]
+ParameterName=Read Analog Input 16-bit
+ObjectType=0x8
+SubNumber=9
+
+[6401sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=8
+PDOMapping=0
+
+[6401sub1]
+ParameterName=AnalogInput16_1
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6401sub2]
+ParameterName=AnalogInput16_2
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6401sub3]
+ParameterName=AnalogInput16_3
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6401sub4]
+ParameterName=AnalogInput16_4
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6401sub5]
+ParameterName=AnalogInput16_5
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6401sub6]
+ParameterName=AnalogInput16_6
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6401sub7]
+ParameterName=AnalogInput16_7
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6401sub8]
+ParameterName=AnalogInput16_8
+ObjectType=0x7
+DataType=0x0003
+AccessType=ro
+PDOMapping=1
+
+[6411]
+ParameterName=Write Analog Output 16-bit
+ObjectType=0x8
+SubNumber=5
+
+[6411sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=4
+PDOMapping=0
+
+[6411sub1]
+ParameterName=AnalogOutput16_1
+ObjectType=0x7
+DataType=0x0003
+AccessType=rww
+PDOMapping=1
+
+[6411sub2]
+ParameterName=AnalogOutput16_2
+ObjectType=0x7
+DataType=0x0003
+AccessType=rww
+PDOMapping=1
+
+[6411sub3]
+ParameterName=AnalogOutput16_3
+ObjectType=0x7
+DataType=0x0003
+AccessType=rww
+PDOMapping=1
+
+[6411sub4]
+ParameterName=AnalogOutput16_4
+ObjectType=0x7
+DataType=0x0003
+AccessType=rww
+PDOMapping=1
+
+[6423]
+ParameterName=Analog Input Global Interrupt
+ObjectType=0x7
+DataType=0x0001
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426]
+ParameterName=Analog Input Interrupt Delta
+ObjectType=0x8
+SubNumber=9
+
+[6426sub0]
+ParameterName=NrOfObjects
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=8
+PDOMapping=0
+
+[6426sub1]
+ParameterName=Analog Input Delta 1
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426sub2]
+ParameterName=Analog Input Delta 2
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426sub3]
+ParameterName=Analog Input Delta 3
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426sub4]
+ParameterName=Analog Input Delta 4
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426sub5]
+ParameterName=Analog Input Delta 5
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426sub6]
+ParameterName=Analog Input Delta 6
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426sub7]
+ParameterName=Analog Input Delta 7
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6426sub8]
+ParameterName=Analog Input Delta 8
+ObjectType=0x7
+DataType=0x0007
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6443]
+ParameterName=Error Mode Analog Output
+ObjectType=0x8
+SubNumber=5
+
+[6443sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=4
+PDOMapping=0
+
+[6443sub1]
+ParameterName=Error Mode 1
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6443sub2]
+ParameterName=Error Mode 2
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6443sub3]
+ParameterName=Error Mode 3
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6443sub4]
+ParameterName=Error Mode 4
+ObjectType=0x7
+DataType=0x0005
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6444]
+ParameterName=Error Value Analog Output
+ObjectType=0x8
+SubNumber=5
+
+[6444sub0]
+ParameterName=Number of elements
+ObjectType=0x7
+DataType=0x0005
+AccessType=ro
+DefaultValue=4
+PDOMapping=0
+
+[6444sub1]
+ParameterName=Error Value 1
+ObjectType=0x7
+DataType=0x0004
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6444sub2]
+ParameterName=Error Value 2
+ObjectType=0x7
+DataType=0x0004
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6444sub3]
+ParameterName=Error Value 3
+ObjectType=0x7
+DataType=0x0004
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[6444sub4]
+ParameterName=Error Value 4
+ObjectType=0x7
+DataType=0x0004
+AccessType=rw
+DefaultValue=0
+PDOMapping=0
+
+[ManufacturerObjects]
+SupportedObjects=0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/test_config/master.od Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,314 @@
+<?xml version="1.0"?>
+<!DOCTYPE PyObject SYSTEM "PyObjects.dtd">
+<PyObject module="node" class="Node" id="148584620">
+<attr name="Profile" type="dict" id="148589396" >
+</attr>
+<attr name="Description" type="string" value="" />
+<attr name="Dictionary" type="dict" id="148592132" >
+ <entry>
+ <key type="numeric" value="4096" />
+ <val type="numeric" value="302" />
+ </entry>
+ <entry>
+ <key type="numeric" value="4097" />
+ <val type="numeric" value="0" />
+ </entry>
+ <entry>
+ <key type="numeric" value="6144" />
+ <val type="list" id="148585004" >
+ <item type="string" value="{True:"$NODEID+0x%X80"%(base+1),False:0x80000000}[base<4]" />
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ </val>
+ </entry>
+ <entry>
+ <key type="numeric" value="5120" />
+ <val type="list" id="148586060" >
+ <item type="numeric" value="448" />
+ <item type="numeric" value="1" />
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ </val>
+ </entry>
+ <entry>
+ <key type="numeric" value="4101" />
+ <val type="numeric" value="1073741952" />
+ </entry>
+ <entry>
+ <key type="numeric" value="4102" />
+ <val type="numeric" value="50000" />
+ </entry>
+ <entry>
+ <key type="numeric" value="8192" />
+ <val type="numeric" value="0" />
+ </entry>
+ <entry>
+ <key type="numeric" value="6656" />
+ <val type="list" id="148585228" >
+ <item type="numeric" value="268501000" />
+ </val>
+ </entry>
+ <entry>
+ <key type="numeric" value="5632" />
+ <val type="list" id="148585036" >
+ <item type="numeric" value="536870920" />
+ </val>
+ </entry>
+ <entry>
+ <key type="numeric" value="4120" />
+ <val type="list" id="148585292" >
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ <item type="numeric" value="0" />
+ </val>
+ </entry>
+ <entry>
+ <key type="numeric" value="4118" />
+ <val type="list" id="148585100" >
+ <item type="numeric" value="4195804" />
+ </val>
+ </entry>
+</attr>
+<attr name="SpecificMenu" type="list" id="148584044" >
+</attr>
+<attr name="ParamsDictionary" type="dict" id="148592268" >
+</attr>
+<attr name="UserMapping" type="dict" id="148592404" >
+ <entry>
+ <key type="numeric" value="8192" />
+ <val type="dict" id="148592540" >
+ <entry>
+ <key type="string" value="need" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="values" />
+ <val type="list" id="148585868" >
+ <item type="dict" id="148592676" >
+ <entry>
+ <key type="string" value="access" />
+ <val type="string" value="rw" />
+ </entry>
+ <entry>
+ <key type="string" value="pdo" />
+ <val type="True" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="type" />
+ <val type="numeric" value="5" />
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string">Read Inputs</val>
+ </entry>
+ </item>
+ </val>
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string">Read Inputs</val>
+ </entry>
+ <entry>
+ <key type="string" value="struct" />
+ <val type="numeric" value="1" />
+ </entry>
+ </val>
+ </entry>
+</attr>
+<attr name="DS302" type="dict" id="148592812" >
+ <entry>
+ <key type="numeric" value="7968" />
+ <val type="dict" id="148592948" >
+ <entry>
+ <key type="string" value="need" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="values" />
+ <val type="list" id="148584684" >
+ <item type="dict" id="148593084" >
+ <entry>
+ <key type="string" value="access" />
+ <val type="string" value="ro" />
+ </entry>
+ <entry>
+ <key type="string" value="pdo" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="type" />
+ <val type="numeric" value="5" />
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Number of Entries" />
+ </entry>
+ </item>
+ <item type="dict" id="148593220" >
+ <entry>
+ <key type="string" value="access" />
+ <val type="string" value="rw" />
+ </entry>
+ <entry>
+ <key type="string" value="pdo" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="type" />
+ <val type="numeric" value="15" />
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Store DCF for node %d[(sub)]" />
+ </entry>
+ <entry>
+ <key type="string" value="nbmax" />
+ <val type="numeric" value="127" />
+ </entry>
+ </item>
+ </val>
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Store DCF" />
+ </entry>
+ <entry>
+ <key type="string" value="struct" />
+ <val type="numeric" value="7" />
+ </entry>
+ </val>
+ </entry>
+ <entry>
+ <key type="numeric" value="7969" />
+ <val type="dict" id="148593356" >
+ <entry>
+ <key type="string" value="need" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="values" />
+ <val type="list" id="148585516" >
+ <item type="dict" id="148593492" >
+ <entry>
+ <key type="string" value="access" />
+ <val type="string" value="ro" />
+ </entry>
+ <entry>
+ <key type="string" value="pdo" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="type" />
+ <val type="numeric" value="5" />
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Number of Entries" />
+ </entry>
+ </item>
+ <item type="dict" id="148593628" >
+ <entry>
+ <key type="string" value="access" />
+ <val type="string" value="rw" />
+ </entry>
+ <entry>
+ <key type="string" value="pdo" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="type" />
+ <val type="numeric" value="2" />
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Storage Format for Node %d[(sub)]" />
+ </entry>
+ <entry>
+ <key type="string" value="nbmax" />
+ <val type="numeric" value="127" />
+ </entry>
+ </item>
+ </val>
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Storage Format" />
+ </entry>
+ <entry>
+ <key type="string" value="struct" />
+ <val type="numeric" value="7" />
+ </entry>
+ </val>
+ </entry>
+ <entry>
+ <key type="numeric" value="7970" />
+ <val type="dict" id="148593764" >
+ <entry>
+ <key type="string" value="need" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="values" />
+ <val type="list" id="148594956" >
+ <item type="dict" id="148593900" >
+ <entry>
+ <key type="string" value="access" />
+ <val type="string" value="ro" />
+ </entry>
+ <entry>
+ <key type="string" value="pdo" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="type" />
+ <val type="numeric" value="5" />
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Number of Entries" />
+ </entry>
+ </item>
+ <item type="dict" id="148594036" >
+ <entry>
+ <key type="string" value="access" />
+ <val type="string" value="rw" />
+ </entry>
+ <entry>
+ <key type="string" value="pdo" />
+ <val type="False" value="" />
+ </entry>
+ <entry>
+ <key type="string" value="type" />
+ <val type="numeric" value="15" />
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Concise DCF for Node %d[(sub)]" />
+ </entry>
+ <entry>
+ <key type="string" value="nbmax" />
+ <val type="numeric" value="127" />
+ </entry>
+ </item>
+ </val>
+ </entry>
+ <entry>
+ <key type="string" value="name" />
+ <val type="string" value="Concise DCF" />
+ </entry>
+ <entry>
+ <key type="string" value="struct" />
+ <val type="numeric" value="7" />
+ </entry>
+ </val>
+ </entry>
+</attr>
+<attr name="ProfileName" type="string" value="None" />
+<attr name="Type" type="string">master</attr>
+<attr name="ID" type="numeric" value="0" />
+<attr name="Name" type="string">TestMaster</attr>
+</PyObject>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/test_config/nodelist.cpj Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,7 @@
+[TOPOLOGY]
+NetName=None
+Nodes=0x01
+Node64Present=0x01
+Node64Name=micromod
+Node64DCFName=PEAK MicroMod.eds
+EDSBaseName=eds
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/canfestival/test_config/result.txt Tue May 08 17:08:45 2012 +0200
@@ -0,0 +1,257 @@
+1000 (Device Type): 12E
+1001 (Error Register): 0
+1005 (SYNC COB ID): 40000080
+1006 (Communication / Cycle Period): C350
+1016 (Consumer Heartbeat Time):
+1016 01 (Consumer Heartbeat Time): 4005DC
+1018 (Identity):
+1018 01 (Vendor ID): 0
+1018 02 (Product Code): 0
+1018 03 (Revision Number): 0
+1018 04 (Serial Number): 0
+1280 (Client SDO 1 Parameter):
+1280 01 (COB ID Client to Server (Transmit SDO)): 640
+1280 02 (COB ID Server to Client (Receive SDO)): 5C0
+1280 03 (Node ID of the SDO Server): 40
+1400 (Receive PDO 1 Parameter):
+1400 01 (COB ID used by PDO): 1C0
+1400 02 (Transmission Type): 1
+1400 03 (Inhibit Time): 0
+1400 04 (Compatibility Entry): 0
+1400 05 (Event Timer): 0
+1401 (Receive PDO 2 Parameter):
+1401 01 (COB ID used by PDO): 2C0
+1401 02 (Transmission Type): 1
+1401 03 (Inhibit Time): 0
+1401 04 (Compatibility Entry): 0
+1401 05 (Event Timer): 0
+1402 (Receive PDO 3 Parameter):
+1402 01 (COB ID used by PDO): 182
+1402 02 (Transmission Type): 1
+1402 03 (Inhibit Time): 0
+1402 04 (Compatibility Entry): 0
+1402 05 (Event Timer): 0
+1403 (Receive PDO 4 Parameter):
+1403 01 (COB ID used by PDO): 183
+1403 02 (Transmission Type): 1
+1403 03 (Inhibit Time): 0
+1403 04 (Compatibility Entry): 0
+1403 05 (Event Timer): 0
+1404 (Receive PDO 5 Parameter):
+1404 01 (COB ID used by PDO): 181
+1404 02 (Transmission Type): 1
+1404 03 (Inhibit Time): 0
+1404 04 (Compatibility Entry): 0
+1404 05 (Event Timer): 0
+1600 (Receive PDO 1 Mapping):
+1600 01 (PDO 1 Mapping for an application object 1): 22400108
+1600 02 (PDO 1 Mapping for an application object 2): 0
+1601 (Receive PDO 2 Mapping):
+1601 01 (PDO 2 Mapping for an application object 1): 20000310
+1601 02 (PDO 2 Mapping for an application object 2): 23400110
+1601 03 (PDO 2 Mapping for an application object 3): 23400210
+1601 04 (PDO 2 Mapping for an application object 4): 20000310
+1602 (Receive PDO 3 Mapping):
+1602 01 (PDO 3 Mapping for an application object 1): 24400120
+1602 02 (PDO 3 Mapping for an application object 2): 24400220
+1603 (Receive PDO 4 Mapping):
+1603 01 (PDO 4 Mapping for an application object 1): 24400320
+1604 (Receive PDO 5 Mapping):
+1604 01 (PDO 5 Mapping for an application object 1): 22400208
+1604 02 (PDO 5 Mapping for an application object 2): 24400420
+1800 (Transmit PDO 1 Parameter):
+1800 01 (COB ID used by PDO): {True:"$NODEID+0x%X80"%(base+1),False:0x80000000}[base<4]
+1800 02 (Transmission Type): 0
+1800 03 (Inhibit Time): 0
+1800 04 (Compatibility Entry): 0
+1800 05 (Event Timer): 0
+1801 (Transmit PDO 2 Parameter):
+1801 01 (COB ID used by PDO): 340
+1801 02 (Transmission Type): 1
+1801 03 (Inhibit Time): 0
+1801 04 (Compatibility Entry): 0
+1801 05 (Event Timer): 0
+1A00 (Transmit PDO 1 Mapping):
+1A00 01 (PDO 1 Mapping for a process data variable 1): 10010008
+1A01 (Transmit PDO 2 Mapping):
+1A01 01 (PDO 2 Mapping for a process data variable 1): 43400110
+1A01 02 (PDO 2 Mapping for a process data variable 2): 20000310
+1A01 03 (PDO 2 Mapping for a process data variable 3): 20000310
+1A01 04 (PDO 2 Mapping for a process data variable 4): 20000310
+1F22 (Concise DCF):
+1F22 01 (Concise DCF for Node 1):
+1F22 02 (Concise DCF for Node 2):
+1F22 03 (Concise DCF for Node 3):
+1F22 04 (Concise DCF for Node 4):
+1F22 05 (Concise DCF for Node 5):
+1F22 06 (Concise DCF for Node 6):
+1F22 07 (Concise DCF for Node 7):
+1F22 08 (Concise DCF for Node 8):
+1F22 09 (Concise DCF for Node 9):
+1F22 0A (Concise DCF for Node 10):
+1F22 0B (Concise DCF for Node 11):
+1F22 0C (Concise DCF for Node 12):
+1F22 0D (Concise DCF for Node 13):
+1F22 0E (Concise DCF for Node 14):
+1F22 0F (Concise DCF for Node 15):
+1F22 10 (Concise DCF for Node 16):
+1F22 11 (Concise DCF for Node 17):
+1F22 12 (Concise DCF for Node 18):
+1F22 13 (Concise DCF for Node 19):
+1F22 14 (Concise DCF for Node 20):
+1F22 15 (Concise DCF for Node 21):
+1F22 16 (Concise DCF for Node 22):
+1F22 17 (Concise DCF for Node 23):
+1F22 18 (Concise DCF for Node 24):
+1F22 19 (Concise DCF for Node 25):
+1F22 1A (Concise DCF for Node 26):
+1F22 1B (Concise DCF for Node 27):
+1F22 1C (Concise DCF for Node 28):
+1F22 1D (Concise DCF for Node 29):
+1F22 1E (Concise DCF for Node 30):
+1F22 1F (Concise DCF for Node 31):
+1F22 20 (Concise DCF for Node 32):
+1F22 21 (Concise DCF for Node 33):
+1F22 22 (Concise DCF for Node 34):
+1F22 23 (Concise DCF for Node 35):
+1F22 24 (Concise DCF for Node 36):
+1F22 25 (Concise DCF for Node 37):
+1F22 26 (Concise DCF for Node 38):
+1F22 27 (Concise DCF for Node 39):
+1F22 28 (Concise DCF for Node 40):
+1F22 29 (Concise DCF for Node 41):
+1F22 2A (Concise DCF for Node 42):
+1F22 2B (Concise DCF for Node 43):
+1F22 2C (Concise DCF for Node 44):
+1F22 2D (Concise DCF for Node 45):
+1F22 2E (Concise DCF for Node 46):
+1F22 2F (Concise DCF for Node 47):
+1F22 30 (Concise DCF for Node 48):
+1F22 31 (Concise DCF for Node 49):
+1F22 32 (Concise DCF for Node 50):
+1F22 33 (Concise DCF for Node 51):
+1F22 34 (Concise DCF for Node 52):
+1F22 35 (Concise DCF for Node 53):
+1F22 36 (Concise DCF for Node 54):
+1F22 37 (Concise DCF for Node 55):
+1F22 38 (Concise DCF for Node 56):
+1F22 39 (Concise DCF for Node 57):
+1F22 3A (Concise DCF for Node 58):
+1F22 3B (Concise DCF for Node 59):
+1F22 3C (Concise DCF for Node 60):
+1F22 3D (Concise DCF for Node 61):
+1F22 3E (Concise DCF for Node 62):
+1F22 3F (Concise DCF for Node 63):
+1F22 40 (Concise DCF for Node 64): 23 arg defined
+1F22 40, arg 1: 1800 01 00000004 800001C0
+1F22 40, arg 2: 1800 02 00000001 01
+1F22 40, arg 3: 1800 01 00000004 000001C0
+1F22 40, arg 4: 1801 01 00000004 800002C0
+1F22 40, arg 5: 1801 02 00000001 01
+1F22 40, arg 6: 1801 01 00000004 000002C0
+1F22 40, arg 7: 1401 01 00000004 80000340
+1F22 40, arg 8: 1401 02 00000001 01
+1F22 40, arg 9: 1401 01 00000004 00000340
+1F22 40, arg 10: 1804 01 00000004 80000181
+1F22 40, arg 11: 1804 02 00000001 01
+1F22 40, arg 12: 1804 01 00000004 00000181
+1F22 40, arg 13: 1A04 01 00000004 60020108
+1F22 40, arg 14: 1A04 02 00000004 64260120
+1F22 40, arg 15: 1805 01 00000004 80000182
+1F22 40, arg 16: 1805 02 00000001 01
+1F22 40, arg 17: 1805 01 00000004 00000182
+1F22 40, arg 18: 1A05 01 00000004 64260220
+1F22 40, arg 19: 1A05 02 00000004 64260320
+1F22 40, arg 20: 1806 01 00000004 80000183
+1F22 40, arg 21: 1806 02 00000001 01
+1F22 40, arg 22: 1806 01 00000004 00000183
+1F22 40, arg 23: 1A06 01 00000004 64260420
+1F22 41 (Concise DCF for Node 65):
+1F22 42 (Concise DCF for Node 66):
+1F22 43 (Concise DCF for Node 67):
+1F22 44 (Concise DCF for Node 68):
+1F22 45 (Concise DCF for Node 69):
+1F22 46 (Concise DCF for Node 70):
+1F22 47 (Concise DCF for Node 71):
+1F22 48 (Concise DCF for Node 72):
+1F22 49 (Concise DCF for Node 73):
+1F22 4A (Concise DCF for Node 74):
+1F22 4B (Concise DCF for Node 75):
+1F22 4C (Concise DCF for Node 76):
+1F22 4D (Concise DCF for Node 77):
+1F22 4E (Concise DCF for Node 78):
+1F22 4F (Concise DCF for Node 79):
+1F22 50 (Concise DCF for Node 80):
+1F22 51 (Concise DCF for Node 81):
+1F22 52 (Concise DCF for Node 82):
+1F22 53 (Concise DCF for Node 83):
+1F22 54 (Concise DCF for Node 84):
+1F22 55 (Concise DCF for Node 85):
+1F22 56 (Concise DCF for Node 86):
+1F22 57 (Concise DCF for Node 87):
+1F22 58 (Concise DCF for Node 88):
+1F22 59 (Concise DCF for Node 89):
+1F22 5A (Concise DCF for Node 90):
+1F22 5B (Concise DCF for Node 91):
+1F22 5C (Concise DCF for Node 92):
+1F22 5D (Concise DCF for Node 93):
+1F22 5E (Concise DCF for Node 94):
+1F22 5F (Concise DCF for Node 95):
+1F22 60 (Concise DCF for Node 96):
+1F22 61 (Concise DCF for Node 97):
+1F22 62 (Concise DCF for Node 98):
+1F22 63 (Concise DCF for Node 99):
+1F22 64 (Concise DCF for Node 100):
+1F22 65 (Concise DCF for Node 101):
+1F22 66 (Concise DCF for Node 102):
+1F22 67 (Concise DCF for Node 103):
+1F22 68 (Concise DCF for Node 104):
+1F22 69 (Concise DCF for Node 105):
+1F22 6A (Concise DCF for Node 106):
+1F22 6B (Concise DCF for Node 107):
+1F22 6C (Concise DCF for Node 108):
+1F22 6D (Concise DCF for Node 109):
+1F22 6E (Concise DCF for Node 110):
+1F22 6F (Concise DCF for Node 111):
+1F22 70 (Concise DCF for Node 112):
+1F22 71 (Concise DCF for Node 113):
+1F22 72 (Concise DCF for Node 114):
+1F22 73 (Concise DCF for Node 115):
+1F22 74 (Concise DCF for Node 116):
+1F22 75 (Concise DCF for Node 117):
+1F22 76 (Concise DCF for Node 118):
+1F22 77 (Concise DCF for Node 119):
+1F22 78 (Concise DCF for Node 120):
+1F22 79 (Concise DCF for Node 121):
+1F22 7A (Concise DCF for Node 122):
+1F22 7B (Concise DCF for Node 123):
+1F22 7C (Concise DCF for Node 124):
+1F22 7D (Concise DCF for Node 125):
+1F22 7E (Concise DCF for Node 126):
+1F22 7F (Concise DCF for Node 127):
+2000 (Read Inputs): 0
+2240 (beremiz__IB0_1_64):
+2240 01 (24576_1): 0
+2240 02 (24578_1): 0
+2340 (beremiz__IW0_1_64):
+2340 01 (25601_2): 0
+2340 02 (25601_3): 0
+2440 (beremiz__ID0_1_64):
+2440 01 (25638_2): 0
+2440 02 (25638_3): 0
+2440 03 (25638_4): 0
+2440 04 (25638_1): 0
+4340 (beremiz__QW0_1_64):
+4340 01 (25617_1): 0
+
+********POINTERS*********
+{(4096, 0): '__ID0_1_4096_0',
+ (8768, 1): '__IB0_1_64_24576_1',
+ (8768, 2): '__IB0_1_64_24578_1',
+ (9024, 1): '__IW0_1_64_25601_2',
+ (9024, 2): '__IW0_1_64_25601_3',
+ (9280, 1): '__ID0_1_64_25638_2',
+ (9280, 2): '__ID0_1_64_25638_3',
+ (9280, 3): '__ID0_1_64_25638_4',
+ (9280, 4): '__ID0_1_64_25638_1',
+ (17216, 1): '__QW0_1_64_25617_1'}
--- a/confnodes/.cvsignore Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-*.pyc
--- a/confnodes/__init__.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-from os import listdir, path
-
-catalog = [
- ('canfestival', _('CANopen support'), _('Map located variables over CANopen'), 'confnodes.canfestival.canfestival.RootClass'),
- ('c_ext', _('C extention'), _('Extend project with C code accessing located variables'), 'confnodes.c_ext.c_ext.RootClass'),
- ('python', _('Python extention'), _('Extend project with Pyhon code executed asynchronously'), 'confnodes.python.python.RootClass')]
-# ('ethercat_master', _('Ethercat master'), _('Map located variables over EtherCat, as a master'), 'ethercat.EthercatPlug')]
-
-
-
--- a/confnodes/c_ext/.cvsignore Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-*.pyc
--- a/confnodes/c_ext/CFileEditor.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,967 +0,0 @@
-import keyword
-
-import wx
-import wx.grid
-import wx.stc as stc
-import wx.lib.buttons
-
-from controls import CustomGrid, CustomTable, EditorPanel
-
-if wx.Platform == '__WXMSW__':
- faces = { 'times': 'Times New Roman',
- 'mono' : 'Courier New',
- 'helv' : 'Arial',
- 'other': 'Comic Sans MS',
- 'size' : 10,
- 'size2': 8,
- }
-else:
- faces = { 'times': 'Times',
- 'mono' : 'Courier',
- 'helv' : 'Helvetica',
- 'other': 'new century schoolbook',
- 'size' : 12,
- 'size2': 10,
- }
-
-
-def AppendMenu(parent, help, id, kind, text):
- if wx.VERSION >= (2, 6, 0):
- parent.Append(help=help, id=id, kind=kind, text=text)
- else:
- parent.Append(helpString=help, id=id, kind=kind, item=text)
-
-
-[ID_CPPEDITOR,
-] = [wx.NewId() for _init_ctrls in range(1)]
-
-CPP_KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class",
- "const", "const_cast", "continue", "default", "delete", "do", "double",
- "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
- "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
- "namespace", "new", "operator", "private", "protected", "public", "register",
- "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
- "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
- "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
- "void", "volatile", "wchar_t", "while"]
-
-def GetCursorPos(old, new):
- old_length = len(old)
- new_length = len(new)
- common_length = min(old_length, new_length)
- i = 0
- for i in xrange(common_length):
- if old[i] != new[i]:
- break
- if old_length < new_length:
- if common_length > 0 and old[i] != new[i]:
- return i + new_length - old_length
- else:
- return i + new_length - old_length + 1
- elif old_length > new_length or i < min(old_length, new_length) - 1:
- if common_length > 0 and old[i] != new[i]:
- return i
- else:
- return i + 1
- else:
- return None
-
-class CppEditor(stc.StyledTextCtrl):
-
- fold_symbols = 3
-
- def __init__(self, parent, name, window, controler):
- stc.StyledTextCtrl.__init__(self, parent, ID_CPPEDITOR, wx.DefaultPosition,
- wx.Size(0, 0), 0)
-
- self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
- self.SetMarginWidth(1, 25)
-
- self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
- self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
-
- self.SetLexer(stc.STC_LEX_CPP)
- self.SetKeyWords(0, " ".join(CPP_KEYWORDS))
-
- self.SetProperty("fold", "1")
- self.SetProperty("tab.timmy.whinge.level", "1")
- self.SetMargins(0,0)
-
- self.SetViewWhiteSpace(False)
- #self.SetBufferedDraw(False)
- #self.SetViewEOL(True)
- #self.SetEOLMode(stc.STC_EOL_CRLF)
- #self.SetUseAntiAliasing(True)
-
- self.SetEdgeMode(stc.STC_EDGE_BACKGROUND)
- self.SetEdgeColumn(78)
-
- # Setup a margin to hold fold markers
- #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
- self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
- self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
- self.SetMarginSensitive(2, True)
- self.SetMarginWidth(2, 12)
-
- if self.fold_symbols == 0:
- # Arrow pointing right for contracted folders, arrow pointing down for expanded
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
-
- elif self.fold_symbols == 1:
- # Plus for contracted folders, minus for expanded
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
-
- elif self.fold_symbols == 2:
- # Like a flattened tree control using circular headers and curved joins
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040")
-
- elif self.fold_symbols == 3:
- # Like a flattened tree control using square headers
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
- self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080")
-
-
- self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
- self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
- self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
-
- # Make some styles, The lexer defines what each style is used for, we
- # just have to define what each style looks like. This set is adapted from
- # Scintilla sample property files.
-
- # Global default styles for all languages
- self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
- self.StyleClearAll() # Reset all to be like the default
-
- # Global default styles for all languages
- self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
- self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
- self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
- self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
- self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
-
- self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060')
- self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060')
- self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060')
- self.StyleSetSpec(stc.STC_C_NUMBER, 'fore:#0076AE')
- self.StyleSetSpec(stc.STC_C_WORD, 'bold,fore:#800056')
- self.StyleSetSpec(stc.STC_C_STRING, 'fore:#2a00ff')
- self.StyleSetSpec(stc.STC_C_PREPROCESSOR, 'bold,fore:#800056')
- self.StyleSetSpec(stc.STC_C_OPERATOR, 'bold')
- self.StyleSetSpec(stc.STC_C_STRINGEOL, 'back:#FFD5FF')
-
- # register some images for use in the AutoComplete box.
- #self.RegisterImage(1, images.getSmilesBitmap())
- self.RegisterImage(1,
- wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16)))
- self.RegisterImage(2,
- wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
- self.RegisterImage(3,
- wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
-
- # Indentation size
- self.SetTabWidth(2)
- self.SetUseTabs(0)
-
- self.Controler = controler
- self.ParentWindow = window
-
- self.DisableEvents = True
- self.Name = name
- self.CurrentAction = None
-
- self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE)
-
- self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_CPPEDITOR)
- self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
- self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_CPPEDITOR)
-
- def OnModification(self, event):
- if not self.DisableEvents:
- mod_type = event.GetModificationType()
- if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO):
- if mod_type&wx.stc.STC_MOD_BEFOREINSERT:
- if self.CurrentAction == None:
- self.StartBuffering()
- elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
- self.Controler.EndBuffering()
- self.StartBuffering()
- self.CurrentAction = ("Add", event.GetPosition())
- wx.CallAfter(self.RefreshModel)
- elif mod_type&wx.stc.STC_MOD_BEFOREDELETE:
- if self.CurrentAction == None:
- self.StartBuffering()
- elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
- self.Controler.EndBuffering()
- self.StartBuffering()
- self.CurrentAction = ("Delete", event.GetPosition())
- wx.CallAfter(self.RefreshModel)
- event.Skip()
-
- def OnDoDrop(self, event):
- self.ResetBuffer()
- wx.CallAfter(self.RefreshModel)
- event.Skip()
-
- # Buffer the last model state
- def RefreshBuffer(self):
- self.Controler.BufferCFile()
- if self.ParentWindow is not None:
- self.ParentWindow.RefreshTitle()
- self.ParentWindow.RefreshFileMenu()
- self.ParentWindow.RefreshEditMenu()
- self.ParentWindow.RefreshPageTitles()
-
- def StartBuffering(self):
- self.Controler.StartBuffering()
- if self.ParentWindow is not None:
- self.ParentWindow.RefreshTitle()
- self.ParentWindow.RefreshFileMenu()
- self.ParentWindow.RefreshEditMenu()
- self.ParentWindow.RefreshPageTitles()
-
- def ResetBuffer(self):
- if self.CurrentAction != None:
- self.Controler.EndBuffering()
- self.CurrentAction = None
-
- def RefreshView(self):
- self.ResetBuffer()
- self.DisableEvents = True
- old_cursor_pos = self.GetCurrentPos()
- old_text = self.GetText()
- new_text = self.Controler.GetPartText(self.Name)
- self.SetText(new_text)
- new_cursor_pos = GetCursorPos(old_text, new_text)
- if new_cursor_pos != None:
- self.GotoPos(new_cursor_pos)
- else:
- self.GotoPos(old_cursor_pos)
- self.ScrollToColumn(0)
- self.EmptyUndoBuffer()
- self.DisableEvents = False
-
- self.Colourise(0, -1)
-
- def DoGetBestSize(self):
- return self.ParentWindow.GetPanelBestSize()
-
- def RefreshModel(self):
- self.Controler.SetPartText(self.Name, self.GetText())
-
- def OnKeyPressed(self, event):
- if self.CallTipActive():
- self.CallTipCancel()
- key = event.GetKeyCode()
-
- if key == 32 and event.ControlDown():
- pos = self.GetCurrentPos()
-
- # Tips
- if event.ShiftDown():
- pass
-## self.CallTipSetBackground("yellow")
-## self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
-## 'show some suff, maybe parameters..\n\n'
-## 'fubar(param1, param2)')
- # Code completion
- else:
- self.AutoCompSetIgnoreCase(False) # so this needs to match
-
- # Images are specified with a appended "?type"
- self.AutoCompShow(0, " ".join([word + "?1" for word in CPP_KEYWORDS]))
- else:
- event.Skip()
-
- def OnKillFocus(self, event):
- self.AutoCompCancel()
- event.Skip()
-
- def OnUpdateUI(self, evt):
- # check for matching braces
- braceAtCaret = -1
- braceOpposite = -1
- charBefore = None
- caretPos = self.GetCurrentPos()
-
- if caretPos > 0:
- charBefore = self.GetCharAt(caretPos - 1)
- styleBefore = self.GetStyleAt(caretPos - 1)
-
- # check before
- if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
- braceAtCaret = caretPos - 1
-
- # check after
- if braceAtCaret < 0:
- charAfter = self.GetCharAt(caretPos)
- styleAfter = self.GetStyleAt(caretPos)
-
- if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
- braceAtCaret = caretPos
-
- if braceAtCaret >= 0:
- braceOpposite = self.BraceMatch(braceAtCaret)
-
- if braceAtCaret != -1 and braceOpposite == -1:
- self.BraceBadLight(braceAtCaret)
- else:
- self.BraceHighlight(braceAtCaret, braceOpposite)
- #pt = self.PointFromPosition(braceOpposite)
- #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
- #print pt
- #self.Refresh(False)
-
-
- def OnMarginClick(self, evt):
- # fold and unfold as needed
- if evt.GetMargin() == 2:
- if evt.GetShift() and evt.GetControl():
- self.FoldAll()
- else:
- lineClicked = self.LineFromPosition(evt.GetPosition())
-
- if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
- if evt.GetShift():
- self.SetFoldExpanded(lineClicked, True)
- self.Expand(lineClicked, True, True, 1)
- elif evt.GetControl():
- if self.GetFoldExpanded(lineClicked):
- self.SetFoldExpanded(lineClicked, False)
- self.Expand(lineClicked, False, True, 0)
- else:
- self.SetFoldExpanded(lineClicked, True)
- self.Expand(lineClicked, True, True, 100)
- else:
- self.ToggleFold(lineClicked)
-
-
- def FoldAll(self):
- lineCount = self.GetLineCount()
- expanding = True
-
- # find out if we are folding or unfolding
- for lineNum in range(lineCount):
- if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
- expanding = not self.GetFoldExpanded(lineNum)
- break
-
- lineNum = 0
-
- while lineNum < lineCount:
- level = self.GetFoldLevel(lineNum)
- if level & stc.STC_FOLDLEVELHEADERFLAG and \
- (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
-
- if expanding:
- self.SetFoldExpanded(lineNum, True)
- lineNum = self.Expand(lineNum, True)
- lineNum = lineNum - 1
- else:
- lastChild = self.GetLastChild(lineNum, -1)
- self.SetFoldExpanded(lineNum, False)
-
- if lastChild > lineNum:
- self.HideLines(lineNum+1, lastChild)
-
- lineNum = lineNum + 1
-
-
-
- def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
- lastChild = self.GetLastChild(line, level)
- line = line + 1
-
- while line <= lastChild:
- if force:
- if visLevels > 0:
- self.ShowLines(line, line)
- else:
- self.HideLines(line, line)
- else:
- if doExpand:
- self.ShowLines(line, line)
-
- if level == -1:
- level = self.GetFoldLevel(line)
-
- if level & stc.STC_FOLDLEVELHEADERFLAG:
- if force:
- if visLevels > 1:
- self.SetFoldExpanded(line, True)
- else:
- self.SetFoldExpanded(line, False)
-
- line = self.Expand(line, doExpand, force, visLevels-1)
-
- else:
- if doExpand and self.GetFoldExpanded(line):
- line = self.Expand(line, True, force, visLevels-1)
- else:
- line = self.Expand(line, False, force, visLevels-1)
- else:
- line = line + 1
-
- return line
-
- def Cut(self):
- self.ResetBuffer()
- self.DisableEvents = True
- self.CmdKeyExecute(wx.stc.STC_CMD_CUT)
- self.DisableEvents = False
- self.RefreshModel()
- self.RefreshBuffer()
-
- def Copy(self):
- self.CmdKeyExecute(wx.stc.STC_CMD_COPY)
-
- def Paste(self):
- self.ResetBuffer()
- self.DisableEvents = True
- self.CmdKeyExecute(wx.stc.STC_CMD_PASTE)
- self.DisableEvents = False
- self.RefreshModel()
- self.RefreshBuffer()
-
-
-#-------------------------------------------------------------------------------
-# Helper for VariablesGrid values
-#-------------------------------------------------------------------------------
-
-class VariablesTable(CustomTable):
-
- def GetValue(self, row, col):
- if row < self.GetNumberRows():
- if col == 0:
- return row + 1
- else:
- return str(self.data[row].get(self.GetColLabelValue(col, False), ""))
-
- def _updateColAttrs(self, grid):
- """
- wxGrid -> update the column attributes to add the
- appropriate renderer given the column name.
-
- Otherwise default to the default renderer.
- """
-
- typelist = None
- accesslist = None
- for row in range(self.GetNumberRows()):
- for col in range(self.GetNumberCols()):
- editor = None
- renderer = None
- colname = self.GetColLabelValue(col, False)
-
- if colname == "Name":
- editor = wx.grid.GridCellTextEditor()
- elif colname == "Class":
- editor = wx.grid.GridCellChoiceEditor()
- editor.SetParameters("input,memory,output")
- elif colname == "Type":
- pass
- else:
- grid.SetReadOnly(row, col, True)
-
- grid.SetCellEditor(row, col, editor)
- grid.SetCellRenderer(row, col, renderer)
-
- grid.SetCellBackgroundColour(row, col, wx.WHITE)
- self.ResizeRow(grid, row)
-
-
-[ID_VARIABLESEDITOR, ID_VARIABLESEDITORVARIABLESGRID,
- ID_VARIABLESEDITORADDVARIABLEBUTTON, ID_VARIABLESEDITORDELETEVARIABLEBUTTON,
- ID_VARIABLESEDITORUPVARIABLEBUTTON, ID_VARIABLESEDITORDOWNVARIABLEBUTTON
-] = [wx.NewId() for _init_ctrls in range(6)]
-
-class VariablesEditor(wx.Panel):
-
- if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
- if id is not None:
- event(self, id, function)
- else:
- event(self, function)
-
- def _init_coll_MainSizer_Growables(self, parent):
- parent.AddGrowableCol(0)
- parent.AddGrowableRow(0)
-
- def _init_coll_MainSizer_Items(self, parent):
- parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
- parent.AddSizer(self.ButtonsSizer, 0, border=0, flag=wx.GROW)
-
- def _init_coll_ButtonsSizer_Growables(self, parent):
- parent.AddGrowableCol(0)
- parent.AddGrowableRow(0)
-
- def _init_coll_ButtonsSizer_Items(self, parent):
- parent.AddWindow(self.AddVariableButton, 0, border=0, flag=wx.ALIGN_RIGHT)
- parent.AddWindow(self.DeleteVariableButton, 0, border=0, flag=0)
- parent.AddWindow(self.UpVariableButton, 0, border=0, flag=0)
- parent.AddWindow(self.DownVariableButton, 0, border=0, flag=0)
-
- def _init_sizers(self):
- self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=4)
- self.ButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
-
- self._init_coll_MainSizer_Growables(self.MainSizer)
- self._init_coll_MainSizer_Items(self.MainSizer)
- self._init_coll_ButtonsSizer_Growables(self.ButtonsSizer)
- self._init_coll_ButtonsSizer_Items(self.ButtonsSizer)
-
- self.SetSizer(self.MainSizer)
-
- def _init_ctrls(self, prnt):
- wx.Panel.__init__(self, id=ID_VARIABLESEDITOR, name='', parent=prnt,
- size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
-
- self.VariablesGrid = CustomGrid(id=ID_VARIABLESEDITORVARIABLESGRID,
- name='VariablesGrid', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(-1, -1), style=wx.VSCROLL)
- if wx.VERSION >= (2, 5, 0):
- self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
- self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
- self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
- else:
- wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange)
- wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
- wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown)
-
- self.AddVariableButton = wx.Button(id=ID_VARIABLESEDITORADDVARIABLEBUTTON, label='Add Variable',
- name='AddVariableButton', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(122, 32), style=0)
-
- self.DeleteVariableButton = wx.Button(id=ID_VARIABLESEDITORDELETEVARIABLEBUTTON, label='Delete Variable',
- name='DeleteVariableButton', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(122, 32), style=0)
-
- self.UpVariableButton = wx.Button(id=ID_VARIABLESEDITORUPVARIABLEBUTTON, label='^',
- name='UpVariableButton', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(32, 32), style=0)
-
- self.DownVariableButton = wx.Button(id=ID_VARIABLESEDITORDOWNVARIABLEBUTTON, label='v',
- name='DownVariableButton', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(32, 32), style=0)
-
- self._init_sizers()
-
- def __init__(self, parent, window, controler):
- self._init_ctrls(parent)
-
- self.ParentWindow = window
- self.Controler = controler
-
- self.VariablesDefaultValue = {"Name" : "", "Class" : "input", "Type" : ""}
- self.Table = VariablesTable(self, [], ["#", "Name", "Class", "Type"])
- self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
- self.ColSizes = [40, 200, 150, 150]
- self.VariablesGrid.SetTable(self.Table)
- self.VariablesGrid.SetButtons({"Add": self.AddVariableButton,
- "Delete": self.DeleteVariableButton,
- "Up": self.UpVariableButton,
- "Down": self.DownVariableButton})
-
- def _AddVariable(new_row):
- self.Table.InsertRow(new_row, self.VariablesDefaultValue.copy())
- self.RefreshModel()
- self.RefreshView()
- return new_row
- setattr(self.VariablesGrid, "_AddRow", _AddVariable)
-
- def _DeleteVariable(row):
- self.Table.RemoveRow(row)
- self.RefreshModel()
- self.RefreshView()
- setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
-
- def _MoveVariable(row, move):
- new_row = self.Table.MoveRow(row, move)
- if new_row != row:
- self.RefreshModel()
- self.RefreshView()
- return new_row
- setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
-
- self.VariablesGrid.SetRowLabelSize(0)
- for col in range(self.Table.GetNumberCols()):
- attr = wx.grid.GridCellAttr()
- attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
- self.VariablesGrid.SetColAttr(col, attr)
- self.VariablesGrid.SetColSize(col, self.ColSizes[col])
- self.Table.ResetView(self.VariablesGrid)
-
- def RefreshModel(self):
- self.Controler.SetVariables(self.Table.GetData())
- self.RefreshBuffer()
-
- # Buffer the last model state
- def RefreshBuffer(self):
- self.Controler.BufferCFile()
- self.ParentWindow.RefreshTitle()
- self.ParentWindow.RefreshFileMenu()
- self.ParentWindow.RefreshEditMenu()
- self.ParentWindow.RefreshPageTitles()
-
- def RefreshView(self):
- self.Table.SetData(self.Controler.GetVariables())
- self.Table.ResetView(self.VariablesGrid)
- self.VariablesGrid.RefreshButtons()
-
- def DoGetBestSize(self):
- return self.ParentWindow.GetPanelBestSize()
-
- def OnVariablesGridCellChange(self, event):
- self.RefreshModel()
- wx.CallAfter(self.RefreshView)
- event.Skip()
-
- def OnVariablesGridEditorShown(self, event):
- row, col = event.GetRow(), event.GetCol()
- if self.Table.GetColLabelValue(col) == "Type":
- type_menu = wx.Menu(title='')
- base_menu = wx.Menu(title='')
- for base_type in self.Controler.GetBaseTypes():
- new_id = wx.NewId()
- AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type)
- self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id)
- type_menu.AppendMenu(wx.NewId(), "Base Types", base_menu)
- datatype_menu = wx.Menu(title='')
- for datatype in self.Controler.GetDataTypes(basetypes=False, only_locatables=True):
- new_id = wx.NewId()
- AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
- self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
- type_menu.AppendMenu(wx.NewId(), "User Data Types", datatype_menu)
- rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col))
-
- self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize())
- type_menu.Destroy()
- event.Veto()
- else:
- event.Skip()
-
- def GetVariableTypeFunction(self, base_type):
- def VariableTypeFunction(event):
- row = self.VariablesGrid.GetGridCursorRow()
- self.Table.SetValueByName(row, "Type", base_type)
- self.Table.ResetView(self.VariablesGrid)
- self.RefreshModel()
- self.RefreshView()
- event.Skip()
- return VariableTypeFunction
-
- def OnVariablesGridCellLeftClick(self, event):
- if event.GetCol() == 0:
- row = event.GetRow()
- num = 0
- if self.Table.GetValueByName(row, "Class") == "input":
- dir = "%I"
- for i in xrange(row):
- if self.Table.GetValueByName(i, "Class") == "input":
- num += 1
- elif self.Table.GetValueByName(row, "Class") == "memory":
- dir = "%M"
- for i in xrange(row):
- if self.Table.GetValueByName(i, "Class") == "memory":
- num += 1
- else:
- dir = "%Q"
- for i in xrange(row):
- if self.Table.GetValueByName(i, "Class") == "output":
- num += 1
- data_type = self.Table.GetValueByName(row, "Type")
- var_name = self.Table.GetValueByName(row, "Name")
- base_location = ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation()))
- location = "%s%s%s.%d"%(dir, self.Controler.GetSizeOfType(data_type), base_location, num)
- data = wx.TextDataObject(str((location, "location", data_type, var_name, "")))
- dragSource = wx.DropSource(self.VariablesGrid)
- dragSource.SetData(data)
- dragSource.DoDragDrop()
- event.Skip()
-
-
-#-------------------------------------------------------------------------------
-# SVGUIEditor Main Frame Class
-#-------------------------------------------------------------------------------
-
-CFILE_PARTS = [
- ("Includes", CppEditor),
- ("Variables", VariablesEditor),
- ("Globals", CppEditor),
- ("Init", CppEditor),
- ("CleanUp", CppEditor),
- ("Retrieve", CppEditor),
- ("Publish", CppEditor),
-]
-
-#----------------------------------------------------------------------
-# different icons for the collapsed/expanded states.
-# Taken from standard Windows XP collapsed/expanded states.
-#----------------------------------------------------------------------
-
-def GetCollapsedIconData():
- return \
-'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
-\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
-\x00\x01\x8eIDAT8\x8d\xa5\x93-n\xe4@\x10\x85?g\x03\n6lh)\xc4\xd2\x12\xc3\x81\
-\xd6\xa2I\x90\x154\xb9\x81\x8f1G\xc8\x11\x16\x86\xcd\xa0\x99F\xb3A\x91\xa1\
-\xc9J&\x96L"5lX\xcc\x0bl\xf7v\xb2\x7fZ\xa5\x98\xebU\xbdz\xf5\\\x9deW\x9f\xf8\
-H\\\xbfO|{y\x9dT\x15P\x04\x01\x01UPUD\x84\xdb/7YZ\x9f\xa5\n\xce\x97aRU\x8a\
-\xdc`\xacA\x00\x04P\xf0!0\xf6\x81\xa0\xf0p\xff9\xfb\x85\xe0|\x19&T)K\x8b\x18\
-\xf9\xa3\xe4\xbe\xf3\x8c^#\xc9\xd5\n\xa8*\xc5?\x9a\x01\x8a\xd2b\r\x1cN\xc3\
-\x14\t\xce\x97a\xb2F0Ks\xd58\xaa\xc6\xc5\xa6\xf7\xdfya\xe7\xbdR\x13M2\xf9\
-\xf9qKQ\x1fi\xf6-\x00~T\xfac\x1dq#\x82,\xe5q\x05\x91D\xba@\xefj\xba1\xf0\xdc\
-zzW\xcff&\xb8,\x89\xa8@Q\xd6\xaaf\xdfRm,\xee\xb1BDxr#\xae\xf5|\xddo\xd6\xe2H\
-\x18\x15\x84\xa0q@]\xe54\x8d\xa3\xedf\x05M\xe3\xd8Uy\xc4\x15\x8d\xf5\xd7\x8b\
-~\x82\x0fh\x0e"\xb0\xad,\xee\xb8c\xbb\x18\xe7\x8e;6\xa5\x89\x04\xde\xff\x1c\
-\x16\xef\xe0p\xfa>\x19\x11\xca\x8d\x8d\xe0\x93\x1b\x01\xd8m\xf3(;x\xa5\xef=\
-\xb7w\xf3\x1d$\x7f\xc1\xe0\xbd\xa7\xeb\xa0(,"Kc\x12\xc1+\xfd\xe8\tI\xee\xed)\
-\xbf\xbcN\xc1{D\x04k\x05#\x12\xfd\xf2a\xde[\x81\x87\xbb\xdf\x9cr\x1a\x87\xd3\
-0)\xba>\x83\xd5\xb97o\xe0\xaf\x04\xff\x13?\x00\xd2\xfb\xa9`z\xac\x80w\x00\
-\x00\x00\x00IEND\xaeB`\x82'
-
-def GetCollapsedIconBitmap():
- return wx.BitmapFromImage(GetCollapsedIconImage())
-
-def GetCollapsedIconImage():
- import cStringIO
- stream = cStringIO.StringIO(GetCollapsedIconData())
- return wx.ImageFromStream(stream)
-
-#----------------------------------------------------------------------
-def GetExpandedIconData():
- return \
-'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
-\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
-\x00\x01\x9fIDAT8\x8d\x95\x93\xa1\x8e\xdc0\x14EO\xb2\xc4\xd0\xd2\x12\xb7(mI\
-\xa4%V\xd1lQT4[4-\x9a\xfe\xc1\xc2|\xc6\xc2~BY\x83:A3E\xd3\xa0*\xa4\xd2\x90H!\
-\x95\x0c\r\r\x1fK\x81g\xb2\x99\x84\xb4\x0fY\xd6\xbb\xc7\xf7>=\'Iz\xc3\xbcv\
-\xfbn\xb8\x9c\x15 \xe7\xf3\xc7\x0fw\xc9\xbc7\x99\x03\x0e\xfbn0\x99F+\x85R\
-\x80RH\x10\x82\x08\xde\x05\x1ef\x90+\xc0\xe1\xd8\ryn\xd0Z-\\A\xb4\xd2\xf7\
-\x9e\xfbwoF\xc8\x088\x1c\xbbae\xb3\xe8y&\x9a\xdf\xf5\xbd\xe7\xfem\x84\xa4\
-\x97\xccYf\x16\x8d\xdb\xb2a]\xfeX\x18\xc9s\xc3\xe1\x18\xe7\x94\x12cb\xcc\xb5\
-\xfa\xb1l8\xf5\x01\xe7\x84\xc7\xb2Y@\xb2\xcc0\x02\xb4\x9a\x88%\xbe\xdc\xb4\
-\x9e\xb6Zs\xaa74\xadg[6\x88<\xb7]\xc6\x14\x1dL\x86\xe6\x83\xa0\x81\xba\xda\
-\x10\x02x/\xd4\xd5\x06\r\x840!\x9c\x1fM\x92\xf4\x86\x9f\xbf\xfe\x0c\xd6\x9ae\
-\xd6u\x8d \xf4\xf5\x165\x9b\x8f\x04\xe1\xc5\xcb\xdb$\x05\x90\xa97@\x04lQas\
-\xcd*7\x14\xdb\x9aY\xcb\xb8\\\xe9E\x10|\xbc\xf2^\xb0E\x85\xc95_\x9f\n\xaa/\
-\x05\x10\x81\xce\xc9\xa8\xf6><G\xd8\xed\xbbA)X\xd9\x0c\x01\x9a\xc6Q\x14\xd9h\
-[\x04\xda\xd6c\xadFkE\xf0\xc2\xab\xd7\xb7\xc9\x08\x00\xf8\xf6\xbd\x1b\x8cQ\
-\xd8|\xb9\x0f\xd3\x9a\x8a\xc7\x08\x00\x9f?\xdd%\xde\x07\xda\x93\xc3{\x19C\
-\x8a\x9c\x03\x0b8\x17\xe8\x9d\xbf\x02.>\x13\xc0n\xff{PJ\xc5\xfdP\x11""<\xbc\
-\xff\x87\xdf\xf8\xbf\xf5\x17FF\xaf\x8f\x8b\xd3\xe6K\x00\x00\x00\x00IEND\xaeB\
-`\x82'
-
-def GetExpandedIconBitmap():
- return wx.BitmapFromImage(GetExpandedIconImage())
-
-def GetExpandedIconImage():
- import cStringIO
- stream = cStringIO.StringIO(GetExpandedIconData())
- return wx.ImageFromStream(stream)
-
-class FoldPanelCaption(wx.lib.buttons.GenBitmapTextToggleButton):
-
- def GetBackgroundBrush(self, dc):
- colBg = self.GetBackgroundColour()
- brush = wx.Brush(colBg, wx.SOLID)
- if self.style & wx.BORDER_NONE:
- myAttr = self.GetDefaultAttributes()
- parAttr = self.GetParent().GetDefaultAttributes()
- myDef = colBg == myAttr.colBg
- parDef = self.GetParent().GetBackgroundColour() == parAttr.colBg
- if myDef and parDef:
- if wx.Platform == "__WXMAC__":
- brush.MacSetTheme(1) # 1 == kThemeBrushDialogBackgroundActive
- elif wx.Platform == "__WXMSW__":
- if self.DoEraseBackground(dc):
- brush = None
- elif myDef and not parDef:
- colBg = self.GetParent().GetBackgroundColour()
- brush = wx.Brush(colBg, wx.SOLID)
- return brush
-
- def DrawLabel(self, dc, width, height, dx=0, dy=0):
- bmp = self.bmpLabel
- if bmp is not None: # if the bitmap is used
- if self.bmpDisabled and not self.IsEnabled():
- bmp = self.bmpDisabled
- if self.bmpFocus and self.hasFocus:
- bmp = self.bmpFocus
- if self.bmpSelected and not self.up:
- bmp = self.bmpSelected
- bw,bh = bmp.GetWidth(), bmp.GetHeight()
- hasMask = bmp.GetMask() is not None
- else:
- bw = bh = 0 # no bitmap -> size is zero
-
- dc.SetFont(self.GetFont())
- if self.IsEnabled():
- dc.SetTextForeground(self.GetForegroundColour())
- else:
- dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
-
- label = self.GetLabel()
- tw, th = dc.GetTextExtent(label) # size of text
-
- if bmp is not None:
- dc.DrawBitmap(bmp, width - bw - 2, (height-bh)/2, hasMask) # draw bitmap if available
-
- dc.DrawText(label, 2, (height-th)/2) # draw the text
-
- dc.SetPen(wx.Pen(self.GetForegroundColour()))
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.DrawRectangle(0, 0, width, height)
-
-[ID_CFILEEDITOR, ID_CFILEEDITORMAINSPLITTER,
- ID_CFILEEDITORCFILETREE, ID_CFILEEDITORPARTSOPENED,
-] = [wx.NewId() for _init_ctrls in range(4)]
-
-class CFileEditor(EditorPanel):
-
- def _init_Editor(self, prnt):
- self.Editor = wx.Panel(id=ID_CFILEEDITOR, parent=prnt, pos=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
-
- self.Panels = {}
- self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2 * len(CFILE_PARTS) + 1, vgap=0)
- self.MainSizer.AddGrowableCol(0)
-
- for idx, (name, panel_class) in enumerate(CFILE_PARTS):
- button_id = wx.NewId()
- button = FoldPanelCaption(id=button_id, name='FoldPanelCaption_%s' % name,
- label=name, bitmap=GetCollapsedIconBitmap(), parent=self.Editor, pos=wx.Point(0, 0),
- size=wx.Size(0, 20), style=wx.NO_BORDER|wx.ALIGN_LEFT)
- button.SetBitmapSelected(GetExpandedIconBitmap())
- button.Bind(wx.EVT_BUTTON, self.GenPanelButtonCallback(name), id=button_id)
- self.MainSizer.AddWindow(button, 0, border=0, flag=wx.TOP|wx.GROW)
-
- if panel_class == VariablesEditor:
- panel = VariablesEditor(self.Editor, self.ParentWindow, self.Controler)
- else:
- panel = panel_class(self.Editor, name, self.ParentWindow, self.Controler)
- self.MainSizer.AddWindow(panel, 0, border=0, flag=wx.BOTTOM|wx.GROW)
- panel.Hide()
-
- self.Panels[name] = {"button": button, "panel": panel, "expanded": False, "row": 2 * idx + 1}
-
- self.Spacer = wx.Panel(self.Editor, -1)
- self.SpacerExpanded = True
- self.MainSizer.AddWindow(self.Spacer, 0, border=0, flag=wx.GROW)
-
- self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS))
-
- self.Editor.SetSizer(self.MainSizer)
-
- def __init__(self, parent, controler, window):
- EditorPanel.__init__(self, parent, "", window, controler)
-
- img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
- self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
-
- def __del__(self):
- self.Controler.OnCloseEditor(self)
-
- def GetTitle(self):
- fullname = self.Controler.CTNFullName()
- if not self.Controler.CFileIsSaved():
- return "~%s~" % fullname
- return fullname
-
- def GetBufferState(self):
- return self.Controler.GetBufferState()
-
- def Undo(self):
- self.Controler.LoadPrevious()
- self.RefreshView()
-
- def Redo(self):
- self.Controler.LoadNext()
- self.RefreshView()
-
- def HasNoModel(self):
- return False
-
- def RefreshView(self):
- for infos in self.Panels.itervalues():
- infos["panel"].RefreshView()
-
- def GenPanelButtonCallback(self, name):
- def PanelButtonCallback(event):
- self.TogglePanel(name)
- return PanelButtonCallback
-
- def ExpandPanel(self, name):
- infos = self.Panels.get(name, None)
- if infos is not None and not infos["expanded"]:
- infos["expanded"] = True
- infos["button"].SetToggle(True)
- infos["panel"].Show()
- self.MainSizer.AddGrowableRow(infos["row"])
-
- self.RefreshSizerLayout()
-
- def CollapsePanel(self, name):
- infos = self.Panels.get(name, None)
- if infos is not None and infos["expanded"]:
- infos["expanded"] = False
- infos["button"].SetToggle(False)
- infos["panel"].Hide()
- self.MainSizer.RemoveGrowableRow(infos["row"])
-
- self.RefreshSizerLayout()
-
- def TogglePanel(self, name):
- infos = self.Panels.get(name, None)
- if infos is not None:
- infos["expanded"] = not infos["expanded"]
- infos["button"].SetToggle(infos["expanded"])
- if infos["expanded"]:
- infos["panel"].Show()
- self.MainSizer.AddGrowableRow(infos["row"])
- else:
- infos["panel"].Hide()
- self.MainSizer.RemoveGrowableRow(infos["row"])
-
- self.RefreshSizerLayout()
-
- def RefreshSizerLayout(self):
- expand_spacer = True
- for infos in self.Panels.itervalues():
- expand_spacer = expand_spacer and not infos["expanded"]
-
- if self.SpacerExpanded != expand_spacer:
- self.SpacerExpanded = expand_spacer
- if expand_spacer:
- self.Spacer.Show()
- self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS))
- else:
- self.Spacer.Hide()
- self.MainSizer.RemoveGrowableRow(2 * len(CFILE_PARTS))
-
- self.MainSizer.Layout()
-
--- a/confnodes/c_ext/README Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-C extension
\ No newline at end of file
--- a/confnodes/c_ext/__init__.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-from c_ext import *
--- a/confnodes/c_ext/c_ext.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,315 +0,0 @@
-import wx
-import os
-from xml.dom import minidom
-import cPickle
-
-from xmlclass import *
-
-from ConfigTree import ConfigTreeNode, opjimg
-from CFileEditor import CFileEditor
-from PLCControler import PLCControler, UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
-
-CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd"))
-
-TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
- "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L",
- "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"}
-
-class _Cfile:
- XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="CExtension">
- <xsd:complexType>
- <xsd:attribute name="CFLAGS" type="xsd:string" use="required"/>
- <xsd:attribute name="LDFLAGS" type="xsd:string" use="required"/>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- """
- EditorType = CFileEditor
-
- def __init__(self):
- filepath = self.CFileName()
-
- self.CFile = CFileClasses["CFile"]()
- if os.path.isfile(filepath):
- xmlfile = open(filepath, 'r')
- tree = minidom.parse(xmlfile)
- xmlfile.close()
-
- for child in tree.childNodes:
- if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "CFile":
- self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"])
- self.CreateCFileBuffer(True)
- else:
- self.CreateCFileBuffer(False)
- self.OnCTNSave()
-
- def CFileName(self):
- return os.path.join(self.CTNPath(), "cfile.xml")
-
- def GetBaseTypes(self):
- return self.GetCTRoot().GetBaseTypes()
-
- def GetDataTypes(self, basetypes = False, only_locatables = False):
- return self.GetCTRoot().GetDataTypes(basetypes=basetypes, only_locatables=only_locatables)
-
- def GetSizeOfType(self, type):
- return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None)
-
- def SetVariables(self, variables):
- self.CFile.variables.setvariable([])
- for var in variables:
- variable = CFileClasses["variables_variable"]()
- variable.setname(var["Name"])
- variable.settype(var["Type"])
- variable.setclass(var["Class"])
- self.CFile.variables.appendvariable(variable)
-
- def GetVariables(self):
- datas = []
- for var in self.CFile.variables.getvariable():
- datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()})
- return datas
-
- def GetVariableLocationTree(self):
- '''See ConfigTreeNode.GetVariableLocationTree() for a description.'''
-
- current_location = ".".join(map(str, self.GetCurrentLocation()))
-
- vars = []
- input = memory = output = 0
- for var in self.CFile.variables.getvariable():
- var_size = self.GetSizeOfType(var.gettype())
- var_location = ""
- if var.getclass() == "input":
- var_class = LOCATION_VAR_INPUT
- if var_size is not None:
- var_location = "%%I%s%s.%d"%(var_size, current_location, input)
- input += 1
- elif var.getclass() == "memory":
- var_class = LOCATION_VAR_INPUT
- if var_size is not None:
- var_location = "%%M%s%s.%d"%(var_size, current_location, memory)
- memory += 1
- else:
- var_class = LOCATION_VAR_OUTPUT
- if var_size is not None:
- var_location = "%%Q%s%s.%d"%(var_size, current_location, output)
- output += 1
- vars.append({"name": var.getname(),
- "type": var_class,
- "size": var_size,
- "IEC_type": var.gettype(),
- "var_name": var.getname(),
- "location": var_location,
- "description": "",
- "children": []})
-
- return {"name": self.BaseParams.getName(),
- "type": LOCATION_CONFNODE,
- "location": self.GetFullIEC_Channel(),
- "children": vars}
-
- def SetPartText(self, name, text):
- if name == "Includes":
- self.CFile.includes.settext(text)
- elif name == "Globals":
- self.CFile.globals.settext(text)
- elif name == "Init":
- self.CFile.initFunction.settext(text)
- elif name == "CleanUp":
- self.CFile.cleanUpFunction.settext(text)
- elif name == "Retrieve":
- self.CFile.retrieveFunction.settext(text)
- elif name == "Publish":
- self.CFile.publishFunction.settext(text)
-
- def GetPartText(self, name):
- if name == "Includes":
- return self.CFile.includes.gettext()
- elif name == "Globals":
- return self.CFile.globals.gettext()
- elif name == "Init":
- return self.CFile.initFunction.gettext()
- elif name == "CleanUp":
- return self.CFile.cleanUpFunction.gettext()
- elif name == "Retrieve":
- return self.CFile.retrieveFunction.gettext()
- elif name == "Publish":
- return self.CFile.publishFunction.gettext()
- return ""
-
- ConfNodeMethods = [
- {"bitmap" : os.path.join("images", "EditCfile"),
- "name" : _("Edit C File"),
- "tooltip" : _("Edit C File"),
- "method" : "_OpenView"},
- ]
-
- def CTNTestModified(self):
- return self.ChangesToSave or not self.CFileIsSaved()
-
- def OnCTNSave(self):
- filepath = self.CFileName()
-
- text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
- extras = {"xmlns":"http://www.w3.org/2001/XMLSchema",
- "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
- "xsi:schemaLocation" : "cext_xsd.xsd"}
- text += self.CFile.generateXMLText("CFile", 0, extras)
-
- xmlfile = open(filepath,"w")
- xmlfile.write(text.encode("utf-8"))
- xmlfile.close()
-
- self.MarkCFileAsSaved()
- return True
-
- def CTNGenerate_C(self, buildpath, locations):
- """
- Generate C code
- @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5)
- @param locations: List of complete variables locations \
- [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
- "NAME" : name of the variable (generally "__IW0_1_2" style)
- "DIR" : direction "Q","I" or "M"
- "SIZE" : size "X", "B", "W", "D", "L"
- "LOC" : tuple of interger for IEC location (0,1,2,...)
- }, ...]
- @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
- """
- current_location = self.GetCurrentLocation()
- # define a unique name for the generated C file
- location_str = "_".join(map(str, current_location))
-
- text = "/* Code generated by Beremiz c_ext confnode */\n\n"
-
- # Adding includes
- text += "/* User includes */\n"
- text += self.CFile.includes.gettext()
- text += "\n"
-
- text += """/* Beremiz c_ext confnode includes */
-#ifdef _WINDOWS_H
- #include "iec_types.h"
-#else
- #include "iec_std_lib.h"
-#endif
-
-"""
-
- # Adding variables
- vars = []
- inputs = memories = outputs = 0
- for variable in self.CFile.variables.variable:
- var = {"Name" : variable.getname(), "Type" : variable.gettype()}
- if variable.getclass() == "input":
- var["location"] = "__I%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, inputs)
- inputs += 1
- elif variable.getclass() == "memory":
- var["location"] = "__M%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, memories)
- memories += 1
- else:
- var["location"] = "__Q%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, outputs)
- outputs += 1
- vars.append(var)
- text += "/* Beremiz c_ext confnode user variables definition */\n"
- base_types = self.GetCTRoot().GetBaseTypes()
- for var in vars:
- if var["Type"] in base_types:
- prefix = "IEC_"
- else:
- prefix = ""
- text += "%s%s beremiz%s;\n"%(prefix, var["Type"], var["location"])
- text += "%s%s *%s = &beremiz%s;\n"%(prefix, var["Type"], var["location"], var["location"])
- text += "/* User variables reference */\n"
- for var in vars:
- text += "#define %s beremiz%s\n"%(var["Name"], var["location"])
- text += "\n"
-
- # Adding user global variables and routines
- text += "/* User internal user variables and routines */\n"
- text += self.CFile.globals.gettext()
-
- # Adding Beremiz confnode functions
- text += "/* Beremiz confnode functions */\n"
- text += "int __init_%s(int argc,char **argv)\n{\n"%location_str
- text += self.CFile.initFunction.gettext()
- text += " return 0;\n"
- text += "\n}\n\n"
-
- text += "void __cleanup_%s(void)\n{\n"%location_str
- text += self.CFile.cleanUpFunction.gettext()
- text += "\n}\n\n"
-
- text += "void __retrieve_%s(void)\n{\n"%location_str
- text += self.CFile.retrieveFunction.gettext()
- text += "\n}\n\n"
-
- text += "void __publish_%s(void)\n{\n"%location_str
- text += self.CFile.publishFunction.gettext()
- text += "\n}\n\n"
-
- Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str)
- cfile = open(Gen_Cfile_path,'w')
- cfile.write(text)
- cfile.close()
-
- matiec_flags = '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath())
-
- return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True
-
-
-#-------------------------------------------------------------------------------
-# Current Buffering Management Functions
-#-------------------------------------------------------------------------------
-
- """
- Return a copy of the cfile model
- """
- def Copy(self, model):
- return cPickle.loads(cPickle.dumps(model))
-
- def CreateCFileBuffer(self, saved):
- self.Buffering = False
- self.CFileBuffer = UndoBuffer(cPickle.dumps(self.CFile), saved)
-
- def BufferCFile(self):
- self.CFileBuffer.Buffering(cPickle.dumps(self.CFile))
-
- def StartBuffering(self):
- self.Buffering = True
-
- def EndBuffering(self):
- if self.Buffering:
- self.CFileBuffer.Buffering(cPickle.dumps(self.CFile))
- self.Buffering = False
-
- def MarkCFileAsSaved(self):
- self.EndBuffering()
- self.CFileBuffer.CurrentSaved()
-
- def CFileIsSaved(self):
- return self.CFileBuffer.IsCurrentSaved() and not self.Buffering
-
- def LoadPrevious(self):
- self.EndBuffering()
- self.CFile = cPickle.loads(self.CFileBuffer.Previous())
-
- def LoadNext(self):
- self.CFile = cPickle.loads(self.CFileBuffer.Next())
-
- def GetBufferState(self):
- first = self.CFileBuffer.IsFirst() and not self.Buffering
- last = self.CFileBuffer.IsLast()
- return not first, not last
-
-class RootClass:
-
- CTNChildrenTypes = [("C_File",_Cfile, "C file")]
-
- def CTNGenerate_C(self, buildpath, locations):
- return [],"",False
-
-
--- a/confnodes/c_ext/cext_xsd.xsd Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-<xsd:schema targetNamespace="cext_xsd.xsd"
- xmlns:cext="cext_xsd.xsd"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- elementFormDefault="qualified"
- attributeFormDefault="unqualified">
-
- <xsd:element name="CFile">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="includes" type="cext:CCode"/>
- <xsd:element name="variables">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="variable" minOccurs="0" maxOccurs="unbounded">
- <xsd:complexType>
- <xsd:attribute name="name" type="xsd:string" use="required"/>
- <xsd:attribute name="type" type="xsd:string" use="required"/>
- <xsd:attribute name="class" use="required">
- <xsd:simpleType>
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="input"/>
- <xsd:enumeration value="memory"/>
- <xsd:enumeration value="output"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:attribute>
- </xsd:complexType>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="globals" type="cext:CCode"/>
- <xsd:element name="initFunction" type="cext:CCode"/>
- <xsd:element name="cleanUpFunction" type="cext:CCode"/>
- <xsd:element name="retrieveFunction" type="cext:CCode"/>
- <xsd:element name="publishFunction" type="cext:CCode"/>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
- <xsd:complexType name="CCode">
- <xsd:annotation>
- <xsd:documentation>Formatted text according to parts of XHTML 1.1</xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:any namespace="http://www.w3.org/1999/xhtml" processContents="lax"/>
- </xsd:sequence>
- </xsd:complexType>
-</xsd:schema>
--- a/confnodes/canfestival/.cvsignore Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-*.pyc
--- a/confnodes/canfestival/NetworkEditor.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-import os, sys
-base_folder = os.path.split(sys.path[0])[0]
-CanFestivalPath = os.path.join(base_folder, "CanFestival-3")
-
-import wx
-
-from subindextable import EditingPanel
-from networkedit import NetworkEditorTemplate
-from controls import EditorPanel
-
-[ID_NETWORKEDITOR,
-] = [wx.NewId() for _init_ctrls in range(1)]
-
-[ID_NETWORKEDITORCONFNODEMENUADDSLAVE, ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE,
- ID_NETWORKEDITORCONFNODEMENUMASTER,
-] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(3)]
-
-[ID_NETWORKEDITORMASTERMENUNODEINFOS, ID_NETWORKEDITORMASTERMENUDS301PROFILE,
- ID_NETWORKEDITORMASTERMENUDS302PROFILE, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE,
- ID_NETWORKEDITORMASTERMENUADD,
-] = [wx.NewId() for _init_coll_MasterMenu_Items in range(5)]
-
-[ID_NETWORKEDITORADDMENUSDOSERVER, ID_NETWORKEDITORADDMENUSDOCLIENT,
- ID_NETWORKEDITORADDMENUPDOTRANSMIT, ID_NETWORKEDITORADDMENUPDORECEIVE,
- ID_NETWORKEDITORADDMENUMAPVARIABLE, ID_NETWORKEDITORADDMENUUSERTYPE,
-] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
-
-class NetworkEditor(EditorPanel, NetworkEditorTemplate):
-
- ID = ID_NETWORKEDITOR
-
- def _init_coll_MainSizer_Items(self, parent):
- parent.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW|wx.ALL)
-
- def _init_coll_MainSizer_Growables(self, parent):
- parent.AddGrowableCol(0)
- parent.AddGrowableRow(0)
-
- def _init_sizers(self):
- self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0)
-
- self._init_coll_MainSizer_Items(self.MainSizer)
- self._init_coll_MainSizer_Growables(self.MainSizer)
-
- self.Editor.SetSizer(self.MainSizer)
-
- def _init_Editor(self, prnt):
- self.Editor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
-
- NetworkEditorTemplate._init_ctrls(self, self.Editor)
-
- self._init_sizers()
-
- def __init__(self, parent, controler, window):
- EditorPanel.__init__(self, parent, "", window, controler)
- NetworkEditorTemplate.__init__(self, controler, window, False)
-
- img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
- self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
-
- self.RefreshNetworkNodes()
- self.RefreshBufferState()
-
- def __del__(self):
- self.Controler.OnCloseEditor(self)
-
- def GetConfNodeMenuItems(self):
- add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_NETWORKEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)),
- (wx.ITEM_NORMAL, (_('SDO Client'), ID_NETWORKEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)),
- (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_NETWORKEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)),
- (wx.ITEM_NORMAL, (_('PDO Receive'), ID_NETWORKEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)),
- (wx.ITEM_NORMAL, (_('Map Variable'), ID_NETWORKEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)),
- (wx.ITEM_NORMAL, (_('User Type'), ID_NETWORKEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))]
-
- profile = self.Manager.GetCurrentProfileName()
- if profile not in ("None", "DS-301"):
- other_profile_text = _("%s Profile") % profile
- add_menu.append((wx.ITEM_SEPARATOR, None))
- for text, indexes in self.Manager.GetCurrentSpecificMenu():
- add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text))))
- else:
- other_profile_text = _('Other Profile')
-
- master_menu = [(wx.ITEM_NORMAL, (_('Node infos'), ID_NETWORKEDITORMASTERMENUNODEINFOS, '', self.OnNodeInfosMenu)),
- (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_NETWORKEDITORMASTERMENUDS301PROFILE, '', self.OnCommunicationMenu)),
- (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_NETWORKEDITORMASTERMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)),
- (wx.ITEM_NORMAL, (other_profile_text, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)),
- (wx.ITEM_SEPARATOR, None),
- (add_menu, (_('Add'), ID_NETWORKEDITORMASTERMENUADD))]
-
- return [(wx.ITEM_NORMAL, (_('Add slave'), ID_NETWORKEDITORCONFNODEMENUADDSLAVE, '', self.OnAddSlaveMenu)),
- (wx.ITEM_NORMAL, (_('Remove slave'), ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, '', self.OnRemoveSlaveMenu)),
- (wx.ITEM_SEPARATOR, None),
- (master_menu, (_('Master'), ID_NETWORKEDITORCONFNODEMENUMASTER))]
-
- def RefreshMainMenu(self):
- pass
-
- def RefreshConfNodeMenu(self, confnode_menu):
- confnode_menu.Enable(ID_NETWORKEDITORCONFNODEMENUMASTER, self.NetworkNodes.GetSelection() == 0)
-
- def GetTitle(self):
- fullname = self.Controler.CTNFullName()
- if not self.Manager.CurrentIsSaved():
- return "~%s~" % fullname
- return fullname
-
- def RefreshView(self):
- self.RefreshCurrentIndexList()
-
- def RefreshBufferState(self):
- NetworkEditorTemplate.RefreshBufferState(self)
- self.ParentWindow.RefreshTitle()
- self.ParentWindow.RefreshFileMenu()
- self.ParentWindow.RefreshEditMenu()
- self.ParentWindow.RefreshPageTitles()
-
- def OnNodeSelectedChanged(self, event):
- NetworkEditorTemplate.OnNodeSelectedChanged(self, event)
- wx.CallAfter(self.ParentWindow.RefreshConfNodeMenu)
-
--- a/confnodes/canfestival/README Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-CANOpen
\ No newline at end of file
--- a/confnodes/canfestival/SlaveEditor.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-import os, sys
-base_folder = os.path.split(sys.path[0])[0]
-CanFestivalPath = os.path.join(base_folder, "CanFestival-3")
-
-import wx
-
-from subindextable import EditingPanel
-from nodeeditor import NodeEditorTemplate
-from controls import EditorPanel
-
-[ID_SLAVEEDITORCONFNODEMENUNODEINFOS, ID_SLAVEEDITORCONFNODEMENUDS301PROFILE,
- ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE,
- ID_SLAVEEDITORCONFNODEMENUADD,
-] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(5)]
-
-[ID_SLAVEEDITORADDMENUSDOSERVER, ID_SLAVEEDITORADDMENUSDOCLIENT,
- ID_SLAVEEDITORADDMENUPDOTRANSMIT, ID_SLAVEEDITORADDMENUPDORECEIVE,
- ID_SLAVEEDITORADDMENUMAPVARIABLE, ID_SLAVEEDITORADDMENUUSERTYPE,
-] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
-
-class SlaveEditor(EditorPanel, NodeEditorTemplate):
-
- def _init_Editor(self, prnt):
- self.Editor = EditingPanel(prnt, self, self.Controler, self.Editable)
-
- def __init__(self, parent, controler, window, editable=True):
- self.Editable = editable
- EditorPanel.__init__(self, parent, "", window, controler)
- NodeEditorTemplate.__init__(self, controler, window, False)
-
- img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
- self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
-
- def __del__(self):
- self.Controler.OnCloseEditor(self)
-
- def GetConfNodeMenuItems(self):
- if self.Editable:
- add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_SLAVEEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)),
- (wx.ITEM_NORMAL, (_('SDO Client'), ID_SLAVEEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)),
- (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_SLAVEEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)),
- (wx.ITEM_NORMAL, (_('PDO Receive'), ID_SLAVEEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)),
- (wx.ITEM_NORMAL, (_('Map Variable'), ID_SLAVEEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)),
- (wx.ITEM_NORMAL, (_('User Type'), ID_SLAVEEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))]
-
- profile = self.Controler.GetCurrentProfileName()
- if profile not in ("None", "DS-301"):
- other_profile_text = _("%s Profile") % profile
- add_menu.append((wx.ITEM_SEPARATOR, None))
- for text, indexes in self.Manager.GetCurrentSpecificMenu():
- add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text))))
- else:
- other_profile_text = _('Other Profile')
-
- return [(wx.ITEM_NORMAL, (_('Node infos'), ID_SLAVEEDITORCONFNODEMENUNODEINFOS, '', self.OnNodeInfosMenu)),
- (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_SLAVEEDITORCONFNODEMENUDS301PROFILE, '', self.OnCommunicationMenu)),
- (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)),
- (wx.ITEM_NORMAL, (other_profile_text, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)),
- (wx.ITEM_SEPARATOR, None),
- (add_menu, (_('Add'), ID_SLAVEEDITORCONFNODEMENUADD))]
- return []
-
- def RefreshConfNodeMenu(self, confnode_menu):
- confnode_menu.Enable(ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, False)
-
- def GetTitle(self):
- fullname = self.Controler.CTNFullName()
- if not self.Controler.CurrentIsSaved():
- return "~%s~" % fullname
- return fullname
-
- def RefreshView(self):
- self.Editor.RefreshIndexList()
-
- def RefreshCurrentIndexList(self):
- self.RefreshView()
-
- def RefreshBufferState(self):
- self.ParentWindow.RefreshTitle()
- self.ParentWindow.RefreshFileMenu()
- self.ParentWindow.RefreshEditMenu()
- self.ParentWindow.RefreshPageTitles()
-
--- a/confnodes/canfestival/__init__.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-from canfestival import *
--- a/confnodes/canfestival/canfestival.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,484 +0,0 @@
-import os, sys
-base_folder = os.path.split(sys.path[0])[0]
-CanFestivalPath = os.path.join(base_folder, "CanFestival-3")
-sys.path.append(os.path.join(CanFestivalPath, "objdictgen"))
-
-from nodelist import NodeList
-from nodemanager import NodeManager
-import config_utils, gen_cfile, eds_utils
-from networkedit import networkedit
-from objdictedit import objdictedit
-import canfestival_config as local_canfestival_config
-from ConfigTree import ConfigTreeNode
-from commondialogs import CreateNodeDialog
-import wx
-
-from SlaveEditor import SlaveEditor
-from NetworkEditor import NetworkEditor
-
-from gnosis.xml.pickle import *
-from gnosis.xml.pickle.util import setParanoia
-setParanoia(0)
-
-if wx.Platform == '__WXMSW__':
- DEFAULT_SETTINGS = {
- "CAN_Driver": "can_tcp_win32",
- "CAN_Device": "127.0.0.1",
- "CAN_Baudrate": "125K",
- "Slave_NodeId": 2,
- "Master_NodeId": 1,
- }
-else:
- DEFAULT_SETTINGS = {
- "CAN_Driver": "../CanFestival-3/drivers/can_socket/libcanfestival_can_socket.so",
- "CAN_Device": "vcan0",
- "CAN_Baudrate": "125K",
- "Slave_NodeId": 2,
- "Master_NodeId": 1,
- }
-
-#--------------------------------------------------
-# SLAVE
-#--------------------------------------------------
-
-class _SlaveCTN(NodeManager):
- XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="CanFestivalSlaveNode">
- <xsd:complexType>
- <xsd:attribute name="CAN_Device" type="xsd:string" use="optional" default="%(CAN_Device)s"/>
- <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
- <xsd:attribute name="NodeId" type="xsd:string" use="optional" default="%(Slave_NodeId)d"/>
- <xsd:attribute name="Sync_Align" type="xsd:integer" use="optional" default="0"/>
- <xsd:attribute name="Sync_Align_Ratio" use="optional" default="50">
- <xsd:simpleType>
- <xsd:restriction base="xsd:integer">
- <xsd:minInclusive value="1"/>
- <xsd:maxInclusive value="99"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:attribute>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- """ % DEFAULT_SETTINGS
-
- EditorType = SlaveEditor
-
- def __init__(self):
- # TODO change netname when name change
- NodeManager.__init__(self)
- odfilepath = self.GetSlaveODPath()
- if(os.path.isfile(odfilepath)):
- self.OpenFileInCurrent(odfilepath)
- else:
- self.FilePath = ""
- dialog = CreateNodeDialog(None, wx.OK)
- dialog.Type.Enable(False)
- dialog.GenSYNC.Enable(False)
- if dialog.ShowModal() == wx.ID_OK:
- name, id, nodetype, description = dialog.GetValues()
- profile, filepath = dialog.GetProfile()
- NMT = dialog.GetNMTManagement()
- options = dialog.GetOptions()
- self.CreateNewNode(name, # Name - will be changed at build time
- id, # NodeID - will be changed at build time
- "slave", # Type
- description,# description
- profile, # profile
- filepath, # prfile filepath
- NMT, # NMT
- options) # options
- else:
- self.CreateNewNode("SlaveNode", # Name - will be changed at build time
- 0x00, # NodeID - will be changed at build time
- "slave", # Type
- "", # description
- "None", # profile
- "", # prfile filepath
- "heartbeat", # NMT
- []) # options
- dialog.Destroy()
- self.OnCTNSave()
-
- def GetSlaveODPath(self):
- return os.path.join(self.CTNPath(), 'slave.od')
-
- def GetCanDevice(self):
- return self.CanFestivalSlaveNode.getCan_Device()
-
- def _OpenView(self):
- ConfigTreeNode._OpenView(self)
- if self._View is not None:
- self._View.SetBusId(self.GetCurrentLocation())
-
- ConfNodeMethods = [
- {"bitmap" : os.path.join("images", "NetworkEdit"),
- "name" : "Edit slave",
- "tooltip" : "Edit CanOpen slave with ObjdictEdit",
- "method" : "_OpenView"},
- ]
-
- def OnCTNClose(self):
- if self._View:
- self._View.Close()
-
- def CTNTestModified(self):
- return self.ChangesToSave or self.OneFileHasChanged()
-
- def OnCTNSave(self):
- return self.SaveCurrentInFile(self.GetSlaveODPath())
-
- def SetParamsAttribute(self, path, value):
- result = ConfigTreeNode.SetParamsAttribute(self, path, value)
-
- # Filter IEC_Channel and Name, that have specific behavior
- if path == "BaseParams.IEC_Channel" and self._View is not None:
- self._View.SetBusId(self.GetCurrentLocation())
-
- return result
-
- def CTNGenerate_C(self, buildpath, locations):
- """
- Generate C code
- @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5)
- @param locations: List of complete variables locations \
- [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
- "NAME" : name of the variable (generally "__IW0_1_2" style)
- "DIR" : direction "Q","I" or "M"
- "SIZE" : size "X", "B", "W", "D", "L"
- "LOC" : tuple of interger for IEC location (0,1,2,...)
- }, ...]
- @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
- """
- current_location = self.GetCurrentLocation()
- # define a unique name for the generated C file
- prefix = "_".join(map(str, current_location))
- Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix )
- # Create a new copy of the model
- slave = self.GetCurrentNodeCopy()
- slave.SetNodeName("OD_%s"%prefix)
- # allow access to local OD from Slave PLC
- pointers = config_utils.LocalODPointers(locations, current_location, slave)
- res = gen_cfile.GenerateFile(Gen_OD_path, slave, pointers)
- if res :
- raise Exception, res
- res = eds_utils.GenerateEDSFile(os.path.join(buildpath, "Slave_%s.eds"%prefix), slave)
- if res :
- raise Exception, res
- return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False
-
- def LoadPrevious(self):
- self.LoadCurrentPrevious()
-
- def LoadNext(self):
- self.LoadCurrentNext()
-
- def GetBufferState(self):
- return self.GetCurrentBufferState()
-
-#--------------------------------------------------
-# MASTER
-#--------------------------------------------------
-
-class MiniNodeManager(NodeManager):
-
- def __init__(self, parent, filepath, fullname):
- NodeManager.__init__(self)
-
- self.OpenFileInCurrent(filepath)
-
- self.Parent = parent
- self.Fullname = fullname
-
- def OnCloseEditor(self, view):
- self.Parent.OnCloseEditor(view)
-
- def CTNFullName(self):
- return self.Fullname
-
- def GetBufferState(self):
- return self.GetCurrentBufferState()
-
-class _NodeListCTN(NodeList):
- XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="CanFestivalNode">
- <xsd:complexType>
- <xsd:attribute name="CAN_Device" type="xsd:string" use="optional" default="%(CAN_Device)s"/>
- <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
- <xsd:attribute name="NodeId" type="xsd:string" use="optional" default="%(Master_NodeId)d"/>
- <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- """ % DEFAULT_SETTINGS
-
- EditorType = NetworkEditor
-
- def __init__(self):
- manager = NodeManager()
- NodeList.__init__(self, manager)
- self.LoadProject(self.CTNPath())
- self.SetNetworkName(self.BaseParams.getName())
-
- def GetCanDevice(self):
- return self.CanFestivalNode.getCan_Device()
-
- def SetParamsAttribute(self, path, value):
- result = ConfigTreeNode.SetParamsAttribute(self, path, value)
-
- # Filter IEC_Channel and Name, that have specific behavior
- if path == "BaseParams.IEC_Channel" and self._View is not None:
- self._View.SetBusId(self.GetCurrentLocation())
- elif path == "BaseParams.Name":
- self.SetNetworkName(value)
-
- return result
-
- def _OpenView(self):
- ConfigTreeNode._OpenView(self)
- if self._View is not None:
- self._View.SetBusId(self.GetCurrentLocation())
-
- _GeneratedView = None
- def _ShowMasterGenerated(self):
- if self._GeneratedView is None:
- buildpath = self._getBuildPath()
- # Eventually create build dir
- if not os.path.exists(buildpath):
- self.GetCTRoot().logger.write_error(_("Error: No PLC built\n"))
- return
-
- masterpath = os.path.join(buildpath, "MasterGenerated.od")
- if not os.path.exists(masterpath):
- self.GetCTRoot().logger.write_error(_("Error: No Master generated\n"))
- return
-
- app_frame = self.GetCTRoot().AppFrame
-
- manager = MiniNodeManager(self, masterpath, self.CTNFullName() + ".generated_master")
- self._GeneratedView = SlaveEditor(app_frame.TabsOpened, manager, app_frame, False)
-
- app_frame.EditProjectElement(self._GeneratedView, "MasterGenerated")
-
- def _CloseGenerateView(self):
- if self._GeneratedView is not None:
- app_frame = self.GetCTRoot().AppFrame
- if app_frame is not None:
- app_frame.DeletePage(self._GeneratedView)
-
- ConfNodeMethods = [
- {"bitmap" : os.path.join("images", "NetworkEdit"),
- "name" : _("Edit network"),
- "tooltip" : _("Edit CanOpen Network with NetworkEdit"),
- "method" : "_OpenView"},
- {"bitmap" : os.path.join("images", "ShowMaster"),
- "name" : _("Show Master"),
- "tooltip" : _("Show Master generated by config_utils"),
- "method" : "_ShowMasterGenerated"}
- ]
-
- def OnCloseEditor(self, view):
- ConfigTreeNode.OnCloseEditor(self, view)
- if self._GeneratedView == view:
- self._GeneratedView = None
-
- def OnCTNClose(self):
- ConfigTreeNode.OnCTNClose(self)
- self._CloseGenerateView()
- return True
-
- def CTNTestModified(self):
- return self.ChangesToSave or self.HasChanged()
-
- def OnCTNSave(self):
- self.SetRoot(self.CTNPath())
- return self.SaveProject() is None
-
- def CTNGenerate_C(self, buildpath, locations):
- """
- Generate C code
- @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5)
- @param locations: List of complete variables locations \
- [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
- "NAME" : name of the variable (generally "__IW0_1_2" style)
- "DIR" : direction "Q","I" or "M"
- "SIZE" : size "X", "B", "W", "D", "L"
- "LOC" : tuple of interger for IEC location (0,1,2,...)
- }, ...]
- @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
- """
- self._CloseGenerateView()
- current_location = self.GetCurrentLocation()
- # define a unique name for the generated C file
- prefix = "_".join(map(str, current_location))
- Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix )
- # Create a new copy of the model with DCF loaded with PDO mappings for desired location
- try:
- master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix)
- except config_utils.PDOmappingException, e:
- raise Exception, e.message
- # Do generate C file.
- res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers)
- if res :
- raise Exception, res
-
- file = open(os.path.join(buildpath, "MasterGenerated.od"), "w")
- dump(master, file)
- file.close()
-
- return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False
-
- def LoadPrevious(self):
- self.Manager.LoadCurrentPrevious()
-
- def LoadNext(self):
- self.Manager.LoadCurrentNext()
-
- def GetBufferState(self):
- return self.Manager.GetCurrentBufferState()
-
-class RootClass:
- XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="CanFestivalInstance">
- <xsd:complexType>
- <xsd:attribute name="CAN_Driver" type="xsd:string" use="optional" default="%(CAN_Driver)s"/>
- <xsd:attribute name="Debug_mode" type="xsd:boolean" use="optional" default="false"/>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- """ % DEFAULT_SETTINGS
-
- CTNChildrenTypes = [("CanOpenNode",_NodeListCTN, "CanOpen Master"),
- ("CanOpenSlave",_SlaveCTN, "CanOpen Slave")]
- def GetParamsAttributes(self, path = None):
- infos = ConfigTreeNode.GetParamsAttributes(self, path = None)
- for element in infos:
- if element["name"] == "CanFestivalInstance":
- for child in element["children"]:
- if child["name"] == "CAN_Driver":
- DLL_LIST= getattr(local_canfestival_config,"DLL_LIST",None)
- if DLL_LIST is not None:
- child["type"] = DLL_LIST
- return infos
-
- def GetCanDriver(self):
- can_driver = self.CanFestivalInstance.getCAN_Driver()
- if sys.platform == 'win32':
- if self.CanFestivalInstance.getDebug_mode() and os.path.isfile(os.path.join("%s"%(can_driver + '_DEBUG.dll'))):
- can_driver += '_DEBUG.dll'
- else:
- can_driver += '.dll'
- return can_driver
-
- def CTNGenerate_C(self, buildpath, locations):
-
- format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())),
- "candriver" : self.GetCanDriver(),
- "nodes_includes" : "",
- "board_decls" : "",
- "nodes_init" : "",
- "nodes_open" : "",
- "nodes_stop" : "",
- "nodes_close" : "",
- "nodes_send_sync" : "",
- "nodes_proceed_sync" : "",
- "slavebootups" : "",
- "slavebootup_register" : "",
- "post_sync" : "",
- "post_sync_register" : "",
- }
- for child in self.IECSortedChildren():
- childlocstr = "_".join(map(str,child.GetCurrentLocation()))
- nodename = "OD_%s" % childlocstr
-
- # Try to get Slave Node
- child_data = getattr(child, "CanFestivalSlaveNode", None)
- if child_data is None:
- # Not a slave -> master
- child_data = getattr(child, "CanFestivalNode")
- # Apply sync setting
- format_dict["nodes_init"] += 'NODE_MASTER_INIT(%s, %s)\n '%(
- nodename,
- child_data.getNodeId())
- if child_data.getSync_TPDOs():
- format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n '%(nodename)
- format_dict["nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n '%(nodename)
-
- # initialize and declare node boot status variables for post_SlaveBootup lookup
- SlaveIDs = child.GetSlaveIDs()
- if len(SlaveIDs) == 0:
- # define post_SlaveBootup lookup functions
- format_dict["slavebootups"] += (
- "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n"%(nodename))
- else:
- for id in SlaveIDs:
- format_dict["slavebootups"] += (
- "int %s_slave_%d_booted = 0;\n"%(nodename, id))
- # define post_SlaveBootup lookup functions
- format_dict["slavebootups"] += (
- "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"%(nodename)+
- " switch(nodeId){\n")
- # one case per declared node, mark node as booted
- for id in SlaveIDs:
- format_dict["slavebootups"] += (
- " case %d:\n"%(id)+
- " %s_slave_%d_booted = 1;\n"%(nodename, id)+
- " break;\n")
- format_dict["slavebootups"] += (
- " default:\n"+
- " break;\n"+
- " }\n"+
- " if( ")
- # expression to test if all declared nodes booted
- format_dict["slavebootups"] += " && ".join(["%s_slave_%d_booted"%(nodename, id) for id in SlaveIDs])
- format_dict["slavebootups"] += " )\n" + (
- " Master_post_SlaveBootup(d,nodeId);\n"+
- "}\n")
- # register previously declared func as post_SlaveBootup callback for that node
- format_dict["slavebootup_register"] += (
- "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n"%(nodename,nodename))
- else:
- # Slave node
- align = child_data.getSync_Align()
- align_ratio=child_data.getSync_Align_Ratio()
- if align > 0:
- format_dict["post_sync"] += (
- "static int %s_CalCount = 0;\n"%(nodename)+
- "static void %s_post_sync(CO_Data* d){\n"%(nodename)+
- " if(%s_CalCount < %d){\n"%(nodename, align)+
- " %s_CalCount++;\n"%(nodename)+
- " align_tick(-1);\n"+
- " }else{\n"+
- " align_tick(%d);\n"%(align_ratio)+
- " }\n"+
- "}\n")
- format_dict["post_sync_register"] += (
- "%s_Data.post_sync = %s_post_sync;\n"%(nodename,nodename))
- format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n '%(
- nodename,
- child_data.getNodeId())
-
- # Include generated OD headers
- format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename)
- # Declare CAN channels according user filled config
- format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n'%(
- nodename,
- child.GetCanDevice(),
- child_data.getCAN_Baudrate())
- format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename)
- format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename)
- format_dict["nodes_stop"] += 'NODE_STOP(%s)\n '%(nodename)
-
- filename = os.path.join(os.path.split(__file__)[0],"cf_runtime.c")
- cf_main = open(filename).read() % format_dict
- cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict)
- f = open(cf_main_path,'w')
- f.write(cf_main)
- f.close()
-
- return [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True
-
-
--- a/confnodes/canfestival/cf_runtime.c Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-
-#include "canfestival.h"
-
-/* CanFestival nodes generated OD headers*/
-%(nodes_includes)s
-
-#define BOARD_DECL(nodename, busname, baudrate)\
- s_BOARD nodename##Board = {busname, baudrate};
-
-/* CAN channels declaration */
-%(board_decls)s
-
-/* Keep track of init level to cleanup correctly */
-static int init_level=0;
-/* Retrieve PLC cycle time */
-extern int common_ticktime__;
-
-/* Called once all NetworkEdit declares slaves have booted*/
-static void Master_post_SlaveBootup(CO_Data* d, UNS8 nodeId)
-{
- /* Put the master in operational mode */
- setState(d, Operational);
-
- /* Ask slave node to go in operational mode */
- masterSendNMTstateChange (d, 0, NMT_Start_Node);
-}
-
-/* Per master node slavebootup callbacks. Checks that
- * every node have booted before calling Master_post_SlaveBootup */
-%(slavebootups)s
-
-/* One slave node post_sync callback.
- * Used to align PLC tick-time on CANopen SYNC
- */
-%(post_sync)s
-
-#define NODE_FORCE_SYNC(nodename) \
- /* Artificially force sync state to 1 so that it is not started */\
- nodename##_Data.CurrentCommunicationState.csSYNC = -1;\
- /* Force sync period to common_ticktime__ so that other node can read it*/\
- *nodename##_Data.COB_ID_Sync = 0x40000080;\
- *nodename##_Data.Sync_Cycle_Period = common_ticktime__ * 1000;
-
-#define NODE_INIT(nodename, nodeid) \
- /* Defining the node Id */\
- setNodeId(&nodename##_Data, nodeid);\
- /* init */\
- setState(&nodename##_Data, Initialisation);
-
-#define NODE_MASTER_INIT(nodename, nodeid) \
- NODE_FORCE_SYNC(nodename) \
- NODE_INIT(nodename, nodeid)
-
-#define NODE_SLAVE_INIT(nodename, nodeid) \
- NODE_INIT(nodename, nodeid)
-
-void InitNodes(CO_Data* d, UNS32 id)
-{
- %(slavebootup_register)s
- %(post_sync_register)s
- %(nodes_init)s
-}
-
-#define NODE_STOP(nodename) \
- if(init_level-- > 0)\
- {\
- masterSendNMTstateChange(&nodename##_Data, 0, NMT_Reset_Node);\
- setState(&nodename##_Data, Stopped);\
- }
-
-void Exit(CO_Data* d, UNS32 id)
-{
- %(nodes_stop)s
-}
-
-#define NODE_CLOSE(nodename) \
- if(init_level_c-- > 0)\
- {\
- canClose(&nodename##_Data);\
- }
-
-void __cleanup_%(locstr)s(void)
-{
- // Stop timer thread
- if(init_level-- > 0){
- int init_level_c = init_level;
- StopTimerLoop(&Exit);
- %(nodes_close)s
- }
-
- TimerCleanup();
-}
-
-#ifndef stderr
-#define fprintf(...)
-#define fflush(...)
-#endif
-
-#define NODE_OPEN(nodename)\
- if(!canOpen(&nodename##Board,&nodename##_Data)){\
- fprintf(stderr,"Cannot open CAN intefrace %%s at speed %%s\n for CANopen node \"" #nodename "\"",nodename##Board.busname, nodename##Board.baudrate);\
- fflush(stderr);\
- return -1;\
- }\
- init_level++;
-
-/*************************** INIT *****************************************/
-int __init_%(locstr)s(int argc,char **argv)
-{
-#ifndef NOT_USE_DYNAMIC_LOADING
- if( !LoadCanDriver("%(candriver)s") ){
- fprintf(stderr, "Cannot load CAN interface library for CanFestival (%(candriver)s)\n");\
- fflush(stderr);\
- return -1;\
- }
-#endif
-
- TimerInit();
-
- %(nodes_open)s
-
- // Start timer thread
- StartTimerLoop(&InitNodes);
- init_level++;
- return 0;
-}
-
-#define NODE_SEND_SYNC(nodename)\
- sendSYNCMessage(&nodename##_Data);
-
-void __retrieve_%(locstr)s(void)
-{
- /* Locks the stack, so that no changes occurs while PLC access variables
- * TODO : implement buffers to avoid such a big lock
- * */
- EnterMutex();
- /* Send Sync */
- %(nodes_send_sync)s
-}
-
-#define NODE_PROCEED_SYNC(nodename)\
- proceedSYNC(&nodename##_Data);
-
-void __publish_%(locstr)s(void)
-{
- /* Process sync event */
- %(nodes_proceed_sync)s
- LeaveMutex();
-}
-
--- a/confnodes/canfestival/config_utils.py Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,737 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-#This file is part of Beremiz, a Integrated Development Environment for
-#programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
-#
-#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
-#
-#See COPYING file for copyrights details.
-#
-#This library is free software; you can redistribute it and/or
-#modify it under the terms of the GNU General Public
-#License as published by the Free Software Foundation; either
-#version 2.1 of the License, or (at your option) any later version.
-#
-#This library is distributed in the hope that it will be useful,
-#but WITHOUT ANY WARRANTY; without even the implied warranty of
-#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-#General Public License for more details.
-#
-#You should have received a copy of the GNU General Public
-#License along with this library; if not, write to the Free Software
-#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-from types import *
-
-# Translation between IEC types and Can Open types
-IECToCOType = {"BOOL":0x01, "SINT":0x02, "INT":0x03,"DINT":0x04,"LINT":0x10,
- "USINT":0x05,"UINT":0x06,"UDINT":0x07,"ULINT":0x1B,"REAL":0x08,
- "LREAL":0x11,"STRING":0x09,"BYTE":0x05,"WORD":0x06,"DWORD":0x07,
- "LWORD":0x1B,"WSTRING":0x0B}
-
-# Constants for PDO types
-RPDO = 1
-TPDO = 2
-
-SlavePDOType = {"I" : TPDO, "Q" : RPDO}
-InvertPDOType = {RPDO : TPDO, TPDO : RPDO}
-PDOTypeBaseIndex = {RPDO : 0x1400, TPDO : 0x1800}
-PDOTypeBaseCobId = {RPDO : 0x200, TPDO : 0x180}
-
-VariableIncrement = 0x100
-VariableStartIndex = {TPDO : 0x2000, RPDO : 0x4000}
-VariableDirText = {TPDO : "__I", RPDO : "__Q"}
-VariableTypeOffset = dict(zip(["","X","B","W","D","L"], range(6)))
-
-TrashVariables = [(1, 0x01), (8, 0x05), (16, 0x06), (32, 0x07), (64, 0x1B)]
-
-#-------------------------------------------------------------------------------
-# Specific exception for PDO mapping errors
-#-------------------------------------------------------------------------------
-
-class PDOmappingException(Exception):
- pass
-
-
-def LE_to_BE(value, size):
- """
- Convert Little Endian to Big Endian
- @param value: value expressed in integer
- @param size: number of bytes generated
- @return: a string containing the value converted
- """
-
- data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
- list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
- list_car.reverse()
- return "".join([chr(int(car, 16)) for car in list_car])
-
-
-def GetNodePDOIndexes(node, type, parameters = False):
- """
- Find the PDO indexes of a node
- @param node: node
- @param type: type of PDO searched (RPDO or TPDO or both)
- @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
- @return: a list of indexes found
- """
-
- indexes = []
- if type & RPDO:
- indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF])
- if type & TPDO:
- indexes.extend([idx for idx in node.GetIndexes() if 0x1800 <= idx <= 0x19FF])
- if not parameters:
- return [idx + 0x200 for idx in indexes]
- else:
- return indexes
-
-
-def SearchNodePDOMapping(loc_infos, node):
- """
- Find the PDO indexes of a node
- @param node: node
- @param type: type of PDO searched (RPDO or TPDO or both)
- @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
- @return: a list of indexes found
- """
-
- model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8)
-
- for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]):
- values = node.GetEntry(PDOidx)
- if values != None:
- for subindex, mapping in enumerate(values):
- if subindex != 0 and mapping & 0xFFFFFF00 == model:
- return PDOidx, subindex
- return None
-
-
-def GeneratePDOMappingDCF(idx, cobid, transmittype, pdomapping):
- """
- Build concise DCF value for configuring a PDO
- @param idx: index of PDO parameters
- @param cobid: PDO generated COB ID
- @param transmittype : PDO transmit type
- @param pdomapping: list of PDO mappings
- @return: a tuple of value and number of parameters to add to DCF
- """
-
- # Create entry for RPDO or TPDO parameters and Disable PDO
- dcfdata = LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x80000000 + cobid, 4)
- # Set Transmit type synchrone
- dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x02, 1) + LE_to_BE(0x01, 4) + LE_to_BE(transmittype, 1)
- # Re-Enable PDO
- # ---- INDEX ----- --- SUBINDEX ---- ----- SIZE ------ ------ DATA ------
- dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(cobid, 4)
- nbparams = 3
- if len(pdomapping) > 0:
- dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(0x00, 1) + LE_to_BE(0x01, 4) + LE_to_BE(len(pdomapping), 1)
- nbparams += 1
- # Map Variables
- for subindex, (name, loc_infos) in enumerate(pdomapping):
- value = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) + loc_infos["size"]
- dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(subindex + 1, 1) + LE_to_BE(0x04, 4) + LE_to_BE(value, 4)
- nbparams += 1
- return dcfdata, nbparams
-
-class ConciseDCFGenerator:
-
- def __init__(self, nodelist, nodename):
- # Dictionary of location informations classed by name
- self.IECLocations = {}
- # Dictionary of location that have not been mapped yet
- self.LocationsNotMapped = {}
- # Dictionary of location informations classed by name
- self.MasterMapping = {}
- # List of COB IDs available
- self.ListCobIDAvailable = range(0x180, 0x580)
- # Dictionary of mapping value where unexpected variables are stored
- self.TrashVariables = {}
- # Dictionary of pointed variables
- self.PointedVariables = {}
-
- self.NodeList = nodelist
- self.Manager = self.NodeList.Manager
- self.MasterNode = self.Manager.GetCurrentNodeCopy()
- self.MasterNode.SetNodeName(nodename)
- self.PrepareMasterNode()
-
- def GetPointedVariables(self):
- return self.PointedVariables
-
- def RemoveUsedNodeCobId(self, node):
- """
- Remove all PDO COB ID used by the given node from the list of available COB ID
- @param node: node
- @return: a tuple of number of RPDO and TPDO for the node
- """
-
- # Get list of all node TPDO and RPDO indexes
- nodeRpdoIndexes = GetNodePDOIndexes(node, RPDO, True)
- nodeTpdoIndexes = GetNodePDOIndexes(node, TPDO, True)
-
- # Mark all the COB ID of the node already mapped PDO as not available
- for PdoIdx in nodeRpdoIndexes + nodeTpdoIndexes:
- pdo_cobid = node.GetEntry(PdoIdx, 0x01)
- # Extract COB ID, if PDO isn't active
- if pdo_cobid > 0x600 :
- pdo_cobid -= 0x80000000
- # Remove COB ID from the list of available COB ID
- if pdo_cobid in self.ListCobIDAvailable:
- self.ListCobIDAvailable.remove(pdo_cobid)
-
- return len(nodeRpdoIndexes), len(nodeTpdoIndexes)
-
-
- def PrepareMasterNode(self):
- """
- Add mandatory entries for DCF generation into MasterNode.
- """
-
- # Adding DCF entry into Master node
- if not self.MasterNode.IsEntry(0x1F22):
- self.MasterNode.AddEntry(0x1F22, 1, "")
- self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode)
-
- # Adding trash mappable variables for unused mapped datas
- idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID()
- # Add an entry for storing unexpected all variable
- self.Manager.AddMapVariableToCurrent(idxTrashVariables, self.MasterNode.GetNodeName()+"_trashvariables", 3, len(TrashVariables), self.MasterNode)
- for subidx, (size, typeidx) in enumerate(TrashVariables):
- # Add a subentry for storing unexpected variable of this size
- self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode)
- self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode)
- # Store the mapping value for this entry
- self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size
-
- RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode)
-
- # Store the indexes of the first RPDO and TPDO available for MasterNode
- self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber}
-
- # Prepare MasterNode with all nodelist slaves
- for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()):
- node = nodeinfos["Node"]
- node.SetNodeID(nodeid)
-
- RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node)
-
- # Get Slave's default SDO server parameters
- RSDO_cobid = node.GetEntry(0x1200,0x01)
- if not RSDO_cobid:
- RSDO_cobid = 0x600 + nodeid
- TSDO_cobid = node.GetEntry(0x1200,0x02)
- if not TSDO_cobid:
- TSDO_cobid = 0x580 + nodeid
-
- # Configure Master's SDO parameters entries
- self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode)
- self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid)
- self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid)
- self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid)
-
-
- def GetMasterNode(self):
- """
- Return MasterNode.
- """
- return self.MasterNode
-
- def AddParamsToDCF(self, nodeid, data, nbparams):
- """
- Add entry to DCF, for the requested nodeID
- @param nodeid: id of the slave (int)
- @param data: data to add to slave DCF (string)
- @param nbparams: number of params added to slave DCF (int)
- """
- # Get current DCF for slave
- nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid)
-
- # Extract data and number of params in current DCF
- if nodeDCF != None and nodeDCF != '':
- tmpnbparams = [i for i in nodeDCF[:4]]
- tmpnbparams.reverse()
- nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
- data = nodeDCF[4:] + data
-
- # Build new DCF
- dcf = LE_to_BE(nbparams, 0x04) + data
- # Set new DCF for slave
- self.MasterNode.SetEntry(0x1F22, nodeid, dcf)
-
- def GetEmptyPDO(self, nodeid, pdotype, start_index=None):
- """
- Search a not configured PDO for a slave
- @param node: the slave node object
- @param pdotype: type of PDO to generated (RPDO or TPDO)
- @param start_index: Index where search must start (default: None)
- @return tuple of PDO index, COB ID and number of subindex defined
- """
- # If no start_index defined, start with PDOtype base index
- if start_index is None:
- index = PDOTypeBaseIndex[pdotype]
- else:
- index = start_index
-
- # Search for all PDO possible index until find a configurable PDO
- # starting from start_index
- while index < PDOTypeBaseIndex[pdotype] + 0x200:
- values = self.NodeList.GetSlaveNodeEntry(nodeid, index + 0x200)
- if values != None and values[0] > 0:
- # Check that all subindex upper than 0 equal 0 => configurable PDO
- if reduce(lambda x, y: x and y, map(lambda x: x == 0, values[1:]), True):
- cobid = self.NodeList.GetSlaveNodeEntry(nodeid, index, 1)
- # If no COB ID defined in PDO, generate a new one (not used)
- if cobid == 0:
- if len(self.ListCobIDAvailable) == 0:
- return None
- # Calculate COB ID from standard values
- if index < PDOTypeBaseIndex[pdotype] + 4:
- cobid = PDOTypeBaseCobId[pdotype] + 0x100 * (index - PDOTypeBaseIndex[pdotype]) + nodeid
- if cobid not in self.ListCobIDAvailable:
- cobid = self.ListCobIDAvailable.pop(0)
- return index, cobid, values[0]
- index += 1
- return None
-
- def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs):
- """
- Record a new mapping request for a slave, and add related slave config to the DCF
- @param nodeid: id of the slave (int)
- @param pdotype: type of PDO to generated (RPDO or TPDO)
- @param pdomapping: list od variables to map with PDO
- """
- # Add an entry to MasterMapping
- self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype],
- "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]}
-
- # Return the data to add to DCF
- if sync_TPDOs:
- return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping)
- else:
- return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping)
- return 0, ""
-
- def GenerateDCF(self, locations, current_location, sync_TPDOs):
- """
- Generate Concise DCF of MasterNode for the locations list given
- @param locations: list of locations to be mapped
- @param current_location: tuple of the located prefixes not to be considered
- @param sync_TPDOs: indicate if TPDO must be synchronous
- """
-
- #-------------------------------------------------------------------------------
- # Verify that locations correspond to real slave variables
- #-------------------------------------------------------------------------------
-
- # Get list of locations check if exists and mappables -> put them in IECLocations
- for location in locations:
- COlocationtype = IECToCOType[location["IEC_TYPE"]]
- name = location["NAME"]
- if name in self.IECLocations:
- if self.IECLocations[name]["type"] != COlocationtype:
- raise PDOmappingException, _("Type conflict for location \"%s\"") % name
- else:
- # Get only the part of the location that concern this node
- loc = location["LOC"][len(current_location):]
- # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
- if len(loc) not in (2, 3, 4):
- raise PDOmappingException, _("Bad location size : %s") % str(loc)
- elif len(loc) == 2:
- continue
-
- direction = location["DIR"]
-
- sizelocation = location["SIZE"]
-
- # Extract and check nodeid
- nodeid, index, subindex = loc[:3]
-
- # Check Id is in slave node list
- if nodeid not in self.NodeList.SlaveNodes.keys():
- raise PDOmappingException, _("Non existing node ID : %d (variable %s)") % (nodeid,name)
-
- # Get the model for this node (made from EDS)
- node = self.NodeList.SlaveNodes[nodeid]["Node"]
-
- # Extract and check index and subindex
- if not node.IsEntry(index, subindex):
- raise PDOmappingException, _("No such index/subindex (%x,%x) in ID : %d (variable %s)") % (index,subindex,nodeid,name)
-
- # Get the entry info
- subentry_infos = node.GetSubentryInfos(index, subindex)
-
- # If a PDO mappable
- if subentry_infos and subentry_infos["pdo"]:
- if sizelocation == "X" and len(loc) > 3:
- numbit = loc[3]
- elif sizelocation != "X" and len(loc) > 3:
- raise PDOmappingException, _("Cannot set bit offset for non bool '%s' variable (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex)
- else:
- numbit = None
-
- if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype:
- raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name)
-
- typeinfos = node.GetEntryInfos(COlocationtype)
- self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction],
- "nodeid": nodeid, "index": index,"subindex": subindex,
- "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation}
- else:
- raise PDOmappingException, _("Not PDO mappable variable : '%s' (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex)
-
- #-------------------------------------------------------------------------------
- # Search for locations already mapped
- #-------------------------------------------------------------------------------
-
- for name, locationinfos in self.IECLocations.items():
- node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"]
-
- # Search if slave has a PDO mapping this locations
- result = SearchNodePDOMapping(locationinfos, node)
- if result != None:
- index, subindex = result
- # Get COB ID of the PDO
- cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1)
-
- # Add PDO to MasterMapping
- if cobid not in self.MasterMapping.keys():
- # Verify that PDO transmit type is conform to sync_TPDOs
- transmittype = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2)
- if sync_TPDOs and transmittype != 0x01 or transmittype != 0xFF:
- if sync_TPDOs:
- # Change TransmitType to SYNCHRONE
- data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0x01, [])
- else:
- # Change TransmitType to ASYCHRONE
- data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, [])
-
- # Add entry to slave dcf to change transmit type of
- self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams)
-
- mapping = [None]
- values = node.GetEntry(index)
- # Store the size of each entry mapped in PDO
- for value in values[1:]:
- if value != 0:
- mapping.append(value % 0x100)
- self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping}
-
- # Indicate that this PDO entry must be saved
- if locationinfos["bit"] is not None:
- if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType):
- self.MasterMapping[cobid]["mapping"][subindex] = [1] * self.MasterMapping[cobid]["mapping"][subindex]
- if locationinfos["bit"] < len(self.MasterMapping[cobid]["mapping"][subindex]):
- self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name)
- else:
- self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name)
-
- else:
- # Add location to those that haven't been mapped yet
- if locationinfos["nodeid"] not in self.LocationsNotMapped.keys():
- self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []}
- self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos))
-
- #-------------------------------------------------------------------------------
- # Build concise DCF for the others locations
- #-------------------------------------------------------------------------------
-
- for nodeid, locations in self.LocationsNotMapped.items():
- node = self.NodeList.SlaveNodes[nodeid]["Node"]
-
- # Initialize number of params and data to add to node DCF
- nbparams = 0
- dataparams = ""
-
- # Generate the best PDO mapping for each type of PDO
- for pdotype in (TPDO, RPDO):
- if len(locations[pdotype]) > 0:
- pdosize = 0
- pdomapping = []
- result = self.GetEmptyPDO(nodeid, pdotype)
- if result is None:
- raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid
- pdoindex, pdocobid, pdonbparams = result
- for name, loc_infos in locations[pdotype]:
- pdosize += loc_infos["size"]
- # If pdo's size > 64 bits
- if pdosize > 64 or len(pdomapping) >= pdonbparams:
- # Generate a new PDO Mapping
- data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs)
- dataparams += data
- nbparams += nbaddedparams
- pdosize = loc_infos["size"]
- pdomapping = [(name, loc_infos)]
- result = self.GetEmptyPDO(nodeid, pdotype, pdoindex + 1)
- if result is None:
- raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid
- pdoindex, pdocobid, pdonbparams = result
- else:
- pdomapping.append((name, loc_infos))
- # If there isn't locations yet but there is still a PDO to generate
- if len(pdomapping) > 0:
- # Generate a new PDO Mapping
- data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs)
- dataparams += data
- nbparams += nbaddedparams
-
- # Add number of params and data to node DCF
- self.AddParamsToDCF(nodeid, dataparams, nbparams)
-
- #-------------------------------------------------------------------------------
- # Master Node Configuration
- #-------------------------------------------------------------------------------
-
- # Generate Master's Configuration from informations stored in MasterMapping
- for cobid, pdo_infos in self.MasterMapping.items():
- # Get next PDO index in MasterNode for this PDO type
- current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]]
-
- # Search if there is already a PDO in MasterNode with this cob id
- for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True):
- if self.MasterNode.GetEntry(idx, 1) == cobid:
- current_idx = idx
-
- # Add a PDO to MasterNode if not PDO have been found
- if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]:
- addinglist = [current_idx, current_idx + 0x200]
- self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode)
- self.MasterNode.SetEntry(current_idx, 0x01, cobid)
-
- # Increment the number of PDO for this PDO type
- self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1
-
- # Change the transmit type of the PDO
- if sync_TPDOs:
- self.MasterNode.SetEntry(current_idx, 0x02, 0x01)
- else:
- self.MasterNode.SetEntry(current_idx, 0x02, 0xFF)
-
- mapping = []
- for item in pdo_infos["mapping"]:
- if isinstance(item, ListType):
- mapping.extend(item)
- else:
- mapping.append(item)
-
- # Add some subentries to PDO mapping if there is not enough
- if len(mapping) > 1:
- self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(mapping) - 1, self.MasterNode)
-
- # Generate MasterNode's PDO mapping
- for subindex, variable in enumerate(mapping):
- if subindex == 0:
- continue
- new_index = False
-
- if isinstance(variable, (IntType, LongType)):
- # If variable is an integer then variable is unexpected
- self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable])
- else:
- typeidx, varname = variable
- variable_infos = self.IECLocations[varname]
-
- # Calculate base index for storing variable
- mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \
- VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \
- variable_infos["nodeid"]
-
- # Generate entry name
- indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]],
- variable_infos["sizelocation"],
- '_'.join(map(str,current_location)),
- variable_infos["nodeid"])
-
- # Search for an entry that has an empty subindex
- while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
- # Entry doesn't exist
- if not self.MasterNode.IsEntry(mapvariableidx):
- # Add entry to MasterNode
- self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode)
- new_index = True
- nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
- else:
- # Get Number of subentries already defined
- nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
- # if entry is full, go to next entry possible or stop now
- if nbsubentries == 0xFF:
- mapvariableidx += 8 * VariableIncrement
- else:
- break
-
- # Verify that a not full entry has been found
- if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
- # Generate subentry name
- if variable_infos["bit"] != None:
- subindexname = "%(index)d_%(subindex)d_%(bit)d"%variable_infos
- else:
- subindexname = "%(index)d_%(subindex)d"%variable_infos
- # If entry have just been created, no subentry have to be added
- if not new_index:
- self.Manager.AddSubentriesToCurrent(mapvariableidx, 1, self.MasterNode)
- nbsubentries += 1
- # Add informations to the new subentry created
- self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname})
- self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx})
-
- # Set value of the PDO mapping
- typeinfos = self.Manager.GetEntryInfos(typeidx)
- if typeinfos != None:
- value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"]
- self.MasterNode.SetEntry(current_idx + 0x200, subindex, value)
-
- # Add variable to pointed variables
- self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s"%(indexname, subindexname)
-
-def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename):
- """
- Fills a CanFestival network editor model, with DCF with requested PDO mappings.
- @param locations: List of complete variables locations \
- [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
- "NAME" : name of the variable (generally "__IW0_1_2" style)
- "DIR" : direction "Q","I" or "M"
- "SIZE" : size "X", "B", "W", "D", "L"
- "LOC" : tuple of interger for IEC location (0,1,2,...)
- }, ...]
- @param nodelist: CanFestival network editor model
- @return: a modified copy of the given CanFestival network editor model
- """
-
- dcfgenerator = ConciseDCFGenerator(nodelist, nodename)
- dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs)
- masternode,pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables()
- # allow access to local OD from Master PLC
- pointers.update(LocalODPointers(locations, current_location, masternode))
- return masternode,pointers
-
-def LocalODPointers(locations, current_location, slave):
- IECLocations = {}
- pointers = {}
- for location in locations:
- COlocationtype = IECToCOType[location["IEC_TYPE"]]
- name = location["NAME"]
- if name in IECLocations:
- if IECLocations[name] != COlocationtype:
- raise PDOmappingException, _("Type conflict for location \"%s\"") % name
- else:
- # Get only the part of the location that concern this node
- loc = location["LOC"][len(current_location):]
- # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
- if len(loc) not in (2, 3, 4):
- raise PDOmappingException, _("Bad location size : %s") % str(loc)
- elif len(loc) != 2:
- continue
-
- # Extract and check nodeid
- index, subindex = loc[:2]
-
- # Extract and check index and subindex
- if not slave.IsEntry(index, subindex):
- raise PDOmappingException, _("No such index/subindex (%x,%x) (variable %s)") % (index, subindex, name)
-
- # Get the entry info
- subentry_infos = slave.GetSubentryInfos(index, subindex)
- if subentry_infos["type"] != COlocationtype:
- raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name)
-
- IECLocations[name] = COlocationtype
- pointers[(index, subindex)] = name
- return pointers
-
-if __name__ == "__main__":
- import os, sys, getopt
-
- def usage():
- print """
-Usage of config_utils.py test :
-
- %s [options]
-
-Options:
- --help (-h)
- Displays help informations for config_utils
-
- --reset (-r)
- Reset the reference result of config_utils test.
- Use with caution. Be sure that config_utils
- is currently working properly.
-"""%sys.argv[0]
-
- # Boolean that indicate if reference result must be redefined
- reset = False
-
- # Extract command options
- try:
- opts, args = getopt.getopt(sys.argv[1:], "hr", ["help","reset"])
- except getopt.GetoptError:
- # print help information and exit:
- usage()
- sys.exit(2)
-
- # Test each option
- for o, a in opts:
- if o in ("-h", "--help"):
- usage()
- sys.exit()
- elif o in ("-r", "--reset"):
- reset = True
-
- # Extract workspace base folder
- base_folder = sys.path[0]
- for i in xrange(3):
- base_folder = os.path.split(base_folder)[0]
- # Add CanFestival folder to search pathes
- sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
-
- from nodemanager import *
- from nodelist import *
-
- # Open the test nodelist contained into test_config folder
- manager = NodeManager()
- nodelist = NodeList(manager)
- result = nodelist.LoadProject("test_config")
-
- # List of locations, we try to map for test
- locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)},
- {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)},
- {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_3","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,3)},
- {"IEC_TYPE":"INT","NAME":"__QW0_1_64_25617_2","DIR":"Q","SIZE":"W","LOC":(0,1,64,25617,1)},
- {"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24578_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24578,1)},
- {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_1","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,1)},
- {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_2","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,2)},
- {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)},
- {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)},
- {"IEC_TYPE":"UDINT","NAME":"__ID0_1_4096_0","DIR":"I","SIZE":"D","LOC":(0,1,4096,0)}]
-
- # Generate MasterNode configuration
- try:
- masternode, pointedvariables = GenerateConciseDCF(locations, (0, 1), nodelist, True, "TestNode")
- except ValueError, message:
- print "%s\nTest Failed!"%message
- sys.exit()
-
- import pprint
- # Get Text corresponding to MasterNode
- result_node = masternode.PrintString()
- result_vars = pprint.pformat(pointedvariables)
- result = result_node + "\n********POINTERS*********\n" + result_vars + "\n"
-
- # If reset has been choosen
- if reset:
- # Write Text into reference result file
- testfile = open("test_config/result.txt", "w")
- testfile.write(result)
- testfile.close()
-
- print "Reset Successful!"
- else:
- import os
-
- testfile = open("test_config/result_tmp.txt", "w")
- testfile.write(result)
- testfile.close()
-
- os.system("diff test_config/result.txt test_config/result_tmp.txt")
- os.remove("test_config/result_tmp.txt")
--- a/confnodes/canfestival/test_config/eds/PEAK MicroMod.eds Tue May 08 16:31:12 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1289 +0,0 @@
-[FileInfo]
-CreatedBy=ESAcademy
-ModifiedBy=ESAcademy
-Description=PEAK MicroMod CANopenIA Generic
-CreationTime=09:41PM
-CreationDate=05-05-2003
-ModificationTime=05:05PM
-ModificationDate=03-23-2005
-FileName=C:\CANopenCT\Tests\PEAK MicroMod.eds
-FileVersion=1
-FileRevision=1
-EDSVersion=4
-
-[DeviceInfo]
-VendorName=PEAK System Technik
-VendorNumber=0x00000175
-ProductName=PEAK MicroMod CANopenIA Generic
-ProductNumber=0x00100000
-RevisionNumber=0x00010001
-OrderCode=na
-BaudRate_10=0
-BaudRate_20=0
-BaudRate_50=1
-BaudRate_125=1
-BaudRate_250=1
-BaudRate_500=1
-BaudRate_800=1
-BaudRate_1000=1
-SimpleBootUpMaster=0
-SimpleBootUpSlave=1
-Granularity=0
-DynamicChannelsSupported=0
-CompactPDO=0
-GroupMessaging=0
-NrOfRXPDO=4
-NrOfTXPDO=4
-LSS_Supported=0
-
-[DummyUsage]
-Dummy0001=0
-Dummy0002=0
-Dummy0003=0
-Dummy0004=0
-Dummy0005=1
-Dummy0006=1
-Dummy0007=1
-
-[Comments]
-Lines=0
-
-[MandatoryObjects]
-SupportedObjects=3
-1=0x1000
-2=0x1001
-3=0x1018
-
-[1000]
-ParameterName=Device Type
-ObjectType=0x7
-DataType=0x0007
-AccessType=ro
-DefaultValue=0x000F0191
-PDOMapping=0
-
-[1001]
-ParameterName=Error Register
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=0
-PDOMapping=0
-
-[1018]
-ParameterName=Identity Object
-ObjectType=0x9
-SubNumber=4
-
-[1018sub0]
-ParameterName=number of entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=3
-PDOMapping=0
-
-[1018sub1]
-ParameterName=Vendor ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=ro
-DefaultValue=0x00000175
-PDOMapping=0
-
-[1018sub2]
-ParameterName=Product Code
-ObjectType=0x7
-DataType=0x0007
-AccessType=ro
-DefaultValue=0x00100000
-PDOMapping=0
-
-[1018sub3]
-ParameterName=Revision number
-ObjectType=0x7
-DataType=0x0007
-AccessType=ro
-DefaultValue=0x00010001
-PDOMapping=0
-
-[OptionalObjects]
-SupportedObjects=41
-1=0x1002
-2=0x1005
-3=0x1008
-4=0x1009
-5=0x100A
-6=0x100C
-7=0x100D
-8=0x1010
-9=0x1011
-10=0x1016
-11=0x1017
-12=0x1020
-13=0x1400
-14=0x1401
-15=0x1402
-16=0x1403
-17=0x1600
-18=0x1601
-19=0x1602
-20=0x1603
-21=0x1800
-22=0x1801
-23=0x1802
-24=0x1803
-25=0x1A00
-26=0x1A01
-27=0x1A02
-28=0x1A03
-29=0x1F50
-30=0x6000
-31=0x6002
-32=0x6200
-33=0x6202
-34=0x6206
-35=0x6207
-36=0x6401
-37=0x6411
-38=0x6423
-39=0x6426
-40=0x6443
-41=0x6444
-
-[1002]
-ParameterName=PEAK Status Register
-ObjectType=0x7
-DataType=0x0007
-AccessType=ro
-PDOMapping=0
-
-[1005]
-ParameterName=COB-ID SYNC
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x00000080
-PDOMapping=0
-
-[1008]
-ParameterName=Manufacturer Device Name
-ObjectType=0x7
-DataType=0x0009
-AccessType=const
-PDOMapping=0
-
-[1009]
-ParameterName=Manufacturer Hardware Version
-ObjectType=0x7
-DataType=0x0009
-AccessType=const
-PDOMapping=0
-
-[100a]
-ParameterName=Manufacturer Software Version
-ObjectType=0x7
-DataType=0x0009
-AccessType=const
-PDOMapping=0
-
-[100c]
-ParameterName=Guard Time
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[100d]
-ParameterName=Life Time Factor
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0x00
-PDOMapping=0
-
-[1010]
-ParameterName=Store Parameter Field
-ObjectType=0x8
-SubNumber=2
-
-[1010sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[1010sub1]
-ParameterName=Save all Parameters
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-PDOMapping=0
-
-[1011]
-ParameterName=Restore Default Parameters
-ObjectType=0x8
-SubNumber=2
-
-[1011sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[1011sub1]
-ParameterName=Restore all Default Parameters
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-PDOMapping=0
-
-[1016]
-ParameterName=Consumer Heartbeat Time
-ObjectType=0x8
-SubNumber=4
-
-[1016sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=3
-PDOMapping=0
-LowLimit=0x1
-
-[1016sub1]
-ParameterName=Consumer Heartbeat Time
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1016sub2]
-ParameterName=Consumer Heartbeat Time
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1016sub3]
-ParameterName=Consumer Heartbeat Time
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1017]
-ParameterName=Producer Heartbeat Time
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1020]
-ParameterName=Verify Configuration
-ObjectType=0x8
-SubNumber=3
-
-[1020sub0]
-ParameterName=Number of entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=2
-PDOMapping=0
-
-[1020sub1]
-ParameterName=Configuration date
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-PDOMapping=0
-
-[1020sub2]
-ParameterName=Configuration time
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-PDOMapping=0
-
-[1400]
-ParameterName=Receive PDO Communication Parameter
-ObjectType=0x9
-SubNumber=3
-
-[1400sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=2
-PDOMapping=0
-
-[1400sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x200
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1400sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1401]
-ParameterName=Receive PDO Communication Parameter
-ObjectType=0x9
-SubNumber=3
-
-[1401sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=2
-PDOMapping=0
-
-[1401sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x300
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1401sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1402]
-ParameterName=Receive PDO Communication Parameter
-ObjectType=0x9
-SubNumber=3
-
-[1402sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=2
-PDOMapping=0
-LowLimit=0x02
-HighLimit=0x05
-
-[1402sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x80000400
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1402sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1403]
-ParameterName=Receive PDO Communication Parameter
-ObjectType=0x9
-SubNumber=3
-
-[1403sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=2
-PDOMapping=0
-LowLimit=0x02
-HighLimit=0x05
-
-[1403sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x80000500
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1403sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1600]
-ParameterName=Receive PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=2
-
-[1600sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=1
-PDOMapping=0
-
-[1600sub1]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x62000108
-PDOMapping=0
-
-[1601]
-ParameterName=Receive PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=5
-
-[1601sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=4
-PDOMapping=0
-
-[1601sub1]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64110110
-PDOMapping=0
-
-[1601sub2]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64110210
-PDOMapping=0
-
-[1601sub3]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64110310
-PDOMapping=0
-
-[1601sub4]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64110410
-PDOMapping=0
-
-[1602]
-ParameterName=Receive PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=1
-
-[1602sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1603]
-ParameterName=Receive PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=1
-
-[1603sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1800]
-ParameterName=Transmit PDO Communication Parameter
-ObjectType=0x9
-SubNumber=5
-
-[1800sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=5
-PDOMapping=0
-LowLimit=0x02
-HighLimit=0x05
-
-[1800sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x180
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1800sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1800sub3]
-ParameterName=Inhibit Time
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0x0000
-PDOMapping=0
-
-[1800sub5]
-ParameterName=Event Timer
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1801]
-ParameterName=Transmit PDO Communication Parameter
-ObjectType=0x9
-SubNumber=5
-
-[1801sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=5
-PDOMapping=0
-LowLimit=0x02
-HighLimit=0x05
-
-[1801sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x280
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1801sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1801sub3]
-ParameterName=Inhibit Time
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0x0000
-PDOMapping=0
-
-[1801sub5]
-ParameterName=Event Timer
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1802]
-ParameterName=Transmit PDO Communication Parameter
-ObjectType=0x9
-SubNumber=5
-
-[1802sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=5
-PDOMapping=0
-LowLimit=0x02
-HighLimit=0x05
-
-[1802sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x380
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1802sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1802sub3]
-ParameterName=Inhibit Time
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0x0000
-PDOMapping=0
-
-[1802sub5]
-ParameterName=Event Timer
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1803]
-ParameterName=Transmit PDO Communication Parameter
-ObjectType=0x9
-SubNumber=5
-
-[1803sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=5
-PDOMapping=0
-LowLimit=0x02
-HighLimit=0x05
-
-[1803sub1]
-ParameterName=COB-ID
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=$NODEID+0x80000480
-PDOMapping=0
-LowLimit=0x00000001
-HighLimit=0xFFFFFFFF
-
-[1803sub2]
-ParameterName=Transmission Type
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=255
-PDOMapping=0
-
-[1803sub3]
-ParameterName=Inhibit Time
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0x0000
-PDOMapping=0
-
-[1803sub5]
-ParameterName=Event Timer
-ObjectType=0x7
-DataType=0x0006
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1a00]
-ParameterName=Transmit PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=2
-
-[1a00sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=1
-PDOMapping=0
-
-[1a00sub1]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x60000108
-PDOMapping=0
-
-[1a01]
-ParameterName=Transmit PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=5
-
-[1a01sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=4
-PDOMapping=0
-
-[1a01sub1]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010110
-PDOMapping=0
-
-[1a01sub2]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010210
-PDOMapping=0
-
-[1a01sub3]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010310
-PDOMapping=0
-
-[1a01sub4]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010410
-PDOMapping=0
-
-[1a02]
-ParameterName=Transmit PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=5
-
-[1a02sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=4
-PDOMapping=0
-
-[1a02sub1]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010510
-PDOMapping=0
-
-[1a02sub2]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010610
-PDOMapping=0
-
-[1a02sub3]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010710
-PDOMapping=0
-
-[1a02sub4]
-ParameterName=PDO Mapping Entry
-ObjectType=0x7
-DataType=0x0007
-AccessType=rw
-DefaultValue=0x64010810
-PDOMapping=0
-
-[1a03]
-ParameterName=Transmit PDO Mapping Parameter
-ObjectType=0x9
-SubNumber=1
-
-[1a03sub0]
-ParameterName=Number of Entries
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[1f50]
-ParameterName=Download Program Data
-ObjectType=0x8
-SubNumber=2
-
-[1f50sub0]
-ParameterName=Number of elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=3
-PDOMapping=0
-
-[1f50sub3]
-ParameterName=Download Program Data - HW Settings
-ObjectType=0x7
-DataType=0x000F
-AccessType=rw
-PDOMapping=0
-
-[6000]
-ParameterName=Read Digital Input 8-bit
-ObjectType=0x8
-SubNumber=2
-
-[6000sub0]
-ParameterName=Number of Elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[6000sub1]
-ParameterName=DigInput8_1
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-PDOMapping=1
-
-[6002]
-ParameterName=Polarity Digital Input
-ObjectType=0x8
-SubNumber=2
-
-[6002sub0]
-ParameterName=Number of Elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[6002sub1]
-ParameterName=Polarity8_1
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[6200]
-ParameterName=Write Digital Output 8-bit
-ObjectType=0x8
-SubNumber=2
-
-[6200sub0]
-ParameterName=Number of elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[6200sub1]
-ParameterName=DigOutput8_1
-ObjectType=0x7
-DataType=0x0005
-AccessType=rww
-PDOMapping=1
-
-[6202]
-ParameterName=Polarity Digital Output
-ObjectType=0x8
-SubNumber=2
-
-[6202sub0]
-ParameterName=Number of Elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[6202sub1]
-ParameterName=Polarity8_1
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[6206]
-ParameterName=Error Mode Digital Output
-ObjectType=0x8
-SubNumber=2
-
-[6206sub0]
-ParameterName=Number of elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[6206sub1]
-ParameterName=Error Mode 1
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[6207]
-ParameterName=Error Value Digital Output
-ObjectType=0x8
-SubNumber=2
-
-[6207sub0]
-ParameterName=Number of elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=1
-PDOMapping=0
-
-[6207sub1]
-ParameterName=Error Value 1
-ObjectType=0x7
-DataType=0x0005
-AccessType=rw
-DefaultValue=0
-PDOMapping=0
-
-[6401]
-ParameterName=Read Analog Input 16-bit
-ObjectType=0x8
-SubNumber=9
-
-[6401sub0]
-ParameterName=Number of elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=8
-PDOMapping=0
-
-[6401sub1]
-ParameterName=AnalogInput16_1
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6401sub2]
-ParameterName=AnalogInput16_2
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6401sub3]
-ParameterName=AnalogInput16_3
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6401sub4]
-ParameterName=AnalogInput16_4
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6401sub5]
-ParameterName=AnalogInput16_5
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6401sub6]
-ParameterName=AnalogInput16_6
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6401sub7]
-ParameterName=AnalogInput16_7
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6401sub8]
-ParameterName=AnalogInput16_8
-ObjectType=0x7
-DataType=0x0003
-AccessType=ro
-PDOMapping=1
-
-[6411]
-ParameterName=Write Analog Output 16-bit
-ObjectType=0x8
-SubNumber=5
-
-[6411sub0]
-ParameterName=Number of elements
-ObjectType=0x7
-DataType=0x0005
-AccessType=ro
-DefaultValue=4
-PDOMapping=0
-
-[6411sub1]
-ParameterName=AnalogOutput16_1
-ObjectType=0x7
-DataType=0x0003
-AccessType=rww
-PDOMapping=1
-
-[6411sub2]
-ParameterName=AnalogOutput16_2
-ObjectType=0x7
-DataType=0x0003
-AccessType=rww
-PDOMapping=1
-
-[6411sub3]
-Paramet