--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/CommonEtherCATFunction.py Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,1591 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+
+# This file is part of Beremiz
+#
+# Copyright (C) 2013: Real-Time & Embedded Systems (RTES) Lab. University of Seoul, Korea
+#
+# See COPYING file for copyrights details.
+
+import os
+import wx
+
+mailbox_protocols = ["AoE", "EoE", "CoE", "FoE", "SoE", "VoE"]
+
+def ExtractHexDecValue(value):
+ """
+ convert numerical value in string format into decimal or hex format.
+ @param value : hex or decimal data
+ @return integer data
+ """
+ try:
+ return int(value)
+ except:
+ pass
+ try:
+ return int(value.replace("#", "0"), 16)
+
+ except:
+ raise ValueError, "Invalid value for HexDecValue \"%s\"" % value
+
+def ExtractName(names, default=None):
+ """
+ Extract "name" field from XML entries.
+ @param names : XML entry
+ @default : if it fails to extract from the designated XML entry, return the default value ("None").
+ @return default or the name extracted
+ """
+ if len(names) == 1:
+ return names[0].getcontent()
+ else:
+ for name in names:
+ if name.getLcId() == 1033:
+ return name.getcontent()
+ return default
+
+#--------------------------------------------------
+# Remote Exec Etherlab Commands
+#--------------------------------------------------
+
+# --------------------- for master ---------------------------
+MASTER_STATE = """
+import commands
+result = commands.getoutput("ethercat master")
+returnVal =result
+"""
+
+# --------------------- for slave ----------------------------
+# ethercat state -p (slave position) (state (INIT, PREOP, SAFEOP, OP))
+SLAVE_STATE = """
+import commands
+result = commands.getoutput("ethercat state -p %d %s")
+returnVal = result
+"""
+
+# ethercat slave
+GET_SLAVE = """
+import commands
+result = commands.getoutput("ethercat slaves")
+returnVal =result
+"""
+
+# ethercat xml -p (slave position)
+SLAVE_XML = """
+import commands
+result = commands.getoutput("ethercat xml -p %d")
+returnVal = result
+"""
+
+# ethercat sdos -p (slave position)
+SLAVE_SDO = """
+import commands
+result = commands.getoutput("ethercat sdos -p %d")
+returnVal =result
+"""
+
+# ethercat upload -p (slave position) (main index) (sub index)
+GET_SLOW_SDO = """
+import commands
+result = commands.getoutput("ethercat upload -p %d %s %s")
+returnVal =result
+"""
+
+# ethercat download -p (slave position) (main index) (sub index) (value)
+SDO_DOWNLOAD = """
+import commands
+result = commands.getoutput("ethercat download --type %s -p %d %s %s %s")
+returnVal =result
+"""
+
+# ethercat sii_read -p (slave position)
+SII_READ = """
+import commands
+result = commands.getoutput("ethercat sii_read -p %d")
+returnVal =result
+"""
+
+# ethercat reg_read -p (slave position) (address) (size)
+REG_READ = """
+import commands
+result = commands.getoutput("ethercat reg_read -p %d %s %s")
+returnVal =result
+"""
+
+# ethercat sii_write -p (slave position) - (contents)
+SII_WRITE = """
+import subprocess
+process = subprocess.Popen(
+ ["ethercat", "-f", "sii_write", "-p", "%d", "-"],
+ stdin=subprocess.PIPE)
+process.communicate(sii_data)
+returnVal = process.returncode
+"""
+
+# ethercat reg_write -p (slave position) -t (uinit16) (address) (data)
+REG_WRITE = """
+import commands
+result = commands.getoutput("ethercat reg_write -p %d -t uint16 %s %s")
+returnVal =result
+"""
+
+# ethercat rescan -p (slave position)
+RESCAN = """
+import commands
+result = commands.getoutput("ethercat rescan -p %d")
+returnVal =result
+"""
+
+#--------------------------------------------------
+# Common Method For EtherCAT Management
+#--------------------------------------------------
+class _CommonSlave:
+
+ # ----- Data Structure for ethercat management ----
+ SlaveState = ""
+
+ # category of SDO data
+ DatatypeDescription, CommunicationObject, ManufacturerSpecific, \
+ ProfileSpecific, Reserved, AllSDOData = range(6)
+
+ # store the execution result of "ethercat sdos" command into SaveSDOData.
+ SaveSDOData = []
+
+ # Flags for checking "write" permission of OD entries
+ CheckPREOP = False
+ CheckSAFEOP = False
+ CheckOP = False
+
+ # Save PDO Data
+ TxPDOInfo = []
+ TxPDOCategory = []
+ RxPDOInfo = []
+ RxPDOCategory = []
+
+ # Save EEPROM Data
+ SiiData = ""
+
+ # Save Register Data
+ RegData = ""
+ CrtRegSpec = {"ESCType": "",
+ "FMMUNumber": "",
+ "SMNumber": "",
+ "PDIType": ""}
+
+ def __init__(self, controler):
+ """
+ Constructor
+ @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+ """
+ self.Controler = controler
+
+ self.ClearSDODataSet()
+
+ #-------------------------------------------------------------------------------
+ # Used Master State
+ #-------------------------------------------------------------------------------
+ def GetMasterState(self):
+ """
+ Execute "ethercat master" command and parse the execution result
+ @return MasterState
+ """
+
+ # exectute "ethercat master" command
+ error, return_val = self.Controler.RemoteExec(MASTER_STATE, return_val = None)
+ master_state = {}
+ # parse the reslut
+ for each_line in return_val.splitlines():
+ if len(each_line) > 0 :
+ chunks = each_line.strip().split(':', 1)
+ key = chunks[0]
+ value = []
+ if len(chunks) > 1 :
+ value = chunks[1].split()
+ if '(attached)' in value:
+ value.remove('(attached)')
+ master_state[key] = value
+
+ return master_state
+
+ #-------------------------------------------------------------------------------
+ # Used Slave State
+ #-------------------------------------------------------------------------------
+ def RequestSlaveState(self, command):
+ """
+ Set slave state to the specified one using "ethercat states -p %d %s" command.
+ Command example : "ethercat states -p 0 PREOP" (target slave position and target state are given.)
+ @param command : target slave state
+ """
+ error, return_val = self.Controler.RemoteExec(SLAVE_STATE%(self.Controler.GetSlavePos(), command), return_val = None)
+
+ def GetSlaveStateFromSlave(self):
+ """
+ Get slave information using "ethercat slaves" command and store the information into internal data structure
+ (self.SlaveState) for "Slave State"
+ return_val example : 0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100)
+ """
+ error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val = None)
+ self.SlaveState = return_val
+ return return_val
+
+ #-------------------------------------------------------------------------------
+ # Used SDO Management
+ #-------------------------------------------------------------------------------
+ def GetSlaveSDOFromSlave(self):
+ """
+ Get SDO objects information of current slave using "ethercat sdos -p %d" command.
+ Command example : "ethercat sdos -p 0"
+ @return return_val : execution results of "ethercat sdos" command (need to be parsed later)
+ """
+ error, return_val = self.Controler.RemoteExec(SLAVE_SDO%(self.Controler.GetSlavePos()), return_val = None)
+ return return_val
+
+ def SDODownload(self, data_type, idx, sub_idx, value):
+ """
+ Set an SDO object value to user-specified value using "ethercat download" command.
+ Command example : "ethercat download --type int32 -p 0 0x8020 0x12 0x00000000"
+ @param data_type : data type of SDO entry
+ @param idx : index of the SDO entry
+ @param sub_idx : subindex of the SDO entry
+ @param value : value of SDO entry
+ """
+ error, return_val = self.Controler.RemoteExec(SDO_DOWNLOAD%(data_type, self.Controler.GetSlavePos(), idx, sub_idx, value), return_val = None)
+
+ def BackupSDODataSet(self):
+ """
+ Back-up current SDO entry information to restore the SDO data
+ in case that the user cancels SDO update operation.
+ """
+ self.BackupDatatypeDescription = self.SaveDatatypeDescription
+ self.BackupCommunicationObject = self.SaveCommunicationObject
+ self.BackupManufacturerSpecific = self.SaveManufacturerSpecific
+ self.BackupProfileSpecific = self.SaveProfileSpecific
+ self.BackupReserved = self.SaveReserved
+ self.BackupAllSDOData = self.SaveAllSDOData
+
+ def ClearSDODataSet(self):
+ """
+ Clear the specified SDO entry information.
+ """
+ for count in range(6):
+ self.SaveSDOData.append([])
+
+ #-------------------------------------------------------------------------------
+ # Used PDO Monitoring
+ #-------------------------------------------------------------------------------
+ def RequestPDOInfo(self):
+ """
+ Load slave information from RootClass (XML data) and parse the information (calling SlavePDOData() method).
+ """
+ # Load slave information from ESI XML file (def EthercatMaster.py)
+ slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+
+ type_infos = slave.getType()
+ device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+ # Initialize PDO data set
+ self.ClearDataSet()
+
+ # if 'device' object is valid, call SavePDOData() to parse PDO data
+ if device is not None :
+ self.SavePDOData(device)
+
+ def SavePDOData(self, device):
+ """
+ Parse PDO data and store the results in TXPDOCategory and RXPDOCategory
+ Tx(Rx)PDOCategory : index, name, entry number
+ Tx(Rx)Info : entry index, sub index, name, length, type
+ @param device : Slave information extracted from ESI XML file
+ """
+ # Parsing TXPDO entries
+ for pdo, pdo_info in ([(pdo, "Inputs") for pdo in device.getTxPdo()]):
+ # Save pdo_index, entry, and name of each entry
+ pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
+ entries = pdo.getEntry()
+ pdo_name = ExtractName(pdo.getName())
+
+ # Initialize entry number count
+ count = 0
+
+ # Parse entries
+ for entry in entries:
+ # Save index and subindex
+ index = ExtractHexDecValue(entry.getIndex().getcontent())
+ subindex = ExtractHexDecValue(entry.getSubIndex())
+ # if entry name exists, save entry data
+ if ExtractName(entry.getName()) is not None :
+ entry_infos = {
+ "entry_index" : index,
+ "subindex" : subindex,
+ "name" : ExtractName(entry.getName()),
+ "bitlen" : entry.getBitLen(),
+ "type" : entry.getDataType().getcontent()
+ }
+ self.TxPDOInfo.append(entry_infos)
+ count += 1
+
+ categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}
+ self.TxPDOCategory.append(categorys)
+
+ # Parsing RxPDO entries
+ for pdo, pdo_info in ([(pdo, "Outputs") for pdo in device.getRxPdo()]):
+ # Save pdo_index, entry, and name of each entry
+ pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
+ entries = pdo.getEntry()
+ pdo_name = ExtractName(pdo.getName())
+
+ # Initialize entry number count
+ count = 0
+
+ # Parse entries
+ for entry in entries:
+ # Save index and subindex
+ index = ExtractHexDecValue(entry.getIndex().getcontent())
+ subindex = ExtractHexDecValue(entry.getSubIndex())
+ # if entry name exists, save entry data
+ if ExtractName(entry.getName()) is not None :
+ entry_infos = {
+ "entry_index" : index,
+ "subindex" : subindex,
+ "name" : ExtractName(entry.getName()),
+ "bitlen" : str(entry.getBitLen()),
+ "type" : entry.getDataType().getcontent()
+ }
+ self.RxPDOInfo.append(entry_infos)
+ count += 1
+
+ categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}
+ self.RxPDOCategory.append(categorys)
+
+ def GetTxPDOCategory(self):
+ """
+ Get TxPDOCategory data structure (Meta informaton of TxPDO).
+ TxPDOCategorys : index, name, number of entries
+ @return TxPDOCategorys
+ """
+ return self.TxPDOCategory
+
+ def GetRxPDOCategory(self):
+ """
+ Get RxPDOCategory data structure (Meta information of RxPDO).
+ RxPDOCategorys : index, name, number of entries
+ @return RxPDOCategorys
+ """
+ return self.RxPDOCategory
+
+ def GetTxPDOInfo(self):
+ """
+ Get TxPDOInfo data structure (Detailed information on TxPDO entries).
+ TxPDOInfos : entry index, sub index, name, length, type
+ @return TxPDOInfos
+ """
+ return self.TxPDOInfo
+
+ def GetRxPDOInfo(self):
+ """
+ Get RxPDOInfo data structure (Detailed information on RxPDO entries).
+ RxPDOInfos : entry index, sub index, name, length, type
+ @return RxPDOInfos
+ """
+ return self.RxPDOInfo
+
+ def ClearDataSet(self):
+ """
+ Initialize PDO management data structure.
+ """
+ self.TxPDOInfos = []
+ self.TxPDOCategorys = []
+ self.RxPDOInfos = []
+ self.RxPDOCategorys = []
+
+ #-------------------------------------------------------------------------------
+ # Used EEPROM Management
+ #-------------------------------------------------------------------------------
+ # Base data types in ETG2000; format = {"Name": "BitSize"}
+ BaseDataTypeDict = {"BOOL": "01",
+ "SINT": "02",
+ "INT": "03",
+ "DINT": "04",
+ "USINT": "05",
+ "UINT": "06",
+ "UDINT": "07",
+ "REAL": "08",
+ "INT24": "10",
+ "LREAL": "11",
+ "INT40": "12",
+ "INT48": "13",
+ "INT56": "14",
+ "LINT": "15",
+ "UINT24": "16",
+ "UINT40": "18",
+ "UINT48": "19",
+ "UINT56": "1a",
+ "ULINT": "1b",
+ "USINT": "1e",
+ "BITARR8": "2d",
+ "BITARR16": "2e",
+ "BITARR32": "2f",
+ "BIT1": "30",
+ "BIT2": "31",
+ "BIT3": "32",
+ "BIT4": "33",
+ "BIT5": "34",
+ "BIT6": "35",
+ "BIT7": "36",
+ "BIT8": "37"}
+
+ def GetSmartViewInfos(self):
+ """
+ Parse XML data for "Smart View" of EEPROM contents.
+ @return smartview_infos : EEPROM contents dictionary
+ """
+
+ smartview_infos = {"eeprom_size": 128,
+ "pdi_type": 0,
+ "device_emulation": "False",
+ "vendor_id": '0x00000000',
+ "product_code": '0x00000000',
+ "revision_no": '0x00000000',
+ "serial_no": '0x00000000',
+ "supported_mailbox": "",
+ "mailbox_bootstrapconf_outstart": '0',
+ "mailbox_bootstrapconf_outlength": '0',
+ "mailbox_bootstrapconf_instart": '0',
+ "mailbox_bootstrapconf_inlength": '0',
+ "mailbox_standardconf_outstart": '0',
+ "mailbox_standardconf_outlength": '0',
+ "mailbox_standardconf_instart": '0',
+ "mailbox_standardconf_inlength": '0'}
+
+ slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+ type_infos = slave.getType()
+ device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+
+ # 'device' represents current slave device selected by user
+ if device is not None:
+ for eeprom_element in device.getEeprom().getcontent():
+ # get EEPROM size; <Device>-<Eeprom>-<ByteSize>
+ if eeprom_element["name"] == "ByteSize":
+ smartview_infos["eeprom_size"] = eeprom_element
+
+ elif eeprom_element["name"] == "ConfigData":
+ configData_data = self.DecimalToHex(eeprom_element)
+ # get PDI type; <Device>-<Eeprom>-<ConfigData> address 0x00
+ smartview_infos["pdi_type"] = int(configData_data[0:2], 16)
+ # get state of device emulation; <Device>-<Eeprom>-<ConfigData> address 0x01
+ if "{:0>8b}".format(int(configData_data[2:4], 16))[7] == '1':
+ smartview_infos["device_emulation"] = "True"
+
+ elif eeprom_element["name"] == "BootStrap":
+ bootstrap_data = "{:0>16x}".format(eeprom_element)
+ # get bootstrap configuration; <Device>-<Eeprom>-<BootStrap>
+ for cfg, iter in [("mailbox_bootstrapconf_outstart", 0),
+ ("mailbox_bootstrapconf_outlength", 1),
+ ("mailbox_bootstrapconf_instart", 2),
+ ("mailbox_bootstrapconf_inlength", 3)]:
+ smartview_infos[cfg] = str(int(bootstrap_data[4*iter+2:4*(iter+1)]+bootstrap_data[4*iter:4*iter+2], 16))
+
+ # get protocol (profile) types supported by mailbox; <Device>-<Mailbox>
+ mb = device.getMailbox()
+ if mb is not None:
+ for mailbox_protocol in mailbox_protocols:
+ if getattr(mb,"get%s"%mailbox_protocol)() is not None:
+ smartview_infos["supported_mailbox"] += "%s, "%mailbox_protocol
+ smartview_infos["supported_mailbox"] = smartview_infos["supported_mailbox"].strip(", ")
+
+ # get standard configuration of mailbox; <Device>-<Sm>
+ for sm_element in device.getSm():
+ if sm_element.getcontent() == "MBoxOut":
+ smartview_infos["mailbox_standardconf_outstart"] = str(ExtractHexDecValue(sm_element.getStartAddress()))
+ smartview_infos["mailbox_standardconf_outlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize()))
+ elif sm_element.getcontent() == "MBoxIn":
+ smartview_infos["mailbox_standardconf_instart"] = str(ExtractHexDecValue(sm_element.getStartAddress()))
+ smartview_infos["mailbox_standardconf_inlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize()))
+ else:
+ pass
+
+ # get device identity from <Device>-<Type>
+ # vendor ID; by default, pre-defined value in self.ModulesLibrary
+ # if device type in 'vendor' item equals to actual slave device type, set 'vendor_id' to vendor ID.
+ for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+ for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]:
+ if available_device[0] == type_infos["device_type"]:
+ smartview_infos["vendor_id"] = "0x" + "{:0>8x}".format(vendor_id)
+
+ # product code;
+ if device.getType().getProductCode() is not None:
+ product_code = device.getType().getProductCode()
+ smartview_infos["product_code"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(product_code))
+
+ # revision number;
+ if device.getType().getRevisionNo() is not None:
+ revision_no = device.getType().getRevisionNo()
+ smartview_infos["revision_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(revision_no))
+
+ # serial number;
+ if device.getType().getSerialNo() is not None:
+ serial_no = device.getType().getSerialNo()
+ smartview_infos["serial_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(serial_no))
+
+ return smartview_infos
+
+ else:
+ return None
+
+ def DecimalToHex(self, decnum):
+ """
+ Convert decimal value into hexadecimal representation.
+ @param decnum : decimal value
+ @return hex_data : hexadecimal representation of input value in decimal
+ """
+ value = "%x" % decnum
+ value_len = len(value)
+ if (value_len % 2) == 0:
+ hex_len = value_len
+ else:
+ hex_len = (value_len / 2) * 2 + 2
+
+ hex_data = ("{:0>"+str(hex_len)+"x}").format(decnum)
+
+ return hex_data
+
+ def SiiRead(self):
+ """
+ Get slave EEPROM contents maintained by master device using "ethercat sii_read -p %d" command.
+ Command example : "ethercat sii_read -p 0"
+ @return return_val : result of "ethercat sii_read" (binary data)
+ """
+ error, return_val = self.Controler.RemoteExec(SII_READ%(self.Controler.GetSlavePos()), return_val = None)
+ self.SiiData = return_val
+ return return_val
+
+ def SiiWrite(self, binary):
+ """
+ Overwrite slave EEPROM contents using "ethercat sii_write -p %d" command.
+ Command example : "ethercat sii_write -p 0 - (binary contents)"
+ @param binary : EEPROM contents in binary data format
+ @return return_val : result of "ethercat sii_write" (If it succeeds, the return value is NULL.)
+ """
+ error, return_val = self.Controler.RemoteExec(SII_WRITE%(self.Controler.GetSlavePos()), return_val = None, sii_data = binary)
+ return return_val
+
+ def LoadData(self):
+ """
+ Loading data from EEPROM use Sii_Read Method
+ @return self.BinaryCode : slave EEPROM data in binary format (zero-padded)
+ """
+ return_val = self.Controler.CommonMethod.SiiRead()
+ self.BinaryCode = return_val
+ self.Controler.SiiData = self.BinaryCode
+
+ # append zero-filled padding data up to EEPROM size
+ for index in range(self.SmartViewInfosFromXML["eeprom_size"] - len(self.BinaryCode)):
+ self.BinaryCode = self.BinaryCode +'ff'.decode('hex')
+
+ return self.BinaryCode
+
+ def HexRead(self, binary):
+ """
+ Convert binary digit representation into hexadecimal representation for "Hex View" menu.
+ @param binary : binary digits
+ @return hexCode : hexadecimal digits
+ @return hexview_table_row, hexview_table_col : Grid size for "Hex View" UI
+ """
+ row_code = []
+ row_text = ""
+ row = 0
+ hex_code = []
+
+ hexview_table_col = 17
+
+ for index in range(0, len(binary)) :
+ if len(binary[index]) != 1:
+ break
+ else:
+ digithexstr = hex(ord(binary[index]))
+
+ tempvar2 = digithexstr[2:4]
+ if len(tempvar2) == 1:
+ tempvar2 = "0" + tempvar2
+ row_code.append(tempvar2)
+
+ if int(digithexstr, 16)>=32 and int(digithexstr, 16)<=126:
+ row_text = row_text + chr(int(digithexstr, 16))
+ else:
+ row_text = row_text + "."
+
+ if index != 0 :
+ if len(row_code) == (hexview_table_col - 1):
+ row_code.append(row_text)
+ hex_code.append(row_code)
+ row_text = ""
+ row_code = []
+ row = row + 1
+
+ hexview_table_row = row
+
+ return hex_code, hexview_table_row, hexview_table_col
+
+ def GenerateEEPROMList(self, data, direction, length):
+ """
+ Generate EEPROM data list by reconstructing 'data' string.
+ example : data="12345678", direction=0, length=8 -> eeprom_list=['12', '34', '56', '78']
+ data="12345678", direction=1, length=8 -> eeprom_list=['78', '56', '34', '12']
+ @param data : string to be reconstructed
+ @param direction : endianness
+ @param length : data length
+ @return eeprom_list : reconstructed list data structure
+ """
+ eeprom_list = []
+
+ if direction is 0 or 1:
+ for i in range(length/2):
+ if data == "":
+ eeprom_list.append("00")
+ else:
+ eeprom_list.append(data[direction*(length-2):direction*(length-2)+2])
+ data = data[(1-direction)*2:length-direction*2]
+ length -= 2
+ return eeprom_list
+
+ def XmlToEeprom(self):
+ """
+ Extract slave EEPROM contents using slave ESI XML file.
+ - Mandatory parts
+ - String category : ExtractEEPROMStringCategory()
+ - General category : ExtractEEPROMGeneralCategory()
+ - FMMU category : ExtractEEPROMFMMUCategory
+ - SyncM category : ExtractEEPROMSyncMCategory()
+ - Tx/RxPDO category : ExtractEEPROMPDOCategory()
+ - DC category : ExtractEEPROMDCCategory()
+ @return eeprom_binary
+ """
+ eeprom = []
+ data = ""
+ eeprom_size = 0
+ eeprom_binary = ""
+
+ # 'device' is the slave device of the current EtherCAT slave plugin
+ slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+ type_infos = slave.getType()
+ device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+
+ if device is not None:
+ # get ConfigData for EEPROM offset 0x0000-0x000d; <Device>-<Eeprom>-<ConfigData>
+ for eeprom_element in device.getEeprom().getcontent():
+ if eeprom_element["name"] == "ConfigData":
+ data = self.DecimalToHex(eeprom_element)
+ eeprom += self.GenerateEEPROMList(data, 0, 28)
+
+ # calculate CRC for EEPROM offset 0x000e-0x000f
+ crc = 0x48
+ for segment in eeprom:
+ for i in range(8):
+ bit = crc & 0x80
+ crc = (crc << 1) | ((int(segment, 16) >> (7 - i)) & 0x01)
+ if bit:
+ crc ^= 0x07
+ for k in range(8):
+ bit = crc & 0x80
+ crc <<= 1
+ if bit:
+ crc ^= 0x07
+ eeprom.append(hex(crc)[len(hex(crc))-3:len(hex(crc))-1])
+ eeprom.append("00")
+
+ # get VendorID for EEPROM offset 0x0010-0x0013;
+ data = ""
+ for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+ for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]:
+ if available_device[0] == type_infos["device_type"]:
+ data = "{:0>8x}".format(vendor_id)
+ eeprom += self.GenerateEEPROMList(data, 1, 8)
+
+ # get Product Code for EEPROM offset 0x0014-0x0017;
+ data = ""
+ if device.getType().getProductCode() is not None:
+ data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getProductCode()))
+ eeprom += self.GenerateEEPROMList(data, 1, 8)
+
+ # get Revision Number for EEPROM offset 0x0018-0x001b;
+ data = ""
+ if device.getType().getRevisionNo() is not None:
+ data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getRevisionNo()))
+ eeprom += self.GenerateEEPROMList(data, 1, 8)
+
+ # get Serial Number for EEPROM 0x001c-0x001f;
+ data = ""
+ if device.getType().getSerialNo() is not None:
+ data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getSerialNo()))
+ eeprom += self.GenerateEEPROMList(data, 1, 8)
+
+ # get Execution Delay for EEPROM 0x0020-0x0021; not analyzed yet
+ eeprom.append("00")
+ eeprom.append("00")
+
+ # get Port0/1 Delay for EEPROM offset 0x0022-0x0025; not analyzed yet
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+
+ # reserved for EEPROM offset 0x0026-0x0027;
+ eeprom.append("00")
+ eeprom.append("00")
+
+ # get BootStrap for EEPROM offset 0x0028-0x002e; <Device>-<Eeprom>-<BootStrap>
+ data = ""
+ for eeprom_element in device.getEeprom().getcontent():
+ if eeprom_element["name"] == "BootStrap":
+ data = "{:0>16x}".format(eeprom_element)
+ eeprom += self.GenerateEEPROMList(data, 0, 16)
+
+ # get Standard Mailbox for EEPROM offset 0x0030-0x0037; <Device>-<sm>
+ data = ""
+ standard_send_mailbox_offset = None
+ standard_send_mailbox_size = None
+ standard_receive_mailbox_offset = None
+ standard_receive_mailbox_size = None
+ for sm_element in device.getSm():
+ if sm_element.getcontent() == "MBoxOut":
+ standard_receive_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress()))
+ standard_receive_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize()))
+ elif sm_element.getcontent() == "MBoxIn":
+ standard_send_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress()))
+ standard_send_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize()))
+
+ if standard_receive_mailbox_offset is None:
+ eeprom.append("00")
+ eeprom.append("00")
+ else:
+ eeprom.append(standard_receive_mailbox_offset[2:4])
+ eeprom.append(standard_receive_mailbox_offset[0:2])
+ if standard_receive_mailbox_size is None:
+ eeprom.append("00")
+ eeprom.append("00")
+ else:
+ eeprom.append(standard_receive_mailbox_size[2:4])
+ eeprom.append(standard_receive_mailbox_size[0:2])
+ if standard_send_mailbox_offset is None:
+ eeprom.append("00")
+ eeprom.append("00")
+ else:
+ eeprom.append(standard_send_mailbox_offset[2:4])
+ eeprom.append(standard_send_mailbox_offset[0:2])
+ if standard_send_mailbox_size is None:
+ eeprom.append("00")
+ eeprom.append("00")
+ else:
+ eeprom.append(standard_send_mailbox_size[2:4])
+ eeprom.append(standard_send_mailbox_size[0:2])
+
+ # get supported mailbox protocols for EEPROM offset 0x0038-0x0039;
+ data = 0
+ mb = device.getMailbox()
+ if mb is not None :
+ for bit,mbprot in enumerate(mailbox_protocols):
+ if getattr(mb,"get%s"%mbprot)() is not None:
+ data += 1<<bit
+ data = "{:0>4x}".format(data)
+ eeprom.append(data[2:4])
+ eeprom.append(data[0:2])
+
+ # resereved for EEPROM offset 0x003a-0x007b;
+ for i in range(0x007b-0x003a+0x0001):
+ eeprom.append("00")
+
+ # get EEPROM size for EEPROM offset 0x007c-0x007d;
+ data = ""
+ for eeprom_element in device.getEeprom().getcontent():
+ if eeprom_element["name"] == "ByteSize":
+ eeprom_size = int(str(eeprom_element))
+ data = "{:0>4x}".format(int(eeprom_element)/1024*8-1)
+
+ if data == "":
+ eeprom.append("00")
+ eeprom.append("00")
+ else:
+ eeprom.append(data[2:4])
+ eeprom.append(data[0:2])
+
+ # Version for EEPROM 0x007e-0x007f;
+ # According to "EtherCAT Slave Device Description(V0.3.0)"
+ eeprom.append("01")
+ eeprom.append("00")
+
+ # append String Category data
+ for data in self.ExtractEEPROMStringCategory(device):
+ eeprom.append(data)
+
+ # append General Category data
+ for data in self.ExtractEEPROMGeneralCategory(device):
+ eeprom.append(data)
+
+ # append FMMU Category data
+ for data in self.ExtractEEPROMFMMUCategory(device):
+ eeprom.append(data)
+
+ # append SyncM Category data
+ for data in self.ExtractEEPROMSyncMCategory(device):
+ eeprom.append(data)
+
+ # append TxPDO Category data
+ for data in self.ExtractEEPROMPDOCategory(device, "TxPdo"):
+ eeprom.append(data)
+
+ # append RxPDO Category data
+ for data in self.ExtractEEPROMPDOCategory(device, "RxPdo"):
+ eeprom.append(data)
+
+ # append DC Category data
+ for data in self.ExtractEEPROMDCCategory(device):
+ eeprom.append(data)
+
+ # append padding
+ padding = eeprom_size-len(eeprom)
+ for i in range(padding):
+ eeprom.append("ff")
+
+ # convert binary code
+ for index in range(eeprom_size):
+ eeprom_binary = eeprom_binary + eeprom[index].decode('hex')
+
+ return eeprom_binary
+
+ def ExtractEEPROMStringCategory(self, device):
+ """
+ Extract "Strings" category data from slave ESI XML and generate EEPROM image data.
+ @param device : 'device' object in the slave ESI XML
+ @return eeprom : "Strings" category EEPROM image data
+ """
+ eeprom = []
+ self.Strings = []
+ data = ""
+ count = 0 # string counter
+ padflag = False # padding flag if category length is odd
+
+ # index information for General Category in EEPROM
+ self.GroupIdx = 0
+ self.ImgIdx = 0
+ self.OrderIdx = 0
+ self.NameIdx = 0
+
+ # flag for preventing duplicated vendor specific data
+ typeflag = False
+ grouptypeflag = False
+ groupnameflag = False
+ devnameflag = False
+ imageflag = False
+
+ # vendor specific data
+ # element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type>
+ # vendor_specific_data : vendor specific data (binary type)
+ vendor_specific_data = ""
+ # vendor_spec_strings : list of vendor specific "strings" for preventing duplicated strings
+ vendor_spec_strings = []
+ for element in device.getType().getcontent():
+ data += element
+ if data is not "" and type(data) == unicode:
+ for vendor_spec_string in vendor_spec_strings:
+ if data == vendor_spec_string:
+ self.OrderIdx = vendor_spec_strings.index(data)+1
+ typeflag = True
+ break
+ if typeflag is False:
+ count += 1
+ self.Strings.append(data)
+ vendor_spec_strings.append(data)
+ typeflag = True
+ self.OrderIdx = count
+ vendor_specific_data += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType>
+ data = device.getGroupType()
+ if data is not None and type(data) == unicode:
+ for vendor_spec_string in vendor_spec_strings:
+ if data == vendor_spec_string:
+ self.GroupIdx = vendor_spec_strings.index(data)+1
+ grouptypeflag = True
+ break
+ if grouptypeflag is False:
+ grouptype = data
+ count += 1
+ self.Strings.append(data)
+ vendor_spec_strings.append(data)
+ grouptypeflag = True
+ self.GroupIdx = count
+ vendor_specific_data += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+
+ # element2-2; <EtherCATInfo>-<Groups>-<Group>-<Type>
+ if grouptypeflag is False:
+ if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+ for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+ for group_type, group_etc in vendor["groups"].iteritems():
+ for device_item in group_etc["devices"]:
+ if device == device_item[1]:
+ data = group_type
+ if data is not None and type(data) == unicode:
+ for vendor_spec_string in vendor_spec_strings:
+ if data == vendor_spec_string:
+ self.GroupIdx = vendor_spec_strings.index(data)+1
+ grouptypeflag = True
+ break
+ if grouptypeflag is False:
+ grouptype = data
+ count += 1
+ self.Strings.append(data)
+ vendor_spec_strings.append(data)
+ grouptypeflag = True
+ self.GroupIdx = count
+ vendor_specific_data += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # element3; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Name(LcId is "1033")>
+ if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+ for vendorId, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+ for group_type, group_etc in vendor["groups"].iteritems():
+ for device_item in group_etc["devices"]:
+ if device == device_item[1]:
+ data = group_etc["name"]
+ if data is not "" and type(data) == unicode:
+ for vendor_spec_string in vendor_spec_strings:
+ if data == vendor_spec_string:
+ groupnameflag = True
+ break
+ if groupnameflag is False:
+ count += 1
+ self.Strings.append(data)
+ vendor_spec_strings.append(data)
+ groupnameflag = True
+ vendor_specific_data += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # element4; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Name(LcId is "1033" or "1"?)>
+ for element in device.getName():
+ if element.getLcId() == 1 or element.getLcId()==1033:
+ data = element.getcontent()
+ if data is not "" and type(data) == unicode:
+ for vendor_spec_string in vendor_spec_strings:
+ if data == vendor_spec_string:
+ self.NameIdx = vendor_spec_strings.index(data)+1
+ devnameflag = True
+ break
+ if devnameflag is False:
+ count += 1
+ self.Strings.append(data)
+ vendor_spec_strings.append(data)
+ devnameflag = True
+ self.NameIdx = count
+ vendor_specific_data += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # element5-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Image16x14>
+ if device.getcontent() is not None:
+ data = device.getcontent()
+ if data is not None and type(data) == unicode:
+ for vendor_spec_string in vendor_spec_strings:
+ if data == vendor_spec_string:
+ self.ImgIdx = vendor_spec_strings.index(data)+1
+ imageflag = True
+ break
+ if imageflag is False:
+ count += 1
+ self.Strings.append(data)
+ vendor_spec_strings.append(data)
+ imageflag = True
+ self.ImgIdx = count
+ vendor_specific_data += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+
+ # element5-2; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Image16x14>
+ if imageflag is False:
+ if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+ for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+ for group_type, group_etc in vendor["groups"].iteritems():
+ for device_item in group_etc["devices"]:
+ if device == device_item[1]:
+ data = group_etc
+ if data is not None and type(data) == unicode:
+ for vendor_spec_string in vendor_spec_strings:
+ if data == vendor_spec_string:
+ self.ImgIdx = vendor_spec_strings.index(data)+1
+ imageflag = True
+ break
+ if imageflag is False:
+ count += 1
+ self.Strings.append(data)
+ vendor_spec_strings.append(data)
+ imageflag = True
+ self.ImgIdx = count
+ vendor_specific_data += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # DC related elements
+ # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Dc>-<OpMode>-<Name>
+ dc_related_elements = ""
+ if device.getDc() is not None:
+ for element in device.getDc().getOpMode():
+ data = element.getName()
+ if data is not "":
+ count += 1
+ self.Strings.append(data)
+ dc_related_elements += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ dc_related_elements += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # Input elements(TxPDO)
+ # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name
+ input_elements = ""
+ inputs = []
+ for element in device.getTxPdo():
+ for name in element.getName():
+ data = name.getcontent()
+ for input in inputs:
+ if data == input:
+ data = ""
+ if data is not "":
+ count += 1
+ self.Strings.append(data)
+ inputs.append(data)
+ input_elements += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ input_elements += "{:0>2x}".format(ord(data[character]))
+ data = ""
+ for entry in element.getEntry():
+ for name in entry.getName():
+ data = name.getcontent()
+ for input in inputs:
+ if data == input:
+ data = ""
+ if data is not "":
+ count += 1
+ self.Strings.append(data)
+ inputs.append(data)
+ input_elements += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ input_elements += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # Output elements(RxPDO)
+ # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name
+ output_elements = ""
+ outputs = []
+ for element in device.getRxPdo():
+ for name in element.getName():
+ data = name.getcontent()
+ for output in outputs:
+ if data == output:
+ data = ""
+ if data is not "":
+ count += 1
+ self.Strings.append(data)
+ outputs.append(data)
+ output_elements += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ output_elements += "{:0>2x}".format(ord(data[character]))
+ data = ""
+ for entry in element.getEntry():
+ for name in entry.getName():
+ data = name.getcontent()
+ for output in outputs:
+ if data == output:
+ data = ""
+ if data is not "":
+ count += 1
+ self.Strings.append(data)
+ outputs.append(data)
+ output_elements += "{:0>2x}".format(len(data))
+ for character in range(len(data)):
+ output_elements += "{:0>2x}".format(ord(data[character]))
+ data = ""
+
+ # form eeprom data
+ # category header
+ eeprom.append("0a")
+ eeprom.append("00")
+ # category length (word); 1 word is 4 bytes. "+2" is the length of string's total number
+ length = len(vendor_specific_data + dc_related_elements + input_elements + output_elements) + 2
+ if length%4 == 0:
+ pass
+ else:
+ length +=length%4
+ padflag = True
+ eeprom.append("{:0>4x}".format(length/4)[2:4])
+ eeprom.append("{:0>4x}".format(length/4)[0:2])
+ # total numbers of strings
+ eeprom.append("{:0>2x}".format(count))
+ for element in [vendor_specific_data,
+ dc_related_elements,
+ input_elements,
+ output_elements]:
+ for iter in range(len(element)/2):
+ if element == "":
+ eeprom.append("00")
+ else:
+ eeprom.append(element[0:2])
+ element = element[2:len(element)]
+ # padding if length is odd bytes
+ if padflag is True:
+ eeprom.append("ff")
+
+ return eeprom
+
+ def ExtractEEPROMGeneralCategory(self, device):
+ """
+ Extract "General" category data from slave ESI XML and generate EEPROM image data.
+ @param device : 'device' object in the slave ESI XML
+ @return eeprom : "Strings" category EEPROM image data
+ """
+ eeprom = []
+ data = ""
+
+ # category header
+ eeprom.append("1e")
+ eeprom.append("00")
+
+ # category length
+ eeprom.append("10")
+ eeprom.append("00")
+
+ # word 1 : Group Type index and Image index in STRINGS Category
+ eeprom.append("{:0>2x}".format(self.GroupIdx))
+ eeprom.append("{:0>2x}".format(self.ImgIdx))
+
+ # word 2 : Device Type index and Device Name index in STRINGS Category
+ eeprom.append("{:0>2x}".format(self.OrderIdx))
+ eeprom.append("{:0>2x}".format(self.NameIdx))
+
+ # word 3 : Physical Layer Port info. and CoE Details
+ eeprom.append("01") # Physical Layer Port info - assume 01
+ # CoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>
+ coe_details = 0
+ mb = device.getMailbox()
+ coe_details = 1 # sdo enabled
+ if mb is not None :
+ coe = mb.getCoE()
+ if coe is not None:
+ for bit,flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig",
+ "PdoUpload", "CompleteAccess"]):
+ if getattr(coe,"get%s"%flag)() is not None:
+ coe_details += 1<<bit
+ eeprom.append("{:0>2x}".format(coe_details))
+
+ # word 4 : FoE Details and EoE Details
+ # FoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<FoE>
+ if mb is not None and mb.getFoE() is not None:
+ eeprom.append("01")
+ else:
+ eeprom.append("00")
+ # EoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<EoE>
+ if mb is not None and mb.getEoE() is not None:
+ eeprom.append("01")
+ else:
+ eeprom.append("00")
+
+ # word 5 : SoE Channels(reserved) and DS402 Channels
+ # SoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<SoE>
+ if mb is not None and mb.getSoE() is not None:
+ eeprom.append("01")
+ else:
+ eeprom.append("00")
+ # DS402Channels; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>: DS402Channels
+ ds402ch = False
+ if mb is not None :
+ coe = mb.getCoE()
+ if coe is not None :
+ ds402ch = coe.getDS402Channels()
+ eeprom.append("01" if ds402ch in [True,1] else "00")
+
+ # word 6 : SysmanClass(reserved) and Flags
+ eeprom.append("00") # reserved
+ # Flags
+ en_safeop = False
+ en_lrw = False
+ if device.getType().getTcCfgModeSafeOp() == True \
+ or device.getType().getTcCfgModeSafeOp() == 1:
+ en_safeop = True
+ if device.getType().getUseLrdLwr() == True \
+ or device.getType().getUseLrdLwr() == 1:
+ en_lrw = True
+
+ flags = "0b"+"000000"+str(int(en_lrw))+str(int(en_safeop))
+ eeprom.append("{:0>2x}".format(int(flags, 2)))
+
+ # word 7 : Current On EBus (assume 0x0000)
+ eeprom.append("00")
+ eeprom.append("00")
+ # after word 7; couldn't analyze yet
+ eeprom.append("03")
+ eeprom.append("00")
+ eeprom.append("11")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+ eeprom.append("00")
+
+ return eeprom
+
+ def ExtractEEPROMFMMUCategory(self, device):
+ """
+ Extract "FMMU" category data from slave ESI XML and generate EEPROM image data.
+ @param device : 'device' object in the slave ESI XML
+ @return eeprom : "Strings" category EEPROM image data
+ """
+ eeprom = []
+ data = ""
+ count = 0 # number of FMMU
+ padflag = False
+
+ for fmmu in device.getFmmu():
+ count += 1
+ if fmmu.getcontent() == "Outputs":
+ data += "01"
+ if fmmu.getcontent() == "Inputs":
+ data += "02"
+ if fmmu.getcontent() == "MBoxState":
+ data += "03"
+
+ # construct of EEPROM data
+ if data is not "":
+ # category header
+ eeprom.append("28")
+ eeprom.append("00")
+ # category length
+ if count%2 == 1:
+ padflag = True
+ eeprom.append("{:0>4x}".format((count+1)/2)[2:4])
+ eeprom.append("{:0>4x}".format((count+1)/2)[0:2])
+ else:
+ eeprom.append("{:0>4x}".format((count)/2)[2:4])
+ eeprom.append("{:0>4x}".format((count)/2)[0:2])
+ for i in range(count):
+ if data == "":
+ eeprom.append("00")
+ else:
+ eeprom.append(data[0:2])
+ data = data[2:len(data)]
+ # padding if length is odd bytes
+ if padflag is True:
+ eeprom.append("ff")
+
+ return eeprom
+
+ def ExtractEEPROMSyncMCategory(self, device):
+ """
+ Extract "SyncM" category data from slave ESI XML and generate EEPROM image data.
+ @param device : 'device' object in the slave ESI XML
+ @return eeprom : "Strings" category EEPROM image data
+ """
+ eeprom = []
+ data = ""
+ number = {"MBoxOut":"01", "MBoxIn":"02", "Outputs":"03", "Inputs":"04"}
+
+ for sm in device.getSm():
+ for attr in [sm.getStartAddress(),
+ sm.getDefaultSize(),
+ sm.getControlByte()]:
+ if attr is not None:
+ data += "{:0>4x}".format(ExtractHexDecValue(attr))[2:4]
+ data += "{:0>4x}".format(ExtractHexDecValue(attr))[0:2]
+ else:
+ data += "0000"
+ if sm.getEnable() == "1" or sm.getEnable() == True:
+ data += "01"
+ else:
+ data += "00"
+ data += number[sm.getcontent()]
+
+ if data is not "":
+ # category header
+ eeprom.append("29")
+ eeprom.append("00")
+ # category length
+ eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
+ eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
+ for i in range(len(data)/2):
+ if data == "":
+ eeprom.append("00")
+ else:
+ eeprom.append(data[0:2])
+ data = data[2:len(data)]
+
+ return eeprom
+
+ def ExtractEEPROMPDOCategory(self, device, pdotype):
+ """
+ Extract ""PDO (Tx, Rx)"" category data from slave ESI XML and generate EEPROM image data.
+ @param device : 'device' object in the slave ESI XML
+ @param pdotype : identifier whether "TxPDO" or "RxPDO".
+ @return eeprom : "Strings" category EEPROM image data
+ """
+ eeprom = []
+ data = ""
+ count = 0
+ en_fixed = False
+ en_mandatory = False
+ en_virtual = False
+
+ for element in eval("device.get%s()"%pdotype):
+ # PDO Index
+ data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[2:4]
+ data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[0:2]
+ # Number of Entries
+ data += "{:0>2x}".format(len(element.getEntry()))
+ # About Sync Manager
+ if element.getSm() is not None:
+ data += "{:0>2x}".format(element.getSm())
+ else:
+ data += "ff"
+ # Reference to DC Synch (according to ET1100 documentation) - assume 0
+ data += "00"
+ # Name Index
+ objname = ""
+ for name in element.getName():
+ objname = name.getcontent()
+ for name in self.Strings:
+ count += 1
+ if objname == name:
+ break
+ if len(self.Strings)+1 == count:
+ data += "00"
+ else:
+ data += "{:0>2x}".format(count)
+ count = 0
+ # Flags; by Fixed, Mandatory, Virtual attributes ?
+ if element.getFixed() == True or 1:
+ en_fixed = True
+ if element.getMandatory() == True or 1:
+ en_mandatory = True
+ if element.getVirtual() == True or element.getVirtual():
+ en_virtual = True
+ data += str(int(en_fixed)) + str(int(en_mandatory)) + str(int(en_virtual)) + "0"
+
+ for entry in element.getEntry():
+ # Entry Index
+ data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[2:4]
+ data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[0:2]
+ # Subindex
+ data += "{:0>2x}".format(int(entry.getSubIndex()))
+ # Entry Name Index
+ objname = ""
+ for name in entry.getName():
+ objname = name.getcontent()
+ for name in self.Strings:
+ count += 1
+ if objname == name:
+ break
+ if len(self.Strings)+1 == count:
+ data += "00"
+ else:
+ data += "{:0>2x}".format(count)
+ count = 0
+ # DataType
+ if entry.getDataType() is not None:
+ if entry.getDataType().getcontent() in self.BaseDataTypeDict:
+ data += self.BaseDataTypeDict[entry.getDataType().getcontent()]
+ else:
+ data += "00"
+ else:
+ data += "00"
+ # BitLen
+ if entry.getBitLen() is not None:
+ data += "{:0>2x}".format(int(entry.getBitLen()))
+ else:
+ data += "00"
+ # Flags; by Fixed attributes ?
+ en_fixed = False
+ if entry.getFixed() == True or entry.getFixed() == 1:
+ en_fixed = True
+ data += str(int(en_fixed)) + "000"
+
+ if data is not "":
+ # category header
+ if pdotype == "TxPdo":
+ eeprom.append("32")
+ elif pdotype == "RxPdo":
+ eeprom.append("33")
+ else:
+ eeprom.append("00")
+ eeprom.append("00")
+ # category length
+ eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
+ eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
+ data = str(data.lower())
+ for i in range(len(data)/2):
+ if data == "":
+ eeprom.append("00")
+ else:
+ eeprom.append(data[0:2])
+ data = data[2:len(data)]
+
+ return eeprom
+
+ def ExtractEEPROMDCCategory(self, device):
+ """
+ Extract "DC(Distributed Clock)" category data from slave ESI XML and generate EEPROM image data.
+ @param device : 'device' object in the slave ESI XML
+ @return eeprom : "Strings" category EEPROM image data
+ """
+ eeprom = []
+ data = ""
+ count = 0
+ namecount = 0
+
+ if device.getDc() is not None:
+ for element in device.getDc().getOpMode():
+ count += 1
+ # assume that word 1-7 are 0x0000
+ data += "0000"
+ data += "0000"
+ data += "0000"
+ data += "0000"
+ data += "0000"
+ data += "0000"
+ data += "0000"
+ # word 8-10
+ # AssignActivate
+ if element.getAssignActivate() is not None:
+ data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[2:4]
+ data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[0:2]
+ else:
+ data += "0000"
+ # Factor of CycleTimeSync0 ? and default is 1?
+ if element.getCycleTimeSync0() is not None:
+ if element.getCycleTimeSync0().getFactor() is not None:
+ data += "{:0>2x}".format(int(element.getCycleTimeSync0().getFactor()))
+ data += "00"
+ else:
+ data += "0100"
+ else:
+ data += "0100"
+ # Index of Name in STRINGS Category
+ # Name Index
+ objname = ""
+ for name in element.getName():
+ objname += name
+ for name in self.Strings:
+ namecount += 1
+ if objname == name:
+ break
+ if len(self.Strings)+1 == namecount:
+ data += "00"
+ else:
+ data += "{:0>2x}".format(namecount)
+ namecount = 0
+ data += "00"
+ # assume that word 11-12 are 0x0000
+ data += "0000"
+ data += "0000"
+
+ if data is not "":
+ # category header
+ eeprom.append("3c")
+ eeprom.append("00")
+ # category length
+ eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
+ eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
+ data = str(data.lower())
+ for i in range(len(data)/2):
+ if data == "":
+ eeprom.append("00")
+ else:
+ eeprom.append(data[0:2])
+ data = data[2:len(data)]
+
+ return eeprom
+
+ #-------------------------------------------------------------------------------
+ # Used Register Access
+ #-------------------------------------------------------------------------------
+ def RegRead(self, offset, length):
+ """
+ Read slave ESC register content using "ethercat reg_read -p %d %s %s" command.
+ Command example : "ethercat reg_read -p 0 0x0c00 0x0400"
+ @param offset : register address
+ @param length : register length
+ @return return_val : register data
+ """
+ error, return_val = self.Controler.RemoteExec(REG_READ%(self.Controler.GetSlavePos(), offset, length), return_val = None)
+ return return_val
+
+ def RegWrite(self, address, data):
+ """
+ Write data to slave ESC register using "ethercat reg_write -p %d %s %s" command.
+ Command example : "ethercat reg_write -p 0 0x0c04 0x0001"
+ @param address : register address
+ @param data : data to write
+ @return return_val : the execution result of "ethercat reg_write" (for error check)
+ """
+ error, return_val = self.Controler.RemoteExec(REG_WRITE%(self.Controler.GetSlavePos(), address, data), return_val = None)
+ return return_val
+
+ def Rescan(self):
+ """
+ Synchronize EEPROM data in master controller with the data in slave device after EEPROM write.
+ Command example : "ethercat rescan -p 0"
+ """
+ error, return_val = self.Controler.RemoteExec(RESCAN%(self.Controler.GetSlavePos()), return_val = None)
+
+ #-------------------------------------------------------------------------------
+ # Common Use Methods
+ #-------------------------------------------------------------------------------
+ def CheckConnect(self, cyclic_flag):
+ """
+ Check connection status (1) between Beremiz and the master (2) between the master and the slave.
+ @param cyclic_flag: 0 - one shot, 1 - periodic
+ @return True or False
+ """
+ if self.Controler.GetCTRoot()._connector is not None:
+ # Check connection between the master and the slave.
+ # Command example : "ethercat xml -p 0"
+ error, return_val = self.Controler.RemoteExec(SLAVE_XML%(self.Controler.GetSlavePos()), return_val = None)
+ number_of_lines = return_val.split("\n")
+ if len(number_of_lines) <= 2 : # No slave connected to the master controller
+ if not cyclic_flag :
+ self.CreateErrorDialog('No connected slaves')
+ return False
+
+ elif len(number_of_lines) > 2 :
+ return True
+ else:
+ # The master controller is not connected to Beremiz host
+ if not cyclic_flag :
+ self.CreateErrorDialog('PLC not connected!')
+ return False
+
+ def CreateErrorDialog(self, mention):
+ """
+ Create a dialog to indicate error or warning.
+ @param mention : Error String
+ """
+ app_frame = self.Controler.GetCTRoot().AppFrame
+ dlg = wx.MessageDialog (app_frame, mention,
+ ' Warning...',
+ wx.OK | wx.ICON_INFORMATION)
+ dlg.ShowModal()
+ dlg.Destroy()