etherlab/CommonEtherCATFunction.py
changeset 2354 9460872f1440
parent 2353 8f1a2846b2f5
child 2355 fec77f2b9e07
--- a/etherlab/CommonEtherCATFunction.py	Fri Sep 28 17:14:42 2018 +0300
+++ b/etherlab/CommonEtherCATFunction.py	Fri Sep 28 17:15:53 2018 +0300
@@ -1,1591 +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 Exception:
-        pass
-    try:
-        return int(value.replace("#", "0"), 16)
-        
-    except Exception:
-        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()             
+#!/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 Exception:
+        pass
+    try:
+        return int(value.replace("#", "0"), 16)
+        
+    except Exception:
+        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()