--- a/etherlab/CommonEtherCATFunction.py Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/CommonEtherCATFunction.py Wed Nov 20 16:57:15 2019 +0100
@@ -10,8 +10,9 @@
-mailbox_protocols = ["AoE", "EoE", "CoE", "FoE", "SoE", "VoE"]
+from lxml import objectify def ExtractHexDecValue(value):
@@ -77,18 +78,21 @@
-# ethercat sdos -p (slave position)
+# ethercat upload -p (slave position) -t (type) (index) (sub index) -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")
+for sdo_token in input_data.split(","): + sdo_token = sdo_token.strip() + type, idx, subidx = sdo_token.split(" ") + command_string = "ethercat upload -p " + str(slave_pos) + " -t " + type + " " + idx + " " + subidx + result = commands.getoutput(command_string) + sdo_data.append(result) # ethercat download -p (slave position) (main index) (sub index) (value)
@@ -112,6 +116,25 @@
+# ethercat reg_read -p (slave position) (address) (size) +reg_info_list = reg_info_str.split("|") +for slave_idx in range(slave_num): + for reg_info in reg_info_list: + param = reg_info.split(",") + result = commands.getoutput("ethercat reg_read -p " + output.append(str(slave_idx) + "," + param[addr] + "," + result) # ethercat sii_write -p (slave position) - (contents)
@@ -136,6 +159,13 @@
+result = commands.getoutput("ethercat pdos -p 0") #--------------------------------------------------
# Common Method For EtherCAT Management
#--------------------------------------------------
@@ -144,12 +174,38 @@
# ----- Data Structure for ethercat management ----
+ # SDO base data type for Ethercatmaster + "bool": ["BOOLEAN", "BOOL", "BIT"], + "uint8": ["BYTE", "USINT", "BIT1", "BIT2", "BIT3", "BIT4", "BIT5", "BIT6", + "BIT7", "BIT8", "BITARR8", "UNSIGNED8"], + "uint16": ["BITARR16", "UNSIGNED16", "UINT"], + "uint32": ["BITARR32", "UNSIGNED24", "UINT24", "UNSIGNED32", "UDINT"], + "uint64": ["UNSINED40", "UINT40", "UNSIGNED48", "UINT48", "UNSIGNED56", + "UINT56", "UNSIGNED64", "ULINT"], + "int8": ["INTEGER8", "SINT"], + "int16": ["INTEGER16", "INT"], + "int32": ["INTEGER24", "INT24", "INTEGER32", "DINT"], + "int64": ["INTEGER40", "INT40", "INTEGER48", "INT48", "INTEGER56", "INT56", + "float": ["REAL", "REAL32"], + "double": ["LREAL", "REAL64"], + "string": ["VISUBLE_STRING", "STRING(n)"], + "octet_string": ["OCTET_STRING"], + "unicode_string": ["UNICODE_STRING"] DatatypeDescription, CommunicationObject, ManufacturerSpecific, \
ProfileSpecific, Reserved, AllSDOData = range(6)
- # store the execution result of "ethercat sdos" command into SaveSDOData.
+ # SDO data informations: index, sub-index, type, bit size, category-name + # defalut value of SDO data in XML # Flags for checking "write" permission of OD entries
@@ -180,7 +236,7 @@
self.Controler = controler
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
@@ -189,7 +245,6 @@
Execute "ethercat master" command and parse the execution result
# exectute "ethercat master" command
error, return_val = self.Controler.RemoteExec(MASTER_STATE, return_val = None)
@@ -226,20 +281,11 @@
error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val = None)
self.SlaveState = return_val
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
- def GetSlaveSDOFromSlave(self):
- 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,8 +294,11 @@
@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)
+ valid_type = self.GetValidDataType(data_type) + error, return_val = self.Controler.RemoteExec(SDO_DOWNLOAD%(valid_type, self.Controler.GetSlavePos(), idx, sub_idx, value), return_val = None) def BackupSDODataSet(self):
@@ -268,14 +317,318 @@
Clear the specified SDO entry information.
- self.SaveSDOData.append([])
+ self.SDOVariables.append([]) + def GetAllSDOValuesFromSlave(self): + Get SDO values of All SDO entries. + @return return_val: list of result of "SDO_UPLOAD" + alldata_idx = len(self.SDOVariables) + for category in self.SDOVariables: + # for avoid redundant repetition + if counter == alldata_idx: + valid_type = self.GetValidDataType(entry["type"]) + for_command_string = "%s %s %s ," % \ + (valid_type, entry["idx"], entry["subIdx"]) + entry_infos += for_command_string + error, return_val = self.Controler.RemoteExec(SDO_UPLOAD%(entry_infos, self.Controler.GetSlavePos()), return_val = None) + def GetSDOValuesFromSlave(self, entries_info): + Get SDO values of some SDO entries. + @param entries_info: dictionary of SDO entries that is wanted to know the value. + @return return_val: list of result of "SDO_UPLOAD" + entries_info_list = entries_info.items() + entries_info_list.sort() + for (idx, subIdx), entry in entries_info_list: + valid_type = self.GetValidDataType(entry["type"]) + for_command_string = "%s %s %s ," % \ + (valid_type, str(idx), str(subIdx)) + entry_infos += for_command_string + error, return_val = self.Controler.RemoteExec(SDO_UPLOAD%(entry_infos, self.Controler.GetSlavePos()), return_val = None) + def ExtractObjects(self): + Extract object type items from imported ESI xml. + And they are stuctured as dictionary. + @return objects: dictionary of objects + slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) + type_infos = slave.getType() + device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) + if device is not None : + for dictionary in device.GetProfileDictionaries(): + for object in dictionary.getObjects().getObject(): + object_index = ExtractHexDecValue(object.getIndex().getcontent()) + objects[(object_index)] = object + def ExtractAllDataTypes(self): + Extract all data types from imported ESI xml. + @return dataTypes: dictionary of datatypes + slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) + type_infos = slave.getType() + device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) + for dictionary in device.GetProfileDictionaries(): + datatypes = dictionary.getDataTypes() + if datatypes is not None: + for datatype in datatypes.getDataType(): + dataTypes[datatype.getName()] = datatype + def IsBaseDataType(self, datatype): + Check if the datatype is a base data type. + @return baseTypeFlag: true if datatype is a base data type, unless false + for baseDataTypeList in self.BaseDataTypes.values(): + if datatype in baseDataTypeList: + def GetBaseDataType(self, datatype): + Get a base data type corresponding the datatype. + @param datatype: Some data type (string format) + if self.IsBaseDataType(datatype): + elif not datatype.find("STRING") == -1: + datatypes = self.ExtractAllDataTypes() + base_datatype = datatypes[datatype].getBaseType() + return self.GetBaseDataType(base_datatype) + def GetValidDataType(self, datatype): + Convert the datatype into a data type that is possible to download/upload + in etherlab master stack. + @param datatype: Some data type (string format) + @return base_type: vaild data type + base_type = self.GetBaseDataType(datatype) + if re.match("STRING\([0-9]*\)", datatype) is not None: + for key, value in self.BaseDataTypes.items(): + def GetAllEntriesList(self): + Get All entries information that includes index, sub-index, name, + type, bit size, PDO mapping, and default value. + @return self.entries: dictionary of entry + slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) + type_infos = slave.getType() + device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) + self.entries = device.GetEntriesList() + datatypes = self.ExtractAllDataTypes() + objects = self.ExtractObjects() + entries_list = self.entries.items() + for (index, subidx), entry in entries_list: + # entry_* is string type + entry_type = entry["Type"] + entry_index = entry["Index"] + object_info = objects[index].getInfo() + if object_info is not None: + obj_content = object_info.getcontent() + typeinfo = datatypes.get(entry_type, None) + bitsize = typeinfo.getBitSize() + type_content = typeinfo.getcontent() + if type_content is not None and type_content["name"] == "ArrayInfo": + for arrayinfo in type_content["value"]: + element_num = arrayinfo.getElements() + first_subidx = arrayinfo.getLBound() + for offset in range(element_num): + new_subidx = int(first_subidx) + offset + entry_subidx = hex(new_subidx) + if obj_content["value"][new_subidx]["name"] == "SubItem": + subitem = obj_content["value"][new_subidx]["value"] + subname = subitem[new_subidx].getName() + if subname is not None: + entry_name = "%s - %s" % \ + (ExtractName(objects[index].getName()), subname) + entry_name = ExtractName(objects[index].getName()) + self.entries[(index, new_subidx)] = { + "SubIndex": entry_subidx, + "Type": typeinfo.getBaseType(), + "BitSize": str(bitsize/element_num), + "Access": entry["Access"], + "PDOMapping": entry["PDOMapping"]} + value_info = subitem[new_subidx].getInfo().getcontent()\ + ["value"][0]["value"][0] + self.AppendDefaultValue(index, new_subidx, value_info) + value_info = subitem[subidx].getInfo().getcontent()\ + ["value"][0]["value"][0] + self.AppendDefaultValue(index, subidx, value_info) + elif type_content is not None and type_content["name"] == "EnumInfo": + self.entries[(index, subidx)]["EnumInfo"] = {} + for enuminfo in type_content["value"]: + text = enuminfo.getText() + enum = enuminfo.getEnum() + self.entries[(index, subidx)]["EnumInfo"][str(enum)] = text + self.entries[(index, subidx)]["DefaultValue"] = "0x00" + if obj_content["value"][tmp_subidx]["name"] == "SubItem": + sub_name = entry["Name"].split(" - ")[1] + for num in range(len(obj_content["value"])): + obj_content["value"][num]["value"][num].getName(): + subitem_content = obj_content["value"][tmp_subidx]\ + value_info = subitem_content.getInfo().getcontent()\ + ["value"][0]["value"][0] + obj_content["value"][tmp_subidx]["value"][tmp_subidx] + self.AppendDefaultValue(index, subidx, value_info) + def AppendDefaultValue(self, index, subidx, value_info=None): + Get the default value from the ESI xml + @param index: entry index + @param subidx: entry sub index + @param value_info: dictionary of infomation about default value + # there is not default value. + raw_value = value_info["value"] + # default value is hex binary type. + if value_info["name"] == "DefaultData": + raw_value_bit = list(hex(raw_value).split("0x")[1]) + datatype = self.GetValidDataType(self.entries[(index, subidx)]["Type"]) + if datatype is "string" or datatype is "octet_string": + if "L" in raw_value_bit: + raw_value_bit.remove("L") + default_value = "".join(raw_value_bit).decode("hex") + elif datatype is "unicode_string": + default_value = "".join(raw_value_bit).decode("hex").\ + bit_num = len(raw_value_bit) + raw_value_bit.insert(0, "0") + # little endian -> big endian + for num in range(bit_num): + default_value_bit.insert(0, raw_value_bit[num]) + default_value_bit.insert(1, raw_value_bit[num+1]) + default_value = "0x%s" % "".join(default_value_bit) + # default value is string type. + # this case is not tested yet. + elif value_info["name"] == "DefaultString": + default_value = raw_value + # default value is Hex or Dec type. + elif value_info["name"] == "DefaultValue": + default_value = "0x" + hex(ExtractHexDecValue(raw_value)) + self.entries[(index, subidx)]["DefaultValue"] = default_value #-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def RequestPDOInfo(self):
- Load slave information from RootClass (XML data) and parse the information (calling SlavePDOData() method).
+ 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())
@@ -292,7 +645,7 @@
def SavePDOData(self, device):
Parse PDO data and store the results in TXPDOCategory and RXPDOCategory
- Tx(Rx)PDOCategory : index, name, entry number
+ Tx(Rx)PDOCategory : index, name, entry number, exclude list, Sm Tx(Rx)Info : entry index, sub index, name, length, type
@param device : Slave information extracted from ESI XML file
@@ -302,10 +655,17 @@
pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
pdo_name = ExtractName(pdo.getName())
+ excludes = pdo.getExclude() + for exclude in excludes: + exclude_list.append(ExtractHexDecValue(exclude.getcontent())) # Initialize entry number count
# Save index and subindex
@@ -317,13 +677,14 @@
"name" : ExtractName(entry.getName()),
- "bitlen" : entry.getBitLen(),
- "type" : entry.getDataType().getcontent()
+ "bitlen" : entry.getBitLen()} + if entry.getDataType() is not None: + entry_infos["type"] = entry.getDataType().getcontent() 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, "sm" : Sm, + "number_of_entry" : count, "exclude_list" : exclude_list} self.TxPDOCategory.append(categorys)
@@ -332,7 +693,14 @@
pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
pdo_name = ExtractName(pdo.getName())
+ excludes = pdo.getExclude() + for exclude in excludes: + exclude_list.append(ExtractHexDecValue(exclude.getcontent())) # Initialize entry number count
@@ -347,13 +715,14 @@
"name" : ExtractName(entry.getName()),
- "bitlen" : str(entry.getBitLen()),
- "type" : entry.getDataType().getcontent()
+ "bitlen" : entry.getBitLen()} + if entry.getDataType() is not None: + entry_infos["type"] = entry.getDataType().getcontent() self.RxPDOInfo.append(entry_infos)
- categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}
+ categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "sm" : Sm, + "number_of_entry" : count, "exclude_list" : exclude_list} self.RxPDOCategory.append(categorys)
def GetTxPDOCategory(self):
@@ -392,10 +761,10 @@
Initialize PDO management data structure.
- self.TxPDOCategorys = []
- self.RxPDOCategorys = []
+ self.TxPDOCategory = [] + self.RxPDOCategory = [] #-------------------------------------------------------------------------------
@@ -460,15 +829,48 @@
type_infos = slave.getType()
device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+ #from decimal import Decimal # 'device' represents current slave device selected by user
- for eeprom_element in device.getEeprom().getcontent():
+ # dir() method print available method list + #print dir(device.getEeprom().getchildren()[1]) + # success get subitem second object + #print objectify.fromstring(device.getEeprom().getchildren()[1].tostring()).text + for eeprom_element in device.getEeprom().getchildren(): + # get EEPROM size; <Device>-<Eeprom>-<ByteSize> + if eeprom_element.tag == "ByteSize": + smartview_infos["eeprom_size"] = objectify.fromstring(eeprom_element.tostring()).text + elif eeprom_element.tag == "ConfigData": + # ConfigData Field Datatype??? + #print type(objectify.fromstring(eeprom_element.tostring()).text) + configData_data = self.DecimalToHex(objectify.fromstring(eeprom_element.tostring()).text) + # get PDI type; <Device>-<Eeprom>-<ConfigData> address 0x00 + smartview_infos["pdi_type"] = int(configData_data[0:2], 16) + # get state of device emulation; <Device>-<Eeprom>-<ConfigData> address 0x01 + if len(configData_data) > 3 and "{:0>8b}".format(int(configData_data[2:4], 16))[7] == '1': + smartview_infos["device_emulation"] = "True" + elif eeprom_element.tag == "BootStrap": + bootstrap_data = "{:0>16x}".format(int(objectify.fromstring(eeprom_element.tostring()).text, 16)) + # get bootstrap configuration; <Device>-<Eeprom>-<BootStrap> + 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)) + for eeprom_element in device.getEeprom().getcontent()["value"]: # get EEPROM size; <Device>-<Eeprom>-<ByteSize>
if eeprom_element["name"] == "ByteSize":
- smartview_infos["eeprom_size"] = eeprom_element
+ smartview_infos["eeprom_size"] = eeprom_element["value"] elif eeprom_element["name"] == "ConfigData":
- configData_data = self.DecimalToHex(eeprom_element)
+ configData_data = self.DecimalToHex(eeprom_element["value"]) # get PDI type; <Device>-<Eeprom>-<ConfigData> address 0x00
smartview_infos["pdi_type"] = int(configData_data[0:2], 16)
# get state of device emulation; <Device>-<Eeprom>-<ConfigData> address 0x01
@@ -476,20 +878,19 @@
smartview_infos["device_emulation"] = "True"
elif eeprom_element["name"] == "BootStrap":
- bootstrap_data = "{:0>16x}".format(eeprom_element)
+ bootstrap_data = "{:0>16x}".format(eeprom_element["value"]) # get bootstrap configuration; <Device>-<Eeprom>-<BootStrap>
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>
- mb = device.getMailbox()
- for mailbox_protocol in mailbox_protocols:
- if getattr(mb,"get%s"%mailbox_protocol)() is not None:
- smartview_infos["supported_mailbox"] += "%s, "%mailbox_protocol
+ for mailbox_protocol in ["VoE", "SoE", "FoE", "CoE", "EoE", "AoE"]: + if device.getMailbox() is not None and eval("device.getMailbox().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>
@@ -504,24 +905,24 @@
# get device identity from <Device>-<Type>
- # vendor ID; by default, pre-defined value in self.ModulesLibrary
- # if device type in 'vendor' item equals to actual slave device type, set 'vendor_id' to vendor ID.
+ # vendor ID; by default, pre-defined value in self.ModulesLibrary + # if device type in 'vendor' item equals to actual slave device type, set 'vendor_id' to vendor ID. for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
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))
@@ -537,14 +938,14 @@
@param decnum : decimal value
@return hex_data : hexadecimal representation of input value in decimal
+ value = "%x" % int(decnum, 16) hex_len = (value_len / 2) * 2 + 2
- hex_data = ("{:0>"+str(hex_len)+"x}").format(decnum)
+ hex_data = ("{:0>"+str(hex_len)+"x}").format(int(decnum, 16)) @@ -668,12 +1069,13 @@
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)
+ # Modify by jblee because of update IDE module (minidom -> lxml) + for eeprom_element in device.getEeprom().getchildren(): + if eeprom_element.tag == "ConfigData": + data = self.DecimalToHex(objectify.fromstring(eeprom_element.tostring()).text) eeprom += self.GenerateEEPROMList(data, 0, 28)
# calculate CRC for EEPROM offset 0x000e-0x000f
@@ -732,19 +1134,20 @@
# get BootStrap for EEPROM offset 0x0028-0x002e; <Device>-<Eeprom>-<BootStrap>
- for eeprom_element in device.getEeprom().getcontent():
- if eeprom_element["name"] == "BootStrap":
- data = "{:0>16x}".format(eeprom_element)
+ # Modify by jblee because of update IDE module (minidom -> lxml) + for eeprom_element in device.getEeprom().getchildren(): + if eeprom_element.tag == "BootStrap": + data = "{:0>16x}".format(int(objectify.fromstring(eeprom_element.tostring()).text, 16)) eeprom += self.GenerateEEPROMList(data, 0, 16)
# get Standard Mailbox for EEPROM offset 0x0030-0x0037; <Device>-<sm>
+ standard_receive_mailbox_offset = None + standard_receive_mailbox_size = None standard_send_mailbox_offset = None
standard_send_mailbox_size = None
- standard_receive_mailbox_offset = None
- standard_receive_mailbox_size = None
for sm_element in device.getSm():
if sm_element.getcontent() == "MBoxOut":
standard_receive_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress()))
@@ -780,10 +1183,14 @@
# get supported mailbox protocols for EEPROM offset 0x0038-0x0039;
- mb = device.getMailbox()
- for bit,mbprot in enumerate(mailbox_protocols):
- if getattr(mb,"get%s"%mbprot)() is not None:
+ if device.getMailbox() is not None: + for mbox, bit in [(device.getMailbox().getAoE(), 0), + (device.getMailbox().getEoE(), 1), + (device.getMailbox().getCoE(), 2), + (device.getMailbox().getFoE(), 3), + (device.getMailbox().getSoE(), 4), + (device.getMailbox().getVoE(), 5)]: data = "{:0>4x}".format(data)
@@ -794,12 +1201,13 @@
# get EEPROM size for EEPROM offset 0x007c-0x007d;
+ # Modify by jblee because of update IDE module (minidom -> lxml) - for eeprom_element in device.getEeprom().getcontent():
- if eeprom_element["name"] == "ByteSize":
- eeprom_size = int(str(eeprom_element))
- data = "{:0>4x}".format(int(eeprom_element)/1024*8-1)
+ for eeprom_element in device.getEeprom().getchildren(): + if eeprom_element.tag == "ByteSize": + eeprom_size = int(objectify.fromstring(eeprom_element.tostring()).text) + data = "{:0>4x}".format(eeprom_size/1024*8-1) @@ -808,7 +1216,7 @@
# Version for EEPROM 0x007e-0x007f;
- # According to "EtherCAT Slave Device Description(V0.3.0)"
+ # According to "EtherCAT Slave Device Description(V0.3.0)" @@ -877,14 +1285,16 @@
- # element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type>
- # vendor_specific_data : vendor specific data (binary type)
+ # element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type> + # vendor_specific_data : vendor specific data (binary type) + # Modify by jblee because of update IDE module (minidom -> lxml) vendor_specific_data = ""
- # vendor_spec_strings : list of vendor specific "strings" for preventing duplicated strings
+ # vendor_spec_strings : list of vendor specific "strings" for preventing duplicated strings for element in device.getType().getcontent():
- if data is not "" and type(data) == unicode:
+ # retrun type change unicode -> str + if data is not "" and type(data) == str: for vendor_spec_string in vendor_spec_strings:
if data == vendor_spec_string:
self.OrderIdx = vendor_spec_strings.index(data)+1
@@ -901,9 +1311,11 @@
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
- # element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType>
+ # element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType> + # Modify by jblee because of update IDE module (minidom -> lxml) data = device.getGroupType()
- if data is not None and type(data) == unicode:
+ # retrun type change unicode -> str + if data is not None and type(data) == str: for vendor_spec_string in vendor_spec_strings:
if data == vendor_spec_string:
self.GroupIdx = vendor_spec_strings.index(data)+1
@@ -920,7 +1332,7 @@
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
- # element2-2; <EtherCATInfo>-<Groups>-<Group>-<Type>
+ # 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():
@@ -945,8 +1357,30 @@
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+ # element3; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Name(LcId is "1033")> + # Modify by jblee because of update IDE module (minidom -> lxml) + if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: + LcId_obj = self.Controler.CTNParent.CTNParent.ModulesLibrary.LcId_data + data = LcId_obj.getcontent() + # retrun type change unicode -> str + if data is not "" and type(data) == str: + for vendor_spec_string in vendor_spec_strings: + if data == vendor_spec_string: + if groupnameflag is False: + self.Strings.append(data) + vendor_spec_strings.append(data) + vendor_specific_data += "{:0>2x}".format(len(data)) + for character in range(len(data)): + vendor_specific_data += "{:0>2x}".format(ord(data[character])) - # element3; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Name(LcId is "1033")>
+ # 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():
for group_type, group_etc in vendor["groups"].iteritems():
@@ -966,13 +1400,17 @@
vendor_specific_data += "{:0>2x}".format(len(data))
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"?)>
+ # element4; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Name(LcId is "1033" or "1"?)> + # Modify by jblee because of update IDE module (minidom -> lxml) for element in device.getName():
if element.getLcId() == 1 or element.getLcId()==1033:
data = element.getcontent()
- if data is not "" and type(data) == unicode:
+ # retrun type change unicode -> str + if data is not "" and type(data) == str: for vendor_spec_string in vendor_spec_strings:
if data == vendor_spec_string:
self.NameIdx = vendor_spec_strings.index(data)+1
@@ -987,12 +1425,18 @@
vendor_specific_data += "{:0>2x}".format(len(data))
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
- # element5-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Image16x14>
+ # element5-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Image16x14> if device.getcontent() is not None:
- data = device.getcontent()
- if data is not None and type(data) == unicode:
+ #data = device.getcontent()["value"] + # xml module change minidom -> lxml + # use lxml objectify module + data = objectify.fromstring(device.getcontent().tostring()).text + # retrun type change unicode -> str + if data is not None and type(data) == str: for vendor_spec_string in vendor_spec_strings:
if data == vendor_spec_string:
self.ImgIdx = vendor_spec_strings.index(data)+1
@@ -1007,16 +1451,43 @@
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>
+ # element5-2; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Image16x14> + # Modify by jblee because of update IDE module (minidom -> lxml) + if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: + data_obj = self.Controler.CTNParent.CTNParent.ModulesLibrary.Image16x14_data + # retrun type change unicode -> str + if data is not None and type(data) == str: + for vendor_spec_string in vendor_spec_strings: + if data == vendor_spec_string: + self.ImgIdx = vendor_spec_strings.index(data)+1 + self.Strings.append(data) + vendor_spec_strings.append(data) + 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:
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 data is not None and type(data) == unicode:
+ data = group_etc["value"] + # retrun type change unicode -> str + if data is not None and type(data) == str: for vendor_spec_string in vendor_spec_strings:
if data == vendor_spec_string:
self.ImgIdx = vendor_spec_strings.index(data)+1
@@ -1031,10 +1502,11 @@
vendor_specific_data += "{:0>2x}".format(len(data))
for character in range(len(data)):
vendor_specific_data += "{:0>2x}".format(ord(data[character]))
- # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Dc>-<OpMode>-<Name>
+ # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Dc>-<OpMode>-<Name> if device.getDc() is not None:
for element in device.getDc().getOpMode():
@@ -1048,7 +1520,7 @@
- # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name
+ # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name for element in device.getTxPdo():
@@ -1081,7 +1553,7 @@
- # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name
+ # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name for element in device.getRxPdo():
@@ -1114,10 +1586,10 @@
- # category length (word); 1 word is 4 bytes. "+2" is the length of string's total number
+ # category length (word); 1 word is 4 bytes. "+2" is the length of string's total number length = len(vendor_specific_data + dc_related_elements + input_elements + output_elements) + 2
@@ -1126,7 +1598,7 @@
eeprom.append("{:0>4x}".format(length/4)[2:4])
eeprom.append("{:0>4x}".format(length/4)[0:2])
- # total numbers of strings
+ # total numbers of strings eeprom.append("{:0>2x}".format(count))
for element in [vendor_specific_data,
@@ -1171,48 +1643,48 @@
# 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>
+ # CoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE> - mb = device.getMailbox()
- coe_details = 1 # sdo enabled
- for bit,flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig",
- "PdoUpload", "CompleteAccess"]):
- if getattr(coe,"get%s"%flag)() is not None:
+ if device.getMailbox() is not None and device.getMailbox().getCoE() is not None: + coe_details = 1 # sdo enabled + for attr, bit in [(device.getMailbox().getCoE().getSdoInfo(), 1), + (device.getMailbox().getCoE().getPdoAssign(), 2), + (device.getMailbox().getCoE().getPdoConfig(), 3), + (device.getMailbox().getCoE().getPdoUpload(), 4), + (device.getMailbox().getCoE().getCompleteAccess(), 5)]: + if attr==1 or attr==True: 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:
+ # FoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<FoE> + if device.getMailbox() is not None and device.getMailbox().getFoE() is not None: - # EoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<EoE>
- if mb is not None and mb.getEoE() is not None:
+ # EoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<EoE> + if device.getMailbox() is not None and device.getMailbox().getEoE() is not None: # 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:
+ # SoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<SoE> + if device.getMailbox() is not None and device.getMailbox().getSoE() is not None: - # DS402Channels; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>: DS402Channels
- ds402ch = coe.getDS402Channels()
- eeprom.append("01" if ds402ch in [True,1] else "00")
+ # DS402Channels; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>: DS402Channels + if device.getMailbox() is not None and \ + (device.getMailbox().getCoE().getDS402Channels() == True \ + or device.getMailbox().getCoE().getDS402Channels() == 1): # word 6 : SysmanClass(reserved) and Flags
eeprom.append("00") # reserved
if device.getType().getTcCfgModeSafeOp() == True \
@@ -1272,10 +1744,10 @@
# construct of EEPROM data
eeprom.append("{:0>4x}".format((count+1)/2)[2:4])
@@ -1289,7 +1761,7 @@
- # padding if length is odd bytes
+ # padding if length is odd bytes @@ -1321,10 +1793,10 @@
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):
@@ -1351,19 +1823,19 @@
for element in eval("device.get%s()"%pdotype):
data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[2:4]
data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[0:2]
data += "{:0>2x}".format(len(element.getEntry()))
if element.getSm() is not None:
data += "{:0>2x}".format(element.getSm())
- # Reference to DC Synch (according to ET1100 documentation) - assume 0
+ # Reference to DC Synch (according to ET1100 documentation) - assume 0
for name in element.getName():
objname = name.getcontent()
@@ -1376,7 +1848,7 @@
data += "{:0>2x}".format(count)
- # Flags; by Fixed, Mandatory, Virtual attributes ?
+ # Flags; by Fixed, Mandatory, Virtual attributes ? if element.getFixed() == True or 1:
if element.getMandatory() == True or 1:
@@ -1386,12 +1858,12 @@
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]
data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[0:2]
data += "{:0>2x}".format(int(entry.getSubIndex()))
for name in entry.getName():
objname = name.getcontent()
@@ -1404,7 +1876,7 @@
data += "{:0>2x}".format(count)
if entry.getDataType() is not None:
if entry.getDataType().getcontent() in self.BaseDataTypeDict:
data += self.BaseDataTypeDict[entry.getDataType().getcontent()]
@@ -1412,19 +1884,19 @@
if entry.getBitLen() is not None:
data += "{:0>2x}".format(int(entry.getBitLen()))
- # Flags; by Fixed attributes ?
+ # Flags; by Fixed attributes ? if entry.getFixed() == True or entry.getFixed() == 1:
data += str(int(en_fixed)) + "000"
@@ -1432,7 +1904,7 @@
eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
@@ -1459,7 +1931,7 @@
if device.getDc() is not None:
for element in device.getDc().getOpMode():
- # assume that word 1-7 are 0x0000
+ # assume that word 1-7 are 0x0000 @@ -1467,14 +1939,14 @@
if element.getAssignActivate() is not None:
data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[2:4]
data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[0:2]
- # Factor of CycleTimeSync0 ? and default is 1?
+ # Factor of CycleTimeSync0 ? and default is 1? if element.getCycleTimeSync0() is not None:
if element.getCycleTimeSync0().getFactor() is not None:
data += "{:0>2x}".format(int(element.getCycleTimeSync0().getFactor()))
@@ -1483,8 +1955,8 @@
- # Index of Name in STRINGS Category
+ # Index of Name in STRINGS Category for name in element.getName():
@@ -1498,15 +1970,15 @@
data += "{:0>2x}".format(namecount)
- # assume that word 11-12 are 0x0000
+ # 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])
@@ -1533,6 +2005,24 @@
error, return_val = self.Controler.RemoteExec(REG_READ%(self.Controler.GetSlavePos(), offset, length), return_val = None)
+ def MultiRegRead(self, slave_num, reg_infos): + for reg_info in reg_infos: + reg_info_str = reg_info_str + "%s|" % reg_info + reg_info_str = reg_info_str.strip("|") + error, return_val = self.Controler.RemoteExec(\ + MULTI_REG_READ%(slave_num, reg_info_str), def RegWrite(self, address, data):
Write data to slave ESC register using "ethercat reg_write -p %d %s %s" command.
@@ -1550,6 +2040,40 @@
Command example : "ethercat rescan -p 0"
error, return_val = self.Controler.RemoteExec(RESCAN%(self.Controler.GetSlavePos()), return_val = None)
+ #------------------------------------------------------------------------------- + # Used DC Configuration + #------------------------------------------------------------------------------- + slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) + type_infos = slave.getType() + device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) + if device.getDc() is not None: + for OpMode in device.getDc().getOpMode(): + "desc" : OpMode.getDesc() if OpMode.getDesc() is not None else "Unused", + "assign_activate" : OpMode.getAssignActivate() \ + if OpMode.getAssignActivate() is not None else "#x0000", + "cycletime_sync0" : OpMode.getCycleTimeSync0().getcontent() \ + if OpMode.getCycleTimeSync0() is not None else None, + "shifttime_sync0" : OpMode.getShiftTimeSync0().getcontent() \ + if OpMode.getShiftTimeSync0() is not None else None, + "cycletime_sync1" : OpMode.getShiftTimeSync1().getcontent() \ + if OpMode.getShiftTimeSync1() is not None else None, + "shifttime_sync1" : OpMode.getShiftTimeSync1().getcontent() \ + if OpMode.getShiftTimeSync1() is not None else None + if OpMode.getCycleTimeSync0() is not None: + temp_data["cycletime_sync0_factor"] = OpMode.getCycleTimeSync0().getFactor() + if OpMode.getCycleTimeSync1() is not None: + temp_data["cycletime_sync1_factor"] = OpMode.getCycleTimeSync1().getFactor() + return_data.append(temp_data) #-------------------------------------------------------------------------------
@@ -1559,7 +2083,7 @@
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.
# Command example : "ethercat xml -p 0"
--- a/etherlab/EtherCATManagementEditor.py Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/EtherCATManagementEditor.py Wed Nov 20 16:57:15 2019 +0100
@@ -21,6 +21,18 @@
# ------------ for SDO Management --------------------
import wx.grid as gridlib
+ from agw import pyprogress as PP + import wx.lib.agw.pyprogress as PP + from agw import genericmessagedialog as GMD + import wx.lib.agw.genericmessagedialog as GMD +from threading import Timer, Thread, Lock +#from time import localtime #-------------------------------------------------------------
# ------------ for register management ---------------
@@ -60,37 +72,42 @@
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 Mapping", PDOPanelClass, []), + # ("ESC Management", EEPROMAccessPanel, [ + # ("Smart View", SlaveSiiSmartView), + # ("Hex View", HexView)]), + # ("Register Access", RegisterAccessPanel, [])]: + # pclass = pclass(self, self.Controler) + # self.AddPage(pclass, pname) + # for spname, spclass in subs: + # spclass = spclass(self, self.Controler) + # self.AddSubPage(spclass, spname) for pname, pclass, subs in [
("Slave State", SlaveStatePanelClass, []),
("SDO Management", SDOPanelClass, []),
- ("PDO Monitoring", PDOPanelClass, []),
- ("ESC Management", EEPROMAccessPanel, [
- ("Smart View", SlaveSiiSmartView),
- ("Hex View", HexView)]),
- ("Register Access", RegisterAccessPanel, [])]:
- self.AddPage(pclass(self, self.Controler), pname)
+ ("PDO Mapping", PDOPanelClass, [ + ("Rx PDO", RxPDOPanelClass), + ("Tx PDO", TxPDOPanelClass)]), + ("MDP Setting", MDPPanel, []), + ("ESC Management", EEPROMAccessPanel, [ + ("Smart View", SlaveSiiSmartView), + ("Hex View", HexView)]), + ("Register Access", RegisterAccessPanel, []), + ("DC Configuration", DCConfigPanel, []) + pclass = pclass(self, self.Controler) + self.AddPage(pclass, pname) for spname, spclass in subs:
- self.AddSubPage(spclass(self, self.Controler), spname)
+ spclass = spclass(self, self.Controler) + self.AddSubPage(spclass, spname) - 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()
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
@@ -184,7 +201,7 @@
self.SetSizer(self.SizerDic["SlaveState_main_sizer"])
- # register a timer for periodic exectuion of slave state update (period: 1000 ms)
+ # register a timer for periodic exectuion of slave state update (period: 2000 ms) self.Bind(wx.EVT_TIMER, self.GetCurrentState)
self.CreateSyncManagerTable()
@@ -199,14 +216,14 @@
self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames())
self.SyncManagersGrid.SetTable(self.SyncManagersTable)
# set grid alignment attr. (CENTER)
- self.SyncManagersGridColAlignements = [wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE,
- wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE]
+ self.SyncManagersGridColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_CENTER, wx.ALIGN_CENTER, + wx.ALIGN_CENTER, wx.ALIGN_CENTER, wx.ALIGN_CENTER] self.SyncManagersGridColSizes = [40, 150, 100, 100, 100, 100]
self.SyncManagersGrid.SetRowLabelSize(0)
for col in range(self.SyncManagersTable.GetNumberCols()):
attr = wx.grid.GridCellAttr()
- attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTRE)
+ attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTER) self.SyncManagersGrid.SetColAttr(col, attr)
self.SyncManagersGrid.SetColMinimalWidth(col, self.SyncManagersGridColSizes[col])
self.SyncManagersGrid.AutoSizeColumn(col, False)
@@ -236,7 +253,9 @@
Event handler for slave state transition button click (Init, PreOP, SafeOP, OP button)
@param event : wx.EVT_BUTTON object
- check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+ # Check whether beremiz connected or not. + # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) state_dic = ["INIT", "PREOP", "SAFEOP", "OP"]
@@ -258,10 +277,15 @@
def GetCurrentState(self, event):
- Timer event handler for periodic slave state monitoring (Default period: 1 sec = 1000 msec).
+ Timer event handler for periodic slave state monitoring (Default period: 1 sec = 2000 msec). @param event : wx.TIMER object
- check_connect_flag = self.Controler.CommonMethod.CheckConnect(True)
+ if self.IsShownOnScreen() is False: + # Check whether beremiz connected or not. + # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = True) returnVal = self.Controler.CommonMethod.GetSlaveStateFromSlave()
line = returnVal.split("\n")
@@ -291,9 +315,15 @@
- start slave state monitoring thread
@param event : wx.EVT_BUTTON object
- self.SlaveStateThread = wx.Timer(self)
- # set timer period (1000 ms)
- self.SlaveStateThread.Start(1000)
+ # Check whether beremiz connected or not. + # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) + self.SlaveStateThread = wx.Timer(self) + # set timer period (2000 ms) + self.SlaveStateThread.Start(2000) def CurrentStateThreadStop(self, event):
@@ -309,7 +339,7 @@
#-------------------------------------------------------------------------------
# For SDO Management Panel
#-------------------------------------------------------------------------------
-class SDOPanelClass(wx.Panel):
+class SDOPanelClass(wx.ScrolledWindow): def __init__(self, parent, controler):
@@ -322,141 +352,217 @@
self.ProfileSpecific, self.Reserved, self.AllSDOData = range(6)
self.Controler = controler
+ self.SDOMonitorEntries = {} + #----------------------------- SDO Monitor -------------------------------# + self.RBList = ["ON","OFF"] - 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.Bind(wx.EVT_BUTTON, self.SDOInfoUpdate)
+ self.SDOMonitorRB = wx.RadioBox(self, label=_("monitoring"), + choices=self.RBList, majorDimension=2) + self.SDOMonitorRB.SetSelection(1) + self.Bind(wx.EVT_RADIOBOX, self.OnRadioBox, self.SDOMonitorRB) + self.SDOMonitorGrid = wx.grid.Grid(self,size=wx.Size(850,150),style=wx.EXPAND + |wx.ALIGN_CENTER_HORIZONTAL + |wx.ALIGN_CENTER_VERTICAL) + self.SDOMonitorGrid.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, + self.onMonitorGridDoubleClick) + #----------------------------- SDO Entries ----------------------------# + self.SDOUpdateBtn = wx.Button(self, label=_("update")) + self.SDOUpdateBtn.Bind(wx.EVT_BUTTON, self.OnSDOUpdate) - self.CallSDONoteBook = SDONoteBook(self, controler=self.Controler)
- self.SDOManagementInnerMainSizer.Add(self.SDOUpdate)
- self.SDOManagementInnerMainSizer.Add(self.CallSDONoteBook, wx.ALL | wx.EXPAND)
+ self.SDOTraceThread = None + self.SDOMonitoringFlag = False + self.SDOValuesList = [] + # Default SDO Page Number + #----------------------------- Sizer --------------------------------------# + self.SDOManagementMainSizer = wx.BoxSizer(wx.VERTICAL) + self.SDOInfoBox = wx.StaticBox(self, label=_("SDO Entries")) + self.SDOMonitorBox = wx.StaticBox(self, label=_("SDO Monitor")) - self.SDOManagementMainSizer.Add(self.SDOManagementInnerMainSizer)
+ self.SDONoteBook = SDONoteBook(self, controler=self.Controler) + self.SDOInfoBoxSizer = wx.StaticBoxSizer(self.SDOInfoBox, orient=wx.VERTICAL) + self.SDOMonitorBoxSizer = wx.StaticBoxSizer(self.SDOMonitorBox, + self.SDOInfoBoxSizer.Add(self.SDOUpdateBtn) + self.SDOInfoBoxSizer.Add(self.SDONoteBook, wx.ALL|wx.EXPAND) + self.SDOMonitorBoxSizer.Add(self.SDOMonitorRB) + self.SDOMonitorBoxSizer.Add(self.SDOMonitorGrid) + self.SDOManagementMainSizer.AddMany([self.SDOInfoBoxSizer, + self.SDOMonitorBoxSizer]) self.SetSizer(self.SDOManagementMainSizer)
- def SDOInfoUpdate(self, event):
+ #----------------------------- fill the contents --------------------------# + #self.entries = self.Controler.CTNParent.CTNParent.GetEntriesList() + slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) + type_infos = slave.getType() + device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) + self.entries = device.GetEntriesList() + self.Controler.CommonMethod.SDOVariables = [] + self.Controler.CommonMethod.SDOSubEntryData = [] + self.Controler.CommonMethod.ClearSDODataSet() + self.SDOParserXML(self.entries) + self.SDONoteBook.CreateNoteBook() + self.CreateSDOMonitorGrid() + def OnSDOUpdate(self, event): + SlavePos = self.Controler.GetSlavePos() + num = self.SDOPageNum - 1 + for i in range(len(self.Controler.CommonMethod.SDOVariables)): + data = self.Controler.GetCTRoot()._connector.GetSDOEntriesData( + self.Controler.CommonMethod.SDOVariables[i], SlavePos) + self.Controler.CommonMethod.SDOVariables[i] = data + SDOUploadEntries = self.Controler.CommonMethod.SDOVariables[num] + data = self.Controler.GetCTRoot()._connector.GetSDOEntriesData(SDOUploadEntries, SlavePos) + self.Controler.CommonMethod.SDOVariables[num] = data + self.SDONoteBook.CreateNoteBook() + def OnRadioBox(self, event): - Evenet handler for SDO "update" button.
- - 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)
+ There are two selections that are on and off. + If the on is selected, the monitor thread begins to run. + If the off is selected, the monitor thread gets off. + @param event: wx.EVT_RADIOBOX object + if event.GetInt() == on: + CheckThreadFlag = self.SDOMonitoringThreadOn() + if not CheckThreadFlag: + self.SDOMonitorRB.SetSelection(off) + elif event.GetInt() == off: + self.SDOMonitoringThreadOff() + def SDOMonitoringThreadOn(self): + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) - self.SDOs = self.Controler.CommonMethod.GetSlaveSDOFromSlave()
- # SDOFlag is "False", user click "Cancel" button
- self.SDOFlag = self.SDOParser()
+ self.SetSDOTraceValues(self.SDOMonitorEntries) + self.Controler.GetCTRoot()._connector.GetSDOData() + self.SDOTraceThread = Thread(target=self.SDOMonitorThreadProc) + self.SDOMonitoringFlag = True + self.SDOTraceThread.start() + return check_connect_flag
- self.CallSDONoteBook.CreateNoteBook()
- Parse SDO data set that obtain "SDOInfoUpdate" Method
+ def SDOMonitoringThreadOff(self): + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) + self.SDOMonitoringFlag = False + if self.SDOTraceThread is not None: + self.SDOTraceThread.join() + self.SDOTraceThread = None + self.Controler.GetCTRoot()._connector.StopSDOThread() + def SetSDOTraceValues(self, SDOMonitorEntries): + SlavePos = self.Controler.GetSlavePos() + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = True) + self.Controler.GetCTRoot()._connector.SetSDOTraceValues(SDOMonitorEntries, SlavePos) - 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)
+ def SDOMonitorThreadProc(self): + while self.SDOMonitoringFlag and self.Controler.GetCTRoot()._connector.PLCStatus != "Started": + self.SDOValuesList = self.Controler.GetCTRoot()._connector.GetSDOData() + LocalData = self.SDOValuesList[0].items() + if self.SDOValuesList[1] != self.Controler.GetSlavePos(): + for (idx, subidx), data in LocalData: + self.SDOMonitorGrid.SetCellValue(row, 6, str(data["value"])) + def CreateSDOMonitorGrid(self): + It creates SDO Monitor table and specifies cell size and labels. + self.SDOMonitorGrid.CreateGrid(0,7) + SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 70), + (4, 40), (5, 450), (6, 85)] + for (index, size) in SDOCellSize: + self.SDOMonitorGrid.SetColSize(index, size) + self.SDOMonitorGrid.SetRowLabelSize(0) + SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"), + (3, "Type"), (4, "Size"), (5, "Name"), (6, "Value")] - # 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():
- line_token = details_line.split("\"")
- # len(line_token[2]) case : SDO 0x1000, "Device type"
- if len(line_token[2]) == 0:
- title_name = line_token[1]
- # else case : 0x1000:00,r-r-r-,uint32,32 bit,"Device type",0x00020192, 131474
- # 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(":")
+ for (index, label) in SDOTableLabel: + self.SDOMonitorGrid.SetColLabelValue(index, label) + self.SDOMonitorGrid.SetColLabelAlignment(index, wx.ALIGN_CENTER) + def onMonitorGridDoubleClick(self, event): + Event Handler for double click on the SDO entries table. + It adds the entry into the SDO monitor table. + If the entry is already in the SDO monitor table, + then it's removed from the SDO monitor table. + @pram event: gridlib.EVT_GRID_CELL_LEFT_DCLICK object + idx = self.SDOMonitorGrid.GetCellValue(row, 0) + subIdx = self.SDOMonitorGrid.GetCellValue(row, 1) + del self.SDOMonitorEntries[(idx, subIdx)] + self.SDOMonitorGrid.DeleteRows(row, 1) + self.SetSDOTraceValues(self.SDOMonitorEntries) + self.SDOMonitorGrid.Refresh() + def SDOParserXML(self, entries): + Parse SDO data set that obtain "ESI file" + @param entries: SDO entry list + entries_list = entries.items() + self.ForDefaultValueFlag = False + self.sub_entry_value_list = [] + for (index, subidx), entry in entries_list: + # exclude entry that isn't in the objects + check_mapping = entry["PDOMapping"] + if check_mapping is "T" or check_mapping is "R": + if "PDO index" not in entry.keys(): + idx = "0" + entry["Index"].strip("#") + #subidx = hex(int(entry["SubIndex"], 0)) + subidx = "0x" + entry["SubIndex"] + datatype = entry["Type"] + default_value = entry["DefaultData"] + default_value = " --- " + # Result of SlaveSDO data parsing. (data type : dictionary) + self.Data = {'idx':idx, 'subIdx':subidx, 'access':entry["Access"], + 'type':datatype, 'size': str(entry["BitSize"]), + 'name':entry["Name"], 'value':default_value} + category_divide_value = [0x1000, 0x2000, 0x6000, 0xa000, 0xffff] - # 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", ----
- empty, hex_val = token_tail
- name_after_check = self.StringTest(name)
- sub_idx = "0x" + sub_idx
- 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("\""),
- '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.SDOVariables[count].append(self.Data) - 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 (keep_going == False):
- slaveSDO_progress.Destroy()
- def StringTest(self, check_string):
- 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
- allow_range = string.printable
- for i in range(0, len(check_string)):
- # string.isalnum() is check whether string is alphanumeric or not
- if check_string[len(check_string)-1-i:len(check_string)-i] in allow_range :
- result = check_string[:len(check_string) - i]
+ self.Controler.CommonMethod.SDOSubEntryData = self.sub_entry_value_list #-------------------------------------------------------------------------------
# For SDO Notebook (divide category)
@@ -468,14 +574,14 @@
@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, 350)) self.Controler = controler
- self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
- self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
+ self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging) def CreateNoteBook(self):
@@ -500,48 +606,57 @@
+ self.Controler.CommonMethod.SDOVariables[5] = [] + self.Controler.CommonMethod.SDOVariables[5] += self.Controler.CommonMethod.SDOVariables[i] for txt, count in page_texts:
- self.Data = self.Controler.CommonMethod.SaveSDOData[count]
- self.Win = SlaveSDOTable(self, self.Data)
+ self.Data = self.Controler.CommonMethod.SDOVariables[count] + self.SubEntryData = self.Controler.CommonMethod.SDOSubEntryData + self.Win = SlaveSDOTable(self, self.Data, self.SubEntryData) self.AddPage(self.Win, txt)
def OnPageChanged(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
sel = self.GetSelection()
+ self.parent.SDOPageNum = new def OnPageChanging(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
- sel = self.GetSelection()
+ sel = self.GetSelection() #-------------------------------------------------------------------------------
# For SDO Grid (fill index, subindex, etc...)
#-------------------------------------------------------------------------------
class SlaveSDOTable(wx.grid.Grid):
- def __init__(self, parent, data):
+ def __init__(self, parent, data, fixed_value): @param parent: Reference to the parent SDOPanelClass class
@param data: SDO data after parsing "SDOParser" method
wx.grid.Grid.__init__(self, parent, -1, size=(830,490),
- style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ style=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL) self.Controler = parent.Controler
+ self.sub_entry_value = [] + self.sub_entry_value = fixed_value - self.CreateGrid(len(self.SDOs), 8)
- SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 55),
- (4, 40), (5, 200), (6, 250), (7, 85)]
+ self.CreateGrid(len(self.SDOs), 7) + SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 70), + (4, 40), (5, 400), (6, 135)] for (index, size) in SDOCellSize:
self.SetColSize(index, size)
@@ -549,17 +664,16 @@
SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
- (3, "Type"), (4, "Size"), (5, "Category"),
- (6, "Name"), (7, "Value")]
+ (3, "Type"), (4, "Size"), (5, "Name"), (6, "Value")] for (index, label) in SDOTableLabel:
self.SetColLabelValue(index, label)
- self.SetColLabelAlignment(index, wx.ALIGN_CENTRE)
+ self.SetColLabelAlignment(index, wx.ALIGN_CENTER) attr = wx.grid.GridCellAttr()
- self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.SDOModifyDialog)
+ # for SDO download and monitoring + self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.onGridDoubleClick) @@ -572,55 +686,45 @@
Cell is filled by new parsing data
- sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'category', 'name', 'value']
+ sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'name', 'value'] for row_idx in range(len(self.SDOs)):
- for col_idx in range(len(self.SDOs[row_idx])):
- self.SetCellValue(row_idx, col_idx, self.SDOs[row_idx][sdo_list[col_idx]])
+ for col_idx in range(len(self.SDOs[row_idx])): + # the top entries that have sub index is shaded. + if int(self.SDOs[row_idx]['subIdx'], 16) == 0x00: + if int(self.SDOs[row_idx + 1]['subIdx'], 16) is not 0x00: + self.SetCellBackgroundColour(row_idx, col_idx, \ + if self.SDOs[row_idx][sdo_list[col_idx]] == "modifying": + if len(self.sub_entry_value) == count: + self.SetCellValue(row_idx, col_idx, self.sub_entry_value[count]) + self.SetCellValue(row_idx, col_idx, \ + self.SDOs[row_idx][sdo_list[col_idx]]) self.SetReadOnly(row_idx, col_idx, True)
- self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
+ self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTER, wx.ALIGN_CENTER) 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--
+ check that access field has "rw" @param row : Selected cell by user
@return Write_flag : If data has "w", flag is true
check = self.SDOs[row]['access']
- 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,
- result notify SDOModifyDialog method
- @param state : current slave state
- # 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 :
- elif state == "SAFEOP" and self.Controler.CommonMethod.Check_SAFEOP :
- elif state == "OP" and self.Controler.CommonMethod.Check_OP :
def ClearStateFlag(self):
@@ -631,7 +735,7 @@
self.Controler.CommonMethod.Check_SAFEOP = False
self.Controler.CommonMethod.Check_OP = False
- def SDOModifyDialog (self, event):
+ def onGridDoubleClick (self, event): Create dialog for SDO value modify
if user enter data, perform command "ethercat download"
@@ -640,32 +744,100 @@
# 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)
+ if event.GetCol() == 6 and self.CheckSDODataAccess(event.GetRow()) : + dlg = wx.TextEntryDialog (self, + "Enter hex or dec value (if enter dec value, " \ + + "it automatically conversed hex value)", + "SDOModifyDialog", style = wx.OK | wx.CANCEL) start_value = self.GetCellValue(event.GetRow(), event.GetCol())
dlg.SetValue(start_value)
if dlg.ShowModal() == wx.ID_OK:
- if self.DecideSDODownload(self.Controler.CommonMethod.SlaveState[self.Controler.GetSlavePos()]) :
+ # Check whether beremiz connected or not. + # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) + input_val = hex(int(dlg.GetValue(), 0)) - 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')
- # Error occured process of "int(variable)"
- # User input is not hex, dec value
- self.Controler.CommonMethod.CreateErrorDialog('You can input only hex, dec value')
+ return_val = self.Controler.CommonMethod.SDODownload( + self.SDOs[event.GetRow()]["type"], + self.SDOs[event.GetRow()]["idx"], + self.SDOs[event.GetRow()]["subIdx"], + SDOUploadEntry = {"idx" : self.SDOs[event.GetRow()]["idx"], + "subIdx" : self.SDOs[event.GetRow()]["subIdx"], + "size" : self.SDOs[event.GetRow()]["size"] + data = self.Controler.GetCTRoot()._connector.GetSDOEntryData( + SDOUploadEntry, self.Controler.GetSlavePos()) + hex_val = hex(data)[:-1] + if input_val == hex_val: + display_val = "%s(%d)" % (hex_val, data) + self.SetCellValue(event.GetRow(), event.GetCol(), + self.Controler.CommonMethod.CreateErrorDialog(\ + 'SDO Value not completely download, please try again') + self.Controler.GetCTRoot().logger.write_error(return_val) + # Error occured process of "int(variable)" + # User input is not hex, dec value + self.Controler.CommonMethod.CreateErrorDialog(\ + 'You can input only hex, dec value') + SDOPanel = self.parent.parent + idx = self.SDOs[row]["idx"] + subIdx = self.SDOs[row]["subIdx"] + SDOPanel.SDOMonitorEntries[(idx, subIdx)] = { + "access": self.SDOs[row]["access"], + "type": self.SDOs[row]["type"], + "size": self.SDOs[row]["size"], + "name": self.SDOs[row]["name"], + del_rows = SDOPanel.SDOMonitorGrid.GetNumberRows() + SDOPanel.SDOMonitorGrid.DeleteRows(0, del_rows) + SDOPanel.SDOMonitorGrid.AppendRows(len(SDOPanel.SDOMonitorEntries)) + SDOPanel.SetSDOTraceValues(SDOPanel.SDOMonitorEntries) + SME_list = SDOPanel.SDOMonitorEntries.items() + for (idx, subIdx), entry in SME_list: + SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, 0, str(idx)) + SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, 1, str(subIdx)) + for col, key in [(2, "access"), + SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, col, entry[key]) + SDOPanel.SDOMonitorGrid.SetReadOnly(gridRow, col, True) + SDOPanel.SDOMonitorGrid.SetCellAlignment(\ + gridRow, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER) + SDOPanel.SDOMonitorGrid.Refresh() #-------------------------------------------------------------------------------
-# For PDO Monitoring Panel
# PDO Class UI : Panel -> Choicebook (RxPDO, TxPDO) ->
# Notebook (PDO Index) -> Grid (PDO entry)
#-------------------------------------------------------------------------------
@@ -678,16 +850,152 @@
wx.Panel.__init__(self, parent, -1)
self.Controler = controler
+ sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20) + line = wx.StaticText(self, -1, "\n In order to control Ethercat device, user must select proper PDO set.\ + \n Each PDO sets describe operation modes (CSP, CSV, CST) supported by Ethercat devices.\ + \n\n PDOs have two types, RxPDO and TxPDO.\ + \n - RxPDO refers to the Receive Process Data Object. It means the control parameters which sent from controller to the EtherCAT Slave device.\ + \n In general, ControlWord (0x6040), Modes of Operations (0x6060), and TargetPosition (0x607A) are regarded as RxPDO.\ + \n - TxPDO refers to the Transmit Process Data Object. It used to report status of EtherCAT Slave device to the controller in order to calibrate their next actuation.\ + \n StatusWord (0x6041), Modes of Operation Display (0x6061), and ActualPosition (0x607A) include in TxPDO.\ + \n\n PDO Mapping feature provides available RxPDO and TxPDO sets which defined in Ethercat slave description XML.\ + \n If there is no selection of PDO set, first set (0x1600, 0x1A00) will be chosen as default configuration.") - self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
- self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
+class RxPDOPanelClass(wx.Panel): + def __init__(self, parent, controler): + @param parent: Reference to the parent EtherCATManagementTreebook class + @param controler: _EthercatSlaveCTN class in EthercatSlave.py + wx.Panel.__init__(self, parent, -1) + self.Controler = controler + #self.PDOIndexList = ["RxPDO"] + self.LoadPDOSelectData() + #HSAHN ADD. 2015.7.26 PDO Select Function ADD + self.Controler.CommonMethod.RequestPDOInfo() + self.rx_pdo_entries = self.Controler.CommonMethod.GetRxPDOCategory() + if len(self.rx_pdo_entries): + for i in range(len(self.rx_pdo_entries)): + self.PDOcheckBox.append(wx.CheckBox(self, label=str(hex(self.rx_pdo_entries[i]['pdo_index'])), size=(120,15))) + if not self.Controler.SelectedRxPDOIndex and self.rx_pdo_entries[i]['sm'] is not None: + self.PDOcheckBox[-1].SetValue(True) + self.Controler.SelectedRxPDOIndex.append(int(self.PDOcheckBox[-1].GetLabel(), 0)) + elif self.rx_pdo_entries[i]['pdo_index'] in self.Controler.SelectedRxPDOIndex: + self.PDOIndexList.append(str(hex(self.rx_pdo_entries[i]['pdo_index']))) + self.PDOcheckBox[-1].SetValue(True) + for cb in self.PDOcheckBox: + self.Bind(wx.EVT_CHECKBOX, self.PDOSelectCheck, cb) + self.PDOListBox = wx.StaticBox(self, label=_("PDO Mapping Select")) + self.PDOListBoxSizer = wx.StaticBoxSizer(self.PDOListBox, orient=wx.HORIZONTAL) + self.RxPDOListBox = wx.StaticBox(self, label=_("RxPDO")) + self.RxPDOListBoxSizer = wx.StaticBoxSizer(self.RxPDOListBox, orient=wx.VERTICAL) + self.RxPDOListBoxInnerSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=10, vgap=5) + self.RxPDOListBoxInnerSizer.AddMany(self.PDOcheckBox[0:len(self.rx_pdo_entries)]) + self.RxPDOListBoxSizer.Add(self.RxPDOListBoxInnerSizer) + self.PDOListBoxSizer.Add(self.RxPDOListBoxSizer) + self.PDOWarningText = wx.StaticText(self, -1, + " *Warning*\n\n By default configuration, \n\n first mapping set is selected. \n\n Choose the PDO mapping!", + self.PDOListBoxSizer.Add(self.PDOWarningText) + self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL) + self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10) - self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)
- self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)
+ self.CallPDOChoicebook = PDONoteBook(self, controler=self.Controler, name="Rx") + self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL) + self.PDOInformationBox = wx.StaticBox(self, label=_("RxPDO Mapping List")) + self.PDOInformationBoxSizer = wx.StaticBoxSizer(self.PDOInformationBox, orient=wx.VERTICAL) + self.PDOInformationBoxSizer.Add(self.PDOMonitoringEditorInnerMainSizer) + self.PDOMonitoringEditorMainSizer.Add(self.PDOListBoxSizer) + self.PDOMonitoringEditorMainSizer.Add(self.PDOInformationBoxSizer) + self.SetSizer(self.PDOMonitoringEditorMainSizer) + sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20) + line = wx.StaticText(self, -1, "\n This device does not support RxPDO.") - self.PDOMonitoringEditorMainSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
- self.SetSizer(self.PDOMonitoringEditorMainSizer)
+ def LoadPDOSelectData(self): + RxPDOData = self.Controler.BaseParams.getRxPDO() + if RxPDOData != "None": + RxPDOs = RxPDOData.split() + self.Controler.SelectedRxPDOIndex.append(int(RxPDO, 0)) + def PDOSelectCheck(self, event): + # add jblee for Save User Select + cb = event.GetEventObject() + # prevent duplicated check + if cb.GetValue() and int(cb.GetLabel(), 0) not in self.Controler.SelectedRxPDOIndex: + self.Controler.SelectedRxPDOIndex.append(int(cb.GetLabel(), 0)) + self.PDOIndexList.append(cb.GetLabel()) + self.Controler.SelectedRxPDOIndex.remove(int(cb.GetLabel(), 0)) + self.PDOIndexList.remove(cb.GetLabel()) + for PDOIndex in self.PDOIndexList: + data = data + " " + PDOIndex + self.Controler.BaseParams.setRxPDO(data) + self.Controler.GetCTRoot().CTNRequestSave() + for PDOIndex in self.Controler.SelectedRxPDOIndex: + self.PDOIndexList.append(str(hex(PDOIndex))) + for PDOIndex in self.PDOIndexList: + data = data + " " + PDOIndex + self.Controler.BaseParams.setRxPDO(data) + # add jblee for check exclude pdo list + def PDOExcludeCheck(self): + #files = os.listdir(self.Controler.CTNPath()) + #filepath = os.path.join(self.Controler.CTNPath(), "DataForPDO.txt") + CurIndexs = self.Controler.SelectedRxPDOIndex + for CB in self.PDOcheckBox: + if len(CB.GetLabel().split()) > 1: + CB.SetLabel(CB.GetLabel().split()[0]) + for pdo in self.rx_pdo_entries: + for CurIndex in CurIndexs: + if pdo["pdo_index"] == CurIndex: + ex_list = pdo["exclude_list"] + for ex_item in ex_list: + for CB in self.PDOcheckBox: + if CB.GetLabel() == hex(ex_item): + CB.SetLabel(CB.GetLabel() + " (Excluded)") + def RefreshPDOInfo(self): @@ -695,43 +1003,142 @@
self.Controler.CommonMethod.RequestPDOInfo()
self.CallPDOChoicebook.Destroy()
- self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)
+ self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler, name="Rx")
-#-------------------------------------------------------------------------------
-# For PDO Choicebook (divide Tx, Rx PDO)
-#-------------------------------------------------------------------------------
-class PDOChoicebook(wx.Choicebook):
+class TxPDOPanelClass(wx.Panel): def __init__(self, parent, controler):
- @param parent: Reference to the parent PDOPanelClass class
+ @param parent: Reference to the parent EtherCATManagementTreebook class @param controler: _EthercatSlaveCTN class in EthercatSlave.py
- wx.Choicebook.__init__(self, parent, id=-1, size=(500, 500), style=wx.CHB_DEFAULT)
+ wx.Panel.__init__(self, parent, -1) self.Controler = controler
+ self.LoadPDOSelectData() + #HSAHN ADD. 2015.7.26 PDO Select Function ADD + self.Controler.CommonMethod.RequestPDOInfo() + self.tx_pdo_entries = self.Controler.CommonMethod.GetTxPDOCategory() + if len(self.tx_pdo_entries): + for i in range(len(self.tx_pdo_entries)): + self.PDOcheckBox.append(wx.CheckBox(self, label=str(hex(self.tx_pdo_entries[i]['pdo_index'])), size=(120,15))) + if not self.Controler.SelectedTxPDOIndex and self.tx_pdo_entries[i]['sm'] is not None: + self.PDOcheckBox[-1].SetValue(True) + self.Controler.SelectedTxPDOIndex.append(int(self.PDOcheckBox[-1].GetLabel(), 0)) + elif self.tx_pdo_entries[i]['pdo_index'] in self.Controler.SelectedTxPDOIndex: + self.PDOIndexList.append(str(hex(self.tx_pdo_entries[i]['pdo_index']))) + self.PDOcheckBox[-1].SetValue(True) + for cb in self.PDOcheckBox: + self.Bind(wx.EVT_CHECKBOX, self.PDOSelectCheck, cb) - 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)
+ self.PDOListBox = wx.StaticBox(self, label=_("PDO Mapping Select")) + self.PDOListBoxSizer = wx.StaticBoxSizer(self.PDOListBox, orient=wx.HORIZONTAL) + self.TxPDOListBox = wx.StaticBox(self, label=_("TxPDO")) + self.TxPDOListBoxSizer = wx.StaticBoxSizer(self.TxPDOListBox, orient=wx.VERTICAL) + self.TxPDOListBoxInnerSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=10, vgap=5) + self.TxPDOListBoxInnerSizer.AddMany(self.PDOcheckBox[0:len(self.tx_pdo_entries)]) + self.TxPDOListBoxSizer.Add(self.TxPDOListBoxInnerSizer) + self.PDOListBoxSizer.Add(self.TxPDOListBoxSizer) + self.PDOWarningText = wx.StaticText(self, -1, + " *Warning*\n\n By default configuration, \n\n first mapping set is selected. \n\n Choose the PDO mapping!", + self.PDOListBoxSizer.Add(self.PDOWarningText) + self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL) + self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10) + self.CallPDOChoicebook = PDONoteBook(self, controler=self.Controler, name="Tx") + self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL) + self.PDOInformationBox = wx.StaticBox(self, label=_("TxPDO Mapping List")) + self.PDOInformationBoxSizer = wx.StaticBoxSizer(self.PDOInformationBox, orient=wx.VERTICAL) + self.PDOInformationBoxSizer.Add(self.PDOMonitoringEditorInnerMainSizer) + self.PDOMonitoringEditorMainSizer.Add(self.PDOListBoxSizer) + self.PDOMonitoringEditorMainSizer.Add(self.PDOInformationBoxSizer) + self.SetSizer(self.PDOMonitoringEditorMainSizer) + sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20) + line = wx.StaticText(self, -1, "\n This device does not support TxPDO.") - def OnPageChanged(self, event):
- old = event.GetOldSelection()
- new = event.GetSelection()
- sel = self.GetSelection()
+ def LoadPDOSelectData(self): + TxPDOData = self.Controler.BaseParams.getTxPDO() + if TxPDOData != "None": + TxPDOs = TxPDOData.split() + self.Controler.SelectedTxPDOIndex.append(int(TxPDO, 0)) + def PDOSelectCheck(self, event): + # add jblee for Save User Select + cb = event.GetEventObject() + # prevent duplicated check + if cb.GetValue() and int(cb.GetLabel(), 0) not in self.Controler.SelectedTxPDOIndex: + self.Controler.SelectedTxPDOIndex.append(int(cb.GetLabel(), 0)) + self.PDOIndexList.append(cb.GetLabel()) + self.Controler.SelectedTxPDOIndex.remove(int(cb.GetLabel(), 0)) + self.PDOIndexList.remove(cb.GetLabel()) + for PDOIndex in self.PDOIndexList: + data = data + " " + PDOIndex + self.Controler.BaseParams.setTxPDO(data) + self.Controler.GetCTRoot().CTNRequestSave() - def OnPageChanging(self, event):
- old = event.GetOldSelection()
- new = event.GetSelection()
- sel = self.GetSelection()
+ for PDOIndex in self.Controler.SelectedTxPDOIndex: + self.PDOIndexList.append(str(hex(PDOIndex))) + for PDOIndex in self.PDOIndexList: + data = data + " " + PDOIndex + self.Controler.BaseParams.setTxPDO(data) + # add jblee for check exclude pdo list + def PDOExcludeCheck(self): + CurIndexs = self.Controler.SelectedTxPDOIndex + for CB in self.PDOcheckBox: + if len(CB.GetLabel().split()) > 1: + CB.SetLabel(CB.GetLabel().split()[0]) + for pdo in self.tx_pdo_entries: + for CurIndex in CurIndexs: + if pdo["pdo_index"] == CurIndex: + ex_list = pdo["exclude_list"] + for ex_item in ex_list: + for CB in self.PDOcheckBox: + if CB.GetLabel() == hex(ex_item): + CB.SetLabel(CB.GetLabel() + " (Excluded)") + def PDOInfoUpdate(self): + Call RequestPDOInfo method and create Choicebook + self.Controler.CommonMethod.RequestPDOInfo() + self.CallPDOChoicebook.Destroy() + self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler, name="Tx") #-------------------------------------------------------------------------------
# For PDO Notebook (divide PDO index)
@@ -744,14 +1151,12 @@
@param name: identifier whether RxPDO or TxPDO
@param controler: _EthercatSlaveCTN class in EthercatSlave.py
- wx.Notebook.__init__(self, parent, id=-1, size=(640, 400))
+ wx.Notebook.__init__(self, parent, id=-1, size=(600, 400)) self.Controler = controler
- self.Controler.CommonMethod.RequestPDOInfo()
# obtain pdo_info and pdo_entry
# pdo_info include (PDO index, name, number of entry)
@@ -774,22 +1179,6 @@
- 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()
- sel = self.GetSelection()
- def OnPageChanging(self, event):
- old = event.GetOldSelection()
- new = event.GetSelection()
- sel = self.GetSelection()
#-------------------------------------------------------------------------------
# For PDO Grid (fill entry index, subindex etc...)
#-------------------------------------------------------------------------------
@@ -803,7 +1192,7 @@
@param count : page number
wx.grid.Grid.__init__(self, parent, -1, size=(500, 400), pos=wx.Point(0,0),
- style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ style=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL) self.Controler = parent.Controler
@@ -854,13 +1243,190 @@
self.SetCellValue(row_idx, col_idx, str(self.PDOEntry[start_value][pdo_list[col_idx]]))
- self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
+ self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTER, wx.ALIGN_CENTER) - self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
+ self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_LEFT, wx.ALIGN_CENTER) self.SetReadOnly(row_idx, col_idx, True)
self.SetRowSize(row_idx, 25)
+#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +class MDPPanel(wx.Panel): + def __init__(self, parent, controler): + @param parent: Reference to the parent EtherCATManagementTreebook class + @param controler: _EthercatSlaveCTN class in EthercatSlave.py + wx.Panel.__init__(self, parent, -1) + self.Controler = controler + sizer = wx.FlexGridSizer(cols=3, hgap=20, rows=1, vgap=20) + # Include Module ListBox + leftInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10) + # Include Add, Delete Button + middleInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10) + rightInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10) + # Get Module Name as Array + # MDPArray = {SlaveName, [data0, data1, ...], SlotIndexIncrement, SlotPdoIncrement} + # data = [ModuleName, ModuleInfo, [PDOInfo1, PDOInfo2, ...]] + # PDOInfo = {Index, Name, BitSize, Access, PDOMapping, SubIndex, Type} + slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) + type_infos = slave.getType() + MDPArray = self.Controler.CTNParent.CTNParent.GetMDPInfos(type_infos) + for info in MDPArray[0][1]: + NameSet.append(info[0]) + self.ModuleLabel = wx.StaticText(self, -1, "Module") + self.ModuleListBox = wx.ListBox(self, size = (150, 200), choices = NameSet) + #self.ModuleListBox = wx.ListBox(self, size = (150, 200), choices = []) + self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnModuleListBoxDCClick, self.ModuleListBox) + self.AddButton = wx.Button(self, label=_(" Add Module ")) + self.DeleteButton = wx.Button(self, label=_("Delete Module")) + self.AddButton.Bind(wx.EVT_BUTTON, self.OnAddButton) + self.DeleteButton.Bind(wx.EVT_BUTTON, self.OnDeleteButton) + self.SlotLabel = wx.StaticText(self, -1, "Slot") + self.SlotListBox = wx.ListBox(self, size = (150, 200)) + self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnSlotListBoxDCClick, self.SlotListBox) + # Add Object Each Sizer + leftInnerSizer.AddMany([self.ModuleLabel, self.ModuleListBox]) + middleInnerSizer.Add(self.AddButton, 0, wx.TOP, 100) + middleInnerSizer.Add(self.DeleteButton, 0, wx.BOTTOM, 120) + rightInnerSizer.AddMany([self.SlotLabel, self.SlotListBox]) + sizer.AddMany([leftInnerSizer, middleInnerSizer, rightInnerSizer]) + files = os.listdir(self.Controler.CTNPath()) + filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt") + moduleDataFile = open(filepath, 'r') + lines = moduleDataFile.readlines() + module_pos = line.split()[-1] + name_len_limit = len(line) - len(module_pos) - 2 + module_name = line[0:name_len_limit] + self.SelectModule.append((module_name, int(module_pos))) + for (item, pos) in self.SelectModule: + slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0] + localModuleInfo.append(slotString) + self.SlotListBox.SetItems(localModuleInfo) + moduleDataFile = open(filepath, 'w') + def OnAddButton(self, event): + files = os.listdir(self.Controler.CTNPath()) + filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt") + moduleDataFile = open(filepath, 'w') + selectNum = self.ModuleListBox.GetSelection() + selectStr = self.ModuleListBox.GetString(selectNum) + self.SelectModule.append((selectStr, selectNum)) + for (item, pos) in self.SelectModule: + slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0] + localModuleInfo.append(slotString) + self.SlotListBox.SetItems(localModuleInfo) + def OnDeleteButton(self, event): + files = os.listdir(self.Controler.CTNPath()) + filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt") + moduleDataFile = open(filepath, 'w') + selectNum = self.SlotListBox.GetSelection() + selectStr = self.SlotListBox.GetString(selectNum) + self.SelectModule.pop(selectNum) + for (item, pos) in self.SelectModule: + moduleDataFile.write(item + " " + str(pos) + "\n") + slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0] + localModuleInfo.append(slotString) + self.SlotListBox.SetItems(localModuleInfo) + def OnModuleListBoxDCClick(self, event): + files = os.listdir(self.Controler.CTNPath()) + filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt") + moduleDataFile = open(filepath, 'w') + selectNum = self.ModuleListBox.GetSelection() + selectStr = self.ModuleListBox.GetString(selectNum) + self.SelectModule.append((selectStr, selectNum)) + for (item, pos) in self.SelectModule: + moduleDataFile.write(item + " " + str(pos) + "\n") + slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0] + localModuleInfo.append(slotString) + module = self.Controler.CTNParent.CTNParent.GetSelectModule(pos) + self.Controler.CommonMethod.SavePDOData(module) + self.SlotListBox.SetItems(localModuleInfo) + def OnSlotListBoxDCClick(self, event): + files = os.listdir(self.Controler.CTNPath()) + filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt") + moduleDataFile = open(filepath, 'w') + selectNum = self.SlotListBox.GetSelection() + selectStr = self.SlotListBox.GetString(selectNum) + self.SelectModule.pop(selectNum) + for (item, pos) in self.SelectModule: + moduleDataFile.write(item + " " + str(pos) + "\n") + slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0] + localModuleInfo.append(slotString) + self.SlotListBox.SetItems(localModuleInfo) #-------------------------------------------------------------------------------
# For EEPROM Access Main Panel
@@ -899,7 +1465,9 @@
self.Controler = controler
+ # PDI Type 1, 13 unknown Type, Fix Future self.PDIType = {0 :['none', '00000000'],
+ 1 :['unknown', '00000000'], 4 :['Digital I/O', '00000100'],
5 :['SPI Slave', '00000101'],
7 :['EtherCAT Bridge (port3)', '00000111'],
@@ -907,6 +1475,7 @@
9 :['uC async. 8bit', '00001001'],
10 :['uC sync. 16bit', '00001010'],
11 :['uC sync. 8bit', '00001011'],
+ 13 :['unknown', '00000000'], 16 :['32 Digtal Input and 0 Digital Output', '00010000'],
17 :['24 Digtal Input and 8 Digital Output', '00010001'],
18 :['16 Digtal Input and 16 Digital Output','00010010'],
@@ -944,8 +1513,9 @@
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)
+ # Check whether beremiz connected or not. + # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
if status is not "Started":
@@ -975,7 +1545,8 @@
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not.
- check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+ # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) self.SiiBinary = self.Controler.CommonMethod.LoadData()
@@ -1002,7 +1573,7 @@
cnt_pdi_type = self.PDIType[i][0]
for treelist, data in [("EEPROM Size (Bytes)",
str(self.Controler.CommonMethod.SmartViewInfosFromXML["eeprom_size"])),
@@ -1012,7 +1583,7 @@
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
# Device Identity: Vendor ID, Product Code, Revision No., Serial No.
for treelist, data in [("Vendor ID", self.Controler.CommonMethod.SmartViewInfosFromXML["vendor_id"]),
("Product Code", self.Controler.CommonMethod.SmartViewInfosFromXML["product_code"]),
("Revision No.", self.Controler.CommonMethod.SmartViewInfosFromXML["revision_no"]),
@@ -1020,18 +1591,18 @@
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
# Mailbox: Supported Mailbox, Bootstrap Configuration, Standard Configuration
for treelist, data in [("Supported Mailbox", self.Controler.CommonMethod.SmartViewInfosFromXML["supported_mailbox"]),
("Bootstrap Configuration", ""),
("Standard Configuration", "")]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)
- # Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+ # Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size for treelist, data in [("Receive Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outstart"]),
("Receive Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outlength"]),
("Send Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_instart"]),
("Send Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_inlength"])]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.BootstrapConfig[treelist], data, 1)
- # Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+ # 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"]),
@@ -1042,7 +1613,6 @@
Set data based on slave EEPROM.
- # sii_dict = { Parameter : (WordAddress, WordSize) }
sii_dict= { 'PDIControl' : ( '0', 1),
'PDIConfiguration' : ( '1', 1),
'PulseLengthOfSYNCSignals' : ( '2', 1),
@@ -1081,16 +1651,16 @@
cnt_pdi_type = self.PDIType[i][0]
device_emulation = str(bool(int("{:0>16b}".format(int(self.GetWordAddressData( sii_dict.get('PDIControl'),16 ), 16))[7])))
for treelist, data in [("EEPROM Size (Bytes)", eeprom_size),
("PDI Type", cnt_pdi_type),
("Device Emulation", device_emulation)]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
# Device Identity: Vendor ID, Product Code, Revision No., Serial No.
for treelist, data in [("Vendor ID", self.GetWordAddressData( sii_dict.get('VendorID'),16 )),
("Product Code", self.GetWordAddressData( sii_dict.get('ProductCode'),16 )),
("Revision No.", self.GetWordAddressData( sii_dict.get('RevisionNumber'),16 )),
@@ -1108,18 +1678,18 @@
if mailbox_data[protocol+2] == '1':
supported_mailbox += mailbox_protocol[protocol]
supported_mailbox = supported_mailbox.strip(", ")
for treelist, data in [("Supported Mailbox", supported_mailbox),
("Bootstrap Configuration", ""),
("Standard Configuration", "")]:
self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)
- # Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+ # 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)
- # Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+ # 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 )),
@@ -1190,31 +1760,31 @@
self.Root = self.Tree.AddRoot("")
for lv1 in ["Config Data", "Device Identity", "Mailbox"]:
self.Level1Nodes[lv1] = self.Tree.AppendItem(self.Root, lv1)
for lv2 in ["EEPROM Size (Bytes)", "PDI Type", "Device Emulation"]:
self.ConfigData[lv2] = self.Tree.AppendItem(self.Level1Nodes["Config Data"], lv2)
for lv2 in ["Vendor ID", "Product Code", "Revision No.", "Serial No."]:
self.DeviceIdentity[lv2] = self.Tree.AppendItem(self.Level1Nodes["Device Identity"], lv2)
for lv2 in ["Supported Mailbox", "Bootstrap Configuration", "Standard Configuration"]:
self.Mailbox[lv2] = self.Tree.AppendItem(self.Level1Nodes["Mailbox"], lv2)
- # Children of Bootstrap Configuration
+ # Children of Bootstrap Configuration self.BootstrapConfig = {}
for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
self.BootstrapConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Bootstrap Configuration"], lv3)
- # Children of Standard Configuration
+ # Children of Standard Configuration for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
self.StandardConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Standard Configuration"], lv3)
@@ -1292,7 +1862,8 @@
@param event : wx.EVT_BUTTON object
# Check whether beremiz connected or not.
- check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+ # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) # load from EEPROM data and parsing
self.SiiBinary = self.Controler.CommonMethod.LoadData()
@@ -1307,9 +1878,9 @@
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_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+ # Check whether beremiz connected or not. + # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
if status is not "Started":
@@ -1387,7 +1958,7 @@
wx.grid.Grid.__init__(self, parent, -1, size=(830,450),
- style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ style=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL) def SetValue(self, value):
@@ -1415,7 +1986,7 @@
self.SetCellAlignment(row, col, wx.ALIGN_LEFT, wx.ALIGN_CENTER)
- self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
+ self.SetCellAlignment(row, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER) self.SetReadOnly(row, col, True)
@@ -1428,10 +1999,10 @@
class RegisterAccessPanel(wx.Panel):
def __init__(self, parent, controler):
- @param parent: EEPROMAccessPanel object
- @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+ @param parent: EEPROMAccessPanel object + @param controler: _EthercatSlaveCTN class in EthercatSlave.py self.Controler = controler
@@ -1474,7 +2045,7 @@
- # main grid의 rows and cols
+ # main grid��rows and cols self.MainRow = [512, 512, 512, 512]
@@ -1483,7 +2054,7 @@
self.PageRange.append([512*index, 512*(index+1)])
- # Previous value of register data for register description configuration
+ # Previous value of register data for register description configuration self.PreRegSpec = {"ESCType": "",
@@ -1494,9 +2065,9 @@
Get data from the register.
self.Controler.CommonMethod.RegData = ""
- #ex : ethercat reg_read -p 0 0x0000 0x0001
+ # ex : ethercat reg_read -p 0 0x0000 0x0001 self.Controler.CommonMethod.RegData = self.Controler.CommonMethod.RegData + " " + self.Controler.CommonMethod.RegRead("0x"+"{:0>4x}".format(index*1024), "0x0400")
@@ -1709,7 +2280,8 @@
@param event: wx.EVT_BUTTON object
# Check whether beremiz connected or not.
- check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+ # If this method is called cyclically, set the cyclic flag true + check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False) @@ -1809,21 +2381,6 @@
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)
- def OnPageChanged(self, event):
- old = event.GetOldSelection()
- new = event.GetSelection()
- sel = self.GetSelection()
- def OnPageChanging(self, event):
- old = event.GetOldSelection()
- new = event.GetSelection()
- sel = self.GetSelection()
#-------------------------------------------------------------------------------
# For Register Access Notebook Panel
@@ -1900,20 +2457,19 @@
class RegisterMainTable(wx.grid.Grid):
def __init__(self, parent, row, col, controler):
- @param parent: RegisterNotebook object
- @param row, col: size of the table
- @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+ @param parent: RegisterNotebook object + @param row, col: size of the table + @param controler: _EthercatSlaveCTN class in EthercatSlave.py self.Controler = controler
self.RegisterAccessPanel = self.parent.parent.parent
wx.grid.Grid.__init__(self, parent, -1, size=(820,300),
- style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ style=wx.EXPAND|wx.ALIGN_CENTER_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),
@@ -1922,12 +2478,12 @@
def SetValue(self, parent, reg_monitor_data, low_index, high_index):
- Set the RegMonitorData into the main table.
- @param parent: RegisterNotebook object
- @param reg_monitor_data: data
- @param low_index: the lowest index of the page
- @param high_index: the highest index of the page
+ Set the RegMonitorData into the main table. + @param parent: RegisterNotebook object + @param reg_monitor_data: data + @param low_index: the lowest index of the page + @param high_index: the highest index of the page self.RegMonitorData = reg_monitor_data
# set label name and size
@@ -1950,16 +2506,16 @@
self.SetRowLabelValue(row, row_index[0])
for data_index in range(4):
self.SetCellValue(row, col, row_index[data_index+1])
- self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
+ self.SetCellAlignment(row, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER) self.SetReadOnly(row, col, True)
def OnSelectCell(self, event):
- Handles the event of the cell of the main table.
- @param event: gridlib object (left click)
+ Handles the event of the cell of the main table. + @param event: gridlib object (left click) # if reg_monitor_data is 0, it is initialization of register access.
if self.RegMonitorData == 0:
@@ -2051,9 +2607,9 @@
class RegisterSubTable(wx.grid.Grid):
def __init__(self, parent, row, col):
- @param parent: RegisterNotebook object
- @param row, col: size of the table
+ @param parent: RegisterNotebook object + @param row, col: size of the table @@ -2061,14 +2617,14 @@
wx.grid.Grid.__init__(self, parent, -1, size=(820,150),
- style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ style=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL) def SetValue(self, parent, data):
- Set the data into the subtable.
- @param parent: RegisterNotebook object
+ Set the data into the subtable. + @param parent: RegisterNotebook object # lset label name and size
Register_SubTable_Label = [(0, "Bits"), (1, "Name"),
(2, "Value"), (3, "Enum")]
@@ -2085,7 +2641,7 @@
self.SetCellValue(row, col, element)
- self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
+ self.SetCellAlignment(row, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER) self.SetReadOnly(row, col, True)
@@ -2099,97 +2655,107 @@
@param parent: wx.ScrollWindow object
- @Param controler: _EthercatSlaveCTN class in EthercatSlave.py
+ @Param controler: _EthercatCTN class in EthercatMaster.py - wx.Panel.__init__(self, parent, -1, (0, 0),
- size=wx.DefaultSize, style = wx.SUNKEN_BORDER)
+ wx.Panel.__init__(self, parent) self.Controler = controler
- # ----------------------- Main Sizer and Update Button --------------------------------------------
+ # ---------------------------- Main Sizer and Buttons -------------------------------------------- self.MasterStateSizer = {"main" : wx.BoxSizer(wx.VERTICAL)}
- ("innerMain", [1, 10, 2, 10]),
- ("innerTopHalf", [2, 10, 1, 10]),
- ("innerBottomHalf", [2, 10, 1, 10]),
+ ("innerTop", [2, 10, 1, 10]), + ("innerMiddle", [1, 10, 1, 10]), + ("innerBottom", [1, 10, 1, 10]), ("innerMasterState", [2, 10, 3, 10]),
("innerDeviceInfo", [4, 10, 3, 10]),
- ("innerFrameInfo", [4, 10, 5, 10])]:
+ ("innerFrameInfo", [4, 10, 5, 10]), + ("innerSlaveInfo", [1, 10, 2, 10])]: self.MasterStateSizer[key] = wx.FlexGridSizer(cols=attr[0], hgap=attr[1], rows=attr[2], vgap=attr[3])
- self.UpdateButton = wx.Button(self, label=_('Update'))
- self.UpdateButton.Bind(wx.EVT_BUTTON, self.OnButtonClick)
+ self.MSUpdateButton = wx.Button(self, label=_("Update")) + self.MSUpdateButton.Bind(wx.EVT_BUTTON, self.OnMSUpdateButtonClick) + self.SIUpdateButton = wx.Button(self, label=_("Update")) + self.SIUpdateButton.Bind(wx.EVT_BUTTON, self.OnSIUpdateButtonClick) - ('masterState', 'EtherCAT Master State'),
- ('deviceInfo', 'Ethernet Network Card Information'),
- ('frameInfo', 'Network Frame Information')]:
+ ("masterState", "EtherCAT Master State"), + ("deviceInfo", "Ethernet Network Card Information"), + ("frameInfo", "Network Frame Information"), + ("slaveInfo", "Slave Information")]: self.StaticBox[key] = wx.StaticBox(self, label=_(label))
self.MasterStateSizer[key] = wx.StaticBoxSizer(self.StaticBox[key])
# ----------------------- Master State -----------------------------------------------------------
- ('Slaves', 'Slave Count:')]:
+ ("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'])
+ self.MasterStateSizer["masterState"].AddSizer(self.MasterStateSizer["innerMasterState"]) # ----------------------- Ethernet Network Card Information ---------------------------------------
- ('Main', 'MAC Address:'),
- ('Link', 'Link State:'),
- ('Tx frames', 'Tx Frames:'),
- ('Rx frames', 'Rx Frames:'),
- ('Lost frames', 'Lost Frames:')]:
+ ("Main", "MAC Address:"), + ("Link", "Link State:"), + ("Tx frames", "Tx Frames:"), + ("Rx frames", "Rx Frames:"), + ("Lost frames", "Lost Frames:")]: self.StaticText[key] = wx.StaticText(self, label=_(label))
self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
- self.MasterStateSizer['innerDeviceInfo'].AddMany([self.StaticText[key], self.TextCtrl[key]])
+ self.MasterStateSizer["innerDeviceInfo"].AddMany([self.StaticText[key], self.TextCtrl[key]]) - self.MasterStateSizer['deviceInfo'].AddSizer(self.MasterStateSizer['innerDeviceInfo'])
+ 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]:'),
- ('Loss rate [1/s]', 'Loss Rate [1/s]:'),
- ('Frame loss [%]', 'Frame Loss [%]:')]:
+ ("Tx frame rate [1/s]", "Tx Frame Rate [1/s]:"), + ("Tx rate [KByte/s]", "Tx Rate [KByte/s]:"), + ("Rx frame rate [1/s]", "Rx Frame Rate [1/s]:"), + ("Rx rate [KByte/s]", "Rx Rate [KByte/s]:"), + ("Loss rate [1/s]", "Loss Rate [1/s]:"), + ("Frame loss [%]", "Frame Loss [%]:")]: self.StaticText[key] = wx.StaticText(self, label=_(label))
- self.MasterStateSizer['innerFrameInfo'].Add(self.StaticText[key])
+ self.MasterStateSizer["innerFrameInfo"].Add(self.StaticText[key]) - for index in ['0', '1', '2']:
+ 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["innerFrameInfo"].Add(self.TextCtrl[key][index]) + self.MasterStateSizer["frameInfo"].AddSizer(self.MasterStateSizer["innerFrameInfo"]) - self.MasterStateSizer['frameInfo'].AddSizer(self.MasterStateSizer['innerFrameInfo'])
+ # ------------------------------- Slave Information ----------------------------------------------- + self.SITreeListCtrl = SITreeListCtrl(self, self.Controler) + self.MasterStateSizer["innerSlaveInfo"].AddMany([self.SIUpdateButton, + self.MasterStateSizer["slaveInfo"].AddSizer( + self.MasterStateSizer["innerSlaveInfo"]) # --------------------------------- Main Sizer ----------------------------------------------------
+ self.MasterStateSizer["main"].Add(self.MSUpdateButton)
- 'masterState', 'deviceInfo']),
- 'innerTopHalf', 'innerBottomHalf'])]:
+ "masterState", "deviceInfo"]), + "innerTop", "innerMiddle", "innerBottom"])]: self.MasterStateSizer[key].AddSizer(self.MasterStateSizer[key2])
- self.MasterStateSizer['main'].AddSizer(self.UpdateButton)
- self.MasterStateSizer['main'].AddSizer(self.MasterStateSizer['innerMain'])
- self.SetSizer(self.MasterStateSizer['main'])
- def OnButtonClick(self, event):
+ self.SetSizer(self.MasterStateSizer["main"]) + def OnMSUpdateButtonClick(self, event): - Handle the event of the 'Update' button.
+ Handle the event of the "Update" button. Update the data of the master state.
@param event: wx.EVT_BUTTON object
@@ -2203,5 +2769,821 @@
self.TextCtrl[key][index].SetValue(self.MasterState[key][int(index)])
self.TextCtrl[key].SetValue(self.MasterState[key][0])
+ self.Controler.CommonMethod.CreateErrorDialog('PLC not connected!') + def OnSIUpdateButtonClick(self, event): + Handle the event of the radio box in the slave information + @param event: wx.EVT_RADIOBOX object + if self.Controler.GetCTRoot()._connector is not None: + self.SITreeListCtrl.UpdateSI() self.Controler.CommonMethod.CreateErrorDialog('PLC not connected!')
+#------------------------------------------------------------------------------- +# For Slave Information Panel +#------------------------------------------------------------------------------- +class SITreeListCtrl(wx.Panel): + EC_Addrs = ["0x0300", "0x0302", "0x0304", "0x0306", "0x0301", "0x0303", "0x0305", + "0x0307", "0x0308", "0x0309", "0x030A", "0x030B", "0x030C", "0x030D", + "0x0310", "0x0311", "0x0312", "0x0313", "0x0442", "0x0443"] + def __init__(self, parent, controler): + @param parent: Reference to the MasterStatePanel class + @param Controler: _EthercatCTN class in EthercatMaster.py + wx.Panel.__init__(self, parent, -1, size=wx.Size(750, 350)) + self.Controler=controler + self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=wx.Size(750,350), + style=wx.TR_HAS_BUTTONS + |wx.TR_FULL_ROW_HIGHLIGHT) + self.Tree.AddColumn(label, width=width) + self.Tree.SetMainColumn(0) + Update the data of the slave information. + position, not_used, state, not_used, name = range(5) + # get slave informations (name, position, state) + slaves_infos = self.Controler.CommonMethod.GetSlaveStateFromSlave() + slave_info_lines = slaves_infos.splitlines() + for line in slave_info_lines: + slave_info_list.append(line.split(None,4)) + slave_num = len(slave_info_lines) + for ec in self.EC_Addrs: + reg_info.append(ec + ",0x001") + # get error counts of slaves + err_count_list = self.Controler.CommonMethod.MultiRegRead(slave_num, reg_info) + self.Tree.DeleteAllItems() + root = self.Tree.AddRoot("") + for slave_idx in range(slave_num): + slave_node = self.Tree.AppendItem(root, "") + # set name, postion, state + for info_idx in [name, position, state]: + self.Tree.SetItemText(slave_node, + slave_info_list[slave_idx][info_idx], col_num) + # set error counter's name and default value + for ec, sub_ecs in [("Port Error Counters 0/1/2/3",[ + "Invaild Frame Counter 0/1/2/3", + "RX Error Counter 0/1/2/3"]), + ("Forward RX Error Counter 0/1/2/3", []), + ("ECAT Processing Unit Error Counter", []), + ("PDI Error Counter", []), + ("Lost Link Counter 0/1/2/3", []), + ("Watchdog Counter Process Data", []), + ("Watchdog Counter PDI", [])]: + tree_node = self.Tree.AppendItem(slave_node, "%s" % ec) + if ec_name.find("0/1/2/3") > 0: + err_count = [0, 0, 0, 0] + error_counter[(ec_idx, ec_sub_idx)] = { + "tree_node": tree_node, + "num_ports": num_ports, + "err_count": err_count} + tree_node = self.Tree.AppendItem(\ + error_counter[(ec_idx, 0)]["tree_node"], + if ec_name.find("0/1/2/3") > 0: + err_count = [0, 0, 0, 0] + error_counter[(ec_idx, ec_sub_idx)] = { + "tree_node": tree_node, + "num_ports": num_ports, + "err_count": err_count} + for port_num in range(num_ports): + error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] += \ + int(err_count_list[ec_list_idx].split(",")[2], 16) + error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] = -1 + for port_num in range(num_ports): + for sub_idx in range(1, ec_sub_idx+1): + err_sum += error_counter[(ec_idx, sub_idx)]\ + ["err_count"][port_num] + error_counter[(ec_idx, 0)]["err_count"][port_num] = err_sum + for port_num in range(num_ports): + error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] += \ + int(err_count_list[ec_list_idx].split(",")[2], 16) + error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] = -1 + # set texts in "error" column. + ec_info_list = error_counter.items() + for (idx, sub_idx), ec_info in ec_info_list: + for port_num in range(ec_info["num_ports"]): + if ec_info["err_count"][port_num] != 0: + err_checker = "occurred" + if ec_info["err_count"][port_num] < 0: + ec_text = "reg I/O error" + ec_text = ec_text + "%d/" % ec_info["err_count"][port_num] + ec_text = ec_text.strip("/") + self.Tree.SetItemText(ec_info["tree_node"], ec_text, col_num) + self.Tree.SetItemText(slave_node, err_checker, col_num) +class DCConfigPanel(wx.Panel): + def __init__(self, parent, controler): + @param parent: Reference to the MasterStatePanel class + @param Controler: _EthercatCTN class in EthercatMaster.py + wx.Panel.__init__(self, parent, -1, size=wx.Size(750, 350)) + self.Controler = controler + self.ESI_DC_Data = self.Controler.CommonMethod.LoadESIData() + # initialize SlaveStatePanel UI dictionaries + self.StaticTextDic = {} + self.RadioButtonDic = {} + OperationModeComboList = [] + Sync1CycleComboList = [] + for ESI_Data in self.ESI_DC_Data: + OperationModeComboList.append(ESI_Data["desc"]) + UnitComboList = [ "/100", "/ 50", "/ 40", "/ 30", "/ 25", "/ 20", "/16", + "/ 10", "/ 8", "/ 5", "/ 4", "/ 3", "/ 2", "x 1", "x 2", "x 3", "x 4", + "x 5", "x 8", "x 10", "x 16", "x 20", "x 25", "x 30", "x 40", "x 50", + UnitComboListPlus = [ "/100", "/ 50", "/ 40", "/ 30", "/ 25", "/ 20", "/16", + "/ 10", "/ 8", "/ 5", "/ 4", "/ 3", "/ 2", "x 0", "x 1", "x 2", "x 3", + "x 4", "x 5", "x 8", "x 10", "x 16", "x 20", "x 25", "x 30", "x 40", + Sync1CycleComboList.append("x " + str(i + 1)) + # iniitalize BoxSizer and FlexGridSizer + "DCConfig_main_sizer" : wx.BoxSizer(wx.VERTICAL), + "DCConfig_inner_main_sizer" : wx.FlexGridSizer(cols=1, hgap=50, rows=2, vgap=10), + "CyclicMode_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5), + "SyncMode_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5), + "OperationMode_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=100, rows=2, vgap=10), + "CheckEnable_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10), + "Sync0_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=15, rows=3, vgap=10), + "Sync0_CycleTimeSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=2, vgap=5), + "Sync0_ShiftTimeSizer" : wx.FlexGridSizer(cols=2, hgap=20, rows=2, vgap=5), + "Sync1_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=15, rows=3, vgap=10), + "Sync1_CycleTimeSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=2, vgap=5), + "Sync1_ShiftTimeSizer" : wx.FlexGridSizer(cols=2, hgap=20, rows=2, vgap=5) + # initialize StaticBox and StaticBoxSizer + for box_name, box_label in [ + ("CyclicModeBox", "Cyclic Mode"), + ("Sync0CycleTimeBox", "Cycle Time (us):"), + ("Sync0ShiftTimeBox", "Shift Time (us):"), + ("Sync1CycleTimeBox", "Cycle Time (us):"), + ("Sync1ShiftTimeBox", "Shift Time (us):") + self.StaticBoxDic[box_name] = wx.StaticBox(self, label=_(box_label)) + self.SizerDic[box_name] = wx.StaticBoxSizer(self.StaticBoxDic[box_name]) + for statictext_name, statictext_label in [ + ("MainLabel", "Distributed Clock"), + ("OperationModeLabel", "Operation Mode:"), + ("SyncUnitCycleLabel", "Sync Unit Cycle (us)"), + ("Sync0ShiftTimeUserDefinedLabel", "User Defined"), + ("Sync1ShiftTimeUserDefinedLabel", "User Defined"), + self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label)) + ("Sync0CycleTimeUserDefined_Ctl"), + ("Sync0ShiftTimeUserDefined_Ctl"), + ("Sync1CycleTimeUserDefined_Ctl"), + ("Sync1ShiftTimeUserDefined_Ctl"), + self.TextCtrlDic[textctl_name] = wx.TextCtrl( + self, size=wx.Size(130, 24), style=wx.TE_READONLY) + for checkbox_name, checkbox_label in [ + ("DCEnable", "Enable"), + ("Sync0Enable", "Enable Sync0"), + ("Sync1Enable", "Enable Sync1") + self.CheckBoxDic[checkbox_name] = wx.CheckBox(self, -1, checkbox_label) + for combobox_name, combobox_list, size in [ + ("OperationModeChoice", OperationModeComboList, 250), + ("Sync0UnitCycleChoice", UnitComboList, 130), + ("Sync1UnitCycleChoice", UnitComboList, 130) + self.ComboBoxDic[combobox_name] = wx.ComboBox(self, size=wx.Size(size, 24), + choices = combobox_list, style = wx.CB_DROPDOWN | wx.CB_READONLY) + for radiobutton_name, radiobutton_label in [ + ("Sync0CycleTimeUnitRadioButton", "Sync Unit Cycle"), + ("Sync0CycleTimeUserDefinedRadioButton", "User Defined"), + ("Sync1CycleTimeUnitRadioButton", "Sync Unit Cycle"), + ("Sync1CycleTimeUserDefinedRadioButton", "User Defined") + self.RadioButtonDic[radiobutton_name] = wx.RadioButton( + self, label = radiobutton_label, style = wx.RB_SINGLE) + self.ApplyButton = wx.Button(self, label="Apply") + self.Bind(wx.EVT_CHECKBOX, self.CheckDCEnable, self.CheckBoxDic["DCEnable"]) + #self.Bind(wx.EVT_COMBOBOX, self.SelectOperationMode, self.ComboBoxDic["OperationModeChoice"]) + #self.Bind(wx.EVT_COMBOBOX, self.SelectUnitCycle, self.ComboBoxDic["Sync0UnitChoice"]) + self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync0CycleTime, + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"]) + self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync0CycleTime, + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"]) + self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync1CycleTime, + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"]) + self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync1CycleTime, + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"]) + self.Bind(wx.EVT_CHECKBOX, self.CheckSync0Enable, self.CheckBoxDic["Sync0Enable"]) + self.Bind(wx.EVT_CHECKBOX, self.CheckSync1Enable, self.CheckBoxDic["Sync1Enable"]) + self.Bind(wx.EVT_BUTTON, self.OnClickApplyButton, self.ApplyButton) + # sync1 shifttime box contents + self.SizerDic["Sync1_ShiftTimeSizer"].AddMany([ + self.StaticTextDic["Sync1ShiftTimeUserDefinedLabel"], + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"] + self.SizerDic["Sync1ShiftTimeBox"].Add(self.SizerDic["Sync1_ShiftTimeSizer"]) + # sync1 cycletime box contents + self.SizerDic["Sync1_CycleTimeSizer"].AddMany([ + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"], + self.ComboBoxDic["Sync1UnitCycleChoice"], + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"], + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"] + self.SizerDic["Sync1CycleTimeBox"].Add(self.SizerDic["Sync1_CycleTimeSizer"]) + self.SizerDic["Sync1_InnerSizer"].AddMany([ + self.CheckBoxDic["Sync1Enable"], self.SizerDic["Sync1CycleTimeBox"], + self.SizerDic["Sync1ShiftTimeBox"] + self.SizerDic["Sync1Box"].Add(self.SizerDic["Sync1_InnerSizer"]) + # sync0 shifttime box contents + self.SizerDic["Sync0_ShiftTimeSizer"].AddMany([ + self.StaticTextDic["Sync0ShiftTimeUserDefinedLabel"], + self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"] + self.SizerDic["Sync0ShiftTimeBox"].Add(self.SizerDic["Sync0_ShiftTimeSizer"]) + # sync0 cycletime box contents + self.SizerDic["Sync0_CycleTimeSizer"].AddMany([ + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"], + self.ComboBoxDic["Sync0UnitCycleChoice"], + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"], + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"] + self.SizerDic["Sync0CycleTimeBox"].Add(self.SizerDic["Sync0_CycleTimeSizer"]) + self.SizerDic["Sync0_InnerSizer"].AddMany([ + self.CheckBoxDic["Sync0Enable"], self.SizerDic["Sync0CycleTimeBox"], + self.SizerDic["Sync0ShiftTimeBox"] + self.SizerDic["Sync0Box"].Add(self.SizerDic["Sync0_InnerSizer"]) + self.SizerDic["SyncMode_InnerSizer"].AddMany([ + self.SizerDic["Sync0Box"], self.SizerDic["Sync1Box"] + self.SizerDic["CheckEnable_InnerSizer"].AddMany([ + self.StaticTextDic["SyncUnitCycleLabel"], + self.TextCtrlDic["SyncUnitCycle_Ctl"] + self.SizerDic["OperationMode_InnerSizer"].AddMany([ + self.StaticTextDic["OperationModeLabel"], + self.ComboBoxDic["OperationModeChoice"], + self.CheckBoxDic["DCEnable"], self.SizerDic["CheckEnable_InnerSizer"] + self.SizerDic["CyclicMode_InnerSizer"].AddMany([ + self.SizerDic["OperationMode_InnerSizer"], + self.SizerDic["SyncMode_InnerSizer"] + self.SizerDic["CyclicModeBox"].Add(self.SizerDic["CyclicMode_InnerSizer"]) + self.SizerDic["DCConfig_inner_main_sizer"].AddMany([ + self.StaticTextDic["MainLabel"], self.ApplyButton, + self.SizerDic["CyclicModeBox"] + self.SizerDic["DCConfig_main_sizer"].Add(self.SizerDic["DCConfig_inner_main_sizer"]) + self.SetSizer(self.SizerDic["DCConfig_main_sizer"]) + self.LoadProjectDCData() + def UIOnOffSet(self, activate): + for object in self.RadioButtonDic: + self.RadioButtonDic[object].Enable() + for object in self.ComboBoxDic: + if object == "OperationModeChoice": + self.ComboBoxDic[object].Enable() + for object in self.TextCtrlDic: + if object in ["SyncUnitCycle_Ctl", "InputReference_Ctl"]: + self.TextCtrlDic[object].Enable() + for object in self.CheckBoxDic: + if object == "DCEnable": + self.CheckBoxDic[object].Enable() + # initial set or DC enable uncheck + for object in self.RadioButtonDic: + self.RadioButtonDic[object].Disable() + for object in self.ComboBoxDic: + if object == "OperationModeChoice": + self.ComboBoxDic[object].Disable() + for object in self.TextCtrlDic: + if object == "SyncUnitCycle_Ctl": + self.TextCtrlDic[object].Disable() + for object in self.CheckBoxDic: + if object == "DCEnable": + self.CheckBoxDic[object].Disable() + for data in self.ESI_DC_Data: + index = self.Controler.ExtractHexDecValue(data["assign_activate"]) + config_name = data["desc"] + self.ComboBoxDic["OperationModeChoice"].SetStringSelection(config_name) + def CheckSync0Enable(self, evt): + self.ComboBoxDic["Sync0UnitCycleChoice"].Enable() + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].Enable() + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].Enable() + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Enable() + self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].Enable() + self.ComboBoxDic["Sync0UnitCycleChoice"].Disable() + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].Disable() + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].Disable() + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable() + self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].Disable() + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False) + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False) + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue("") + self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue("") + def CheckSync1Enable(self, evt): + self.ComboBoxDic["Sync1UnitCycleChoice"].Enable() + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Enable() + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Enable() + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Enable() + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Enable() + self.ComboBoxDic["Sync1UnitCycleChoice"].Disable() + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable() + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable() + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable() + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable() + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False) + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False) + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue("") + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue("") + def CheckDCEnable(self, evt): + task_cycle_ns = self.GetInterval(ns_mode) + sync0_cycle_factor = None + sync1_cycle_factor = None + #task_cycle_ns = self.Controler.GetCTRoot()._Ticktime + if (task_cycle_ns > 0): + self.UIOnOffSet(evt.GetInt()) + # default select DC enable sync0 + config_name = self.ESI_DC_Data[default_list_num]["desc"] + assign_act = self.ESI_DC_Data[default_list_num]["assign_activate"] + sync0_cycle_time_ns = self.ESI_DC_Data[default_list_num]["cycletime_sync0"] + if sync0_cycle_time_ns == 0 : + sync0_cycle_factor = self.ESI_DC_Data[default_list_num]["cycletime_sync0_factor"] + sync0_shift_time_ns = self.ESI_DC_Data[default_list_num]["shifttime_sync0"] + sync1_cycle_time_ns = self.ESI_DC_Data[default_list_num]["cycletime_sync1"] + if sync1_cycle_time_ns == 0 : + sync1_cycle_factor = self.ESI_DC_Data[default_list_num]["cycletime_sync1_factor"] + sync1_shift_time_ns = self.ESI_DC_Data[default_list_num]["shifttime_sync1"] + cal_assign_act = self.Controler.ExtractHexDecValue(assign_act) + sync0_cycle_time_us = str(int(sync0_cycle_time_ns) / 1000) + sync0_shift_time_us = str(int(sync0_shift_time_ns) / 1000) + sync1_cycle_time_us = str(int(sync1_cycle_time_ns) / 1000) + sync1_shift_time_us = str(int(sync1_shift_time_ns) / 1000) + task_cycle_to_us = str(int(task_cycle_ns) / 1000) + if cal_assign_act == 768: + # Disable About Sync1 Objects + self.CheckBoxDic["Sync1Enable"].SetValue(False) + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable() + self.ComboBoxDic["Sync1UnitCycleChoice"].Disable() + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable() + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable() + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable() + self.CheckBoxDic["Sync1Enable"].SetValue(True) + if sync1_cycle_factor is not None: + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(True) + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False) + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable() + self.SetSyncUnitCycle(sync1_cycle_factor, + self.ComboBoxDic["Sync1UnitCycleChoice"]) + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False) + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(True) + self.ComboBoxDic["Sync1UnitCycleChoice"].Disable() + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue(sync1_cycle_time_us) + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue(sync1_shift_time_us) + self.CheckBoxDic["Sync0Enable"].SetValue(True) + if sync0_cycle_factor is not None: + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(True) + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False) + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable() + self.SetSyncUnitCycle(sync0_cycle_factor, + self.ComboBoxDic["Sync0UnitCycleChoice"]) + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False) + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(True) + self.ComboBoxDic["Sync0UnitCycleChoice"].Disable() + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue(sync0_cycle_time_us) + self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue(sync0_shift_time_us) + self.ComboBoxDic["OperationModeChoice"].SetStringSelection(config_name) + self.TextCtrlDic["SyncUnitCycle_Ctl"].SetValue(task_cycle_to_us) + self.CheckBoxDic["Sync0Enable"].SetValue(False) + self.CheckBoxDic["Sync1Enable"].SetValue(False) + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False) + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False) + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False) + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False) + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue("") + self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue("") + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue("") + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue("") + #error_str = "DC Enable is not possble, please set task interval" + error_str = "Can't Set DC Enable" + self.Controler.CommonMethod.CreateErrorDialog(error_str) + def SetSyncUnitCycle(self, factor, object): + # factor > 0 ==> * factor, factor < 0 ==> / factor + factor_to_int = int(factor) + lists = object.GetStrings() + temp = token.split(" ") + if (temp[0] == "x") and (int(temp[1]) == factor_to_int): + object.SetStringSelection(token) + lists = object.GetStrings() + temp = token.split(" ") + if (temp[0] == "/") and (int(temp[1]) == factor_to_int): + object.SetStringSelection(token) + def GetInterval(self, mode): + project_infos = self.Controler.GetCTRoot().GetProjectInfos() + for project_info_list in project_infos["values"]: + if project_info_list["name"] == "Resources" : + token = project_info_list["values"][0]["tagname"] + tasks, instances = self.Controler.GetCTRoot().GetEditedResourceInfos(token) + task_cycle_ns = self.ParseTime(tasks[0]["Interval"]) + task_cycle_us = int(task_cycle_ns) / 1000 + # mode == 1 ==> return ns + # mode == 2 ==> return us + return str(task_cycle_us) + def ParseTime(self, input): + # input example : 't#1ms' + # temp.split('#') -> ['t', '1ms'] + temp = input.split('#') + if temp[1][-2:] == "ms": + # convert nanosecond unit + result = int(temp[1][:-2]) * 1000000 + elif temp[1][-2:] == "us": + result = int(temp[1][:-2]) * 1000 + def SelectSync0CycleTime(self, evt): + selected_object = evt.GetEventObject() + if selected_object.GetLabel() == "User Defined" : + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False) + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Enable() + self.ComboBoxDic["Sync0UnitCycleChoice"].Disable() + elif selected_object.GetLabel() == "Sync Unit Cycle" : + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False) + self.ComboBoxDic["Sync0UnitCycleChoice"].Enable() + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable() + def SelectSync1CycleTime(self, evt): + selected_object = evt.GetEventObject() + if selected_object.GetLabel() == "User Defined" : + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False) + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Enable() + self.ComboBoxDic["Sync1UnitCycleChoice"].Disable() + elif selected_object.GetLabel() == "Sync Unit Cycle" : + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False) + self.ComboBoxDic["Sync1UnitCycleChoice"].Enable() + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable() + def GetCycle(self, period, section): + temp = section.split(" ") + result = int(period) * int(temp[1]) + result = int(period) / int(temp[1]) + def OnClickApplyButton(self, evt): + dc_enable = self.CheckBoxDic["DCEnable"].GetValue() + dc_desc = self.ComboBoxDic["OperationModeChoice"].GetStringSelection() + dc_assign_activate = self.ESI_DC_Data[0]["assign_activate"] + dc_assign_activate_mod = dc_assign_activate.split('x')[1] + if self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].GetValue(): + temp = self.ComboBoxDic["Sync0UnitCycleChoice"].GetStringSelection() + dc_sync0_cycle = "1_" + str(self.GetCycle(self.GetInterval(us_mode), temp)) + elif self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].GetValue(): + dc_sync0_cycle = "2_" + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].GetValue() + if self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].GetValue(): + temp = self.ComboBoxDic["Sync1UnitCycleChoice"].GetStringSelection() + dc_sync1_cycle = "1_" + self.GetCycle(self.GetInterval(us_mode), temp) + elif self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].GetValue(): + dc_sync1_cycle = "2_" + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].GetValue() + dc_sync0_shift = self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].GetValue() + dc_sync1_shift = self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].GetValue() + self.Controler.BaseParams.setDC_Enable(dc_enable) + self.Controler.BaseParams.setDC_Desc(dc_desc) + self.Controler.BaseParams.setDC_Assign_Activate(dc_assign_activate_mod) + self.Controler.BaseParams.setDC_Sync0_Cycle_Time(dc_sync0_cycle) + self.Controler.BaseParams.setDC_Sync0_Shift_Time(dc_sync0_shift) + self.Controler.BaseParams.setDC_Sync1_Cycle_Time(dc_sync1_cycle) + self.Controler.BaseParams.setDC_Sync1_Shift_Time(dc_sync1_shift) + project_infos = self.Controler.GetCTRoot().CTNRequestSave() + def GetSymbol(self, period, cycle): + result = "x " + str(temp) + result = "/ " + str(temp) + def SetSyncCycle(self, period, sync0_cycle, sync1_cycle): + if sync0_cycle != "None": + self.CheckBoxDic["Sync0Enable"].SetValue(True) + temp = sync0_cycle.split("_") + symbol = self.GetSymbol(period, temp[1]) + self.ComboBoxDic["Sync0UnitCycleChoice"].SetStringSelection(symbol) + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable() + self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(True) + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue(temp[1]) + self.ComboBoxDic["Sync0UnitCycleChoice"].Disable() + self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(True) + if sync1_cycle != "None": + self.CheckBoxDic["Sync1Enable"].SetValue(True) + temp = sync1_cycle.split("_") + symbol = self.GetSymbol(period, temp[1]) + self.ComboBoxDic["Sync1UnitChoice"].SetStringSelection(symbol) + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable() + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(True) + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue(temp[1]) + self.ComboBoxDic["Sync1UnitChoice"].Disable() + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(True) + def LoadProjectDCData(self): + task_cycle_ns = self.GetInterval(ns_mode) + task_cycle_to_us = int(task_cycle_ns) / 1000 + dc_enable = self.Controler.BaseParams.getDC_Enable() + dc_desc = self.Controler.BaseParams.getDC_Desc() + dc_assign_activate = self.Controler.BaseParams.getDC_Assign_Activate() + dc_sync0_cycle = self.Controler.BaseParams.getDC_Sync0_Cycle_Time() + dc_sync0_shift = self.Controler.BaseParams.getDC_Sync0_Shift_Time() + dc_sync1_cycle = self.Controler.BaseParams.getDC_Sync1_Cycle_Time() + dc_sync1_shift = self.Controler.BaseParams.getDC_Sync1_Shift_Time() + self.UIOnOffSet(dc_enable) + self.CheckBoxDic["DCEnable"].SetValue(dc_enable) + self.ComboBoxDic["OperationModeChoice"].SetStringSelection(dc_desc) + self.TextCtrlDic["SyncUnitCycle_Ctl"].SetValue(str(task_cycle_to_us)) + self.SetSyncCycle(str(task_cycle_to_us), dc_sync0_cycle, dc_sync1_cycle) + if dc_sync0_shift != "None": + self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue(dc_sync0_shift) + if dc_sync1_shift != "None": + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue(dc_sync1_shift) + if dc_assign_activate == "300": + self.CheckBoxDic["Sync1Enable"].SetValue(False) + self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable() + self.ComboBoxDic["Sync1UnitCycleChoice"].Disable() + self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable() + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable() + self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable() --- a/etherlab/EthercatCFileGenerator.py Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/EthercatCFileGenerator.py Wed Nov 20 16:57:15 2019 +0100
@@ -68,6 +68,38 @@
+SLAVE_OUTPUT_PDO_DEFAULT_VALUE_BIT = """ + uint8_t value[%(data_size)d]; + if (ecrt_master_sdo_upload(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &result_size, &abort_code)) { + SLOGF(LOG_CRITICAL, "EtherCAT failed to get default value for output PDO in slave %(device_type)s at alias %(alias)d and position %(position)d. Error: %%ud", abort_code); + %(real_var)s = EC_READ_%(data_type)s((uint8_t *)value, %(subindex)d); +SLAVE_INPUT_PDO_DEFAULT_VALUE = """ + uint8_t value[%(data_size)d]; + if (ecrt_master_sdo_upload(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &result_size, &abort_code)) { + SLOGF(LOG_CRITICAL, "EtherCAT failed to get default value for input PDO in slave %(device_type)s at alias %(alias)d and position %(position)d. Error: %%ud", abort_code); + %(real_var)s = EC_READ_%(data_type)s((uint8_t *)value); +#define DC_ENABLE %(dc_flag)d + ecrt_slave_config_dc (slave%(slave)d, 0x0%(assign_activate)ld, %(sync0_cycle_time)d, %(sync0_shift_time)d, %(sync1_cycle_time)d, %(sync1_shift_time)d); def ConfigureVariable(entry_infos, str_completion):
entry_infos["data_type"] = DATATYPECONVERSION.get(entry_infos["var_type"], None)
if entry_infos["data_type"] is None:
@@ -167,7 +199,6 @@
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')
@@ -184,10 +215,15 @@
"pdos_configuration_declaration": "",
"slaves_declaration": "",
"slaves_configuration": "",
+ "slaves_input_pdos_default_values_extraction": "", "slaves_output_pdos_default_values_extraction": "",
"slaves_initialization": "",
"retrieve_variables": [],
+ #-----------This Code templete for dc -------------------# # Initialize variable storing variable mapping state
@@ -199,6 +235,9 @@
# Initialize dictionary storing alias auto-increment position values
# Generating code for each slave
for (slave_idx, slave_alias, slave) in self.Slaves:
@@ -221,6 +260,7 @@
# Extract slave device object dictionary entries
device_entries = device.GetEntriesList()
+ #device_entries = self.Controler.CTNParent.GetEntriesList() # Adding code for declaring slave in master code template strings
for element in ["vendor", "product_code", "revision_number"]:
@@ -230,15 +270,17 @@
# 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
# init commands when initializing slave in master code template strings
for initCmd in device_coe.getInitCmd():
"Index": ExtractHexDecValue(initCmd.getIndex()),
"Subindex": ExtractHexDecValue(initCmd.getSubIndex()),
- "Value": initCmd.getData().getcontent()})
+ #"Value": initCmd.getData().getcontent()}) + "Value": int(initCmd.getData().text, 16)}) initCmds.extend(slave.getStartupCommands())
@@ -264,11 +306,11 @@
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:
+ #if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 and PdoConfig and PdoAssign: + if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 or device.getSlots() is not None: 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": [],
@@ -304,28 +346,122 @@
- for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
- [(pdo, "Outputs") for pdo in device.getRxPdo()]):
+ if len(device.getTxPdo() + device.getRxPdo()) > 0: + for pdo in device.getTxPdo(): + PdoData.append((pdo, "Inputs")) + for pdo in device.getRxPdo(): + PdoData.append((pdo, "Outputs")) + #for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] + + # [(pdo, "Outputs") for pdo in device.getRxPdo()]): + #for pdo, pdo_type in (TxPdoData + RxPdoData): + data_files = os.listdir(self.Controler.CTNPath()) + RxPDOData = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getRxPDO() + TxPDOData = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getTxPDO() + PDOList = RxPDOData.split() + TxPDOData.split() + for PDOIndex in PDOList: + if PDOIndex in ["RxPDO", "TxPDO", "None"]: + PDODataList.append(int(PDOIndex, 0)) + # add jblee for DC Configuration + dc_enable = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Enable() + sync0_cycle_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync0_Cycle_Time() + if sync0_cycle_token != "None": + sync0_cycle_time = int(sync0_cycle_token.split("_")[1]) * 1000 + sync0_shift_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync0_Shift_Time() + if sync0_shift_token != "None": + sync0_shift_time = int(sync0_shift_token) * 1000 + sync1_cycle_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync1_Cycle_Time() + if sync1_cycle_token != "None": + sync1_cycle_time = int(sync1_cycle_token.split("_")[1]) * 1000 + sync1_shift_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync1_Shift_Time() + if sync1_shift_token != "None": + sync1_shift_time = int(sync1_shift_token) * 1000 + "assign_activate" : int(self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Assign_Activate()), + "sync0_cycle_time" : sync0_cycle_time, + "sync0_shift_time" : sync0_shift_time, + "sync1_cycle_time" : sync1_cycle_time, + "sync1_shift_time" : sync1_shift_time, + if dc_enable and not str_completion["dc_variable"] : + str_completion["dc_variable"] += DC_VARIABLE % {"dc_flag" : dc_enable} + str_completion["config_dc"] += CONFIG_DC % dc_config_data + for data_file in data_files: + slave_path = os.path.join(self.Controler.CTNPath(), data_file) + if os.path.isdir(slave_path): + CheckConfNodePath = os.path.join(slave_path, "baseconfnode.xml") + confNodeFile = open(CheckConfNodePath, 'r') + checklines = confNodeFile.readlines() + # checklines(ex) : <BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="EthercatSlave_0"/> + # checklines[1].split() : [<BaseParams, xmlns:xsd="http://www.w3.org/2001/XMLSchema", + # IEC_Channel="0", Name="EthercatSlave_0"/>] + # checklines[1].split()[2] : IEC_Channel="0" + # checklines[1].split()[2].split("\"") = [IEC_Channel=, 0, ] + pos_check = int(checklines[1].split()[2].split("\"")[1]) + if slave_idx == pos_check: + MDPDataFilePath = os.path.join(slave_path, "DataForMDP.txt") + if os.path.isfile(MDPDataFilePath): + MDPDataFile = open(MDPDataFilePath, 'r') + MDPData = MDPDataFile.readlines() + for MDPLine in MDPData: + module_pos = int(MDPLine.split()[-1]) + module = self.Controler.CTNParent.GetSelectModule(module_pos) + for pdo in module.getTxPdo(): + PdoData.append((pdo, "Inputs")) + PDODataList.append(ExtractHexDecValue(pdo.getIndex().getcontent())) + for pdo in module.getRxPdo(): + PdoData.append((pdo, "Outputs")) + PDODataList.append(ExtractHexDecValue(pdo.getIndex().getcontent())) + for pdo, pdo_type in PdoData: pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
pdos_index.append(pdo_index)
+ if PDODataList and (pdo_index in PDODataList): 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), [])
+ exclusion_scope = exclusive_pdos.setdefault(tuple(exclusion_list), []) "assigned": pdo.getSm() is not None
exclusion_scope.append(pdo_mapping_match)
@@ -352,30 +488,57 @@
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()]):
- entries = pdo.getEntry()
+ #for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] + + # [(pdo, "Outputs") for pdo in device.getRxPdo()]): + #for pdo, pdo_type in (TxPdoData + RxPdoData): + for pdo, pdo_type in PdoData: + entries = pdo.getEntry() pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
if pdo_index in excluded_pdos:
- pdo_needed = pdo_index in selected_pdos
+ if PDODataList and (pdo_index not in PDODataList):
+ #pdo_needed = pdo_index in selected_pdos + pdo_needed = pdo_index in PDODataList + pdo_index += index_padding index = ExtractHexDecValue(entry.getIndex().getcontent())
subindex = ExtractHexDecValue(entry.getSubIndex())
+ increse = self.Controler.CTNParent.GetMDPInfos(type_infos) + if increse and index != 0: + index += int(increse[0][2]) * slotNumber "name": ExtractName(entry.getName()),
"bitlen": entry.getBitLen(),
entry_infos.update(type_infos)
+ #temp_data = " {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos + check_data = "{0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}" % entry_infos + if entry_check_list and check_data in entry_check_list: + if (entry_infos["index"] == 0) or (entry_infos["name"] == None): entries_infos.append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
+ entry_check_list.append(check_data) entry_declaration = slave_variables.get((index, subindex), None)
if entry_declaration is not None and not entry_declaration["mapped"]:
@@ -399,7 +562,7 @@
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()
@@ -409,16 +572,34 @@
entry_infos["real_var"] = "slave%(slave)d_%(index).4x_%(subindex).2x_default" % entry_infos
ConfigureVariable(entry_infos, str_completion)
+ if entry_infos["data_type"] == "BIT" : + str_completion["slaves_output_pdos_default_values_extraction"] += \ + SLAVE_OUTPUT_PDO_DEFAULT_VALUE_BIT % entry_infos + str_completion["slaves_output_pdos_default_values_extraction"] += \ + SLAVE_OUTPUT_PDO_DEFAULT_VALUE % entry_infos + elif pdo_type == "Inputs" and entry.getDataType() is not None and device_coe is not None: + data_type = entry.getDataType().getcontent() + entry_infos["dir"] = "I" + entry_infos["data_size"] = max(1, entry_infos["bitlen"] / 8) + 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 - str_completion["slaves_output_pdos_default_values_extraction"] += \
- SLAVE_OUTPUT_PDO_DEFAULT_VALUE % entry_infos
+ ConfigureVariable(entry_infos, str_completion) + str_completion["slaves_input_pdos_default_values_extraction"] += \ + SLAVE_INPUT_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,7 +607,7 @@
raise ValueError, _("No sync manager available for %s pdo!") % pdo_type
sync_managers[sm]["pdos_number"] += 1
sync_managers[sm]["pdos"].append(
@@ -436,6 +617,10 @@
"entries": entries_infos,
"entries_number": len(entries_infos),
"fixed": pdo.getFixed() == True})
+ ############################################################# if PdoConfig and PdoAssign:
@@ -459,7 +644,7 @@
raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \
(index, subindex, type_infos["device_type"])
@@ -526,8 +711,8 @@
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"]
@@ -550,11 +735,11 @@
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 (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",
--- a/etherlab/etherlab.py Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/etherlab.py Wed Nov 20 16:57:15 2019 +0100
@@ -10,6 +10,8 @@
# See COPYING file for copyrights details.
+#from xml.dom import minidom @@ -33,13 +35,16 @@
EtherCATInfoParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd"))
EtherCATInfo_XPath = lambda xpath: etree.XPath(xpath)
+EtherCATBaseParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATBase.xsd")) +EtherCATBase_XPath = lambda xpath1: etree.XPath(xpath1) def HexDecValue(context, *args):
return str(ExtractHexDecValue(args[0][0]))
def EntryName(context, *args):
return ExtractName(args[0],
args[1][0] if len(args) > 1 else None)
("Index", lambda x: "#x%4.4X" % int(x), "#x0000"),
@@ -52,6 +57,19 @@
+# Read DefaultValue from ESI file +ENTRY_INFOS_KEYS_FOR_DV = [ + ("Index", lambda x: "#x%4.4X" % int(x), "#x0000"), + ("SubIndex", str, "0"), + ("PDOMapping", str, ""), + ("DefaultValue", str, ""), + ("Sub_entry_flag", str, "0")] def __init__(self, entries):
@@ -59,11 +77,17 @@
def AddEntry(self, context, *args):
index, subindex = map(lambda x: int(x[0]), args[:2])
key: translate(arg[0]) if len(arg) > 0 else default
for (key, translate, default), arg
in zip(ENTRY_INFOS_KEYS, args)}
+ key: translate(arg[0]) if len(arg) > 0 else default + for (key, translate, default), arg + in zip(ENTRY_INFOS_KEYS_FOR_DV, args)} if (index, subindex) != (0, 0):
entry_infos = self.Entries.get((index, subindex))
if entry_infos is not None:
@@ -79,6 +103,7 @@
cls = EtherCATInfoParser.GetElementClass("DeviceType")
profile_numbers_xpath = EtherCATInfo_XPath("Profile/ProfileNo")
def GetProfileNumbers(self):
@@ -92,25 +117,151 @@
setattr(cls, "getCoE", getCoE)
+ def ExtractDataTypes(self): + for profile in self.getProfile(): + # get each (ProfileNo, Dictionary) Field as child + for child in profile.getchildren(): + # child.text is not None -> ProfileNo, is None -> Dictionary + # get each (DataTypes, Objects) Field + dataTypes = child.getDataTypes() + objects = child.getObjects() + for dataType in dataTypes.getDataType(): + #if dataType.getName() is not None: + # print dataType.getName(), dataType + DT[dataType.getName()] = dataType + setattr(cls, "ExtractDataTypes", ExtractDataTypes) def GetEntriesList(self, limits=None):
+ DataTypes, objects = self.ExtractDataTypes()
- factory = EntryListFactory(entries)
- entries_list_xslt_tree = etree.XSLT(
- entries_list_xslt, extensions = {
- ("entries_list_ns", "AddEntry"): factory.AddEntry,
- ("entries_list_ns", "HexDecValue"): HexDecValue,
- ("entries_list_ns", "EntryName"): EntryName})
- entries_list_xslt_tree(self, **dict(zip(
- ["min_index", "max_index"],
- map(lambda x: etree.XSLT.strparam(str(x)),
- limits if limits is not None else [0x0000, 0xFFFF])
+ # get each Object Field + # Object Field mendatory : Index, Name, Type, BitSize + # Frequently Use : Info, Flags + # Info Field -> DefaultData, SubItem + # Flags Field -> Access, Category, PdoMapping + object_index = object.getIndex().getcontent() + index = ExtractHexDecValue(object_index) + if limits is None or limits[0] <= index <= limits[1]: + object_type = object.getType() + object_name = ExtractName(object.getName()) + object_size = object.getBitSize() + object_PDOMapping_data = "" + object_type_infos = DataTypes.get(object_type, None) + subItem_infos = object_type_infos.getchildren() + if len(subItem_infos) > 2: + for subItem_info in subItem_infos: + if subItem_info.tag == "SubItem" : + subItemName = subItem_info.getName() + subIdx = subItem_info.getSubIdx() + object_subidx = ExtractHexDecValue(subIdx) + object_subidx = ExtractHexDecValue(countSubIndex) + subType = subItem_info.getType() + subBitSize = subItem_info.getBitSize() + subFlags = subItem_info.getFlags() + subPDOMapping_data = "" + if subFlags is not None: + subAccess = subFlags.getAccess().getcontent() + subPDOMapping = subFlags.getPdoMapping() + if subPDOMapping is not None: + subPDOMapping_data = subFlags.getPdoMapping().upper() + entries[(index, object_subidx)] = { + (object_name.decode("utf-8"), + subItemName.decode("utf-8")), + "PDOMapping": subPDOMapping_data} + info = object.getInfo() + # subItemTest : check subItem + subItems = info.getchildren() + for subItem in subItems: + defaultdata_subidx = ExtractHexDecValue(countSubIndex) + defaultData = subItem.getchildren()[1].findtext("DefaultData") + entry = entries.get((index, defaultdata_subidx), None) + entry["DefaultData"] = defaultData + info = object.getInfo() + subItems = info.getchildren() + defaultData = subItems[0].text + object_flag = object.getFlags() + object_access = object_flag.getAccess().getcontent() + object_PDOMapping = object_flag.getPdoMapping() + if object_PDOMapping is not None: + object_PDOMapping_data = object_flag.getPdoMapping().upper() + entries[(index, 0)] = { + "BitSize": object_size, + "DefaultData" : defaultData, + "Access": object_access, + "PDOMapping": object_PDOMapping_data} + for TxPdo in self.getTxPdo(): + ExtractPdoInfos(TxPdo, "Transmit", entries, limits) + for RxPdo in self.getRxPdo(): + ExtractPdoInfos(RxPdo, "Receive", entries, limits) setattr(cls, "GetEntriesList", GetEntriesList)
+# def GetEntriesList(self, limits=None): +# factory = EntryListFactory(entries) +# entries_list_xslt_tree = etree.XSLT( +# entries_list_xslt, extensions = { +# ("entries_list_ns", "AddEntry"): factory.AddEntry, +# ("entries_list_ns", "HexDecValue"): HexDecValue, +# ("entries_list_ns", "EntryName"): EntryName}) +# entries_list_xslt_tree(self, **dict(zip( +# ["min_index", "max_index"], +# map(lambda x: etree.XSLT.strparam(str(x)), +# limits if limits is not None else [0x0000, 0xFFFF]) +# setattr(cls, "GetEntriesList", GetEntriesList) def GetSyncManagers(self):
for sync_manager in self.getSm():
@@ -127,6 +278,8 @@
setattr(cls, "GetSyncManagers", GetSyncManagers)
+cls2 = EtherCATInfoParser.GetElementClass("DeviceType") def GroupItemCompare(x, y):
if x["type"] == y["type"]:
if x["type"] == ETHERCAT_GROUP:
@@ -143,6 +296,50 @@
group["children"].sort(GroupItemCompare)
+def ExtractPdoInfos(pdo, pdo_type, entries, limits=None): + pdo_index = pdo.getIndex().getcontent() + pdo_name = ExtractName(pdo.getName()) + exclude = pdo.getExclude() + for pdo_entry in pdo.getEntry(): + entry_index = pdo_entry.getIndex().getcontent() + entry_subindex = pdo_entry.getSubIndex() + index = ExtractHexDecValue(entry_index) + subindex = ExtractHexDecValue(entry_subindex) + object_size = pdo_entry.getBitLen() + if limits is None or limits[0] <= index <= limits[1]: + entry = entries.get((index, subindex), None) + entry["PDO index"] = pdo_index + entry["PDO name"] = pdo_name + entry["PDO type"] = pdo_type + entry_type = pdo_entry.getDataType() + if entry_type is not None: + if pdo_type == "Transmit": + entries[(index, subindex)] = { + "SubIndex": entry_subindex, + "Name": ExtractName(pdo_entry.getName()), + "Type": entry_type.getcontent(), + "BitSize": object_size, + "PDOMapping": pdomapping} +#cls3 = EtherCATBaseParser.GetElementClass("ModuleType") +# module_xpath = EtherCATBase_XPath("Descriptions/Modules/Module") +# setattr(cls, "test", test) @@ -180,7 +377,7 @@
self.LoadModulesExtraParams()
@@ -189,8 +386,20 @@
groups_xpath = EtherCATInfo_XPath("Descriptions/Groups/Group")
devices_xpath = EtherCATInfo_XPath("Descriptions/Devices/Device")
+ module_xpath = EtherCATBase_XPath("Descriptions/Modules/Module") + # add by jblee for Modular Device Profile + # add by jblee for PDO Mapping + self.ObjectDictionary = {} files = os.listdir(self.Path)
@@ -201,13 +410,13 @@
xmlfile = open(filepath, 'r')
self.modules_infos, error = EtherCATInfoParser.LoadXMLString(xmlfile.read())
- self.GetCTRoot().logger.write_warning(
- XSDSchemaErrorMessage % (filepath + error))
+ # self.GetCTRoot().logger.write_warning( + # XSDSchemaErrorMessage % (filepath + error)) self.modules_infos, error = None, unicode(exc)
if self.modules_infos is not None:
vendor = self.modules_infos.getVendor()
@@ -218,13 +427,17 @@
for group in self.groups_xpath(self.modules_infos):
group_type = group.getType()
+ # add for XmlToEeprom Func by jblee. + self.LcId_data = group.getchildren()[1] + self.Image16x14_data = group.getchildren()[2] vendor_category["groups"].setdefault(group_type,
{"name": ExtractName(group.getName(), group_type),
"parent": group.getParentGroup(),
"order": group.getSortOrder(),
- #"value": group.getcontent()["value"],
+ # add jblee for support Moduler Device Profile (MDP) for device in self.devices_xpath(self.modules_infos):
device_group = device.getGroupType()
@@ -232,14 +445,101 @@
raise ValueError, "Not such group \"%\"" % device_group
vendor_category["groups"][device_group]["devices"].append(
(device.getType().getcontent(), device))
+ # ------------------ Test Section --------------------# + slots = device.getSlots() + for slot in slots.getSlot(): + self.idxIncrement = slot.getSlotIndexIncrement() + self.slotIncrement = slot.getSlotPdoIncrement() + for child in slot.getchildren(): + if child.tag == "ModuleClass": + child_class = child.getClass() + child_name = child.getName() + # -------------------- Test Section ----------------------------------# + for module in self.module_xpath(self.modules_infos): + module_type = module.getType().getModuleClass() + module_name = module.getName() + LocalMDPData = ExtractName(module_name) + " (" + module_type + ")" + self.ModuleList.append(module) + module_pdos = module.getTxPdo() + module_pdos += module.getRxPdo() + for module_pdo in module_pdos: + device_name = ExtractName(module_name) + pdo_index = module_pdo.getIndex().getcontent() + pdo_name = ExtractName(module_pdo.getName()) + pdo_entry = module_pdo.getEntry() + if module_pdo.tag == "TxPdo": + for entry in pdo_entry: + entry_index = entry.getIndex().getcontent() + entry_subidx = entry.getSubIndex() + entry_name = ExtractName(entry.getName()) + entry_bitsize = entry.getBitLen() + entry_type = entry.getDataType().getcontent() + "SubIndex": entry_subidx, + "Name": "%s - %s" % (pdo_name, entry_name), + "BitSize": entry_bitsize, + "PDOMapping": mapping_type}) + self.MDPEntryList[device_name] = LocalMDPEntry + LocalMDPList.append([LocalMDPData, module, LocalMDPEntry]) + LocalMDPList.append([LocalMDPData, module, []]) + vendor_category["groups"][device_group]["modules"].append( + (device.getType().getcontent(), LocalMDPList, self.idxIncrement, self.slotIncrement)) + #self.MDPList.append([device.getType().getcontent(), LocalMDPList, + # self.idxIncrement, self.slotIncrement]) + # --------------------------------------------------------------------- #
- self.GetCTRoot().logger.write_error(
- _("Couldn't load %s XML file:\n%s") % (filepath, error))
+ #self.GetCTRoot().logger.write_error( + # _("Couldn't load %s XML file:\n%s") % (filepath, error)) + #print self.ObjectDictionary + return self.Library ## add jblee + def GetSelectModule(self, idx): + return self.ModuleList[idx] + def GetModuleEntryList(self): + return self.MDPEntryList + def GetModuleIncrement(self): + return (self.idxIncrement, self.slotIncrement) + #def GetEntriesList(self): + # return self.ObjectDictionary def GetModulesLibrary(self, profile_filter=None):
@@ -301,10 +601,22 @@
revision_number = ExtractHexDecValue(device_infos.getType().getRevisionNo())
if (product_code == ExtractHexDecValue(module_infos["product_code"]) and
revision_number == ExtractHexDecValue(module_infos["revision_number"])):
- self.cntdevice = device_infos
- self.cntdeviceType = device_type
+ self.cntdevice = device_infos ## add by hwang 13.05.01. + self.cntdeviceType = device_type ## add by hwang 13.05.01. return device_infos, self.GetModuleExtraParams(vendor, product_code, revision_number)
+ def GetMDPInfos(self, module_infos): + vendor = ExtractHexDecValue(module_infos["vendor"]) + vendor_infos = self.Library.get(vendor) + if vendor_infos is not None: + for group_name, group_infos in vendor_infos["groups"].iteritems(): + return group_infos["modules"] + #for device_type, module_list, idx_inc, slot_inc in group_infos["modules"]: + # return module_list, idx_inc, slot_inc + #return None, None, None def ImportModuleLibrary(self, filepath):
if os.path.isfile(filepath):
@@ -387,7 +699,6 @@
CTNChildrenTypes = [("EthercatNode",_EthercatCTN,"Ethercat Master")]
EditorType = LibraryEditor
self.ModulesLibrary = None
@@ -424,10 +735,32 @@
def GetModulesLibrary(self, profile_filter=None):
return self.ModulesLibrary.GetModulesLibrary(profile_filter)
+ return self.ModulesLibrary.GetMDPList() + def GetSelectModule(self, idx): + return self.ModulesLibrary.GetSelectModule(idx) + def GetModuleEntryList(self): + return self.ModulesLibrary.GetModuleEntryList() + def GetModuleIncrement(self): + return self.ModulesLibrary.GetModuleIncrement() + #def GetEntriesList(self, limits = None): + # return self.ModulesLibrary.GetEntriesList() return self.ModulesLibrary.GetVendors()
def GetModuleInfos(self, module_infos):
return self.ModulesLibrary.GetModuleInfos(module_infos)
+ def GetMDPInfos(self, module_infos): + return self.ModulesLibrary.GetMDPInfos(module_infos)