# HG changeset patch # User laurent # Date 1332111452 -3600 # Node ID ce37271712070a0d8770e978852ab4cbab705f8e # Parent d676082c1d2fa9c8aa118fa2dafdffff30a67c68 Defining all slaves as Etherlab master subplugin instead of editing them in an editor with vertical notebook diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/MCL@motion/baseplugin.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ethercat_tests/wago_sanyo/MCL@motion/baseplugin.xml Sun Mar 18 23:57:32 2012 +0100 @@ -0,0 +1,2 @@ + + diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/config.xml --- a/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/config.xml Sun Mar 11 21:57:00 2012 +0100 +++ b/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/config.xml Sun Mar 18 23:57:32 2012 +0100 @@ -23,8 +23,8 @@ EL1088 - 0 - 1 + 1 + 0 2 71315538 @@ -35,8 +35,8 @@ EL2088 - 0 - 2 + 2 + 0 2 136851538 @@ -44,5 +44,17 @@ 0 + + + SanyoDenki RS2 EtherCAT + 3 + 1 + + 441 + 2 + 0 + 0 + + diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/baseplugin.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/baseplugin.xml Sun Mar 18 23:57:32 2012 +0100 @@ -0,0 +1,2 @@ + + diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/baseplugin.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/baseplugin.xml Sun Mar 18 23:57:32 2012 +0100 @@ -0,0 +1,2 @@ + + diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/baseplugin.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/baseplugin.xml Sun Mar 18 23:57:32 2012 +0100 @@ -0,0 +1,2 @@ + + diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatDS402Slave/baseplugin.xml --- a/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatDS402Slave/baseplugin.xml Sun Mar 11 21:57:00 2012 +0100 +++ b/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatDS402Slave/baseplugin.xml Sun Mar 18 23:57:32 2012 +0100 @@ -1,2 +1,2 @@ - + diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatDS402Slave/plugin.xml --- a/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatDS402Slave/plugin.xml Sun Mar 11 21:57:00 2012 +0100 +++ b/ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatDS402Slave/plugin.xml Sun Mar 18 23:57:32 2012 +0100 @@ -1,2 +1,2 @@ - + diff -r d676082c1d2f -r ce3727171207 ethercat_tests/wago_sanyo/plc.xml --- a/ethercat_tests/wago_sanyo/plc.xml Sun Mar 11 21:57:00 2012 +0100 +++ b/ethercat_tests/wago_sanyo/plc.xml Sun Mar 18 23:57:32 2012 +0100 @@ -8,7 +8,7 @@ productVersion="1.0" creationDateTime="2011-10-20T19:01:52"/> + modificationDateTime="2012-03-18T23:04:07"> @@ -27,12 +27,12 @@ - + - + @@ -40,26 +40,36 @@ - + - + - + - + + + + + + + + + + + @@ -68,14 +78,353 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CLOCK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + CLOCK + + + + + + + CLOCK + + + + + + + 4000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Axis + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1800.0 + + + + + + + 360.0 + + + + - + + diff -r d676082c1d2f -r ce3727171207 etherlab/ConfigEditor.py --- a/etherlab/ConfigEditor.py Sun Mar 11 21:57:00 2012 +0100 +++ b/etherlab/ConfigEditor.py Sun Mar 18 23:57:32 2012 +0100 @@ -4,32 +4,6 @@ from controls import CustomGrid, CustomTable, EditorPanel -SCAN_COMMAND = """ -import commands -result = commands.getoutput("ethercat slaves") -slaves = [] -for slave_line in result.splitlines(): - chunks = slave_line.split() - idx, pos, state, flag = chunks[:4] - name = " ".join(chunks[4:]) - alias, position = pos.split(":") - slave = {"idx": int(idx), - "alias": int(alias), - "position": int(position), - "name": name} - details = commands.getoutput("ethercat slaves -p %d -v" % slave["idx"]) - for details_line in details.splitlines(): - details_line = details_line.strip() - for header, param in [("Vendor Id:", "vendor_id"), - ("Product code:", "product_code"), - ("Revision number:", "revision_number")]: - if details_line.startswith(header): - slave[param] = int(details_line.split()[-1], 16) - break - slaves.append(slave) -returnVal = slaves -""" - [ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE] = range(3) def AppendMenu(parent, help, id, kind, text): @@ -38,91 +12,6 @@ else: parent.Append(helpString=help, id=id, kind=kind, item=text) -[ID_SLAVETYPECHOICEDIALOG, ID_SLAVETYPECHOICEDIALOGSTATICTEXT1, - ID_SLAVETYPECHOICEDIALOGSLAVETYPESLIBRARY -] = [wx.NewId() for _init_ctrls in range(3)] - -class SlaveTypeChoiceDialog(wx.Dialog): - - 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_flexGridSizer1_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - parent.AddWindow(self.SlaveTypesLibrary, 0, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT) - parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - - def _init_coll_flexGridSizer1_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(1) - - def _init_sizers(self): - self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) - - self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) - self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1) - - self.SetSizer(self.flexGridSizer1) - - def _init_ctrls(self, prnt): - wx.Dialog.__init__(self, id=ID_SLAVETYPECHOICEDIALOG, - name='SlaveTypeChoiceDialog', parent=prnt, - size=wx.Size(600, 400), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, - title=_('Browse slave types library')) - self.SetClientSize(wx.Size(600, 400)) - - self.staticText1 = wx.StaticText(id=ID_SLAVETYPECHOICEDIALOGSTATICTEXT1, - label=_('Choose a slave type:'), name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.SlaveTypesLibrary = wx.TreeCtrl(id=ID_SLAVETYPECHOICEDIALOGSLAVETYPESLIBRARY, - name='TypeTree', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT) - - self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) - if wx.VERSION >= (2, 5, 0): - self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId()) - else: - self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) - - self._init_sizers() - - def __init__(self, parent, controler, default=None): - self._init_ctrls(parent) - - slaves_types = controler.GetSlaveTypesLibrary() - - root = self.SlaveTypesLibrary.AddRoot("") - self.GenerateSlaveTypesLibraryTreeBranch(root, slaves_types, default) - - def GenerateSlaveTypesLibraryTreeBranch(self, root, children, default): - for infos in children: - item = self.SlaveTypesLibrary.AppendItem(root, infos["name"]) - if infos["type"] == ETHERCAT_DEVICE: - self.SlaveTypesLibrary.SetPyData(item, infos["infos"]) - if infos["infos"] == default: - self.SlaveTypesLibrary.SelectItem(item) - self.SlaveTypesLibrary.EnsureVisible(item) - else: - self.GenerateSlaveTypesLibraryTreeBranch(item, infos["children"], default) - - def GetType(self): - selected = self.SlaveTypesLibrary.GetSelection() - return self.SlaveTypesLibrary.GetPyData(selected) - - def OnOK(self, event): - selected = self.SlaveTypesLibrary.GetSelection() - if not selected.IsOk() or self.SlaveTypesLibrary.GetPyData(selected) is None: - message = wx.MessageDialog(self, _("No valid slave type selected!"), _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - else: - self.EndModal(wx.ID_OK) - def GetSyncManagersTableColnames(): _ = lambda x : x return ["#", _("Name"), _("Start Address"), _("Default Size"), _("Control Byte"), _("Enable")] @@ -139,23 +28,18 @@ _ = lambda x : x return ["#", _("Name"), _("Index"), _("SubIndex"), _("Type"), _("PDO index"), _("PDO name"), _("PDO type")] -[ID_SLAVEINFOSPANEL, ID_SLAVEINFOSPANELVENDORLABEL, - ID_SLAVEINFOSPANELVENDOR, ID_SLAVEINFOSPANELPRODUCTCODELABEL, - ID_SLAVEINFOSPANELPRODUCTCODE, ID_SLAVEINFOSPANELREVISIONNUMBERLABEL, - ID_SLAVEINFOSPANELREVISIONNUMBER, ID_SLAVEINFOSPANELPHYSICSLABEL, - ID_SLAVEINFOSPANELPHYSICS, ID_SLAVEINFOSPANELSYNCMANAGERSLABEL, - ID_SLAVEINFOSPANELSYNCMANAGERSGRID, ID_SLAVEINFOSPANELVARIABLESLABEL, - ID_SLAVEINFOSPANELVARIABLESGRID, +[ID_NODEEDITOR, ID_NODEEDITORVENDORLABEL, + ID_NODEEDITORVENDOR, ID_NODEEDITORPRODUCTCODELABEL, + ID_NODEEDITORPRODUCTCODE, ID_NODEEDITORREVISIONNUMBERLABEL, + ID_NODEEDITORREVISIONNUMBER, ID_NODEEDITORPHYSICSLABEL, + ID_NODEEDITORPHYSICS, ID_NODEEDITORSYNCMANAGERSLABEL, + ID_NODEEDITORSYNCMANAGERSGRID, ID_NODEEDITORVARIABLESLABEL, + ID_NODEEDITORVARIABLESGRID, ] = [wx.NewId() for _init_ctrls in range(13)] -class SlaveInfosPanel(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) +class NodeEditor(EditorPanel): + + ID = ID_NODEEDITOR def _init_coll_MainSizer_Items(self, parent): parent.AddSizer(self.SlaveInfosDetailsSizer, 0, border=5, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) @@ -192,58 +76,58 @@ self._init_coll_SlaveInfosDetailsSizer_Growables(self.SlaveInfosDetailsSizer) self._init_coll_SlaveInfosDetailsSizer_Items(self.SlaveInfosDetailsSizer) - self.SetSizer(self.MainSizer) - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=ID_SLAVEINFOSPANEL, name='SlavePanel', parent=prnt, + self.Editor.SetSizer(self.MainSizer) + + def _init_Editor(self, prnt): + self.Editor = wx.Panel(id=-1, name='SlavePanel', parent=prnt, size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - self.VendorLabel = wx.StaticText(id=ID_SLAVEINFOSPANELVENDORLABEL, - label=_('Vendor:'), name='VendorLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.Vendor = wx.TextCtrl(id=ID_SLAVEINFOSPANELVENDOR, value='', - name='Vendor', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 24), style=wx.TE_READONLY) - - self.ProductCodeLabel = wx.StaticText(id=ID_SLAVEINFOSPANELPRODUCTCODELABEL, - label=_('Product code:'), name='ProductCodeLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.ProductCode = wx.TextCtrl(id=ID_SLAVEINFOSPANELPRODUCTCODE, value='', - name='ProductCode', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 24), style=wx.TE_READONLY) - - self.RevisionNumberLabel = wx.StaticText(id=ID_SLAVEINFOSPANELREVISIONNUMBERLABEL, - label=_('Revision number:'), name='RevisionNumberLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.RevisionNumber = wx.TextCtrl(id=ID_SLAVEINFOSPANELREVISIONNUMBER, value='', - name='RevisionNumber', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 24), style=wx.TE_READONLY) - - self.PhysicsLabel = wx.StaticText(id=ID_SLAVEINFOSPANELPHYSICSLABEL, - label=_('Physics:'), name='PhysicsLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.Physics = wx.TextCtrl(id=ID_SLAVEINFOSPANELPHYSICS, value='', - name='Physics', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 24), style=wx.TE_READONLY) - - self.SyncManagersLabel = wx.StaticText(id=ID_SLAVEINFOSPANELSYNCMANAGERSLABEL, - label=_('Sync managers:'), name='SyncManagersLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.SyncManagersGrid = CustomGrid(id=ID_SLAVEINFOSPANELSYNCMANAGERSGRID, - name='SyncManagersGrid', parent=self, pos=wx.Point(0, 0), + self.VendorLabel = wx.StaticText(id=ID_NODEEDITORVENDORLABEL, + label=_('Vendor:'), name='VendorLabel', parent=self.Editor, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.Vendor = wx.TextCtrl(id=ID_NODEEDITORVENDOR, value='', + name='Vendor', parent=self.Editor, pos=wx.Point(0, 0), + size=wx.Size(0, 24), style=wx.TE_READONLY) + + self.ProductCodeLabel = wx.StaticText(id=ID_NODEEDITORPRODUCTCODELABEL, + label=_('Product code:'), name='ProductCodeLabel', parent=self.Editor, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.ProductCode = wx.TextCtrl(id=ID_NODEEDITORPRODUCTCODE, value='', + name='ProductCode', parent=self.Editor, pos=wx.Point(0, 0), + size=wx.Size(0, 24), style=wx.TE_READONLY) + + self.RevisionNumberLabel = wx.StaticText(id=ID_NODEEDITORREVISIONNUMBERLABEL, + label=_('Revision number:'), name='RevisionNumberLabel', parent=self.Editor, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.RevisionNumber = wx.TextCtrl(id=ID_NODEEDITORREVISIONNUMBER, value='', + name='RevisionNumber', parent=self.Editor, pos=wx.Point(0, 0), + size=wx.Size(0, 24), style=wx.TE_READONLY) + + self.PhysicsLabel = wx.StaticText(id=ID_NODEEDITORPHYSICSLABEL, + label=_('Physics:'), name='PhysicsLabel', parent=self.Editor, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.Physics = wx.TextCtrl(id=ID_NODEEDITORPHYSICS, value='', + name='Physics', parent=self.Editor, pos=wx.Point(0, 0), + size=wx.Size(0, 24), style=wx.TE_READONLY) + + self.SyncManagersLabel = wx.StaticText(id=ID_NODEEDITORSYNCMANAGERSLABEL, + label=_('Sync managers:'), name='SyncManagersLabel', parent=self.Editor, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.SyncManagersGrid = CustomGrid(id=ID_NODEEDITORSYNCMANAGERSGRID, + name='SyncManagersGrid', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.VSCROLL) - self.VariablesLabel = wx.StaticText(id=ID_SLAVEINFOSPANELVARIABLESLABEL, + self.VariablesLabel = wx.StaticText(id=ID_NODEEDITORVARIABLESLABEL, label=_('Variable entries:'), name='VariablesLabel', parent=self, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - self.VariablesGrid = wx.gizmos.TreeListCtrl(id=ID_SLAVEINFOSPANELVARIABLESGRID, - name='VariablesGrid', parent=self, pos=wx.Point(0, 0), + self.VariablesGrid = wx.gizmos.TreeListCtrl(id=ID_NODEEDITORVARIABLESGRID, + name='VariablesGrid', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TR_DEFAULT_STYLE | wx.TR_ROW_LINES | wx.TR_COLUMN_LINES | @@ -252,14 +136,10 @@ self.VariablesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN, self.OnVariablesGridLeftClick) self._init_sizers() - - def __init__(self, parent, controler): - self._init_ctrls(parent) - - self.Controler = controler - self.Slave = None - self.Type = None - + + def __init__(self, parent, controler, window): + EditorPanel.__init__(self, parent, "", window, controler) + self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames()) self.SyncManagersGrid.SetTable(self.SyncManagersTable) self.SyncManagersGridColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, @@ -281,10 +161,21 @@ self.VariablesGrid.AddColumn(colname, colsize, colalign) self.VariablesGrid.SetMainColumn(1) - def SetSlaveInfos(self, slave_pos, slave_infos): - self.Slave = slave_pos + 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): + return self.Controler.PlugFullName() + + def GetBufferState(self): + return False, False + + def RefreshView(self): + slave_infos = self.Controler.GetSlaveInfos() if slave_infos is not None: - self.Type = slave_infos["device_type"] self.Vendor.SetValue(slave_infos["vendor"]) self.ProductCode.SetValue(slave_infos["product_code"]) self.RevisionNumber.SetValue(slave_infos["revision_number"]) @@ -293,7 +184,6 @@ self.SyncManagersTable.ResetView(self.SyncManagersGrid) self.RefreshVariablesGrid(slave_infos["entries"]) else: - self.Type = None self.Vendor.SetValue("") self.ProductCode.SetValue("") self.RevisionNumber.SetValue("") @@ -301,7 +191,7 @@ self.SyncManagersTable.SetData([]) self.SyncManagersTable.ResetView(self.SyncManagersGrid) self.RefreshVariablesGrid([]) - + def RefreshVariablesGrid(self, entries): root = self.VariablesGrid.GetRootItem() if not root.IsOk(): @@ -317,7 +207,8 @@ for entry in entries: idx += 1 - if not item.IsOk(): + create_new = not item.IsOk() + if create_new: item = self.VariablesGrid.AppendItem(root, "") for col, colname in enumerate(colnames): if col == 0: @@ -327,9 +218,9 @@ if entry["PDOMapping"] == "": self.VariablesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY) self.VariablesGrid.SetItemPyData(item, entry) + if create_new and wx.Platform != '__WXMSW__': + item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie) idx = self.GenerateVariablesGridBranch(item, entry["children"], colnames, idx) - if wx.Platform != '__WXMSW__': - item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie) item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie) to_delete = [] @@ -353,13 +244,13 @@ entry_index = self.Controler.ExtractHexDecValue(entry.get("Index", "0")) entry_subindex = self.Controler.ExtractHexDecValue(entry.get("SubIndex", "0")) - var_name = "%s_%4.4x_%2.2x" % (self.Type, entry_index, entry_subindex) + var_name = "%s_%4.4x_%2.2x" % (self.Controler.PlugName(), entry_index, entry_subindex) if pdo_mapping == "R": dir = "%I" else: dir = "%Q" location = "%s%s" % (dir, self.Controler.GetSizeOfType(data_type)) + \ - ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + self.Slave + (entry_index, entry_subindex))) + ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + (self.Controler.GetSlavePos(), entry_index, entry_subindex))) data = wx.TextDataObject(str((location, "location", data_type, var_name, ""))) dragSource = wx.DropSource(self.VariablesGrid) @@ -368,339 +259,4 @@ event.Skip() -[ID_SLAVEPANEL, ID_SLAVEPANELTYPELABEL, - ID_SLAVEPANELTYPE, ID_SLAVEPANELTYPEBROWSE, - ID_SLAVEPANELALIASLABEL, ID_SLAVEPANELALIAS, - ID_SLAVEPANELPOSLABEL, ID_SLAVEPANELPOS, - ID_SLAVEPANELSLAVEINFOSSTATICBOX, -] = [wx.NewId() for _init_ctrls in range(9)] - -class SlavePanel(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_Items(self, parent): - parent.AddSizer(self.PositionSizer, 0, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - parent.AddSizer(self.SlaveInfosBoxSizer, 0, border=5, flag=wx.GROW|wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT) - - def _init_coll_MainSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(1) - - def _init_coll_PositionSizer_Items(self, parent): - parent.AddWindow(self.TypeLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) - parent.AddSizer(self.TypeSizer, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.AliasLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) - parent.AddWindow(self.Alias, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.PosLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) - parent.AddWindow(self.Pos, 0, border=0, flag=wx.GROW) - - def _init_coll_PositionSizer_Growables(self, parent): - parent.AddGrowableCol(1) - parent.AddGrowableCol(3) - parent.AddGrowableCol(5) - parent.AddGrowableRow(0) - - def _init_coll_TypeSizer_Items(self, parent): - parent.AddWindow(self.Type, 1, border=0, flag=0) - parent.AddWindow(self.TypeBrowse, 0, border=0, flag=0) - - def _init_coll_SlaveInfosBoxSizer_Items(self, parent): - parent.AddWindow(self.SlaveInfosPanel, 1, border=0, flag=wx.GROW) - - def _init_sizers(self): - self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) - self.PositionSizer = wx.FlexGridSizer(cols=6, hgap=5, rows=1, vgap=0) - self.TypeSizer = wx.BoxSizer(wx.HORIZONTAL) - self.SlaveInfosBoxSizer = wx.StaticBoxSizer(self.SlaveInfosStaticBox, wx.VERTICAL) - - self._init_coll_MainSizer_Growables(self.MainSizer) - self._init_coll_MainSizer_Items(self.MainSizer) - self._init_coll_PositionSizer_Growables(self.PositionSizer) - self._init_coll_PositionSizer_Items(self.PositionSizer) - self._init_coll_TypeSizer_Items(self.TypeSizer) - self._init_coll_SlaveInfosBoxSizer_Items(self.SlaveInfosBoxSizer) - - self.SetSizer(self.MainSizer) - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=ID_SLAVEPANEL, name='SlavePanel', parent=prnt, - size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - - self.TypeLabel = wx.StaticText(id=ID_SLAVEPANELTYPELABEL, - label=_('Type:'), name='TypeLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.Type = wx.TextCtrl(id=ID_SLAVEPANELTYPE, value='', - name='Type', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 24), style=wx.TE_READONLY) - - self.TypeBrowse = wx.Button(id=ID_SLAVEPANELTYPEBROWSE, label='...', - name='TypeBrowse', parent=self, pos=wx.Point(0, 0), - size=wx.Size(30, 24), style=0) - self.Bind(wx.EVT_BUTTON, self.OnTypeBrowseClick, id=ID_SLAVEPANELTYPEBROWSE) - - self.AliasLabel = wx.StaticText(id=ID_SLAVEPANELALIASLABEL, - label=_('Alias:'), name='AliasLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.Alias = wx.SpinCtrl(id=ID_SLAVEPANELALIAS, - name='Alias', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff) - self.Bind(wx.EVT_SPINCTRL, self.OnAliasChanged, id=ID_SLAVEPANELALIAS) - - self.PosLabel = wx.StaticText(id=ID_SLAVEPANELPOSLABEL, - label=_('Position:'), name='PositionLabel', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.Pos = wx.SpinCtrl(id=ID_SLAVEPANELPOS, - name='Pos', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff) - self.Bind(wx.EVT_SPINCTRL, self.OnPositionChanged, id=ID_SLAVEPANELPOS) - - self.SlaveInfosStaticBox = wx.StaticBox(id=ID_SLAVEPANELSLAVEINFOSSTATICBOX, - label=_('Slave infos:'), name='SlaveInfosStaticBox', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0) - - self.SlaveInfosPanel = SlaveInfosPanel(self, self.Controler) - - self._init_sizers() - - def __init__(self, parent, controler, window, slave): - self.Controler = controler - self.ParentWindow = window - self.Slave = slave - - self._init_ctrls(parent) - - self.RefreshView() - - def GetSlaveTitle(self): - type_infos = self.Controler.GetSlaveType(self.Slave) - return "%s (%d:%d)" % (type_infos["device_type"], self.Slave[0], self.Slave[1]) - - def GetSlave(self): - return self.Slave - - def SetSlave(self, slave): - if self.Slave != slave: - self.Slave = slave - self.RefreshView() - - def RefreshView(self): - self.Alias.SetValue(self.Slave[0]) - self.Pos.SetValue(self.Slave[1]) - slave_infos = self.Controler.GetSlaveInfos(self.Slave) - if slave_infos is not None: - self.Type.SetValue(slave_infos["device_type"]) - else: - type_infos = self.Controler.GetSlaveType(self.Slave) - self.Type.SetValue(type_infos["device_type"]) - self.SlaveInfosPanel.SetSlaveInfos(self.Slave, slave_infos) - - def OnAliasChanged(self, event): - alias = self.Alias.GetValue() - if alias != self.Slave[0]: - result = self.Controler.SetSlavePos(self.Slave[:2], alias = alias) - if result is not None: - message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - else: - wx.CallAfter(self.ParentWindow.RefreshView, (alias, self.Slave[1])) - wx.CallAfter(self.ParentWindow.RefreshParentWindow) - event.Skip() - - def OnPositionChanged(self, event): - position = self.Pos.GetValue() - if position != self.Slave[1]: - result = self.Controler.SetSlavePos(self.Slave, position = position) - if result is not None: - message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - else: - wx.CallAfter(self.ParentWindow.RefreshView, (self.Slave[0], position)) - wx.CallAfter(self.ParentWindow.RefreshParentWindow) - event.Skip() - - def OnTypeBrowseClick(self, event): - dialog = SlaveTypeChoiceDialog(self, self.Controler, self.Controler.GetSlaveType(self.Slave)) - if dialog.ShowModal() == wx.ID_OK: - result = self.Controler.SetSlaveType(self.Slave, dialog.GetType()) - if result is not None: - message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - else: - wx.CallAfter(self.RefreshView) - wx.CallAfter(self.ParentWindow.RefreshSlaveNodesTitles) - wx.CallAfter(self.ParentWindow.RefreshParentWindow) - dialog.Destroy() - event.Skip() - -[ID_CONFIGEDITOR, ID_CONFIGEDITORSLAVENODES, -] = [wx.NewId() for _init_ctrls in range(2)] - -[ID_CONFIGEDITORPLUGINMENUSCANNETWORK, ID_CONFIGEDITORPLUGINMENUADDSLAVE, - ID_CONFIGEDITORPLUGINMENUDELETESLAVE, -] = [wx.NewId() for _init_coll_PluginMenu_Items in range(3)] - -class ConfigEditor(EditorPanel): - - ID = ID_CONFIGEDITOR - - def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.SlaveNodes, 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) - - self.SlaveNodes = wx.Notebook(id=ID_CONFIGEDITORSLAVENODES, - name='SlaveNodes', parent=self.Editor, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.NB_LEFT) - - self._init_sizers() - - def _init_MenuItems(self): - self.MenuItems = [ - (wx.ITEM_NORMAL, (_("Scan network"), ID_CONFIGEDITORPLUGINMENUSCANNETWORK, '', self.OnScanNetworkMenu)), - (wx.ITEM_SEPARATOR, None), - (wx.ITEM_NORMAL, (_("Add slave"), ID_CONFIGEDITORPLUGINMENUADDSLAVE, '', self.OnAddSlaveMenu)), - (wx.ITEM_NORMAL, (_("Delete slave"), ID_CONFIGEDITORPLUGINMENUDELETESLAVE, '', self.OnDeleteSlaveMenu)), - ] - - 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.PlugFullName() - if not self.Controler.ConfigIsSaved(): - 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 RefreshView(self, slave_pos=None): - slaves = self.Controler.GetSlaves() - for i, slave in enumerate(slaves): - if i < self.SlaveNodes.GetPageCount(): - panel = self.SlaveNodes.GetPage(i) - panel.SetSlave(slave) - else: - panel = SlavePanel(self.SlaveNodes, self.Controler, self, slave) - self.SlaveNodes.AddPage(panel, "") - while self.SlaveNodes.GetPageCount() > len(slaves): - self.SlaveNodes.RemovePage(len(slaves)) - self.RefreshSlaveNodesTitles() - if slave_pos is not None: - self.SelectSlave(slave_pos) - - def RefreshParentWindow(self): - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPluginMenu() - self.ParentWindow.RefreshPageTitles() - - def RefreshSlaveNodesTitles(self): - for idx in xrange(self.SlaveNodes.GetPageCount()): - panel = self.SlaveNodes.GetPage(idx) - self.SlaveNodes.SetPageText(idx, panel.GetSlaveTitle()) - - def RefreshPluginMenu(self, plugin_menu): - plugin_menu.Enable(ID_CONFIGEDITORPLUGINMENUDELETESLAVE, - self.SlaveNodes.GetPageCount() > 0) - - def SelectSlave(self, slave): - for idx in xrange(self.SlaveNodes.GetPageCount()): - panel = self.SlaveNodes.GetPage(idx) - if panel.GetSlave() == slave: - self.SlaveNodes.SetSelection(idx) - return - - def OnScanNetworkMenu(self, event): - error, returnVal = self.Controler.RemoteExec(SCAN_COMMAND, returnVal = None) - if error != 0: - dialog = wx.MessageDialog(self, returnVal, "Error", wx.OK|wx.ICON_ERROR) - dialog.ShowModal() - dialog.Destroy() - elif returnVal is not None: - print returnVal - wx.CallAfter(self.RefreshView) - - def OnAddSlaveMenu(self, event): - slave = self.Controler.AddSlave() - self.RefreshParentWindow() - wx.CallAfter(self.RefreshView, slave) - - def OnDeleteSlaveMenu(self, event): - selected = self.SlaveNodes.GetSelection() - if selected != -1: - panel = self.SlaveNodes.GetPage(selected) - if self.Controler.RemoveSlave(panel.GetSlave()[:2]): - self.RefreshParentWindow() - wx.CallAfter(self.RefreshView) - - -[ID_DS402NODEEDITOR, -] = [wx.NewId() for _init_ctrls in range(1)] - -class DS402NodeEditor(EditorPanel): - - ID = ID_DS402NODEEDITOR - - def _init_Editor(self, prnt): - self.Editor = SlaveInfosPanel(prnt, self.Controler) - - 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): - return self.Controler.PlugFullName() - - def GetBufferState(self): - return False, False - - def RefreshView(self): - self.Editor.SetSlaveInfos(self.Controler.GetSlavePos(), self.Controler.GetSlaveInfos()) - \ No newline at end of file +DS402NodeEditor = NodeEditor diff -r d676082c1d2f -r ce3727171207 etherlab/etherlab.py --- a/etherlab/etherlab.py Sun Mar 11 21:57:00 2012 +0100 +++ b/etherlab/etherlab.py Sun Mar 18 23:57:32 2012 +0100 @@ -7,118 +7,129 @@ from xmlclass import * from plugger import PlugTemplate from PLCControler import UndoBuffer, LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY -from ConfigEditor import ConfigEditor, DS402NodeEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE +from ConfigEditor import NodeEditor, DS402NodeEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE + +try: + from plugins.motion import Headers, AxisXSD + HAS_MCL = True +except: + HAS_MCL = False + + +TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", + "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", + "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"} + +DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64", + "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", + "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"} + +VARCLASSCONVERSION = {"T": LOCATION_VAR_INPUT, "R": LOCATION_VAR_OUTPUT, "RT": LOCATION_VAR_MEMORY} #-------------------------------------------------- -# Ethercat DS402 Node +# Remote Exec Etherlab Commands #-------------------------------------------------- -NODE_VARIABLES = [ - ("ControlWord", 0x6040, 0x00, "UINT", "Q"), - ("TargetPosition", 0x607a, 0x00, "DINT", "Q"), - ("StatusWord", 0x6041, 0x00, "UINT", "I"), - ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"), - ("ActualPosition", 0x6064, 0x00, "DINT", "I"), - ("ErrorCode", 0x603f, 0x00, "UINT", "I"), -] - -class _EthercatDS402SlavePlug: - XSD = """ - - - - - - - - """ - EditorType = DS402NodeEditor +SCAN_COMMAND = """ +import commands +result = commands.getoutput("ethercat slaves") +slaves = [] +for slave_line in result.splitlines(): + chunks = slave_line.split() + idx, pos, state, flag = chunks[:4] + name = " ".join(chunks[4:]) + alias, position = pos.split(":") + slave = {"idx": int(idx), + "alias": int(alias), + "position": int(position), + "name": name} + details = commands.getoutput("ethercat slaves -p %d -v" % slave["idx"]) + for details_line in details.splitlines(): + details_line = details_line.strip() + for header, param in [("Vendor Id:", "vendor_id"), + ("Product code:", "product_code"), + ("Revision number:", "revision_number")]: + if details_line.startswith(header): + slave[param] = int(details_line.split()[-1], 16) + break + slaves.append(slave) +returnVal = slaves +""" + +#-------------------------------------------------- +# Ethercat Node +#-------------------------------------------------- + +class _EthercatSlavePlug: + + NODE_PROFILE = None + EditorType = NodeEditor def ExtractHexDecValue(self, value): return ExtractHexDecValue(value) - + def GetSizeOfType(self, type): return TYPECONVERSION.get(self.GetPlugRoot().GetBaseType(type), None) - def _GetChildBySomething(self, something, toks): - return self + def GetSlavePos(self): + return self.BaseParams.getIEC_Channel() def GetParamsAttributes(self, path = None): - infos = PlugTemplate.GetParamsAttributes(self, path = None) - for element in infos: - if element["name"] == "EtherlabDS402Slave": - for child in element["children"]: - if child["name"] == "Node_Type": - child["type"] = [module[0] for module in self.PlugParent.GetModulesByProfile(402)] - return infos - - def GetAllChannels(self): - AllChannels = PlugTemplate.GetAllChannels(self) - for slave_pos in self.PlugParent.GetSlaves(): - if slave_pos[0] not in AllChannels: - AllChannels.append(slave_pos[0]) - AllChannels.sort() - return AllChannels - - def GetCurrentLocation(self): - """ - @return: Tupple containing plugin IEC location of current plugin : %I0.0.4.5 => (0,0,4,5) - """ - return self.PlugParent.GetCurrentLocation() + self.GetSlavePos() - - def GetSlavePos(self): - return self.BaseParams.getIEC_Channel(), 0 - - def GetSlaveTypeInfos(self): - slave_type = self.EtherlabDS402Slave.getNode_Type() - - for module_type, vendor_id, product_code, revision_number in self.PlugParent.GetModulesByProfile(402): - if module_type == slave_type: - return {"device_type": module_type, - "vendor": GenerateHexDecValue(vendor_id), - "product_code": GenerateHexDecValue(product_code, 16), - "revision_number": GenerateHexDecValue(revision_number, 16)} - - return None + if path: + parts = path.split(".", 1) + if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: + return self.MandatoryParams[1].getElementInfos(parts[0], parts[1]) + elif self.PlugParams and parts[0] == self.PlugParams[0]: + return self.PlugParams[1].getElementInfos(parts[0], parts[1]) + else: + params = [] + if wx.VERSION < (2, 8, 0) and self.MandatoryParams: + params.append(self.MandatoryParams[1].getElementInfos(self.MandatoryParams[0])) + slave_type = self.PlugParent.GetSlaveType(self.GetSlavePos()) + params.append({ + 'use': 'required', + 'type': 'element', + 'name': 'SlaveParams', + 'value': None, + 'children': [{ + 'use': 'optional', + 'type': self.PlugParent.GetSlaveTypesLibrary(self.NODE_PROFILE), + 'name': 'Type', + 'value': (slave_type["device_type"], slave_type)}, + {'use': 'optional', + 'type': 'unsignedLong', + 'name': 'Alias', + 'value': self.PlugParent.GetSlaveAlias(self.GetSlavePos())}] + }) + if self.PlugParams: + params.append(self.PlugParams[1].getElementInfos(self.PlugParams[0])) + return params + + def SetParamsAttribute(self, path, value): + position = self.BaseParams.getIEC_Channel() + value, changed = PlugTemplate.SetParamsAttribute(self, path, value) + # Filter IEC_Channel, Slave_Type and Alias that have specific behavior + if path == "BaseParams.IEC_Channel": + self.PlugParent.SetSlavePosition(position, value) + elif path == "SlaveParams.Type": + self.PlugParent.SetSlaveType(position, value) + slave_type = self.PlugParent.GetSlaveType(self.GetSlavePos()) + value = (slave_type["device_type"], slave_type) + changed = True + elif path == "SlaveParams.Alias": + self.PlugParent.SetSlaveAlias(position, value) + changed = True + return value, changed def GetSlaveInfos(self): - slave_typeinfos = self.GetSlaveTypeInfos() - if slave_typeinfos is not None: - device = self.PlugParent.GetModuleInfos(slave_typeinfos) - if device is not None: - infos = slave_typeinfos.copy() - entries = device.GetEntriesList() - entries_list = entries.items() - entries_list.sort() - entries = [] - current_index = None - current_entry = None - for (index, subindex), entry in entries_list: - entry["children"] = [] - if index != current_index: - current_index = index - current_entry = entry - entries.append(entry) - elif current_entry is not None: - current_entry["children"].append(entry) - else: - entries.append(entry) - infos.update({"physics": device.getPhysics(), - "sync_managers": device.GetSyncManagers(), - "entries": entries}) - return infos - return None - + return self.PlugParent.GetSlaveInfos(self.GetSlavePos()) + def GetVariableLocationTree(self): - slave_typeinfos = self.GetSlaveTypeInfos() - vars = [] - if slave_typeinfos is not None: - vars = self.PlugParent.GetDeviceLocationTree(self.GetCurrentLocation(), slave_typeinfos) - return {"name": self.BaseParams.getName(), "type": LOCATION_PLUGIN, "location": self.GetFullIEC_Channel(), - "children": vars} + "children": self.PlugParent.GetDeviceLocationTree(self.GetSlavePos(), self.GetCurrentLocation(), self.BaseParams.getName()) + } PluginMethods = [ {"bitmap" : os.path.join("images", "EditCfile"), @@ -127,7 +138,6 @@ "method" : "_OpenView"}, ] - def PlugGenerate_C(self, buildpath, locations): """ Generate C code @@ -141,79 +151,111 @@ }, ...] @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND """ - current_location = self.GetCurrentLocation() - - location_str = "_".join(map(lambda x:str(x), current_location)) - - slave_pos = current_location[-2:] - - slave_typeinfos = self.GetSlaveTypeInfos() - device = None - if slave_typeinfos is not None: - device = self.PlugParent.GetModuleInfos(slave_typeinfos) - - if device is None: - raise (ValueError, - _("No information found for DS402 node \"%s\" at location %s!") % ( - slave_typeinfos["device_type"], ".".join(current_location))) - - self.PlugParent.FileGenerator.DeclareSlave(slave_pos, slave_typeinfos) - - plc_ds402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_ds402node.c") - plc_ds402node_file = open(plc_ds402node_filepath, 'r') - plc_ds402node_code = plc_ds402node_file.read() - plc_ds402node_file.close() - - from plugins.motion import Headers - - str_completion = { - "location": location_str, - "MCL_headers": Headers, - "extern_located_variables_declaration": [], - "entry_variables": [], - "init_entry_variables": [], - } - - for variable in NODE_VARIABLES: - var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable)) - var_infos["location"] = location_str - var_infos["var_size"] = self.PlugParent.GetSizeOfType(var_infos["var_type"]) - var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos - - str_completion["extern_located_variables_declaration"].append( - "IEC_%(var_type)s *%(var_name)s;" % var_infos) - str_completion["entry_variables"].append( - " IEC_%(var_type)s *%(name)s;" % var_infos) - str_completion["init_entry_variables"].append( - " __DS402Node_%(location)s.%(name)s = %(var_name)s;" % var_infos) - - self.PlugParent.FileGenerator.DeclareVariable( - slave_pos, var_infos["index"], var_infos["subindex"], - var_infos["var_type"], var_infos["dir"], var_infos["var_name"]) - - for element in ["extern_located_variables_declaration", - "entry_variables", - "init_entry_variables"]: - str_completion[element] = "\n".join(str_completion[element]) - - Gen_DS402Nodefile_path = os.path.join(buildpath, "ds402node_%s.c"%location_str) - ds402nodefile = open(Gen_DS402Nodefile_path, 'w') - ds402nodefile.write(plc_ds402node_code % str_completion) - ds402nodefile.close() - - return [(Gen_DS402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))],"",True - - - -TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", - "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", - "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"} - -DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64", - "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", - "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"} - -VARCLASSCONVERSION = {"T": LOCATION_VAR_INPUT, "R": LOCATION_VAR_OUTPUT, "RT": LOCATION_VAR_MEMORY} + return [],"",False + +#-------------------------------------------------- +# Ethercat DS402 Node +#-------------------------------------------------- + +if HAS_MCL: + + NODE_VARIABLES = [ + ("ControlWord", 0x6040, 0x00, "UINT", "Q"), + ("TargetPosition", 0x607a, 0x00, "DINT", "Q"), + ("StatusWord", 0x6041, 0x00, "UINT", "I"), + ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"), + ("ActualPosition", 0x6064, 0x00, "DINT", "I"), + ("ErrorCode", 0x603f, 0x00, "UINT", "I"), + ] + + class _EthercatDS402SlavePlug(_EthercatSlavePlug): + XSD = """ + + + + %s + + + + """ % AxisXSD + + NODE_PROFILE = 402 + EditorType = DS402NodeEditor + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param current_location: Tupple containing plugin 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() + + location_str = "_".join(map(lambda x:str(x), current_location)) + + plc_ds402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_ds402node.c") + plc_ds402node_file = open(plc_ds402node_filepath, 'r') + plc_ds402node_code = plc_ds402node_file.read() + plc_ds402node_file.close() + + str_completion = { + "location": location_str, + "MCL_headers": Headers, + "extern_located_variables_declaration": [], + "entry_variables": [], + "init_axis_params": [], + "init_entry_variables": [], + } + + for variable in NODE_VARIABLES: + var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable)) + var_infos["location"] = location_str + var_infos["var_size"] = self.GetSizeOfType(var_infos["var_type"]) + var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos + + str_completion["extern_located_variables_declaration"].append( + "IEC_%(var_type)s *%(var_name)s;" % var_infos) + str_completion["entry_variables"].append( + " IEC_%(var_type)s *%(name)s;" % var_infos) + str_completion["init_entry_variables"].append( + " __DS402Node_%(location)s.%(name)s = %(var_name)s;" % var_infos) + + self.PlugParent.FileGenerator.DeclareVariable( + self.GetSlavePos(), var_infos["index"], var_infos["subindex"], + var_infos["var_type"], var_infos["dir"], var_infos["var_name"]) + + params = self.PlugParams[1].getElementInfos(self.PlugParams[0]) + for param in params["children"]: + if param["value"] is not None: + param_infos = { + "location": location_str, + "param_name": param["name"], + } + if param["type"] == "boolean": + param_infos["param_value"] = {True: "true", False: "false"}[param["value"]] + else: + param_infos["param_value"] = str(param["value"]) + str_completion["init_axis_params"].append( + " __DS402Node_%(location)s.axis->%(param_name)s = %(param_value)s;" % param_infos) + + for element in ["extern_located_variables_declaration", + "entry_variables", + "init_axis_params", + "init_entry_variables"]: + str_completion[element] = "\n".join(str_completion[element]) + + Gen_DS402Nodefile_path = os.path.join(buildpath, "ds402node_%s.c"%location_str) + ds402nodefile = open(Gen_DS402Nodefile_path, 'w') + ds402nodefile.write(plc_ds402node_code % str_completion) + ds402nodefile.close() + + return [(Gen_DS402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))],"",True #-------------------------------------------------- # Ethercat MASTER @@ -257,18 +299,6 @@ slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"])) slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"])) setattr(cls, "setType", setType) - -cls = EtherCATConfigClasses.get("Slave_Info", None) -if cls: - - def getSlavePosition(self): - return self.getPhysAddr(), self.getAutoIncAddr() - setattr(cls, "getSlavePosition", getSlavePosition) - - def setSlavePosition(self, alias, pos): - self.setPhysAddr(alias) - self.setAutoIncAddr(pos) - setattr(cls, "setSlavePosition", setSlavePosition) class _EthercatPlug: XSD = """ @@ -281,9 +311,10 @@ """ - EditorType = ConfigEditor - - PlugChildsTypes = [("EthercatDS402Slave", _EthercatDS402SlavePlug, "Ethercat DS402 Slave")] + + PlugChildsTypes = [("EthercatSlave", _EthercatSlavePlug, "Ethercat Slave")] + if HAS_MCL: + PlugChildsTypes.append(("EthercatDS402Slave", _EthercatDS402SlavePlug, "Ethercat DS402 Slave")) def __init__(self): filepath = self.ConfigFileName() @@ -314,62 +345,70 @@ def GetSlaves(self): slaves = [] for slave in self.Config.getConfig().getSlave(): - slaves.append(slave.getInfo().getSlavePosition()) + slaves.append(slave.getInfo().getPhysAddr()) slaves.sort() return slaves def GetSlave(self, slave_pos): for slave in self.Config.getConfig().getSlave(): slave_info = slave.getInfo() - if slave_info.getSlavePosition() == slave_pos: + if slave_info.getPhysAddr() == slave_pos: return slave return None - def AddSlave(self): - slaves = self.GetSlaves() - for PlugInstance in self.IterChilds(): - slaves.append(PlugInstance.GetSlavePos()) - slaves.sort() - if len(slaves) > 0: - new_pos = (slaves[-1][0] + 1, 0) - else: - new_pos = (0, 0) - slave = EtherCATConfigClasses["Config_Slave"]() - slave_infos = slave.getInfo() - slave_infos.setName("undefined") - slave_infos.setSlavePosition(new_pos[0], new_pos[1]) - self.Config.getConfig().appendSlave(slave) - self.BufferConfig() - return new_pos - - def RemoveSlave(self, slave_pos): + def PlugAddChild(self, PlugName, PlugType, IEC_Channel=0): + """ + Create the plugins that may be added as child to this node self + @param PlugType: string desining the plugin class name (get name from PlugChildsTypes) + @param PlugName: string for the name of the plugin instance + """ + newPluginOpj = PlugTemplate.PlugAddChild(self, PlugName, PlugType, IEC_Channel) + + slave = self.GetSlave(newPluginOpj.BaseParams.getIEC_Channel()) + if slave is None: + slave = EtherCATConfigClasses["Config_Slave"]() + slave_infos = slave.getInfo() + slave_infos.setName("undefined") + slave_infos.setPhysAddr(newPluginOpj.BaseParams.getIEC_Channel()) + slave_infos.setAutoIncAddr(0) + self.Config.getConfig().appendSlave(slave) + self.BufferConfig() + self.OnPlugSave() + + return newPluginOpj + + def _doRemoveChild(self, PlugInstance): + slave_pos = PlugInstance.GetSlavePos() config = self.Config.getConfig() for idx, slave in enumerate(config.getSlave()): slave_infos = slave.getInfo() - if slave_infos.getSlavePosition() == slave_pos: + if slave_infos.getPhysAddr() == slave_pos: config.removeSlave(idx) self.BufferConfig() - return True - return False - - def SetSlavePos(self, slave_pos, alias=None, position=None): - for PlugInstance in self.IterChilds(): - if PlugInstance.BaseParams.getIEC_Channel() == alias: - return _("Slave with alias \"%d\" already exists!" % alias) + self.OnPlugSave() + PlugTemplate._doRemoveChild(self, PlugInstance) + + def SetSlavePosition(self, slave_pos, new_pos): slave = self.GetSlave(slave_pos) if slave is not None: slave_info = slave.getInfo() - new_pos = slave_pos - if alias is not None: - new_pos = (alias, new_pos[1]) - if position is not None: - new_pos = (new_pos[0], position) - if self.GetSlave(new_pos) is not None: - return _("Slave with position \"%d:%d\" already exists!" % new_pos) - slave_info.setSlavePosition(*new_pos) + slave_info.setPhysAddr(new_pos) self.BufferConfig() + + def GetSlaveAlias(self, slave_pos): + slave = self.GetSlave(slave_pos) + if slave is not None: + slave_info = slave.getInfo() + return slave_info.getAutoIncAddr() return None + def SetSlaveAlias(self, slave_pos, alias): + slave = self.GetSlave(slave_pos) + if slave is not None: + slave_info = slave.getInfo() + slave_info.setAutoIncAddr(alias) + self.BufferConfig() + def GetSlaveType(self, slave_pos): slave = self.GetSlave(slave_pos) if slave is not None: @@ -381,7 +420,6 @@ if slave is not None: slave.setType(type_infos) self.BufferConfig() - return None def GetSlaveInfos(self, slave_pos): slave = self.GetSlave(slave_pos) @@ -415,81 +453,51 @@ def GetModuleInfos(self, type_infos): return self.PlugParent.GetModuleInfos(type_infos) - def GetModulesByProfile(self, profile_type): - return self.PlugParent.GetModulesByProfile(profile_type) - - def GetSlaveTypesLibrary(self): - return self.PlugParent.GetModulesLibrary() - - def GetDeviceLocationTree(self, current_location, type_infos): - vars = [] - - device = self.GetModuleInfos(type_infos) - if device is not None: - sync_managers = [] - for sync_manager in device.getSm(): - sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) - sync_manager_direction = sync_manager_control_byte & 0x0c - if sync_manager_direction: - sync_managers.append(LOCATION_VAR_OUTPUT) - else: - sync_managers.append(LOCATION_VAR_INPUT) - - entries = device.GetEntriesList().items() - entries.sort() - for (index, subindex), entry in entries: - var_size = self.GetSizeOfType(entry["Type"]) - if var_size is not None: - var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None) - if var_class is not None: - if var_class == LOCATION_VAR_INPUT: - var_dir = "%I" - else: - var_dir = "%Q" - - vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]), - "type": var_class, - "size": var_size, - "IEC_type": entry["Type"], - "var_name": "%s_%4.4x_%2.2x" % ("_".join(type_infos["device_type"].split()), index, subindex), - "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + - (index, subindex)))), - "description": "", - "children": []}) + def GetSlaveTypesLibrary(self, profile_filter=None): + return self.PlugParent.GetModulesLibrary(profile_filter) + + def GetDeviceLocationTree(self, slave_pos, current_location, device_name): + slave = self.GetSlave(slave_pos) + if slave is not None: + type_infos = slave.getType() + + vars = [] + + device = self.GetModuleInfos(type_infos) + if device is not None: + sync_managers = [] + for sync_manager in device.getSm(): + sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) + sync_manager_direction = sync_manager_control_byte & 0x0c + if sync_manager_direction: + sync_managers.append(LOCATION_VAR_OUTPUT) + else: + sync_managers.append(LOCATION_VAR_INPUT) + + entries = device.GetEntriesList().items() + entries.sort() + for (index, subindex), entry in entries: + var_size = self.GetSizeOfType(entry["Type"]) + if var_size is not None: + var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None) + if var_class is not None: + if var_class == LOCATION_VAR_INPUT: + var_dir = "%I" + else: + var_dir = "%Q" + + vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]), + "type": var_class, + "size": var_size, + "IEC_type": entry["Type"], + "var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex), + "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + + (index, subindex)))), + "description": "", + "children": []}) return vars - def GetVariableLocationTree(self): - '''See PlugTemplate.GetVariableLocationTree() for a description.''' - - current_location = self.GetCurrentLocation() - - groups = [] - for slave_pos in self.GetSlaves(): - - slave = self.GetSlave(slave_pos) - if slave is not None: - type_infos = slave.getType() - - vars = self.GetDeviceLocationTree(current_location + slave_pos, type_infos) - if len(vars) > 0: - groups.append({"name": "%s (%d,%d)" % ((type_infos["device_type"],) + slave_pos), - "type": LOCATION_GROUP, - "location": ".".join(map(str, current_location + slave_pos)) + ".x", - "children": vars}) - - return {"name": self.BaseParams.getName(), - "type": LOCATION_PLUGIN, - "location": self.GetFullIEC_Channel(), - "children": groups} - - PluginMethods = [ - {"bitmap" : os.path.join("images", "EditCfile"), - "name" : _("Edit Config"), - "tooltip" : _("Edit Config"), - "method" : "_OpenView"}, - ] - def PlugTestModified(self): return self.ChangesToSave or not self.ConfigIsSaved() @@ -548,14 +556,14 @@ for slave_pos in slaves: slave = self.GetSlave(slave_pos) if slave is not None: - self.FileGenerator.DeclareSlave(slave_pos, slave.getType()) + self.FileGenerator.DeclareSlave(slave_pos, slave.getInfo().getAutoIncAddr(), slave.getType()) for location in locations: loc = location["LOC"][len(current_location):] - slave_pos = loc[:2] - if slave_pos in slaves: + slave_pos = loc[0] + if slave_pos in slaves and len(loc) == 3: self.FileGenerator.DeclareVariable( - slave_pos, loc[2], loc[3], location["IEC_TYPE"], location["DIR"], location["NAME"]) + slave_pos, loc[1], loc[2], location["IEC_TYPE"], location["DIR"], location["NAME"]) return [],"",False @@ -709,13 +717,11 @@ def __del__(self): self.Controler = None - def DeclareSlave(self, slave_identifier, slave): - self.Slaves.append((slave_identifier, slave)) - self.Slaves.sort() - return self.Slaves.index((slave_identifier, slave)) - - def DeclareVariable(self, slave_identifier, index, subindex, iec_type, dir, name): - slave_variables = self.UsedVariables.setdefault(slave_identifier, {}) + def DeclareSlave(self, slave_index, slave_alias, slave): + self.Slaves.append((slave_index, slave_alias, slave)) + + def DeclareVariable(self, slave_index, index, subindex, iec_type, dir, name): + slave_variables = self.UsedVariables.setdefault(slave_index, {}) entry_infos = slave_variables.get((index, subindex), None) if entry_infos is None: @@ -752,12 +758,19 @@ for entry_infos in slave_entries.itervalues(): entry_infos["mapped"] = False - for slave_idx, (slave_pos, type_infos) in enumerate(self.Slaves): + self.Slaves.sort() + alias = {} + for (slave_idx, slave_alias, type_infos) in self.Slaves: + if alias.get(slave_alias) is not None: + alias[slave_alias] += 1 + else: + alias[slave_alias] = 0 + slave_pos = (slave_alias, alias[slave_alias]) device = self.Controler.GetModuleInfos(type_infos) if device is not None: - slave_variables = self.UsedVariables.get(slave_pos, {}) + slave_variables = self.UsedVariables.get(slave_idx, {}) device_entries = device.GetEntriesList() if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0: @@ -1306,39 +1319,45 @@ raise ValueError, "Not such group \"%\"" % device_group vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device)) - def GetModulesLibrary(self): + def GetModulesLibrary(self, profile_filter=None): library = [] children_dict = {} for vendor_id, vendor in self.ModulesLibrary.iteritems(): groups = [] - library.append({"name": vendor["name"], - "type": ETHERCAT_VENDOR, - "children": groups}) for group_type, group in vendor["groups"].iteritems(): group_infos = {"name": group["name"], "order": group["order"], "type": ETHERCAT_GROUP, + "infos": None, "children": children_dict.setdefault(group_type, [])} - if group["parent"] is not None: - parent_children = children_dict.setdefault(group["parent"], []) - parent_children.append(group_infos) - else: - groups.append(group_infos) device_dict = {} for device_type, device in group["devices"]: - device_infos = {"name": ExtractName(device.getName()), - "type": ETHERCAT_DEVICE, - "infos": {"device_type": device_type, - "vendor": vendor_id, - "product_code": device.getType().getProductCode(), - "revision_number": device.getType().getRevisionNo()}} - group_infos["children"].append(device_infos) - device_type_occurrences = device_dict.setdefault(device_type, []) - device_type_occurrences.append(device_infos) + if profile_filter is None or profile_filter in device.GetProfileNumbers(): + device_infos = {"name": ExtractName(device.getName()), + "type": ETHERCAT_DEVICE, + "infos": {"device_type": device_type, + "vendor": vendor_id, + "product_code": device.getType().getProductCode(), + "revision_number": device.getType().getRevisionNo()}, + "children": []} + group_infos["children"].append(device_infos) + device_type_occurrences = device_dict.setdefault(device_type, []) + device_type_occurrences.append(device_infos) for device_type_occurrences in device_dict.itervalues(): if len(device_type_occurrences) > 1: for occurrence in device_type_occurrences: occurrence["name"] += _(" (rev. %s)") % occurrence["infos"]["revision_number"] + if len(group_infos["children"]) > 0: + if group["parent"] is not None: + parent_children = children_dict.setdefault(group["parent"], []) + parent_children.append(group_infos) + else: + groups.append(group_infos) + if len(groups) > 0: + library.append({"name": vendor["name"], + "type": ETHERCAT_VENDOR, + "infos": None, + "children": groups}) library.sort(lambda x, y: cmp(x["name"], y["name"])) return library @@ -1354,16 +1373,5 @@ revision_number == ExtractHexDecValue(type_infos["revision_number"])): return device return None - - def GetModulesByProfile(self, profile_type): - modules = [] - for vendor_id, vendor in self.ModulesLibrary.iteritems(): - for group_type, group in vendor["groups"].iteritems(): - for device_type, device in group["devices"]: - if profile_type in device.GetProfileNumbers(): - product_code = ExtractHexDecValue(device.getType().getProductCode()) - revision_number = ExtractHexDecValue(device.getType().getRevisionNo()) - modules.append((device_type, vendor_id, product_code, revision_number)) - return modules - - + + diff -r d676082c1d2f -r ce3727171207 etherlab/plc_ds402node.c --- a/etherlab/plc_ds402node.c Sun Mar 11 21:57:00 2012 +0100 +++ b/etherlab/plc_ds402node.c Sun Mar 18 23:57:32 2012 +0100 @@ -19,6 +19,7 @@ IEC_UINT __InactiveMask = 0x4f; IEC_UINT __ActiveMask = 0x6f; IEC_UINT __PowerMask = 0x10; +IEC_BOOL __FirstTick = 1; typedef enum { __Unknown, @@ -44,8 +45,8 @@ int __init_%(location)s() { -%(init_entry_variables)s; -*__IW%(location)s_0 = __MK_AllocAxis(&(__DS402Node_%(location)s.axis)); +%(init_entry_variables)s + *__IW%(location)s_0 = __MK_AllocAxis(&(__DS402Node_%(location)s.axis)); return 0; } @@ -58,6 +59,11 @@ IEC_UINT statusword_inactive = *(__DS402Node_%(location)s.StatusWord) & __InactiveMask; IEC_UINT statusword_active = *(__DS402Node_%(location)s.StatusWord) & __ActiveMask; + if (__FirstTick) { +%(init_axis_params)s + _FirstTick = 0; + } + // DS402 node state computation __DS402Node_%(location)s.state = __Unknown; switch (statusword_inactive) {