diff -r 09d5d1456616 -r c9deff128c37 etherlab/CommonEtherCATFunction.py --- 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 @@ import os import wx - -mailbox_protocols = ["AoE", "EoE", "CoE", "FoE", "SoE", "VoE"] +import re + +from lxml import objectify def ExtractHexDecValue(value): """ @@ -77,18 +78,21 @@ returnVal = result """ -# ethercat sdos -p (slave position) -SLAVE_SDO = """ +# ethercat upload -p (slave position) -t (type) (index) (sub index) +SDO_UPLOAD = """ import commands -result = commands.getoutput("ethercat sdos -p %d") -returnVal =result -""" - -# ethercat upload -p (slave position) (main index) (sub index) -GET_SLOW_SDO = """ -import commands -result = commands.getoutput("ethercat upload -p %d %s %s") -returnVal =result +sdo_data = [] +input_data = "%s" +slave_pos = %d +command_string = "" +for sdo_token in input_data.split(","): + if len(sdo_token) > 1: + 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) +returnVal =sdo_data """ # ethercat download -p (slave position) (main index) (sub index) (value) @@ -112,6 +116,25 @@ returnVal =result """ +# ethercat reg_read -p (slave position) (address) (size) +MULTI_REG_READ = """ +import commands +output = [] +addr, size = range(2) +slave_num = %d +reg_info_str = "%s" +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 " + + str(slave_idx) + " " + + param[addr] + " " + + param[size]) + output.append(str(slave_idx) + "," + param[addr] + "," + result) +returnVal = output +""" + # ethercat sii_write -p (slave position) - (contents) SII_WRITE = """ import subprocess @@ -136,6 +159,13 @@ returnVal =result """ +# ethercat pdos +PDOS = """ +import commands +result = commands.getoutput("ethercat pdos -p 0") +returnVal =result +""" + #-------------------------------------------------- # Common Method For EtherCAT Management #-------------------------------------------------- @@ -144,12 +174,38 @@ # ----- Data Structure for ethercat management ---- SlaveState = "" + # SDO base data type for Ethercatmaster + BaseDataTypes = { + "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", + "INTEGER64", "LINT"], + "float": ["REAL", "REAL32"], + "double": ["LREAL", "REAL64"], + "string": ["VISUBLE_STRING", "STRING(n)"], + "octet_string": ["OCTET_STRING"], + "unicode_string": ["UNICODE_STRING"] + } + # category of SDO data DatatypeDescription, CommunicationObject, ManufacturerSpecific, \ ProfileSpecific, Reserved, AllSDOData = range(6) - # store the execution result of "ethercat sdos" command into SaveSDOData. - SaveSDOData = [] + # SDO data informations: index, sub-index, type, bit size, category-name + SDOVariables = [] + SDOSubEntryData = [] + + # defalut value of SDO data in XML + # Not Used + DefaultValueDic = {} # Flags for checking "write" permission of OD entries CheckPREOP = False @@ -180,7 +236,7 @@ self.Controler = controler self.ClearSDODataSet() - + #------------------------------------------------------------------------------- # Used Master State #------------------------------------------------------------------------------- @@ -189,7 +245,6 @@ Execute "ethercat master" command and parse the execution result @return MasterState """ - # exectute "ethercat master" command error, return_val = self.Controler.RemoteExec(MASTER_STATE, return_val = None) master_state = {} @@ -226,20 +281,11 @@ """ error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val = None) self.SlaveState = return_val - return return_val + return return_val #------------------------------------------------------------------------------- # Used SDO Management #------------------------------------------------------------------------------- - 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) - return return_val - 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) + + return return_val def BackupSDODataSet(self): """ @@ -268,14 +317,318 @@ Clear the specified SDO entry information. """ for count in range(6): - 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" + """ + entry_infos = "" + alldata_idx = len(self.SDOVariables) + counter = 0 + for category in self.SDOVariables: + counter +=1 + # for avoid redundant repetition + if counter == alldata_idx: + continue + + for entry in category: + 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) + + return return_val + + 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" + """ + entry_infos = "" + + 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) + + return return_val + + def ExtractObjects(self): + """ + Extract object type items from imported ESI xml. + And they are stuctured as dictionary. + @return objects: dictionary of objects + """ + 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(): + dictionary.load() + for object in dictionary.getObjects().getObject(): + object_index = ExtractHexDecValue(object.getIndex().getcontent()) + objects[(object_index)] = object + + return objects + + def ExtractAllDataTypes(self): + """ + Extract all data types from imported ESI xml. + @return dataTypes: dictionary of datatypes + """ + 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(): + dictionary.load() + + datatypes = dictionary.getDataTypes() + if datatypes is not None: + + for datatype in datatypes.getDataType(): + dataTypes[datatype.getName()] = datatype + return dataTypes + + 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 + """ + baseTypeFlag = False + for baseDataTypeList in self.BaseDataTypes.values(): + if datatype in baseDataTypeList: + baseTypeFlag = True + break + return baseTypeFlag + + def GetBaseDataType(self, datatype): + """ + Get a base data type corresponding the datatype. + @param datatype: Some data type (string format) + @return base data type + """ + if self.IsBaseDataType(datatype): + return datatype + elif not datatype.find("STRING") == -1: + return datatype + else: + 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: + return "string" + else: + for key, value in self.BaseDataTypes.items(): + if base_type in value: + return key + return base_type + + # Not Used + 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() + entries_list.sort() + + # append sub entries + for (index, subidx), entry in entries_list: + # entry_* is string type + entry_type = entry["Type"] + entry_index = entry["Index"] + + try: + object_info = objects[index].getInfo() + except: + continue + + if object_info is not None: + obj_content = object_info.getcontent() + + typeinfo = datatypes.get(entry_type, None) + bitsize = typeinfo.getBitSize() + type_content = typeinfo.getcontent() + + # ArrayInfo type + 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) + else: + entry_name = ExtractName(objects[index].getName()) + self.entries[(index, new_subidx)] = { + "Index": entry_index, + "SubIndex": entry_subidx, + "Name": entry_name, + "Type": typeinfo.getBaseType(), + "BitSize": str(bitsize/element_num), + "Access": entry["Access"], + "PDOMapping": entry["PDOMapping"]} + try: + value_info = subitem[new_subidx].getInfo().getcontent()\ + ["value"][0]["value"][0] + self.AppendDefaultValue(index, new_subidx, value_info) + except: + pass + + try: + value_info = subitem[subidx].getInfo().getcontent()\ + ["value"][0]["value"][0] + self.AppendDefaultValue(index, subidx, value_info) + except: + pass + + # EnumInfo type + 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" + + # another types + else: + if subidx == 0x00: + tmp_subidx = 0x00 + + try: + if obj_content["value"][tmp_subidx]["name"] == "SubItem": + sub_name = entry["Name"].split(" - ")[1] + for num in range(len(obj_content["value"])): + if sub_name == \ + obj_content["value"][num]["value"][num].getName(): + subitem_content = obj_content["value"][tmp_subidx]\ + ["value"][tmp_subidx] + value_info = subitem_content.getInfo().getcontent()\ + ["value"][0]["value"][0] + tmp_subidx += 1 + break + else: + value_info = None + + else: + value_info = \ + obj_content["value"][tmp_subidx]["value"][tmp_subidx] + + self.AppendDefaultValue(index, subidx, value_info) + + except: + pass + + return self.entries + + # Not Used + 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. + if value_info == None: + return + + 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").\ + decode("utf-8") + + else: + bit_num = len(raw_value_bit) + # padding + if not bit_num%2 == 0: + raw_value_bit.insert(0, "0") + + default_value_bit = [] + + # little endian -> big endian + for num in range(bit_num): + if num%2 == 0: + 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 + #------------------------------------------------------------------------------- # Used PDO Monitoring #------------------------------------------------------------------------------- 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()) entries = pdo.getEntry() pdo_name = ExtractName(pdo.getName()) - + excludes = pdo.getExclude() + exclude_list = [] + Sm = pdo.getSm() + + if excludes : + for exclude in excludes: + exclude_list.append(ExtractHexDecValue(exclude.getcontent())) + # Initialize entry number count count = 0 - + # Parse entries for entry in entries: # Save index and subindex @@ -317,13 +677,14 @@ "entry_index" : index, "subindex" : subindex, "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) count += 1 - - 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) # Parsing RxPDO entries @@ -332,7 +693,14 @@ pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) entries = pdo.getEntry() pdo_name = ExtractName(pdo.getName()) - + excludes = pdo.getExclude() + exclude_list = [] + Sm = pdo.getSm() + + if excludes : + for exclude in excludes: + exclude_list.append(ExtractHexDecValue(exclude.getcontent())) + # Initialize entry number count count = 0 @@ -347,13 +715,14 @@ "entry_index" : index, "subindex" : subindex, "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) count += 1 - 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.TxPDOInfos = [] - self.TxPDOCategorys = [] - self.RxPDOInfos = [] - self.RxPDOCategorys = [] + self.TxPDOInfo = [] + self.TxPDOCategory = [] + self.RxPDOInfo = [] + self.RxPDOCategory = [] #------------------------------------------------------------------------------- # Used EEPROM Management @@ -460,23 +829,33 @@ type_infos = slave.getType() device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) + #from decimal import Decimal + # 'device' represents current slave device selected by user if device is not None: - 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; -- - if eeprom_element["name"] == "ByteSize": - smartview_infos["eeprom_size"] = eeprom_element + if eeprom_element.tag == "ByteSize": + smartview_infos["eeprom_size"] = objectify.fromstring(eeprom_element.tostring()).text - elif eeprom_element["name"] == "ConfigData": - configData_data = self.DecimalToHex(eeprom_element) + 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; -- address 0x00 smartview_infos["pdi_type"] = int(configData_data[0:2], 16) # get state of device emulation; -- address 0x01 - if "{:0>8b}".format(int(configData_data[2:4], 16))[7] == '1': + 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["name"] == "BootStrap": - bootstrap_data = "{:0>16x}".format(eeprom_element) + elif eeprom_element.tag == "BootStrap": + bootstrap_data = "{:0>16x}".format(int(objectify.fromstring(eeprom_element.tostring()).text, 16)) # get bootstrap configuration; -- for cfg, iter in [("mailbox_bootstrapconf_outstart", 0), ("mailbox_bootstrapconf_outlength", 1), @@ -484,12 +863,34 @@ ("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; -- + if eeprom_element["name"] == "ByteSize": + smartview_infos["eeprom_size"] = eeprom_element["value"] + + elif eeprom_element["name"] == "ConfigData": + configData_data = self.DecimalToHex(eeprom_element["value"]) + # get PDI type; -- address 0x00 + smartview_infos["pdi_type"] = int(configData_data[0:2], 16) + # get state of device emulation; -- address 0x01 + if "{:0>8b}".format(int(configData_data[2:4], 16))[7] == '1': + smartview_infos["device_emulation"] = "True" + + elif eeprom_element["name"] == "BootStrap": + bootstrap_data = "{:0>16x}".format(eeprom_element["value"]) + # get bootstrap configuration; -- + 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; - - mb = device.getMailbox() - if mb is not None: - 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; - @@ -504,24 +905,24 @@ pass # get device identity from - - # 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) - # product code; + # product code; if device.getType().getProductCode() is not None: product_code = device.getType().getProductCode() smartview_infos["product_code"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(product_code)) - # revision number; + # revision number; if device.getType().getRevisionNo() is not None: revision_no = device.getType().getRevisionNo() smartview_infos["revision_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(revision_no)) - # serial number; + # serial number; 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" % decnum + value = "%x" % int(decnum, 16) value_len = len(value) if (value_len % 2) == 0: hex_len = value_len else: 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)) return hex_data @@ -668,12 +1069,13 @@ 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: # get ConfigData for EEPROM offset 0x0000-0x000d; -- - 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 @@ eeprom.append("00") eeprom.append("00") + data = "" # get BootStrap for EEPROM offset 0x0028-0x002e; -- - data = "" - 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; - data = "" + 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; data = 0 - mb = device.getMailbox() - if mb is not None : - 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)]: + if mbox is not None: data += 1< lxml) data = "" - 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) + if data == "": eeprom.append("00") eeprom.append("00") @@ -808,7 +1216,7 @@ eeprom.append(data[0:2]) # Version for EEPROM 0x007e-0x007f; - # According to "EtherCAT Slave Device Description(V0.3.0)" + # According to "EtherCAT Slave Device Description(V0.3.0)" eeprom.append("01") eeprom.append("00") @@ -877,14 +1285,16 @@ imageflag = False # vendor specific data - # element1; ---- - # vendor_specific_data : vendor specific data (binary type) + # element1; ---- + # 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 vendor_spec_strings = [] for element in device.getType().getcontent(): data += element - 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])) data = "" - # element2-1; ---- + # element2-1; ---- + # 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; --- + # element2-2; --- 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])) data = "" - - # element3; ---- + + # element3; ---- + # 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: + groupnameflag = True + break + if groupnameflag is False: + count += 1 + self.Strings.append(data) + vendor_spec_strings.append(data) + groupnameflag = True + vendor_specific_data += "{:0>2x}".format(len(data)) + for character in range(len(data)): + vendor_specific_data += "{:0>2x}".format(ord(data[character])) + + """ + # element3; ---- 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])) + """ + data = "" - # element4; ---- + # element4; ---- + # 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])) + data = "" - # element5-1; ---- + # element5-1; ---- if device.getcontent() is not None: - data = device.getcontent() - if data is not None and type(data) == unicode: + #data = device.getcontent()["value"] + # mod by jblee 151224 + # 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; ---- + + # element5-2; ---- + # Modify by jblee because of update IDE module (minidom -> lxml) + if imageflag is False: + if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: + data_obj = self.Controler.CTNParent.CTNParent.ModulesLibrary.Image16x14_data + data = data_obj.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 + imageflag = True + break + if imageflag is False: + count += 1 + self.Strings.append(data) + vendor_spec_strings.append(data) + imageflag = True + self.ImgIdx = count + 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; ---- if imageflag is False: if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): for group_type, group_etc in vendor["groups"].iteritems(): for device_item in group_etc["devices"]: if device == device_item[1]: - data = group_etc - if data is not None and type(data) == unicode: + print group_etc + 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])) + """ + data = "" - # DC related elements - # ------ + # ------ dc_related_elements = "" if device.getDc() is not None: for element in device.getDc().getOpMode(): @@ -1048,7 +1520,7 @@ data = "" # Input elements(TxPDO) - # ----; Name + # ----; Name input_elements = "" inputs = [] for element in device.getTxPdo(): @@ -1081,7 +1553,7 @@ data = "" # Output elements(RxPDO) - # ----; Name + # ----; Name output_elements = "" outputs = [] for element in device.getRxPdo(): @@ -1114,10 +1586,10 @@ data = "" # form eeprom data - # category header + # category header eeprom.append("0a") eeprom.append("00") - # 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 if length%4 == 0: pass @@ -1126,7 +1598,7 @@ padflag = True 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, dc_related_elements, @@ -1171,48 +1643,48 @@ # word 3 : Physical Layer Port info. and CoE Details eeprom.append("01") # Physical Layer Port info - assume 01 - # CoE Details; ----- + # CoE Details; ----- coe_details = 0 - mb = device.getMailbox() - coe_details = 1 # sdo enabled - if mb is not None : - coe = mb.getCoE() - if coe is not None: - for bit,flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig", - "PdoUpload", "CompleteAccess"]): - if getattr(coe,"get%s"%flag)() is not None: - coe_details += 1<2x}".format(coe_details)) # word 4 : FoE Details and EoE Details - # FoE Details; ----- - if mb is not None and mb.getFoE() is not None: + # FoE Details; ----- + if device.getMailbox() is not None and device.getMailbox().getFoE() is not None: eeprom.append("01") else: eeprom.append("00") - # EoE Details; ----- - if mb is not None and mb.getEoE() is not None: + # EoE Details; ----- + if device.getMailbox() is not None and device.getMailbox().getEoE() is not None: eeprom.append("01") else: eeprom.append("00") # word 5 : SoE Channels(reserved) and DS402 Channels - # SoE Details; ----- - if mb is not None and mb.getSoE() is not None: + # SoE Details; ----- + if device.getMailbox() is not None and device.getMailbox().getSoE() is not None: eeprom.append("01") else: eeprom.append("00") - # DS402Channels; -----: DS402Channels - ds402ch = False - if mb is not None : - coe = mb.getCoE() - if coe is not None : - ds402ch = coe.getDS402Channels() - eeprom.append("01" if ds402ch in [True,1] else "00") + # DS402Channels; -----: DS402Channels + if device.getMailbox() is not None and \ + (device.getMailbox().getCoE().getDS402Channels() == True \ + or device.getMailbox().getCoE().getDS402Channels() == 1): + eeprom.append("01") + else: + eeprom.append("00") # word 6 : SysmanClass(reserved) and Flags eeprom.append("00") # reserved - # Flags + # Flags en_safeop = False en_lrw = False if device.getType().getTcCfgModeSafeOp() == True \ @@ -1272,10 +1744,10 @@ # construct of EEPROM data if data is not "": - # category header + # category header eeprom.append("28") eeprom.append("00") - # category length + # category length if count%2 == 1: padflag = True eeprom.append("{:0>4x}".format((count+1)/2)[2:4]) @@ -1289,7 +1761,7 @@ else: eeprom.append(data[0:2]) data = data[2:len(data)] - # padding if length is odd bytes + # padding if length is odd bytes if padflag is True: eeprom.append("ff") @@ -1321,10 +1793,10 @@ data += number[sm.getcontent()] if data is not "": - # category header + # category header eeprom.append("29") eeprom.append("00") - # category length + # category length 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 @@ en_virtual = False for element in eval("device.get%s()"%pdotype): - # PDO Index + # PDO Index data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[2:4] data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[0:2] - # Number of Entries + # Number of Entries data += "{:0>2x}".format(len(element.getEntry())) - # About Sync Manager + # About Sync Manager if element.getSm() is not None: data += "{:0>2x}".format(element.getSm()) else: data += "ff" - # Reference to DC Synch (according to ET1100 documentation) - assume 0 + # Reference to DC Synch (according to ET1100 documentation) - assume 0 data += "00" - # Name Index + # Name Index objname = "" for name in element.getName(): objname = name.getcontent() @@ -1376,7 +1848,7 @@ else: data += "{:0>2x}".format(count) count = 0 - # Flags; by Fixed, Mandatory, Virtual attributes ? + # Flags; by Fixed, Mandatory, Virtual attributes ? if element.getFixed() == True or 1: en_fixed = True 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(): - # Entry Index + # Entry Index data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[2:4] data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[0:2] - # Subindex + # Subindex data += "{:0>2x}".format(int(entry.getSubIndex())) - # Entry Name Index + # Entry Name Index objname = "" for name in entry.getName(): objname = name.getcontent() @@ -1404,7 +1876,7 @@ else: data += "{:0>2x}".format(count) count = 0 - # DataType + # DataType if entry.getDataType() is not None: if entry.getDataType().getcontent() in self.BaseDataTypeDict: data += self.BaseDataTypeDict[entry.getDataType().getcontent()] @@ -1412,19 +1884,19 @@ data += "00" else: data += "00" - # BitLen + # BitLen if entry.getBitLen() is not None: data += "{:0>2x}".format(int(entry.getBitLen())) else: data += "00" - # Flags; by Fixed attributes ? + # Flags; by Fixed attributes ? en_fixed = False if entry.getFixed() == True or entry.getFixed() == 1: en_fixed = True data += str(int(en_fixed)) + "000" if data is not "": - # category header + # category header if pdotype == "TxPdo": eeprom.append("32") elif pdotype == "RxPdo": @@ -1432,7 +1904,7 @@ else: eeprom.append("00") eeprom.append("00") - # category length + # category length eeprom.append("{:0>4x}".format(len(data)/4)[2:4]) eeprom.append("{:0>4x}".format(len(data)/4)[0:2]) data = str(data.lower()) @@ -1459,7 +1931,7 @@ if device.getDc() is not None: for element in device.getDc().getOpMode(): count += 1 - # assume that word 1-7 are 0x0000 + # assume that word 1-7 are 0x0000 data += "0000" data += "0000" data += "0000" @@ -1467,14 +1939,14 @@ data += "0000" data += "0000" data += "0000" - # word 8-10 - # AssignActivate + # word 8-10 + # AssignActivate if element.getAssignActivate() is not None: data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[2:4] data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[0:2] else: data += "0000" - # 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 @@ data += "0100" else: data += "0100" - # Index of Name in STRINGS Category - # Name Index + # Index of Name in STRINGS Category + # Name Index objname = "" for name in element.getName(): objname += name @@ -1498,15 +1970,15 @@ data += "{:0>2x}".format(namecount) namecount = 0 data += "00" - # assume that word 11-12 are 0x0000 + # assume that word 11-12 are 0x0000 data += "0000" data += "0000" if data is not "": - # category header + # category header eeprom.append("3c") eeprom.append("00") - # category length + # category length eeprom.append("{:0>4x}".format(len(data)/4)[2:4]) eeprom.append("{:0>4x}".format(len(data)/4)[0:2]) data = str(data.lower()) @@ -1533,6 +2005,24 @@ error, return_val = self.Controler.RemoteExec(REG_READ%(self.Controler.GetSlavePos(), offset, length), return_val = None) return return_val + def MultiRegRead(self, slave_num, reg_infos): + """ + + @slave_num: + @param addr_info: + @return return_val: + """ + reg_info_str = "" + 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), + return_val = None) + + return return_val + 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 + #------------------------------------------------------------------------------- + def LoadESIData(self): + return_data = [] + 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(): + temp_data = { + "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) + + return return_data #------------------------------------------------------------------------------- # Common Use Methods @@ -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 @return True or False - """ + """ if self.Controler.GetCTRoot()._connector is not None: # Check connection between the master and the slave. # Command example : "ethercat xml -p 0"