# This file is part of Beremiz
# Copyright (C) 2013: Real-Time & Embedded Systems (RTES) Lab., University of Seoul
# See COPYING file for copyrights details.
from __future__ import absolute_import
from __future__ import division
from xml.dom import minidom
# --------------------------------------------------------------------
from controls import CustomGrid, CustomTable
from runtime import PlcStatus
# --------------------------------------------------------------------
# ------------ for register management ---------------
from util.TranslationCatalogs import NoTranslate
# -------------------------------------------------------------
# ----------------------------- For Sync Manager Table -----------------------------------
def GetSyncManagersTableColnames():
Returns column names of SyncManager Table in Slave state panel.
return ["#", _("Name"), _("Start Address"), _("Default Size"), _("Control Byte"), _("Enable")]
# -------------------------------------------------------------------------------
# -------------------------------------------------------------------------------
class SyncManagersTable(CustomTable):
def GetValue(self, row, col):
if row < self.GetNumberRows():
return self.data[row].get(self.GetColLabelValue(col, False), "")
# -------------------------------------------------------------------------------
# EtherCAT Management Treebook
# -------------------------------------------------------------------------------
class EtherCATManagementTreebook(wx.Treebook):
def __init__(self, parent, controler, node_editor):
@param parent: Reference to the parent wx.ScrolledWindow object
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
@param node_editor: Reference to Beremiz frame
wx.Treebook.__init__(self, parent, -1, size=wx.DefaultSize, style=wx.BK_DEFAULT)
self.Controler = controler
self.NodeEditor = node_editor
self.EtherCATManagementClassObject = {}
# fill EtherCAT Management Treebook
("Slave State", SlaveStatePanelClass, []),
("SDO Management", SDOPanelClass, []),
("PDO Mapping", PDOPanelClass, [
("Rx PDO", RxPDOPanelClass),
("Tx PDO", TxPDOPanelClass)]),
("MDP Setting", MDPPanel, []),
("ESC Management", EEPROMAccessPanel, [
("Smart View", SlaveSiiSmartView),
("Register Access", RegisterAccessPanel, []),
("DC Configuration", DCConfigPanel, [])
for pname, pclass, subs in panels:
self.AddPage(pclass(self, self.Controler), pname)
for spname, spclass in subs:
self.AddSubPage(spclass(self, self.Controler), spname)
# -------------------------------------------------------------------------------
# -------------------------------------------------------------------------------
class SlaveStatePanelClass(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1, (0, 0), size=wx.DefaultSize, style=wx.SUNKEN_BORDER)
self.Controler = controler
# initialize SlaveStatePanel UI dictionaries
# iniitalize BoxSizer and FlexGridSizer
"SlaveState_main_sizer": wx.BoxSizer(wx.VERTICAL),
"SlaveState_inner_main_sizer": wx.FlexGridSizer(cols=1, hgap=50, rows=3, vgap=10),
"SlaveInfosDetailsInnerSizer": wx.FlexGridSizer(cols=4, hgap=10, rows=2, vgap=10),
"SyncManagerInnerSizer": wx.FlexGridSizer(cols=1, hgap=5, rows=1, vgap=5),
"SlaveState_sizer": wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10),
"SlaveState_up_sizer": wx.FlexGridSizer(cols=4, hgap=10, rows=2, vgap=10),
"SlaveState_down_sizer": wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10)}
# initialize StaticBox and StaticBoxSizer
for box_name, box_label in [
("SlaveInfosDetailsBox", "Slave Informations"),
("SyncManagerBox", "Sync Manager"),
("SlaveStateBox", "Slave State Transition && Monitoring")]:
self.StaticBoxDic[box_name] = wx.StaticBox(self, label=_(box_label))
self.SizerDic[box_name] = wx.StaticBoxSizer(self.StaticBoxDic[box_name])
for statictext_name, statictext_label, textctrl_name in [
("VendorLabel", "Vendor:", "vendor"),
("ProductcodeLabel", "Product code:", "product_code"),
("RevisionnumberLabel", "Slave Count:", "revision_number"),
("PhysicsLabel", "Physics:", "physics")]:
self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
self.TextCtrlDic[textctrl_name] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
self.SizerDic["SlaveInfosDetailsInnerSizer"].AddMany([self.StaticTextDic[statictext_name],
self.TextCtrlDic[textctrl_name]])
self.SizerDic["SlaveInfosDetailsBox"].AddSizer(self.SizerDic["SlaveInfosDetailsInnerSizer"])
self.SyncManagersGrid = CustomGrid(self, size=wx.Size(605, 155), style=wx.VSCROLL)
self.SizerDic["SyncManagerInnerSizer"].Add(self.SyncManagersGrid)
self.SizerDic["SyncManagerBox"].Add(self.SizerDic["SyncManagerInnerSizer"])
("InitButton", 0, "INIT", "State Transition to \"Init\" State", self.OnButtonClick, []),
("PreOPButton", 1, "PREOP", "State Transition to \"PreOP\" State", self.OnButtonClick, [
("TargetStateLabel", "Target State:", "TargetState")]),
("SafeOPButton", 2, "SAFEOP", "State Transition to \"SafeOP\" State", self.OnButtonClick, []),
("OPButton", 3, "OP", "State Transition to \"OP\" State", self.OnButtonClick, [
("CurrentStateLabel", "Current State:", "CurrentState")])
for button_name, button_id, button_label, button_tooltipstring, event_method, sub_item in buttons:
self.ButtonDic[button_name] = wx.Button(self, id=button_id, label=_(button_label))
self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method)
self.ButtonDic[button_name].SetToolTipString(button_tooltipstring)
self.SizerDic["SlaveState_up_sizer"].Add(self.ButtonDic[button_name])
for statictext_name, statictext_label, textctrl_name in sub_item:
self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
self.TextCtrlDic[textctrl_name] = wx.TextCtrl(self, size=wx.DefaultSize, style=wx.TE_READONLY)
self.SizerDic["SlaveState_up_sizer"].AddMany([self.StaticTextDic[statictext_name],
self.TextCtrlDic[textctrl_name]])
for button_name, button_label, button_tooltipstring, event_method in [
("StartTimerButton", "Start State Monitoring", "Slave State Update Restart", self.StartTimer),
("StopTimerButton", "Stop State Monitoring", "Slave State Update Stop", self.CurrentStateThreadStop)]:
self.ButtonDic[button_name] = wx.Button(self, label=_(button_label))
self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method)
self.ButtonDic[button_name].SetToolTipString(button_tooltipstring)
self.SizerDic["SlaveState_down_sizer"].Add(self.ButtonDic[button_name])
self.SizerDic["SlaveState_sizer"].AddMany([self.SizerDic["SlaveState_up_sizer"],
self.SizerDic["SlaveState_down_sizer"]])
self.SizerDic["SlaveStateBox"].Add(self.SizerDic["SlaveState_sizer"])
self.SizerDic["SlaveState_inner_main_sizer"].AddMany([
self.SizerDic["SlaveInfosDetailsBox"], self.SizerDic["SyncManagerBox"],
self.SizerDic["SlaveStateBox"]])
self.SizerDic["SlaveState_main_sizer"].Add(self.SizerDic["SlaveState_inner_main_sizer"])
self.SetSizer(self.SizerDic["SlaveState_main_sizer"])
# register a timer for periodic exectuion of slave state update (period: 1000 ms)
self.Bind(wx.EVT_TIMER, self.GetCurrentState)
self.CreateSyncManagerTable()
def CreateSyncManagerTable(self):
Create grid for "SyncManager"
self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames())
self.SyncManagersGrid.SetTable(self.SyncManagersTable)
# set grid alignment attr. (CENTER)
self.SyncManagersGridColAlignements = [wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE,
wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE]
self.SyncManagersGridColSizes = [40, 150, 100, 100, 100, 100]
self.SyncManagersGrid.SetRowLabelSize(0)
for col in range(self.SyncManagersTable.GetNumberCols()):
attr = wx.grid.GridCellAttr()
attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTRE)
self.SyncManagersGrid.SetColAttr(col, attr)
self.SyncManagersGrid.SetColMinimalWidth(col, self.SyncManagersGridColSizes[col])
self.SyncManagersGrid.AutoSizeColumn(col, False)
def RefreshSlaveInfos(self):
Fill data in "Slave Information" and "SyncManager"
slave_infos = self.Controler.GetSlaveInfos()
sync_manager_section = ["vendor", "product_code", "revision_number", "physics"]
if slave_infos is not None:
# this method is same as "TextCtrl.SetValue"
for textctrl_name in sync_manager_section:
self.TextCtrlDic[textctrl_name].SetValue(slave_infos[textctrl_name])
self.SyncManagersTable.SetData(slave_infos["sync_managers"])
self.SyncManagersTable.ResetView(self.SyncManagersGrid)
for textctrl_name in sync_manager_section:
self.TextCtrlDic[textctrl_name].SetValue("")
self.SyncManagersTable.SetData([])
self.SyncManagersTable.ResetView(self.SyncManagersGrid)
def OnButtonClick(self, event):
Event handler for slave state transition button click (Init, PreOP, SafeOP, OP button)
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
state_dic = ["INIT", "PREOP", "SAFEOP", "OP"]
# If target state is one of {INIT, PREOP, SAFEOP}, request slave state transition immediately.
self.Controler.CommonMethod.RequestSlaveState(state_dic[event.GetId()])
self.TextCtrlDic["TargetState"].SetValue(state_dic[event.GetId()])
# If target state is OP, first check "PLC status".
# (1) If current PLC status is "Started", then request slave state transition
# (2) Otherwise, show error message and return
status, _log_count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
if status == PlcStatus.Started:
self.Controler.CommonMethod.RequestSlaveState("OP")
self.TextCtrlDic["TargetState"].SetValue("OP")
self.Controler.CommonMethod.CreateErrorDialog(_("PLC is Not Started"))
def GetCurrentState(self, event):
Timer event handler for periodic slave state monitoring (Default period: 1 sec = 1000 msec).
@param event : wx.TIMER object
if self.IsShownOnScreen() is False:
# Check whether beremiz connected or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = True)
returnVal = self.Controler.CommonMethod.GetSlaveStateFromSlave()
line = returnVal.split("\n")
self.SetCurrentState(line[self.Controler.GetSlavePos()])
def SetCurrentState(self, line):
Show current slave state using the executiob result of "ethercat slaves" command.
@param line : result of "ethercat slaves" command
state_array = ["INIT", "PREOP", "SAFEOP", "OP"]
# parse the execution result of "ethercat slaves" command
# Result example : 0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100)
if token[2] in state_array:
self.TextCtrlDic["CurrentState"].SetValue(token[2])
def StartTimer(self, event):
Event handler for "Start State Monitoring" button.
- start slave state monitoring thread
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
self.SlaveStateThread = wx.Timer(self)
# set timer period (2000 ms)
self.SlaveStateThread.Start(2000)
def CurrentStateThreadStop(self, event):
Event handler for "Stop State Monitoring" button.
- stop slave state monitoring thread
@param event : wx.EVT_BUTTON object
self.SlaveStateThread.Stop()
# -------------------------------------------------------------------------------
# For SDO Management Panel
# -------------------------------------------------------------------------------
class SDOPanelClass(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
self.DatatypeDescription, self.CommunicationObject, self.ManufacturerSpecific, \
self.ProfileSpecific, self.Reserved, self.AllSDOData = range(6)
self.Controler = controler
self.SDOMonitorEntries = {}
#----------------------------- SDO Monitor -------------------------------#
self.RBList = ["ON","OFF"]
self.SDOMonitorRB = wx.RadioBox(self, label=_("monitoring"),
choices=self.RBList, majorDimension=2)
self.SDOMonitorRB.SetSelection(1)
self.Bind(wx.EVT_RADIOBOX, self.OnRadioBox, self.SDOMonitorRB)
self.SDOMonitorGrid = wx.grid.Grid(self,size=wx.Size(850,150),style=wx.EXPAND
|wx.ALIGN_CENTER_HORIZONTAL
|wx.ALIGN_CENTER_VERTICAL)
self.SDOMonitorGrid.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK,
self.onMonitorGridDoubleClick)
#----------------------------- SDO Entries ----------------------------#
self.SDOUpdateBtn = wx.Button(self, label=_("update"))
self.SDOUpdateBtn.Bind(wx.EVT_BUTTON, self.OnSDOUpdate)
self.SDOTraceThread = None
self.SDOMonitoringFlag = False
# Default SDO Page Number
#----------------------------- Sizer --------------------------------------#
self.SDOManagementMainSizer = wx.BoxSizer(wx.VERTICAL)
self.SDOInfoBox = wx.StaticBox(self, label=_("SDO Entries"))
self.SDOMonitorBox = wx.StaticBox(self, label=_("SDO Monitor"))
self.SDONoteBook = SDONoteBook(self, controler=self.Controler)
self.SDOInfoBoxSizer = wx.StaticBoxSizer(self.SDOInfoBox, orient=wx.VERTICAL)
self.SDOMonitorBoxSizer = wx.StaticBoxSizer(self.SDOMonitorBox,
self.SDOInfoBoxSizer.Add(self.SDOUpdateBtn)
self.SDOInfoBoxSizer.Add(self.SDONoteBook, wx.ALL|wx.EXPAND)
self.SDOMonitorBoxSizer.Add(self.SDOMonitorRB)
self.SDOMonitorBoxSizer.Add(self.SDOMonitorGrid)
self.SDOManagementMainSizer.AddMany([self.SDOInfoBoxSizer,
self.SDOMonitorBoxSizer])
self.SetSizer(self.SDOManagementMainSizer)
#----------------------------- fill the contents --------------------------#
#self.entries = self.Controler.CTNParent.CTNParent.GetEntriesList()
slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
type_infos = slave.getType()
device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
self.entries = device.GetEntriesList()
self.Controler.CommonMethod.SDOVariables = []
self.Controler.CommonMethod.SDOSubEntryData = []
self.Controler.CommonMethod.ClearSDODataSet()
self.SDOParserXML(self.entries)
self.SDONoteBook.CreateNoteBook()
self.CreateSDOMonitorGrid()
def OnSDOUpdate(self, event):
SlavePos = self.Controler.GetSlavePos()
num = self.SDOPageNum - 1
for i in range(len(self.Controler.CommonMethod.SDOVariables)):
data = self.Controler.GetCTRoot()._connector.GetSDOEntriesData(
self.Controler.CommonMethod.SDOVariables[i], SlavePos)
self.Controler.CommonMethod.SDOVariables[i] = data
SDOUploadEntries = self.Controler.CommonMethod.SDOVariables[num]
data = self.Controler.GetCTRoot()._connector.GetSDOEntriesData(SDOUploadEntries, SlavePos)
self.Controler.CommonMethod.SDOVariables[num] = data
self.SDONoteBook.CreateNoteBook()
def OnRadioBox(self, event):
There are two selections that are on and off.
If the on is selected, the monitor thread begins to run.
If the off is selected, the monitor thread gets off.
@param event: wx.EVT_RADIOBOX object
CheckThreadFlag = self.SDOMonitoringThreadOn()
self.SDOMonitorRB.SetSelection(off)
elif event.GetInt() == off:
self.SDOMonitoringThreadOff()
def SDOMonitoringThreadOn(self):
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
self.SetSDOTraceValues(self.SDOMonitorEntries)
self.Controler.GetCTRoot()._connector.GetSDOData()
self.SDOTraceThread = Thread(target=self.SDOMonitorThreadProc)
self.SDOMonitoringFlag = True
self.SDOTraceThread.start()
return check_connect_flag
def SDOMonitoringThreadOff(self):
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
self.SDOMonitoringFlag = False
if self.SDOTraceThread is not None:
self.SDOTraceThread.join()
self.SDOTraceThread = None
self.Controler.GetCTRoot()._connector.StopSDOThread()
def SetSDOTraceValues(self, SDOMonitorEntries):
SlavePos = self.Controler.GetSlavePos()
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = True)
self.Controler.GetCTRoot()._connector.SetSDOTraceValues(SDOMonitorEntries, SlavePos)
def SDOMonitorThreadProc(self):
while self.SDOMonitoringFlag and self.Controler.GetCTRoot()._connector.PLCStatus != "Started":
self.SDOValuesList = self.Controler.GetCTRoot()._connector.GetSDOData()
LocalData = self.SDOValuesList[0].items()
if self.SDOValuesList[1] != self.Controler.GetSlavePos():
for (idx, subidx), data in LocalData:
self.SDOMonitorGrid.SetCellValue(row, 6, str(data["value"]))
def CreateSDOMonitorGrid(self):
It creates SDO Monitor table and specifies cell size and labels.
self.SDOMonitorGrid.CreateGrid(0,7)
SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 70),
(4, 40), (5, 450), (6, 85)]
for (index, size) in SDOCellSize:
self.SDOMonitorGrid.SetColSize(index, size)
self.SDOMonitorGrid.SetRowLabelSize(0)
SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
(3, "Type"), (4, "Size"), (5, "Name"), (6, "Value")]
for (index, label) in SDOTableLabel:
self.SDOMonitorGrid.SetColLabelValue(index, label)
self.SDOMonitorGrid.SetColLabelAlignment(index, wx.ALIGN_CENTER)
def onMonitorGridDoubleClick(self, event):
Event Handler for double click on the SDO entries table.
It adds the entry into the SDO monitor table.
If the entry is already in the SDO monitor table,
then it's removed from the SDO monitor table.
@pram event: gridlib.EVT_GRID_CELL_LEFT_DCLICK object
idx = self.SDOMonitorGrid.GetCellValue(row, 0)
subIdx = self.SDOMonitorGrid.GetCellValue(row, 1)
del self.SDOMonitorEntries[(idx, subIdx)]
self.SDOMonitorGrid.DeleteRows(row, 1)
self.SetSDOTraceValues(self.SDOMonitorEntries)
self.SDOMonitorGrid.Refresh()
def SDOParserXML(self, entries):
Parse SDO data set that obtain "ESI file"
@param entries: SDO entry list
entries_list = entries.items()
self.ForDefaultValueFlag = False
self.sub_entry_value_list = []
for (index, subidx), entry in entries_list:
# exclude entry that isn't in the objects
check_mapping = entry["PDOMapping"]
if check_mapping is "T" or check_mapping is "R":
if "PDO index" not in entry.keys():
idx = "0" + entry["Index"].strip("#")
#subidx = hex(int(entry["SubIndex"], 0))
subidx = "0x" + entry["SubIndex"]
default_value = entry["DefaultData"]
# Result of SlaveSDO data parsing. (data type : dictionary)
self.Data = {'idx':idx, 'subIdx':subidx, 'access':entry["Access"],
'type':datatype, 'size': str(entry["BitSize"]),
'name':entry["Name"], 'value':default_value}
category_divide_value = [0x1000, 0x2000, 0x6000, 0xa000, 0xffff]
for count in range(len(category_divide_value)) :
if int(idx, 0) < category_divide_value[count]:
self.Controler.CommonMethod.SDOVariables[count].append(self.Data)
self.Controler.CommonMethod.SDOSubEntryData = self.sub_entry_value_list
#-------------------------------------------------------------------------------
# For SDO Notebook (divide category)
# -------------------------------------------------------------------------------
class SDONoteBook(wx.Notebook):
def __init__(self, parent, controler):
@param parent: Reference to the parent SDOPanelClass class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Notebook.__init__(self, parent, id=-1, size=(850, 500))
self.Controler = controler
def CreateNoteBook(self):
Create each NoteBook page, divided SDO index
According to EtherCAT Communication(03/2011), 158p
page_texts = [("all", self.parent.AllSDOData),
("0x0000 - 0x0ff", self.parent.DatatypeDescription),
("0x1000 - 0x1fff", self.parent.CommunicationObject),
("0x2000 - 0x5fff", self.parent.ManufacturerSpecific),
("0x6000 - 0x9fff", self.parent.ProfileSpecific),
("0xa000 - 0xffff", self.parent.Reserved)]
# page_tooltip_string = ["SDO Index 0x0000 - 0x0fff : Data Type Description",
# "SDO Index 0x1000 - 0x1fff : Communication object",
# "SDO Index 0x2000 - 0x5fff : Manufacturer specific",
# "SDO Index 0x6000 - 0x9fff : Profile specific",
# "SDO Index 0xa000 - 0xffff : Reserved",
self.Controler.CommonMethod.SDOVariables[5] = []
self.Controler.CommonMethod.SDOVariables[5] += self.Controler.CommonMethod.SDOVariables[i]
for txt, count in page_texts:
self.Data = self.Controler.CommonMethod.SDOVariables[count]
self.SubEntryData = self.Controler.CommonMethod.SDOSubEntryData
self.Win = SlaveSDOTable(self, self.Data, self.SubEntryData)
self.AddPage(self.Win, txt)
def OnPageChanged(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
sel = self.GetSelection()
self.parent.SDOPageNum = new
def OnPageChanging(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
sel = self.GetSelection()
# -------------------------------------------------------------------------------
# For SDO Grid (fill index, subindex, etc...)
# -------------------------------------------------------------------------------
class SlaveSDOTable(wx.grid.Grid):
def __init__(self, parent, data, fixed_value):
@param parent: Reference to the parent SDOPanelClass class
@param data: SDO data after parsing "SDOParser" method
wx.grid.Grid.__init__(self, parent, -1, size=(830, 490),
style=wx.EXPAND | wx.ALIGN_CENTRE_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)
self.Controler = parent.Controler
self.sub_entry_value = []
self.sub_entry_value = fixed_value
self.CreateGrid(len(self.SDOs), 7)
SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 70),
(4, 40), (5, 400), (6, 135)]
for (index, size) in SDOCellSize:
self.SetColSize(index, size)
SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
(3, "Type"), (4, "Size"), (5, "Name"), (6, "Value")]
for (index, label) in SDOTableLabel:
self.SetColLabelValue(index, label)
self.SetColLabelAlignment(index, wx.ALIGN_CENTER)
attr = wx.grid.GridCellAttr()
# for SDO download and monitoring
self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.onGridDoubleClick)
self.SetColLabelAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)
Cell is filled by new parsing data
sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'name', 'value']
for row_idx in range(len(self.SDOs)):
for col_idx in range(len(self.SDOs[row_idx])):
# the top entries that have sub index is shaded.
if int(self.SDOs[row_idx]['subIdx'], 16) == 0x00:
if int(self.SDOs[row_idx + 1]['subIdx'], 16) is not 0x00:
self.SetCellBackgroundColour(row_idx, col_idx, \
if self.SDOs[row_idx][sdo_list[col_idx]] == "modifying":
if len(self.sub_entry_value) == count:
self.SetCellValue(row_idx, col_idx, self.sub_entry_value[count])
self.SetCellValue(row_idx, col_idx, \
self.SDOs[row_idx][sdo_list[col_idx]])
self.SetReadOnly(row_idx, col_idx, True)
self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
def CheckSDODataAccess(self, row):
check that access field has "rw"
@param row : Selected cell by user
@return Write_flag : If data has "w", flag is true
check = self.SDOs[row]['access']
def ClearStateFlag(self):
StateFlag is notice SDOData access each slave state
self.Controler.CommonMethod.Check_PREOP = False
self.Controler.CommonMethod.Check_SAFEOP = False
self.Controler.CommonMethod.Check_OP = False
def onGridDoubleClick (self, event):
Create dialog for SDO value modify
if user enter data, perform command "ethercat download"
@param event : gridlib.EVT_GRID_CELL_LEFT_DCLICK object
# CheckSDODataAccess is checking that OD(Object Dictionary) has "w"
if event.GetCol() == 6 and self.CheckSDODataAccess(event.GetRow()) :
dlg = wx.TextEntryDialog (self,
"Enter hex or dec value (if enter dec value, " \
+ "it automatically conversed hex value)",
"SDOModifyDialog", style = wx.OK | wx.CANCEL)
start_value = self.GetCellValue(event.GetRow(), event.GetCol())
dlg.SetValue(start_value)
if dlg.ShowModal() == wx.ID_OK:
# Check whether beremiz connected or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
input_val = hex(int(dlg.GetValue(), 0))
return_val = self.Controler.CommonMethod.SDODownload(
self.SDOs[event.GetRow()]["type"],
self.SDOs[event.GetRow()]["idx"],
self.SDOs[event.GetRow()]["subIdx"],
SDOUploadEntry = {"idx" : self.SDOs[event.GetRow()]["idx"],
"subIdx" : self.SDOs[event.GetRow()]["subIdx"],
"size" : self.SDOs[event.GetRow()]["size"]
data = self.Controler.GetCTRoot()._connector.GetSDOEntryData(
SDOUploadEntry, self.Controler.GetSlavePos())
display_val = "%s(%d)" % (hex_val, data)
self.SetCellValue(event.GetRow(), event.GetCol(),
self.Controler.CommonMethod.CreateErrorDialog(\
'SDO Value not completely download, please try again')
self.Controler.GetCTRoot().logger.write_error(return_val)
# Error occured process of "int(variable)"
# User input is not hex, dec value
self.Controler.CommonMethod.CreateErrorDialog(\
'You can input only hex, dec value')
SDOPanel = self.parent.parent
idx = self.SDOs[row]["idx"]
subIdx = self.SDOs[row]["subIdx"]
SDOPanel.SDOMonitorEntries[(idx, subIdx)] = {
"access": self.SDOs[row]["access"],
"type": self.SDOs[row]["type"],
"size": self.SDOs[row]["size"],
"name": self.SDOs[row]["name"],
del_rows = SDOPanel.SDOMonitorGrid.GetNumberRows()
SDOPanel.SDOMonitorGrid.DeleteRows(0, del_rows)
SDOPanel.SDOMonitorGrid.AppendRows(len(SDOPanel.SDOMonitorEntries))
SDOPanel.SetSDOTraceValues(SDOPanel.SDOMonitorEntries)
SME_list = SDOPanel.SDOMonitorEntries.items()
for (idx, subIdx), entry in SME_list:
SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, 0, str(idx))
SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, 1, str(subIdx))
for col, key in [(2, "access"),
SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, col, entry[key])
SDOPanel.SDOMonitorGrid.SetReadOnly(gridRow, col, True)
SDOPanel.SDOMonitorGrid.SetCellAlignment(\
gridRow, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER)
SDOPanel.SDOMonitorGrid.Refresh()
#-------------------------------------------------------------------------------
# PDO Class UI : Panel -> Choicebook (RxPDO, TxPDO) ->
# Notebook (PDO Index) -> Grid (PDO entry)
#-------------------------------------------------------------------------------
class PDOPanelClass(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
line = wx.StaticText(self, -1, "\n In order to control Ethercat device, user must select proper PDO set.\
\n Each PDO sets describe operation modes (CSP, CSV, CST) supported by Ethercat devices.\
\n\n PDOs have two types, RxPDO and TxPDO.\
\n - RxPDO refers to the Receive Process Data Object. It means the control parameters which sent from controller to the EtherCAT Slave device.\
\n In general, ControlWord (0x6040), Modes of Operations (0x6060), and TargetPosition (0x607A) are regarded as RxPDO.\
\n - TxPDO refers to the Transmit Process Data Object. It used to report status of EtherCAT Slave device to the controller in order to calibrate their next actuation.\
\n StatusWord (0x6041), Modes of Operation Display (0x6061), and ActualPosition (0x607A) include in TxPDO.\
\n\n PDO Mapping feature provides available RxPDO and TxPDO sets which defined in Ethercat slave description XML.\
\n If there is no selection of PDO set, first set (0x1600, 0x1A00) will be chosen as default configuration.")
class RxPDOPanelClass(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
#self.PDOIndexList = ["RxPDO"]
#HSAHN ADD. 2015.7.26 PDO Select Function ADD
self.Controler.CommonMethod.RequestPDOInfo()
self.rx_pdo_entries = self.Controler.CommonMethod.GetRxPDOCategory()
if len(self.rx_pdo_entries):
for i in range(len(self.rx_pdo_entries)):
self.PDOcheckBox.append(wx.CheckBox(self, label=str(hex(self.rx_pdo_entries[i]['pdo_index'])), size=(120,15)))
if not self.Controler.SelectedRxPDOIndex and self.rx_pdo_entries[i]['sm'] is not None:
self.PDOcheckBox[-1].SetValue(True)
self.Controler.SelectedRxPDOIndex.append(int(self.PDOcheckBox[-1].GetLabel(), 0))
elif self.rx_pdo_entries[i]['pdo_index'] in self.Controler.SelectedRxPDOIndex:
self.PDOIndexList.append(str(hex(self.rx_pdo_entries[i]['pdo_index'])))
self.PDOcheckBox[-1].SetValue(True)
for cb in self.PDOcheckBox:
self.Bind(wx.EVT_CHECKBOX, self.PDOSelectCheck, cb)
self.PDOListBox = wx.StaticBox(self, label=_("PDO Mapping Select"))
self.PDOListBoxSizer = wx.StaticBoxSizer(self.PDOListBox, orient=wx.HORIZONTAL)
self.RxPDOListBox = wx.StaticBox(self, label=_("RxPDO"))
self.RxPDOListBoxSizer = wx.StaticBoxSizer(self.RxPDOListBox, orient=wx.VERTICAL)
self.RxPDOListBoxInnerSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=10, vgap=5)
self.RxPDOListBoxInnerSizer.AddMany(self.PDOcheckBox[0:len(self.rx_pdo_entries)])
self.RxPDOListBoxSizer.Add(self.RxPDOListBoxInnerSizer)
self.PDOListBoxSizer.Add(self.RxPDOListBoxSizer)
self.PDOWarningText = wx.StaticText(self, -1,
" *Warning*\n\n By default configuration, \n\n first mapping set is selected. \n\n Choose the PDO mapping!",
self.PDOListBoxSizer.Add(self.PDOWarningText)
self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
self.CallPDOChoicebook = PDONoteBook(self, controler=self.Controler, name="Rx")
self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)
self.PDOInformationBox = wx.StaticBox(self, label=_("RxPDO Mapping List"))
self.PDOInformationBoxSizer = wx.StaticBoxSizer(self.PDOInformationBox, orient=wx.VERTICAL)
self.PDOInformationBoxSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
self.PDOMonitoringEditorMainSizer.Add(self.PDOListBoxSizer)
self.PDOMonitoringEditorMainSizer.Add(self.PDOInformationBoxSizer)
self.SetSizer(self.PDOMonitoringEditorMainSizer)
sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
line = wx.StaticText(self, -1, "\n This device does not support RxPDO.")
def LoadPDOSelectData(self):
RxPDOData = self.Controler.BaseParams.getRxPDO()
RxPDOs = RxPDOData.split()
self.Controler.SelectedRxPDOIndex.append(int(RxPDO, 0))
def PDOSelectCheck(self, event):
# add jblee for Save User Select
cb = event.GetEventObject()
# prevent duplicated check
if cb.GetValue() and int(cb.GetLabel(), 0) not in self.Controler.SelectedRxPDOIndex:
self.Controler.SelectedRxPDOIndex.append(int(cb.GetLabel(), 0))
self.PDOIndexList.append(cb.GetLabel())
self.Controler.SelectedRxPDOIndex.remove(int(cb.GetLabel(), 0))
self.PDOIndexList.remove(cb.GetLabel())
for PDOIndex in self.PDOIndexList:
data = data + " " + PDOIndex
self.Controler.BaseParams.setRxPDO(data)
self.Controler.GetCTRoot().CTNRequestSave()
for PDOIndex in self.Controler.SelectedRxPDOIndex:
self.PDOIndexList.append(str(hex(PDOIndex)))
for PDOIndex in self.PDOIndexList:
data = data + " " + PDOIndex
self.Controler.BaseParams.setRxPDO(data)
# add jblee for check exclude pdo list
def PDOExcludeCheck(self):
#files = os.listdir(self.Controler.CTNPath())
#filepath = os.path.join(self.Controler.CTNPath(), "DataForPDO.txt")
CurIndexs = self.Controler.SelectedRxPDOIndex
for CB in self.PDOcheckBox:
if len(CB.GetLabel().split()) > 1:
CB.SetLabel(CB.GetLabel().split()[0])
for pdo in self.rx_pdo_entries:
for CurIndex in CurIndexs:
if pdo["pdo_index"] == CurIndex:
ex_list = pdo["exclude_list"]
for CB in self.PDOcheckBox:
if CB.GetLabel() == hex(ex_item):
CB.SetLabel(CB.GetLabel() + " (Excluded)")
def RefreshPDOInfo(self):
Call RequestPDOInfo method and create Choicebook
self.Controler.CommonMethod.RequestPDOInfo()
self.CallPDOChoicebook.Destroy()
self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler, name="Rx")
class TxPDOPanelClass(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
#HSAHN ADD. 2015.7.26 PDO Select Function ADD
self.Controler.CommonMethod.RequestPDOInfo()
self.tx_pdo_entries = self.Controler.CommonMethod.GetTxPDOCategory()
if len(self.tx_pdo_entries):
for i in range(len(self.tx_pdo_entries)):
self.PDOcheckBox.append(wx.CheckBox(self, label=str(hex(self.tx_pdo_entries[i]['pdo_index'])), size=(120,15)))
if not self.Controler.SelectedTxPDOIndex and self.tx_pdo_entries[i]['sm'] is not None:
self.PDOcheckBox[-1].SetValue(True)
self.Controler.SelectedTxPDOIndex.append(int(self.PDOcheckBox[-1].GetLabel(), 0))
elif self.tx_pdo_entries[i]['pdo_index'] in self.Controler.SelectedTxPDOIndex:
self.PDOIndexList.append(str(hex(self.tx_pdo_entries[i]['pdo_index'])))
self.PDOcheckBox[-1].SetValue(True)
for cb in self.PDOcheckBox:
self.Bind(wx.EVT_CHECKBOX, self.PDOSelectCheck, cb)
self.PDOListBox = wx.StaticBox(self, label=_("PDO Mapping Select"))
self.PDOListBoxSizer = wx.StaticBoxSizer(self.PDOListBox, orient=wx.HORIZONTAL)
self.TxPDOListBox = wx.StaticBox(self, label=_("TxPDO"))
self.TxPDOListBoxSizer = wx.StaticBoxSizer(self.TxPDOListBox, orient=wx.VERTICAL)
self.TxPDOListBoxInnerSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=10, vgap=5)
self.TxPDOListBoxInnerSizer.AddMany(self.PDOcheckBox[0:len(self.tx_pdo_entries)])
self.TxPDOListBoxSizer.Add(self.TxPDOListBoxInnerSizer)
self.PDOListBoxSizer.Add(self.TxPDOListBoxSizer)
self.PDOWarningText = wx.StaticText(self, -1,
" *Warning*\n\n By default configuration, \n\n first mapping set is selected. \n\n Choose the PDO mapping!",
self.PDOListBoxSizer.Add(self.PDOWarningText)
self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
self.CallPDOChoicebook = PDONoteBook(self, controler=self.Controler, name="Tx")
self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)
self.PDOInformationBox = wx.StaticBox(self, label=_("TxPDO Mapping List"))
self.PDOInformationBoxSizer = wx.StaticBoxSizer(self.PDOInformationBox, orient=wx.VERTICAL)
self.PDOInformationBoxSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
self.PDOMonitoringEditorMainSizer.Add(self.PDOListBoxSizer)
self.PDOMonitoringEditorMainSizer.Add(self.PDOInformationBoxSizer)
self.SetSizer(self.PDOMonitoringEditorMainSizer)
sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
line = wx.StaticText(self, -1, "\n This device does not support TxPDO.")
def LoadPDOSelectData(self):
TxPDOData = self.Controler.BaseParams.getTxPDO()
TxPDOs = TxPDOData.split()
self.Controler.SelectedTxPDOIndex.append(int(TxPDO, 0))
def PDOSelectCheck(self, event):
# add jblee for Save User Select
cb = event.GetEventObject()
# prevent duplicated check
if cb.GetValue() and int(cb.GetLabel(), 0) not in self.Controler.SelectedTxPDOIndex:
self.Controler.SelectedTxPDOIndex.append(int(cb.GetLabel(), 0))
self.PDOIndexList.append(cb.GetLabel())
self.Controler.SelectedTxPDOIndex.remove(int(cb.GetLabel(), 0))
self.PDOIndexList.remove(cb.GetLabel())
for PDOIndex in self.PDOIndexList:
data = data + " " + PDOIndex
self.Controler.BaseParams.setTxPDO(data)
self.Controler.GetCTRoot().CTNRequestSave()
for PDOIndex in self.Controler.SelectedTxPDOIndex:
self.PDOIndexList.append(str(hex(PDOIndex)))
for PDOIndex in self.PDOIndexList:
data = data + " " + PDOIndex
self.Controler.BaseParams.setTxPDO(data)
# add jblee for check exclude pdo list
def PDOExcludeCheck(self):
CurIndexs = self.Controler.SelectedTxPDOIndex
for CB in self.PDOcheckBox:
if len(CB.GetLabel().split()) > 1:
CB.SetLabel(CB.GetLabel().split()[0])
for pdo in self.tx_pdo_entries:
for CurIndex in CurIndexs:
if pdo["pdo_index"] == CurIndex:
ex_list = pdo["exclude_list"]
for CB in self.PDOcheckBox:
if CB.GetLabel() == hex(ex_item):
CB.SetLabel(CB.GetLabel() + " (Excluded)")
Call RequestPDOInfo method and create Choicebook
self.Controler.CommonMethod.RequestPDOInfo()
self.CallPDOChoicebook.Destroy()
self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler, name="Tx")
# -------------------------------------------------------------------------------
# For PDO Notebook (divide PDO index)
# -------------------------------------------------------------------------------
class PDONoteBook(wx.Notebook):
def __init__(self, parent, name, controler):
@param parent: Reference to the parent PDOChoicebook class
@param name: identifier whether RxPDO or TxPDO
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Notebook.__init__(self, parent, id=-1, size=(600, 400))
self.Controler = controler
# obtain pdo_info and pdo_entry
# pdo_info include (PDO index, name, number of entry)
pdo_info = self.Controler.CommonMethod.GetTxPDOCategory()
pdo_entry = self.Controler.CommonMethod.GetTxPDOInfo()
title = str(hex(tmp['pdo_index']))
pdo_info = self.Controler.CommonMethod.GetRxPDOCategory()
pdo_entry = self.Controler.CommonMethod.GetRxPDOInfo()
title = str(hex(tmp['pdo_index']))
# Add page depending on the number of pdo_info
win = PDOEntryTable(self, pdo_info, pdo_entry, count)
# -------------------------------------------------------------------------------
# For PDO Grid (fill entry index, subindex etc...)
# -------------------------------------------------------------------------------
class PDOEntryTable(wx.grid.Grid):
def __init__(self, parent, info, entry, count):
@param parent: Reference to the parent PDONoteBook class
@param info : data structure including entry index, sub index, name, length, type
@param entry : data structure including index, name, entry number
@param count : page number
wx.grid.Grid.__init__(self, parent, -1, size=(500, 400), pos=wx.Point(0, 0),
style=wx.EXPAND | wx.ALIGN_CENTRE_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)
self.Controler = parent.Controler
self.CreateGrid(self.PDOInfo[self.Count]['number_of_entry'], 5)
PDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Length"),
(3, "Type"), (4, "Name")]
for (index, label) in PDOTableLabel:
self.SetColLabelValue(index, label)
PDOCellSize = [(0, 45), (1, 65), (2, 55), (3, 40), (4, 300)]
for (index, size) in PDOCellSize:
self.SetColSize(index, size)
self.SetColLabelAlignment(index, wx.ALIGN_LEFT)
attr = wx.grid.GridCellAttr()
Cell is filled by new parsing data in XML
for i in range(self.Count + 1):
list_index += self.PDOInfo[i]['number_of_entry']
start_value = list_index - self.PDOInfo[self.Count]['number_of_entry']
pdo_list = ['entry_index', 'subindex', 'bitlen', 'type', 'name']
for row_idx in range(self.PDOInfo[self.Count]['number_of_entry']):
for col_idx in range(len(self.PDOEntry[row_idx])):
# entry index is converted hex value.
self.SetCellValue(row_idx, col_idx, hex(self.PDOEntry[start_value][pdo_list[col_idx]]))
self.SetCellValue(row_idx, col_idx, str(self.PDOEntry[start_value][pdo_list[col_idx]]))
self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
self.SetReadOnly(row_idx, col_idx, True)
self.SetRowSize(row_idx, 25)
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
class MDPPanel(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
sizer = wx.FlexGridSizer(cols=3, hgap=20, rows=1, vgap=20)
leftInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10)
# Include Add, Delete Button
middleInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10)
rightInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10)
# Get Module Name as Array
# MDPArray = {SlaveName, [data0, data1, ...], SlotIndexIncrement, SlotPdoIncrement}
# data = [ModuleName, ModuleInfo, [PDOInfo1, PDOInfo2, ...]]
# PDOInfo = {Index, Name, BitSize, Access, PDOMapping, SubIndex, Type}
slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
type_infos = slave.getType()
MDPArray = self.Controler.CTNParent.CTNParent.GetMDPInfos(type_infos)
for info in MDPArray[0][1]:
self.ModuleLabel = wx.StaticText(self, -1, "Module")
self.ModuleListBox = wx.ListBox(self, size = (150, 200), choices = NameSet)
#self.ModuleListBox = wx.ListBox(self, size = (150, 200), choices = [])
self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnModuleListBoxDCClick, self.ModuleListBox)
self.AddButton = wx.Button(self, label=_(" Add Module "))
self.DeleteButton = wx.Button(self, label=_("Delete Module"))
self.AddButton.Bind(wx.EVT_BUTTON, self.OnAddButton)
self.DeleteButton.Bind(wx.EVT_BUTTON, self.OnDeleteButton)
self.SlotLabel = wx.StaticText(self, -1, "Slot")
self.SlotListBox = wx.ListBox(self, size = (150, 200))
self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnSlotListBoxDCClick, self.SlotListBox)
leftInnerSizer.AddMany([self.ModuleLabel, self.ModuleListBox])
middleInnerSizer.Add(self.AddButton, 0, wx.TOP, 100)
middleInnerSizer.Add(self.DeleteButton, 0, wx.BOTTOM, 120)
rightInnerSizer.AddMany([self.SlotLabel, self.SlotListBox])
sizer.AddMany([leftInnerSizer, middleInnerSizer, rightInnerSizer])
files = os.listdir(self.Controler.CTNPath())
filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
moduleDataFile = open(filepath, 'r')
lines = moduleDataFile.readlines()
module_pos = line.split()[-1]
name_len_limit = len(line) - len(module_pos) - 2
module_name = line[0:name_len_limit]
self.SelectModule.append((module_name, int(module_pos)))
for (item, pos) in self.SelectModule:
slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
localModuleInfo.append(slotString)
self.SlotListBox.SetItems(localModuleInfo)
moduleDataFile = open(filepath, 'w')
def OnAddButton(self, event):
files = os.listdir(self.Controler.CTNPath())
filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
moduleDataFile = open(filepath, 'w')
selectNum = self.ModuleListBox.GetSelection()
selectStr = self.ModuleListBox.GetString(selectNum)
self.SelectModule.append((selectStr, selectNum))
for (item, pos) in self.SelectModule:
slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
localModuleInfo.append(slotString)
self.SlotListBox.SetItems(localModuleInfo)
def OnDeleteButton(self, event):
files = os.listdir(self.Controler.CTNPath())
filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
moduleDataFile = open(filepath, 'w')
selectNum = self.SlotListBox.GetSelection()
selectStr = self.SlotListBox.GetString(selectNum)
self.SelectModule.pop(selectNum)
for (item, pos) in self.SelectModule:
moduleDataFile.write(item + " " + str(pos) + "\n")
slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
localModuleInfo.append(slotString)
self.SlotListBox.SetItems(localModuleInfo)
def OnModuleListBoxDCClick(self, event):
files = os.listdir(self.Controler.CTNPath())
filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
moduleDataFile = open(filepath, 'w')
selectNum = self.ModuleListBox.GetSelection()
selectStr = self.ModuleListBox.GetString(selectNum)
self.SelectModule.append((selectStr, selectNum))
for (item, pos) in self.SelectModule:
moduleDataFile.write(item + " " + str(pos) + "\n")
slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
localModuleInfo.append(slotString)
module = self.Controler.CTNParent.CTNParent.GetSelectModule(pos)
self.Controler.CommonMethod.SavePDOData(module)
self.SlotListBox.SetItems(localModuleInfo)
def OnSlotListBoxDCClick(self, event):
files = os.listdir(self.Controler.CTNPath())
filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
moduleDataFile = open(filepath, 'w')
selectNum = self.SlotListBox.GetSelection()
selectStr = self.SlotListBox.GetString(selectNum)
self.SelectModule.pop(selectNum)
for (item, pos) in self.SelectModule:
moduleDataFile.write(item + " " + str(pos) + "\n")
slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
localModuleInfo.append(slotString)
self.SlotListBox.SetItems(localModuleInfo)
# -------------------------------------------------------------------------------
# For EEPROM Access Main Panel
# (This class explain EEPROM Access)
# -------------------------------------------------------------------------------
class EEPROMAccessPanel(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
sizer = wx.FlexGridSizer(cols=1, hgap=20, rows=3, vgap=20)
line = wx.StaticText(self, -1, "\n EEPROM Access is composed to SmartView and HexView. \
\n\n - SmartView shows Config Data, Device Identity, Mailbox settings, etc. \
\n\n - HexView shows EEPROM's contents.")
# -------------------------------------------------------------------------------
# -------------------------------------------------------------------------------
class SlaveSiiSmartView(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
# PDI Type 1, 13 unknown Type, Fix Future
self.PDIType = {0 :['none', '00000000'],
1 :['unknown', '00000000'],
4 :['Digital I/O', '00000100'],
5 :['SPI Slave', '00000101'],
7 :['EtherCAT Bridge (port3)', '00000111'],
8 :['uC async. 16bit', '00001000'],
9 :['uC async. 8bit', '00001001'],
10 :['uC sync. 16bit', '00001010'],
11 :['uC sync. 8bit', '00001011'],
13 :['unknown', '00000000'],
16 :['32 Digtal Input and 0 Digital Output', '00010000'],
17 :['24 Digtal Input and 8 Digital Output', '00010001'],
18 :['16 Digtal Input and 16 Digital Output','00010010'],
19 :['8 Digtal Input and 24 Digital Output', '00010011'],
20 :['0 Digtal Input and 32 Digital Output', '00010100'],
128:['On-chip bus', '11111111']
sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5)
button_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5)
for button, mapping_method in [("Write EEPROM", self.WriteToEEPROM),
("Read EEPROM", self.ReadFromEEPROM)]:
btn = wx.Button(self, -1, button, size=(150, 40))
button_sizer.Add(btn, border=10, flag=wx.ALL)
btn.Bind(wx.EVT_BUTTON, mapping_method)
self.TreeListCtrl = SmartViewTreeListCtrl(self, self.Controler)
sizer.Add(button_sizer, border=10, flag=wx.ALL)
sizer.Add(self.TreeListCtrl, border=10, flag=wx.ALL)
def Create_SmartView(self):
SmartView shows information based on XML as initial value.
self.Controler.CommonMethod.SmartViewInfosFromXML = self.Controler.CommonMethod.GetSmartViewInfos()
def WriteToEEPROM(self, event):
Open binary file (user select) and write the selected binary data to EEPROM
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not, and whether status is "Started" or not.
check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
status, _log_count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
if status is not PlcStatus.Started:
dialog = wx.FileDialog(self, _("Choose a binary file"), os.getcwd(), "", _("bin files (*.bin)|*.bin"), wx.OPEN)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
binfile = open(filepath, "rb")
self.SiiBinary = binfile.read()
self.Controler.CommonMethod.SiiWrite(self.SiiBinary)
# refresh data structure kept by master
self.Controler.CommonMethod.Rescan()
# save binary data as inner global data of beremiz
# for fast loading when slave plugin node is reopened.
self.Controler.CommonMethod.SiiData = self.SiiBinary
self.Controler.CommonMethod.CreateErrorDialog(_('The file does not exist!'))
def ReadFromEEPROM(self, event):
Refresh displayed data based on slave EEPROM and save binary file through dialog
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
self.SiiBinary = self.Controler.CommonMethod.LoadData()
dialog = wx.FileDialog(self, _("Save as..."), os.getcwd(),
"slave0.bin", _("bin files (*.bin)|*.bin|All files|*.*"),
wx.SAVE | wx.OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
binfile = open(filepath, "wb")
binfile.write(self.SiiBinary)
Set data based on XML initially
# Config Data: EEPROM Size, PDI Type, Device Emulation
# Find PDI Type in pdiType dictionary
cnt_pdi_type = self.Controler.CommonMethod.SmartViewInfosFromXML["pdi_type"]
for i in self.PDIType.keys():
cnt_pdi_type = self.PDIType[i][0]
for treelist, data in [("EEPROM Size (Bytes)",
str(self.Controler.CommonMethod.SmartViewInfosFromXML["eeprom_size"])),
self.Controler.CommonMethod.SmartViewInfosFromXML["device_emulation"])]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
# Device Identity: Vendor ID, Product Code, Revision No., Serial No.
for treelist, data in [("Vendor ID", self.Controler.CommonMethod.SmartViewInfosFromXML["vendor_id"]),
("Product Code", self.Controler.CommonMethod.SmartViewInfosFromXML["product_code"]),
("Revision No.", self.Controler.CommonMethod.SmartViewInfosFromXML["revision_no"]),
("Serial No.", self.Controler.CommonMethod.SmartViewInfosFromXML["serial_no"])]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
# Mailbox: Supported Mailbox, Bootstrap Configuration, Standard Configuration
for treelist, data in [("Supported Mailbox", self.Controler.CommonMethod.SmartViewInfosFromXML["supported_mailbox"]),
("Bootstrap Configuration", ""),
("Standard Configuration", "")]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)
# Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
for treelist, data in [("Receive Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outstart"]),
("Receive Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outlength"]),
("Send Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_instart"]),
("Send Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_inlength"])]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.BootstrapConfig[treelist], data, 1)
# Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
for treelist, data in [("Receive Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_outstart"]),
("Receive Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_outlength"]),
("Send Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_instart"]),
("Send Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_inlength"])]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.StandardConfig[treelist], data, 1)
Set data based on slave EEPROM.
# sii_dict = { Parameter : (WordAddress, WordSize) }
'PDIConfiguration': ('1', 1),
'PulseLengthOfSYNCSignals': ('2', 1),
'ExtendedPDIConfiguration': ('3', 1),
'ConfiguredStationAlias': ('4', 1),
'RevisionNumber': ('c', 2),
'SerialNumber': ('e', 2),
'Execution Delay': ('10', 1),
'BootstrapReceiveMailboxOffset': ('14', 1),
'BootstrapReceiveMailboxSize': ('15', 1),
'BootstrapSendMailboxOffset': ('16', 1),
'BootstrapSendMailboxSize': ('17', 1),
'StandardReceiveMailboxOffset': ('18', 1),
'StandardReceiveMailboxSize': ('19', 1),
'StandardSendMailboxOffset': ('1a', 1),
'StandardSendMailboxSize': ('1b', 1),
'MailboxProtocol': ('1c', 1),
'First Category Type/Vendor Specific': ('40', 1),
'Following Category Word Size': ('41', 1),
'Category Data': ('42', 1),
# Config Data: EEPROM Size, PDI Type, Device Emulation
# EEPROM's data in address '0x003f' is Size of EEPROM in KBit-1
eeprom_size = str((int(self.GetWordAddressData(sii_dict.get('Size'), 10))+1)//8*1024)
# Find PDI Type in pdiType dictionary
cnt_pdi_type = int(self.GetWordAddressData(sii_dict.get('PDIControl'), 16).split('x')[1][2:4], 16)
for i in self.PDIType.keys():
cnt_pdi_type = self.PDIType[i][0]
device_emulation = str(bool(int("{:0>16b}".format(int(self.GetWordAddressData(sii_dict.get('PDIControl'), 16), 16))[7])))
for treelist, data in [("EEPROM Size (Bytes)", eeprom_size),
("PDI Type", cnt_pdi_type),
("Device Emulation", device_emulation)]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
# Device Identity: Vendor ID, Product Code, Revision No., Serial No.
("Vendor ID", self.GetWordAddressData(sii_dict.get('VendorID'), 16)),
("Product Code", self.GetWordAddressData(sii_dict.get('ProductCode'), 16)),
("Revision No.", self.GetWordAddressData(sii_dict.get('RevisionNumber'), 16)),
("Serial No.", self.GetWordAddressData(sii_dict.get('SerialNumber'), 16))]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
# EEORPOM's word address '1c' indicates supported mailbox protocol.
# each value of mailbox protocol :
# VoE(0x0020), SoE(0x0010), FoE(0x0008), CoE(0x0004), EoE(0x0002), AoE(0x0001)
mailbox_protocol = ["VoE, ", "SoE, ", "FoE, ", "CoE, ", "EoE, ", "AoE, "]
mailbox_data = "{:0>8b}".format(int(self.GetWordAddressData(sii_dict.get('MailboxProtocol'), 16), 16))
for protocol in range(6):
if mailbox_data[protocol+2] == '1':
supported_mailbox += mailbox_protocol[protocol]
supported_mailbox = supported_mailbox.strip(", ")
for treelist, data in [("Supported Mailbox", supported_mailbox),
("Bootstrap Configuration", ""),
("Standard Configuration", "")]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)
# Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
("Receive Offset", self.GetWordAddressData(sii_dict.get('BootstrapReceiveMailboxOffset'), 10)),
("Receive Size", self.GetWordAddressData(sii_dict.get('BootstrapReceiveMailboxSize'), 10)),
("Send Offset", self.GetWordAddressData(sii_dict.get('BootstrapSendMailboxOffset'), 10)),
("Send Size", self.GetWordAddressData(sii_dict.get('BootstrapSendMailboxSize'), 10))]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.BootstrapConfig[treelist], data, 1)
# Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
("Receive Offset", self.GetWordAddressData(sii_dict.get('StandardReceiveMailboxOffset'), 10)),
("Receive Size", self.GetWordAddressData(sii_dict.get('StandardReceiveMailboxSize'), 10)),
("Send Offset", self.GetWordAddressData(sii_dict.get('StandardSendMailboxOffset'), 10)),
("Send Size", self.GetWordAddressData(sii_dict.get('StandardSendMailboxSize'), 10))]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.StandardConfig[treelist], data, 1)
def MakeStaticBoxSizer(self, boxlabel):
@param boxlabel : label of box sizer
@return sizer : the StaticBoxSizer labeled 'boxlabel'
box = wx.StaticBox(self, -1, boxlabel)
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
def GetWordAddressData(self, dict_tuple, format):
This method converts word address data from EEPROM binary.
@param dict_tuple : element of 'sii_dict' dictionary in SetEEPROMData()
@param format : format of data. It can be 16(hex), 10(decimal) and 2(binary).
offset = int(str(dict_tuple[0]), 16) * 2
length = int(str(dict_tuple[1]), 16) * 2
for index in range(length):
hexdata = hex(ord(self.SiiBinary[offset + index]))[2:]
list.append(hexdata.zfill(2))
return '0x' + ''.join(data)
return str(int(str(''.join(data)), 16))
# -------------------------------------------------------------------------------
# For Smart View TreeListCtrl
# -------------------------------------------------------------------------------
class SmartViewTreeListCtrl(wx.Panel):
def __init__(self, parent, Controler):
@param parent: Reference to the parent SlaveSiiSmartView class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1, size=(350, 500))
self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=(350, 500),
style=(wx.TR_DEFAULT_STYLE |
wx.TR_FULL_ROW_HIGHLIGHT |
self.Tree.AddColumn("Description", width=200)
self.Tree.AddColumn("Value", width=140)
self.Tree.SetMainColumn(0)
self.Root = self.Tree.AddRoot("")
for lv1 in ["Config Data", "Device Identity", "Mailbox"]:
self.Level1Nodes[lv1] = self.Tree.AppendItem(self.Root, lv1)
for lv2 in ["EEPROM Size (Bytes)", "PDI Type", "Device Emulation"]:
self.ConfigData[lv2] = self.Tree.AppendItem(self.Level1Nodes["Config Data"], lv2)
for lv2 in ["Vendor ID", "Product Code", "Revision No.", "Serial No."]:
self.DeviceIdentity[lv2] = self.Tree.AppendItem(self.Level1Nodes["Device Identity"], lv2)
for lv2 in ["Supported Mailbox", "Bootstrap Configuration", "Standard Configuration"]:
self.Mailbox[lv2] = self.Tree.AppendItem(self.Level1Nodes["Mailbox"], lv2)
# Children of Bootstrap Configuration
self.BootstrapConfig = {}
for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
self.BootstrapConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Bootstrap Configuration"], lv3)
# Children of Standard Configuration
for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
self.StandardConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Standard Configuration"], lv3)
self.Level1Nodes["Config Data"],
self.Level1Nodes["Device Identity"],
self.Level1Nodes["Mailbox"],
self.Mailbox["Bootstrap Configuration"],
self.Mailbox["Standard Configuration"]]:
# -------------------------------------------------------------------------------
# shows EEPROM binary as hex data and characters.
# -------------------------------------------------------------------------------
def __init__(self, parent, controler):
@param parent: Reference to the parent EtherCATManagementTreebook class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
self.HexViewSizer = {"view": wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10),
"siiButton": wx.BoxSizer()}
for key, evt_handler in [
("Sii Upload", self.OnButtonSiiUpload),
("Sii Download", self.OnButtonSiiDownload),
("Write to File", self.OnButtonWriteToBinFile),
("Read from File", self.OnButtonReadFromBinFile),
("XML to EEPROM Image", self.OnButtonXmlToEEPROMImg)]:
self.HexViewButton[key] = wx.Button(self, -1, key)
self.HexViewButton[key].Bind(wx.EVT_BUTTON, evt_handler)
self.HexViewSizer["siiButton"].Add(self.HexViewButton[key])
self.SiiBinary = self.Controler.CommonMethod.XmlToEeprom()
self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
self.SiiGrid = SiiGridTable(self, self.Controler, self.HexRow, self.HexCol)
self.HexViewSizer["view"].AddMany([self.HexViewSizer["siiButton"], self.SiiGrid])
self.SiiGrid.CreateGrid(self.HexRow, self.HexCol)
self.SetSizer(self.HexViewSizer["view"])
self.HexViewSizer["view"].FitInside(self.parent.parent)
self.parent.parent.FitInside()
self.SiiGrid.SetValue(self.HexCode)
def UpdateSiiGridTable(self, row, col):
Destroy existing grid and recreate
@param row, col : Hex View grid size
self.HexViewSizer["view"].Detach(self.SiiGrid)
self.SiiGrid = SiiGridTable(self, self.Controler, row, col)
self.HexViewSizer["view"].Add(self.SiiGrid)
self.SiiGrid.CreateGrid(row, col)
self.SetSizer(self.HexViewSizer["view"])
self.HexViewSizer["view"].FitInside(self.parent.parent)
self.parent.parent.FitInside()
def OnButtonSiiUpload(self, event):
Load EEPROM data from slave and refresh Hex View grid
Binded to 'Sii Upload' button.
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
# load from EEPROM data and parsing
self.SiiBinary = self.Controler.CommonMethod.LoadData()
self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
self.UpdateSiiGridTable(self.HexRow, self.HexCol)
self.SiiGrid.SetValue(self.HexCode)
def OnButtonSiiDownload(self, event):
Write current EEPROM data to slave and refresh data structure kept by master
Binded to 'Sii Download' button.
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not,
# and whether status is "Started" or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
status, _log_count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
if status is not PlcStatus.Started:
self.Controler.CommonMethod.SiiWrite(self.SiiBinary)
self.Controler.CommonMethod.Rescan()
def OnButtonWriteToBinFile(self, event):
Save current EEPROM data to binary file through FileDialog
Binded to 'Write to File' button.
@param event : wx.EVT_BUTTON object
dialog = wx.FileDialog(self, _("Save as..."), os.getcwd(), "slave0.bin",
_("bin files (*.bin)|*.bin|All files|*.*"), wx.SAVE | wx.OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
binfile = open(filepath, "wb")
binfile.write(self.SiiBinary)
def OnButtonReadFromBinFile(self, event):
Load binary file through FileDialog
Binded to 'Read from File' button.
@param event : wx.EVT_BUTTON object
dialog = wx.FileDialog(self, _("Choose a binary file"), os.getcwd(), "",
_("bin files (*.bin)|*.bin"), wx.OPEN)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
binfile = open(filepath, "rb")
self.SiiBinary = binfile.read()
self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
self.UpdateSiiGridTable(self.HexRow, self.HexCol)
self.SiiGrid.SetValue(self.HexCode)
self.Controler.CommonMethod.CreateErrorDialog(_('The file does not exist!'))
def OnButtonXmlToEEPROMImg(self, event):
Create EEPROM data based XML data that current imported
Binded to 'XML to EEPROM' button.
@param event : wx.EVT_BUTTON object
self.SiiBinary = self.Controler.CommonMethod.XmlToEeprom()
self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
self.UpdateSiiGridTable(self.HexRow, self.HexCol)
self.SiiGrid.SetValue(self.HexCode)
# -------------------------------------------------------------------------------
# For Hex View grid (fill hex data)
# -------------------------------------------------------------------------------
class SiiGridTable(wx.grid.Grid):
def __init__(self, parent, controler, row, col):
@param parent: Reference to the parent HexView class
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
@param row, col: Hex View grid size
self.Controler = controler
wx.grid.Grid.__init__(self, parent, -1, size=(830, 450),
style=wx.ALIGN_CENTRE_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)
def SetValue(self, value):
@param value: EEPROM data list of which element is 1 Byte hex data
# set label name and size
self.SetRowLabelSize(100)
for col in range(self.Col):
self.SetColLabelValue(16, "Text View")
self.SetColSize(16, (self.GetSize().x-120)*4//20)
self.SetColLabelValue(col, '%s' % col)
self.SetColSize(col, (self.GetSize().x-120)//20)
self.SetRowLabelValue(row, "0x"+"{:0>4x}".format(row*(self.Col-1)))
self.SetCellValue(row, col, hex)
self.SetCellAlignment(row, col, wx.ALIGN_LEFT, wx.ALIGN_CENTER)
self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
self.SetReadOnly(row, col, True)
# -------------------------------------------------------------------------------
# For Register Access Panel
# -------------------------------------------------------------------------------
class RegisterAccessPanel(wx.Panel):
def __init__(self, parent, controler):
@param parent: EEPROMAccessPanel object
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
self.Controler = controler
wx.Panel.__init__(self, parent, -1)
sizer = wx.FlexGridSizer(cols=1, hgap=20, rows=2, vgap=5)
button_sizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10)
self.ReloadButton = wx.Button(self, -1, "Reload")
self.CompactViewCheckbox = wx.CheckBox(self, -1, "Compact View")
self.RegisterNotebook = RegisterNotebook(self, self.Controler)
button_sizer.AddMany([self.ReloadButton, self.CompactViewCheckbox])
sizer.AddMany([button_sizer, self.RegisterNotebook])
self.ReloadButton.Bind(wx.EVT_BUTTON, self.OnReloadButton)
self.CompactViewCheckbox.Bind(wx.EVT_CHECKBOX, self.ToggleCompactViewCheckbox)
self.RegisterNotebook.RegPage[index].MainTable.CreateGrid(self.MainRow[index], self.MainCol)
self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, 0, index*512, (index+1)*512)
if self.Controler.CommonMethod.RegData == "":
self.CompactViewCheckbox.Disable()
self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, 0, index*512, (index+1)*512)
else: # If data was saved,
self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, self.RegMonitorData, index*512, (index+1)*512)
# main grid rows and cols
self.MainRow = [512, 512, 512, 512]
self.PageRange.append([512*index, 512*(index+1)])
# Previous value of register data for register description configuration
self.PreRegSpec = {"ESCType": "",
Get data from the register.
self.Controler.CommonMethod.RegData = ""
# ex : ethercat reg_read -p 0 0x0000 0x0001
self.Controler.CommonMethod.RegData = self.Controler.CommonMethod.RegData + " " + self.Controler.CommonMethod.RegRead("0x"+"{:0>4x}".format(index*1024), "0x0400")
# (ESC type, port number of FMMU, port number of SM, and PDI type))
for reg_spec in ["ESCType", "FMMUNumber", "SMNumber", "PDIType"]:
self.PreRegSpec[reg_spec] = self.Controler.CommonMethod.CrtRegSpec[reg_spec]
# update registers' description
# (ESC type, port number of FMMU, port number of SM, and PDI type)
for reg_spec, address in [("ESCType", "0x0000"),
("FMMUNumber", "0x0004"),
self.Controler.CommonMethod.CrtRegSpec[reg_spec] = self.Controler.CommonMethod.RegRead(address, "0x0001")
# Enable compactView checkbox
self.CompactViewCheckbox.Enable()
Get and save the description of registers.
It's done by parsing register_information.xml.
# parse the above register's value
# If the value is 0x12, the result is 12
self.ESCType = self.Controler.CommonMethod.CrtRegSpec["ESCType"].split('x')[1]
self.PDIType = self.Controler.CommonMethod.CrtRegSpec["PDIType"].split('x')[1]
# If the value is 0x12, the result is 18 (It's converted to decimal value)
self.FMMUNumber = int(self.Controler.CommonMethod.CrtRegSpec["FMMUNumber"], 16)
self.SMNumber = int(self.Controler.CommonMethod.CrtRegSpec["SMNumber"], 16)
# initialize description dictionary of register main table and register sub table.
self.RegisterDescriptionDict = {}
self.RegisterSubGridDict = {}
# ./EthercatMaster/register_information.xml contains register description.
if wx.Platform == '__WXMSW__':
reg_info_file = open("../../EthercatMaster/register_information.xml", 'r')
reg_info_file = open("./EthercatMaster/register_information.xml", 'r')
reg_info_tree = minidom.parse(reg_info_file)
# parse register description
for register_info in reg_info_tree.childNodes:
for register in register_info.childNodes:
if register.nodeType == reg_info_tree.ELEMENT_NODE and register.nodeName == "Register":
# If it depends on the property(ESC type, PDI type, FMMU number, SM number)
for property, type, value in [("esc", "type", self.ESCType),
("pdi", "type", self.PDIType),
("fmmu", "number", self.FMMUNumber),
("sm", "number", self.SMNumber)]:
if property in register.attributes.keys():
if register.attributes[property].value == value:
self.GetRegisterInfo(reg_info_tree, register)
if register.attributes[property].value < value:
self.GetRegisterInfo(reg_info_tree, register)
self.GetRegisterInfo(reg_info_tree, register)
def GetRegisterInfo(self, reg_info_tree, register):
Save the register's description into the dictionary.
reg_info_tree is based on the register_information.xml.
@param reg_info_tree: XML tree
@param register: register which you want to get the description
# temporary variables for register main table idescription dictionary
reg_main_description = ""
for data in register.childNodes:
if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Index":
for index in data.childNodes:
reg_index = index.nodeValue
if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Description":
for description in data.childNodes:
reg_main_description = description.nodeValue
# Add description for register main table
if reg_index != "" and reg_main_description != "":
self.RegisterDescriptionDict[reg_index] = reg_main_description
if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Details":
# declare register sub table description dictionary about this index
self.RegisterSubGridDict[reg_index] = []
for detail in data.childNodes:
if detail.nodeType == reg_info_tree.ELEMENT_NODE and detail.nodeName == "Detail":
# If it depends on the property(ESC type, PDI type, FMMU number, SM number)
for property, type, value in [("esc", "type", self.ESCType),
("pdi", "type", self.PDIType),
("fmmu", "number", self.FMMUNumber),
("sm", "number", self.SMNumber)]:
if property in detail.attributes.keys():
if detail.attributes[property].value == value:
self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
if detail.attributes[property].value < value:
self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
def GetRegisterDetailInfo(self, reg_info_tree, reg_index, detail):
Get the resgister's detailed description(for sub table) from the reg_info_tree.
@param reg_info_tree: XML tree (register_information.xml)
@param reg_index: index of the register
@param detail: description of the register
# temporary variables for register sub table description dictionary
# - It is initialized in every sub description
for detail_data in detail.childNodes:
if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Range":
for range in detail_data.childNodes:
reg_bit_range = range.nodeValue
if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Description":
for description in detail_data.childNodes:
reg_sub_description = description.nodeValue
if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Enum":
for enum in detail_data.childNodes:
if enum.nodeType == reg_info_tree.ELEMENT_NODE and enum.nodeName == "item":
# temporary variables for a description of each value
# For example, if the bit is 1, it is 'enabled'('On', 'True', etc.),
# otherwise 'disabled'('Off', 'False', etc.).
reg_sub_value_description = ""
for item in enum.childNodes:
if item.nodeType == reg_info_tree.ELEMENT_NODE and item.nodeName == "value":
for value in item.childNodes:
reg_sub_value = value.nodeValue
if item.nodeType == reg_info_tree.ELEMENT_NODE and item.nodeName == "Description":
for description in item.childNodes:
reg_sub_value_description = description.nodeValue
# Add a description of each value to register enum dictionary
if reg_sub_value != "" and reg_sub_value_description != "":
reg_enum_dictionary[reg_sub_value] = reg_sub_value_description
# add a description to register sub table description dictionary
if reg_bit_range != "" and reg_sub_description != "":
self.RegisterSubGridDict[reg_index].append([reg_bit_range,
Transform the data into dec, hex, string, and description
reg_data = self.Controler.CommonMethod.RegData.split()
# loop for register(0x0000:0x0fff)
for address in range(0x1000):
# arrange 2 Bytes of register data
reg_word = reg_data[address].split('x')[1] + reg_word
hex_address = "{:0>4x}".format(address-1)
row_data.append(hex_address)
if hex_address in self.RegisterDescriptionDict:
row_data.append(self.RegisterDescriptionDict[hex_address])
row_data.append(str(int(reg_word, 16)))
row_data.append('0x'+reg_word)
if int(reg_word[iter*2:iter*2+2], 16) >= 32 and int(reg_word[iter*2:iter*2+2], 16) <= 126:
char_data = char_data + chr(int(reg_word[iter*2:iter*2+2], 16))
char_data = char_data + "."
row_data.append(char_data)
self.RegMonitorData.append(row_data)
reg_word = "" # initialize regWord
def OnReloadButton(self, event):
Handle the click event of the 'Reload' button.
Get the data from registers again, and update the table.
@param event: wx.EVT_BUTTON object
# Check whether beremiz connected or not.
# If this method is called cyclically, set the cyclic flag true
check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
self.ToggleCompactViewCheckbox(True)
self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol,
self.PageRange[index][0], self.PageRange[index][1],
def ToggleCompactViewCheckbox(self, event):
Handles the event of the 'Compact view' check box.
If it's checked, show only the registers that have a description.
If not, show all the registers.
@param event: wx.EVT_CHECKBOX object
# If "Compact View" Checkbox is True
# 'event' is argument of this method or event of checkbox.
if event is True or event.GetEventObject().GetValue():
self.PageRange[index] = [0, 0]
for reg_row_data in self.RegMonitorData:
if reg_row_data[1] != "":
# data structure for "compact view"
reg_compact_data.append(reg_row_data)
# count for each register notebooks' row
# It compare with register's address.
if int('0x'+reg_row_data[0], 16) < (index+1)*1024:
# Setting tables' rows and cols, range for compact view
self.MainRow[index] = page_row[index]
self.PageRange[index][1] = page_row[index]
for iter in range(index):
self.PageRange[index][0] += page_row[iter]
self.PageRange[index][1] += page_row[iter]
self.RegisterNotebook.RegPage[index].UpdateMainTable(
self.PageRange[index][0],
self.PageRange[index][1],
# Compact View Checkbox is False
# Setting original rows, cols and range
self.MainRow = [512, 512, 512, 512]
self.PageRange.append([512*index, 512*(index+1)])
self.RegisterNotebook.RegPage[index].UpdateMainTable(
self.PageRange[index][0],
self.PageRange[index][1],
# -------------------------------------------------------------------------------
# For Register Access Notebook (divide index range)
# -------------------------------------------------------------------------------
class RegisterNotebook(wx.Notebook):
def __init__(self, parent, controler):
@param parent: RegisterAccessPanel object
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Notebook.__init__(self, parent, id=-1)
self.Controler = controler
for dummy in range(pages):
self.RegPage.append(None)
for index in range(pages):
self.RegPage[index] = RegisterNotebookPanel(self, self.Controler,
parent.MainRow[index], parent.MainCol)
self.AddPage(self.RegPage[index],
"0x"+"{:0>4x}".format(index*1024)+" - 0x"+"{:0>4x}".format((index+1)*1024-1))
# -------------------------------------------------------------------------------
# For Register Access Notebook Panel
# (Main UI : including main, sub table)
# -------------------------------------------------------------------------------
class RegisterNotebookPanel(wx.Panel):
def __init__(self, parent, controler, row, col):
@param parent: RegisterAccessPanel object
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
@param row, col: size of the table
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
self.Sizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=30)
self.MainTable = RegisterMainTable(self, self.Row, self.Col, self.Controler)
self.SubTable = RegisterSubTable(self, sub_row, sub_col)
self.SubTable.CreateGrid(sub_row, sub_col)
self.SubTable.SetValue(self, [])
self.Sizer.AddMany([self.MainTable, self.SubTable])
self.SetSizer(self.Sizer)
def UpdateMainTable(self, row, col, low_index, high_index, data):
It's done by deleting the main table and creating it again.
@param row, col: size of the table
@param low_index: the lowest index of the page
@param high_index: the highest index of the page
self.MainTable = RegisterMainTable(self, row, col, self.Controler)
self.Sizer.Detach(self.SubTable)
self.Sizer.AddMany([self.MainTable, self.SubTable])
self.SetSizer(self.Sizer)
self.MainTable.CreateGrid(row, col)
self.MainTable.SetValue(self, data, low_index, high_index)
def UpdateSubTable(self, row, col, data):
It's done by deleting the sub table and creating it again.
@param row, col: size of the table
self.SubTable = RegisterSubTable(self, row, col)
self.Sizer.Detach(self.MainTable)
self.Sizer.AddMany([self.MainTable, self.SubTable])
self.SetSizer(self.Sizer)
self.SubTable.CreateGrid(row, col)
self.SubTable.SetValue(self, data)
# -------------------------------------------------------------------------------
# For Register Access Notebook Panel (Main Table)
# -------------------------------------------------------------------------------
class RegisterMainTable(wx.grid.Grid):
def __init__(self, parent, row, col, controler):
@param parent: RegisterNotebook object
@param row, col: size of the table
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
self.Controler = controler
self.RegisterAccessPanel = self.parent.parent.parent
wx.grid.Grid.__init__(self, parent, -1, size=(820, 300),
style=wx.EXPAND | wx.ALIGN_CENTRE_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)
for evt, mapping_method in [(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.OnRegModifyDialog)]:
self.Bind(evt, mapping_method)
def SetValue(self, parent, reg_monitor_data, low_index, high_index):
Set the RegMonitorData into the main table.
@param parent: RegisterNotebook object
@param reg_monitor_data: data
@param low_index: the lowest index of the page
@param high_index: the highest index of the page
self.RegMonitorData = reg_monitor_data
# set label name and size
register_maintable_label = [(0, "Description"), (1, "Dec"),
for (index, label) in register_maintable_label:
self.SetColLabelValue(index, label)
# if reg_monitor_data is 0, it is initialization of register access.
if reg_monitor_data == 0:
for row_index in reg_monitor_data[low_index:high_index]:
self.SetRowLabelValue(row, row_index[0])
for data_index in range(4):
self.SetCellValue(row, col, row_index[data_index+1])
self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
self.SetReadOnly(row, col, True)
def OnSelectCell(self, event):
Handles the event of the cell of the main table.
@param event: wx.grid object (left click)
# if reg_monitor_data is 0, it is initialization of register access.
if self.RegMonitorData == 0:
address = self.GetRowLabelValue(event.GetRow())
BIT_RANGE, NAME, DESCRIPTIONS = range(3)
# Check if this register's detail description is exist or not,
# and create data structure for the detail description table ; sub grid
if address in self.RegisterAccessPanel.RegisterSubGridDict:
for element in self.RegisterAccessPanel.RegisterSubGridDict[address]:
row_data.append(element[BIT_RANGE])
row_data.append(element[NAME])
bin_data = "{:0>16b}".format(int(self.GetCellValue(event.GetRow(), 1)))
value_range = element[BIT_RANGE].split('-')
value = (bin_data[8:16][::-1]+bin_data[0:8][::-1])[int(value_range[0]):(int(value_range[-1])+1)][::-1]
row_data.append(str(int(('0b'+str(value)), 2)))
if value in element[DESCRIPTIONS]:
row_data.append(element[DESCRIPTIONS][value])
reg_sub_grid_data.append(row_data)
self.parent.UpdateSubTable(sub_row, sub_col, reg_sub_grid_data)
# event.Skip() updates UI of selecting cell
def OnRegModifyDialog(self, event):
Handle the event of the cell of the main table.
Display the window where the user modifies the value of the cell.
@param event: wx.grid object (double click)
# user can enter a value in case that user double-clicked 'Dec' or 'Hex' value.
if event.GetCol() == 1 or event.GetCol() == 2:
dlg = wx.TextEntryDialog(self, _("Enter hex(0xnnnn) or dec(n) value"),
_("Register Modify Dialog"), style=wx.OK | wx.CANCEL)
# Setting value in initial dialog value
start_value = self.GetCellValue(event.GetRow(), event.GetCol())
dlg.SetValue(start_value)
if dlg.ShowModal() == wx.ID_OK:
# It int(input) success, this input is dev or hex value.
# Otherwise, it's error, so it goes except.
# ex) ethercat reg_write -p 0 -t uint16 0x0000 0x0000
return_val = self.Controler.CommonMethod.RegWrite('0x'+self.GetRowLabelValue(event.GetRow()), dlg.GetValue())
self.SetCellValue(event.GetRow(), 1, str(int(dlg.GetValue(), 0)))
hex_data = '0x'+"{:0>4x}".format(int(dlg.GetValue(), 0))
self.SetCellValue(event.GetRow(), 2, hex_data)
# If hex_data is been able to convert to ascii code, append ascii code.
if int(hex_data[(iter+1)*2:(iter+2)*2], 16) >= 32 and int(hex_data[(iter+1)*2:(iter+2)*2], 16) <= 126:
char_data = char_data + chr(int(hex_data[(iter+1)*2:(iter+2)*2], 16))
char_data = char_data + "."
self.SetCellValue(event.GetRow(), 3, char_data)
self.Controler.CommonMethod.CreateErrorDialog(_('You can\'t modify it. This register is read-only or it\'s not connected.'))
self.Controler.CommonMethod.CreateErrorDialog(_('You entered wrong value. You can enter dec or hex value only.'))
# -------------------------------------------------------------------------------
# For Register Access Notebook Panel (Sub Table)
# -------------------------------------------------------------------------------
class RegisterSubTable(wx.grid.Grid):
def __init__(self, parent, row, col):
@param parent: RegisterNotebook object
@param row, col: size of the table
wx.grid.Grid.__init__(self, parent, -1, size=(820, 150),
style=wx.EXPAND | wx.ALIGN_CENTRE_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)
def SetValue(self, parent, data):
Set the data into the subtable.
@param parent: RegisterNotebook object
# lset label name and size
Register_SubTable_Label = [(0, "Bits"), (1, "Name"),
(2, "Value"), (3, "Enum")]
for (index, label) in Register_SubTable_Label:
self.SetColLabelValue(index, label)
self.SetCellValue(row, col, element)
self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
self.SetReadOnly(row, col, True)
# -------------------------------------------------------------------------------
# -------------------------------------------------------------------------------
class MasterStatePanelClass(wx.Panel):
def __init__(self, parent, controler):
@param parent: wx.ScrollWindow object
@Param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Panel.__init__(self, parent)
self.Controler = controler
# ----------------------- Main Sizer and Update Button --------------------------------------------
self.MasterStateSizer = {"main": wx.BoxSizer(wx.VERTICAL)}
("innerTop", [2, 10, 1, 10]),
("innerMiddle", [1, 10, 1, 10]),
("innerBottom", [1, 10, 1, 10]),
("innerMasterState", [2, 10, 3, 10]),
("innerDeviceInfo", [4, 10, 3, 10]),
("innerFrameInfo", [4, 10, 5, 10]),
("innerSlaveInfo", [1, 10, 2, 10])]:
self.MasterStateSizer[key] = wx.FlexGridSizer(cols=attr[0], hgap=attr[1], rows=attr[2], vgap=attr[3])
self.MSUpdateButton = wx.Button(self, label=_("Update"))
self.MSUpdateButton.Bind(wx.EVT_BUTTON, self.OnMSUpdateButtonClick)
self.SIUpdateButton = wx.Button(self, label=_("Update"))
self.SIUpdateButton.Bind(wx.EVT_BUTTON, self.OnSIUpdateButtonClick)
("masterState", "EtherCAT Master State"),
("deviceInfo", "Ethernet Network Card Information"),
("frameInfo", "Network Frame Information"),
("slaveInfo", "Slave Information")]:
self.StaticBox[key] = wx.StaticBox(self, label=_(label))
self.MasterStateSizer[key] = wx.StaticBoxSizer(self.StaticBox[key])
# ----------------------- Master State -----------------------------------------------------------
('Slaves', 'Slave Count:')]:
self.StaticText[key] = wx.StaticText(self, label=_(label))
self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
self.MasterStateSizer['innerMasterState'].AddMany([self.StaticText[key], self.TextCtrl[key]])
self.MasterStateSizer['masterState'].AddSizer(self.MasterStateSizer['innerMasterState'])
# ----------------------- Ethernet Network Card Information ---------------------------------------
('Main', 'MAC Address:'),
('Tx frames', 'Tx Frames:'),
('Rx frames', 'Rx Frames:'),
('Lost frames', 'Lost Frames:')]:
self.StaticText[key] = wx.StaticText(self, label=_(label))
self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
self.MasterStateSizer['innerDeviceInfo'].AddMany([self.StaticText[key], self.TextCtrl[key]])
self.MasterStateSizer['deviceInfo'].AddSizer(self.MasterStateSizer['innerDeviceInfo'])
# ----------------------- Network Frame Information -----------------------------------------------
("Tx frame rate [1/s]", "Tx Frame Rate [1/s]:"),
("Tx rate [KByte/s]", "Tx Rate [KByte/s]:"),
("Rx frame rate [1/s]", "Rx Frame Rate [1/s]:"),
("Rx rate [KByte/s]", "Rx Rate [KByte/s]:"),
("Loss rate [1/s]", "Loss Rate [1/s]:"),
("Frame loss [%]", "Frame Loss [%]:")]:
self.StaticText[key] = wx.StaticText(self, label=_(label))
self.MasterStateSizer['innerFrameInfo'].Add(self.StaticText[key])
for index in ['0', '1', '2']:
self.TextCtrl[key][index] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
self.MasterStateSizer['innerFrameInfo'].Add(self.TextCtrl[key][index])
self.MasterStateSizer['frameInfo'].AddSizer(self.MasterStateSizer['innerFrameInfo'])
# ------------------------------- Slave Information -----------------------------------------------
self.SITreeListCtrl = SITreeListCtrl(self, self.Controler)
self.MasterStateSizer["innerSlaveInfo"].AddMany([self.SIUpdateButton,
self.MasterStateSizer["slaveInfo"].AddSizer(
self.MasterStateSizer["innerSlaveInfo"])
# --------------------------------- Main Sizer ----------------------------------------------------
self.MasterStateSizer["main"].Add(self.MSUpdateButton)
"masterState", "deviceInfo"]),
"innerTop", "innerMiddle", "innerBottom"])]:
self.MasterStateSizer[key].AddSizer(self.MasterStateSizer[key2])
self.SetSizer(self.MasterStateSizer["main"])
def OnMSUpdateButtonClick(self, event):
Handle the event of the 'Update' button.
Update the data of the master state.
@param event: wx.EVT_BUTTON object
if self.Controler.GetCTRoot()._connector is not None:
self.MasterState = self.Controler.CommonMethod.GetMasterState()
for key in self.TextCtrl:
if isinstance(self.TextCtrl[key], dict):
for index in self.TextCtrl[key]:
self.TextCtrl[key][index].SetValue(self.MasterState[key][int(index)])
self.TextCtrl[key].SetValue(self.MasterState[key][0])
self.Controler.CommonMethod.CreateErrorDialog(_('PLC not connected!'))
def OnSIUpdateButtonClick(self, event):
Handle the event of the radio box in the slave information
@param event: wx.EVT_RADIOBOX object
if self.Controler.GetCTRoot()._connector is not None:
self.SITreeListCtrl.UpdateSI()
self.Controler.CommonMethod.CreateErrorDialog('PLC not connected!')
#-------------------------------------------------------------------------------
# For Slave Information Panel
#-------------------------------------------------------------------------------
class SITreeListCtrl(wx.Panel):
EC_Addrs = ["0x0300", "0x0302", "0x0304", "0x0306", "0x0301", "0x0303", "0x0305",
"0x0307", "0x0308", "0x0309", "0x030A", "0x030B", "0x030C", "0x030D",
"0x0310", "0x0311", "0x0312", "0x0313", "0x0442", "0x0443"]
def __init__(self, parent, controler):
@param parent: Reference to the MasterStatePanel class
@param Controler: _EthercatCTN class in EthercatMaster.py
wx.Panel.__init__(self, parent, -1, size=wx.Size(750, 350))
self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=wx.Size(750,350),
|wx.TR_FULL_ROW_HIGHLIGHT)
self.Tree.AddColumn(label, width=width)
self.Tree.SetMainColumn(0)
Update the data of the slave information.
position, not_used, state, not_used, name = range(5)
# get slave informations (name, position, state)
slaves_infos = self.Controler.CommonMethod.GetSlaveStateFromSlave()
slave_info_lines = slaves_infos.splitlines()
for line in slave_info_lines:
slave_info_list.append(line.split(None,4))
slave_num = len(slave_info_lines)
reg_info.append(ec + ",0x001")
# get error counts of slaves
err_count_list = self.Controler.CommonMethod.MultiRegRead(slave_num, reg_info)
self.Tree.DeleteAllItems()
root = self.Tree.AddRoot("")
for slave_idx in range(slave_num):
slave_node = self.Tree.AppendItem(root, "")
# set name, postion, state
for info_idx in [name, position, state]:
self.Tree.SetItemText(slave_node,
slave_info_list[slave_idx][info_idx], col_num)
# set error counter's name and default value
for ec, sub_ecs in [("Port Error Counters 0/1/2/3",[
"Invaild Frame Counter 0/1/2/3",
"RX Error Counter 0/1/2/3"]),
("Forward RX Error Counter 0/1/2/3", []),
("ECAT Processing Unit Error Counter", []),
("PDI Error Counter", []),
("Lost Link Counter 0/1/2/3", []),
("Watchdog Counter Process Data", []),
("Watchdog Counter PDI", [])]:
tree_node = self.Tree.AppendItem(slave_node, "%s" % ec)
if ec_name.find("0/1/2/3") > 0:
error_counter[(ec_idx, ec_sub_idx)] = {
tree_node = self.Tree.AppendItem(\
error_counter[(ec_idx, 0)]["tree_node"],
if ec_name.find("0/1/2/3") > 0:
error_counter[(ec_idx, ec_sub_idx)] = {
for port_num in range(num_ports):
error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] += \
int(err_count_list[ec_list_idx].split(",")[2], 16)
error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] = -1
for port_num in range(num_ports):
for sub_idx in range(1, ec_sub_idx+1):
err_sum += error_counter[(ec_idx, sub_idx)]\
error_counter[(ec_idx, 0)]["err_count"][port_num] = err_sum
for port_num in range(num_ports):
error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] += \
int(err_count_list[ec_list_idx].split(",")[2], 16)
error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] = -1
# set texts in "error" column.
ec_info_list = error_counter.items()
for (idx, sub_idx), ec_info in ec_info_list:
for port_num in range(ec_info["num_ports"]):
if ec_info["err_count"][port_num] != 0:
if ec_info["err_count"][port_num] < 0:
ec_text = "reg I/O error"
ec_text = ec_text + "%d/" % ec_info["err_count"][port_num]
ec_text = ec_text.strip("/")
self.Tree.SetItemText(ec_info["tree_node"], ec_text, col_num)
self.Tree.SetItemText(slave_node, err_checker, col_num)
class DCConfigPanel(wx.Panel):
def __init__(self, parent, controler):
@param parent: Reference to the MasterStatePanel class
@param Controler: _EthercatCTN class in EthercatMaster.py
wx.Panel.__init__(self, parent, -1, size=wx.Size(750, 350))
self.Controler = controler
self.ESI_DC_Data = self.Controler.CommonMethod.LoadESIData()
# initialize SlaveStatePanel UI dictionaries
OperationModeComboList = []
for ESI_Data in self.ESI_DC_Data:
OperationModeComboList.append(ESI_Data["desc"])
UnitComboList = [ "/100", "/ 50", "/ 40", "/ 30", "/ 25", "/ 20", "/16",
"/ 10", "/ 8", "/ 5", "/ 4", "/ 3", "/ 2", "x 1", "x 2", "x 3", "x 4",
"x 5", "x 8", "x 10", "x 16", "x 20", "x 25", "x 30", "x 40", "x 50",
UnitComboListPlus = [ "/100", "/ 50", "/ 40", "/ 30", "/ 25", "/ 20", "/16",
"/ 10", "/ 8", "/ 5", "/ 4", "/ 3", "/ 2", "x 0", "x 1", "x 2", "x 3",
"x 4", "x 5", "x 8", "x 10", "x 16", "x 20", "x 25", "x 30", "x 40",
Sync1CycleComboList.append("x " + str(i + 1))
# iniitalize BoxSizer and FlexGridSizer
"DCConfig_main_sizer" : wx.BoxSizer(wx.VERTICAL),
"DCConfig_inner_main_sizer" : wx.FlexGridSizer(cols=1, hgap=50, rows=2, vgap=10),
"CyclicMode_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5),
"SyncMode_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5),
"OperationMode_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=100, rows=2, vgap=10),
"CheckEnable_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10),
"Sync0_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=15, rows=3, vgap=10),
"Sync0_CycleTimeSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=2, vgap=5),
"Sync0_ShiftTimeSizer" : wx.FlexGridSizer(cols=2, hgap=20, rows=2, vgap=5),
"Sync1_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=15, rows=3, vgap=10),
"Sync1_CycleTimeSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=2, vgap=5),
"Sync1_ShiftTimeSizer" : wx.FlexGridSizer(cols=2, hgap=20, rows=2, vgap=5)
# initialize StaticBox and StaticBoxSizer
for box_name, box_label in [
("CyclicModeBox", "Cyclic Mode"),
("Sync0CycleTimeBox", "Cycle Time (us):"),
("Sync0ShiftTimeBox", "Shift Time (us):"),
("Sync1CycleTimeBox", "Cycle Time (us):"),
("Sync1ShiftTimeBox", "Shift Time (us):")
self.StaticBoxDic[box_name] = wx.StaticBox(self, label=_(box_label))
self.SizerDic[box_name] = wx.StaticBoxSizer(self.StaticBoxDic[box_name])
for statictext_name, statictext_label in [
("MainLabel", "Distributed Clock"),
("OperationModeLabel", "Operation Mode:"),
("SyncUnitCycleLabel", "Sync Unit Cycle (us)"),
("Sync0ShiftTimeUserDefinedLabel", "User Defined"),
("Sync1ShiftTimeUserDefinedLabel", "User Defined"),
self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
("Sync0CycleTimeUserDefined_Ctl"),
("Sync0ShiftTimeUserDefined_Ctl"),
("Sync1CycleTimeUserDefined_Ctl"),
("Sync1ShiftTimeUserDefined_Ctl"),
self.TextCtrlDic[textctl_name] = wx.TextCtrl(
self, size=wx.Size(130, 24), style=wx.TE_READONLY)
for checkbox_name, checkbox_label in [
("Sync0Enable", "Enable Sync0"),
("Sync1Enable", "Enable Sync1")
self.CheckBoxDic[checkbox_name] = wx.CheckBox(self, -1, checkbox_label)
for combobox_name, combobox_list, size in [
("OperationModeChoice", OperationModeComboList, 250),
("Sync0UnitCycleChoice", UnitComboList, 130),
("Sync1UnitCycleChoice", UnitComboList, 130)
self.ComboBoxDic[combobox_name] = wx.ComboBox(self, size=wx.Size(size, 24),
choices = combobox_list, style = wx.CB_DROPDOWN | wx.CB_READONLY)
for radiobutton_name, radiobutton_label in [
("Sync0CycleTimeUnitRadioButton", "Sync Unit Cycle"),
("Sync0CycleTimeUserDefinedRadioButton", "User Defined"),
("Sync1CycleTimeUnitRadioButton", "Sync Unit Cycle"),
("Sync1CycleTimeUserDefinedRadioButton", "User Defined")
self.RadioButtonDic[radiobutton_name] = wx.RadioButton(
self, label = radiobutton_label, style = wx.RB_SINGLE)
self.ApplyButton = wx.Button(self, label="Apply")
self.Bind(wx.EVT_CHECKBOX, self.CheckDCEnable, self.CheckBoxDic["DCEnable"])
#self.Bind(wx.EVT_COMBOBOX, self.SelectOperationMode, self.ComboBoxDic["OperationModeChoice"])
#self.Bind(wx.EVT_COMBOBOX, self.SelectUnitCycle, self.ComboBoxDic["Sync0UnitChoice"])
self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync0CycleTime,
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"])
self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync0CycleTime,
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"])
self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync1CycleTime,
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"])
self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync1CycleTime,
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"])
self.Bind(wx.EVT_CHECKBOX, self.CheckSync0Enable, self.CheckBoxDic["Sync0Enable"])
self.Bind(wx.EVT_CHECKBOX, self.CheckSync1Enable, self.CheckBoxDic["Sync1Enable"])
self.Bind(wx.EVT_BUTTON, self.OnClickApplyButton, self.ApplyButton)
# sync1 shifttime box contents
self.SizerDic["Sync1_ShiftTimeSizer"].AddMany([
self.StaticTextDic["Sync1ShiftTimeUserDefinedLabel"],
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"]
self.SizerDic["Sync1ShiftTimeBox"].Add(self.SizerDic["Sync1_ShiftTimeSizer"])
# sync1 cycletime box contents
self.SizerDic["Sync1_CycleTimeSizer"].AddMany([
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"],
self.ComboBoxDic["Sync1UnitCycleChoice"],
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"],
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"]
self.SizerDic["Sync1CycleTimeBox"].Add(self.SizerDic["Sync1_CycleTimeSizer"])
self.SizerDic["Sync1_InnerSizer"].AddMany([
self.CheckBoxDic["Sync1Enable"], self.SizerDic["Sync1CycleTimeBox"],
self.SizerDic["Sync1ShiftTimeBox"]
self.SizerDic["Sync1Box"].Add(self.SizerDic["Sync1_InnerSizer"])
# sync0 shifttime box contents
self.SizerDic["Sync0_ShiftTimeSizer"].AddMany([
self.StaticTextDic["Sync0ShiftTimeUserDefinedLabel"],
self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"]
self.SizerDic["Sync0ShiftTimeBox"].Add(self.SizerDic["Sync0_ShiftTimeSizer"])
# sync0 cycletime box contents
self.SizerDic["Sync0_CycleTimeSizer"].AddMany([
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"],
self.ComboBoxDic["Sync0UnitCycleChoice"],
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"],
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"]
self.SizerDic["Sync0CycleTimeBox"].Add(self.SizerDic["Sync0_CycleTimeSizer"])
self.SizerDic["Sync0_InnerSizer"].AddMany([
self.CheckBoxDic["Sync0Enable"], self.SizerDic["Sync0CycleTimeBox"],
self.SizerDic["Sync0ShiftTimeBox"]
self.SizerDic["Sync0Box"].Add(self.SizerDic["Sync0_InnerSizer"])
self.SizerDic["SyncMode_InnerSizer"].AddMany([
self.SizerDic["Sync0Box"], self.SizerDic["Sync1Box"]
self.SizerDic["CheckEnable_InnerSizer"].AddMany([
self.StaticTextDic["SyncUnitCycleLabel"],
self.TextCtrlDic["SyncUnitCycle_Ctl"]
self.SizerDic["OperationMode_InnerSizer"].AddMany([
self.StaticTextDic["OperationModeLabel"],
self.ComboBoxDic["OperationModeChoice"],
self.CheckBoxDic["DCEnable"], self.SizerDic["CheckEnable_InnerSizer"]
self.SizerDic["CyclicMode_InnerSizer"].AddMany([
self.SizerDic["OperationMode_InnerSizer"],
self.SizerDic["SyncMode_InnerSizer"]
self.SizerDic["CyclicModeBox"].Add(self.SizerDic["CyclicMode_InnerSizer"])
self.SizerDic["DCConfig_inner_main_sizer"].AddMany([
self.StaticTextDic["MainLabel"], self.ApplyButton,
self.SizerDic["CyclicModeBox"]
self.SizerDic["DCConfig_main_sizer"].Add(self.SizerDic["DCConfig_inner_main_sizer"])
self.SetSizer(self.SizerDic["DCConfig_main_sizer"])
def UIOnOffSet(self, activate):
for object in self.RadioButtonDic:
self.RadioButtonDic[object].Enable()
for object in self.ComboBoxDic:
if object == "OperationModeChoice":
self.ComboBoxDic[object].Enable()
for object in self.TextCtrlDic:
if object in ["SyncUnitCycle_Ctl", "InputReference_Ctl"]:
self.TextCtrlDic[object].Enable()
for object in self.CheckBoxDic:
self.CheckBoxDic[object].Enable()
# initial set or DC enable uncheck
for object in self.RadioButtonDic:
self.RadioButtonDic[object].Disable()
for object in self.ComboBoxDic:
if object == "OperationModeChoice":
self.ComboBoxDic[object].Disable()
for object in self.TextCtrlDic:
if object == "SyncUnitCycle_Ctl":
self.TextCtrlDic[object].Disable()
for object in self.CheckBoxDic:
self.CheckBoxDic[object].Disable()
for data in self.ESI_DC_Data:
index = self.Controler.ExtractHexDecValue(data["assign_activate"])
config_name = data["desc"]
self.ComboBoxDic["OperationModeChoice"].SetStringSelection(config_name)
def CheckSync0Enable(self, evt):
self.ComboBoxDic["Sync0UnitCycleChoice"].Enable()
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].Enable()
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].Enable()
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Enable()
self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].Enable()
self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].Disable()
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].Disable()
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].Disable()
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue("")
self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue("")
def CheckSync1Enable(self, evt):
self.ComboBoxDic["Sync1UnitCycleChoice"].Enable()
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Enable()
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Enable()
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Enable()
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Enable()
self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable()
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable()
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable()
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue("")
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue("")
def CheckDCEnable(self, evt):
task_cycle_ns = self.GetInterval(ns_mode)
sync0_cycle_factor = None
sync1_cycle_factor = None
#task_cycle_ns = self.Controler.GetCTRoot()._Ticktime
self.UIOnOffSet(evt.GetInt())
# default select DC enable sync0
config_name = self.ESI_DC_Data[default_list_num]["desc"]
assign_act = self.ESI_DC_Data[default_list_num]["assign_activate"]
sync0_cycle_time_ns = self.ESI_DC_Data[default_list_num]["cycletime_sync0"]
if sync0_cycle_time_ns == 0 :
sync0_cycle_factor = self.ESI_DC_Data[default_list_num]["cycletime_sync0_factor"]
sync0_shift_time_ns = self.ESI_DC_Data[default_list_num]["shifttime_sync0"]
sync1_cycle_time_ns = self.ESI_DC_Data[default_list_num]["cycletime_sync1"]
if sync1_cycle_time_ns == 0 :
sync1_cycle_factor = self.ESI_DC_Data[default_list_num]["cycletime_sync1_factor"]
sync1_shift_time_ns = self.ESI_DC_Data[default_list_num]["shifttime_sync1"]
cal_assign_act = self.Controler.ExtractHexDecValue(assign_act)
sync0_cycle_time_us = str(int(sync0_cycle_time_ns) / 1000)
sync0_shift_time_us = str(int(sync0_shift_time_ns) / 1000)
sync1_cycle_time_us = str(int(sync1_cycle_time_ns) / 1000)
sync1_shift_time_us = str(int(sync1_shift_time_ns) / 1000)
task_cycle_to_us = str(int(task_cycle_ns) / 1000)
if cal_assign_act == 768:
# Disable About Sync1 Objects
self.CheckBoxDic["Sync1Enable"].SetValue(False)
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable()
self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable()
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable()
self.CheckBoxDic["Sync1Enable"].SetValue(True)
if sync1_cycle_factor is not None:
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(True)
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
self.SetSyncUnitCycle(sync1_cycle_factor,
self.ComboBoxDic["Sync1UnitCycleChoice"])
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(True)
self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue(sync1_cycle_time_us)
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue(sync1_shift_time_us)
self.CheckBoxDic["Sync0Enable"].SetValue(True)
if sync0_cycle_factor is not None:
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(True)
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
self.SetSyncUnitCycle(sync0_cycle_factor,
self.ComboBoxDic["Sync0UnitCycleChoice"])
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(True)
self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue(sync0_cycle_time_us)
self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue(sync0_shift_time_us)
self.ComboBoxDic["OperationModeChoice"].SetStringSelection(config_name)
self.TextCtrlDic["SyncUnitCycle_Ctl"].SetValue(task_cycle_to_us)
self.CheckBoxDic["Sync0Enable"].SetValue(False)
self.CheckBoxDic["Sync1Enable"].SetValue(False)
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue("")
self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue("")
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue("")
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue("")
#error_str = "DC Enable is not possble, please set task interval"
error_str = "Can't Set DC Enable"
self.Controler.CommonMethod.CreateErrorDialog(error_str)
def SetSyncUnitCycle(self, factor, object):
# factor > 0 ==> * factor, factor < 0 ==> / factor
factor_to_int = int(factor)
lists = object.GetStrings()
if (temp[0] == "x") and (int(temp[1]) == factor_to_int):
object.SetStringSelection(token)
lists = object.GetStrings()
if (temp[0] == "/") and (int(temp[1]) == factor_to_int):
object.SetStringSelection(token)
def GetInterval(self, mode):
project_infos = self.Controler.GetCTRoot().GetProjectInfos()
for project_info_list in project_infos["values"]:
if project_info_list["name"] == "Resources" :
token = project_info_list["values"][0]["tagname"]
tasks, instances = self.Controler.GetCTRoot().GetEditedResourceInfos(token)
task_cycle_ns = self.ParseTime(tasks[0]["Interval"])
task_cycle_us = int(task_cycle_ns) / 1000
# mode == 1 ==> return ns
# mode == 2 ==> return us
return str(task_cycle_us)
def ParseTime(self, input):
# input example : 't#1ms'
# temp.split('#') -> ['t', '1ms']
# convert nanosecond unit
result = int(temp[1][:-2]) * 1000000
elif temp[1][-2:] == "us":
result = int(temp[1][:-2]) * 1000
def SelectSync0CycleTime(self, evt):
selected_object = evt.GetEventObject()
if selected_object.GetLabel() == "User Defined" :
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Enable()
self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
elif selected_object.GetLabel() == "Sync Unit Cycle" :
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
self.ComboBoxDic["Sync0UnitCycleChoice"].Enable()
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
def SelectSync1CycleTime(self, evt):
selected_object = evt.GetEventObject()
if selected_object.GetLabel() == "User Defined" :
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Enable()
self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
elif selected_object.GetLabel() == "Sync Unit Cycle" :
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
self.ComboBoxDic["Sync1UnitCycleChoice"].Enable()
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
def GetCycle(self, period, section):
temp = section.split(" ")
result = int(period) * int(temp[1])
result = int(period) / int(temp[1])
def OnClickApplyButton(self, evt):
dc_enable = self.CheckBoxDic["DCEnable"].GetValue()
dc_desc = self.ComboBoxDic["OperationModeChoice"].GetStringSelection()
dc_assign_activate = self.ESI_DC_Data[0]["assign_activate"]
dc_assign_activate_mod = dc_assign_activate.split('x')[1]
if self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].GetValue():
temp = self.ComboBoxDic["Sync0UnitCycleChoice"].GetStringSelection()
dc_sync0_cycle = "1_" + str(self.GetCycle(self.GetInterval(us_mode), temp))
elif self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].GetValue():
dc_sync0_cycle = "2_" + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].GetValue()
if self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].GetValue():
temp = self.ComboBoxDic["Sync1UnitCycleChoice"].GetStringSelection()
dc_sync1_cycle = "1_" + self.GetCycle(self.GetInterval(us_mode), temp)
elif self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].GetValue():
dc_sync1_cycle = "2_" + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].GetValue()
dc_sync0_shift = self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].GetValue()
dc_sync1_shift = self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].GetValue()
self.Controler.BaseParams.setDC_Enable(dc_enable)
self.Controler.BaseParams.setDC_Desc(dc_desc)
self.Controler.BaseParams.setDC_Assign_Activate(dc_assign_activate_mod)
self.Controler.BaseParams.setDC_Sync0_Cycle_Time(dc_sync0_cycle)
self.Controler.BaseParams.setDC_Sync0_Shift_Time(dc_sync0_shift)
self.Controler.BaseParams.setDC_Sync1_Cycle_Time(dc_sync1_cycle)
self.Controler.BaseParams.setDC_Sync1_Shift_Time(dc_sync1_shift)
project_infos = self.Controler.GetCTRoot().CTNRequestSave()
def GetSymbol(self, period, cycle):
result = "x " + str(temp)
result = "/ " + str(temp)
def SetSyncCycle(self, period, sync0_cycle, sync1_cycle):
if sync0_cycle != "None":
self.CheckBoxDic["Sync0Enable"].SetValue(True)
temp = sync0_cycle.split("_")
symbol = self.GetSymbol(period, temp[1])
self.ComboBoxDic["Sync0UnitCycleChoice"].SetStringSelection(symbol)
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(True)
self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue(temp[1])
self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(True)
if sync1_cycle != "None":
self.CheckBoxDic["Sync1Enable"].SetValue(True)
temp = sync1_cycle.split("_")
symbol = self.GetSymbol(period, temp[1])
self.ComboBoxDic["Sync1UnitChoice"].SetStringSelection(symbol)
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(True)
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue(temp[1])
self.ComboBoxDic["Sync1UnitChoice"].Disable()
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(True)
def LoadProjectDCData(self):
task_cycle_ns = self.GetInterval(ns_mode)
task_cycle_to_us = int(task_cycle_ns) / 1000
dc_enable = self.Controler.BaseParams.getDC_Enable()
dc_desc = self.Controler.BaseParams.getDC_Desc()
dc_assign_activate = self.Controler.BaseParams.getDC_Assign_Activate()
dc_sync0_cycle = self.Controler.BaseParams.getDC_Sync0_Cycle_Time()
dc_sync0_shift = self.Controler.BaseParams.getDC_Sync0_Shift_Time()
dc_sync1_cycle = self.Controler.BaseParams.getDC_Sync1_Cycle_Time()
dc_sync1_shift = self.Controler.BaseParams.getDC_Sync1_Shift_Time()
self.UIOnOffSet(dc_enable)
self.CheckBoxDic["DCEnable"].SetValue(dc_enable)
self.ComboBoxDic["OperationModeChoice"].SetStringSelection(dc_desc)
self.TextCtrlDic["SyncUnitCycle_Ctl"].SetValue(str(task_cycle_to_us))
self.SetSyncCycle(str(task_cycle_to_us), dc_sync0_cycle, dc_sync1_cycle)
if dc_sync0_shift != "None":
self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue(dc_sync0_shift)
if dc_sync1_shift != "None":
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue(dc_sync1_shift)
if dc_assign_activate == "300":
self.CheckBoxDic["Sync1Enable"].SetValue(False)
self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable()
self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable()
self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable()