andrej@2354: #!/usr/bin/env python andrej@2354: # -*- coding: utf-8 -*- andrej@2354: andrej@2354: andrej@2354: # This file is part of Beremiz andrej@2354: # andrej@2354: # Copyright (C) 2013: Real-Time & Embedded Systems (RTES) Lab. University of Seoul, Korea andrej@2354: # andrej@2354: # See COPYING file for copyrights details. andrej@2354: andrej@2405: from __future__ import absolute_import andrej@2437: from __future__ import division andrej@2434: from builtins import str as text andrej@2446: import codecs andrej@2354: import wx andrej@2354: andrej@2434: andrej@2373: mailbox_protocols = ["AoE", "EoE", "CoE", "FoE", "SoE", "VoE"] andrej@2354: andrej@2360: andrej@2354: def ExtractHexDecValue(value): andrej@2354: """ andrej@2354: convert numerical value in string format into decimal or hex format. andrej@2354: @param value : hex or decimal data andrej@2354: @return integer data andrej@2354: """ andrej@2354: try: andrej@2354: return int(value) andrej@2354: except Exception: andrej@2354: pass andrej@2354: try: andrej@2354: return int(value.replace("#", "0"), 16) andrej@2355: andrej@2354: except Exception: andrej@2423: raise ValueError(_("Invalid value for HexDecValue \"%s\"") % value) andrej@2354: andrej@2360: andrej@2354: def ExtractName(names, default=None): andrej@2354: """ andrej@2354: Extract "name" field from XML entries. andrej@2354: @param names : XML entry andrej@2354: @default : if it fails to extract from the designated XML entry, return the default value ("None"). andrej@2354: @return default or the name extracted andrej@2354: """ andrej@2354: if len(names) == 1: andrej@2354: return names[0].getcontent() andrej@2354: else: andrej@2354: for name in names: andrej@2354: if name.getLcId() == 1033: andrej@2354: return name.getcontent() andrej@2354: return default andrej@2354: edouard@2643: #-------------------------------------------------- andrej@2354: # Remote Exec Etherlab Commands edouard@2643: #-------------------------------------------------- andrej@2370: andrej@2354: # --------------------- for master --------------------------- andrej@2354: MASTER_STATE = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat master") andrej@2355: returnVal =result andrej@2354: """ andrej@2354: andrej@2354: # --------------------- for slave ---------------------------- andrej@2354: # ethercat state -p (slave position) (state (INIT, PREOP, SAFEOP, OP)) andrej@2354: SLAVE_STATE = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat state -p %d %s") andrej@2355: returnVal = result andrej@2354: """ andrej@2354: andrej@2354: # ethercat slave andrej@2354: GET_SLAVE = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat slaves") andrej@2355: returnVal =result andrej@2354: """ andrej@2354: andrej@2354: # ethercat xml -p (slave position) andrej@2354: SLAVE_XML = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat xml -p %d") andrej@2355: returnVal = result andrej@2354: """ andrej@2354: edouard@2643: # ethercat upload -p (slave position) -t (type) (index) (sub index) edouard@2643: SDO_UPLOAD = """ andrej@2354: import commands edouard@2643: sdo_data = [] edouard@2643: input_data = "%s" edouard@2643: slave_pos = %d edouard@2643: command_string = "" edouard@2643: for sdo_token in input_data.split(","): edouard@2643: if len(sdo_token) > 1: edouard@2643: sdo_token = sdo_token.strip() edouard@2643: type, idx, subidx = sdo_token.split(" ") edouard@2643: command_string = "ethercat upload -p " + str(slave_pos) + " -t " + type + " " + idx + " " + subidx edouard@2643: result = commands.getoutput(command_string) edouard@2643: sdo_data.append(result) edouard@2643: returnVal =sdo_data andrej@2354: """ andrej@2354: andrej@2354: # ethercat download -p (slave position) (main index) (sub index) (value) andrej@2354: SDO_DOWNLOAD = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat download --type %s -p %d %s %s %s") andrej@2355: returnVal =result andrej@2354: """ andrej@2354: andrej@2354: # ethercat sii_read -p (slave position) andrej@2354: SII_READ = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat sii_read -p %d") andrej@2355: returnVal =result andrej@2354: """ andrej@2354: andrej@2354: # ethercat reg_read -p (slave position) (address) (size) andrej@2354: REG_READ = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat reg_read -p %d %s %s") andrej@2355: returnVal =result andrej@2354: """ andrej@2354: edouard@2643: # ethercat reg_read -p (slave position) (address) (size) edouard@2643: MULTI_REG_READ = """ edouard@2643: import commands edouard@2643: output = [] edouard@2643: addr, size = range(2) edouard@2643: slave_num = %d edouard@2643: reg_info_str = "%s" edouard@2643: reg_info_list = reg_info_str.split("|") edouard@2643: for slave_idx in range(slave_num): edouard@2643: for reg_info in reg_info_list: edouard@2643: param = reg_info.split(",") edouard@2643: result = commands.getoutput("ethercat reg_read -p " edouard@2643: + str(slave_idx) + " " edouard@2643: + param[addr] + " " edouard@2643: + param[size]) edouard@2643: output.append(str(slave_idx) + "," + param[addr] + "," + result) edouard@2643: returnVal = output edouard@2643: """ edouard@2643: andrej@2354: # ethercat sii_write -p (slave position) - (contents) andrej@2355: SII_WRITE = """ andrej@2355: import subprocess andrej@2354: process = subprocess.Popen( andrej@2354: ["ethercat", "-f", "sii_write", "-p", "%d", "-"], andrej@2354: stdin=subprocess.PIPE) andrej@2354: process.communicate(sii_data) andrej@2355: returnVal = process.returncode andrej@2354: """ andrej@2354: andrej@2354: # ethercat reg_write -p (slave position) -t (uinit16) (address) (data) andrej@2355: REG_WRITE = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat reg_write -p %d -t uint16 %s %s") andrej@2355: returnVal =result andrej@2355: """ andrej@2354: andrej@2354: # ethercat rescan -p (slave position) andrej@2355: RESCAN = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat rescan -p %d") andrej@2355: returnVal =result andrej@2354: """ andrej@2354: edouard@2643: # ethercat pdos edouard@2643: PDOS = """ edouard@2643: import commands edouard@2643: result = commands.getoutput("ethercat pdos -p 0") edouard@2643: returnVal =result edouard@2643: """ andrej@2360: andrej@2356: # -------------------------------------------------- andrej@2355: # Common Method For EtherCAT Management andrej@2356: # -------------------------------------------------- andrej@2397: class _CommonSlave(object): andrej@2354: andrej@2354: # ----- Data Structure for ethercat management ---- andrej@2354: SlaveState = "" andrej@2354: edouard@2643: # SDO base data type for Ethercatmaster edouard@2643: BaseDataTypes = { edouard@2643: "bool": ["BOOLEAN", "BOOL", "BIT"], edouard@2643: "uint8": ["BYTE", "USINT", "BIT1", "BIT2", "BIT3", "BIT4", "BIT5", "BIT6", edouard@2643: "BIT7", "BIT8", "BITARR8", "UNSIGNED8"], edouard@2643: "uint16": ["BITARR16", "UNSIGNED16", "UINT"], edouard@2643: "uint32": ["BITARR32", "UNSIGNED24", "UINT24", "UNSIGNED32", "UDINT"], edouard@2643: "uint64": ["UNSINED40", "UINT40", "UNSIGNED48", "UINT48", "UNSIGNED56", edouard@2643: "UINT56", "UNSIGNED64", "ULINT"], edouard@2643: "int8": ["INTEGER8", "SINT"], edouard@2643: "int16": ["INTEGER16", "INT"], edouard@2643: "int32": ["INTEGER24", "INT24", "INTEGER32", "DINT"], edouard@2643: "int64": ["INTEGER40", "INT40", "INTEGER48", "INT48", "INTEGER56", "INT56", edouard@2643: "INTEGER64", "LINT"], edouard@2643: "float": ["REAL", "REAL32"], edouard@2643: "double": ["LREAL", "REAL64"], edouard@2643: "string": ["VISUBLE_STRING", "STRING(n)"], edouard@2643: "octet_string": ["OCTET_STRING"], edouard@2643: "unicode_string": ["UNICODE_STRING"] edouard@2643: } edouard@2643: andrej@2354: # category of SDO data andrej@2354: DatatypeDescription, CommunicationObject, ManufacturerSpecific, \ andrej@2384: ProfileSpecific, Reserved, AllSDOData = range(6) andrej@2355: edouard@2643: # SDO data informations: index, sub-index, type, bit size, category-name edouard@2643: SDOVariables = [] edouard@2643: SDOSubEntryData = [] edouard@2643: edouard@2643: # defalut value of SDO data in XML edouard@2643: # Not Used edouard@2643: DefaultValueDic = {} edouard@2643: edouard@2643: # Flags for checking "write" permission of OD entries andrej@2354: CheckPREOP = False andrej@2354: CheckSAFEOP = False andrej@2354: CheckOP = False andrej@2354: andrej@2354: # Save PDO Data andrej@2354: TxPDOInfo = [] andrej@2354: TxPDOCategory = [] andrej@2354: RxPDOInfo = [] andrej@2354: RxPDOCategory = [] andrej@2355: andrej@2354: # Save EEPROM Data andrej@2354: SiiData = "" andrej@2354: andrej@2354: # Save Register Data andrej@2354: RegData = "" andrej@2354: CrtRegSpec = {"ESCType": "", andrej@2354: "FMMUNumber": "", andrej@2354: "SMNumber": "", andrej@2354: "PDIType": ""} andrej@2355: andrej@2354: def __init__(self, controler): andrej@2354: """ andrej@2354: Constructor andrej@2354: @param controler: _EthercatSlaveCTN class in EthercatSlave.py andrej@2354: """ andrej@2354: self.Controler = controler andrej@2446: self.HexDecode = codecs.getdecoder("hex_codec") andrej@2354: self.ClearSDODataSet() andrej@2355: andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Used Master State andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: def GetMasterState(self): andrej@2354: """ andrej@2354: Execute "ethercat master" command and parse the execution result andrej@2355: @return MasterState andrej@2355: """ andrej@2355: andrej@2355: # exectute "ethercat master" command andrej@2406: _error, return_val = self.Controler.RemoteExec(MASTER_STATE, return_val=None) andrej@2354: master_state = {} andrej@2354: # parse the reslut andrej@2354: for each_line in return_val.splitlines(): andrej@2375: if len(each_line) > 0: andrej@2354: chunks = each_line.strip().split(':', 1) andrej@2354: key = chunks[0] andrej@2354: value = [] andrej@2375: if len(chunks) > 1: andrej@2354: value = chunks[1].split() andrej@2354: if '(attached)' in value: andrej@2354: value.remove('(attached)') andrej@2354: master_state[key] = value andrej@2355: andrej@2355: return master_state andrej@2355: andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Used Slave State andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: def RequestSlaveState(self, command): andrej@2354: """ andrej@2354: Set slave state to the specified one using "ethercat states -p %d %s" command. andrej@2354: Command example : "ethercat states -p 0 PREOP" (target slave position and target state are given.) andrej@2355: @param command : target slave state andrej@2354: """ andrej@2406: _error, _return_val = self.Controler.RemoteExec( andrej@2406: SLAVE_STATE % (self.Controler.GetSlavePos(), command), andrej@2406: return_val=None) andrej@2355: andrej@2355: def GetSlaveStateFromSlave(self): andrej@2355: """ andrej@2355: Get slave information using "ethercat slaves" command and store the information into internal data structure andrej@2355: (self.SlaveState) for "Slave State" andrej@2354: return_val example : 0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100) andrej@2355: """ andrej@2406: _error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val=None) andrej@2354: self.SlaveState = return_val andrej@2355: return return_val andrej@2354: andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Used SDO Management andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: def SDODownload(self, data_type, idx, sub_idx, value): andrej@2354: """ andrej@2354: Set an SDO object value to user-specified value using "ethercat download" command. andrej@2354: Command example : "ethercat download --type int32 -p 0 0x8020 0x12 0x00000000" andrej@2354: @param data_type : data type of SDO entry andrej@2354: @param idx : index of the SDO entry andrej@2354: @param sub_idx : subindex of the SDO entry andrej@2354: @param value : value of SDO entry edouard@2643: """ edouard@2643: valid_type = self.GetValidDataType(data_type) edouard@2643: _error, return_val = self.Controler.RemoteExec( edouard@2643: SDO_DOWNLOAD%(valid_type, self.Controler.GetSlavePos(), edouard@2643: idx, sub_idx, value), return_val = None) edouard@2643: edouard@2643: return return_val edouard@2643: andrej@2354: def BackupSDODataSet(self): andrej@2354: """ andrej@2355: Back-up current SDO entry information to restore the SDO data andrej@2383: in case that the user cancels SDO update operation. andrej@2383: """ andrej@2354: self.BackupDatatypeDescription = self.SaveDatatypeDescription andrej@2354: self.BackupCommunicationObject = self.SaveCommunicationObject andrej@2354: self.BackupManufacturerSpecific = self.SaveManufacturerSpecific andrej@2354: self.BackupProfileSpecific = self.SaveProfileSpecific andrej@2354: self.BackupReserved = self.SaveReserved andrej@2354: self.BackupAllSDOData = self.SaveAllSDOData andrej@2355: andrej@2354: def ClearSDODataSet(self): andrej@2354: """ andrej@2354: Clear the specified SDO entry information. andrej@2355: """ andrej@2406: for dummy in range(6): andrej@2354: self.SaveSDOData.append([]) andrej@2355: edouard@2643: def GetAllSDOValuesFromSlave(self): edouard@2643: """ edouard@2643: Get SDO values of All SDO entries. edouard@2643: @return return_val: list of result of "SDO_UPLOAD" edouard@2643: """ edouard@2643: entry_infos = "" edouard@2643: alldata_idx = len(self.SDOVariables) edouard@2643: counter = 0 edouard@2643: for category in self.SDOVariables: edouard@2643: counter +=1 edouard@2643: # for avoid redundant repetition edouard@2643: if counter == alldata_idx: edouard@2643: continue edouard@2643: edouard@2643: for entry in category: edouard@2643: valid_type = self.GetValidDataType(entry["type"]) edouard@2643: for_command_string = "%s %s %s ," % \ edouard@2643: (valid_type, entry["idx"], entry["subIdx"]) edouard@2643: entry_infos += for_command_string edouard@2643: edouard@2643: error, return_val = self.Controler.RemoteExec(SDO_UPLOAD%(entry_infos, self.Controler.GetSlavePos()), return_val = None) edouard@2643: edouard@2643: return return_val edouard@2643: edouard@2643: def GetSDOValuesFromSlave(self, entries_info): edouard@2643: """ edouard@2643: Get SDO values of some SDO entries. edouard@2643: @param entries_info: dictionary of SDO entries that is wanted to know the value. edouard@2643: @return return_val: list of result of "SDO_UPLOAD" edouard@2643: """ edouard@2643: entry_infos = "" edouard@2643: edouard@2643: entries_info_list = entries_info.items() edouard@2643: entries_info_list.sort() edouard@2643: edouard@2643: for (idx, subIdx), entry in entries_info_list: edouard@2643: valid_type = self.GetValidDataType(entry["type"]) edouard@2643: for_command_string = "%s %s %s ," % \ edouard@2643: (valid_type, str(idx), str(subIdx)) edouard@2643: entry_infos += for_command_string edouard@2643: edouard@2643: error, return_val = self.Controler.RemoteExec(SDO_UPLOAD%(entry_infos, self.Controler.GetSlavePos()), return_val = None) edouard@2643: edouard@2643: return return_val edouard@2643: edouard@2643: def ExtractObjects(self): edouard@2643: """ edouard@2643: Extract object type items from imported ESI xml. edouard@2643: And they are stuctured as dictionary. edouard@2643: @return objects: dictionary of objects edouard@2643: """ edouard@2643: objects = {} edouard@2643: edouard@2643: slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) edouard@2643: type_infos = slave.getType() edouard@2643: device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) edouard@2643: edouard@2643: if device is not None : edouard@2643: for dictionary in device.GetProfileDictionaries(): edouard@2643: dictionary.load() edouard@2643: for object in dictionary.getObjects().getObject(): edouard@2643: object_index = ExtractHexDecValue(object.getIndex().getcontent()) edouard@2643: objects[(object_index)] = object edouard@2643: edouard@2643: return objects edouard@2643: edouard@2643: def ExtractAllDataTypes(self): edouard@2643: """ edouard@2643: Extract all data types from imported ESI xml. edouard@2643: @return dataTypes: dictionary of datatypes edouard@2643: """ edouard@2643: dataTypes = {} edouard@2643: edouard@2643: slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) edouard@2643: type_infos = slave.getType() edouard@2643: device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) edouard@2643: edouard@2643: for dictionary in device.GetProfileDictionaries(): edouard@2643: dictionary.load() edouard@2643: edouard@2643: datatypes = dictionary.getDataTypes() edouard@2643: if datatypes is not None: edouard@2643: edouard@2643: for datatype in datatypes.getDataType(): edouard@2643: dataTypes[datatype.getName()] = datatype edouard@2643: return dataTypes edouard@2643: edouard@2643: def IsBaseDataType(self, datatype): edouard@2643: """ edouard@2643: Check if the datatype is a base data type. edouard@2643: @return baseTypeFlag: true if datatype is a base data type, unless false edouard@2643: """ edouard@2643: baseTypeFlag = False edouard@2643: for baseDataTypeList in self.BaseDataTypes.values(): edouard@2643: if datatype in baseDataTypeList: edouard@2643: baseTypeFlag = True edouard@2643: break edouard@2643: return baseTypeFlag edouard@2643: edouard@2643: def GetBaseDataType(self, datatype): edouard@2643: """ edouard@2643: Get a base data type corresponding the datatype. edouard@2643: @param datatype: Some data type (string format) edouard@2643: @return base data type edouard@2643: """ edouard@2643: if self.IsBaseDataType(datatype): edouard@2643: return datatype edouard@2643: elif not datatype.find("STRING") == -1: edouard@2643: return datatype edouard@2643: else: edouard@2643: datatypes = self.ExtractAllDataTypes() edouard@2643: base_datatype = datatypes[datatype].getBaseType() edouard@2643: return self.GetBaseDataType(base_datatype) edouard@2643: edouard@2643: def GetValidDataType(self, datatype): edouard@2643: """ edouard@2643: Convert the datatype into a data type that is possible to download/upload edouard@2643: in etherlab master stack. edouard@2643: @param datatype: Some data type (string format) edouard@2643: @return base_type: vaild data type edouard@2643: """ edouard@2643: base_type = self.GetBaseDataType(datatype) edouard@2643: edouard@2643: if re.match("STRING\([0-9]*\)", datatype) is not None: edouard@2643: return "string" edouard@2643: else: edouard@2643: for key, value in self.BaseDataTypes.items(): edouard@2643: if base_type in value: edouard@2643: return key edouard@2643: return base_type edouard@2643: edouard@2643: # Not Used edouard@2643: def GetAllEntriesList(self): edouard@2643: """ edouard@2643: Get All entries information that includes index, sub-index, name, edouard@2643: type, bit size, PDO mapping, and default value. edouard@2643: @return self.entries: dictionary of entry edouard@2643: """ edouard@2643: slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) edouard@2643: type_infos = slave.getType() edouard@2643: device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) edouard@2643: self.entries = device.GetEntriesList() edouard@2643: datatypes = self.ExtractAllDataTypes() edouard@2643: objects = self.ExtractObjects() edouard@2643: entries_list = self.entries.items() edouard@2643: entries_list.sort() edouard@2643: edouard@2643: # append sub entries edouard@2643: for (index, subidx), entry in entries_list: edouard@2643: # entry_* is string type edouard@2643: entry_type = entry["Type"] edouard@2643: entry_index = entry["Index"] edouard@2643: edouard@2643: try: edouard@2643: object_info = objects[index].getInfo() edouard@2643: except: edouard@2643: continue edouard@2643: edouard@2643: if object_info is not None: edouard@2643: obj_content = object_info.getcontent() edouard@2643: edouard@2643: typeinfo = datatypes.get(entry_type, None) edouard@2643: bitsize = typeinfo.getBitSize() edouard@2643: type_content = typeinfo.getcontent() edouard@2643: edouard@2643: # ArrayInfo type edouard@2643: if type_content is not None and type_content["name"] == "ArrayInfo": edouard@2643: for arrayinfo in type_content["value"]: edouard@2643: element_num = arrayinfo.getElements() edouard@2643: first_subidx = arrayinfo.getLBound() edouard@2643: for offset in range(element_num): edouard@2643: new_subidx = int(first_subidx) + offset edouard@2643: entry_subidx = hex(new_subidx) edouard@2643: if obj_content["value"][new_subidx]["name"] == "SubItem": edouard@2643: subitem = obj_content["value"][new_subidx]["value"] edouard@2643: subname = subitem[new_subidx].getName() edouard@2643: if subname is not None: edouard@2643: entry_name = "%s - %s" % \ edouard@2643: (ExtractName(objects[index].getName()), subname) edouard@2643: else: edouard@2643: entry_name = ExtractName(objects[index].getName()) edouard@2643: self.entries[(index, new_subidx)] = { edouard@2643: "Index": entry_index, edouard@2643: "SubIndex": entry_subidx, edouard@2643: "Name": entry_name, edouard@2643: "Type": typeinfo.getBaseType(), edouard@2643: "BitSize": str(bitsize/element_num), edouard@2643: "Access": entry["Access"], edouard@2643: "PDOMapping": entry["PDOMapping"]} edouard@2643: try: edouard@2643: value_info = subitem[new_subidx].getInfo().getcontent()\ edouard@2643: ["value"][0]["value"][0] edouard@2643: self.AppendDefaultValue(index, new_subidx, value_info) edouard@2643: except: edouard@2643: pass edouard@2643: edouard@2643: try: edouard@2643: value_info = subitem[subidx].getInfo().getcontent()\ edouard@2643: ["value"][0]["value"][0] edouard@2643: self.AppendDefaultValue(index, subidx, value_info) edouard@2643: except: edouard@2643: pass edouard@2643: edouard@2643: # EnumInfo type edouard@2643: elif type_content is not None and type_content["name"] == "EnumInfo": edouard@2643: self.entries[(index, subidx)]["EnumInfo"] = {} edouard@2643: edouard@2643: for enuminfo in type_content["value"]: edouard@2643: text = enuminfo.getText() edouard@2643: enum = enuminfo.getEnum() edouard@2643: self.entries[(index, subidx)]["EnumInfo"][str(enum)] = text edouard@2643: edouard@2643: self.entries[(index, subidx)]["DefaultValue"] = "0x00" edouard@2643: edouard@2643: # another types edouard@2643: else: edouard@2643: if subidx == 0x00: edouard@2643: tmp_subidx = 0x00 edouard@2643: edouard@2643: try: edouard@2643: if obj_content["value"][tmp_subidx]["name"] == "SubItem": edouard@2643: sub_name = entry["Name"].split(" - ")[1] edouard@2643: for num in range(len(obj_content["value"])): edouard@2643: if sub_name == \ edouard@2643: obj_content["value"][num]["value"][num].getName(): edouard@2643: subitem_content = obj_content["value"][tmp_subidx]\ edouard@2643: ["value"][tmp_subidx] edouard@2643: value_info = subitem_content.getInfo().getcontent()\ edouard@2643: ["value"][0]["value"][0] edouard@2643: tmp_subidx += 1 edouard@2643: break edouard@2643: else: edouard@2643: value_info = None edouard@2643: edouard@2643: else: edouard@2643: value_info = \ edouard@2643: obj_content["value"][tmp_subidx]["value"][tmp_subidx] edouard@2643: edouard@2643: self.AppendDefaultValue(index, subidx, value_info) edouard@2643: edouard@2643: except: edouard@2643: pass edouard@2643: edouard@2643: return self.entries edouard@2643: edouard@2643: # Not Used edouard@2643: def AppendDefaultValue(self, index, subidx, value_info=None): edouard@2643: """ edouard@2643: Get the default value from the ESI xml edouard@2643: @param index: entry index edouard@2643: @param subidx: entry sub index edouard@2643: @param value_info: dictionary of infomation about default value edouard@2643: edouard@2643: """ edouard@2643: # there is not default value. edouard@2643: if value_info == None: edouard@2643: return edouard@2643: edouard@2643: raw_value = value_info["value"] edouard@2643: edouard@2643: # default value is hex binary type. edouard@2643: if value_info["name"] == "DefaultData": edouard@2643: raw_value_bit = list(hex(raw_value).split("0x")[1]) edouard@2643: edouard@2643: datatype = self.GetValidDataType(self.entries[(index, subidx)]["Type"]) edouard@2643: if datatype is "string" or datatype is "octet_string": edouard@2643: edouard@2643: if "L" in raw_value_bit: edouard@2643: raw_value_bit.remove("L") edouard@2643: edouard@2643: default_value = "".join(raw_value_bit).decode("hex") edouard@2643: edouard@2643: elif datatype is "unicode_string": edouard@2643: default_value = "".join(raw_value_bit).decode("hex").\ edouard@2643: decode("utf-8") edouard@2643: edouard@2643: else: edouard@2643: bit_num = len(raw_value_bit) edouard@2643: # padding edouard@2643: if not bit_num%2 == 0: edouard@2643: raw_value_bit.insert(0, "0") edouard@2643: edouard@2643: default_value_bit = [] edouard@2643: edouard@2643: # little endian -> big endian edouard@2643: for num in range(bit_num): edouard@2643: if num%2 == 0: edouard@2643: default_value_bit.insert(0, raw_value_bit[num]) edouard@2643: default_value_bit.insert(1, raw_value_bit[num+1]) edouard@2643: edouard@2643: default_value = "0x%s" % "".join(default_value_bit) edouard@2643: edouard@2643: # default value is string type. edouard@2643: # this case is not tested yet. edouard@2643: elif value_info["name"] == "DefaultString": edouard@2643: default_value = raw_value edouard@2643: edouard@2643: # default value is Hex or Dec type. edouard@2643: elif value_info["name"] == "DefaultValue": edouard@2643: default_value = "0x" + hex(ExtractHexDecValue(raw_value)) edouard@2643: edouard@2643: self.entries[(index, subidx)]["DefaultValue"] = default_value edouard@2643: andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Used PDO Monitoring andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: def RequestPDOInfo(self): andrej@2354: """ edouard@2643: Load slave information from RootClass (XML data) and parse the information edouard@2643: (calling SlavePDOData() method). andrej@2355: """ andrej@2354: # Load slave information from ESI XML file (def EthercatMaster.py) andrej@2354: slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) andrej@2355: andrej@2354: type_infos = slave.getType() andrej@2406: device, _alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) andrej@2354: # Initialize PDO data set andrej@2354: self.ClearDataSet() andrej@2355: andrej@2355: # if 'device' object is valid, call SavePDOData() to parse PDO data andrej@2375: if device is not None: andrej@2354: self.SavePDOData(device) andrej@2355: andrej@2354: def SavePDOData(self, device): andrej@2354: """ andrej@2354: Parse PDO data and store the results in TXPDOCategory and RXPDOCategory andrej@2354: Tx(Rx)PDOCategory : index, name, entry number andrej@2354: Tx(Rx)Info : entry index, sub index, name, length, type andrej@2354: @param device : Slave information extracted from ESI XML file andrej@2355: """ andrej@2354: # Parsing TXPDO entries andrej@2406: for pdo, _pdo_info in ([(pdo, "Inputs") for pdo in device.getTxPdo()]): andrej@2354: # Save pdo_index, entry, and name of each entry andrej@2354: pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) andrej@2354: entries = pdo.getEntry() andrej@2354: pdo_name = ExtractName(pdo.getName()) edouard@2643: excludes = pdo.getExclude() edouard@2643: exclude_list = [] edouard@2643: Sm = pdo.getSm() edouard@2643: edouard@2643: if excludes : edouard@2643: for exclude in excludes: edouard@2643: exclude_list.append(ExtractHexDecValue(exclude.getcontent())) andrej@2355: andrej@2354: # Initialize entry number count andrej@2354: count = 0 andrej@2355: andrej@2354: # Parse entries andrej@2354: for entry in entries: andrej@2354: # Save index and subindex andrej@2354: index = ExtractHexDecValue(entry.getIndex().getcontent()) andrej@2354: subindex = ExtractHexDecValue(entry.getSubIndex()) andrej@2354: # if entry name exists, save entry data andrej@2375: if ExtractName(entry.getName()) is not None: andrej@2354: entry_infos = { andrej@2407: "entry_index": index, andrej@2407: "subindex": subindex, andrej@2407: "name": ExtractName(entry.getName()), edouard@2643: "bitlen": entry.getBitLen() andrej@2407: } edouard@2643: if entry.getDataType() is not None: edouard@2643: entry_infos["type"] = entry.getDataType().getcontent() andrej@2354: self.TxPDOInfo.append(entry_infos) andrej@2354: count += 1 andrej@2355: edouard@2643: categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "sm" : Sm, edouard@2643: "number_of_entry" : count, "exclude_list" : exclude_list} andrej@2354: self.TxPDOCategory.append(categorys) andrej@2354: andrej@2354: # Parsing RxPDO entries andrej@2406: for pdo, _pdo_info in ([(rxpdo, "Outputs") for rxpdo in device.getRxPdo()]): andrej@2354: # Save pdo_index, entry, and name of each entry andrej@2354: pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) andrej@2354: entries = pdo.getEntry() andrej@2354: pdo_name = ExtractName(pdo.getName()) edouard@2643: excludes = pdo.getExclude() edouard@2643: exclude_list = [] edouard@2643: Sm = pdo.getSm() edouard@2643: edouard@2643: if excludes : edouard@2643: for exclude in excludes: edouard@2643: exclude_list.append(ExtractHexDecValue(exclude.getcontent())) andrej@2355: andrej@2354: # Initialize entry number count andrej@2355: count = 0 andrej@2355: andrej@2355: # Parse entries andrej@2354: for entry in entries: andrej@2354: # Save index and subindex andrej@2354: index = ExtractHexDecValue(entry.getIndex().getcontent()) andrej@2354: subindex = ExtractHexDecValue(entry.getSubIndex()) andrej@2354: # if entry name exists, save entry data andrej@2375: if ExtractName(entry.getName()) is not None: andrej@2354: entry_infos = { andrej@2407: "entry_index": index, andrej@2407: "subindex": subindex, andrej@2407: "name": ExtractName(entry.getName()), edouard@2643: "bitlen": str(entry.getBitLen()) andrej@2407: } edouard@2643: if entry.getDataType() is not None: edouard@2643: entry_infos["type"] = entry.getDataType().getcontent() andrej@2354: self.RxPDOInfo.append(entry_infos) andrej@2354: count += 1 andrej@2355: edouard@2643: categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "sm" : Sm, edouard@2643: "number_of_entry" : count, "exclude_list" : exclude_list} edouard@2643: self.RxPDOCategory.append(categorys) andrej@2354: andrej@2354: def GetTxPDOCategory(self): andrej@2354: """ andrej@2354: Get TxPDOCategory data structure (Meta informaton of TxPDO). andrej@2354: TxPDOCategorys : index, name, number of entries andrej@2354: @return TxPDOCategorys andrej@2355: """ andrej@2354: return self.TxPDOCategory andrej@2355: andrej@2354: def GetRxPDOCategory(self): andrej@2354: """ andrej@2354: Get RxPDOCategory data structure (Meta information of RxPDO). andrej@2354: RxPDOCategorys : index, name, number of entries andrej@2354: @return RxPDOCategorys andrej@2355: """ andrej@2354: return self.RxPDOCategory andrej@2355: andrej@2354: def GetTxPDOInfo(self): andrej@2354: """ andrej@2355: Get TxPDOInfo data structure (Detailed information on TxPDO entries). andrej@2354: TxPDOInfos : entry index, sub index, name, length, type andrej@2354: @return TxPDOInfos andrej@2355: """ andrej@2354: return self.TxPDOInfo andrej@2355: andrej@2354: def GetRxPDOInfo(self): andrej@2354: """ andrej@2355: Get RxPDOInfo data structure (Detailed information on RxPDO entries). andrej@2354: RxPDOInfos : entry index, sub index, name, length, type andrej@2354: @return RxPDOInfos andrej@2355: """ andrej@2354: return self.RxPDOInfo andrej@2355: andrej@2354: def ClearDataSet(self): andrej@2354: """ andrej@2354: Initialize PDO management data structure. andrej@2355: """ edouard@2643: self.TxPDOInfo = [] edouard@2643: self.TxPDOCategory = [] edouard@2643: self.RxPDOInfo = [] edouard@2643: self.RxPDOCategory = [] andrej@2355: andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Used EEPROM Management andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Base data types in ETG2000; format = {"Name": "BitSize"} andrej@2354: BaseDataTypeDict = {"BOOL": "01", andrej@2354: "SINT": "02", andrej@2354: "INT": "03", andrej@2354: "DINT": "04", andrej@2354: "USINT": "05", andrej@2354: "UINT": "06", andrej@2354: "UDINT": "07", andrej@2354: "REAL": "08", andrej@2354: "INT24": "10", andrej@2354: "LREAL": "11", andrej@2354: "INT40": "12", andrej@2354: "INT48": "13", andrej@2354: "INT56": "14", andrej@2354: "LINT": "15", andrej@2354: "UINT24": "16", andrej@2354: "UINT40": "18", andrej@2354: "UINT48": "19", andrej@2354: "UINT56": "1a", andrej@2354: "ULINT": "1b", andrej@2354: "BITARR8": "2d", andrej@2354: "BITARR16": "2e", andrej@2354: "BITARR32": "2f", andrej@2354: "BIT1": "30", andrej@2354: "BIT2": "31", andrej@2354: "BIT3": "32", andrej@2354: "BIT4": "33", andrej@2354: "BIT5": "34", andrej@2354: "BIT6": "35", andrej@2354: "BIT7": "36", andrej@2355: "BIT8": "37"} andrej@2355: andrej@2354: def GetSmartViewInfos(self): andrej@2354: """ andrej@2354: Parse XML data for "Smart View" of EEPROM contents. andrej@2354: @return smartview_infos : EEPROM contents dictionary andrej@2355: """ andrej@2354: andrej@2354: smartview_infos = {"eeprom_size": 128, andrej@2354: "pdi_type": 0, andrej@2354: "device_emulation": "False", andrej@2354: "vendor_id": '0x00000000', andrej@2354: "product_code": '0x00000000', andrej@2354: "revision_no": '0x00000000', andrej@2354: "serial_no": '0x00000000', andrej@2354: "supported_mailbox": "", andrej@2354: "mailbox_bootstrapconf_outstart": '0', andrej@2354: "mailbox_bootstrapconf_outlength": '0', andrej@2354: "mailbox_bootstrapconf_instart": '0', andrej@2354: "mailbox_bootstrapconf_inlength": '0', andrej@2354: "mailbox_standardconf_outstart": '0', andrej@2354: "mailbox_standardconf_outlength": '0', andrej@2354: "mailbox_standardconf_instart": '0', andrej@2354: "mailbox_standardconf_inlength": '0'} andrej@2355: andrej@2354: slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) andrej@2354: type_infos = slave.getType() andrej@2406: device, _alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) andrej@2354: andrej@2354: # 'device' represents current slave device selected by user andrej@2354: if device is not None: andrej@2354: for eeprom_element in device.getEeprom().getcontent(): andrej@2354: # get EEPROM size; -- andrej@2354: if eeprom_element["name"] == "ByteSize": andrej@2354: smartview_infos["eeprom_size"] = eeprom_element andrej@2355: andrej@2354: elif eeprom_element["name"] == "ConfigData": andrej@2354: configData_data = self.DecimalToHex(eeprom_element) andrej@2354: # get PDI type; -- address 0x00 andrej@2354: smartview_infos["pdi_type"] = int(configData_data[0:2], 16) andrej@2354: # get state of device emulation; -- address 0x01 andrej@2354: if "{:0>8b}".format(int(configData_data[2:4], 16))[7] == '1': andrej@2354: smartview_infos["device_emulation"] = "True" andrej@2354: andrej@2354: elif eeprom_element["name"] == "BootStrap": andrej@2354: bootstrap_data = "{:0>16x}".format(eeprom_element) andrej@2354: # get bootstrap configuration; -- andrej@2355: for cfg, iter in [("mailbox_bootstrapconf_outstart", 0), andrej@2354: ("mailbox_bootstrapconf_outlength", 1), andrej@2354: ("mailbox_bootstrapconf_instart", 2), andrej@2354: ("mailbox_bootstrapconf_inlength", 3)]: andrej@2354: smartview_infos[cfg] = str(int(bootstrap_data[4*iter+2:4*(iter+1)]+bootstrap_data[4*iter:4*iter+2], 16)) andrej@2355: andrej@2354: # get protocol (profile) types supported by mailbox; - edouard@2643: with device.getMailbox() as mb: edouard@2643: if mb is not None: edouard@2643: for mailbox_protocol in mailbox_protocols: edouard@2643: if getattr(mb, "get%s" % mailbox_protocol)() is not None: edouard@2643: smartview_infos["supported_mailbox"] += "%s, " % mailbox_protocol andrej@2410: smartview_infos["supported_mailbox"] = smartview_infos["supported_mailbox"].strip(", ") andrej@2355: andrej@2354: # get standard configuration of mailbox; - andrej@2354: for sm_element in device.getSm(): andrej@2354: if sm_element.getcontent() == "MBoxOut": andrej@2354: smartview_infos["mailbox_standardconf_outstart"] = str(ExtractHexDecValue(sm_element.getStartAddress())) andrej@2354: smartview_infos["mailbox_standardconf_outlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize())) andrej@2354: elif sm_element.getcontent() == "MBoxIn": andrej@2354: smartview_infos["mailbox_standardconf_instart"] = str(ExtractHexDecValue(sm_element.getStartAddress())) andrej@2354: smartview_infos["mailbox_standardconf_inlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize())) andrej@2354: else: andrej@2354: pass andrej@2354: andrej@2354: # get device identity from - edouard@2643: # vendor ID; by default, pre-defined value in self.ModulesLibrary edouard@2643: # if device type in 'vendor' item equals to actual slave device type, set 'vendor_id' to vendor ID. andrej@2354: for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): andrej@2354: for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]: andrej@2354: if available_device[0] == type_infos["device_type"]: andrej@2354: smartview_infos["vendor_id"] = "0x" + "{:0>8x}".format(vendor_id) andrej@2355: edouard@2643: # product code; andrej@2354: if device.getType().getProductCode() is not None: andrej@2354: product_code = device.getType().getProductCode() andrej@2354: smartview_infos["product_code"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(product_code)) andrej@2355: edouard@2643: # revision number; andrej@2354: if device.getType().getRevisionNo() is not None: andrej@2354: revision_no = device.getType().getRevisionNo() andrej@2354: smartview_infos["revision_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(revision_no)) andrej@2355: edouard@2643: # serial number; andrej@2354: if device.getType().getSerialNo() is not None: andrej@2354: serial_no = device.getType().getSerialNo() andrej@2354: smartview_infos["serial_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(serial_no)) andrej@2355: andrej@2354: return smartview_infos andrej@2355: andrej@2354: else: andrej@2354: return None andrej@2355: andrej@2354: def DecimalToHex(self, decnum): andrej@2354: """ andrej@2355: Convert decimal value into hexadecimal representation. andrej@2354: @param decnum : decimal value andrej@2354: @return hex_data : hexadecimal representation of input value in decimal andrej@2355: """ edouard@2643: value = "%x" % int(decnum, 16) andrej@2354: value_len = len(value) andrej@2354: if (value_len % 2) == 0: andrej@2354: hex_len = value_len andrej@2354: else: andrej@2437: hex_len = (value_len // 2) * 2 + 2 andrej@2355: edouard@2643: hex_data = ("{:0>"+str(hex_len)+"x}").format(int(decnum, 16)) andrej@2355: andrej@2354: return hex_data andrej@2354: andrej@2354: def SiiRead(self): andrej@2354: """ andrej@2354: Get slave EEPROM contents maintained by master device using "ethercat sii_read -p %d" command. andrej@2354: Command example : "ethercat sii_read -p 0" andrej@2354: @return return_val : result of "ethercat sii_read" (binary data) andrej@2355: """ andrej@2406: _error, return_val = self.Controler.RemoteExec(SII_READ % (self.Controler.GetSlavePos()), return_val=None) andrej@2354: self.SiiData = return_val andrej@2354: return return_val andrej@2354: andrej@2354: def SiiWrite(self, binary): andrej@2354: """ andrej@2354: Overwrite slave EEPROM contents using "ethercat sii_write -p %d" command. andrej@2354: Command example : "ethercat sii_write -p 0 - (binary contents)" andrej@2354: @param binary : EEPROM contents in binary data format andrej@2354: @return return_val : result of "ethercat sii_write" (If it succeeds, the return value is NULL.) andrej@2355: """ andrej@2406: _error, return_val = self.Controler.RemoteExec( andrej@2406: SII_WRITE % (self.Controler.GetSlavePos()), andrej@2406: return_val=None, andrej@2406: sii_data=binary) andrej@2355: return return_val andrej@2354: andrej@2354: def LoadData(self): andrej@2354: """ andrej@2354: Loading data from EEPROM use Sii_Read Method andrej@2354: @return self.BinaryCode : slave EEPROM data in binary format (zero-padded) andrej@2355: """ andrej@2354: return_val = self.Controler.CommonMethod.SiiRead() andrej@2354: self.BinaryCode = return_val andrej@2354: self.Controler.SiiData = self.BinaryCode andrej@2354: andrej@2354: # append zero-filled padding data up to EEPROM size andrej@2406: for dummy in range(self.SmartViewInfosFromXML["eeprom_size"] - len(self.BinaryCode)): andrej@2446: self.BinaryCode = self.BinaryCode + self.HexDecode('ff')[0] andrej@2355: andrej@2354: return self.BinaryCode andrej@2354: andrej@2354: def HexRead(self, binary): andrej@2354: """ andrej@2354: Convert binary digit representation into hexadecimal representation for "Hex View" menu. andrej@2354: @param binary : binary digits andrej@2354: @return hexCode : hexadecimal digits andrej@2354: @return hexview_table_row, hexview_table_col : Grid size for "Hex View" UI andrej@2355: """ andrej@2354: row_code = [] andrej@2354: row_text = "" andrej@2354: row = 0 andrej@2354: hex_code = [] andrej@2354: andrej@2354: hexview_table_col = 17 andrej@2355: andrej@2375: for index in range(0, len(binary)): andrej@2354: if len(binary[index]) != 1: andrej@2354: break andrej@2354: else: andrej@2355: digithexstr = hex(ord(binary[index])) andrej@2354: andrej@2354: tempvar2 = digithexstr[2:4] andrej@2354: if len(tempvar2) == 1: andrej@2354: tempvar2 = "0" + tempvar2 andrej@2355: row_code.append(tempvar2) andrej@2355: andrej@2365: if int(digithexstr, 16) >= 32 and int(digithexstr, 16) <= 126: andrej@2354: row_text = row_text + chr(int(digithexstr, 16)) andrej@2354: else: andrej@2354: row_text = row_text + "." andrej@2355: andrej@2375: if index != 0: andrej@2354: if len(row_code) == (hexview_table_col - 1): andrej@2354: row_code.append(row_text) andrej@2354: hex_code.append(row_code) andrej@2354: row_text = "" andrej@2354: row_code = [] andrej@2355: row = row + 1 andrej@2355: andrej@2354: hexview_table_row = row andrej@2355: andrej@2354: return hex_code, hexview_table_row, hexview_table_col andrej@2355: andrej@2354: def GenerateEEPROMList(self, data, direction, length): andrej@2354: """ andrej@2354: Generate EEPROM data list by reconstructing 'data' string. andrej@2354: example : data="12345678", direction=0, length=8 -> eeprom_list=['12', '34', '56', '78'] andrej@2354: data="12345678", direction=1, length=8 -> eeprom_list=['78', '56', '34', '12'] andrej@2354: @param data : string to be reconstructed andrej@2354: @param direction : endianness andrej@2354: @param length : data length andrej@2354: @return eeprom_list : reconstructed list data structure andrej@2355: """ andrej@2354: eeprom_list = [] andrej@2354: andrej@2354: if direction is 0 or 1: andrej@2437: for dummy in range(length//2): andrej@2354: if data == "": andrej@2354: eeprom_list.append("00") andrej@2354: else: andrej@2354: eeprom_list.append(data[direction*(length-2):direction*(length-2)+2]) andrej@2354: data = data[(1-direction)*2:length-direction*2] andrej@2354: length -= 2 andrej@2354: return eeprom_list andrej@2355: andrej@2354: def XmlToEeprom(self): andrej@2354: """ andrej@2354: Extract slave EEPROM contents using slave ESI XML file. andrej@2354: - Mandatory parts andrej@2354: - String category : ExtractEEPROMStringCategory() andrej@2354: - General category : ExtractEEPROMGeneralCategory() andrej@2354: - FMMU category : ExtractEEPROMFMMUCategory andrej@2354: - SyncM category : ExtractEEPROMSyncMCategory() andrej@2354: - Tx/RxPDO category : ExtractEEPROMPDOCategory() andrej@2354: - DC category : ExtractEEPROMDCCategory() andrej@2355: @return eeprom_binary andrej@2355: """ andrej@2354: eeprom = [] andrej@2354: data = "" andrej@2354: eeprom_size = 0 andrej@2354: eeprom_binary = "" andrej@2354: andrej@2354: # 'device' is the slave device of the current EtherCAT slave plugin andrej@2354: slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) andrej@2354: type_infos = slave.getType() andrej@2406: device, _alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) andrej@2355: andrej@2354: if device is not None: andrej@2354: # get ConfigData for EEPROM offset 0x0000-0x000d; -- andrej@2354: for eeprom_element in device.getEeprom().getcontent(): andrej@2354: if eeprom_element["name"] == "ConfigData": andrej@2354: data = self.DecimalToHex(eeprom_element) andrej@2354: eeprom += self.GenerateEEPROMList(data, 0, 28) andrej@2355: andrej@2354: # calculate CRC for EEPROM offset 0x000e-0x000f andrej@2354: crc = 0x48 andrej@2354: for segment in eeprom: andrej@2354: for i in range(8): andrej@2354: bit = crc & 0x80 andrej@2354: crc = (crc << 1) | ((int(segment, 16) >> (7 - i)) & 0x01) andrej@2354: if bit: andrej@2355: crc ^= 0x07 andrej@2406: for dummy in range(8): andrej@2354: bit = crc & 0x80 andrej@2354: crc <<= 1 andrej@2354: if bit: andrej@2355: crc ^= 0x07 andrej@2354: eeprom.append(hex(crc)[len(hex(crc))-3:len(hex(crc))-1]) andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # get VendorID for EEPROM offset 0x0010-0x0013; andrej@2354: data = "" andrej@2354: for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): andrej@2354: for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]: andrej@2354: if available_device[0] == type_infos["device_type"]: andrej@2354: data = "{:0>8x}".format(vendor_id) andrej@2354: eeprom += self.GenerateEEPROMList(data, 1, 8) andrej@2355: andrej@2354: # get Product Code for EEPROM offset 0x0014-0x0017; andrej@2354: data = "" andrej@2354: if device.getType().getProductCode() is not None: andrej@2354: data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getProductCode())) andrej@2354: eeprom += self.GenerateEEPROMList(data, 1, 8) andrej@2355: andrej@2354: # get Revision Number for EEPROM offset 0x0018-0x001b; andrej@2354: data = "" andrej@2354: if device.getType().getRevisionNo() is not None: andrej@2354: data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getRevisionNo())) andrej@2355: eeprom += self.GenerateEEPROMList(data, 1, 8) andrej@2355: andrej@2354: # get Serial Number for EEPROM 0x001c-0x001f; andrej@2354: data = "" andrej@2354: if device.getType().getSerialNo() is not None: andrej@2354: data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getSerialNo())) andrej@2354: eeprom += self.GenerateEEPROMList(data, 1, 8) andrej@2355: andrej@2354: # get Execution Delay for EEPROM 0x0020-0x0021; not analyzed yet andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # get Port0/1 Delay for EEPROM offset 0x0022-0x0025; not analyzed yet andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # reserved for EEPROM offset 0x0026-0x0027; andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: andrej@2354: # get BootStrap for EEPROM offset 0x0028-0x002e; -- andrej@2354: data = "" andrej@2354: for eeprom_element in device.getEeprom().getcontent(): andrej@2354: if eeprom_element["name"] == "BootStrap": edouard@2643: data = "{:0>16x}".format(int(eeprom_element,16)) andrej@2354: eeprom += self.GenerateEEPROMList(data, 0, 16) andrej@2355: andrej@2354: # get Standard Mailbox for EEPROM offset 0x0030-0x0037; - andrej@2354: data = "" andrej@2354: standard_send_mailbox_offset = None andrej@2354: standard_send_mailbox_size = None andrej@2354: standard_receive_mailbox_offset = None andrej@2354: standard_receive_mailbox_size = None andrej@2354: for sm_element in device.getSm(): andrej@2354: if sm_element.getcontent() == "MBoxOut": andrej@2354: standard_receive_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress())) andrej@2354: standard_receive_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize())) andrej@2354: elif sm_element.getcontent() == "MBoxIn": andrej@2354: standard_send_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress())) andrej@2354: standard_send_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize())) andrej@2355: andrej@2354: if standard_receive_mailbox_offset is None: andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(standard_receive_mailbox_offset[2:4]) andrej@2354: eeprom.append(standard_receive_mailbox_offset[0:2]) andrej@2354: if standard_receive_mailbox_size is None: andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(standard_receive_mailbox_size[2:4]) andrej@2354: eeprom.append(standard_receive_mailbox_size[0:2]) andrej@2354: if standard_send_mailbox_offset is None: andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(standard_send_mailbox_offset[2:4]) andrej@2354: eeprom.append(standard_send_mailbox_offset[0:2]) andrej@2354: if standard_send_mailbox_size is None: andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(standard_send_mailbox_size[2:4]) andrej@2354: eeprom.append(standard_send_mailbox_size[0:2]) andrej@2355: andrej@2354: # get supported mailbox protocols for EEPROM offset 0x0038-0x0039; andrej@2354: data = 0 edouard@2643: with device.getMailbox() as mb: edouard@2643: if mb is not None: edouard@2643: for bit, mbprot in enumerate(mailbox_protocols): edouard@2643: if getattr(mb, "get%s" % mbprot)() is not None: edouard@2643: data += 1 << bit andrej@2354: data = "{:0>4x}".format(data) andrej@2354: eeprom.append(data[2:4]) andrej@2354: eeprom.append(data[0:2]) andrej@2355: andrej@2354: # resereved for EEPROM offset 0x003a-0x007b; andrej@2354: for i in range(0x007b-0x003a+0x0001): andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # get EEPROM size for EEPROM offset 0x007c-0x007d; edouard@2643: # Modify by jblee because of update IDE module (minidom -> lxml) andrej@2354: data = "" edouard@2643: for eeprom_element in device.getEeprom().getchildren(): edouard@2643: if eeprom_element.tag == "ByteSize": edouard@2643: eeprom_size = int(objectify.fromstring(eeprom_element.tostring()).text) edouard@2643: data = "{:0>4x}".format(eeprom_size/1024*8-1) andrej@2354: andrej@2354: if data == "": andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(data[2:4]) andrej@2354: eeprom.append(data[0:2]) andrej@2355: andrej@2355: # Version for EEPROM 0x007e-0x007f; edouard@2643: # According to "EtherCAT Slave Device Description(V0.3.0)" andrej@2354: eeprom.append("01") andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # append String Category data andrej@2354: for data in self.ExtractEEPROMStringCategory(device): andrej@2354: eeprom.append(data) andrej@2355: andrej@2354: # append General Category data andrej@2354: for data in self.ExtractEEPROMGeneralCategory(device): andrej@2354: eeprom.append(data) andrej@2355: andrej@2354: # append FMMU Category data andrej@2354: for data in self.ExtractEEPROMFMMUCategory(device): andrej@2354: eeprom.append(data) andrej@2355: andrej@2354: # append SyncM Category data andrej@2354: for data in self.ExtractEEPROMSyncMCategory(device): andrej@2354: eeprom.append(data) andrej@2355: andrej@2354: # append TxPDO Category data andrej@2354: for data in self.ExtractEEPROMPDOCategory(device, "TxPdo"): andrej@2354: eeprom.append(data) andrej@2355: andrej@2354: # append RxPDO Category data andrej@2354: for data in self.ExtractEEPROMPDOCategory(device, "RxPdo"): andrej@2354: eeprom.append(data) andrej@2355: andrej@2354: # append DC Category data andrej@2354: for data in self.ExtractEEPROMDCCategory(device): andrej@2354: eeprom.append(data) andrej@2355: andrej@2354: # append padding andrej@2354: padding = eeprom_size-len(eeprom) andrej@2354: for i in range(padding): andrej@2354: eeprom.append("ff") andrej@2355: andrej@2354: # convert binary code andrej@2354: for index in range(eeprom_size): andrej@2446: eeprom_binary = eeprom_binary + self.HexDecode(eeprom[index])[0] andrej@2355: andrej@2354: return eeprom_binary andrej@2355: andrej@2354: def ExtractEEPROMStringCategory(self, device): andrej@2354: """ andrej@2354: Extract "Strings" category data from slave ESI XML and generate EEPROM image data. andrej@2354: @param device : 'device' object in the slave ESI XML andrej@2354: @return eeprom : "Strings" category EEPROM image data andrej@2355: """ andrej@2354: eeprom = [] andrej@2354: self.Strings = [] andrej@2355: data = "" andrej@2361: count = 0 # string counter andrej@2361: padflag = False # padding flag if category length is odd andrej@2355: andrej@2354: # index information for General Category in EEPROM andrej@2354: self.GroupIdx = 0 andrej@2354: self.ImgIdx = 0 andrej@2354: self.OrderIdx = 0 andrej@2354: self.NameIdx = 0 andrej@2355: andrej@2355: # flag for preventing duplicated vendor specific data andrej@2354: typeflag = False andrej@2354: grouptypeflag = False andrej@2354: groupnameflag = False andrej@2354: devnameflag = False andrej@2354: imageflag = False andrej@2355: andrej@2354: # vendor specific data andrej@2354: # element1; ---- andrej@2354: # vendor_specific_data : vendor specific data (binary type) andrej@2354: vendor_specific_data = "" andrej@2354: # vendor_spec_strings : list of vendor specific "strings" for preventing duplicated strings andrej@2354: vendor_spec_strings = [] andrej@2354: for element in device.getType().getcontent(): andrej@2354: data += element andrej@2434: if data != "" and isinstance(data, text): andrej@2355: for vendor_spec_string in vendor_spec_strings: andrej@2354: if data == vendor_spec_string: andrej@2354: self.OrderIdx = vendor_spec_strings.index(data)+1 andrej@2354: typeflag = True andrej@2354: break andrej@2354: if typeflag is False: andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: vendor_spec_strings.append(data) andrej@2354: typeflag = True andrej@2354: self.OrderIdx = count andrej@2354: vendor_specific_data += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: vendor_specific_data += "{:0>2x}".format(ord(data[character])) andrej@2354: data = "" andrej@2355: edouard@2643: # element2-1; ---- andrej@2354: data = device.getGroupType() andrej@2434: if data is not None and isinstance(data, text): andrej@2354: for vendor_spec_string in vendor_spec_strings: andrej@2354: if data == vendor_spec_string: andrej@2354: self.GroupIdx = vendor_spec_strings.index(data)+1 andrej@2354: grouptypeflag = True andrej@2354: break andrej@2354: if grouptypeflag is False: andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: vendor_spec_strings.append(data) andrej@2354: grouptypeflag = True andrej@2354: self.GroupIdx = count andrej@2354: vendor_specific_data += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: vendor_specific_data += "{:0>2x}".format(ord(data[character])) andrej@2355: andrej@2355: # element2-2; --- andrej@2355: if grouptypeflag is False: andrej@2354: if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: andrej@2406: for _vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): andrej@2354: for group_type, group_etc in vendor["groups"].iteritems(): andrej@2354: for device_item in group_etc["devices"]: andrej@2355: if device == device_item[1]: andrej@2354: data = group_type andrej@2434: if data is not None and isinstance(data, text): andrej@2354: for vendor_spec_string in vendor_spec_strings: andrej@2354: if data == vendor_spec_string: andrej@2354: self.GroupIdx = vendor_spec_strings.index(data)+1 andrej@2354: grouptypeflag = True andrej@2354: break andrej@2354: if grouptypeflag is False: andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: vendor_spec_strings.append(data) andrej@2354: grouptypeflag = True andrej@2354: self.GroupIdx = count andrej@2354: vendor_specific_data += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: vendor_specific_data += "{:0>2x}".format(ord(data[character])) andrej@2354: data = "" andrej@2355: andrej@2354: # element3; ---- andrej@2354: if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: andrej@2406: for _vendorId, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): andrej@2354: for group_type, group_etc in vendor["groups"].iteritems(): andrej@2354: for device_item in group_etc["devices"]: andrej@2354: if device == device_item[1]: andrej@2354: data = group_etc["name"] andrej@2434: if data != "" and isinstance(data, text): andrej@2354: for vendor_spec_string in vendor_spec_strings: andrej@2354: if data == vendor_spec_string: andrej@2354: groupnameflag = True andrej@2354: break andrej@2354: if groupnameflag is False: andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: vendor_spec_strings.append(data) andrej@2354: groupnameflag = True andrej@2354: vendor_specific_data += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: vendor_specific_data += "{:0>2x}".format(ord(data[character])) edouard@2643: andrej@2354: data = "" andrej@2355: andrej@2354: # element4; ---- andrej@2354: for element in device.getName(): andrej@2365: if element.getLcId() == 1 or element.getLcId() == 1033: andrej@2354: data = element.getcontent() andrej@2434: if data != "" and isinstance(data, text): andrej@2354: for vendor_spec_string in vendor_spec_strings: andrej@2354: if data == vendor_spec_string: andrej@2354: self.NameIdx = vendor_spec_strings.index(data)+1 andrej@2354: devnameflag = True andrej@2354: break andrej@2354: if devnameflag is False: andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: vendor_spec_strings.append(data) andrej@2354: devnameflag = True andrej@2354: self.NameIdx = count andrej@2354: vendor_specific_data += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: vendor_specific_data += "{:0>2x}".format(ord(data[character])) andrej@2354: data = "" andrej@2355: andrej@2354: # element5-1; ---- andrej@2354: if device.getcontent() is not None: andrej@2354: data = device.getcontent() andrej@2434: if data is not None and isinstance(data, text): andrej@2354: for vendor_spec_string in vendor_spec_strings: andrej@2354: if data == vendor_spec_string: andrej@2354: self.ImgIdx = vendor_spec_strings.index(data)+1 andrej@2354: imageflag = True andrej@2354: break andrej@2354: if imageflag is False: andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: vendor_spec_strings.append(data) andrej@2354: imageflag = True andrej@2354: self.ImgIdx = count andrej@2354: vendor_specific_data += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: vendor_specific_data += "{:0>2x}".format(ord(data[character])) andrej@2355: andrej@2354: # element5-2; ---- andrej@2354: if imageflag is False: andrej@2354: if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: andrej@2406: for _vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): andrej@2354: for group_type, group_etc in vendor["groups"].iteritems(): andrej@2354: for device_item in group_etc["devices"]: andrej@2354: if device == device_item[1]: andrej@2354: data = group_etc andrej@2434: if data is not None and isinstance(data, text): andrej@2354: for vendor_spec_string in vendor_spec_strings: andrej@2354: if data == vendor_spec_string: andrej@2354: self.ImgIdx = vendor_spec_strings.index(data)+1 andrej@2354: imageflag = True andrej@2354: break andrej@2354: if imageflag is False: andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: vendor_spec_strings.append(data) andrej@2354: imageflag = True andrej@2354: self.ImgIdx = count andrej@2354: vendor_specific_data += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: vendor_specific_data += "{:0>2x}".format(ord(data[character])) andrej@2354: data = "" andrej@2355: andrej@2354: # DC related elements andrej@2354: # ------ andrej@2354: dc_related_elements = "" andrej@2354: if device.getDc() is not None: andrej@2354: for element in device.getDc().getOpMode(): andrej@2354: data = element.getName() andrej@2417: if data != "": andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: dc_related_elements += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: dc_related_elements += "{:0>2x}".format(ord(data[character])) andrej@2354: data = "" andrej@2355: andrej@2354: # Input elements(TxPDO) andrej@2354: # ----; Name andrej@2354: input_elements = "" andrej@2354: inputs = [] andrej@2354: for element in device.getTxPdo(): andrej@2354: for name in element.getName(): andrej@2354: data = name.getcontent() andrej@2354: for input in inputs: andrej@2355: if data == input: andrej@2354: data = "" andrej@2417: if data != "": andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: inputs.append(data) andrej@2354: input_elements += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: input_elements += "{:0>2x}".format(ord(data[character])) andrej@2355: data = "" andrej@2354: for entry in element.getEntry(): andrej@2354: for name in entry.getName(): andrej@2354: data = name.getcontent() andrej@2354: for input in inputs: andrej@2355: if data == input: andrej@2354: data = "" andrej@2417: if data != "": andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: inputs.append(data) andrej@2354: input_elements += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: input_elements += "{:0>2x}".format(ord(data[character])) andrej@2354: data = "" andrej@2355: andrej@2354: # Output elements(RxPDO) andrej@2354: # ----; Name andrej@2354: output_elements = "" andrej@2354: outputs = [] andrej@2354: for element in device.getRxPdo(): andrej@2354: for name in element.getName(): andrej@2354: data = name.getcontent() andrej@2354: for output in outputs: andrej@2355: if data == output: andrej@2354: data = "" andrej@2417: if data != "": andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: outputs.append(data) andrej@2354: output_elements += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: output_elements += "{:0>2x}".format(ord(data[character])) andrej@2355: data = "" andrej@2354: for entry in element.getEntry(): andrej@2354: for name in entry.getName(): andrej@2354: data = name.getcontent() andrej@2354: for output in outputs: andrej@2355: if data == output: andrej@2354: data = "" andrej@2417: if data != "": andrej@2354: count += 1 andrej@2354: self.Strings.append(data) andrej@2354: outputs.append(data) andrej@2354: output_elements += "{:0>2x}".format(len(data)) andrej@2354: for character in range(len(data)): andrej@2354: output_elements += "{:0>2x}".format(ord(data[character])) andrej@2355: data = "" andrej@2355: andrej@2354: # form eeprom data andrej@2354: # category header andrej@2354: eeprom.append("0a") andrej@2354: eeprom.append("00") andrej@2354: # category length (word); 1 word is 4 bytes. "+2" is the length of string's total number andrej@2354: length = len(vendor_specific_data + dc_related_elements + input_elements + output_elements) + 2 andrej@2358: if length % 4 == 0: andrej@2354: pass andrej@2354: else: andrej@2365: length += length % 4 andrej@2354: padflag = True andrej@2437: eeprom.append("{:0>4x}".format(length//4)[2:4]) andrej@2437: eeprom.append("{:0>4x}".format(length//4)[0:2]) andrej@2354: # total numbers of strings andrej@2354: eeprom.append("{:0>2x}".format(count)) andrej@2354: for element in [vendor_specific_data, andrej@2354: dc_related_elements, andrej@2354: input_elements, andrej@2354: output_elements]: andrej@2437: for dummy in range(len(element)//2): andrej@2354: if element == "": andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(element[0:2]) andrej@2355: element = element[2:len(element)] andrej@2355: # padding if length is odd bytes andrej@2354: if padflag is True: andrej@2354: eeprom.append("ff") andrej@2355: andrej@2354: return eeprom andrej@2355: andrej@2354: def ExtractEEPROMGeneralCategory(self, device): andrej@2354: """ andrej@2354: Extract "General" category data from slave ESI XML and generate EEPROM image data. andrej@2354: @param device : 'device' object in the slave ESI XML andrej@2354: @return eeprom : "Strings" category EEPROM image data andrej@2355: """ andrej@2354: eeprom = [] andrej@2355: andrej@2354: # category header andrej@2354: eeprom.append("1e") andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # category length andrej@2354: eeprom.append("10") andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # word 1 : Group Type index and Image index in STRINGS Category andrej@2354: eeprom.append("{:0>2x}".format(self.GroupIdx)) andrej@2354: eeprom.append("{:0>2x}".format(self.ImgIdx)) andrej@2355: andrej@2354: # word 2 : Device Type index and Device Name index in STRINGS Category andrej@2354: eeprom.append("{:0>2x}".format(self.OrderIdx)) andrej@2354: eeprom.append("{:0>2x}".format(self.NameIdx)) andrej@2355: andrej@2354: # word 3 : Physical Layer Port info. and CoE Details andrej@2361: eeprom.append("01") # Physical Layer Port info - assume 01 andrej@2354: # CoE Details; ----- andrej@2361: coe_details = 1 # sdo enabled edouard@2643: with device.getMailbox() as mb edouard@2643: if mb is not None: edouard@2643: coe = mb.getCoE() edouard@2643: if coe is not None: edouard@2643: for bit, flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig", edouard@2643: "PdoUpload", "CompleteAccess"]): edouard@2643: if getattr(coe, "get%s" % flag)() is not None: edouard@2643: coe_details += 1 << bit edouard@2643: eeprom.append("{:0>2x}".format(coe_details)) edouard@2643: edouard@2643: # word 4 : FoE Details and EoE Details edouard@2643: # FoE Details; ----- edouard@2643: if mb is not None and mb.getFoE() is not None: edouard@2643: eeprom.append("01") edouard@2643: else: edouard@2643: eeprom.append("00") edouard@2643: # EoE Details; ----- edouard@2643: if mb is not None and mb.getEoE() is not None: edouard@2643: eeprom.append("01") edouard@2643: else: edouard@2643: eeprom.append("00") edouard@2643: edouard@2643: # word 5 : SoE Channels(reserved) and DS402 Channels edouard@2643: # SoE Details; ----- edouard@2643: if mb is not None and mb.getSoE() is not None: edouard@2643: eeprom.append("01") edouard@2643: else: edouard@2643: eeprom.append("00") edouard@2643: # DS402Channels; -----: DS402Channels edouard@2643: ds402ch = False edouard@2643: if mb is not None: edouard@2643: coe = mb.getCoE() edouard@2643: if coe is not None: edouard@2643: ds402ch = coe.getDS402Channels() andrej@2363: eeprom.append("01" if ds402ch in [True, 1] else "00") andrej@2355: andrej@2354: # word 6 : SysmanClass(reserved) and Flags andrej@2361: eeprom.append("00") # reserved andrej@2355: # Flags andrej@2354: en_safeop = False andrej@2354: en_lrw = False andrej@2374: if device.getType().getTcCfgModeSafeOp() is True \ andrej@2384: or device.getType().getTcCfgModeSafeOp() == 1: andrej@2354: en_safeop = True andrej@2374: if device.getType().getUseLrdLwr() is True \ andrej@2384: or device.getType().getUseLrdLwr() == 1: andrej@2354: en_lrw = True andrej@2355: andrej@2354: flags = "0b"+"000000"+str(int(en_lrw))+str(int(en_safeop)) andrej@2354: eeprom.append("{:0>2x}".format(int(flags, 2))) andrej@2355: andrej@2354: # word 7 : Current On EBus (assume 0x0000) andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: # after word 7; couldn't analyze yet andrej@2354: eeprom.append("03") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("11") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: return eeprom andrej@2355: andrej@2354: def ExtractEEPROMFMMUCategory(self, device): andrej@2354: """ andrej@2354: Extract "FMMU" category data from slave ESI XML and generate EEPROM image data. andrej@2354: @param device : 'device' object in the slave ESI XML andrej@2354: @return eeprom : "Strings" category EEPROM image data andrej@2355: """ andrej@2354: eeprom = [] andrej@2354: data = "" andrej@2361: count = 0 # number of FMMU andrej@2354: padflag = False andrej@2355: andrej@2354: for fmmu in device.getFmmu(): andrej@2354: count += 1 andrej@2354: if fmmu.getcontent() == "Outputs": andrej@2354: data += "01" andrej@2354: if fmmu.getcontent() == "Inputs": andrej@2354: data += "02" andrej@2354: if fmmu.getcontent() == "MBoxState": andrej@2354: data += "03" andrej@2355: andrej@2354: # construct of EEPROM data andrej@2417: if data != "": andrej@2354: # category header andrej@2354: eeprom.append("28") andrej@2354: eeprom.append("00") andrej@2354: # category length andrej@2358: if count % 2 == 1: andrej@2354: padflag = True andrej@2437: eeprom.append("{:0>4x}".format((count+1)//2)[2:4]) andrej@2437: eeprom.append("{:0>4x}".format((count+1)//2)[0:2]) andrej@2355: else: andrej@2437: eeprom.append("{:0>4x}".format((count)//2)[2:4]) andrej@2437: eeprom.append("{:0>4x}".format((count)//2)[0:2]) andrej@2406: for dummy in range(count): andrej@2354: if data == "": andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(data[0:2]) andrej@2354: data = data[2:len(data)] andrej@2355: # padding if length is odd bytes andrej@2354: if padflag is True: andrej@2355: eeprom.append("ff") andrej@2355: andrej@2354: return eeprom andrej@2355: andrej@2354: def ExtractEEPROMSyncMCategory(self, device): andrej@2354: """ andrej@2354: Extract "SyncM" category data from slave ESI XML and generate EEPROM image data. andrej@2354: @param device : 'device' object in the slave ESI XML andrej@2354: @return eeprom : "Strings" category EEPROM image data andrej@2355: """ andrej@2354: eeprom = [] andrej@2354: data = "" andrej@2363: number = {"MBoxOut": "01", "MBoxIn": "02", "Outputs": "03", "Inputs": "04"} andrej@2355: andrej@2354: for sm in device.getSm(): andrej@2354: for attr in [sm.getStartAddress(), andrej@2354: sm.getDefaultSize(), andrej@2354: sm.getControlByte()]: andrej@2354: if attr is not None: andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(attr))[2:4] andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(attr))[0:2] andrej@2354: else: andrej@2355: data += "0000" andrej@2374: if sm.getEnable() == "1" or sm.getEnable() is True: andrej@2354: data += "01" andrej@2354: else: andrej@2354: data += "00" andrej@2354: data += number[sm.getcontent()] andrej@2355: andrej@2417: if data != "": andrej@2354: # category header andrej@2354: eeprom.append("29") andrej@2354: eeprom.append("00") andrej@2355: # category length andrej@2437: eeprom.append("{:0>4x}".format(len(data)//4)[2:4]) andrej@2437: eeprom.append("{:0>4x}".format(len(data)//4)[0:2]) andrej@2437: for dummy in range(len(data)//2): andrej@2354: if data == "": andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(data[0:2]) andrej@2354: data = data[2:len(data)] andrej@2354: andrej@2354: return eeprom andrej@2355: andrej@2354: def ExtractEEPROMPDOCategory(self, device, pdotype): andrej@2354: """ andrej@2354: Extract ""PDO (Tx, Rx)"" category data from slave ESI XML and generate EEPROM image data. andrej@2354: @param device : 'device' object in the slave ESI XML andrej@2354: @param pdotype : identifier whether "TxPDO" or "RxPDO". andrej@2354: @return eeprom : "Strings" category EEPROM image data andrej@2355: """ andrej@2354: eeprom = [] andrej@2354: data = "" andrej@2354: count = 0 andrej@2354: en_fixed = False andrej@2354: en_mandatory = False andrej@2354: en_virtual = False andrej@2355: andrej@2358: for element in eval("device.get%s()" % pdotype): andrej@2354: # PDO Index andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[2:4] andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[0:2] andrej@2354: # Number of Entries andrej@2354: data += "{:0>2x}".format(len(element.getEntry())) andrej@2354: # About Sync Manager andrej@2354: if element.getSm() is not None: andrej@2354: data += "{:0>2x}".format(element.getSm()) andrej@2354: else: andrej@2354: data += "ff" andrej@2354: # Reference to DC Synch (according to ET1100 documentation) - assume 0 andrej@2354: data += "00" andrej@2354: # Name Index andrej@2354: objname = "" andrej@2354: for name in element.getName(): andrej@2354: objname = name.getcontent() andrej@2354: for name in self.Strings: andrej@2354: count += 1 andrej@2354: if objname == name: andrej@2354: break andrej@2354: if len(self.Strings)+1 == count: andrej@2354: data += "00" andrej@2354: else: andrej@2354: data += "{:0>2x}".format(count) andrej@2354: count = 0 andrej@2354: # Flags; by Fixed, Mandatory, Virtual attributes ? andrej@2374: if element.getFixed() is True or 1: andrej@2354: en_fixed = True andrej@2374: if element.getMandatory() is True or 1: andrej@2354: en_mandatory = True andrej@2374: if element.getVirtual() is True or element.getVirtual(): andrej@2354: en_virtual = True andrej@2354: data += str(int(en_fixed)) + str(int(en_mandatory)) + str(int(en_virtual)) + "0" andrej@2355: andrej@2354: for entry in element.getEntry(): andrej@2354: # Entry Index andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[2:4] andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[0:2] andrej@2354: # Subindex andrej@2354: data += "{:0>2x}".format(int(entry.getSubIndex())) andrej@2354: # Entry Name Index andrej@2354: objname = "" andrej@2354: for name in entry.getName(): andrej@2354: objname = name.getcontent() andrej@2354: for name in self.Strings: andrej@2354: count += 1 andrej@2354: if objname == name: andrej@2354: break andrej@2354: if len(self.Strings)+1 == count: andrej@2354: data += "00" andrej@2354: else: andrej@2354: data += "{:0>2x}".format(count) andrej@2354: count = 0 andrej@2354: # DataType andrej@2354: if entry.getDataType() is not None: andrej@2354: if entry.getDataType().getcontent() in self.BaseDataTypeDict: andrej@2354: data += self.BaseDataTypeDict[entry.getDataType().getcontent()] andrej@2354: else: andrej@2354: data += "00" andrej@2354: else: andrej@2354: data += "00" andrej@2354: # BitLen andrej@2354: if entry.getBitLen() is not None: andrej@2354: data += "{:0>2x}".format(int(entry.getBitLen())) andrej@2354: else: andrej@2354: data += "00" andrej@2354: # Flags; by Fixed attributes ? andrej@2354: en_fixed = False andrej@2374: if entry.getFixed() is True or entry.getFixed() == 1: andrej@2354: en_fixed = True andrej@2354: data += str(int(en_fixed)) + "000" andrej@2355: andrej@2417: if data != "": andrej@2354: # category header andrej@2354: if pdotype == "TxPdo": andrej@2354: eeprom.append("32") andrej@2354: elif pdotype == "RxPdo": andrej@2354: eeprom.append("33") andrej@2354: else: andrej@2354: eeprom.append("00") andrej@2354: eeprom.append("00") andrej@2355: # category length andrej@2437: eeprom.append("{:0>4x}".format(len(data)//4)[2:4]) andrej@2437: eeprom.append("{:0>4x}".format(len(data)//4)[0:2]) andrej@2354: data = str(data.lower()) andrej@2437: for dummy in range(len(data)//2): andrej@2354: if data == "": andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(data[0:2]) andrej@2354: data = data[2:len(data)] andrej@2355: andrej@2354: return eeprom andrej@2355: andrej@2354: def ExtractEEPROMDCCategory(self, device): andrej@2354: """ andrej@2354: Extract "DC(Distributed Clock)" category data from slave ESI XML and generate EEPROM image data. andrej@2354: @param device : 'device' object in the slave ESI XML andrej@2354: @return eeprom : "Strings" category EEPROM image data andrej@2355: """ andrej@2354: eeprom = [] andrej@2354: data = "" andrej@2354: count = 0 andrej@2354: namecount = 0 andrej@2355: andrej@2354: if device.getDc() is not None: andrej@2354: for element in device.getDc().getOpMode(): andrej@2354: count += 1 andrej@2354: # assume that word 1-7 are 0x0000 andrej@2354: data += "0000" andrej@2354: data += "0000" andrej@2354: data += "0000" andrej@2354: data += "0000" andrej@2354: data += "0000" andrej@2354: data += "0000" andrej@2354: data += "0000" andrej@2354: # word 8-10 andrej@2354: # AssignActivate andrej@2354: if element.getAssignActivate() is not None: andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[2:4] andrej@2354: data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[0:2] andrej@2354: else: andrej@2354: data += "0000" andrej@2354: # Factor of CycleTimeSync0 ? and default is 1? andrej@2354: if element.getCycleTimeSync0() is not None: andrej@2354: if element.getCycleTimeSync0().getFactor() is not None: andrej@2354: data += "{:0>2x}".format(int(element.getCycleTimeSync0().getFactor())) andrej@2354: data += "00" andrej@2354: else: andrej@2354: data += "0100" andrej@2354: else: andrej@2354: data += "0100" andrej@2354: # Index of Name in STRINGS Category andrej@2354: # Name Index andrej@2354: objname = "" andrej@2354: for name in element.getName(): andrej@2354: objname += name andrej@2354: for name in self.Strings: andrej@2354: namecount += 1 andrej@2354: if objname == name: andrej@2354: break andrej@2354: if len(self.Strings)+1 == namecount: andrej@2354: data += "00" andrej@2354: else: andrej@2354: data += "{:0>2x}".format(namecount) andrej@2354: namecount = 0 andrej@2354: data += "00" andrej@2354: # assume that word 11-12 are 0x0000 andrej@2354: data += "0000" andrej@2354: data += "0000" andrej@2355: andrej@2417: if data != "": andrej@2354: # category header andrej@2354: eeprom.append("3c") andrej@2354: eeprom.append("00") andrej@2355: # category length andrej@2437: eeprom.append("{:0>4x}".format(len(data)//4)[2:4]) andrej@2437: eeprom.append("{:0>4x}".format(len(data)//4)[0:2]) andrej@2354: data = str(data.lower()) andrej@2437: for dummy in range(len(data)//2): andrej@2354: if data == "": andrej@2354: eeprom.append("00") andrej@2354: else: andrej@2354: eeprom.append(data[0:2]) andrej@2354: data = data[2:len(data)] andrej@2355: andrej@2354: return eeprom andrej@2355: andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Used Register Access andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: def RegRead(self, offset, length): andrej@2354: """ andrej@2354: Read slave ESC register content using "ethercat reg_read -p %d %s %s" command. andrej@2354: Command example : "ethercat reg_read -p 0 0x0c00 0x0400" andrej@2354: @param offset : register address andrej@2354: @param length : register length andrej@2354: @return return_val : register data andrej@2355: """ andrej@2406: _error, return_val = self.Controler.RemoteExec( andrej@2406: REG_READ % (self.Controler.GetSlavePos(), offset, length), andrej@2406: return_val=None) andrej@2355: return return_val andrej@2355: edouard@2643: def MultiRegRead(self, slave_num, reg_infos): edouard@2643: """ edouard@2643: edouard@2643: @slave_num: edouard@2643: @param addr_info: edouard@2643: @return return_val: edouard@2643: """ edouard@2643: reg_info_str = "" edouard@2643: for reg_info in reg_infos: edouard@2643: reg_info_str = reg_info_str + "%s|" % reg_info edouard@2643: reg_info_str = reg_info_str.strip("|") edouard@2643: edouard@2643: _error, return_val = self.Controler.RemoteExec(\ edouard@2643: MULTI_REG_READ%(slave_num, reg_info_str), edouard@2643: return_val = None) edouard@2643: edouard@2643: return return_val edouard@2643: andrej@2354: def RegWrite(self, address, data): andrej@2354: """ andrej@2354: Write data to slave ESC register using "ethercat reg_write -p %d %s %s" command. andrej@2354: Command example : "ethercat reg_write -p 0 0x0c04 0x0001" andrej@2354: @param address : register address andrej@2354: @param data : data to write andrej@2354: @return return_val : the execution result of "ethercat reg_write" (for error check) andrej@2355: """ andrej@2406: _error, return_val = self.Controler.RemoteExec( andrej@2406: REG_WRITE % (self.Controler.GetSlavePos(), address, data), andrej@2406: return_val=None) andrej@2355: return return_val andrej@2355: andrej@2354: def Rescan(self): andrej@2354: """ andrej@2354: Synchronize EEPROM data in master controller with the data in slave device after EEPROM write. andrej@2354: Command example : "ethercat rescan -p 0" andrej@2355: """ andrej@2406: _error, _return_val = self.Controler.RemoteExec(RESCAN % (self.Controler.GetSlavePos()), return_val=None) andrej@2355: andrej@2356: # ------------------------------------------------------------------------------- edouard@2643: # Used DC Configuration edouard@2643: #------------------------------------------------------------------------------- edouard@2643: def LoadESIData(self): edouard@2643: return_data = [] edouard@2643: slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) edouard@2643: type_infos = slave.getType() edouard@2643: device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) edouard@2643: if device.getDc() is not None: edouard@2643: for OpMode in device.getDc().getOpMode(): edouard@2643: temp_data = { edouard@2643: "desc" : OpMode.getDesc() if OpMode.getDesc() is not None else "Unused", edouard@2643: "assign_activate" : OpMode.getAssignActivate() \ edouard@2643: if OpMode.getAssignActivate() is not None else "#x0000", edouard@2643: "cycletime_sync0" : OpMode.getCycleTimeSync0().getcontent() \ edouard@2643: if OpMode.getCycleTimeSync0() is not None else None, edouard@2643: "shifttime_sync0" : OpMode.getShiftTimeSync0().getcontent() \ edouard@2643: if OpMode.getShiftTimeSync0() is not None else None, edouard@2643: "cycletime_sync1" : OpMode.getShiftTimeSync1().getcontent() \ edouard@2643: if OpMode.getShiftTimeSync1() is not None else None, edouard@2643: "shifttime_sync1" : OpMode.getShiftTimeSync1().getcontent() \ edouard@2643: if OpMode.getShiftTimeSync1() is not None else None edouard@2643: } edouard@2643: edouard@2643: if OpMode.getCycleTimeSync0() is not None: edouard@2643: temp_data["cycletime_sync0_factor"] = OpMode.getCycleTimeSync0().getFactor() edouard@2643: edouard@2643: if OpMode.getCycleTimeSync1() is not None: edouard@2643: temp_data["cycletime_sync1_factor"] = OpMode.getCycleTimeSync1().getFactor() edouard@2643: edouard@2643: return_data.append(temp_data) edouard@2643: edouard@2643: return return_data edouard@2643: edouard@2643: #------------------------------------------------------------------------------- andrej@2354: # Common Use Methods andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: def CheckConnect(self, cyclic_flag): andrej@2354: """ andrej@2355: Check connection status (1) between Beremiz and the master (2) between the master and the slave. andrej@2354: @param cyclic_flag: 0 - one shot, 1 - periodic andrej@2354: @return True or False andrej@2355: """ andrej@2354: if self.Controler.GetCTRoot()._connector is not None: andrej@2355: # Check connection between the master and the slave. andrej@2354: # Command example : "ethercat xml -p 0" andrej@2406: _error, return_val = self.Controler.RemoteExec(SLAVE_XML % (self.Controler.GetSlavePos()), return_val=None) andrej@2354: number_of_lines = return_val.split("\n") andrej@2375: if len(number_of_lines) <= 2: # No slave connected to the master controller andrej@2375: if not cyclic_flag: andrej@2423: self.CreateErrorDialog(_('No connected slaves')) andrej@2354: return False andrej@2355: andrej@2375: elif len(number_of_lines) > 2: andrej@2354: return True andrej@2355: else: andrej@2354: # The master controller is not connected to Beremiz host andrej@2375: if not cyclic_flag: andrej@2423: self.CreateErrorDialog(_('PLC not connected!')) andrej@2354: return False andrej@2355: andrej@2354: def CreateErrorDialog(self, mention): andrej@2354: """ andrej@2354: Create a dialog to indicate error or warning. andrej@2354: @param mention : Error String andrej@2355: """ andrej@2354: app_frame = self.Controler.GetCTRoot().AppFrame andrej@2382: dlg = wx.MessageDialog(app_frame, mention, andrej@2423: _(' Warning...'), andrej@2382: wx.OK | wx.ICON_INFORMATION) andrej@2354: dlg.ShowModal() andrej@2355: dlg.Destroy()