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: andrej@2356: # -------------------------------------------------- andrej@2354: # Remote Exec Etherlab Commands andrej@2356: # -------------------------------------------------- andrej@2354: 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: andrej@2354: # ethercat sdos -p (slave position) andrej@2354: SLAVE_SDO = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat sdos -p %d") andrej@2355: returnVal =result andrej@2354: """ andrej@2354: andrej@2354: # ethercat upload -p (slave position) (main index) (sub index) andrej@2354: GET_SLOW_SDO = """ andrej@2354: import commands andrej@2354: result = commands.getoutput("ethercat upload -p %d %s %s") andrej@2355: returnVal =result 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: 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: 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: andrej@2354: # category of SDO data andrej@2354: DatatypeDescription, CommunicationObject, ManufacturerSpecific, \ andrej@2384: ProfileSpecific, Reserved, AllSDOData = range(6) andrej@2355: andrej@2354: # store the execution result of "ethercat sdos" command into SaveSDOData. andrej@2354: SaveSDOData = [] andrej@2355: andrej@2355: # 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 GetSlaveSDOFromSlave(self): andrej@2354: """ andrej@2354: Get SDO objects information of current slave using "ethercat sdos -p %d" command. andrej@2354: Command example : "ethercat sdos -p 0" andrej@2354: @return return_val : execution results of "ethercat sdos" command (need to be parsed later) andrej@2355: """ andrej@2406: _error, return_val = self.Controler.RemoteExec(SLAVE_SDO % (self.Controler.GetSlavePos()), return_val=None) andrej@2355: return return_val andrej@2355: 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 andrej@2355: """ andrej@2406: _error, _return_val = self.Controler.RemoteExec( andrej@2406: SDO_DOWNLOAD % (data_type, self.Controler.GetSlavePos(), idx, sub_idx, value), andrej@2406: return_val=None) andrej@2355: 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: andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: # Used PDO Monitoring andrej@2356: # ------------------------------------------------------------------------------- andrej@2354: def RequestPDOInfo(self): andrej@2354: """ andrej@2354: Load slave information from RootClass (XML data) and parse the information (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()) 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()), andrej@2407: "bitlen": entry.getBitLen(), andrej@2407: "type": entry.getDataType().getcontent() andrej@2407: } andrej@2354: self.TxPDOInfo.append(entry_infos) andrej@2354: count += 1 andrej@2355: andrej@2375: categorys = {"pdo_index": pdo_index, "name": pdo_name, "number_of_entry": count} 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()) 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()), andrej@2407: "bitlen": str(entry.getBitLen()), andrej@2407: "type": entry.getDataType().getcontent() andrej@2407: } andrej@2354: self.RxPDOInfo.append(entry_infos) andrej@2354: count += 1 andrej@2355: andrej@2375: categorys = {"pdo_index": pdo_index, "name": pdo_name, "number_of_entry": count} andrej@2355: 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: """ andrej@2354: self.TxPDOInfos = [] andrej@2354: self.TxPDOCategorys = [] andrej@2354: self.RxPDOInfos = [] andrej@2354: self.RxPDOCategorys = [] 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; - andrej@2354: mb = device.getMailbox() andrej@2354: if mb is not None: andrej@2354: for mailbox_protocol in mailbox_protocols: andrej@2363: if getattr(mb, "get%s" % mailbox_protocol)() is not None: andrej@2358: 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 - andrej@2354: # vendor ID; by default, pre-defined value in self.ModulesLibrary andrej@2354: # 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: andrej@2355: # 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: andrej@2355: # 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: andrej@2354: # 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: """ andrej@2354: value = "%x" % decnum 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: andrej@2354: hex_data = ("{:0>"+str(hex_len)+"x}").format(decnum) 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": andrej@2354: data = "{:0>16x}".format(eeprom_element) 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 andrej@2354: mb = device.getMailbox() andrej@2375: if mb is not None: andrej@2363: for bit, mbprot in enumerate(mailbox_protocols): andrej@2363: if getattr(mb, "get%s" % mbprot)() is not None: andrej@2367: 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; andrej@2354: data = "" andrej@2354: for eeprom_element in device.getEeprom().getcontent(): andrej@2354: if eeprom_element["name"] == "ByteSize": andrej@2354: eeprom_size = int(str(eeprom_element)) andrej@2437: data = "{:0>4x}".format(int(eeprom_element)//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; andrej@2354: # 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: andrej@2354: # 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])) 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@2354: coe_details = 0 andrej@2354: mb = device.getMailbox() andrej@2361: coe_details = 1 # sdo enabled andrej@2375: if mb is not None: andrej@2354: coe = mb.getCoE() andrej@2354: if coe is not None: andrej@2363: for bit, flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig", andrej@2407: "PdoUpload", "CompleteAccess"]): andrej@2363: if getattr(coe, "get%s" % flag)() is not None: andrej@2367: coe_details += 1 << bit andrej@2354: eeprom.append("{:0>2x}".format(coe_details)) andrej@2355: andrej@2354: # word 4 : FoE Details and EoE Details andrej@2354: # FoE Details; ----- andrej@2354: if mb is not None and mb.getFoE() is not None: andrej@2354: eeprom.append("01") andrej@2354: else: andrej@2354: eeprom.append("00") andrej@2354: # EoE Details; ----- andrej@2354: if mb is not None and mb.getEoE() is not None: andrej@2354: eeprom.append("01") andrej@2354: else: andrej@2354: eeprom.append("00") andrej@2355: andrej@2354: # word 5 : SoE Channels(reserved) and DS402 Channels andrej@2354: # SoE Details; ----- andrej@2354: if mb is not None and mb.getSoE() is not None: andrej@2354: eeprom.append("01") andrej@2354: else: andrej@2354: eeprom.append("00") andrej@2354: # DS402Channels; -----: DS402Channels andrej@2354: ds402ch = False andrej@2375: if mb is not None: andrej@2354: coe = mb.getCoE() andrej@2375: if coe is not None: andrej@2354: 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: 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: # ------------------------------------------------------------------------------- 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()