--- a/etherlab/CommonEtherCATFunction.py Fri Sep 28 17:15:53 2018 +0300
+++ b/etherlab/CommonEtherCATFunction.py Fri Sep 28 17:20:11 2018 +0300
@@ -25,7 +25,7 @@
return int(value.replace("#", "0"), 16)
raise ValueError, "Invalid value for HexDecValue \"%s\"" % value
@@ -52,7 +52,7 @@
result = commands.getoutput("ethercat master")
# --------------------- for slave ----------------------------
@@ -60,84 +60,84 @@
result = commands.getoutput("ethercat state -p %d %s")
result = commands.getoutput("ethercat slaves")
# ethercat xml -p (slave position)
result = commands.getoutput("ethercat xml -p %d")
# ethercat sdos -p (slave position)
result = commands.getoutput("ethercat sdos -p %d")
# ethercat upload -p (slave position) (main index) (sub index)
result = commands.getoutput("ethercat upload -p %d %s %s")
# ethercat download -p (slave position) (main index) (sub index) (value)
result = commands.getoutput("ethercat download --type %s -p %d %s %s %s")
# ethercat sii_read -p (slave position)
result = commands.getoutput("ethercat sii_read -p %d")
# ethercat reg_read -p (slave position) (address) (size)
result = commands.getoutput("ethercat reg_read -p %d %s %s")
# ethercat sii_write -p (slave position) - (contents)
process = subprocess.Popen(
["ethercat", "-f", "sii_write", "-p", "%d", "-"],
process.communicate(sii_data)
-returnVal = process.returncode
+returnVal = process.returncode # ethercat reg_write -p (slave position) -t (uinit16) (address) (data)
result = commands.getoutput("ethercat reg_write -p %d -t uint16 %s %s")
# ethercat rescan -p (slave position)
result = commands.getoutput("ethercat rescan -p %d")
#--------------------------------------------------
-# Common Method For EtherCAT Management
+# Common Method For EtherCAT Management #--------------------------------------------------
@@ -147,11 +147,11 @@
DatatypeDescription, CommunicationObject, ManufacturerSpecific, \
ProfileSpecific, Reserved, AllSDOData = range(6)
# store the execution result of "ethercat sdos" command into SaveSDOData.
- # Flags for checking "write" permission of OD entries
+ # Flags for checking "write" permission of OD entries @@ -161,7 +161,7 @@
@@ -171,26 +171,26 @@
def __init__(self, controler):
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
self.Controler = controler
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def GetMasterState(self):
Execute "ethercat master" command and parse the execution result
- # exectute "ethercat master" command
+ # exectute "ethercat master" command error, return_val = self.Controler.RemoteExec(MASTER_STATE, return_val = None)
@@ -204,9 +204,9 @@
if '(attached)' in value:
value.remove('(attached)')
master_state[key] = value
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
@@ -214,19 +214,19 @@
Set slave state to the specified one using "ethercat states -p %d %s" command.
Command example : "ethercat states -p 0 PREOP" (target slave position and target state are given.)
- @param command : target slave state
+ @param command : target slave state error, return_val = self.Controler.RemoteExec(SLAVE_STATE%(self.Controler.GetSlavePos(), command), return_val = None)
- def GetSlaveStateFromSlave(self):
+ def GetSlaveStateFromSlave(self): - Get slave information using "ethercat slaves" command and store the information into internal data structure
- (self.SlaveState) for "Slave State"
+ Get slave information using "ethercat slaves" command and store the information into internal data structure + (self.SlaveState) for "Slave State" return_val example : 0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100)
error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val = None)
self.SlaveState = return_val
#-------------------------------------------------------------------------------
@@ -236,10 +236,10 @@
Get SDO objects information of current slave using "ethercat sdos -p %d" command.
Command example : "ethercat sdos -p 0"
@return return_val : execution results of "ethercat sdos" command (need to be parsed later)
error, return_val = self.Controler.RemoteExec(SLAVE_SDO%(self.Controler.GetSlavePos()), return_val = None)
def SDODownload(self, data_type, idx, sub_idx, value):
Set an SDO object value to user-specified value using "ethercat download" command.
@@ -248,64 +248,64 @@
@param idx : index of the SDO entry
@param sub_idx : subindex of the SDO entry
@param value : value of SDO entry
error, return_val = self.Controler.RemoteExec(SDO_DOWNLOAD%(data_type, self.Controler.GetSlavePos(), idx, sub_idx, value), return_val = None)
def BackupSDODataSet(self):
- Back-up current SDO entry information to restore the SDO data
+ Back-up current SDO entry information to restore the SDO data in case that the user cancels SDO update operation.
self.BackupDatatypeDescription = self.SaveDatatypeDescription
self.BackupCommunicationObject = self.SaveCommunicationObject
self.BackupManufacturerSpecific = self.SaveManufacturerSpecific
self.BackupProfileSpecific = self.SaveProfileSpecific
self.BackupReserved = self.SaveReserved
self.BackupAllSDOData = self.SaveAllSDOData
def ClearSDODataSet(self):
Clear the specified SDO entry information.
self.SaveSDOData.append([])
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def RequestPDOInfo(self):
Load slave information from RootClass (XML data) and parse the information (calling SlavePDOData() method).
# Load slave information from ESI XML file (def EthercatMaster.py)
slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
type_infos = slave.getType()
device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
# Initialize PDO data set
- # if 'device' object is valid, call SavePDOData() to parse PDO data
+ # if 'device' object is valid, call SavePDOData() to parse PDO data
def SavePDOData(self, device):
Parse PDO data and store the results in TXPDOCategory and RXPDOCategory
Tx(Rx)PDOCategory : index, name, entry number
Tx(Rx)Info : entry index, sub index, name, length, type
@param device : Slave information extracted from ESI XML file
for pdo, pdo_info in ([(pdo, "Inputs") for pdo in device.getTxPdo()]):
# Save pdo_index, entry, and name of each entry
pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
pdo_name = ExtractName(pdo.getName())
# Initialize entry number count
# Save index and subindex
@@ -322,8 +322,8 @@
self.TxPDOInfo.append(entry_infos)
- categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}
+ categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count} self.TxPDOCategory.append(categorys)
@@ -332,11 +332,11 @@
pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
pdo_name = ExtractName(pdo.getName())
# Initialize entry number count
# Save index and subindex
index = ExtractHexDecValue(entry.getIndex().getcontent())
@@ -352,51 +352,51 @@
self.RxPDOInfo.append(entry_infos)
- categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}
- self.RxPDOCategory.append(categorys)
+ categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count} + self.RxPDOCategory.append(categorys) def GetTxPDOCategory(self):
Get TxPDOCategory data structure (Meta informaton of TxPDO).
TxPDOCategorys : index, name, number of entries
return self.TxPDOCategory
def GetRxPDOCategory(self):
Get RxPDOCategory data structure (Meta information of RxPDO).
RxPDOCategorys : index, name, number of entries
return self.RxPDOCategory
- Get TxPDOInfo data structure (Detailed information on TxPDO entries).
+ Get TxPDOInfo data structure (Detailed information on TxPDO entries). TxPDOInfos : entry index, sub index, name, length, type
- Get RxPDOInfo data structure (Detailed information on RxPDO entries).
+ Get RxPDOInfo data structure (Detailed information on RxPDO entries). RxPDOInfos : entry index, sub index, name, length, type
Initialize PDO management data structure.
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
@@ -431,13 +431,13 @@
def GetSmartViewInfos(self):
Parse XML data for "Smart View" of EEPROM contents.
@return smartview_infos : EEPROM contents dictionary
smartview_infos = {"eeprom_size": 128,
@@ -455,7 +455,7 @@
"mailbox_standardconf_outlength": '0',
"mailbox_standardconf_instart": '0',
"mailbox_standardconf_inlength": '0'}
slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
type_infos = slave.getType()
device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
@@ -466,7 +466,7 @@
# get EEPROM size; <Device>-<Eeprom>-<ByteSize>
if eeprom_element["name"] == "ByteSize":
smartview_infos["eeprom_size"] = eeprom_element
elif eeprom_element["name"] == "ConfigData":
configData_data = self.DecimalToHex(eeprom_element)
# get PDI type; <Device>-<Eeprom>-<ConfigData> address 0x00
@@ -478,12 +478,12 @@
elif eeprom_element["name"] == "BootStrap":
bootstrap_data = "{:0>16x}".format(eeprom_element)
# get bootstrap configuration; <Device>-<Eeprom>-<BootStrap>
- for cfg, iter in [("mailbox_bootstrapconf_outstart", 0),
+ for cfg, iter in [("mailbox_bootstrapconf_outstart", 0), ("mailbox_bootstrapconf_outlength", 1),
("mailbox_bootstrapconf_instart", 2),
("mailbox_bootstrapconf_inlength", 3)]:
smartview_infos[cfg] = str(int(bootstrap_data[4*iter+2:4*(iter+1)]+bootstrap_data[4*iter:4*iter+2], 16))
# get protocol (profile) types supported by mailbox; <Device>-<Mailbox>
@@ -491,7 +491,7 @@
if getattr(mb,"get%s"%mailbox_protocol)() is not None:
smartview_infos["supported_mailbox"] += "%s, "%mailbox_protocol
smartview_infos["supported_mailbox"] = smartview_infos["supported_mailbox"].strip(", ")
# get standard configuration of mailbox; <Device>-<Sm>
for sm_element in device.getSm():
if sm_element.getcontent() == "MBoxOut":
@@ -510,42 +510,42 @@
for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]:
if available_device[0] == type_infos["device_type"]:
smartview_infos["vendor_id"] = "0x" + "{:0>8x}".format(vendor_id)
if device.getType().getProductCode() is not None:
product_code = device.getType().getProductCode()
smartview_infos["product_code"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(product_code))
if device.getType().getRevisionNo() is not None:
revision_no = device.getType().getRevisionNo()
smartview_infos["revision_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(revision_no))
if device.getType().getSerialNo() is not None:
serial_no = device.getType().getSerialNo()
smartview_infos["serial_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(serial_no))
def DecimalToHex(self, decnum):
- Convert decimal value into hexadecimal representation.
+ Convert decimal value into hexadecimal representation. @param decnum : decimal value
@return hex_data : hexadecimal representation of input value in decimal
hex_len = (value_len / 2) * 2 + 2
hex_data = ("{:0>"+str(hex_len)+"x}").format(decnum)
@@ -553,7 +553,7 @@
Get slave EEPROM contents maintained by master device using "ethercat sii_read -p %d" command.
Command example : "ethercat sii_read -p 0"
@return return_val : result of "ethercat sii_read" (binary data)
error, return_val = self.Controler.RemoteExec(SII_READ%(self.Controler.GetSlavePos()), return_val = None)
self.SiiData = return_val
@@ -564,15 +564,15 @@
Command example : "ethercat sii_write -p 0 - (binary contents)"
@param binary : EEPROM contents in binary data format
@return return_val : result of "ethercat sii_write" (If it succeeds, the return value is NULL.)
error, return_val = self.Controler.RemoteExec(SII_WRITE%(self.Controler.GetSlavePos()), return_val = None, sii_data = binary)
Loading data from EEPROM use Sii_Read Method
@return self.BinaryCode : slave EEPROM data in binary format (zero-padded)
return_val = self.Controler.CommonMethod.SiiRead()
self.BinaryCode = return_val
self.Controler.SiiData = self.BinaryCode
@@ -580,7 +580,7 @@
# append zero-filled padding data up to EEPROM size
for index in range(self.SmartViewInfosFromXML["eeprom_size"] - len(self.BinaryCode)):
self.BinaryCode = self.BinaryCode +'ff'.decode('hex')
def HexRead(self, binary):
@@ -589,42 +589,42 @@
@param binary : binary digits
@return hexCode : hexadecimal digits
@return hexview_table_row, hexview_table_col : Grid size for "Hex View" UI
for index in range(0, len(binary)) :
if len(binary[index]) != 1:
- digithexstr = hex(ord(binary[index]))
+ digithexstr = hex(ord(binary[index])) tempvar2 = digithexstr[2:4]
tempvar2 = "0" + tempvar2
- row_code.append(tempvar2)
+ row_code.append(tempvar2) if int(digithexstr, 16)>=32 and int(digithexstr, 16)<=126:
row_text = row_text + chr(int(digithexstr, 16))
row_text = row_text + "."
if len(row_code) == (hexview_table_col - 1):
row_code.append(row_text)
hex_code.append(row_code)
return hex_code, hexview_table_row, hexview_table_col
def GenerateEEPROMList(self, data, direction, length):
Generate EEPROM data list by reconstructing 'data' string.
@@ -634,7 +634,7 @@
@param direction : endianness
@param length : data length
@return eeprom_list : reconstructed list data structure
@@ -646,7 +646,7 @@
data = data[(1-direction)*2:length-direction*2]
Extract slave EEPROM contents using slave ESI XML file.
@@ -657,8 +657,8 @@
- SyncM category : ExtractEEPROMSyncMCategory()
- Tx/RxPDO category : ExtractEEPROMPDOCategory()
- DC category : ExtractEEPROMDCCategory()
@@ -668,14 +668,14 @@
slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
type_infos = slave.getType()
device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
# get ConfigData for EEPROM offset 0x0000-0x000d; <Device>-<Eeprom>-<ConfigData>
for eeprom_element in device.getEeprom().getcontent():
if eeprom_element["name"] == "ConfigData":
data = self.DecimalToHex(eeprom_element)
eeprom += self.GenerateEEPROMList(data, 0, 28)
# calculate CRC for EEPROM offset 0x000e-0x000f
@@ -683,15 +683,15 @@
crc = (crc << 1) | ((int(segment, 16) >> (7 - i)) & 0x01)
eeprom.append(hex(crc)[len(hex(crc))-3:len(hex(crc))-1])
# get VendorID for EEPROM offset 0x0010-0x0013;
for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
@@ -699,35 +699,35 @@
if available_device[0] == type_infos["device_type"]:
data = "{:0>8x}".format(vendor_id)
eeprom += self.GenerateEEPROMList(data, 1, 8)
# get Product Code for EEPROM offset 0x0014-0x0017;
if device.getType().getProductCode() is not None:
data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getProductCode()))
eeprom += self.GenerateEEPROMList(data, 1, 8)
# get Revision Number for EEPROM offset 0x0018-0x001b;
if device.getType().getRevisionNo() is not None:
data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getRevisionNo()))
- eeprom += self.GenerateEEPROMList(data, 1, 8)
+ eeprom += self.GenerateEEPROMList(data, 1, 8) # get Serial Number for EEPROM 0x001c-0x001f;
if device.getType().getSerialNo() is not None:
data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getSerialNo()))
eeprom += self.GenerateEEPROMList(data, 1, 8)
# get Execution Delay for EEPROM 0x0020-0x0021; not analyzed yet
# get Port0/1 Delay for EEPROM offset 0x0022-0x0025; not analyzed yet
# reserved for EEPROM offset 0x0026-0x0027;
@@ -738,7 +738,7 @@
if eeprom_element["name"] == "BootStrap":
data = "{:0>16x}".format(eeprom_element)
eeprom += self.GenerateEEPROMList(data, 0, 16)
# get Standard Mailbox for EEPROM offset 0x0030-0x0037; <Device>-<sm>
standard_send_mailbox_offset = None
@@ -752,7 +752,7 @@
elif sm_element.getcontent() == "MBoxIn":
standard_send_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress()))
standard_send_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize()))
if standard_receive_mailbox_offset is None:
@@ -777,7 +777,7 @@
eeprom.append(standard_send_mailbox_size[2:4])
eeprom.append(standard_send_mailbox_size[0:2])
# get supported mailbox protocols for EEPROM offset 0x0038-0x0039;
@@ -788,11 +788,11 @@
data = "{:0>4x}".format(data)
# resereved for EEPROM offset 0x003a-0x007b;
for i in range(0x007b-0x003a+0x0001):
# get EEPROM size for EEPROM offset 0x007c-0x007d;
for eeprom_element in device.getEeprom().getcontent():
@@ -806,76 +806,76 @@
- # Version for EEPROM 0x007e-0x007f;
+ # Version for EEPROM 0x007e-0x007f; # According to "EtherCAT Slave Device Description(V0.3.0)"
# append String Category data
for data in self.ExtractEEPROMStringCategory(device):
# append General Category data
for data in self.ExtractEEPROMGeneralCategory(device):
# append FMMU Category data
for data in self.ExtractEEPROMFMMUCategory(device):
# append SyncM Category data
for data in self.ExtractEEPROMSyncMCategory(device):
# append TxPDO Category data
for data in self.ExtractEEPROMPDOCategory(device, "TxPdo"):
# append RxPDO Category data
for data in self.ExtractEEPROMPDOCategory(device, "RxPdo"):
# append DC Category data
for data in self.ExtractEEPROMDCCategory(device):
padding = eeprom_size-len(eeprom)
for index in range(eeprom_size):
eeprom_binary = eeprom_binary + eeprom[index].decode('hex')
def ExtractEEPROMStringCategory(self, device):
Extract "Strings" category data from slave ESI XML and generate EEPROM image data.
@param device : 'device' object in the slave ESI XML
@return eeprom : "Strings" category EEPROM image data
count = 0 # string counter
padflag = False # padding flag if category length is odd
# index information for General Category in EEPROM
- # flag for preventing duplicated vendor specific data
+ # flag for preventing duplicated vendor specific data
# element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type>
# vendor_specific_data : vendor specific data (binary type)
@@ -885,7 +885,7 @@
for element in device.getType().getcontent():
if data is not "" and type(data) == unicode:
- for vendor_spec_string in vendor_spec_strings:
+ for vendor_spec_string in vendor_spec_strings: if data == vendor_spec_string:
self.OrderIdx = vendor_spec_strings.index(data)+1
@@ -900,7 +900,7 @@
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
# element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType>
data = device.getGroupType()
if data is not None and type(data) == unicode:
@@ -919,14 +919,14 @@
vendor_specific_data += "{:0>2x}".format(len(data))
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
- # element2-2; <EtherCATInfo>-<Groups>-<Group>-<Type>
- if grouptypeflag is False:
+ # element2-2; <EtherCATInfo>-<Groups>-<Group>-<Type> + if grouptypeflag is False: if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
for group_type, group_etc in vendor["groups"].iteritems():
for device_item in group_etc["devices"]:
- if device == device_item[1]:
+ if device == device_item[1]: if data is not None and type(data) == unicode:
for vendor_spec_string in vendor_spec_strings:
@@ -945,7 +945,7 @@
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
# element3; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Name(LcId is "1033")>
if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
for vendorId, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
@@ -967,7 +967,7 @@
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
# element4; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Name(LcId is "1033" or "1"?)>
for element in device.getName():
if element.getLcId() == 1 or element.getLcId()==1033:
@@ -988,7 +988,7 @@
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
# element5-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Image16x14>
if device.getcontent() is not None:
data = device.getcontent()
@@ -1007,7 +1007,7 @@
vendor_specific_data += "{:0>2x}".format(len(data))
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
# element5-2; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Image16x14>
if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
@@ -1032,7 +1032,7 @@
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
# <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Dc>-<OpMode>-<Name>
@@ -1046,7 +1046,7 @@
for character in range(len(data)):
dc_related_elements += "{:0>2x}".format(ord(data[character]))
# <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name
@@ -1055,7 +1055,7 @@
for name in element.getName():
@@ -1064,12 +1064,12 @@
input_elements += "{:0>2x}".format(len(data))
for character in range(len(data)):
input_elements += "{:0>2x}".format(ord(data[character]))
for entry in element.getEntry():
for name in entry.getName():
@@ -1079,7 +1079,7 @@
for character in range(len(data)):
input_elements += "{:0>2x}".format(ord(data[character]))
# <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name
@@ -1088,7 +1088,7 @@
for name in element.getName():
@@ -1097,12 +1097,12 @@
output_elements += "{:0>2x}".format(len(data))
for character in range(len(data)):
output_elements += "{:0>2x}".format(ord(data[character]))
for entry in element.getEntry():
for name in entry.getName():
@@ -1111,8 +1111,8 @@
output_elements += "{:0>2x}".format(len(data))
for character in range(len(data)):
output_elements += "{:0>2x}".format(ord(data[character]))
@@ -1137,38 +1137,38 @@
eeprom.append(element[0:2])
- element = element[2:len(element)]
- # padding if length is odd bytes
+ element = element[2:len(element)] + # padding if length is odd bytes
def ExtractEEPROMGeneralCategory(self, device):
Extract "General" category data from slave ESI XML and generate EEPROM image data.
@param device : 'device' object in the slave ESI XML
@return eeprom : "Strings" category EEPROM image data
# word 1 : Group Type index and Image index in STRINGS Category
eeprom.append("{:0>2x}".format(self.GroupIdx))
eeprom.append("{:0>2x}".format(self.ImgIdx))
# word 2 : Device Type index and Device Name index in STRINGS Category
eeprom.append("{:0>2x}".format(self.OrderIdx))
eeprom.append("{:0>2x}".format(self.NameIdx))
# word 3 : Physical Layer Port info. and CoE Details
eeprom.append("01") # Physical Layer Port info - assume 01
# CoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>
@@ -1178,12 +1178,12 @@
- for bit,flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig",
+ for bit,flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig", "PdoUpload", "CompleteAccess"]):
if getattr(coe,"get%s"%flag)() is not None:
eeprom.append("{:0>2x}".format(coe_details))
# word 4 : FoE Details and EoE Details
# FoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<FoE>
if mb is not None and mb.getFoE() is not None:
@@ -1195,7 +1195,7 @@
# word 5 : SoE Channels(reserved) and DS402 Channels
# SoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<SoE>
if mb is not None and mb.getSoE() is not None:
@@ -1209,10 +1209,10 @@
ds402ch = coe.getDS402Channels()
eeprom.append("01" if ds402ch in [True,1] else "00")
# word 6 : SysmanClass(reserved) and Flags
eeprom.append("00") # reserved
if device.getType().getTcCfgModeSafeOp() == True \
@@ -1221,10 +1221,10 @@
if device.getType().getUseLrdLwr() == True \
or device.getType().getUseLrdLwr() == 1:
flags = "0b"+"000000"+str(int(en_lrw))+str(int(en_safeop))
eeprom.append("{:0>2x}".format(int(flags, 2)))
# word 7 : Current On EBus (assume 0x0000)
@@ -1247,20 +1247,20 @@
def ExtractEEPROMFMMUCategory(self, device):
Extract "FMMU" category data from slave ESI XML and generate EEPROM image data.
@param device : 'device' object in the slave ESI XML
@return eeprom : "Strings" category EEPROM image data
count = 0 # number of FMMU
for fmmu in device.getFmmu():
if fmmu.getcontent() == "Outputs":
@@ -1269,7 +1269,7 @@
if fmmu.getcontent() == "MBoxState":
# construct of EEPROM data
@@ -1280,7 +1280,7 @@
eeprom.append("{:0>4x}".format((count+1)/2)[2:4])
eeprom.append("{:0>4x}".format((count+1)/2)[0:2])
eeprom.append("{:0>4x}".format((count)/2)[2:4])
eeprom.append("{:0>4x}".format((count)/2)[0:2])
@@ -1289,22 +1289,22 @@
- # padding if length is odd bytes
+ # padding if length is odd bytes
def ExtractEEPROMSyncMCategory(self, device):
Extract "SyncM" category data from slave ESI XML and generate EEPROM image data.
@param device : 'device' object in the slave ESI XML
@return eeprom : "Strings" category EEPROM image data
number = {"MBoxOut":"01", "MBoxIn":"02", "Outputs":"03", "Inputs":"04"}
for sm in device.getSm():
for attr in [sm.getStartAddress(),
@@ -1313,18 +1313,18 @@
data += "{:0>4x}".format(ExtractHexDecValue(attr))[2:4]
data += "{:0>4x}".format(ExtractHexDecValue(attr))[0:2]
if sm.getEnable() == "1" or sm.getEnable() == True:
data += number[sm.getcontent()]
eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
for i in range(len(data)/2):
@@ -1335,21 +1335,21 @@
def ExtractEEPROMPDOCategory(self, device, pdotype):
Extract ""PDO (Tx, Rx)"" category data from slave ESI XML and generate EEPROM image data.
@param device : 'device' object in the slave ESI XML
@param pdotype : identifier whether "TxPDO" or "RxPDO".
@return eeprom : "Strings" category EEPROM image data
for element in eval("device.get%s()"%pdotype):
data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[2:4]
@@ -1384,7 +1384,7 @@
if element.getVirtual() == True or element.getVirtual():
data += str(int(en_fixed)) + str(int(en_mandatory)) + str(int(en_virtual)) + "0"
for entry in element.getEntry():
data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[2:4]
@@ -1422,7 +1422,7 @@
if entry.getFixed() == True or entry.getFixed() == 1:
data += str(int(en_fixed)) + "000"
@@ -1432,7 +1432,7 @@
eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
@@ -1442,20 +1442,20 @@
def ExtractEEPROMDCCategory(self, device):
Extract "DC(Distributed Clock)" category data from slave ESI XML and generate EEPROM image data.
@param device : 'device' object in the slave ESI XML
@return eeprom : "Strings" category EEPROM image data
if device.getDc() is not None:
for element in device.getDc().getOpMode():
@@ -1501,12 +1501,12 @@
# assume that word 11-12 are 0x0000
eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
@@ -1516,9 +1516,9 @@
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
@@ -1529,10 +1529,10 @@
@param offset : register address
@param length : register length
@return return_val : register data
error, return_val = self.Controler.RemoteExec(REG_READ%(self.Controler.GetSlavePos(), offset, length), return_val = None)
def RegWrite(self, address, data):
Write data to slave ESC register using "ethercat reg_write -p %d %s %s" command.
@@ -1540,28 +1540,28 @@
@param address : register address
@param data : data to write
@return return_val : the execution result of "ethercat reg_write" (for error check)
error, return_val = self.Controler.RemoteExec(REG_WRITE%(self.Controler.GetSlavePos(), address, data), return_val = None)
Synchronize EEPROM data in master controller with the data in slave device after EEPROM write.
Command example : "ethercat rescan -p 0"
error, return_val = self.Controler.RemoteExec(RESCAN%(self.Controler.GetSlavePos()), return_val = None)
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def CheckConnect(self, cyclic_flag):
- Check connection status (1) between Beremiz and the master (2) between the master and the slave.
+ Check connection status (1) between Beremiz and the master (2) between the master and the slave. @param cyclic_flag: 0 - one shot, 1 - periodic
if self.Controler.GetCTRoot()._connector is not None:
- # Check connection between the master and the slave.
+ # Check connection between the master and the slave. # Command example : "ethercat xml -p 0"
error, return_val = self.Controler.RemoteExec(SLAVE_XML%(self.Controler.GetSlavePos()), return_val = None)
number_of_lines = return_val.split("\n")
@@ -1569,23 +1569,23 @@
self.CreateErrorDialog('No connected slaves')
elif len(number_of_lines) > 2 :
# The master controller is not connected to Beremiz host
self.CreateErrorDialog('PLC not connected!')
def CreateErrorDialog(self, mention):
Create a dialog to indicate error or warning.
@param mention : Error String
app_frame = self.Controler.GetCTRoot().AppFrame
- dlg = wx.MessageDialog (app_frame, mention,
+ dlg = wx.MessageDialog (app_frame, mention, wx.OK | wx.ICON_INFORMATION)
--- a/etherlab/ConfigEditor.py Fri Sep 28 17:15:53 2018 +0300
+++ b/etherlab/ConfigEditor.py Fri Sep 28 17:20:11 2018 +0300
@@ -67,22 +67,22 @@
LOCATION_MODEL = re.compile("(?:%[IQM](?:[XBWLD]?([0-9]+(?:\.[0-9]+)*)))$")
class NodeVariablesSizer(wx.FlexGridSizer):
def __init__(self, parent, controler, position_column=False):
wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=2, vgap=5)
self.Controler = controler
self.PositionColumn = position_column
self.VariablesFilter = wx.ComboBox(parent, style=wx.TE_PROCESS_ENTER)
self.VariablesFilter.Bind(wx.EVT_COMBOBOX, self.OnVariablesFilterChanged)
self.VariablesFilter.Bind(wx.EVT_TEXT_ENTER, self.OnVariablesFilterChanged)
self.VariablesFilter.Bind(wx.EVT_CHAR, self.OnVariablesFilterKeyDown)
self.AddWindow(self.VariablesFilter, flag=wx.GROW)
- self.VariablesGrid = wx.gizmos.TreeListCtrl(parent,
+ self.VariablesGrid = wx.gizmos.TreeListCtrl(parent, style=wx.TR_DEFAULT_STYLE |
@@ -91,46 +91,46 @@
self.VariablesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN,
self.OnVariablesGridLeftClick)
self.AddWindow(self.VariablesGrid, flag=wx.GROW)
for desc, value in VARIABLES_FILTERS:
self.VariablesFilter.Append(desc)
self.Filters.append(value)
self.VariablesFilter.SetSelection(0)
self.CurrentFilter = self.Filters[0]
self.VariablesFilterFirstCharacter = True
for colname, colsize, colalign in zip(GetVariablesTableColnames(position_column),
[40, 80, 350, 80, 100, 80, 150],
- [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT,
- wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT,
+ [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, + wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
self.VariablesGrid.SetMainColumn(2)
for colname, colsize, colalign in zip(GetVariablesTableColnames(),
[40, 350, 80, 100, 80, 150],
- [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT,
+ [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]):
self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
self.VariablesGrid.SetMainColumn(1)
entries = self.Controler.GetSlaveVariables(self.CurrentFilter)
self.RefreshVariablesGrid(entries)
def RefreshVariablesGrid(self, entries):
root = self.VariablesGrid.GetRootItem()
root = self.VariablesGrid.AddRoot(_("Slave entries"))
self.GenerateVariablesGridBranch(root, entries, GetVariablesTableColnames(self.PositionColumn))
self.VariablesGrid.Expand(root)
def GenerateVariablesGridBranch(self, root, entries, colnames, idx=0):
item, root_cookie = self.VariablesGrid.GetFirstChild(root)
no_more_items = not item.IsOk()
@@ -153,7 +153,7 @@
item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
no_more_items = not item.IsOk()
@@ -161,9 +161,9 @@
item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
self.VariablesGrid.Delete(item)
def OnVariablesFilterChanged(self, event):
filter = self.VariablesFilter.GetSelection()
@@ -190,29 +190,29 @@
self.VariablesFilter.SetValue(VARIABLE_INDEX_FILTER_FORMAT % self.CurrentFilter[0])
self.VariablesFilterFirstCharacter = True
def OnVariablesFilterKeyDown(self, event):
if self.VariablesFilterFirstCharacter:
keycode = event.GetKeyCode()
- if keycode not in [wx.WXK_RETURN,
+ if keycode not in [wx.WXK_RETURN, self.VariablesFilterFirstCharacter = False
if keycode not in NAVIGATION_KEYS:
self.VariablesFilter.SetValue("")
- if keycode not in [wx.WXK_DELETE,
+ if keycode not in [wx.WXK_DELETE,
def OnVariablesGridLeftClick(self, event):
item, flags, col = self.VariablesGrid.HitTest(event.GetPosition())
entry = self.VariablesGrid.GetItemPyData(item)
data_type = entry.get("Type", "")
data_size = self.Controler.GetSizeOfType(data_type)
if col == -1 and data_size is not None:
pdo_mapping = entry.get("PDOMapping", "")
access = entry.get("Access", "")
@@ -225,7 +225,7 @@
node_name = self.Controler.GetSlaveName(slave_pos)
node_name = self.Controler.CTNName()
var_name = "%s_%4.4x_%2.2x" % (node_name, entry_index, entry_subindex)
@@ -234,13 +234,13 @@
location = "%s%s" % (dir, data_size) + \
".".join(map(lambda x:str(x), location + (entry_index, entry_subindex)))
data = wx.TextDataObject(str((location, "location", data_type, var_name, "", access)))
dragSource = wx.DropSource(self.VariablesGrid)
elif self.PositionColumn:
location = self.Controler.GetCurrentLocation() +\
(slave_pos, entry_index, entry_subindex)
@@ -249,51 +249,51 @@
class NodeEditor(ConfTreeNodeEditor):
(_("Ethercat node"), "_create_EthercatNodeEditor"),
# Add Notebook Tab for EtherCAT Management Treebook
(_("EtherCAT Management"), "_create_EtherCATManagementEditor")
def _create_EthercatNodeEditor(self, prnt):
self.EthercatNodeEditor = wx.Panel(prnt, style=wx.TAB_TRAVERSAL)
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
variables_label = wx.StaticText(self.EthercatNodeEditor,
label=_('Variable entries:'))
main_sizer.AddWindow(variables_label, border=10, flag=wx.TOP|wx.LEFT|wx.RIGHT)
self.NodeVariables = NodeVariablesSizer(self.EthercatNodeEditor, self.Controler)
- main_sizer.AddSizer(self.NodeVariables, border=10,
+ main_sizer.AddSizer(self.NodeVariables, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
self.EthercatNodeEditor.SetSizer(main_sizer)
return self.EthercatNodeEditor
def __init__(self, parent, controler, window):
ConfTreeNodeEditor.__init__(self, parent, controler, window)
# add Contoler for use EthercatSlave.py Method
self.Controler = controler
def GetBufferState(self):
ConfTreeNodeEditor.RefreshView(self)
self.NodeVariables.RefreshView()
- # -------------------For EtherCAT Management ----------------------------------------------
+ # -------------------For EtherCAT Management ---------------------------------------------- def _create_EtherCATManagementEditor(self, prnt):
self.EtherCATManagementEditor = wx.ScrolledWindow(prnt,
style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
@@ -302,14 +302,14 @@
self.EtherCATManagermentEditor_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
self.EtherCATManagermentEditor_Main_Sizer.AddGrowableCol(0)
self.EtherCATManagermentEditor_Main_Sizer.AddGrowableRow(0)
self.EtherCATManagementTreebook = EtherCATManagementTreebook(self.EtherCATManagementEditor, self.Controler, self)
self.EtherCATManagermentEditor_Main_Sizer.AddSizer(self.EtherCATManagementTreebook, border=10, flag=wx.GROW)
self.EtherCATManagementEditor.SetSizer(self.EtherCATManagermentEditor_Main_Sizer)
return self.EtherCATManagementEditor
def OnResize(self, event):
self.EtherCATManagementEditor.GetBestSize()
xstart, ystart = self.EtherCATManagementEditor.GetViewStart()
@@ -318,7 +318,7 @@
posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
self.EtherCATManagementEditor.Scroll(posx, posy)
- self.EtherCATManagementEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
+ self.EtherCATManagementEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
# -------------------------------------------------------------------------------------------------------
@@ -328,13 +328,13 @@
def GetProcessVariablesTableColnames():
- return ["#", _("Name"),
- _("Read from (nodeid, index, subindex)"),
+ return ["#", _("Name"), + _("Read from (nodeid, index, subindex)"), _("Write to (nodeid, index, subindex)"),
class ProcessVariablesTable(CustomTable):
def GetValue(self, row, col):
if row < self.GetNumberRows():
@@ -351,7 +351,7 @@
return "%d, #x%0.4X, #x%0.2X" % value
return self.data[row].get(colname, "")
def SetValue(self, row, col, value):
if col < len(self.colnames):
colname = self.GetColLabelValue(col, False)
@@ -361,7 +361,7 @@
self.data[row]["WriteTo"] = value
self.data[row][colname] = value
def _updateColAttrs(self, grid):
wx.grid.Grid -> update the column attributes to add the
@@ -380,18 +380,18 @@
grid.SetReadOnly(row, col, False)
grid.SetReadOnly(row, col, True)
grid.SetCellEditor(row, col, editor)
grid.SetCellRenderer(row, col, renderer)
self.ResizeRow(grid, row)
class ProcessVariableDropTarget(wx.TextDropTarget):
def __init__(self, parent):
wx.TextDropTarget.__init__(self)
self.ParentWindow = parent
def OnDropText(self, x, y, data):
self.ParentWindow.Select()
x, y = self.ParentWindow.ProcessVariablesGrid.CalcUnscrolledPosition(x, y)
@@ -413,7 +413,7 @@
location = map(int, result.group(1).split('.'))
master_location = self.ParentWindow.GetMasterLocation()
- if (master_location == tuple(location[:len(master_location)]) and
+ if (master_location == tuple(location[:len(master_location)]) and len(location) - len(master_location) == 3):
values = tuple(location[len(master_location):])
var_type = self.ParentWindow.Controler.GetSlaveVariableDataType(*values)
@@ -436,10 +436,10 @@
message = _("'Read from' and 'Write to' variables types are not compatible")
message = _("Invalid value \"%s\" for process variable")%data
wx.CallAfter(self.ShowMessage, message)
def ShowMessage(self, message):
message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
@@ -450,11 +450,11 @@
return [_("Position"), _("Index"), _("Subindex"), _("Value"), _("Description")]
class StartupCommandDropTarget(wx.TextDropTarget):
def __init__(self, parent):
wx.TextDropTarget.__init__(self)
self.ParentWindow = parent
def OnDropText(self, x, y, data):
self.ParentWindow.Select()
@@ -478,7 +478,7 @@
master_location = self.ParentWindow.GetMasterLocation()
- if (master_location == tuple(location[:len(master_location)]) and
+ if (master_location == tuple(location[:len(master_location)]) and len(location) - len(master_location) == 3):
if access in ["wo", "rw"]:
self.ParentWindow.AddStartupCommand(*location[len(master_location):])
@@ -486,10 +486,10 @@
message = _("Entry can't be write through SDO")
message = _("Invalid value \"%s\" for startup command")%data
wx.CallAfter(self.ShowMessage, message)
def ShowMessage(self, message):
message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
@@ -514,7 +514,7 @@
elif colname == "Subindex":
def SetValue(self, row, col, value):
if col < len(self.colnames):
colname = self.GetColLabelValue(col, False)
@@ -532,10 +532,10 @@
self.old_value = self.data[row][colname]
self.data[row][colname] = value
def _updateColAttrs(self, grid):
wx.grid.Grid -> update the column attributes to add the
@@ -554,13 +554,13 @@
editor = wx.grid.GridCellTextEditor()
renderer = wx.grid.GridCellStringRenderer()
grid.SetCellEditor(row, col, editor)
grid.SetCellRenderer(row, col, renderer)
grid.SetReadOnly(row, col, False)
self.ResizeRow(grid, row)
def GetCommandIndex(self, position, command_idx):
for row, command in enumerate(self.data):
if command["Position"] == position and command["command_idx"] == command_idx:
@@ -568,15 +568,15 @@
class MasterNodesVariablesSizer(NodeVariablesSizer):
def __init__(self, parent, controler):
NodeVariablesSizer.__init__(self, parent, controler, True)
self.CurrentNodesFilter = {}
def SetCurrentNodesFilter(self, nodes_filter):
self.CurrentNodesFilter = nodes_filter
if self.CurrentNodesFilter is not None:
args = self.CurrentNodesFilter.copy()
@@ -587,27 +587,27 @@
NODE_POSITION_FILTER_FORMAT = _("Node Position: %d")
class MasterEditor(ConfTreeNodeEditor):
(_("Network"), "_create_EthercatMasterEditor"),
(_("Master State"), "_create_MasterStateEditor")
def _create_MasterStateEditor(self, prnt):
self.MasterStateEditor = wx.ScrolledWindow(prnt, style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
self.MasterStateEditor.Bind(wx.EVT_SIZE, self.OnResize)
self.MasterStateEditor_Panel_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
self.MasterStateEditor_Panel_Main_Sizer.AddGrowableCol(0)
self.MasterStateEditor_Panel_Main_Sizer.AddGrowableRow(0)
self.MasterStateEditor_Panel = MasterStatePanelClass(self.MasterStateEditor, self.Controler)
self.MasterStateEditor_Panel_Main_Sizer.AddSizer(self.MasterStateEditor_Panel, border=10, flag=wx.GROW)
self.MasterStateEditor.SetSizer(self.MasterStateEditor_Panel_Main_Sizer)
return self.MasterStateEditor
def OnResize(self, event):
self.MasterStateEditor.GetBestSize()
xstart, ystart = self.MasterStateEditor.GetViewStart()
@@ -616,80 +616,80 @@
posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
self.MasterStateEditor.Scroll(posx, posy)
- self.MasterStateEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
+ self.MasterStateEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
def _create_EthercatMasterEditor(self, prnt):
- self.EthercatMasterEditor = wx.ScrolledWindow(prnt,
+ self.EthercatMasterEditor = wx.ScrolledWindow(prnt, style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
self.EthercatMasterEditor.Bind(wx.EVT_SIZE, self.OnResize)
self.EthercatMasterEditorSizer = wx.BoxSizer(wx.VERTICAL)
self.NodesFilter = wx.ComboBox(self.EthercatMasterEditor,
style=wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_COMBOBOX, self.OnNodesFilterChanged, self.NodesFilter)
self.Bind(wx.EVT_TEXT_ENTER, self.OnNodesFilterChanged, self.NodesFilter)
self.NodesFilter.Bind(wx.EVT_CHAR, self.OnNodesFilterKeyDown)
process_variables_header = wx.BoxSizer(wx.HORIZONTAL)
process_variables_label = wx.StaticText(self.EthercatMasterEditor,
label=_("Process variables mapped between nodes:"))
process_variables_header.AddWindow(process_variables_label, 1,
flag=wx.ALIGN_CENTER_VERTICAL)
for name, bitmap, help in [
("AddVariableButton", "add_element", _("Add process variable")),
("DeleteVariableButton", "remove_element", _("Remove process variable")),
("UpVariableButton", "up", _("Move process variable up")),
("DownVariableButton", "down", _("Move process variable down"))]:
- button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap),
+ button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
process_variables_header.AddWindow(button, border=5, flag=wx.LEFT)
self.ProcessVariablesGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
self.ProcessVariablesGrid.SetMinSize(wx.Size(0, 150))
self.ProcessVariablesGrid.SetDropTarget(ProcessVariableDropTarget(self))
- self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
+ self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnProcessVariablesGridCellChange)
- self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK,
+ self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnProcessVariablesGridCellLeftClick)
self.ProcessVariablesGrid.Bind(wx.EVT_KEY_DOWN, self.OnProcessVariablesGridKeyDown)
startup_commands_header = wx.BoxSizer(wx.HORIZONTAL)
startup_commands_label = wx.StaticText(self.EthercatMasterEditor,
label=_("Startup service variables assignments:"))
startup_commands_header.AddWindow(startup_commands_label, 1,
flag=wx.ALIGN_CENTER_VERTICAL)
for name, bitmap, help in [
("AddCommandButton", "add_element", _("Add startup service variable")),
("DeleteCommandButton", "remove_element", _("Remove startup service variable"))]:
- button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap),
+ button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
startup_commands_header.AddWindow(button, border=5, flag=wx.LEFT)
self.StartupCommandsGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
self.StartupCommandsGrid.SetDropTarget(StartupCommandDropTarget(self))
self.StartupCommandsGrid.SetMinSize(wx.Size(0, 150))
- self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
+ self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnStartupCommandsGridCellChange)
- self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN,
+ self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnStartupCommandsGridEditorShow)
self.NodesVariables = MasterNodesVariablesSizer(self.EthercatMasterEditor, self.Controler)
main_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Node filter:"))
staticbox_sizer = wx.StaticBoxSizer(main_staticbox, wx.VERTICAL)
self.EthercatMasterEditorSizer.AddSizer(staticbox_sizer, 0, border=10, flag=wx.GROW|wx.ALL)
main_staticbox_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=6, vgap=0)
main_staticbox_sizer.AddGrowableCol(0)
main_staticbox_sizer.AddGrowableRow(2)
@@ -697,61 +697,61 @@
main_staticbox_sizer.AddGrowableRow(5)
staticbox_sizer.AddSizer(main_staticbox_sizer, 1, flag=wx.GROW)
main_staticbox_sizer.AddWindow(self.NodesFilter, border=5, flag=wx.GROW|wx.ALL)
- main_staticbox_sizer.AddSizer(process_variables_header, border=5,
+ main_staticbox_sizer.AddSizer(process_variables_header, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
- main_staticbox_sizer.AddWindow(self.ProcessVariablesGrid, 1,
+ main_staticbox_sizer.AddWindow(self.ProcessVariablesGrid, 1, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
- main_staticbox_sizer.AddSizer(startup_commands_header,
+ main_staticbox_sizer.AddSizer(startup_commands_header, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
- main_staticbox_sizer.AddWindow(self.StartupCommandsGrid, 1,
+ main_staticbox_sizer.AddWindow(self.StartupCommandsGrid, 1, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
second_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Nodes variables filter:"))
second_staticbox_sizer = wx.StaticBoxSizer(second_staticbox, wx.VERTICAL)
second_staticbox_sizer.AddSizer(self.NodesVariables, 1, border=5, flag=wx.GROW|wx.ALL)
- main_staticbox_sizer.AddSizer(second_staticbox_sizer, 1,
+ main_staticbox_sizer.AddSizer(second_staticbox_sizer, 1, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
self.EthercatMasterEditor.SetSizer(self.EthercatMasterEditorSizer)
return self.EthercatMasterEditor
def __init__(self, parent, controler, window):
ConfTreeNodeEditor.__init__(self, parent, controler, window)
# ------------------------------------------------------------------
self.Controler = controler
# ------------------------------------------------------------------
self.ProcessVariables = []
self.NodesFilterFirstCharacter = True
self.ProcessVariablesDefaultValue = {"Name": "", "ReadFrom": "", "WriteTo": "", "Description": ""}
self.ProcessVariablesTable = ProcessVariablesTable(self, [], GetProcessVariablesTableColnames())
self.ProcessVariablesColSizes = [40, 100, 150, 150, 200]
self.ProcessVariablesColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
self.ProcessVariablesGrid.SetTable(self.ProcessVariablesTable)
self.ProcessVariablesGrid.SetButtons({"Add": self.AddVariableButton,
"Delete": self.DeleteVariableButton,
"Up": self.UpVariableButton,
"Down": self.DownVariableButton})
def _AddVariablesElement(new_row):
self.ProcessVariablesTable.InsertRow(new_row, self.ProcessVariablesDefaultValue.copy())
self.SaveProcessVariables()
self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
setattr(self.ProcessVariablesGrid, "_AddRow", _AddVariablesElement)
def _DeleteVariablesElement(row):
self.ProcessVariablesTable.RemoveRow(row)
self.SaveProcessVariables()
self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
setattr(self.ProcessVariablesGrid, "_DeleteRow", _DeleteVariablesElement)
def _MoveVariablesElement(row, move):
new_row = self.ProcessVariablesTable.MoveRow(row, move)
@@ -759,7 +759,7 @@
self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
setattr(self.ProcessVariablesGrid, "_MoveRow", _MoveVariablesElement)
_refresh_buttons = getattr(self.ProcessVariablesGrid, "RefreshButtons")
if self.NodesFilter.GetSelection() == 0:
@@ -770,7 +770,7 @@
self.UpVariableButton.Enable(False)
self.DownVariableButton.Enable(False)
setattr(self.ProcessVariablesGrid, "RefreshButtons", _RefreshButtons)
self.ProcessVariablesGrid.SetRowLabelSize(0)
for col in range(self.ProcessVariablesTable.GetNumberCols()):
attr = wx.grid.GridCellAttr()
@@ -779,16 +779,16 @@
self.ProcessVariablesGrid.SetColMinimalWidth(col, self.ProcessVariablesColSizes[col])
self.ProcessVariablesGrid.AutoSizeColumn(col, False)
self.ProcessVariablesGrid.RefreshButtons()
self.StartupCommandsDefaultValue = {"Position": 0, "Index": 0, "Subindex": 0, "Value": 0, "Description": ""}
self.StartupCommandsTable = StartupCommandsTable(self, [], GetStartupCommandsTableColnames())
self.StartupCommandsColSizes = [100, 100, 50, 100, 200]
self.StartupCommandsColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT]
self.StartupCommandsGrid.SetTable(self.StartupCommandsTable)
self.StartupCommandsGrid.SetButtons({"Add": self.AddCommandButton,
"Delete": self.DeleteCommandButton})
def _AddCommandsElement(new_row):
command = self.StartupCommandsDefaultValue.copy()
command_idx = self.Controler.AppendStartupCommand(command)
@@ -796,14 +796,14 @@
return self.StartupCommandsTable.GetCommandIndex(command["Position"], command_idx)
setattr(self.StartupCommandsGrid, "_AddRow", _AddCommandsElement)
def _DeleteCommandsElement(row):
command = self.StartupCommandsTable.GetRow(row)
self.Controler.RemoveStartupCommand(command["Position"], command["command_idx"])
self.RefreshStartupCommands()
setattr(self.StartupCommandsGrid, "_DeleteRow", _DeleteCommandsElement)
self.StartupCommandsGrid.SetRowLabelSize(0)
for col in range(self.StartupCommandsTable.GetNumberCols()):
attr = wx.grid.GridCellAttr()
@@ -812,32 +812,32 @@
self.StartupCommandsGrid.SetColMinimalWidth(col, self.StartupCommandsColSizes[col])
self.StartupCommandsGrid.AutoSizeColumn(col, False)
self.StartupCommandsGrid.RefreshButtons()
self.ParentWindow.RefreshTitle()
self.ParentWindow.RefreshFileMenu()
self.ParentWindow.RefreshEditMenu()
self.ParentWindow.RefreshPageTitles()
def GetBufferState(self):
return self.Controler.GetBufferState()
self.Controler.LoadPrevious()
self.Controler.LoadNext()
ConfTreeNodeEditor.RefreshView(self)
self.RefreshNodesFilter()
self.RefreshProcessVariables()
self.RefreshStartupCommands()
self.NodesVariables.RefreshView()
def RefreshNodesFilter(self):
value = self.NodesFilter.GetValue()
@@ -857,7 +857,7 @@
self.NodesFilter.SetSelection(0)
self.RefreshCurrentNodesFilter()
def RefreshCurrentNodesFilter(self):
filter = self.NodesFilter.GetSelection()
@@ -879,7 +879,7 @@
self.NodesFilter.SetValue(NODE_POSITION_FILTER_FORMAT % self.CurrentNodesFilter["slave_pos"])
self.NodesFilterFirstCharacter = True
self.NodesVariables.SetCurrentNodesFilter(self.CurrentNodesFilter)
def RefreshProcessVariables(self):
if self.CurrentNodesFilter is not None:
self.ProcessVariables = self.Controler.GetProcessVariables()
@@ -892,7 +892,7 @@
self.ProcessVariablesTable.SetData(data)
self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
self.ProcessVariablesGrid.RefreshButtons()
def SaveProcessVariables(self):
if self.CurrentNodesFilter is not None:
if len(self.CurrentNodesFilter) > 0:
@@ -900,7 +900,7 @@
self.Controler.SetProcessVariables(self.ProcessVariablesTable.GetData())
def RefreshStartupCommands(self, position=None, command_idx=None):
if self.CurrentNodesFilter is not None:
col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
@@ -909,15 +909,15 @@
self.StartupCommandsTable.ResetView(self.StartupCommandsGrid)
if position is not None and command_idx is not None:
self.SelectStartupCommand(position, command_idx, col)
def SelectStartupCommand(self, position, command_idx, col):
self.StartupCommandsGrid.SetSelectedCell(
self.StartupCommandsTable.GetCommandIndex(position, command_idx),
def GetMasterLocation(self):
return self.Controler.GetCurrentLocation()
def AddStartupCommand(self, position, index, subindex):
col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
command = self.StartupCommandsDefaultValue.copy()
@@ -928,7 +928,7 @@
self.RefreshStartupCommands()
self.SelectStartupCommand(position, command_idx, col)
def OnNodesFilterChanged(self, event):
self.RefreshCurrentNodesFilter()
if self.CurrentNodesFilter is not None:
@@ -936,22 +936,22 @@
self.RefreshStartupCommands()
self.NodesVariables.RefreshView()
def OnNodesFilterKeyDown(self, event):
if self.NodesFilterFirstCharacter:
keycode = event.GetKeyCode()
- if keycode not in [wx.WXK_RETURN,
+ if keycode not in [wx.WXK_RETURN, self.NodesFilterFirstCharacter = False
if keycode not in NAVIGATION_KEYS:
self.NodesFilter.SetValue("")
- if keycode not in [wx.WXK_DELETE,
+ if keycode not in [wx.WXK_DELETE,
def OnProcessVariablesGridCellChange(self, event):
row, col = event.GetRow(), event.GetCol()
colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
@@ -973,7 +973,7 @@
def OnProcessVariablesGridCellLeftClick(self, event):
@@ -984,30 +984,30 @@
number = self.ProcessVariablesTable.GetValueByName(row, "Number")
location = "%%M%s" % data_size + \
".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + (number,)))
data = wx.TextDataObject(str((location, "location", var_type, var_name, "")))
dragSource = wx.DropSource(self.ProcessVariablesGrid)
def OnProcessVariablesGridKeyDown(self, event):
keycode = event.GetKeyCode()
col = self.ProcessVariablesGrid.GetGridCursorCol()
row = self.ProcessVariablesGrid.GetGridCursorRow()
colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
- if (keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and
+ if (keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and (colname.startswith("Read from") or colname.startswith("Write to"))):
self.ProcessVariablesTable.SetValue(row, col, "")
self.SaveProcessVariables()
wx.CallAfter(self.ProcessVariablesTable.ResetView, self.ProcessVariablesGrid)
def OnStartupCommandsGridEditorShow(self, event):
self.CellShown = event.GetRow(), event.GetCol()
def OnStartupCommandsGridCellChange(self, event):
row, col = event.GetRow(), event.GetCol()
if self.CellShown == (row, col):
@@ -1029,7 +1029,7 @@
command = self.StartupCommandsTable.GetRow(row)
self.Controler.SetStartupCommandInfos(command)
- if colname in ["Index", "SubIndex"]:
+ if colname in ["Index", "SubIndex"]: wx.CallAfter(self.RefreshStartupCommands, command["Position"], command["command_idx"])
@@ -1041,7 +1041,7 @@
def OnResize(self, event):
self.EthercatMasterEditor.GetBestSize()
xstart, ystart = self.EthercatMasterEditor.GetViewStart()
@@ -1050,10 +1050,10 @@
posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
self.EthercatMasterEditor.Scroll(posx, posy)
- self.EthercatMasterEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
+ self.EthercatMasterEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
#def OnButtonClick(self, event):
# self.MasterState = self.Controler.getMasterState()
@@ -1067,7 +1067,7 @@
# self.TxByte.SetValue(self.MasterState["TXbyte"])
# self.TxError.SetValue(self.MasterState["TXerror"])
# self.LostFrames.SetValue(self.MasterState["lost"])
# self.TxFrameRate1.SetValue(self.MasterState["TXframerate1"])
# self.TxFrameRate2.SetValue(self.MasterState["TXframerate2"])
# self.TxFrameRate3.SetValue(self.MasterState["TXframerate3"])
@@ -1080,41 +1080,41 @@
# self.FrameLoss1.SetValue(self.MasterState["frameloss1"])
# self.FrameLoss2.SetValue(self.MasterState["frameloss2"])
# self.FrameLoss3.SetValue(self.MasterState["frameloss3"])
class LibraryEditorSizer(wx.FlexGridSizer):
def __init__(self, parent, module_library, buttons):
wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=4, vgap=5)
self.ModuleLibrary = module_library
self.ParentWindow = parent
- ESI_files_label = wx.StaticText(parent,
+ ESI_files_label = wx.StaticText(parent, - self.AddWindow(ESI_files_label, border=10,
+ self.AddWindow(ESI_files_label, border=10, flag=wx.TOP|wx.LEFT|wx.RIGHT)
folder_tree_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=0)
folder_tree_sizer.AddGrowableCol(0)
folder_tree_sizer.AddGrowableRow(0)
- self.AddSizer(folder_tree_sizer, border=10,
+ self.AddSizer(folder_tree_sizer, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT)
self.ESIFiles = FolderTree(parent, self.GetPath(), editable=False)
self.ESIFiles.SetFilter(".xml")
folder_tree_sizer.AddWindow(self.ESIFiles, flag=wx.GROW)
buttons_sizer = wx.BoxSizer(wx.VERTICAL)
- folder_tree_sizer.AddSizer(buttons_sizer,
+ folder_tree_sizer.AddSizer(buttons_sizer, flag=wx.ALIGN_CENTER_VERTICAL)
for idx, (name, bitmap, help, callback) in enumerate(buttons):
- button = wx.lib.buttons.GenBitmapButton(parent,
- bitmap=GetBitmap(bitmap),
+ button = wx.lib.buttons.GenBitmapButton(parent, + bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
@@ -1127,12 +1127,12 @@
parent.Bind(wx.EVT_BUTTON, callback, button)
buttons_sizer.AddWindow(button, border=10, flag=flag)
- modules_label = wx.StaticText(parent,
+ modules_label = wx.StaticText(parent, label=_("Modules library:"))
- self.AddSizer(modules_label, border=10,
+ self.AddSizer(modules_label, border=10,
self.ModulesGrid = wx.gizmos.TreeListCtrl(parent,
style=wx.TR_DEFAULT_STYLE |
@@ -1145,51 +1145,51 @@
self.OnModulesGridBeginLabelEdit)
self.ModulesGrid.Bind(wx.EVT_TREE_END_LABEL_EDIT,
self.OnModulesGridEndLabelEdit)
- self.ModulesGrid.GetHeaderWindow().Bind(wx.EVT_MOTION,
+ self.ModulesGrid.GetHeaderWindow().Bind(wx.EVT_MOTION, self.OnModulesGridHeaderMotion)
- self.AddWindow(self.ModulesGrid, border=10,
+ self.AddWindow(self.ModulesGrid, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
for colname, colsize, colalign in zip(
- [_("Name")] + [param_infos["column_label"]
- for param, param_infos in
+ [_("Name")] + [param_infos["column_label"] + for param, param_infos in self.ModuleLibrary.MODULES_EXTRA_PARAMS],
- [400] + [param_infos["column_size"]
- for param, param_infos in
+ [400] + [param_infos["column_size"] + for param, param_infos in self.ModuleLibrary.MODULES_EXTRA_PARAMS],
[wx.ALIGN_LEFT] + [wx.ALIGN_RIGHT] * len(self.ModuleLibrary.MODULES_EXTRA_PARAMS)):
self.ModulesGrid.AddColumn(_(colname), colsize, colalign, edit=True)
self.ModulesGrid.SetMainColumn(0)
self.CurrentSelectedCol = None
self.LastToolTipCol = None
return self.ModuleLibrary.GetPath()
def SetControlMinSize(self, size):
self.ESIFiles.SetMinSize(size)
self.ModulesGrid.SetMinSize(size)
def GetSelectedFilePath(self):
return self.ESIFiles.GetPath()
self.ESIFiles.RefreshTree()
self.RefreshModulesGrid()
def RefreshModulesGrid(self):
root = self.ModulesGrid.GetRootItem()
root = self.ModulesGrid.AddRoot("Modules")
- self.GenerateModulesGridBranch(root,
- self.ModuleLibrary.GetModulesLibrary(),
+ self.GenerateModulesGridBranch(root, + self.ModuleLibrary.GetModulesLibrary(), GetVariablesTableColnames())
self.ModulesGrid.Expand(root)
def GenerateModulesGridBranch(self, root, modules, colnames):
item, root_cookie = self.ModulesGrid.GetFirstChild(root)
no_more_items = not item.IsOk()
@@ -1197,8 +1197,8 @@
self.ModulesGrid.SetItemText(item, module["name"], 0)
if module["infos"] is not None:
for param_idx, (param, param_infos) in enumerate(self.ModuleLibrary.MODULES_EXTRA_PARAMS):
- self.ModulesGrid.SetItemText(item,
- str(module["infos"][param]),
+ self.ModulesGrid.SetItemText(item, + str(module["infos"][param]), self.ModulesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY)
@@ -1207,7 +1207,7 @@
item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
no_more_items = not item.IsOk()
@@ -1215,44 +1215,44 @@
item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
self.ModulesGrid.Delete(item)
def OnImportButton(self, event):
dialog = wx.FileDialog(self.ParentWindow,
- _("Choose an XML file"),
+ _("Choose an XML file"), _("XML files (*.xml)|*.xml|All files|*.*"), wx.OPEN)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
if self.ModuleLibrary.ImportModuleLibrary(filepath):
wx.CallAfter(self.RefreshView)
- message = wx.MessageDialog(self,
- _("No such XML file: %s\n") % filepath,
+ message = wx.MessageDialog(self, + _("No such XML file: %s\n") % filepath, _("Error"), wx.OK|wx.ICON_ERROR)
def OnDeleteButton(self, event):
filepath = self.GetSelectedFilePath()
if os.path.isfile(filepath):
folder, filename = os.path.split(filepath)
- dialog = wx.MessageDialog(self.ParentWindow,
- _("Do you really want to delete the file '%s'?") % filename,
+ dialog = wx.MessageDialog(self.ParentWindow, + _("Do you really want to delete the file '%s'?") % filename, _("Delete File"), wx.YES_NO|wx.ICON_QUESTION)
remove = dialog.ShowModal() == wx.ID_YES
self.ModuleLibrary.LoadModules()
wx.CallAfter(self.RefreshView)
def OnModulesGridLeftDown(self, event):
item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
@@ -1293,8 +1293,8 @@
wx.CallAfter(self.RefreshModulesGrid)
- message = wx.MessageDialog(self,
- _("Module %s must be an integer!") % stripped_column_label,
+ message = wx.MessageDialog(self, + _("Module %s must be an integer!") % stripped_column_label, _("Error"), wx.OK|wx.ICON_ERROR)
@@ -1303,7 +1303,7 @@
def OnModulesGridHeaderMotion(self, event):
item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
if col != self.LastToolTipCol and self.LastToolTipCol is not None:
@@ -1312,51 +1312,51 @@
if col > 0 and self.LastToolTipCol != col:
self.LastToolTipCol = col
param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[col - 1]
- wx.CallAfter(self.ModulesGrid.GetHeaderWindow().SetToolTipString,
+ wx.CallAfter(self.ModulesGrid.GetHeaderWindow().SetToolTipString, param_infos["description"])
class DatabaseManagementDialog(wx.Dialog):
def __init__(self, parent, database):
wx.Dialog.__init__(self, parent,
size=wx.Size(700, 500), title=_('ESI Files Database management'),
style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
self.DatabaseSizer = LibraryEditorSizer(self, database,
[("ImportButton", "ImportESI", _("Import file to ESI files database"), None),
("DeleteButton", "remove_element", _("Remove file from database"), None)])
self.DatabaseSizer.SetControlMinSize(wx.Size(0, 0))
main_sizer.AddSizer(self.DatabaseSizer, border=10,
flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
button_sizer.GetAffirmativeButton().SetLabel(_("Add file to project"))
button_sizer.GetCancelButton().SetLabel(_("Close"))
- main_sizer.AddSizer(button_sizer, border=10,
+ main_sizer.AddSizer(button_sizer, border=10, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
self.SetSizer(main_sizer)
self.DatabaseSizer.RefreshView()
return self.DatabaseSizer.GetSelectedFilePath()
class LibraryEditor(ConfTreeNodeEditor):
(_("Modules Library"), "_create_ModuleLibraryEditor")]
def _create_ModuleLibraryEditor(self, prnt):
self.ModuleLibraryEditor = wx.ScrolledWindow(prnt,
style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
self.ModuleLibraryEditor.Bind(wx.EVT_SIZE, self.OnResize)
self.ModuleLibrarySizer = LibraryEditorSizer(self.ModuleLibraryEditor,
self.Controler.GetModulesLibraryInstance(),
[("ImportButton", "ImportESI", _("Import ESI file"), None),
@@ -1364,30 +1364,30 @@
("DeleteButton", "remove_element", _("Remove file from library"), None)])
self.ModuleLibrarySizer.SetControlMinSize(wx.Size(0, 200))
self.ModuleLibraryEditor.SetSizer(self.ModuleLibrarySizer)
return self.ModuleLibraryEditor
def __init__(self, parent, controler, window):
ConfTreeNodeEditor.__init__(self, parent, controler, window)
ConfTreeNodeEditor.RefreshView(self)
self.ModuleLibrarySizer.RefreshView()
def OnAddButton(self, event):
- dialog = DatabaseManagementDialog(self,
+ dialog = DatabaseManagementDialog(self, self.Controler.GetModulesDatabaseInstance())
if dialog.ShowModal() == wx.ID_OK:
module_library = self.Controler.GetModulesLibraryInstance()
module_library.ImportModuleLibrary(dialog.GetValue())
wx.CallAfter(self.ModuleLibrarySizer.RefreshView)
def OnResize(self, event):
@@ -1398,7 +1398,6 @@
posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
self.ModuleLibraryEditor.Scroll(posx, posy)
- self.ModuleLibraryEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
+ self.ModuleLibraryEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
--- a/etherlab/EtherCATManagementEditor.py Fri Sep 28 17:15:53 2018 +0300
+++ b/etherlab/EtherCATManagementEditor.py Fri Sep 28 17:20:11 2018 +0300
@@ -23,7 +23,7 @@
import wx.grid as gridlib
#-------------------------------------------------------------
-# ------------ for register management ---------------
+# ------------ for register management --------------- from xml.dom import minidom
#-------------------------------------------------------------
@@ -39,7 +39,7 @@
#-------------------------------------------------------------------------------
class SyncManagersTable(CustomTable):
- def GetValue(self, row, col):
+ def GetValue(self, row, col): if row < self.GetNumberRows():
@@ -60,15 +60,15 @@
self.Controler = controler
self.NodeEditor = node_editor
self.EtherCATManagementClassObject = {}
# fill EtherCAT Management Treebook
for pname, pclass, subs in [
("Slave State", SlaveStatePanelClass, []),
("SDO Management", SDOPanelClass, []),
("PDO Monitoring", PDOPanelClass, []),
- ("ESC Management", EEPROMAccessPanel, [
+ ("ESC Management", EEPROMAccessPanel, [ ("Smart View", SlaveSiiSmartView),
("Register Access", RegisterAccessPanel, [])]:
@@ -78,22 +78,22 @@
self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGED, self.OnPageChanged)
self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGING, self.OnPageChanging)
def OnPageChanged(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
sel = event.GetSelection()
def OnPageChanging(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
sel = event.GetSelection()
#-------------------------------------------------------------------------------
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class SlaveStatePanelClass(wx.Panel):
def __init__(self, parent, controler):
@@ -104,13 +104,13 @@
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),
@@ -120,15 +120,15 @@
"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])
+ 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"),
@@ -136,16 +136,16 @@
("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["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.SyncManagersGrid = CustomGrid(self, size=wx.Size(605,155), style=wx.VSCROLL) + self.SizerDic["SyncManagerInnerSizer"].Add(self.SyncManagersGrid) self.SizerDic["SyncManagerBox"].Add(self.SizerDic["SyncManagerInnerSizer"])
for button_name, button_id, button_label, button_tooltipstring, event_method, sub_item in [
("InitButton", 0, "INIT", "State Transition to \"Init\" State", self.OnButtonClick, []),
("PreOPButton", 1, "PREOP", "State Transition to \"PreOP\" State", self.OnButtonClick, [
@@ -160,46 +160,46 @@
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.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"].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,
+ 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]
@@ -209,10 +209,10 @@
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)
+ self.SyncManagersGrid.AutoSizeColumn(col, False)
def RefreshSlaveInfos(self):
Fill data in "Slave Information" and "SyncManager"
@@ -220,7 +220,7 @@
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"
+ # 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"])
@@ -230,7 +230,7 @@
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)
@@ -239,7 +239,7 @@
check_connect_flag = self.Controler.CommonMethod.CheckConnect(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()])
@@ -254,8 +254,8 @@
self.Controler.CommonMethod.RequestSlaveState("OP")
self.TextCtrlDic["TargetState"].SetValue("OP")
- self.Controler.CommonMethod.CreateErrorDialog("PLC is Not Started")
+ 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).
@@ -268,8 +268,8 @@
self.SetCurrentState(line[self.Controler.GetSlavePos()])
def SetCurrentState(self, line):
Show current slave state using the executiob result of "ethercat slaves" command.
@@ -281,10 +281,10 @@
# Result example : 0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100)
if token[2] in state_array:
- self.TextCtrlDic["CurrentState"].SetValue(token[2])
+ self.TextCtrlDic["CurrentState"].SetValue(token[2])
def StartTimer(self, event):
Event handler for "Start State Monitoring" button.
@@ -294,7 +294,7 @@
self.SlaveStateThread = wx.Timer(self)
# set timer period (1000 ms)
self.SlaveStateThread.Start(1000)
def CurrentStateThreadStop(self, event):
Event handler for "Stop State Monitoring" button.
@@ -305,10 +305,10 @@
self.SlaveStateThread.Stop()
#-------------------------------------------------------------------------------
# For SDO Management Panel
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class SDOPanelClass(wx.Panel):
def __init__(self, parent, controler):
@@ -317,64 +317,64 @@
@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.SDOManagementMainSizer = wx.BoxSizer(wx.VERTICAL)
self.SDOManagementInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
- self.SDOUpdate = wx.Button(self, label=_('update'))
+ self.SDOUpdate = wx.Button(self, label=_('update')) self.SDOUpdate.Bind(wx.EVT_BUTTON, self.SDOInfoUpdate)
self.CallSDONoteBook = SDONoteBook(self, controler=self.Controler)
self.SDOManagementInnerMainSizer.Add(self.SDOUpdate)
- self.SDOManagementInnerMainSizer.Add(self.CallSDONoteBook, wx.ALL | wx.EXPAND)
+ self.SDOManagementInnerMainSizer.Add(self.CallSDONoteBook, wx.ALL | wx.EXPAND) self.SDOManagementMainSizer.Add(self.SDOManagementInnerMainSizer)
self.SetSizer(self.SDOManagementMainSizer)
def SDOInfoUpdate(self, event):
Evenet handler for SDO "update" button.
- - Load SDO data from current slave
+ - Load SDO data from current slave @param event : wx.EVT_BUTTON object
self.Controler.CommonMethod.SaveSDOData = []
self.Controler.CommonMethod.ClearSDODataSet()
# Check whether beremiz connected or not.
check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
self.SDOs = self.Controler.CommonMethod.GetSlaveSDOFromSlave()
# SDOFlag is "False", user click "Cancel" button
- self.SDOFlag = self.SDOParser()
+ self.SDOFlag = self.SDOParser() - self.CallSDONoteBook.CreateNoteBook()
+ self.CallSDONoteBook.CreateNoteBook()
Parse SDO data set that obtain "SDOInfoUpdate" Method
slaveSDO_progress = wx.ProgressDialog("Slave SDO Monitoring", "Now Uploading...",
maximum = len(self.SDOs.splitlines()), parent=self,
- style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME |
- wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME |
- wx.PD_AUTO_HIDE | wx.PD_SMOOTH)
+ style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | + wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME | + wx.PD_AUTO_HIDE | wx.PD_SMOOTH) # If keep_going flag is False, SDOParser method is stop and return "False".
# SDO 0x1000, "Device type"
# 0x1000:00,r-r-r-,uint32,32 bit,"Device type",0x00020192, 131474
for details_line in self.SDOs.splitlines():
@@ -387,64 +387,64 @@
# line_token = ['0x1000:00,r-r-r-,uint32,32 bit,', 'Device type', ',0x00020192, 131474']
token_head, name, token_tail = line_token
# token_head = ['0x1000:00', 'r-r-r-', 'uint32', '32 bit', '']
token_head = token_head.split(",")
ful_idx, access, type, size, empty = token_head
# ful_idx.split(":") = ['0x1000', '00']
idx, sub_idx = ful_idx.split(":")
# token_tail = ['', '0x00020192', '131474']
token_tail = token_tail.split(",")
empty, hex_val, dec_val = token_tail
# SDO data is not return "dec value"
- # 0x1702:01,rwr-r-,uint32,32 bit," 1st mapping", ----
+ # 0x1702:01,rwr-r-,uint32,32 bit," 1st mapping", ---- empty, hex_val = token_tail
name_after_check = self.StringTest(name)
if type == "octet_string":
# SResult of SlaveSDO data parsing. (data type : dictionary)
- self.Data = {'idx':idx.strip(), 'subIdx':sub_idx.strip(), 'access':access.strip(),
- 'type':type.strip(), 'size':size.strip(), 'name':name_after_check.strip("\""),
+ self.Data = {'idx':idx.strip(), 'subIdx':sub_idx.strip(), 'access':access.strip(), + 'type':type.strip(), 'size':size.strip(), 'name':name_after_check.strip("\""), 'value':hex_val.strip(), "category":title_name.strip("\"")}
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.SaveSDOData[count].append(self.Data)
self.Controler.CommonMethod.SaveSDOData[self.AllSDOData].append(self.Data)
if count >= len(self.SDOs.splitlines()) / 2:
(keep_going, skip) = slaveSDO_progress.Update(count, "Please waiting a moment!!")
(keep_going, skip) = slaveSDO_progress.Update(count)
- # If user click "Cancel" loop suspend immediately
+ # If user click "Cancel" loop suspend immediately if (keep_going == False):
- slaveSDO_progress.Destroy()
+ slaveSDO_progress.Destroy() def StringTest(self, check_string):
- Test value 'name' is alphanumeric
- @param check_string : input data for check
+ Test value 'name' is alphanumeric + @param check_string : input data for check @return result : output data after check
# string.printable is print this result
#'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
#!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c
@@ -456,11 +456,11 @@
result = check_string[:len(check_string) - i]
#-------------------------------------------------------------------------------
# For SDO Notebook (divide category)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class SDONoteBook(wx.Notebook):
def __init__(self, parent, controler):
@@ -468,23 +468,23 @@
@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))
+ wx.Notebook.__init__(self, parent, id = -1, size=(850,500)) self.Controler = controler
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
- def CreateNoteBook(self):
+ 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),
@@ -500,12 +500,12 @@
for txt, count in page_texts:
self.Data = self.Controler.CommonMethod.SaveSDOData[count]
- self.Win = SlaveSDOTable(self, self.Data)
+ self.Win = SlaveSDOTable(self, self.Data) self.AddPage(self.Win, txt)
def OnPageChanged(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
@@ -520,17 +520,17 @@
#-------------------------------------------------------------------------------
# For SDO Grid (fill index, subindex, etc...)
-#-------------------------------------------------------------------------------
-class SlaveSDOTable(wx.grid.Grid):
+#------------------------------------------------------------------------------- +class SlaveSDOTable(wx.grid.Grid): def __init__(self, parent, data):
@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),
+ 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
@@ -538,55 +538,55 @@
self.CreateGrid(len(self.SDOs), 8)
- SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 55),
+ SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 55), (4, 40), (5, 200), (6, 250), (7, 85)]
for (index, size) in SDOCellSize:
self.SetColSize(index, size)
SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
(3, "Type"), (4, "Size"), (5, "Category"),
(6, "Name"), (7, "Value")]
for (index, label) in SDOTableLabel:
self.SetColLabelValue(index, label)
self.SetColLabelAlignment(index, wx.ALIGN_CENTRE)
attr = wx.grid.GridCellAttr()
self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.SDOModifyDialog)
- self.SetColAttr(i,attr)
+ self.SetColAttr(i,attr) self.SetColLabelAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)
Cell is filled by new parsing data
sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'category', 'name', 'value']
for row_idx in range(len(self.SDOs)):
- for col_idx in range(len(self.SDOs[row_idx])):
+ for col_idx in range(len(self.SDOs[row_idx])): 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):
CheckSDODataAccess method is checking that access data has "w"
Access field consist 6 char, if mean
- Example Access field : rwrwrw, rwrw--
+ Example Access field : rwrwrw, rwrw-- @param row : Selected cell by user
@return Write_flag : If data has "w", flag is true
@@ -595,23 +595,23 @@
self.Controler.CommonMethod.Check_PREOP = True
self.Controler.CommonMethod.Check_SAFEOP = True
self.Controler.CommonMethod.Check_OP = True
def DecideSDODownload(self, state):
- compare current state and "access" field,
+ compare current state and "access" field, result notify SDOModifyDialog method
@param state : current slave state
- # Example of 'state' parameter : "0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100)"
+ # Example of 'state' parameter : "0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100)" state = state[self.Controler.GetSlavePos()].split(" ")[2]
if state == "PREOP" and self.Controler.CommonMethod.Check_PREOP :
@@ -619,9 +619,9 @@
elif state == "OP" and self.Controler.CommonMethod.Check_OP :
def ClearStateFlag(self):
@@ -630,45 +630,45 @@
self.Controler.CommonMethod.Check_PREOP = False
self.Controler.CommonMethod.Check_SAFEOP = False
self.Controler.CommonMethod.Check_OP = False
def SDOModifyDialog (self, event):
Create dialog for SDO value modify
- if user enter data, perform command "ethercat download"
+ 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() == 7 and self.CheckSDODataAccess(event.GetRow()) :
+ # CheckSDODataAccess is checking that OD(Object Dictionary) has "w" + if event.GetCol() == 7 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())
+ start_value = self.GetCellValue(event.GetRow(), event.GetCol()) dlg.SetValue(start_value)
if dlg.ShowModal() == wx.ID_OK:
if self.DecideSDODownload(self.Controler.CommonMethod.SlaveState[self.Controler.GetSlavePos()]) :
- self.Controler.CommonMethod.SDODownload(self.SDOs[event.GetRow()]['type'], self.SDOs[event.GetRow()]['idx'],
+ self.Controler.CommonMethod.SDODownload(self.SDOs[event.GetRow()]['type'], self.SDOs[event.GetRow()]['idx'], self.SDOs[event.GetRow()]['subIdx'], dlg.GetValue())
self.SetCellValue(event.GetRow(), event.GetCol(), hex(int(dlg.GetValue(), 0)))
- self.Controler.CommonMethod.CreateErrorDialog('You cannot SDO download this state')
+ self.Controler.CommonMethod.CreateErrorDialog('You cannot SDO download this state') # Error occured process of "int(variable)"
# User input is not hex, dec value
- self.Controler.CommonMethod.CreateErrorDialog('You can input only hex, dec value')
+ self.Controler.CommonMethod.CreateErrorDialog('You can input only hex, dec value') #-------------------------------------------------------------------------------
# For PDO Monitoring Panel
-# PDO Class UI : Panel -> Choicebook (RxPDO, TxPDO) ->
+# PDO Class UI : Panel -> Choicebook (RxPDO, TxPDO) -> # Notebook (PDO Index) -> Grid (PDO entry)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class PDOPanelClass(wx.Panel):
def __init__(self, parent, controler):
@@ -681,12 +681,12 @@
self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
- self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)
- self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)
+ self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler) + self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL) self.PDOMonitoringEditorMainSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
self.SetSizer(self.PDOMonitoringEditorMainSizer)
@@ -701,7 +701,7 @@
#-------------------------------------------------------------------------------
# For PDO Choicebook (divide Tx, Rx PDO)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class PDOChoicebook(wx.Choicebook):
def __init__(self, parent, controler):
@@ -711,15 +711,15 @@
wx.Choicebook.__init__(self, parent, id=-1, size=(500, 500), style=wx.CHB_DEFAULT)
self.Controler = controler
RxWin = PDONoteBook(self, controler=self.Controler, name="Rx")
TxWin = PDONoteBook(self, controler=self.Controler, name="Tx")
self.AddPage(RxWin, "RxPDO")
self.AddPage(TxWin, "TxPDO")
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
def OnPageChanged(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
@@ -730,12 +730,12 @@
old = event.GetOldSelection()
new = event.GetSelection()
sel = self.GetSelection()
#-------------------------------------------------------------------------------
# For PDO Notebook (divide PDO index)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class PDONoteBook(wx.Notebook):
def __init__(self, parent, name, controler):
@@ -746,12 +746,12 @@
wx.Notebook.__init__(self, parent, id=-1, size=(640, 400))
self.Controler = controler
self.Controler.CommonMethod.RequestPDOInfo()
# obtain pdo_info and pdo_entry
# pdo_info include (PDO index, name, number of entry)
@@ -761,22 +761,22 @@
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)
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
def OnPageChanged(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
@@ -787,12 +787,12 @@
old = event.GetOldSelection()
new = event.GetSelection()
sel = self.GetSelection()
#-------------------------------------------------------------------------------
# For PDO Grid (fill entry index, subindex etc...)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class PDOEntryTable(wx.grid.Grid):
def __init__(self, parent, info, entry, count):
@@ -802,38 +802,38 @@
@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),
+ 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)
- self.SetColLabelSize(25)
+ self.SetColLabelSize(25)
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
@@ -844,7 +844,7 @@
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])):
@@ -863,9 +863,9 @@
#-------------------------------------------------------------------------------
-# For EEPROM Access Main Panel
+# For EEPROM Access Main Panel # (This class explain EEPROM Access)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class EEPROMAccessPanel(wx.Panel):
def __init__(self, parent, controler):
@@ -875,19 +875,19 @@
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):
@@ -898,8 +898,8 @@
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
- self.PDIType = {0 :['none', '00000000'],
+ self.PDIType = {0 :['none', '00000000'], 4 :['Digital I/O', '00000100'],
5 :['SPI Slave', '00000101'],
7 :['EtherCAT Bridge (port3)', '00000111'],
@@ -914,7 +914,7 @@
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)
@@ -923,78 +923,78 @@
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, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
if status is not "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
+ # 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.
check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
self.SiiBinary = self.Controler.CommonMethod.LoadData()
- dialog = wx.FileDialog(self, _("Save as..."), os.getcwd(),
- "slave0.bin", _("bin files (*.bin)|*.bin|All files|*.*"),
+ 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"]
@@ -1003,14 +1003,14 @@
cnt_pdi_type = self.PDIType[i][0]
- for treelist, data in [("EEPROM Size (Bytes)",
+ 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"]),
@@ -1018,30 +1018,30 @@
("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)
+ 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)
+ 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) }
sii_dict= { 'PDIControl' : ( '0', 1),
'PDIConfiguration' : ( '1', 1),
@@ -1071,7 +1071,7 @@
'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)
@@ -1082,13 +1082,13 @@
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])))
+ 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.
for treelist, data in [("Vendor ID", self.GetWordAddressData( sii_dict.get('VendorID'),16 )),
@@ -1096,10 +1096,10 @@
("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 :
+ # 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, "]
@@ -1112,20 +1112,20 @@
for treelist, data in [("Supported Mailbox", supported_mailbox),
("Bootstrap Configuration", ""),
("Standard Configuration", "")]:
- self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)
+ 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.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)
+ 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.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)
+ self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.StandardConfig[treelist], data, 1) def MakeStaticBoxSizer(self, boxlabel):
@@ -1136,14 +1136,14 @@
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
@@ -1151,21 +1151,21 @@
for index in range(length):
hexdata = hex(ord(self.SiiBinary[offset + index]))[2:]
list.append(hexdata.zfill(2))
- return '0x' + ''.join(data)
+ return '0x' + ''.join(data) return str(int(str(''.join(data)), 16))
#-------------------------------------------------------------------------------
# For Smart View TreeListCtrl
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class SmartViewTreeListCtrl(wx.Panel):
def __init__(self, parent, Controler):
@@ -1175,26 +1175,26 @@
wx.Panel.__init__(self, parent, -1, size=(350, 500))
- self.Tree = wx.gizmos.TreeListCtrl(self, -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)
@@ -1208,7 +1208,7 @@
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 = {}
@@ -1218,13 +1218,13 @@
for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
self.StandardConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Standard Configuration"], lv3)
- for tree in [self.Root,
- self.Level1Nodes["Config Data"],
- self.Level1Nodes["Device Identity"],
+ for tree in [self.Root, + self.Level1Nodes["Config Data"], + self.Level1Nodes["Device Identity"], self.Level1Nodes["Mailbox"],
- self.Mailbox["Bootstrap Configuration"],
+ self.Mailbox["Bootstrap Configuration"], self.Mailbox["Standard Configuration"]]:
@@ -1232,7 +1232,7 @@
#-------------------------------------------------------------------------------
# shows EEPROM binary as hex data and characters.
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- def __init__(self, parent, controler):
@@ -1243,10 +1243,10 @@
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()}
@@ -1256,16 +1256,16 @@
("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] = 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.HexViewSizer["view"].AddMany([self.HexViewSizer["siiButton"], self.SiiGrid]) self.SiiGrid.CreateGrid(self.HexRow, self.HexCol)
- self.SetSizer(self.HexViewSizer["view"])
+ self.SetSizer(self.HexViewSizer["view"]) self.HexViewSizer["view"].FitInside(self.parent.parent)
self.parent.parent.FitInside()
self.SiiGrid.SetValue(self.HexCode)
@@ -1275,7 +1275,7 @@
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)
@@ -1290,7 +1290,7 @@
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.
check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
@@ -1300,29 +1300,29 @@
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
+ 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.
+ # Check whether beremiz connected or not, + # and whether status is "Started" or not. check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
if status is not "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",
+ 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:
@@ -1330,33 +1330,33 @@
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(), "",
+ 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.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
@@ -1372,8 +1372,8 @@
#-------------------------------------------------------------------------------
# For Hex View grid (fill hex data)
-#-------------------------------------------------------------------------------
-class SiiGridTable(wx.grid.Grid):
+#------------------------------------------------------------------------------- +class SiiGridTable(wx.grid.Grid): def __init__(self, parent, controler, row, col):
@@ -1384,10 +1384,10 @@
self.Controler = controler
- wx.grid.Grid.__init__(self, parent, -1, size=(830,450),
- style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ wx.grid.Grid.__init__(self, parent, -1, size=(830,450), + style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL) def SetValue(self, value):
@@ -1403,28 +1403,28 @@
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):
@@ -1435,31 +1435,31 @@
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.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()
+ 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,
@@ -1473,22 +1473,22 @@
# 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.
@@ -1499,26 +1499,26 @@
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
+ # 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.
+ Get and save the description of registers. It's done by parsing register_information.xml.
# parse the above register's value
@@ -1528,11 +1528,11 @@
# 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')
@@ -1540,7 +1540,7 @@
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:
@@ -1550,7 +1550,7 @@
("pdi", "type", self.PDIType),
("fmmu", "number", self.FMMUNumber),
("sm", "number", self.SMNumber)]:
- if property in register.attributes.keys():
+ if property in register.attributes.keys(): if register.attributes[property].value == value:
self.GetRegisterInfo(reg_info_tree, register)
@@ -1562,7 +1562,7 @@
self.GetRegisterInfo(reg_info_tree, register)
def GetRegisterInfo(self, reg_info_tree, register):
Save the register's description into the dictionary.
@@ -1573,7 +1573,7 @@
# 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:
@@ -1581,15 +1581,15 @@
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
+ # Add description for register main table if reg_index is not "" and reg_main_description is not "":
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)
@@ -1597,7 +1597,7 @@
("pdi", "type", self.PDIType),
("fmmu", "number", self.FMMUNumber),
("sm", "number", self.SMNumber)]:
- if property in detail.attributes.keys():
+ if property in detail.attributes.keys(): if detail.attributes[property].value == value:
self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
@@ -1609,7 +1609,7 @@
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.
@@ -1617,30 +1617,30 @@
@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
+ # 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":
+ 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.).
+ # 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:
@@ -1648,16 +1648,16 @@
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 is not "" and reg_sub_value_description is not "":
reg_enum_dictionary[reg_sub_value] = reg_sub_value_description
# add a description to register sub table description dictionary
if reg_bit_range is not "" and reg_sub_description is not "":
- self.RegisterSubGridDict[reg_index].append([reg_bit_range,
+ self.RegisterSubGridDict[reg_index].append([reg_bit_range, reg_sub_description, reg_enum_dictionary])
Transform the data into dec, hex, string, and description
@@ -1665,30 +1665,30 @@
reg_data = self.Controler.CommonMethod.RegData.split()
# loop for register(0x0000:0x0fff)
for address in range(0x1000):
- # arrange 2 Bytes of register data
+ # 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 self.RegisterDescriptionDict.has_key(hex_address):
row_data.append(self.RegisterDescriptionDict[hex_address])
row_data.append(str(int(reg_word, 16)))
row_data.append('0x'+reg_word)
@@ -1697,11 +1697,11 @@
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.
@@ -1717,10 +1717,10 @@
self.ToggleCompactViewCheckbox(True)
- self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol,
- self.PageRange[index][0], self.PageRange[index][1],
+ self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, + self.PageRange[index][0], self.PageRange[index][1], def ToggleCompactViewCheckbox(self, event):
@@ -1730,12 +1730,12 @@
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==True or event.GetEventObject().GetValue():
@@ -1758,34 +1758,34 @@
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.PageRange[index][1] += page_row[iter] - self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol,
- self.PageRange[index][0], self.PageRange[index][1],
+ self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, + self.PageRange[index][0], self.PageRange[index][1],
- # Compact View Checkbox is False
+ # 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.MainRow[index], self.MainCol,
- self.PageRange[index][0], self.PageRange[index][1],
+ self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, + self.PageRange[index][0], self.PageRange[index][1],
#-------------------------------------------------------------------------------
# For Register Access Notebook (divide index range)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class RegisterNotebook(wx.Notebook):
def __init__(self, parent, controler):
@@ -1794,21 +1794,21 @@
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
wx.Notebook.__init__(self, parent, id = -1)
self.Controler = controler
self.RegPage.append(None)
- self.RegPage[index] = RegisterNotebookPanel(self, self.Controler,
+ self.RegPage[index] = RegisterNotebookPanel(self, self.Controler, parent.MainRow[index], parent.MainCol)
- self.AddPage(self.RegPage[index],
+ self.AddPage(self.RegPage[index], "0x"+"{:0>4x}".format(index*1024)+" - 0x"+"{:0>4x}".format((index+1)*1024-1))
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
@@ -1826,9 +1826,9 @@
#-------------------------------------------------------------------------------
-# For Register Access Notebook Panel
+# For Register Access Notebook Panel # (Main UI : including main, sub table)
-#-------------------------------------------------------------------------------
+#------------------------------------------------------------------------------- class RegisterNotebookPanel(wx.Panel):
def __init__(self, parent, controler, row, col):
@@ -1838,26 +1838,26 @@
@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):
@@ -1892,13 +1892,13 @@
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):
+ def __init__(self, parent, row, col, controler): @param parent: RegisterNotebook object
@@ -1911,16 +1911,16 @@
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)
+ 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 [(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnRegModifyDialog)]:
self.Bind(evt, mapping_method)
- def SetValue(self, parent, reg_monitor_data, low_index, high_index):
+ def SetValue(self, parent, reg_monitor_data, low_index, high_index): Set the RegMonitorData into the main table.
@param parent: RegisterNotebook object
@@ -1929,21 +1929,21 @@
@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"),
+ 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]:
@@ -1954,8 +1954,8 @@
self.SetReadOnly(row, col, True)
- def OnSelectCell(self, event):
+ def OnSelectCell(self, event): Handles the event of the cell of the main table.
@param event: gridlib object (left click)
@@ -1964,17 +1964,17 @@
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,
+ # 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]:
@@ -1991,11 +1991,11 @@
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.
@@ -2004,16 +2004,16 @@
# 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",
+ 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.
+ # It int(input) success, this input is dev or hex value. # Otherwise, it's error, so it goes except.
@@ -2023,7 +2023,7 @@
- self.SetCellValue(event.GetRow(), 1, str(int(dlg.GetValue(), 0)))
+ 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)
@@ -2035,19 +2035,19 @@
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.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):
@@ -2060,8 +2060,8 @@
- wx.grid.Grid.__init__(self, parent, -1, size=(820,150),
- style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ 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):
@@ -2070,30 +2070,30 @@
# lset label name and size
- Register_SubTable_Label = [(0, "Bits"), (1, "Name"),
+ 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):
@@ -2101,14 +2101,14 @@
@param parent: wx.ScrollWindow object
@Param controler: _EthercatSlaveCTN class in EthercatSlave.py
- wx.Panel.__init__(self, parent, -1, (0, 0),
+ wx.Panel.__init__(self, parent, -1, (0, 0), size=wx.DefaultSize, style = wx.SUNKEN_BORDER)
self.Controler = controler
# ----------------------- Main Sizer and Update Button --------------------------------------------
self.MasterStateSizer = {"main" : wx.BoxSizer(wx.VERTICAL)}
@@ -2123,15 +2123,15 @@
self.UpdateButton = wx.Button(self, label=_('Update'))
self.UpdateButton.Bind(wx.EVT_BUTTON, self.OnButtonClick)
('masterState', 'EtherCAT Master State'),
('deviceInfo', 'Ethernet Network Card Information'),
('frameInfo', 'Network Frame Information')]:
self.StaticBox[key] = wx.StaticBox(self, label=_(label))
self.MasterStateSizer[key] = wx.StaticBoxSizer(self.StaticBox[key])
# ----------------------- Master State -----------------------------------------------------------
@@ -2139,11 +2139,11 @@
('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['innerMasterState'].AddMany([self.StaticText[key], self.TextCtrl[key]]) self.MasterStateSizer['masterState'].AddSizer(self.MasterStateSizer['innerMasterState'])
- # ----------------------- Ethernet Network Card Information ---------------------------------------
+ # ----------------------- Ethernet Network Card Information --------------------------------------- ('Main', 'MAC Address:'),
@@ -2153,24 +2153,24 @@
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]:'),
- ('Rx frame rate [1/s]', 'Tx Rate [kByte/s]:'),
+ ('Tx frame rate [1/s]', 'Tx Frame Rate [1/s]:'), + ('Rx frame rate [1/s]', 'Tx 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])
- self.TextCtrl[key] = {}
- for index in ['0', '1', '2']:
+ self.TextCtrl[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'])
# --------------------------------- Main Sizer ----------------------------------------------------
@@ -2184,7 +2184,7 @@
self.MasterStateSizer['main'].AddSizer(self.UpdateButton)
self.MasterStateSizer['main'].AddSizer(self.MasterStateSizer['innerMain'])
self.SetSizer(self.MasterStateSizer['main'])
def OnButtonClick(self, event):
--- a/etherlab/EthercatCFileGenerator.py Fri Sep 28 17:15:53 2018 +0300
+++ b/etherlab/EthercatCFileGenerator.py Fri Sep 28 17:20:11 2018 +0300
@@ -72,7 +72,7 @@
entry_infos["data_type"] = DATATYPECONVERSION.get(entry_infos["var_type"], None)
if entry_infos["data_type"] is None:
raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"]
if not entry_infos.get("no_decl", False):
if entry_infos.has_key("real_var"):
str_completion["located_variables_declaration"].append(
@@ -88,40 +88,40 @@
"IEC_%(var_type)s *%(extra_decl)s = &%(real_var)s;" % entry_infos)
elif not entry_infos.has_key("real_var"):
entry_infos["real_var"] = "beremiz" + entry_infos["var_name"]
str_completion["used_pdo_entry_offset_variables_declaration"].append(
"unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos)
if entry_infos["data_type"] == "BIT":
str_completion["used_pdo_entry_offset_variables_declaration"].append(
"unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos)
str_completion["used_pdo_entry_configuration"].append(
- (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " +
- "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " +
+ (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + + "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos)
if entry_infos["dir"] == "I":
str_completion["retrieve_variables"].append(
- (" %(real_var)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " +
+ (" %(real_var)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos)
elif entry_infos["dir"] == "Q":
str_completion["publish_variables"].append(
- (" EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " +
+ (" EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + "slave%(slave)d_%(index).4x_%(subindex).2x_bit, %(real_var)s);") % entry_infos)
str_completion["used_pdo_entry_configuration"].append(
- (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " +
+ (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos)
if entry_infos["dir"] == "I":
str_completion["retrieve_variables"].append(
- (" %(real_var)s = EC_READ_%(data_type)s(domain1_pd + " +
+ (" %(real_var)s = EC_READ_%(data_type)s(domain1_pd + " + "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos)
elif entry_infos["dir"] == "Q":
str_completion["publish_variables"].append(
- (" EC_WRITE_%(data_type)s(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " +
+ (" EC_WRITE_%(data_type)s(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + "%(real_var)s);") % entry_infos)
def ExclusionSortFunction(x, y):
@@ -134,22 +134,22 @@
return -cmp(x["matching"], y["matching"])
class _EthercatCFileGenerator:
def __init__(self, controler):
self.Controler = controler
def DeclareSlave(self, slave_index, slave):
self.Slaves.append((slave_index, slave.getInfo().getAutoIncAddr(), slave))
def DeclareVariable(self, slave_index, index, subindex, iec_type, dir, name, no_decl=False):
slave_variables = self.UsedVariables.setdefault(slave_index, {})
entry_infos = slave_variables.get((index, subindex), None)
slave_variables[(index, subindex)] = {
@@ -164,16 +164,16 @@
raise ValueError, _("Output variables can't be defined with different locations (%s and %s)") % (entry_infos["infos"][2], name)
- raise ValueError, _("Definition conflict for location \"%s\"") % name
+ raise ValueError, _("Definition conflict for location \"%s\"") % name def GenerateCFile(self, filepath, location_str, master_number):
# Extract etherlab master code template
plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c")
plc_etherlab_file = open(plc_etherlab_filepath, 'r')
plc_etherlab_code = plc_etherlab_file.read()
plc_etherlab_file.close()
# Initialize strings for formatting master code template
"location": location_str,
@@ -189,49 +189,49 @@
"retrieve_variables": [],
# Initialize variable storing variable mapping state
for slave_entries in self.UsedVariables.itervalues():
for entry_infos in slave_entries.itervalues():
entry_infos["mapped"] = False
# Sort slaves by position (IEC_Channel)
# Initialize dictionary storing alias auto-increment position values
# Generating code for each slave
for (slave_idx, slave_alias, slave) in self.Slaves:
type_infos = slave.getType()
# Defining slave alias and auto-increment position
if alias.get(slave_alias) is not None:
slave_pos = (slave_alias, alias[slave_alias])
# Extract slave device informations
device, module_extra_params = self.Controler.GetModuleInfos(type_infos)
raise ValueError, _("No informations found for device %s!") % (type_infos["device_type"])
# Extract slaves variables to be mapped
slave_variables = self.UsedVariables.get(slave_idx, {})
# Extract slave device object dictionary entries
device_entries = device.GetEntriesList()
# Adding code for declaring slave in master code template strings
for element in ["vendor", "product_code", "revision_number"]:
type_infos[element] = ExtractHexDecValue(type_infos[element])
type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos)))
# Extract slave device CoE informations
device_coe = device.getCoE()
if device_coe is not None:
- # If device support CanOpen over Ethernet, adding code for calling
+ # If device support CanOpen over Ethernet, adding code for calling # init commands when initializing slave in master code template strings
for initCmd in device_coe.getInitCmd():
@@ -256,37 +256,37 @@
init_cmd_infos.update(type_infos)
str_completion["slaves_initialization"] += SLAVE_INITIALIZATION_TEMPLATE % init_cmd_infos
# Extract slave device PDO configuration capabilities
PdoAssign = device_coe.getPdoAssign()
PdoConfig = device_coe.getPdoConfig()
PdoAssign = PdoConfig = False
# Test if slave has a configuration or need one
if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 and PdoConfig and PdoAssign:
str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos
str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos
"pdos_entries_infos": [],
pdos_infos.update(type_infos)
for sync_manager_idx, sync_manager in enumerate(device.getSm()):
- "index": sync_manager_idx,
+ "index": sync_manager_idx, "name": sync_manager.getcontent(),
sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
sync_manager_direction = sync_manager_control_byte & 0x0c
sync_manager_watchdog = sync_manager_control_byte & 0x40
@@ -298,50 +298,50 @@
sync_manager_infos["watchdog"] = "EC_WD_ENABLE"
sync_manager_infos["watchdog"] = "EC_WD_DISABLE"
sync_managers.append(sync_manager_infos)
for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
[(pdo, "Outputs") for pdo in device.getRxPdo()]):
pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
pdos_index.append(pdo_index)
excluded_list = pdo.getExclude()
if len(excluded_list) > 0:
exclusion_list = [pdo_index]
for excluded in excluded_list:
exclusion_list.append(ExtractHexDecValue(excluded.getcontent()))
exclusion_scope = exclusive_pdos.setdefault(tuple(exclusion_list), [])
"assigned": pdo.getSm() is not None
exclusion_scope.append(pdo_mapping_match)
index = ExtractHexDecValue(entry.getIndex().getcontent())
subindex = ExtractHexDecValue(entry.getSubIndex())
if slave_variables.get((index, subindex), None) is not None:
pdo_mapping_match["matching"] += 1
if pdo.getFixed() != True:
pdo_mapping_match["matching"] += \
module_extra_params["max_pdo_size"] - \
pdo_mapping_match["count"]
selected_pdos.append(pdo_index)
for exclusion_scope in exclusive_pdos.itervalues():
exclusion_scope.sort(ExclusionSortFunction)
@@ -349,22 +349,22 @@
if exclusion_scope[0]["matching"] > 0:
selected_pdos.append(exclusion_scope[0]["index"])
start_excluding_index = 1
- excluded_pdos.extend([pdo["index"]
- for pdo in exclusion_scope[start_excluding_index:]
+ excluded_pdos.extend([pdo["index"] + for pdo in exclusion_scope[start_excluding_index:] if PdoAssign or not pdo["assigned"]])
for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
[(pdo, "Outputs") for pdo in device.getRxPdo()]):
pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
if pdo_index in excluded_pdos:
pdo_needed = pdo_index in selected_pdos
index = ExtractHexDecValue(entry.getIndex().getcontent())
subindex = ExtractHexDecValue(entry.getSubIndex())
@@ -376,30 +376,30 @@
entry_infos.update(type_infos)
entries_infos.append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
entry_declaration = slave_variables.get((index, subindex), None)
if entry_declaration is not None and not entry_declaration["mapped"]:
- entry_infos.update(dict(zip(["var_type", "dir", "var_name", "no_decl", "extra_declarations"],
+ entry_infos.update(dict(zip(["var_type", "dir", "var_name", "no_decl", "extra_declarations"], entry_declaration["infos"])))
entry_declaration["mapped"] = True
entry_type = entry.getDataType().getcontent()
if entry_infos["var_type"] != entry_type:
message = _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
- if (self.Controler.GetSizeOfType(entry_infos["var_type"]) !=
+ if (self.Controler.GetSizeOfType(entry_infos["var_type"]) != self.Controler.GetSizeOfType(entry_type)):
raise ValueError, message
self.Controler.GetCTRoot().logger.write_warning(_("Warning: ") + message + "\n")
- if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or
+ if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or entry_infos["dir"] == "Q" and pdo_type != "Outputs"):
raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
ConfigureVariable(entry_infos, str_completion)
elif pdo_type == "Outputs" and entry.getDataType() is not None and device_coe is not None:
data_type = entry.getDataType().getcontent()
@@ -407,18 +407,18 @@
entry_infos["data_type"] = DATATYPECONVERSION.get(data_type)
entry_infos["var_type"] = data_type
entry_infos["real_var"] = "slave%(slave)d_%(index).4x_%(subindex).2x_default" % entry_infos
ConfigureVariable(entry_infos, str_completion)
str_completion["slaves_output_pdos_default_values_extraction"] += \
SLAVE_OUTPUT_PDO_DEFAULT_VALUE % entry_infos
for excluded in pdo.getExclude():
excluded_index = ExtractHexDecValue(excluded.getcontent())
if excluded_index not in excluded_pdos:
excluded_pdos.append(excluded_index)
for sm_idx, sync_manager in enumerate(sync_managers):
@@ -426,40 +426,40 @@
raise ValueError, _("No sync manager available for %s pdo!") % pdo_type
sync_managers[sm]["pdos_number"] += 1
sync_managers[sm]["pdos"].append(
"name": ExtractName(pdo.getName()),
"entries": entries_infos,
"entries_number": len(entries_infos),
"fixed": pdo.getFixed() == True})
if PdoConfig and PdoAssign:
- for category, min_index, max_index in [("Inputs", 0x1600, 0x1800),
+ for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), ("Outputs", 0x1a00, 0x1C00)]:
for sync_manager in sync_managers:
if sync_manager["name"] == category:
category_infos = dynamic_pdos.setdefault(category, {})
category_infos["sync_manager"] = sync_manager
- category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"]
+ category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"] if not pdo["fixed"] and pdo["type"] == category]
category_infos["current_index"] = min_index
category_infos["max_index"] = max_index
for (index, subindex), entry_declaration in slave_variables.iteritems():
if not entry_declaration["mapped"]:
entry = device_entries.get((index, subindex), None)
raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \
(index, subindex, type_infos["device_type"])
@@ -467,31 +467,31 @@
"bitlen": entry["BitSize"],
entry_infos.update(type_infos)
- entry_infos.update(dict(zip(["var_type", "dir", "var_name", "no_decl", "extra_declarations"],
+ entry_infos.update(dict(zip(["var_type", "dir", "var_name", "no_decl", "extra_declarations"], entry_declaration["infos"])))
entry_declaration["mapped"] = True
if entry_infos["var_type"] != entry["Type"]:
message = _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
- if (self.Controler.GetSizeOfType(entry_infos["var_type"]) !=
+ if (self.Controler.GetSizeOfType(entry_infos["var_type"]) != self.Controler.GetSizeOfType(entry["Type"])):
raise ValueError, message
self.Controler.GetCTRoot().logger.write_warning(message + "\n")
if entry_infos["dir"] == "I" and entry["PDOMapping"] in ["T", "RT"]:
elif entry_infos["dir"] == "Q" and entry["PDOMapping"] in ["R", "RT"]:
raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
if not dynamic_pdos.has_key(pdo_type):
raise ValueError, _("No Sync manager defined for %s!") % pdo_type
ConfigureVariable(entry_infos, str_completion)
if len(dynamic_pdos[pdo_type]["pdos"]) > 0:
pdo = dynamic_pdos[pdo_type]["pdos"][0]
elif module_extra_params["add_pdo"]:
@@ -500,12 +500,12 @@
if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]:
raise ValueError, _("No more free PDO index available for %s!") % pdo_type
pdos_index.append(dynamic_pdos[pdo_type]["current_index"])
pdo = {"slave": slave_idx,
"index": dynamic_pdos[pdo_type]["current_index"],
"name": "Dynamic PDO %d" % dynamic_pdos_number,
@@ -514,55 +514,55 @@
dynamic_pdos[pdo_type]["pdos"].append(pdo)
pdo["entries"].append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
if entry_infos["bitlen"] < module_extra_params["pdo_alignment"]:
pdo["entries"].append(" {0x0000, 0x00, %d}, /* None */" % (
module_extra_params["pdo_alignment"] - entry_infos["bitlen"]))
pdo["entries_number"] += 1
if pdo["entries_number"] == module_extra_params["max_pdo_size"]:
dynamic_pdos[pdo_type]["pdos"].pop(0)
for sync_manager_infos in sync_managers:
for pdo_infos in sync_manager_infos["pdos"]:
pdo_infos["offset"] = entry_offset
pdo_entries = pdo_infos["entries"]
pdos_infos["pdos_infos"].append(
- (" {0x%(index).4x, %(entries_number)d, " +
+ (" {0x%(index).4x, %(entries_number)d, " + "slave_%(slave)d_pdo_entries + %(offset)d}, /* %(name)s */") % pdo_infos)
entry_offset += len(pdo_entries)
pdos_infos["pdos_entries_infos"].extend(pdo_entries)
sync_manager_infos["offset"] = pdo_offset
pdo_offset_shift = sync_manager_infos["pdos_number"]
pdos_infos["pdos_sync_infos"].append(
- (" {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " +
+ (" {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " + ("slave_%(slave)d_pdos + %(offset)d" if pdo_offset_shift else "NULL") +
", %(watchdog)s},") % sync_manager_infos)
- pdo_offset += pdo_offset_shift
+ pdo_offset += pdo_offset_shift for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]:
pdos_infos[element] = "\n".join(pdos_infos[element])
str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos
for (index, subindex), entry_declaration in slave_variables.iteritems():
if not entry_declaration["mapped"]:
message = _("Entry index 0x%4.4x, subindex 0x%2.2x not mapped for device %s") % \
(index, subindex, type_infos["device_type"])
self.Controler.GetCTRoot().logger.write_warning(_("Warning: ") + message + "\n")
- for element in ["used_pdo_entry_offset_variables_declaration",
- "used_pdo_entry_configuration",
- "located_variables_declaration",
+ for element in ["used_pdo_entry_offset_variables_declaration", + "used_pdo_entry_configuration", + "located_variables_declaration", str_completion[element] = "\n".join(str_completion[element])
etherlabfile = open(filepath, 'w')
etherlabfile.write(plc_etherlab_code % str_completion)
--- a/etherlab/EthercatMaster.py Fri Sep 28 17:15:53 2018 +0300
+++ b/etherlab/EthercatMaster.py Fri Sep 28 17:20:11 2018 +0300
@@ -79,21 +79,21 @@
etherlab_ext_file = open(GetLocalPath("etherlab_ext.c"), 'r')
etherlab_ext_code = etherlab_ext_file.read()
etherlab_ext_file.close()
Gen_etherlabfile_path = os.path.join(buildpath, "etherlab_ext.c")
ethelabfile = open(Gen_etherlabfile_path,'w')
ethelabfile.write(etherlab_ext_code)
runtimefile_path = os.path.join(os.path.split(__file__)[0], "runtime_etherlab.py")
- return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "",
+ return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", ("runtime_etherlab.py", file(GetLocalPath("runtime_etherlab.py"))))
#--------------------------------------------------
#--------------------------------------------------
-EtherCATConfigParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATConfig.xsd"))
+EtherCATConfigParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATConfig.xsd")) if x["Index"] == y["Index"]:
@@ -102,7 +102,7 @@
cls = EtherCATConfigParser.GetElementClass("Slave", "Config")
slave_info = self.getInfo()
return {"device_type": slave_info.getName(),
@@ -118,7 +118,7 @@
slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"]))
slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"]))
setattr(cls, "setType", setType)
def getInitCmds(self, create_default=False):
Mailbox = self.getMailbox()
@@ -140,7 +140,7 @@
InitCmds = CoE.getInitCmds()
setattr(cls, "getInitCmds", getInitCmds)
def getStartupCommands(self):
pos = self.getInfo().getPhysAddr()
InitCmds = self.getInitCmds()
@@ -161,7 +161,7 @@
commands.sort(sort_commands)
setattr(cls, "getStartupCommands", getStartupCommands)
def appendStartupCommand(self, command_infos):
InitCmds = self.getInitCmds(True)
command = EtherCATConfigParser.CreateElement("InitCmd", "InitCmds", 1)
@@ -172,7 +172,7 @@
command.setComment(command_infos["Description"])
return len(InitCmds.getInitCmd()) - 1
setattr(cls, "appendStartupCommand", appendStartupCommand)
def setStartupCommand(self, command_infos):
InitCmds = self.getInitCmds()
@@ -184,7 +184,7 @@
command.setData(command_infos["Value"])
command.setComment(command_infos["Description"])
setattr(cls, "setStartupCommand", setStartupCommand)
def removeStartupCommand(self, command_idx):
InitCmds = self.getInitCmds()
@@ -218,7 +218,7 @@
-ProcessVariablesParser = GenerateParserFromXSDstring(ProcessVariablesXSD)
+ProcessVariablesParser = GenerateParserFromXSDstring(ProcessVariablesXSD) @@ -226,7 +226,7 @@
CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave"))
EditorType = MasterEditor
config_filepath = self.ConfigFileName()
@@ -241,14 +241,14 @@
self.GetCTRoot().logger.write_error(
- _("Couldn't load %s network configuration file.") % CTNName)
+ _("Couldn't load %s network configuration file.") % CTNName) self.Config = EtherCATConfigParser.CreateElement("EtherCATConfig")
process_filepath = self.ProcessVariablesFileName()
self.ProcessVariables = None
@@ -262,32 +262,32 @@
self.GetCTRoot().logger.write_error(
- _("Couldn't load %s network process variables file.") % CTNName)
+ _("Couldn't load %s network process variables file.") % CTNName) if self.ProcessVariables is None:
self.ProcessVariables = ProcessVariablesParser.CreateElement("ProcessVariables")
if config_is_saved and process_is_saved:
# ----------- call ethercat mng. function --------------
self.CommonMethod = _CommonSlave(self)
def GetContextualMenuItems(self):
return [("Add Ethercat Slave", "Add Ethercat Slave to Master", self.OnAddEthercatSlave)]
def OnAddEthercatSlave(self, event):
app_frame = self.GetCTRoot().AppFrame
- dialog = BrowseValuesLibraryDialog(app_frame,
+ dialog = BrowseValuesLibraryDialog(app_frame, "Ethercat Slave Type", self.GetSlaveTypesLibrary())
if dialog.ShowModal() == wx.ID_OK:
type_infos = dialog.GetValueInfos()
@@ -303,7 +303,7 @@
app_frame._Refresh(TITLE, FILEMENU, PROJECTTREE)
def ExtractHexDecValue(self, value):
return ExtractHexDecValue(value)
@@ -312,10 +312,10 @@
def ConfigFileName(self):
return os.path.join(self.CTNPath(), "config.xml")
def ProcessVariablesFileName(self):
return os.path.join(self.CTNPath(), "process_variables.xml")
def FilterSlave(self, slave, vendor=None, slave_pos=None, slave_profile=None):
if slave_pos is not None and slave.getInfo().getPhysAddr() != slave_pos:
@@ -355,7 +355,7 @@
commands.append((slave.getInfo().getPhysAddr(), slave.getStartupCommands()))
return reduce(lambda x, y: x + y[1], commands, [])
def AppendStartupCommand(self, command_infos):
slave = self.GetSlave(command_infos["Position"])
@@ -363,20 +363,20 @@
def SetStartupCommandInfos(self, command_infos):
slave = self.GetSlave(command_infos["Position"])
slave.setStartupCommand(command_infos)
def RemoveStartupCommand(self, slave_pos, command_idx, buffer=True):
slave = self.GetSlave(slave_pos)
slave.removeStartupCommand(command_idx)
def SetProcessVariables(self, variables):
@@ -406,7 +406,7 @@
self.ProcessVariables.setvariable(vars)
def GetProcessVariables(self):
@@ -431,19 +431,19 @@
app_frame = self.GetCTRoot().AppFrame
if len(self.Children) > 0:
- dialog = wx.MessageDialog(app_frame,
- _("The current network configuration will be deleted.\nDo you want to continue?"),
+ dialog = wx.MessageDialog(app_frame, + _("The current network configuration will be deleted.\nDo you want to continue?"), wx.YES_NO|wx.ICON_QUESTION)
execute = dialog.ShowModal() == wx.ID_YES
error, returnVal = self.RemoteExec(SCAN_COMMAND, returnVal = None)
@@ -453,7 +453,7 @@
elif returnVal is not None:
for child in self.IECSortedChildren():
self._doRemoveChild(child)
"vendor": slave["vendor_id"],
@@ -470,10 +470,10 @@
self.SetSlaveAlias(slave["idx"], slave["alias"])
type_infos["device_type"] = device.getType().getcontent()
self.SetSlaveType(slave["idx"], type_infos)
app_frame.RefreshProjectTree()
def CTNAddChild(self, CTNName, CTNType, IEC_Channel=0):
Create the confnodes that may be added as child to this node self
@@ -481,7 +481,7 @@
@param CTNName: string for the name of the confnode instance
newConfNodeOpj = ConfigTreeNode.CTNAddChild(self, CTNName, CTNType, IEC_Channel)
slave = self.GetSlave(newConfNodeOpj.BaseParams.getIEC_Channel())
slave = EtherCATConfigParser.CreateElement("Slave", "Config")
@@ -492,7 +492,7 @@
slave_infos.setAutoIncAddr(0)
def _doRemoveChild(self, CTNInstance):
@@ -523,33 +523,33 @@
if self._View is not None:
self._View.RefreshBuffer()
def GetSlaveAlias(self, slave_pos):
slave = self.GetSlave(slave_pos)
slave_info = slave.getInfo()
return slave_info.getAutoIncAddr()
def SetSlaveAlias(self, slave_pos, alias):
slave = self.GetSlave(slave_pos)
slave_info = slave.getInfo()
slave_info.setAutoIncAddr(alias)
def GetSlaveType(self, slave_pos):
slave = self.GetSlave(slave_pos)
def SetSlaveType(self, slave_pos, type_infos):
slave = self.GetSlave(slave_pos)
slave.setType(type_infos)
def GetSlaveInfos(self, slave_pos):
slave = self.GetSlave(slave_pos)
@@ -562,7 +562,7 @@
"entries": self.GetSlaveVariables(device)})
def GetSlaveVariables(self, slave_pos=None, limits=None, device=None):
if device is None and slave_pos is not None:
slave = self.GetSlave(slave_pos)
@@ -592,7 +592,7 @@
def GetSlaveVariableDataType(self, slave_pos, index, subindex):
slave = self.GetSlave(slave_pos)
@@ -603,7 +603,7 @@
if entry_infos is not None:
return entry_infos["Type"]
def GetNodesVariables(self, vendor=None, slave_pos=None, slave_profile=None, limits=None):
for slave_position in self.GetSlaves():
@@ -618,22 +618,22 @@
entries.extend(self.GetSlaveVariables(slave_position, limits, device))
def GetModuleInfos(self, type_infos):
return self.CTNParent.GetModuleInfos(type_infos)
def GetSlaveTypesLibrary(self, profile_filter=None):
return self.CTNParent.GetModulesLibrary(profile_filter)
def GetLibraryVendors(self):
return self.CTNParent.GetVendors()
def GetDeviceLocationTree(self, slave_pos, current_location, device_name):
slave = self.GetSlave(slave_pos)
type_infos = slave.getType()
device, module_extra_params = self.GetModuleInfos(type_infos)
@@ -644,7 +644,7 @@
sync_managers.append(LOCATION_VAR_OUTPUT)
sync_managers.append(LOCATION_VAR_INPUT)
entries = device.GetEntriesList().items()
for (index, subindex), entry in entries:
@@ -655,44 +655,44 @@
if var_class == LOCATION_VAR_INPUT:
vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]),
"IEC_type": entry["Type"],
"var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex),
- "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location +
+ "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location +
def CTNTestModified(self):
- return self.ChangesToSave or not self.ModelIsSaved()
+ return self.ChangesToSave or not self.ModelIsSaved() def OnCTNSave(self, from_project_path=None):
config_filepath = self.ConfigFileName()
config_xmlfile = open(config_filepath,"w")
config_xmlfile.write(etree.tostring(
process_filepath = self.ProcessVariablesFileName()
process_xmlfile = open(process_filepath,"w")
process_xmlfile.write(etree.tostring(
self.Buffer.CurrentSaved()
@@ -703,13 +703,13 @@
current_location = self.GetCurrentLocation()
# define a unique name for the generated C file
location_str = "_".join(map(lambda x:str(x), current_location))
Gen_Ethercatfile_path = os.path.join(buildpath, "ethercat_%s.c"%location_str)
self.FileGenerator = _EthercatCFileGenerator(self)
LocationCFilesAndCFLAGS, LDFLAGS, extra_files = ConfigTreeNode._Generate_C(self, buildpath, locations)
for idx, variable in enumerate(self.ProcessVariables.getvariable()):
@@ -734,42 +734,42 @@
name = self.GetProcessVariableName(location, var_type)
self.FileGenerator.DeclareVariable(
pos, index, subindex, var_type, "Q", name, True)
self.FileGenerator.GenerateCFile(Gen_Ethercatfile_path, location_str, self.BaseParams.getIEC_Channel())
- LocationCFilesAndCFLAGS.insert(0,
- [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))],
+ LocationCFilesAndCFLAGS.insert(0, + [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))], LDFLAGS.append("-lethercat_rtdm -lrtdm")
return LocationCFilesAndCFLAGS, LDFLAGS, extra_files
{"bitmap" : "ScanNetwork",
- "name" : _("Scan Network"),
+ "name" : _("Scan Network"), "tooltip" : _("Scan Network"),
"method" : "_ScanNetwork"},
def CTNGenerate_C(self, buildpath, locations):
current_location = self.GetCurrentLocation()
slaves = self.GetSlaves()
slave = self.GetSlave(slave_pos)
self.FileGenerator.DeclareSlave(slave_pos, slave)
for location in locations:
loc = location["LOC"][len(current_location):]
if slave_pos in slaves and len(loc) == 3 and location["DIR"] != "M":
self.FileGenerator.DeclareVariable(
slave_pos, loc[1], loc[2], location["IEC_TYPE"], location["DIR"], location["NAME"])
#-------------------------------------------------------------------------------
# Current Buffering Management Functions
#-------------------------------------------------------------------------------
@@ -779,18 +779,18 @@
def CreateBuffer(self, saved):
self.Buffer = UndoBuffer(
- (EtherCATConfigParser.Dumps(self.Config),
- ProcessVariablesParser.Dumps(self.ProcessVariables)),
+ (EtherCATConfigParser.Dumps(self.Config), + ProcessVariablesParser.Dumps(self.ProcessVariables)),
- (EtherCATConfigParser.Dumps(self.Config),
+ (EtherCATConfigParser.Dumps(self.Config), ProcessVariablesParser.Dumps(self.ProcessVariables)))
if self.Buffer is not None:
return self.Buffer.IsCurrentSaved()
@@ -801,14 +801,13 @@
config, process_variables = self.Buffer.Previous()
self.Config = EtherCATConfigParser.Loads(config)
self.ProcessVariables = ProcessVariablesParser.Loads(process_variables)
config, process_variables = self.Buffer.Next()
self.Config = EtherCATConfigParser.Loads(config)
self.ProcessVariables = ProcessVariablesParser.Loads(process_variables)
def GetBufferState(self):
first = self.Buffer.IsFirst()
last = self.Buffer.IsLast()
return not first, not last