Merged GPL + LGPL v2 or later EtherCAT extension. Fixed headers and copyright notice.
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Sat, 23 Jun 2018 09:08:13 +0200
changeset 2165 02a2b5dee5e3
parent 2021 bcf346f558bd (current diff)
parent 2164 7a959b19d5a4 (diff)
child 2192 09d5d1456616
Merged GPL + LGPL v2 or later EtherCAT extension. Fixed headers and copyright notice.
.hgignore
ethercat_tests/wago_higen/beremiz.xml
ethercat_tests/wago_higen/ethercat@etherlab/baseconfnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/confnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/baseconfnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/config.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/confnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/baseconfnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/confnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/higen@EthercatCIA402Slave/baseconfnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/higen@EthercatCIA402Slave/confnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/baseconfnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/confnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/baseconfnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/confnode.xml
ethercat_tests/wago_higen/ethercat@etherlab/master@EthercatNode/process_variables.xml
ethercat_tests/wago_higen/ethercat@etherlab/modules/Beckhoff EKxxxx.xml
ethercat_tests/wago_higen/ethercat@etherlab/modules/Beckhoff EL1xxx.xml
ethercat_tests/wago_higen/ethercat@etherlab/modules/Beckhoff EL2xxx.xml
ethercat_tests/wago_higen/ethercat@etherlab/modules/Higen_EDA7000_CoE_ver16_with_variablePDO_rv3.xml
ethercat_tests/wago_higen/ethercat@etherlab/modules/modules_extra_params.cfg
ethercat_tests/wago_higen/plc.xml
ethercat_tests/wago_sanyo/beremiz.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/baseconfnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/confnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/baseconfnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/config.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/confnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/baseconfnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/confnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/baseconfnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/confnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/baseconfnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/confnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatCIA402Slave/baseconfnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatCIA402Slave/confnode.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/modules/Beckhoff EKxxxx.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/modules/Beckhoff EL1xxx.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/modules/Beckhoff EL2xxx.xml
ethercat_tests/wago_sanyo/ethercat@etherlab/modules/sanyo.xml
ethercat_tests/wago_sanyo/plc.xml
etherlab/CommonEtherCATFunction.py
etherlab/ConfigEditor.py
etherlab/EtherCATManagementEditor.py
etherlab/EthercatCFileGenerator.py
etherlab/EthercatCIA402Slave.py
etherlab/EthercatMaster.py
etherlab/EthercatSlave.py
etherlab/entries_list.ysl2
etherlab/etherlab.py
etherlab/etherlab_ext.c
etherlab/extension.py
etherlab/plc_cia402node.c
etherlab/plc_etherlab.c
features.py
tests/ethercat/wago_higen/beremiz.xml
tests/ethercat/wago_higen/ethercat@etherlab/baseconfnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/confnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/baseconfnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/config.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/confnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/baseconfnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/confnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/higen@EthercatCIA402Slave/baseconfnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/higen@EthercatCIA402Slave/confnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/baseconfnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/confnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/baseconfnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/confnode.xml
tests/ethercat/wago_higen/ethercat@etherlab/master@EthercatNode/process_variables.xml
tests/ethercat/wago_higen/ethercat@etherlab/modules/Beckhoff EKxxxx.xml
tests/ethercat/wago_higen/ethercat@etherlab/modules/Beckhoff EL1xxx.xml
tests/ethercat/wago_higen/ethercat@etherlab/modules/Beckhoff EL2xxx.xml
tests/ethercat/wago_higen/ethercat@etherlab/modules/Higen_EDA7000_CoE_ver16_with_variablePDO_rv3.xml
tests/ethercat/wago_higen/ethercat@etherlab/modules/modules_extra_params.cfg
tests/ethercat/wago_higen/plc.xml
tests/ethercat/wago_sanyo/beremiz.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/baseconfnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/confnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/baseconfnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/config.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/confnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/baseconfnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/coupler@EthercatSlave/confnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/baseconfnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/inputs@EthercatSlave/confnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/baseconfnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/outputs@EthercatSlave/confnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatCIA402Slave/baseconfnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/master@EthercatNode/sanyo@EthercatCIA402Slave/confnode.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/modules/Beckhoff EKxxxx.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/modules/Beckhoff EL1xxx.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/modules/Beckhoff EL2xxx.xml
tests/ethercat/wago_sanyo/ethercat@etherlab/modules/sanyo.xml
tests/ethercat/wago_sanyo/plc.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/CommonEtherCATFunction.py	Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,1591 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+
+# This file is part of Beremiz
+#
+# Copyright (C) 2013: Real-Time & Embedded Systems (RTES) Lab. University of Seoul, Korea
+#
+# See COPYING file for copyrights details.
+
+import os
+import wx
+
+mailbox_protocols =  ["AoE", "EoE", "CoE", "FoE", "SoE", "VoE"]
+
+def ExtractHexDecValue(value):
+    """
+     convert numerical value in string format into decimal or hex format.
+     @param value : hex or decimal data
+     @return integer data
+    """
+    try:
+        return int(value)
+    except:
+        pass
+    try:
+        return int(value.replace("#", "0"), 16)
+        
+    except:
+        raise ValueError, "Invalid value for HexDecValue \"%s\"" % value
+
+def ExtractName(names, default=None):
+    """
+     Extract "name" field from XML entries.
+     @param names : XML entry
+     @default : if it fails to extract from the designated XML entry, return the default value ("None").
+     @return default or the name extracted
+    """
+    if len(names) == 1:
+        return names[0].getcontent()
+    else:
+        for name in names:
+            if name.getLcId() == 1033:
+                return name.getcontent()
+    return default
+
+#--------------------------------------------------
+#         Remote Exec Etherlab Commands
+#--------------------------------------------------
+
+# --------------------- for master ---------------------------
+MASTER_STATE = """
+import commands
+result = commands.getoutput("ethercat master")
+returnVal =result 
+"""
+
+# --------------------- for slave ----------------------------
+# ethercat state -p (slave position) (state (INIT, PREOP, SAFEOP, OP))
+SLAVE_STATE = """
+import commands
+result = commands.getoutput("ethercat state -p %d %s")
+returnVal = result 
+"""
+
+# ethercat slave
+GET_SLAVE = """
+import commands
+result = commands.getoutput("ethercat slaves")
+returnVal =result 
+"""
+
+# ethercat xml -p (slave position)
+SLAVE_XML = """
+import commands
+result = commands.getoutput("ethercat xml -p %d")
+returnVal = result 
+"""
+
+# ethercat sdos -p (slave position)
+SLAVE_SDO = """
+import commands
+result = commands.getoutput("ethercat sdos -p %d")
+returnVal =result 
+"""
+
+# ethercat upload -p (slave position) (main index) (sub index)
+GET_SLOW_SDO = """
+import commands
+result = commands.getoutput("ethercat upload -p %d %s %s")
+returnVal =result 
+"""
+
+# ethercat download -p (slave position) (main index) (sub index) (value)
+SDO_DOWNLOAD = """
+import commands
+result = commands.getoutput("ethercat download --type %s -p %d %s %s %s")
+returnVal =result 
+"""
+
+# ethercat sii_read -p (slave position)
+SII_READ = """
+import commands
+result = commands.getoutput("ethercat sii_read -p %d")
+returnVal =result 
+"""
+
+# ethercat reg_read -p (slave position) (address) (size)
+REG_READ = """
+import commands
+result = commands.getoutput("ethercat reg_read -p %d %s %s")
+returnVal =result 
+"""
+
+# ethercat sii_write -p (slave position) - (contents)
+SII_WRITE = """ 
+import subprocess 
+process = subprocess.Popen(
+    ["ethercat", "-f", "sii_write", "-p", "%d", "-"],
+    stdin=subprocess.PIPE)
+process.communicate(sii_data)
+returnVal = process.returncode 
+"""
+
+# ethercat reg_write -p (slave position) -t (uinit16) (address) (data)
+REG_WRITE = """ 
+import commands
+result = commands.getoutput("ethercat reg_write -p %d -t uint16 %s %s")
+returnVal =result 
+""" 
+
+# ethercat rescan -p (slave position)
+RESCAN = """ 
+import commands
+result = commands.getoutput("ethercat rescan -p %d")
+returnVal =result 
+"""
+
+#--------------------------------------------------
+#    Common Method For EtherCAT Management 
+#--------------------------------------------------
+class _CommonSlave:
+
+    # ----- Data Structure for ethercat management ----
+    SlaveState = ""
+
+    # category of SDO data
+    DatatypeDescription, CommunicationObject, ManufacturerSpecific, \
+    ProfileSpecific, Reserved, AllSDOData = range(6)
+    
+    # store the execution result of "ethercat sdos" command into SaveSDOData.
+    SaveSDOData = []
+    
+    # Flags for checking "write" permission of OD entries 
+    CheckPREOP = False
+    CheckSAFEOP = False
+    CheckOP = False
+
+    # Save PDO Data
+    TxPDOInfo = []
+    TxPDOCategory = []
+    RxPDOInfo = []
+    RxPDOCategory = []
+    
+    # Save EEPROM Data
+    SiiData = ""
+
+    # Save Register Data
+    RegData = ""
+    CrtRegSpec = {"ESCType": "",
+                  "FMMUNumber": "",
+                  "SMNumber": "",
+                  "PDIType": ""}
+    
+    def __init__(self, controler):
+        """
+        Constructor
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        self.Controler = controler
+         
+        self.ClearSDODataSet()
+    
+    #-------------------------------------------------------------------------------
+    #                        Used Master State
+    #-------------------------------------------------------------------------------
+    def GetMasterState(self):
+        """
+        Execute "ethercat master" command and parse the execution result
+        @return MasterState 
+        """
+
+        # exectute "ethercat master" command 
+        error, return_val = self.Controler.RemoteExec(MASTER_STATE, return_val = None)
+        master_state = {}
+        # parse the reslut
+        for each_line in return_val.splitlines():
+            if len(each_line) > 0 :
+                chunks = each_line.strip().split(':', 1)
+                key = chunks[0]
+                value = []
+                if len(chunks) > 1 :
+                    value = chunks[1].split()
+                if '(attached)' in value:
+                    value.remove('(attached)')
+                master_state[key] = value
+         
+        return master_state     
+    
+    #-------------------------------------------------------------------------------
+    #                        Used Slave State
+    #-------------------------------------------------------------------------------
+    def RequestSlaveState(self, command):
+        """
+        Set slave state to the specified one using "ethercat states -p %d %s" command.
+        Command example : "ethercat states -p 0 PREOP" (target slave position and target state are given.)
+        @param command : target slave state 
+        """
+        error, return_val = self.Controler.RemoteExec(SLAVE_STATE%(self.Controler.GetSlavePos(), command), return_val = None)
+    
+    def GetSlaveStateFromSlave(self):  
+        """
+        Get slave information using "ethercat slaves" command and store the information into internal data structure 
+        (self.SlaveState) for "Slave State" 
+        return_val example : 0  0:0  PREOP  +  EL9800 (V4.30) (PIC24, SPI, ET1100)
+        """ 
+        error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val = None)
+        self.SlaveState = return_val
+        return return_val 
+
+    #-------------------------------------------------------------------------------
+    #                        Used SDO Management
+    #-------------------------------------------------------------------------------
+    def GetSlaveSDOFromSlave(self):
+        """
+        Get SDO objects information of current slave using "ethercat sdos -p %d" command.
+        Command example : "ethercat sdos -p 0"
+        @return return_val : execution results of "ethercat sdos" command (need to be parsed later)
+        """  
+        error, return_val = self.Controler.RemoteExec(SLAVE_SDO%(self.Controler.GetSlavePos()), return_val = None)
+        return return_val   
+        
+    def SDODownload(self, data_type, idx, sub_idx, value):
+        """
+        Set an SDO object value to user-specified value using "ethercat download" command.
+        Command example : "ethercat download --type int32 -p 0 0x8020 0x12 0x00000000"
+        @param data_type : data type of SDO entry
+        @param idx : index of the SDO entry
+        @param sub_idx : subindex of the SDO entry
+        @param value : value of SDO entry
+        """  
+        error, return_val = self.Controler.RemoteExec(SDO_DOWNLOAD%(data_type, self.Controler.GetSlavePos(), idx, sub_idx, value), return_val = None)
+    
+    def BackupSDODataSet(self):
+        """
+        Back-up current SDO entry information to restore the SDO data 
+         in case that the user cancels SDO update operation.
+    	"""  
+        self.BackupDatatypeDescription = self.SaveDatatypeDescription
+        self.BackupCommunicationObject = self.SaveCommunicationObject
+        self.BackupManufacturerSpecific = self.SaveManufacturerSpecific
+        self.BackupProfileSpecific = self.SaveProfileSpecific
+        self.BackupReserved = self.SaveReserved
+        self.BackupAllSDOData = self.SaveAllSDOData
+    
+    def ClearSDODataSet(self):
+        """
+        Clear the specified SDO entry information.
+        """ 
+        for count in range(6):
+            self.SaveSDOData.append([])
+    
+    #-------------------------------------------------------------------------------
+    #                        Used PDO Monitoring
+    #-------------------------------------------------------------------------------
+    def RequestPDOInfo(self):
+        """
+        Load slave information from RootClass (XML data) and parse the information (calling SlavePDOData() method).
+        """ 
+        # Load slave information from ESI XML file (def EthercatMaster.py)
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        
+        type_infos = slave.getType()
+        device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+        # Initialize PDO data set
+        self.ClearDataSet()
+        
+        # if 'device' object is valid, call SavePDOData() to parse PDO data 
+        if device is not None :
+            self.SavePDOData(device)
+    
+    def SavePDOData(self, device):
+        """
+        Parse PDO data and store the results in TXPDOCategory and RXPDOCategory
+        Tx(Rx)PDOCategory : index, name, entry number
+        Tx(Rx)Info : entry index, sub index, name, length, type
+        @param device : Slave information extracted from ESI XML file
+        """ 
+        # Parsing TXPDO entries
+        for pdo, pdo_info in ([(pdo, "Inputs") for pdo in device.getTxPdo()]):
+            # Save pdo_index, entry, and name of each entry
+            pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
+            entries = pdo.getEntry()
+            pdo_name = ExtractName(pdo.getName())
+            
+            # Initialize entry number count
+            count = 0
+            
+            # Parse entries
+            for entry in entries:
+                # Save index and subindex
+                index = ExtractHexDecValue(entry.getIndex().getcontent())
+                subindex = ExtractHexDecValue(entry.getSubIndex())
+                # if entry name exists, save entry data
+                if ExtractName(entry.getName()) is not None :
+                    entry_infos = {
+                                "entry_index" : index,
+                                "subindex" : subindex,
+                                "name" : ExtractName(entry.getName()),
+                                "bitlen" : entry.getBitLen(),
+                                "type" : entry.getDataType().getcontent()
+                                    }
+                    self.TxPDOInfo.append(entry_infos)
+                    count += 1
+              
+            categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}  
+            self.TxPDOCategory.append(categorys)
+
+        # Parsing RxPDO entries
+        for pdo, pdo_info in ([(pdo, "Outputs") for pdo in device.getRxPdo()]):
+            # Save pdo_index, entry, and name of each entry
+            pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
+            entries = pdo.getEntry()
+            pdo_name = ExtractName(pdo.getName())
+            
+            # Initialize entry number count
+            count = 0          
+
+            # Parse entries          
+            for entry in entries:
+                # Save index and subindex
+                index = ExtractHexDecValue(entry.getIndex().getcontent())
+                subindex = ExtractHexDecValue(entry.getSubIndex())
+                # if entry name exists, save entry data
+                if ExtractName(entry.getName()) is not None :
+                    entry_infos = {
+                                "entry_index" : index,
+                                "subindex" : subindex,
+                                "name" : ExtractName(entry.getName()),
+                                "bitlen" : str(entry.getBitLen()),
+                                "type" : entry.getDataType().getcontent()
+                                    }
+                    self.RxPDOInfo.append(entry_infos)
+                    count += 1
+    
+            categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}  
+            self.RxPDOCategory.append(categorys) 
+
+    def GetTxPDOCategory(self):
+        """
+        Get TxPDOCategory data structure (Meta informaton of TxPDO).
+        TxPDOCategorys : index, name, number of entries
+        @return TxPDOCategorys
+        """ 
+        return self.TxPDOCategory
+        
+    def GetRxPDOCategory(self):
+        """
+        Get RxPDOCategory data structure (Meta information of RxPDO).
+        RxPDOCategorys : index, name, number of entries
+        @return RxPDOCategorys
+        """ 
+        return self.RxPDOCategory
+        
+    def GetTxPDOInfo(self):
+        """
+        Get TxPDOInfo data structure (Detailed information on TxPDO entries). 
+        TxPDOInfos : entry index, sub index, name, length, type
+        @return TxPDOInfos
+        """ 
+        return self.TxPDOInfo
+        
+    def GetRxPDOInfo(self):
+        """
+        Get RxPDOInfo data structure (Detailed information on RxPDO entries). 
+        RxPDOInfos : entry index, sub index, name, length, type
+        @return RxPDOInfos
+        """ 
+        return self.RxPDOInfo
+        
+    def ClearDataSet(self):
+        """
+        Initialize PDO management data structure.
+        """ 
+        self.TxPDOInfos = []
+        self.TxPDOCategorys = []
+        self.RxPDOInfos = []
+        self.RxPDOCategorys = []
+               
+    #-------------------------------------------------------------------------------
+    #                        Used EEPROM Management
+    #-------------------------------------------------------------------------------
+    # Base data types in ETG2000; format = {"Name": "BitSize"}
+    BaseDataTypeDict = {"BOOL": "01",
+                        "SINT": "02",
+                        "INT": "03",
+                        "DINT": "04",
+                        "USINT": "05",
+                        "UINT": "06",
+                        "UDINT": "07",
+                        "REAL": "08",
+                        "INT24": "10",
+                        "LREAL": "11",
+                        "INT40": "12",
+                        "INT48": "13",
+                        "INT56": "14",
+                        "LINT": "15",
+                        "UINT24": "16",
+                        "UINT40": "18",
+                        "UINT48": "19",
+                        "UINT56": "1a",
+                        "ULINT": "1b",
+                        "USINT": "1e",
+                        "BITARR8": "2d",
+                        "BITARR16": "2e",
+                        "BITARR32": "2f",
+                        "BIT1": "30",
+                        "BIT2": "31",
+                        "BIT3": "32",
+                        "BIT4": "33",
+                        "BIT5": "34",
+                        "BIT6": "35",
+                        "BIT7": "36",
+                        "BIT8": "37"}        
+        
+    def GetSmartViewInfos(self):
+        """
+        Parse XML data for "Smart View" of EEPROM contents.
+        @return smartview_infos : EEPROM contents dictionary
+        """ 
+
+        smartview_infos = {"eeprom_size": 128,
+                           "pdi_type": 0,
+                           "device_emulation": "False",
+                           "vendor_id": '0x00000000',
+                           "product_code": '0x00000000',
+                           "revision_no": '0x00000000',
+                           "serial_no": '0x00000000',
+                           "supported_mailbox": "",
+                           "mailbox_bootstrapconf_outstart": '0',
+                           "mailbox_bootstrapconf_outlength": '0',
+                           "mailbox_bootstrapconf_instart": '0',
+                           "mailbox_bootstrapconf_inlength": '0',
+                           "mailbox_standardconf_outstart": '0',
+                           "mailbox_standardconf_outlength": '0',
+                           "mailbox_standardconf_instart": '0',
+                           "mailbox_standardconf_inlength": '0'}
+        
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        type_infos = slave.getType()
+        device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+
+        # 'device' represents current slave device selected by user
+        if device is not None:
+            for eeprom_element in device.getEeprom().getcontent():
+                # get EEPROM size; <Device>-<Eeprom>-<ByteSize>
+                if eeprom_element["name"] == "ByteSize":
+                    smartview_infos["eeprom_size"] = eeprom_element
+                        
+                elif eeprom_element["name"] == "ConfigData":
+                    configData_data = self.DecimalToHex(eeprom_element)
+                    # get PDI type; <Device>-<Eeprom>-<ConfigData> address 0x00
+                    smartview_infos["pdi_type"] = int(configData_data[0:2], 16)
+                    # get state of device emulation; <Device>-<Eeprom>-<ConfigData> address 0x01
+                    if "{:0>8b}".format(int(configData_data[2:4], 16))[7] == '1':
+                        smartview_infos["device_emulation"] = "True"
+
+                elif eeprom_element["name"] == "BootStrap":
+                    bootstrap_data = "{:0>16x}".format(eeprom_element)
+                    # get bootstrap configuration; <Device>-<Eeprom>-<BootStrap>
+                    for cfg, iter in [("mailbox_bootstrapconf_outstart", 0), 
+                                      ("mailbox_bootstrapconf_outlength", 1),
+                                      ("mailbox_bootstrapconf_instart", 2),
+                                      ("mailbox_bootstrapconf_inlength", 3)]:
+                        smartview_infos[cfg] = str(int(bootstrap_data[4*iter+2:4*(iter+1)]+bootstrap_data[4*iter:4*iter+2], 16))
+            
+            # get protocol (profile) types supported by mailbox; <Device>-<Mailbox>
+            mb = device.getMailbox()
+            if mb is not None:
+                for mailbox_protocol in mailbox_protocols:
+                    if getattr(mb,"get%s"%mailbox_protocol)() is not None:
+                        smartview_infos["supported_mailbox"] += "%s,  "%mailbox_protocol
+            smartview_infos["supported_mailbox"] = smartview_infos["supported_mailbox"].strip(",  ")
+                
+            # get standard configuration of mailbox; <Device>-<Sm>
+            for sm_element in device.getSm():
+                if sm_element.getcontent() == "MBoxOut":
+                    smartview_infos["mailbox_standardconf_outstart"] = str(ExtractHexDecValue(sm_element.getStartAddress()))
+                    smartview_infos["mailbox_standardconf_outlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize()))
+                elif sm_element.getcontent() == "MBoxIn":
+                    smartview_infos["mailbox_standardconf_instart"] = str(ExtractHexDecValue(sm_element.getStartAddress()))
+                    smartview_infos["mailbox_standardconf_inlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize()))
+                else:
+                    pass
+
+            # get device identity from <Device>-<Type>
+            #  vendor ID; by default, pre-defined value in self.ModulesLibrary
+            #             if device type in 'vendor' item equals to actual slave device type, set 'vendor_id' to vendor ID.
+            for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+                for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]:
+                    if available_device[0] == type_infos["device_type"]:
+                        smartview_infos["vendor_id"] = "0x" + "{:0>8x}".format(vendor_id)
+                        
+            #  product code; 
+            if device.getType().getProductCode() is not None:
+                product_code = device.getType().getProductCode()
+                smartview_infos["product_code"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(product_code))
+                
+            #  revision number; 
+            if device.getType().getRevisionNo() is not None:
+                revision_no = device.getType().getRevisionNo()
+                smartview_infos["revision_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(revision_no))
+                
+            #  serial number;
+            if device.getType().getSerialNo() is not None:
+                serial_no = device.getType().getSerialNo()
+                smartview_infos["serial_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(serial_no))
+                                            
+            return smartview_infos
+        
+        else:
+            return None
+        
+    def DecimalToHex(self, decnum):
+        """
+        Convert decimal value into hexadecimal representation. 
+        @param decnum : decimal value
+        @return hex_data : hexadecimal representation of input value in decimal
+        """ 
+        value = "%x" % decnum
+        value_len = len(value)
+        if (value_len % 2) == 0:
+            hex_len = value_len
+        else:
+            hex_len = (value_len / 2) * 2 + 2
+        
+        hex_data = ("{:0>"+str(hex_len)+"x}").format(decnum)
+        
+        return hex_data
+
+    def SiiRead(self):
+        """
+        Get slave EEPROM contents maintained by master device using "ethercat sii_read -p %d" command.
+        Command example : "ethercat sii_read -p 0"
+        @return return_val : result of "ethercat sii_read" (binary data)
+        """ 
+        error, return_val = self.Controler.RemoteExec(SII_READ%(self.Controler.GetSlavePos()), return_val = None)
+        self.SiiData = return_val
+        return return_val
+
+    def SiiWrite(self, binary):
+        """
+        Overwrite slave EEPROM contents using "ethercat sii_write -p %d" command.
+        Command example : "ethercat sii_write -p 0 - (binary contents)"
+        @param binary : EEPROM contents in binary data format
+        @return return_val : result of "ethercat sii_write" (If it succeeds, the return value is NULL.)
+        """ 
+        error, return_val = self.Controler.RemoteExec(SII_WRITE%(self.Controler.GetSlavePos()), return_val = None, sii_data = binary)
+        return return_val 
+
+    def LoadData(self):
+        """
+        Loading data from EEPROM use Sii_Read Method
+        @return self.BinaryCode : slave EEPROM data in binary format (zero-padded)
+        """ 
+        return_val = self.Controler.CommonMethod.SiiRead()
+        self.BinaryCode = return_val
+        self.Controler.SiiData = self.BinaryCode
+
+        # append zero-filled padding data up to EEPROM size
+        for index in range(self.SmartViewInfosFromXML["eeprom_size"] - len(self.BinaryCode)):
+            self.BinaryCode = self.BinaryCode +'ff'.decode('hex')
+              
+        return self.BinaryCode
+
+    def HexRead(self, binary):
+        """
+        Convert binary digit representation into hexadecimal representation for "Hex View" menu.
+        @param binary : binary digits
+        @return hexCode : hexadecimal digits
+        @return hexview_table_row, hexview_table_col : Grid size for "Hex View" UI
+        """ 
+        row_code = []
+        row_text = ""
+        row = 0
+        hex_code = []
+
+        hexview_table_col = 17
+        
+        for index in range(0, len(binary)) :
+            if len(binary[index]) != 1:
+                break
+            else:
+                digithexstr = hex(ord(binary[index])) 
+
+                tempvar2 = digithexstr[2:4]
+                if len(tempvar2) == 1:
+                    tempvar2 = "0" + tempvar2
+                row_code.append(tempvar2) 
+                
+                if int(digithexstr, 16)>=32 and int(digithexstr, 16)<=126:
+                    row_text = row_text + chr(int(digithexstr, 16))
+                else:
+                    row_text = row_text + "."
+                
+                if index != 0 : 
+                    if len(row_code) == (hexview_table_col - 1):
+                        row_code.append(row_text)
+                        hex_code.append(row_code)
+                        row_text = ""
+                        row_code = []
+                        row = row + 1        
+                                        
+        hexview_table_row = row
+        
+        return hex_code, hexview_table_row, hexview_table_col
+    
+    def GenerateEEPROMList(self, data, direction, length):
+        """
+        Generate EEPROM data list by reconstructing 'data' string.
+        example : data="12345678", direction=0, length=8 -> eeprom_list=['12', '34', '56', '78']
+                  data="12345678", direction=1, length=8 -> eeprom_list=['78', '56', '34', '12']
+        @param data : string to be reconstructed
+        @param direction : endianness
+        @param length : data length
+        @return eeprom_list : reconstructed list data structure
+        """ 
+        eeprom_list = []
+
+        if direction is 0 or 1:
+            for i in range(length/2):
+                if data == "":
+                    eeprom_list.append("00")
+                else:
+                    eeprom_list.append(data[direction*(length-2):direction*(length-2)+2])
+                data = data[(1-direction)*2:length-direction*2]
+                length -= 2
+        return eeprom_list
+    
+    def XmlToEeprom(self):
+        """
+        Extract slave EEPROM contents using slave ESI XML file.
+          - Mandatory parts
+          - String category : ExtractEEPROMStringCategory()
+          - General category : ExtractEEPROMGeneralCategory()
+          - FMMU category : ExtractEEPROMFMMUCategory
+          - SyncM category : ExtractEEPROMSyncMCategory()
+          - Tx/RxPDO category : ExtractEEPROMPDOCategory()
+          - DC category : ExtractEEPROMDCCategory()
+        @return eeprom_binary 
+        """ 
+        eeprom = []
+        data = ""
+        eeprom_size = 0
+        eeprom_binary = ""
+
+        # 'device' is the slave device of the current EtherCAT slave plugin
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        type_infos = slave.getType()
+        device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+        
+        if device is not None:
+            # get ConfigData for EEPROM offset 0x0000-0x000d; <Device>-<Eeprom>-<ConfigData>
+            for eeprom_element in device.getEeprom().getcontent():
+                if eeprom_element["name"] == "ConfigData":
+                    data = self.DecimalToHex(eeprom_element)
+            eeprom += self.GenerateEEPROMList(data, 0, 28)
+            
+            # calculate CRC for EEPROM offset 0x000e-0x000f
+            crc = 0x48
+            for segment in eeprom:
+                for i in range(8):
+                    bit = crc & 0x80
+                    crc = (crc << 1) | ((int(segment, 16) >> (7 - i)) & 0x01)
+                    if bit:
+                        crc ^= 0x07   
+            for k in range(8):
+                bit = crc & 0x80
+                crc <<= 1
+                if bit:
+                    crc ^= 0x07      
+            eeprom.append(hex(crc)[len(hex(crc))-3:len(hex(crc))-1])
+            eeprom.append("00")
+            
+            # get VendorID for EEPROM offset 0x0010-0x0013;
+            data = ""
+            for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+                for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]:
+                    if available_device[0] == type_infos["device_type"]:
+                        data = "{:0>8x}".format(vendor_id)
+            eeprom += self.GenerateEEPROMList(data, 1, 8)
+            
+            # get Product Code for EEPROM offset 0x0014-0x0017;
+            data = ""
+            if device.getType().getProductCode() is not None:
+                data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getProductCode()))
+            eeprom += self.GenerateEEPROMList(data, 1, 8)
+            
+            # get Revision Number for EEPROM offset 0x0018-0x001b;
+            data = ""
+            if device.getType().getRevisionNo() is not None:
+                data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getRevisionNo()))
+            eeprom += self.GenerateEEPROMList(data, 1, 8)  
+            
+            # get Serial Number for EEPROM 0x001c-0x001f;
+            data = ""
+            if device.getType().getSerialNo() is not None:
+                data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getSerialNo()))
+            eeprom += self.GenerateEEPROMList(data, 1, 8)
+                
+            # get Execution Delay for EEPROM 0x0020-0x0021; not analyzed yet
+            eeprom.append("00")
+            eeprom.append("00")
+            
+            # get Port0/1 Delay for EEPROM offset 0x0022-0x0025; not analyzed yet
+            eeprom.append("00")
+            eeprom.append("00")
+            eeprom.append("00")
+            eeprom.append("00")
+            
+            # reserved for EEPROM offset 0x0026-0x0027;
+            eeprom.append("00")
+            eeprom.append("00")
+
+            # get BootStrap for EEPROM offset 0x0028-0x002e; <Device>-<Eeprom>-<BootStrap>
+            data = ""
+            for eeprom_element in device.getEeprom().getcontent():
+                if eeprom_element["name"] == "BootStrap":
+                    data = "{:0>16x}".format(eeprom_element)
+            eeprom += self.GenerateEEPROMList(data, 0, 16)
+            
+            # get Standard Mailbox for EEPROM offset 0x0030-0x0037; <Device>-<sm>
+            data = ""
+            standard_send_mailbox_offset = None
+            standard_send_mailbox_size = None
+            standard_receive_mailbox_offset = None
+            standard_receive_mailbox_size = None
+            for sm_element in device.getSm():
+                if sm_element.getcontent() == "MBoxOut":
+                    standard_receive_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress()))
+                    standard_receive_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize()))
+                elif sm_element.getcontent() == "MBoxIn":
+                    standard_send_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress()))
+                    standard_send_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize()))
+                    
+            if standard_receive_mailbox_offset is None:
+                eeprom.append("00")
+                eeprom.append("00")
+            else:
+                eeprom.append(standard_receive_mailbox_offset[2:4])
+                eeprom.append(standard_receive_mailbox_offset[0:2])
+            if standard_receive_mailbox_size is None:
+                eeprom.append("00")
+                eeprom.append("00")
+            else:
+                eeprom.append(standard_receive_mailbox_size[2:4])
+                eeprom.append(standard_receive_mailbox_size[0:2])
+            if standard_send_mailbox_offset is None:
+                eeprom.append("00")
+                eeprom.append("00")
+            else:
+                eeprom.append(standard_send_mailbox_offset[2:4])
+                eeprom.append(standard_send_mailbox_offset[0:2])
+            if standard_send_mailbox_size is None:
+                eeprom.append("00")
+                eeprom.append("00")
+            else:
+                eeprom.append(standard_send_mailbox_size[2:4])
+                eeprom.append(standard_send_mailbox_size[0:2])
+            
+            # get supported mailbox protocols for EEPROM offset 0x0038-0x0039;
+            data = 0
+            mb = device.getMailbox()
+            if mb is not None :
+                for bit,mbprot in enumerate(mailbox_protocols):
+                    if getattr(mb,"get%s"%mbprot)() is not None:
+                        data += 1<<bit
+            data = "{:0>4x}".format(data)
+            eeprom.append(data[2:4])
+            eeprom.append(data[0:2])
+            
+            # resereved for EEPROM offset 0x003a-0x007b;
+            for i in range(0x007b-0x003a+0x0001):
+                eeprom.append("00")
+            
+            # get EEPROM size for EEPROM offset 0x007c-0x007d;
+            data = ""
+            for eeprom_element in device.getEeprom().getcontent():
+                if eeprom_element["name"] == "ByteSize":
+                    eeprom_size = int(str(eeprom_element))
+                    data = "{:0>4x}".format(int(eeprom_element)/1024*8-1)
+
+            if data == "":
+                eeprom.append("00")
+                eeprom.append("00")
+            else:
+                eeprom.append(data[2:4])
+                eeprom.append(data[0:2])
+                
+            # Version for EEPROM 0x007e-0x007f; 
+            #  According to "EtherCAT Slave Device Description(V0.3.0)"
+            eeprom.append("01")
+            eeprom.append("00")
+            
+            # append String Category data
+            for data in self.ExtractEEPROMStringCategory(device):
+                eeprom.append(data)
+                
+            # append General Category data
+            for data in self.ExtractEEPROMGeneralCategory(device):
+                eeprom.append(data)
+                
+            # append FMMU Category data
+            for data in self.ExtractEEPROMFMMUCategory(device):
+                eeprom.append(data)
+            
+            # append SyncM Category data
+            for data in self.ExtractEEPROMSyncMCategory(device):
+                eeprom.append(data)
+                
+            # append TxPDO Category data
+            for data in self.ExtractEEPROMPDOCategory(device, "TxPdo"):
+                eeprom.append(data)
+                
+            # append RxPDO Category data
+            for data in self.ExtractEEPROMPDOCategory(device, "RxPdo"):
+                eeprom.append(data)
+                
+            # append DC Category data
+            for data in self.ExtractEEPROMDCCategory(device):
+                eeprom.append(data)
+            
+            # append padding
+            padding = eeprom_size-len(eeprom)
+            for i in range(padding):
+                eeprom.append("ff")
+            
+            # convert binary code
+            for index in range(eeprom_size):
+                eeprom_binary = eeprom_binary + eeprom[index].decode('hex')
+            
+            return eeprom_binary
+    
+    def ExtractEEPROMStringCategory(self, device):
+        """
+        Extract "Strings" category data from slave ESI XML and generate EEPROM image data.
+        @param device : 'device' object in the slave ESI XML
+        @return eeprom : "Strings" category EEPROM image data
+        """ 
+        eeprom = []
+        self.Strings = []
+        data = "" 
+        count = 0 # string counter
+        padflag = False # padding flag if category length is odd
+        
+        # index information for General Category in EEPROM
+        self.GroupIdx = 0
+        self.ImgIdx = 0
+        self.OrderIdx = 0
+        self.NameIdx = 0
+        
+        # flag for preventing duplicated vendor specific data 
+        typeflag = False
+        grouptypeflag = False
+        groupnameflag = False
+        devnameflag = False
+        imageflag = False
+        
+        # vendor specific data
+        #   element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type>
+        #   vendor_specific_data : vendor specific data (binary type)
+        vendor_specific_data = ""
+        #   vendor_spec_strings : list of vendor specific "strings" for preventing duplicated strings
+        vendor_spec_strings = []
+        for element in device.getType().getcontent():
+            data += element
+        if data is not "" and type(data) == unicode:
+            for vendor_spec_string in vendor_spec_strings: 
+                if data == vendor_spec_string:
+                    self.OrderIdx = vendor_spec_strings.index(data)+1
+                    typeflag = True
+                    break
+            if typeflag is False:
+                count += 1
+                self.Strings.append(data)
+                vendor_spec_strings.append(data)
+                typeflag = True
+                self.OrderIdx = count
+                vendor_specific_data += "{:0>2x}".format(len(data))
+                for character in range(len(data)):
+                    vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+        data = ""
+        
+        #  element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType>
+        data = device.getGroupType()
+        if data is not None and type(data) == unicode:
+            for vendor_spec_string in vendor_spec_strings:
+                if data == vendor_spec_string:
+                    self.GroupIdx = vendor_spec_strings.index(data)+1
+                    grouptypeflag = True
+                    break
+            if grouptypeflag is False:
+                grouptype = data
+                count += 1
+                self.Strings.append(data)
+                vendor_spec_strings.append(data)
+                grouptypeflag = True
+                self.GroupIdx = count
+                vendor_specific_data += "{:0>2x}".format(len(data))
+                for character in range(len(data)):
+                    vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+        
+        #  element2-2; <EtherCATInfo>-<Groups>-<Group>-<Type>            
+        if grouptypeflag is False: 
+            if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+                for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+                    for group_type, group_etc in vendor["groups"].iteritems():
+                        for device_item in group_etc["devices"]:
+                            if device == device_item[1]: 
+                                data = group_type
+                if data is not None and type(data) == unicode:
+                    for vendor_spec_string in vendor_spec_strings:
+                        if data == vendor_spec_string:
+                            self.GroupIdx = vendor_spec_strings.index(data)+1
+                            grouptypeflag = True
+                            break
+                    if grouptypeflag is False:
+                        grouptype = data
+                        count += 1
+                        self.Strings.append(data)
+                        vendor_spec_strings.append(data)
+                        grouptypeflag = True
+                        self.GroupIdx = count
+                        vendor_specific_data += "{:0>2x}".format(len(data))
+                        for character in range(len(data)):
+                            vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+        data = ""
+        
+        #  element3; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Name(LcId is "1033")>
+        if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+            for vendorId, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+                for group_type, group_etc in vendor["groups"].iteritems():
+                    for device_item in group_etc["devices"]:
+                        if device == device_item[1]:
+                            data = group_etc["name"]
+        if data is not "" and type(data) == unicode:
+            for vendor_spec_string in vendor_spec_strings:
+                if data == vendor_spec_string:
+                    groupnameflag = True
+                    break
+            if groupnameflag is False:
+                count += 1
+                self.Strings.append(data)
+                vendor_spec_strings.append(data)
+                groupnameflag = True
+                vendor_specific_data += "{:0>2x}".format(len(data))
+                for character in range(len(data)):
+                    vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+        data = ""
+        
+        #  element4; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Name(LcId is "1033" or "1"?)>
+        for element in device.getName():
+            if element.getLcId() == 1 or element.getLcId()==1033:
+                data = element.getcontent()
+        if data is not "" and type(data) == unicode:
+            for vendor_spec_string in vendor_spec_strings:
+                if data == vendor_spec_string:
+                    self.NameIdx = vendor_spec_strings.index(data)+1
+                    devnameflag = True
+                    break
+            if devnameflag is False:
+                count += 1
+                self.Strings.append(data)
+                vendor_spec_strings.append(data)
+                devnameflag = True
+                self.NameIdx = count
+                vendor_specific_data += "{:0>2x}".format(len(data))
+                for character in range(len(data)):
+                    vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+        data = ""
+        
+        #  element5-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Image16x14>
+        if device.getcontent() is not None:
+            data = device.getcontent()
+            if data is not None and type(data) == unicode:
+                for vendor_spec_string in vendor_spec_strings:
+                    if data == vendor_spec_string:
+                        self.ImgIdx = vendor_spec_strings.index(data)+1
+                        imageflag = True
+                        break
+                if imageflag is False:
+                    count += 1
+                    self.Strings.append(data)
+                    vendor_spec_strings.append(data)
+                    imageflag = True
+                    self.ImgIdx = count
+                    vendor_specific_data += "{:0>2x}".format(len(data))
+                    for character in range(len(data)):
+                        vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+                        
+        #  element5-2; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Image16x14>
+        if imageflag is False:
+            if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+                for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems():
+                    for group_type, group_etc in vendor["groups"].iteritems():
+                        for device_item in group_etc["devices"]:
+                            if device == device_item[1]:
+                                data = group_etc
+                if data is not None and type(data) == unicode:
+                    for vendor_spec_string in vendor_spec_strings:
+                        if data == vendor_spec_string:
+                            self.ImgIdx = vendor_spec_strings.index(data)+1
+                            imageflag = True
+                            break
+                    if imageflag is False:
+                        count += 1
+                        self.Strings.append(data)
+                        vendor_spec_strings.append(data)
+                        imageflag = True
+                        self.ImgIdx = count
+                        vendor_specific_data += "{:0>2x}".format(len(data))
+                        for character in range(len(data)):
+                            vendor_specific_data += "{:0>2x}".format(ord(data[character]))
+        data = ""
+        
+        # DC related elements
+        #  <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Dc>-<OpMode>-<Name>
+        dc_related_elements = ""
+        if device.getDc() is not None:
+            for element in device.getDc().getOpMode():
+                data = element.getName()
+                if data is not "":
+                    count += 1
+                    self.Strings.append(data)
+                    dc_related_elements += "{:0>2x}".format(len(data))
+                    for character in range(len(data)):
+                        dc_related_elements += "{:0>2x}".format(ord(data[character]))
+                    data = ""
+        
+        # Input elements(TxPDO)
+        #  <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name
+        input_elements = ""
+        inputs = []
+        for element in device.getTxPdo():
+            for name in element.getName():
+                data = name.getcontent()
+            for input in inputs:
+                if data == input: 
+                    data = ""
+            if data is not "":
+                count += 1
+                self.Strings.append(data)
+                inputs.append(data)
+                input_elements += "{:0>2x}".format(len(data))
+                for character in range(len(data)):
+                    input_elements += "{:0>2x}".format(ord(data[character]))
+                data = ""            
+            for entry in element.getEntry():
+                for name in entry.getName():
+                    data = name.getcontent()
+                for input in inputs:
+                    if data == input: 
+                        data = ""
+                if data is not "":
+                    count += 1
+                    self.Strings.append(data)
+                    inputs.append(data)
+                    input_elements += "{:0>2x}".format(len(data))
+                    for character in range(len(data)):
+                        input_elements += "{:0>2x}".format(ord(data[character]))
+                    data = ""
+        
+        # Output elements(RxPDO)
+        #  <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name
+        output_elements = ""
+        outputs = []
+        for element in device.getRxPdo():
+            for name in element.getName():
+                data = name.getcontent()
+            for output in outputs:
+                if data == output: 
+                    data = ""
+            if data is not "":
+                count += 1
+                self.Strings.append(data)
+                outputs.append(data)
+                output_elements += "{:0>2x}".format(len(data))
+                for character in range(len(data)):
+                    output_elements += "{:0>2x}".format(ord(data[character]))
+                data = ""            
+            for entry in element.getEntry():
+                for name in entry.getName():
+                    data = name.getcontent()
+                for output in outputs:
+                    if data == output: 
+                        data = ""
+                if data is not "":
+                    count += 1
+                    self.Strings.append(data)
+                    outputs.append(data)
+                    output_elements += "{:0>2x}".format(len(data))
+                    for character in range(len(data)):
+                        output_elements += "{:0>2x}".format(ord(data[character]))
+                    data = ""     
+        
+        # form eeprom data
+        #  category header
+        eeprom.append("0a")
+        eeprom.append("00")
+        #  category length (word); 1 word is 4 bytes. "+2" is the length of string's total number
+        length = len(vendor_specific_data + dc_related_elements + input_elements + output_elements) + 2
+        if length%4 == 0:
+            pass
+        else:
+            length +=length%4
+            padflag = True
+        eeprom.append("{:0>4x}".format(length/4)[2:4])
+        eeprom.append("{:0>4x}".format(length/4)[0:2])
+        #  total numbers of strings
+        eeprom.append("{:0>2x}".format(count))
+        for element in [vendor_specific_data,
+                        dc_related_elements,
+                        input_elements,
+                        output_elements]:
+            for iter in range(len(element)/2):
+                if element == "":
+                    eeprom.append("00")
+                else:
+                    eeprom.append(element[0:2])
+                element = element[2:len(element)]     
+        # padding if length is odd bytes 
+        if padflag is True:
+            eeprom.append("ff")
+        
+        return eeprom
+    
+    def ExtractEEPROMGeneralCategory(self, device):
+        """
+        Extract "General" category data from slave ESI XML and generate EEPROM image data.
+        @param device : 'device' object in the slave ESI XML
+        @return eeprom : "Strings" category EEPROM image data
+        """ 
+        eeprom = []
+        data = ""
+        
+        # category header
+        eeprom.append("1e")
+        eeprom.append("00")
+        
+        # category length
+        eeprom.append("10")
+        eeprom.append("00")
+        
+        # word 1 : Group Type index and Image index in STRINGS Category
+        eeprom.append("{:0>2x}".format(self.GroupIdx))
+        eeprom.append("{:0>2x}".format(self.ImgIdx))
+        
+        # word 2 : Device Type index and Device Name index in STRINGS Category
+        eeprom.append("{:0>2x}".format(self.OrderIdx))
+        eeprom.append("{:0>2x}".format(self.NameIdx))
+        
+        # word 3 : Physical Layer Port info. and CoE Details
+        eeprom.append("01") # Physical Layer Port info - assume 01
+        #  CoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>
+        coe_details = 0
+        mb = device.getMailbox()
+        coe_details = 1 # sdo enabled
+        if mb is not None :
+            coe = mb.getCoE()
+            if coe is not None:
+                for bit,flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig", 
+                                           "PdoUpload", "CompleteAccess"]):
+                    if getattr(coe,"get%s"%flag)() is not None:
+                        coe_details += 1<<bit        
+        eeprom.append("{:0>2x}".format(coe_details))
+        
+        # word 4 : FoE Details and EoE Details
+        #  FoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<FoE>
+        if mb is not None and mb.getFoE() is not None:
+            eeprom.append("01")
+        else:
+            eeprom.append("00")
+        #  EoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<EoE>
+        if mb is not None and mb.getEoE() is not None:
+            eeprom.append("01")
+        else:
+            eeprom.append("00")
+            
+        # word 5 : SoE Channels(reserved) and DS402 Channels
+        #  SoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<SoE>
+        if mb is not None and mb.getSoE() is not None:
+            eeprom.append("01")
+        else:
+            eeprom.append("00")
+        #  DS402Channels; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>: DS402Channels
+        ds402ch = False
+        if mb is not None :
+            coe = mb.getCoE()
+            if coe is not None :
+                ds402ch = coe.getDS402Channels()
+        eeprom.append("01" if ds402ch in [True,1] else "00")
+            
+        # word 6 : SysmanClass(reserved) and Flags
+        eeprom.append("00") # reserved
+        #  Flags 
+        en_safeop = False
+        en_lrw = False
+        if device.getType().getTcCfgModeSafeOp() == True \
+        or device.getType().getTcCfgModeSafeOp() == 1:
+            en_safeop = True
+        if device.getType().getUseLrdLwr() == True \
+        or device.getType().getUseLrdLwr() == 1:
+            en_lrw = True
+        
+        flags = "0b"+"000000"+str(int(en_lrw))+str(int(en_safeop))
+        eeprom.append("{:0>2x}".format(int(flags, 2)))
+            
+        # word 7 : Current On EBus (assume 0x0000)
+        eeprom.append("00")
+        eeprom.append("00")
+        # after word 7; couldn't analyze yet
+        eeprom.append("03")
+        eeprom.append("00")
+        eeprom.append("11")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        eeprom.append("00")
+        
+        return eeprom
+    
+    def ExtractEEPROMFMMUCategory(self, device):
+        """
+        Extract "FMMU" category data from slave ESI XML and generate EEPROM image data.
+        @param device : 'device' object in the slave ESI XML
+        @return eeprom : "Strings" category EEPROM image data
+        """ 
+        eeprom = []
+        data = ""
+        count = 0 # number of FMMU
+        padflag = False
+        
+        for fmmu in device.getFmmu():
+            count += 1
+            if fmmu.getcontent() == "Outputs":
+                data += "01"
+            if fmmu.getcontent() == "Inputs":
+                data += "02"
+            if fmmu.getcontent() == "MBoxState":
+                data += "03"
+        
+        # construct of EEPROM data
+        if data is not "":
+            #  category header
+            eeprom.append("28")
+            eeprom.append("00")
+            #  category length
+            if count%2 == 1:
+                padflag = True
+                eeprom.append("{:0>4x}".format((count+1)/2)[2:4])
+                eeprom.append("{:0>4x}".format((count+1)/2)[0:2])
+            else: 
+                eeprom.append("{:0>4x}".format((count)/2)[2:4])
+                eeprom.append("{:0>4x}".format((count)/2)[0:2])
+            for i in range(count):
+                if data == "":
+                    eeprom.append("00")
+                else:
+                    eeprom.append(data[0:2])
+                data = data[2:len(data)]
+            #  padding if length is odd bytes 
+            if padflag is True:
+                eeprom.append("ff")       
+            
+        return eeprom
+    
+    def ExtractEEPROMSyncMCategory(self, device):
+        """
+        Extract "SyncM" category data from slave ESI XML and generate EEPROM image data.
+        @param device : 'device' object in the slave ESI XML
+        @return eeprom : "Strings" category EEPROM image data
+        """ 
+        eeprom = []
+        data = ""
+        number = {"MBoxOut":"01", "MBoxIn":"02", "Outputs":"03", "Inputs":"04"}
+        
+        for sm in device.getSm():
+            for attr in [sm.getStartAddress(),
+                         sm.getDefaultSize(),
+                         sm.getControlByte()]:
+                if attr is not None:
+                    data += "{:0>4x}".format(ExtractHexDecValue(attr))[2:4]
+                    data += "{:0>4x}".format(ExtractHexDecValue(attr))[0:2]
+                else:
+                    data += "0000"  
+            if sm.getEnable() == "1" or sm.getEnable() == True:
+                data += "01"
+            else:
+                data += "00"
+            data += number[sm.getcontent()]
+            
+        if data is not "":
+            #  category header
+            eeprom.append("29")
+            eeprom.append("00")
+            #  category length 
+            eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
+            eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
+            for i in range(len(data)/2):
+                if data == "":
+                    eeprom.append("00")
+                else:
+                    eeprom.append(data[0:2])
+                data = data[2:len(data)]
+
+        return eeprom
+    
+    def ExtractEEPROMPDOCategory(self, device, pdotype):
+        """
+        Extract ""PDO (Tx, Rx)"" category data from slave ESI XML and generate EEPROM image data.
+        @param device : 'device' object in the slave ESI XML
+        @param pdotype : identifier whether "TxPDO" or "RxPDO".
+        @return eeprom : "Strings" category EEPROM image data
+        """ 
+        eeprom = []
+        data = ""
+        count = 0
+        en_fixed = False
+        en_mandatory = False
+        en_virtual = False
+        
+        for element in eval("device.get%s()"%pdotype):
+            #  PDO Index
+            data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[2:4]
+            data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[0:2]
+            #  Number of Entries
+            data += "{:0>2x}".format(len(element.getEntry()))
+            #  About Sync Manager
+            if element.getSm() is not None:
+                data += "{:0>2x}".format(element.getSm())
+            else:
+                data += "ff"
+            #  Reference to DC Synch (according to ET1100 documentation) - assume 0
+            data += "00"
+            #  Name Index
+            objname = ""
+            for name in element.getName():
+                objname = name.getcontent()
+            for name in self.Strings:
+                count += 1
+                if objname == name:
+                    break
+            if len(self.Strings)+1 == count:
+                data += "00"
+            else:
+                data += "{:0>2x}".format(count)
+            count = 0
+            #  Flags; by Fixed, Mandatory, Virtual attributes ?
+            if element.getFixed() == True or 1:
+                en_fixed = True
+            if element.getMandatory() == True or 1:
+                en_mandatory = True
+            if element.getVirtual() == True or element.getVirtual():
+                en_virtual = True
+            data += str(int(en_fixed)) + str(int(en_mandatory)) + str(int(en_virtual)) + "0"
+            
+            for entry in element.getEntry():
+                #   Entry Index
+                data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[2:4]
+                data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[0:2]
+                #   Subindex
+                data += "{:0>2x}".format(int(entry.getSubIndex()))
+                #   Entry Name Index
+                objname = ""
+                for name in entry.getName():
+                    objname = name.getcontent()
+                for name in self.Strings:
+                    count += 1
+                    if objname == name:
+                        break
+                if len(self.Strings)+1 == count:
+                    data += "00"
+                else:
+                    data += "{:0>2x}".format(count)
+                count = 0
+                #   DataType
+                if entry.getDataType() is not None:
+                    if entry.getDataType().getcontent() in self.BaseDataTypeDict:
+                        data += self.BaseDataTypeDict[entry.getDataType().getcontent()]
+                    else:
+                        data += "00"
+                else:
+                    data += "00"
+                #   BitLen
+                if entry.getBitLen() is not None:
+                    data += "{:0>2x}".format(int(entry.getBitLen()))
+                else:
+                    data += "00"
+                #   Flags; by Fixed attributes ?
+                en_fixed = False
+                if entry.getFixed() == True or entry.getFixed() == 1:
+                    en_fixed = True
+                data += str(int(en_fixed)) + "000"
+        
+        if data is not "":
+            #  category header
+            if pdotype == "TxPdo":
+                eeprom.append("32")
+            elif pdotype == "RxPdo":
+                eeprom.append("33")
+            else:
+                eeprom.append("00")
+            eeprom.append("00")
+            #  category length 
+            eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
+            eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
+            data = str(data.lower())
+            for i in range(len(data)/2):
+                if data == "":
+                    eeprom.append("00")
+                else:
+                    eeprom.append(data[0:2])
+                data = data[2:len(data)]
+        
+        return eeprom
+    
+    def ExtractEEPROMDCCategory(self, device):
+        """
+        Extract "DC(Distributed Clock)" category data from slave ESI XML and generate EEPROM image data.
+        @param device : 'device' object in the slave ESI XML
+        @return eeprom : "Strings" category EEPROM image data
+        """ 
+        eeprom = []
+        data = ""
+        count = 0
+        namecount = 0
+        
+        if device.getDc() is not None:
+            for element in device.getDc().getOpMode():
+                count += 1
+                #  assume that word 1-7 are 0x0000
+                data += "0000"
+                data += "0000"
+                data += "0000"
+                data += "0000"
+                data += "0000"
+                data += "0000"
+                data += "0000"
+                #  word 8-10
+                #  AssignActivate
+                if element.getAssignActivate() is not None:
+                    data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[2:4]
+                    data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[0:2]
+                else:
+                    data += "0000"
+                #  Factor of CycleTimeSync0 ? and default is 1?
+                if element.getCycleTimeSync0() is not None:
+                    if element.getCycleTimeSync0().getFactor() is not None:
+                        data += "{:0>2x}".format(int(element.getCycleTimeSync0().getFactor()))
+                        data += "00"
+                    else:
+                        data += "0100"
+                else:
+                    data += "0100"
+                #  Index of Name in STRINGS Category
+                #  Name Index
+                objname = ""
+                for name in element.getName():
+                    objname += name
+                for name in self.Strings:
+                    namecount += 1
+                    if objname == name:
+                        break
+                if len(self.Strings)+1 == namecount:
+                    data += "00"
+                else:
+                    data += "{:0>2x}".format(namecount)
+                namecount = 0
+                data += "00"
+                #  assume that word 11-12 are 0x0000
+                data += "0000"
+                data += "0000"
+                
+        if data is not "":
+            #  category header
+            eeprom.append("3c")
+            eeprom.append("00")
+            #  category length 
+            eeprom.append("{:0>4x}".format(len(data)/4)[2:4])
+            eeprom.append("{:0>4x}".format(len(data)/4)[0:2])
+            data = str(data.lower())
+            for i in range(len(data)/2):
+                if data == "":
+                    eeprom.append("00")
+                else:
+                    eeprom.append(data[0:2])
+                data = data[2:len(data)]
+    
+        return eeprom
+    
+    #-------------------------------------------------------------------------------
+    #                        Used Register Access
+    #-------------------------------------------------------------------------------
+    def RegRead(self, offset, length):
+        """
+        Read slave ESC register content using "ethercat reg_read -p %d %s %s" command.
+        Command example : "ethercat reg_read -p 0 0x0c00 0x0400"
+        @param offset : register address
+        @param length : register length
+        @return return_val : register data
+        """ 
+        error, return_val = self.Controler.RemoteExec(REG_READ%(self.Controler.GetSlavePos(), offset, length), return_val = None)
+        return return_val   
+    
+    def RegWrite(self, address, data):
+        """
+        Write data to slave ESC register using "ethercat reg_write -p %d %s %s" command.
+        Command example : "ethercat reg_write -p 0 0x0c04 0x0001"
+        @param address : register address
+        @param data : data to write
+        @return return_val : the execution result of "ethercat reg_write" (for error check)
+        """ 
+        error, return_val = self.Controler.RemoteExec(REG_WRITE%(self.Controler.GetSlavePos(), address, data), return_val = None)
+        return return_val 
+    
+    def Rescan(self):
+        """
+        Synchronize EEPROM data in master controller with the data in slave device after EEPROM write.
+        Command example : "ethercat rescan -p 0"
+        """ 
+        error, return_val = self.Controler.RemoteExec(RESCAN%(self.Controler.GetSlavePos()), return_val = None)
+    
+    #-------------------------------------------------------------------------------
+    #                        Common Use Methods
+    #-------------------------------------------------------------------------------
+    def CheckConnect(self, cyclic_flag):
+        """
+        Check connection status (1) between Beremiz and the master (2) between the master and the slave. 
+        @param cyclic_flag: 0 - one shot, 1 - periodic
+        @return True or False
+        """ 
+        if self.Controler.GetCTRoot()._connector is not None:
+            # Check connection between the master and the slave. 
+            # Command example : "ethercat xml -p 0"
+            error, return_val = self.Controler.RemoteExec(SLAVE_XML%(self.Controler.GetSlavePos()), return_val = None)
+            number_of_lines = return_val.split("\n")
+            if len(number_of_lines) <= 2 :  # No slave connected to the master controller
+                if not cyclic_flag :
+                    self.CreateErrorDialog('No connected slaves')
+                return False
+        
+            elif len(number_of_lines) > 2 :
+                return True
+        else:                               
+            # The master controller is not connected to Beremiz host
+            if not cyclic_flag :
+                self.CreateErrorDialog('PLC not connected!')
+            return False
+        
+    def CreateErrorDialog(self, mention):
+        """
+        Create a dialog to indicate error or warning.
+        @param mention : Error String
+        """ 
+        app_frame = self.Controler.GetCTRoot().AppFrame
+        dlg = wx.MessageDialog (app_frame, mention, 
+                                ' Warning...', 
+                                wx.OK | wx.ICON_INFORMATION)
+        dlg.ShowModal()
+        dlg.Destroy()             
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/ConfigEditor.py	Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,1404 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz
+#
+# Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT
+#                          RTES Lab : CRKim, JBLee, youcu
+#                          Higen Motor : Donggu Kang
+#
+# See COPYING file for copyrights details.
+
+import os
+import re
+from types import TupleType
+
+import wx
+import wx.grid
+import wx.gizmos
+import wx.lib.buttons
+
+from plcopen.structures import IEC_KEYWORDS, TestIdentifier
+from controls import CustomGrid, CustomTable, FolderTree
+from editors.ConfTreeNodeEditor import ConfTreeNodeEditor, SCROLLBAR_UNIT
+from util.BitmapLibrary import GetBitmap
+from controls.CustomStyledTextCtrl import NAVIGATION_KEYS
+
+# -----------------------------------------------------------------------
+from EtherCATManagementEditor import EtherCATManagementTreebook, MasterStatePanelClass
+# -----------------------------------------------------------------------
+
+[ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE] = range(3)
+
+def AppendMenu(parent, help, id, kind, text):
+    if wx.VERSION >= (2, 6, 0):
+        parent.Append(help=help, id=id, kind=kind, text=text)
+    else:
+        parent.Append(helpString=help, id=id, kind=kind, item=text)
+
+def GetVariablesTableColnames(position=False):
+    _ = lambda x : x
+    colname = ["#"]
+    if position:
+        colname.append(_("Position"))
+    return colname + [_("Name"), _("Index"), _("SubIndex"), _("Type"), _("Access")]
+
+ACCESS_TYPES = {
+    'ro': 'R',
+    'wo': 'W',
+    'rw': 'R/W'}
+
+def GetAccessValue(access, pdo_mapping):
+    value = "SDO: %s" % ACCESS_TYPES.get(access, "")
+    if pdo_mapping != "":
+        value += ", PDO: %s" % pdo_mapping
+    return value
+
+VARIABLES_FILTERS = [
+    (_("All"), (0x0000, 0xffff)),
+    (_("Communication Parameters"), (0x1000, 0x1fff)),
+    (_("Manufacturer Specific"), (0x2000, 0x5fff)),
+    (_("Standardized Device Profile"), (0x6000, 0x9fff))]
+
+VARIABLE_INDEX_FILTER_FORMAT = _("Variable Index: #x%4.4X")
+
+ETHERCAT_INDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,4})$")
+ETHERCAT_SUBINDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,2})$")
+LOCATION_MODEL = re.compile("(?:%[IQM](?:[XBWLD]?([0-9]+(?:\.[0-9]+)*)))$")
+
+class NodeVariablesSizer(wx.FlexGridSizer):
+    
+    def __init__(self, parent, controler, position_column=False):
+        wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=2, vgap=5)
+        self.AddGrowableCol(0)
+        self.AddGrowableRow(1)
+        
+        self.Controler = controler
+        self.PositionColumn = position_column
+        
+        self.VariablesFilter = wx.ComboBox(parent, style=wx.TE_PROCESS_ENTER)
+        self.VariablesFilter.Bind(wx.EVT_COMBOBOX, self.OnVariablesFilterChanged)
+        self.VariablesFilter.Bind(wx.EVT_TEXT_ENTER, self.OnVariablesFilterChanged)
+        self.VariablesFilter.Bind(wx.EVT_CHAR, self.OnVariablesFilterKeyDown)
+        self.AddWindow(self.VariablesFilter, flag=wx.GROW)
+        
+        self.VariablesGrid = wx.gizmos.TreeListCtrl(parent, 
+                style=wx.TR_DEFAULT_STYLE |
+                      wx.TR_ROW_LINES |
+                      wx.TR_COLUMN_LINES |
+                      wx.TR_HIDE_ROOT |
+                      wx.TR_FULL_ROW_HIGHLIGHT)
+        self.VariablesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN,
+            self.OnVariablesGridLeftClick)
+        self.AddWindow(self.VariablesGrid, flag=wx.GROW)
+        
+        self.Filters = []
+        for desc, value in VARIABLES_FILTERS:
+            self.VariablesFilter.Append(desc)
+            self.Filters.append(value)
+        
+        self.VariablesFilter.SetSelection(0)
+        self.CurrentFilter = self.Filters[0]
+        self.VariablesFilterFirstCharacter = True
+        
+        if position_column:
+            for colname, colsize, colalign in zip(GetVariablesTableColnames(position_column),
+                                                  [40, 80, 350, 80, 100, 80, 150],
+                                                  [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, 
+                                                   wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, 
+                                                   wx.ALIGN_LEFT]):
+                self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
+            self.VariablesGrid.SetMainColumn(2)
+        else:
+            for colname, colsize, colalign in zip(GetVariablesTableColnames(),
+                                                  [40, 350, 80, 100, 80, 150],
+                                                  [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, 
+                                                   wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]):
+                self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
+            self.VariablesGrid.SetMainColumn(1)
+    
+    def RefreshView(self):
+        entries = self.Controler.GetSlaveVariables(self.CurrentFilter)
+        self.RefreshVariablesGrid(entries)
+    
+    def RefreshVariablesGrid(self, entries):
+        root = self.VariablesGrid.GetRootItem()
+        if not root.IsOk():
+            root = self.VariablesGrid.AddRoot(_("Slave entries"))
+        self.GenerateVariablesGridBranch(root, entries, GetVariablesTableColnames(self.PositionColumn))
+        self.VariablesGrid.Expand(root)
+        
+    def GenerateVariablesGridBranch(self, root, entries, colnames, idx=0):
+        item, root_cookie = self.VariablesGrid.GetFirstChild(root)
+        
+        no_more_items = not item.IsOk()
+        for entry in entries:
+            idx += 1
+            if no_more_items:
+                item = self.VariablesGrid.AppendItem(root, "")
+            for col, colname in enumerate(colnames):
+                if col == 0:
+                    self.VariablesGrid.SetItemText(item, str(idx), 0)
+                else:
+                    value = entry.get(colname, "")
+                    if colname == "Access":
+                        value = GetAccessValue(value, entry.get("PDOMapping", ""))
+                    self.VariablesGrid.SetItemText(item, value, col)
+            if entry["PDOMapping"] == "":
+                self.VariablesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY)
+            else:
+                self.VariablesGrid.SetItemBackgroundColour(item, wx.WHITE)
+            self.VariablesGrid.SetItemPyData(item, entry)
+            idx = self.GenerateVariablesGridBranch(item, entry["children"], colnames, idx)
+            if not no_more_items:
+                item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
+                no_more_items = not item.IsOk()
+        
+        if not no_more_items:
+            to_delete = []
+            while item.IsOk():
+                to_delete.append(item)
+                item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
+            for item in to_delete:
+                self.VariablesGrid.Delete(item)
+        
+        return idx
+    
+    def OnVariablesFilterChanged(self, event):
+        filter = self.VariablesFilter.GetSelection()
+        if filter != -1:
+            self.CurrentFilter = self.Filters[filter]
+            self.RefreshView()
+        else:
+            try:
+                value = self.VariablesFilter.GetValue()
+                if value == "":
+                    self.CurrentFilter = self.Filters[0]
+                    self.VariablesFilter.SetSelection(0)
+                else:
+                    result = ETHERCAT_INDEX_MODEL.match(value)
+                    if result is not None:
+                        value = result.group(1)
+                    index = int(value, 16)
+                    self.CurrentFilter = (index, index)
+                    self.VariablesFilter.SetValue(VARIABLE_INDEX_FILTER_FORMAT % index)
+                self.RefreshView()
+            except:
+                if self.CurrentFilter in self.Filters:
+                    self.VariablesFilter.SetSelection(self.Filters.index(self.CurrentFilter))
+                else:
+                    self.VariablesFilter.SetValue(VARIABLE_INDEX_FILTER_FORMAT % self.CurrentFilter[0])
+        self.VariablesFilterFirstCharacter = True
+        event.Skip()
+    
+    def OnVariablesFilterKeyDown(self, event):
+        if self.VariablesFilterFirstCharacter:
+            keycode = event.GetKeyCode()
+            if keycode not in [wx.WXK_RETURN, 
+                               wx.WXK_NUMPAD_ENTER]:
+                self.VariablesFilterFirstCharacter = False
+                if keycode not in NAVIGATION_KEYS:
+                    self.VariablesFilter.SetValue("")
+            if keycode not in [wx.WXK_DELETE, 
+                               wx.WXK_NUMPAD_DELETE, 
+                               wx.WXK_BACK]:
+                event.Skip()
+        else:
+            event.Skip()
+    
+    def OnVariablesGridLeftClick(self, event):
+        item, flags, col = self.VariablesGrid.HitTest(event.GetPosition())
+        if item.IsOk():
+            entry = self.VariablesGrid.GetItemPyData(item)
+            data_type = entry.get("Type", "")
+            data_size = self.Controler.GetSizeOfType(data_type)
+            
+            if col == -1 and data_size is not None:
+                pdo_mapping = entry.get("PDOMapping", "")
+                access = entry.get("Access", "")
+                entry_index = self.Controler.ExtractHexDecValue(entry.get("Index", "0"))
+                entry_subindex = self.Controler.ExtractHexDecValue(entry.get("SubIndex", "0"))
+                location = self.Controler.GetCurrentLocation()
+                if self.PositionColumn:
+                    slave_pos = self.Controler.ExtractHexDecValue(entry.get("Position", "0"))
+                    location += (slave_pos,)
+                    node_name = self.Controler.GetSlaveName(slave_pos)
+                else:
+                    node_name = self.Controler.CTNName()
+                
+                if pdo_mapping != "":
+                    var_name = "%s_%4.4x_%2.2x" % (node_name, entry_index, entry_subindex)
+                    if pdo_mapping == "T":
+                        dir = "%I"
+                    else:
+                        dir = "%Q"
+                    location = "%s%s" % (dir, data_size) + \
+                               ".".join(map(lambda x:str(x), location + (entry_index, entry_subindex)))
+                    
+                    data = wx.TextDataObject(str((location, "location", data_type, var_name, "", access)))
+                    dragSource = wx.DropSource(self.VariablesGrid)
+                    dragSource.SetData(data)
+                    dragSource.DoDragDrop()
+                    return
+                
+                elif self.PositionColumn:
+                    location = self.Controler.GetCurrentLocation() +\
+                               (slave_pos, entry_index, entry_subindex)
+                    data = wx.TextDataObject(str((location, "variable", access)))
+                    dragSource = wx.DropSource(self.VariablesGrid)
+                    dragSource.SetData(data)
+                    dragSource.DoDragDrop()
+                    return
+        
+        event.Skip()
+
+class NodeEditor(ConfTreeNodeEditor):
+    
+    CONFNODEEDITOR_TABS = [
+        (_("Ethercat node"), "_create_EthercatNodeEditor"),
+        # Add Notebook Tab for EtherCAT Management Treebook
+        (_("EtherCAT Management"), "_create_EtherCATManagementEditor")
+        ]
+    
+    def _create_EthercatNodeEditor(self, prnt):
+        self.EthercatNodeEditor = wx.Panel(prnt, style=wx.TAB_TRAVERSAL)
+        
+        main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+        main_sizer.AddGrowableCol(0)
+        main_sizer.AddGrowableRow(1)
+        
+        variables_label = wx.StaticText(self.EthercatNodeEditor,
+              label=_('Variable entries:'))
+        main_sizer.AddWindow(variables_label, border=10, flag=wx.TOP|wx.LEFT|wx.RIGHT)
+        
+        self.NodeVariables = NodeVariablesSizer(self.EthercatNodeEditor, self.Controler)
+        main_sizer.AddSizer(self.NodeVariables, border=10, 
+            flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+                
+        self.EthercatNodeEditor.SetSizer(main_sizer)
+
+        return self.EthercatNodeEditor
+    
+    def __init__(self, parent, controler, window):
+        ConfTreeNodeEditor.__init__(self, parent, controler, window)
+        
+        # add Contoler for use EthercatSlave.py Method
+        self.Controler = controler
+        
+    def GetBufferState(self):
+        return False, False
+        
+    def RefreshView(self):
+        ConfTreeNodeEditor.RefreshView(self)
+    
+        self.NodeVariables.RefreshView()
+
+    # -------------------For EtherCAT Management ----------------------------------------------    
+    def _create_EtherCATManagementEditor(self, prnt):
+        self.EtherCATManagementEditor = wx.ScrolledWindow(prnt,
+            style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
+        self.EtherCATManagementEditor.Bind(wx.EVT_SIZE, self.OnResize)
+
+        self.EtherCATManagermentEditor_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+        self.EtherCATManagermentEditor_Main_Sizer.AddGrowableCol(0)
+        self.EtherCATManagermentEditor_Main_Sizer.AddGrowableRow(0)
+        
+        self.EtherCATManagementTreebook = EtherCATManagementTreebook(self.EtherCATManagementEditor, self.Controler, self)
+          
+        self.EtherCATManagermentEditor_Main_Sizer.AddSizer(self.EtherCATManagementTreebook, border=10, flag=wx.GROW)
+
+        self.EtherCATManagementEditor.SetSizer(self.EtherCATManagermentEditor_Main_Sizer)
+        return self.EtherCATManagementEditor
+    
+    def OnResize(self, event):
+        self.EtherCATManagementEditor.GetBestSize()
+        xstart, ystart = self.EtherCATManagementEditor.GetViewStart()
+        window_size = self.EtherCATManagementEditor.GetClientSize()
+        maxx, maxy = self.EtherCATManagementEditor.GetMinSize()
+        posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
+        posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
+        self.EtherCATManagementEditor.Scroll(posx, posy)
+        self.EtherCATManagementEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
+                maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
+        event.Skip()
+    # -------------------------------------------------------------------------------------------------------
+
+CIA402NodeEditor = NodeEditor
+
+
+def GetProcessVariablesTableColnames():
+    _ = lambda x : x
+    return ["#", _("Name"), 
+            _("Read from (nodeid, index, subindex)"), 
+            _("Write to (nodeid, index, subindex)"),
+            _("Description")]
+
+class ProcessVariablesTable(CustomTable):
+    
+    def GetValue(self, row, col):
+        if row < self.GetNumberRows():
+            if col == 0:
+                return row + 1
+            colname = self.GetColLabelValue(col, False)
+            if colname.startswith("Read from"):
+                value = self.data[row].get("ReadFrom", "")
+                if value == "":
+                    return value
+                return "%d, #x%0.4X, #x%0.2X" % value
+            elif colname.startswith("Write to"):
+                value = self.data[row].get("WriteTo", "")
+                if value == "":
+                    return value
+                return "%d, #x%0.4X, #x%0.2X" % value
+            return self.data[row].get(colname, "")
+    
+    def SetValue(self, row, col, value):
+        if col < len(self.colnames):
+            colname = self.GetColLabelValue(col, False)
+            if colname.startswith("Read from"):
+                self.data[row]["ReadFrom"] = value
+            elif colname.startswith("Write to"):
+                self.data[row]["WriteTo"] = value
+            else:
+                self.data[row][colname] = value
+    
+    def _updateColAttrs(self, grid):
+        """
+        wx.grid.Grid -> update the column attributes to add the
+        appropriate renderer given the column name.
+
+        Otherwise default to the default renderer.
+        """
+        for row in range(self.GetNumberRows()):
+            for col in range(self.GetNumberCols()):
+                editor = None
+                renderer = None
+                colname = self.GetColLabelValue(col, False)
+                if colname in ["Name", "Description"]:
+                    editor = wx.grid.GridCellTextEditor()
+                    renderer = wx.grid.GridCellStringRenderer()
+                    grid.SetReadOnly(row, col, False)
+                else:
+                    grid.SetReadOnly(row, col, True)
+                
+                grid.SetCellEditor(row, col, editor)
+                grid.SetCellRenderer(row, col, renderer)
+                
+            self.ResizeRow(grid, row)
+
+class ProcessVariableDropTarget(wx.TextDropTarget):
+    
+    def __init__(self, parent):
+        wx.TextDropTarget.__init__(self)
+        self.ParentWindow = parent
+    
+    def OnDropText(self, x, y, data):
+        self.ParentWindow.Select()
+        x, y = self.ParentWindow.ProcessVariablesGrid.CalcUnscrolledPosition(x, y)
+        col = self.ParentWindow.ProcessVariablesGrid.XToCol(x)
+        row = self.ParentWindow.ProcessVariablesGrid.YToRow(y - self.ParentWindow.ProcessVariablesGrid.GetColLabelSize())
+        message = None
+        try:
+            values = eval(data)
+        except:
+            message = _("Invalid value \"%s\" for process variable")%data
+            values = None
+        if not isinstance(values, TupleType):
+            message = _("Invalid value \"%s\" for process variable")%data
+            values = None
+        if values is not None and col != wx.NOT_FOUND and row != wx.NOT_FOUND and 2 <= col <= 3:
+            location = None
+            if values[1] == "location":
+                result = LOCATION_MODEL.match(values[0])
+                if result is not None:
+                    location = map(int, result.group(1).split('.'))
+                master_location = self.ParentWindow.GetMasterLocation()
+                if (master_location == tuple(location[:len(master_location)]) and 
+                    len(location) - len(master_location) == 3):
+                    values = tuple(location[len(master_location):])
+                    var_type = self.ParentWindow.Controler.GetSlaveVariableDataType(*values)
+                    if col == 2:
+                        other_values = self.ParentWindow.ProcessVariablesTable.GetValueByName(row, "WriteTo")
+                    else:
+                        other_values = self.ParentWindow.ProcessVariablesTable.GetValueByName(row, "ReadFrom")
+                    if other_values != "":
+                        other_type = self.ParentWindow.Controler.GetSlaveVariableDataType(*other_values)
+                    else:
+                        other_type = None
+                    if other_type is None or var_type == other_type:
+                        if col == 2:
+                            self.ParentWindow.ProcessVariablesTable.SetValueByName(row, "ReadFrom", values)
+                        else:
+                            self.ParentWindow.ProcessVariablesTable.SetValueByName(row, "WriteTo", values)
+                        self.ParentWindow.SaveProcessVariables()
+                        self.ParentWindow.RefreshProcessVariables()
+                    else:
+                        message = _("'Read from' and 'Write to' variables types are not compatible")
+                else:
+                    message = _("Invalid value \"%s\" for process variable")%data
+                    
+        if message is not None:
+            wx.CallAfter(self.ShowMessage, message)
+    
+    def ShowMessage(self, message):
+        message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
+        message.ShowModal()
+        message.Destroy()
+
+def GetStartupCommandsTableColnames():
+    _ = lambda x : x
+    return [_("Position"), _("Index"), _("Subindex"), _("Value"), _("Description")]
+
+class StartupCommandDropTarget(wx.TextDropTarget):
+    
+    def __init__(self, parent):
+        wx.TextDropTarget.__init__(self)
+        self.ParentWindow = parent
+    
+    def OnDropText(self, x, y, data):
+        self.ParentWindow.Select()
+        message = None
+        try:
+            values = eval(data)
+        except:
+            message = _("Invalid value \"%s\" for startup command")%data
+            values = None
+        if not isinstance(values, TupleType):
+            message = _("Invalid value \"%s\" for startup command")%data
+            values = None
+        if values is not None:
+            location = None
+            if values[1] == "location":
+                result = LOCATION_MODEL.match(values[0])
+                if result is not None and len(values) > 5:
+                    location = map(int, result.group(1).split('.'))
+                    access = values[5]
+            elif values[1] == "variable":
+                location = values[0]
+                access = values[2]
+            if location is not None:
+                master_location = self.ParentWindow.GetMasterLocation()
+                if (master_location == tuple(location[:len(master_location)]) and 
+                    len(location) - len(master_location) == 3):
+                    if access in ["wo", "rw"]:
+                        self.ParentWindow.AddStartupCommand(*location[len(master_location):])
+                    else:
+                        message = _("Entry can't be write through SDO")
+                else:
+                    message = _("Invalid value \"%s\" for startup command")%data
+                    
+        if message is not None:
+            wx.CallAfter(self.ShowMessage, message)
+    
+    def ShowMessage(self, message):
+        message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
+        message.ShowModal()
+        message.Destroy()
+
+class StartupCommandsTable(CustomTable):
+
+    """
+    A custom wx.grid.Grid Table using user supplied data
+    """
+    def __init__(self, parent, data, colnames):
+        # The base class must be initialized *first*
+        CustomTable.__init__(self, parent, data, colnames)
+        self.old_value = None
+
+    def GetValue(self, row, col):
+        if row < self.GetNumberRows():
+            colname = self.GetColLabelValue(col, False)
+            value = self.data[row].get(colname, "")
+            if colname == "Index":
+                return "#x%0.4X" % value
+            elif colname == "Subindex":
+                return "#x%0.2X" % value
+            return value
+    
+    def SetValue(self, row, col, value):
+        if col < len(self.colnames):
+            colname = self.GetColLabelValue(col, False)
+            if colname in ["Index", "Subindex"]:
+                if colname == "Index":
+                    result = ETHERCAT_INDEX_MODEL.match(value)
+                else:
+                    result = ETHERCAT_SUBINDEX_MODEL.match(value)
+                if result is None:
+                    return
+                value = int(result.group(1), 16)
+            elif colname == "Value":
+                value = int(value)
+            elif colname == "Position":
+                self.old_value = self.data[row][colname]
+                value = int(value)
+            self.data[row][colname] = value
+    
+    def GetOldValue(self):
+        return self.old_value
+    
+    def _updateColAttrs(self, grid):
+        """
+        wx.grid.Grid -> update the column attributes to add the
+        appropriate renderer given the column name.
+
+        Otherwise default to the default renderer.
+        """
+        for row in range(self.GetNumberRows()):
+            for col in range(self.GetNumberCols()):
+                editor = None
+                renderer = None
+                colname = self.GetColLabelValue(col, False)
+                if colname in ["Position", "Value"]:
+                    editor = wx.grid.GridCellNumberEditor()
+                    renderer = wx.grid.GridCellNumberRenderer()
+                else:
+                    editor = wx.grid.GridCellTextEditor()
+                    renderer = wx.grid.GridCellStringRenderer()
+                
+                grid.SetCellEditor(row, col, editor)
+                grid.SetCellRenderer(row, col, renderer)
+                grid.SetReadOnly(row, col, False)
+                
+            self.ResizeRow(grid, row)
+    
+    def GetCommandIndex(self, position, command_idx):
+        for row, command in enumerate(self.data):
+            if command["Position"] == position and command["command_idx"] == command_idx:
+                return row
+        return None
+
+class MasterNodesVariablesSizer(NodeVariablesSizer):
+    
+    def __init__(self, parent, controler):
+        NodeVariablesSizer.__init__(self, parent, controler, True)
+        
+        self.CurrentNodesFilter = {}
+    
+    def SetCurrentNodesFilter(self, nodes_filter):
+        self.CurrentNodesFilter = nodes_filter
+        
+    def RefreshView(self):
+        if self.CurrentNodesFilter is not None:
+            args = self.CurrentNodesFilter.copy()
+            args["limits"] = self.CurrentFilter
+            entries = self.Controler.GetNodesVariables(**args)
+            self.RefreshVariablesGrid(entries)
+
+NODE_POSITION_FILTER_FORMAT = _("Node Position: %d")
+
+class MasterEditor(ConfTreeNodeEditor):
+    
+    CONFNODEEDITOR_TABS = [
+        (_("Network"), "_create_EthercatMasterEditor"),
+        (_("Master State"), "_create_MasterStateEditor")
+        ]
+    
+    def _create_MasterStateEditor(self, prnt):
+        self.MasterStateEditor = wx.ScrolledWindow(prnt, style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
+        self.MasterStateEditor.Bind(wx.EVT_SIZE, self.OnResize)
+        
+        self.MasterStateEditor_Panel_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+        self.MasterStateEditor_Panel_Main_Sizer.AddGrowableCol(0)
+        self.MasterStateEditor_Panel_Main_Sizer.AddGrowableRow(0)
+        
+        self.MasterStateEditor_Panel = MasterStatePanelClass(self.MasterStateEditor, self.Controler)
+        
+        self.MasterStateEditor_Panel_Main_Sizer.AddSizer(self.MasterStateEditor_Panel, border=10, flag=wx.GROW)
+         
+        self.MasterStateEditor.SetSizer(self.MasterStateEditor_Panel_Main_Sizer)
+        return self.MasterStateEditor
+    
+    def OnResize(self, event):
+        self.MasterStateEditor.GetBestSize()
+        xstart, ystart = self.MasterStateEditor.GetViewStart()
+        window_size = self.MasterStateEditor.GetClientSize()
+        maxx, maxy = self.MasterStateEditor.GetMinSize()
+        posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
+        posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
+        self.MasterStateEditor.Scroll(posx, posy)
+        self.MasterStateEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
+                maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
+        event.Skip()
+    
+    def _create_EthercatMasterEditor(self, prnt):
+        self.EthercatMasterEditor = wx.ScrolledWindow(prnt, 
+            style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
+        self.EthercatMasterEditor.Bind(wx.EVT_SIZE, self.OnResize)
+        
+        self.EthercatMasterEditorSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        self.NodesFilter = wx.ComboBox(self.EthercatMasterEditor,
+            style=wx.TE_PROCESS_ENTER)
+        self.Bind(wx.EVT_COMBOBOX, self.OnNodesFilterChanged, self.NodesFilter)
+        self.Bind(wx.EVT_TEXT_ENTER, self.OnNodesFilterChanged, self.NodesFilter)
+        self.NodesFilter.Bind(wx.EVT_CHAR, self.OnNodesFilterKeyDown)
+        
+        process_variables_header = wx.BoxSizer(wx.HORIZONTAL)
+        
+        process_variables_label = wx.StaticText(self.EthercatMasterEditor,
+              label=_("Process variables mapped between nodes:"))
+        process_variables_header.AddWindow(process_variables_label, 1,
+              flag=wx.ALIGN_CENTER_VERTICAL)
+        
+        for name, bitmap, help in [
+                ("AddVariableButton", "add_element", _("Add process variable")),
+                ("DeleteVariableButton", "remove_element", _("Remove process variable")),
+                ("UpVariableButton", "up", _("Move process variable up")),
+                ("DownVariableButton", "down", _("Move process variable down"))]:
+            button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), 
+                  size=wx.Size(28, 28), style=wx.NO_BORDER)
+            button.SetToolTipString(help)
+            setattr(self, name, button)
+            process_variables_header.AddWindow(button, border=5, flag=wx.LEFT)
+        
+        self.ProcessVariablesGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
+        self.ProcessVariablesGrid.SetMinSize(wx.Size(0, 150))
+        self.ProcessVariablesGrid.SetDropTarget(ProcessVariableDropTarget(self))
+        self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, 
+              self.OnProcessVariablesGridCellChange)
+        self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, 
+              self.OnProcessVariablesGridCellLeftClick)
+        self.ProcessVariablesGrid.Bind(wx.EVT_KEY_DOWN, self.OnProcessVariablesGridKeyDown)
+        
+        startup_commands_header = wx.BoxSizer(wx.HORIZONTAL)
+        
+        startup_commands_label = wx.StaticText(self.EthercatMasterEditor,
+              label=_("Startup service variables assignments:"))
+        startup_commands_header.AddWindow(startup_commands_label, 1,
+              flag=wx.ALIGN_CENTER_VERTICAL)
+        
+        for name, bitmap, help in [
+                ("AddCommandButton", "add_element", _("Add startup service variable")),
+                ("DeleteCommandButton", "remove_element", _("Remove startup service variable"))]:
+            button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), 
+                  size=wx.Size(28, 28), style=wx.NO_BORDER)
+            button.SetToolTipString(help)
+            setattr(self, name, button)
+            startup_commands_header.AddWindow(button, border=5, flag=wx.LEFT)
+        
+        self.StartupCommandsGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
+        self.StartupCommandsGrid.SetDropTarget(StartupCommandDropTarget(self))
+        self.StartupCommandsGrid.SetMinSize(wx.Size(0, 150))
+        self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, 
+              self.OnStartupCommandsGridCellChange)
+        self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, 
+              self.OnStartupCommandsGridEditorShow)
+        
+        self.NodesVariables = MasterNodesVariablesSizer(self.EthercatMasterEditor, self.Controler)
+        
+        main_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Node filter:"))
+        staticbox_sizer = wx.StaticBoxSizer(main_staticbox, wx.VERTICAL)
+        self.EthercatMasterEditorSizer.AddSizer(staticbox_sizer, 0, border=10, flag=wx.GROW|wx.ALL)
+        
+        main_staticbox_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=6, vgap=0)
+        main_staticbox_sizer.AddGrowableCol(0)
+        main_staticbox_sizer.AddGrowableRow(2)
+        main_staticbox_sizer.AddGrowableRow(4)
+        main_staticbox_sizer.AddGrowableRow(5)
+        staticbox_sizer.AddSizer(main_staticbox_sizer, 1, flag=wx.GROW)
+        main_staticbox_sizer.AddWindow(self.NodesFilter, border=5, flag=wx.GROW|wx.ALL)
+        main_staticbox_sizer.AddSizer(process_variables_header, border=5, 
+              flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+        main_staticbox_sizer.AddWindow(self.ProcessVariablesGrid, 1, 
+              border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+        main_staticbox_sizer.AddSizer(startup_commands_header, 
+              border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+        main_staticbox_sizer.AddWindow(self.StartupCommandsGrid, 1, 
+              border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+        
+        second_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Nodes variables filter:"))
+        second_staticbox_sizer = wx.StaticBoxSizer(second_staticbox, wx.VERTICAL)
+        second_staticbox_sizer.AddSizer(self.NodesVariables, 1, border=5, flag=wx.GROW|wx.ALL)
+        
+        main_staticbox_sizer.AddSizer(second_staticbox_sizer, 1, 
+            border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+        
+        self.EthercatMasterEditor.SetSizer(self.EthercatMasterEditorSizer)
+        
+        return self.EthercatMasterEditor
+
+    def __init__(self, parent, controler, window):
+        ConfTreeNodeEditor.__init__(self, parent, controler, window)
+        
+        # ------------------------------------------------------------------
+        self.Controler = controler
+        # ------------------------------------------------------------------
+        
+        self.ProcessVariables = []
+        self.CellShown = None
+        self.NodesFilterFirstCharacter = True
+        
+        self.ProcessVariablesDefaultValue = {"Name": "", "ReadFrom": "", "WriteTo": "", "Description": ""}
+        self.ProcessVariablesTable = ProcessVariablesTable(self, [], GetProcessVariablesTableColnames())
+        self.ProcessVariablesColSizes = [40, 100, 150, 150, 200]
+        self.ProcessVariablesColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
+        
+        self.ProcessVariablesGrid.SetTable(self.ProcessVariablesTable)
+        self.ProcessVariablesGrid.SetButtons({"Add": self.AddVariableButton,
+                                              "Delete": self.DeleteVariableButton,
+                                              "Up": self.UpVariableButton,
+                                              "Down": self.DownVariableButton})
+        
+        def _AddVariablesElement(new_row):
+            self.ProcessVariablesTable.InsertRow(new_row, self.ProcessVariablesDefaultValue.copy())
+            self.SaveProcessVariables()
+            self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
+            return new_row
+        setattr(self.ProcessVariablesGrid, "_AddRow", _AddVariablesElement)
+        
+        def _DeleteVariablesElement(row):
+            self.ProcessVariablesTable.RemoveRow(row)
+            self.SaveProcessVariables()
+            self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
+        setattr(self.ProcessVariablesGrid, "_DeleteRow", _DeleteVariablesElement)
+            
+        def _MoveVariablesElement(row, move):
+            new_row = self.ProcessVariablesTable.MoveRow(row, move)
+            if new_row != row:
+                self.SaveProcessVariables()
+                self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
+            return new_row
+        setattr(self.ProcessVariablesGrid, "_MoveRow", _MoveVariablesElement)
+        
+        _refresh_buttons = getattr(self.ProcessVariablesGrid, "RefreshButtons")
+        def _RefreshButtons():
+            if self.NodesFilter.GetSelection() == 0:
+                _refresh_buttons()
+            else:
+                self.AddVariableButton.Enable(False)
+                self.DeleteVariableButton.Enable(False)
+                self.UpVariableButton.Enable(False)
+                self.DownVariableButton.Enable(False)
+        setattr(self.ProcessVariablesGrid, "RefreshButtons", _RefreshButtons)
+        
+        self.ProcessVariablesGrid.SetRowLabelSize(0)
+        for col in range(self.ProcessVariablesTable.GetNumberCols()):
+            attr = wx.grid.GridCellAttr()
+            attr.SetAlignment(self.ProcessVariablesColAlignements[col], wx.ALIGN_CENTRE)
+            self.ProcessVariablesGrid.SetColAttr(col, attr)
+            self.ProcessVariablesGrid.SetColMinimalWidth(col, self.ProcessVariablesColSizes[col])
+            self.ProcessVariablesGrid.AutoSizeColumn(col, False)
+        self.ProcessVariablesGrid.RefreshButtons()
+    
+        self.StartupCommandsDefaultValue = {"Position": 0, "Index": 0, "Subindex": 0, "Value": 0, "Description": ""}
+        self.StartupCommandsTable = StartupCommandsTable(self, [], GetStartupCommandsTableColnames())
+        self.StartupCommandsColSizes = [100, 100, 50, 100, 200]
+        self.StartupCommandsColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT]
+        
+        self.StartupCommandsGrid.SetTable(self.StartupCommandsTable)
+        self.StartupCommandsGrid.SetButtons({"Add": self.AddCommandButton,
+                                             "Delete": self.DeleteCommandButton})
+        
+        def _AddCommandsElement(new_row):
+            command = self.StartupCommandsDefaultValue.copy()
+            command_idx = self.Controler.AppendStartupCommand(command)
+            self.RefreshStartupCommands()
+            self.RefreshBuffer()
+            return self.StartupCommandsTable.GetCommandIndex(command["Position"], command_idx)
+        setattr(self.StartupCommandsGrid, "_AddRow", _AddCommandsElement)
+        
+        def _DeleteCommandsElement(row):
+            command = self.StartupCommandsTable.GetRow(row)
+            self.Controler.RemoveStartupCommand(command["Position"], command["command_idx"])
+            self.RefreshStartupCommands()
+            self.RefreshBuffer()
+        setattr(self.StartupCommandsGrid, "_DeleteRow", _DeleteCommandsElement)
+        
+        self.StartupCommandsGrid.SetRowLabelSize(0)
+        for col in range(self.StartupCommandsTable.GetNumberCols()):
+            attr = wx.grid.GridCellAttr()
+            attr.SetAlignment(self.StartupCommandsColAlignements[col], wx.ALIGN_CENTRE)
+            self.StartupCommandsGrid.SetColAttr(col, attr)
+            self.StartupCommandsGrid.SetColMinimalWidth(col, self.StartupCommandsColSizes[col])
+            self.StartupCommandsGrid.AutoSizeColumn(col, False)
+        self.StartupCommandsGrid.RefreshButtons()
+    
+    def RefreshBuffer(self):
+        self.ParentWindow.RefreshTitle()
+        self.ParentWindow.RefreshFileMenu()
+        self.ParentWindow.RefreshEditMenu()
+        self.ParentWindow.RefreshPageTitles()
+    
+    def GetBufferState(self):
+        return self.Controler.GetBufferState()
+    
+    def Undo(self):
+        self.Controler.LoadPrevious()
+        self.RefreshView()
+            
+    def Redo(self):
+        self.Controler.LoadNext()
+        self.RefreshView()
+    
+    def RefreshView(self):
+        ConfTreeNodeEditor.RefreshView(self)
+        
+        self.RefreshNodesFilter()
+        self.RefreshProcessVariables()
+        self.RefreshStartupCommands()
+        self.NodesVariables.RefreshView()
+    
+    def RefreshNodesFilter(self):
+        value = self.NodesFilter.GetValue()
+        self.NodesFilter.Clear()
+        self.NodesFilter.Append(_("All"))
+        self.NodesFilterValues = [{}]
+        for vendor_id, vendor_name in self.Controler.GetLibraryVendors():
+            self.NodesFilter.Append(_("%s's nodes") % vendor_name)
+            self.NodesFilterValues.append({"vendor": vendor_id})
+        self.NodesFilter.Append(_("CIA402 nodes"))
+        self.NodesFilterValues.append({"slave_profile": 402})
+        if value in self.NodesFilter.GetStrings():
+            self.NodesFilter.SetStringSelection(value)
+        else:
+            try:
+                int(value)
+                self.NodesFilter.SetValue(value)
+            except:
+                self.NodesFilter.SetSelection(0)
+        self.RefreshCurrentNodesFilter()
+    
+    def RefreshCurrentNodesFilter(self):
+        filter = self.NodesFilter.GetSelection()
+        if filter != -1:
+            self.CurrentNodesFilter = self.NodesFilterValues[filter]
+        else:
+            try:
+                value = self.NodesFilter.GetValue()
+                if value == "":
+                    self.CurrentNodesFilter = self.NodesFilterValues[0]
+                    self.NodesFilter.SetSelection(0)
+                else:
+                    position = int(self.NodesFilter.GetValue())
+                    self.CurrentNodesFilter = {"slave_pos": position}
+                    self.NodesFilter.SetValue(NODE_POSITION_FILTER_FORMAT % position)
+            except:
+                if self.CurrentNodesFilter in self.NodesFilterValues:
+                    self.NodesFilter.SetSelection(self.NodesFilterValues.index(self.CurrentNodesFilter))
+                else:
+                    self.NodesFilter.SetValue(NODE_POSITION_FILTER_FORMAT % self.CurrentNodesFilter["slave_pos"])
+        self.NodesFilterFirstCharacter = True
+        self.NodesVariables.SetCurrentNodesFilter(self.CurrentNodesFilter)
+    
+    def RefreshProcessVariables(self):
+        if self.CurrentNodesFilter is not None:
+            self.ProcessVariables = self.Controler.GetProcessVariables()
+            slaves = self.Controler.GetSlaves(**self.CurrentNodesFilter)
+            data = []
+            for variable in self.ProcessVariables:
+                if (variable["ReadFrom"] == "" or variable["ReadFrom"][0] in slaves or
+                    variable["WriteTo"] == "" or variable["WriteTo"][0] in slaves):
+                    data.append(variable)
+            self.ProcessVariablesTable.SetData(data)
+            self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
+            self.ProcessVariablesGrid.RefreshButtons()
+    
+    def SaveProcessVariables(self):
+        if self.CurrentNodesFilter is not None:
+            if len(self.CurrentNodesFilter) > 0:
+                self.Controler.SetProcessVariables(self.ProcessVariables)
+            else:
+                self.Controler.SetProcessVariables(self.ProcessVariablesTable.GetData())
+            self.RefreshBuffer()
+    
+    def RefreshStartupCommands(self, position=None, command_idx=None):
+        if self.CurrentNodesFilter is not None:
+            col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
+            self.StartupCommandsTable.SetData(
+                self.Controler.GetStartupCommands(**self.CurrentNodesFilter))
+            self.StartupCommandsTable.ResetView(self.StartupCommandsGrid)
+            if position is not None and command_idx is not None:
+                self.SelectStartupCommand(position, command_idx, col)
+    
+    def SelectStartupCommand(self, position, command_idx, col):
+        self.StartupCommandsGrid.SetSelectedCell(
+            self.StartupCommandsTable.GetCommandIndex(position, command_idx),
+            col)
+    
+    def GetMasterLocation(self):
+        return self.Controler.GetCurrentLocation()
+    
+    def AddStartupCommand(self, position, index, subindex):
+        col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
+        command = self.StartupCommandsDefaultValue.copy()
+        command["Position"] = position
+        command["Index"] = index
+        command["Subindex"] = subindex
+        command_idx = self.Controler.AppendStartupCommand(command)
+        self.RefreshStartupCommands()
+        self.RefreshBuffer()
+        self.SelectStartupCommand(position, command_idx, col)
+    
+    def OnNodesFilterChanged(self, event):
+        self.RefreshCurrentNodesFilter()
+        if self.CurrentNodesFilter is not None:
+            self.RefreshProcessVariables()
+            self.RefreshStartupCommands()
+            self.NodesVariables.RefreshView()
+        event.Skip()
+    
+    def OnNodesFilterKeyDown(self, event):
+        if self.NodesFilterFirstCharacter:
+            keycode = event.GetKeyCode()
+            if keycode not in [wx.WXK_RETURN, 
+                               wx.WXK_NUMPAD_ENTER]:
+                self.NodesFilterFirstCharacter = False
+                if keycode not in NAVIGATION_KEYS:
+                    self.NodesFilter.SetValue("")
+            if keycode not in [wx.WXK_DELETE, 
+                               wx.WXK_NUMPAD_DELETE, 
+                               wx.WXK_BACK]:
+                event.Skip()
+        else:
+            event.Skip()
+    
+    def OnProcessVariablesGridCellChange(self, event):
+        row, col = event.GetRow(), event.GetCol()
+        colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
+        value = self.ProcessVariablesTable.GetValue(row, col)
+        message = None
+        if colname == "Name":
+            if not TestIdentifier(value):
+                message = _("\"%s\" is not a valid identifier!") % value
+            elif value.upper() in IEC_KEYWORDS:
+                message = _("\"%s\" is a keyword. It can't be used!") % value
+            elif value.upper() in [var["Name"].upper() for idx, var in enumerate(self.ProcessVariablesTable.GetData()) if idx != row]:
+                message = _("An variable named \"%s\" already exists!") % value
+        if message is None:
+            self.SaveProcessVariables()
+            wx.CallAfter(self.ProcessVariablesTable.ResetView, self.ProcessVariablesGrid)
+            event.Skip()
+        else:
+            dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+            dialog.ShowModal()
+            dialog.Destroy()
+            event.Veto()
+    
+    def OnProcessVariablesGridCellLeftClick(self, event):
+        row = event.GetRow()
+        if event.GetCol() == 0:
+            var_name = self.ProcessVariablesTable.GetValueByName(row, "Name")
+            var_type = self.Controler.GetSlaveVariableDataType(
+                *self.ProcessVariablesTable.GetValueByName(row, "ReadFrom"))
+            data_size = self.Controler.GetSizeOfType(var_type)
+            number = self.ProcessVariablesTable.GetValueByName(row, "Number")
+            location = "%%M%s" % data_size + \
+                       ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + (number,)))
+            
+            data = wx.TextDataObject(str((location, "location", var_type, var_name, "")))
+            dragSource = wx.DropSource(self.ProcessVariablesGrid)
+            dragSource.SetData(data)
+            dragSource.DoDragDrop()
+        event.Skip()
+    
+    def OnProcessVariablesGridKeyDown(self, event):
+        keycode = event.GetKeyCode()
+        col = self.ProcessVariablesGrid.GetGridCursorCol()
+        row = self.ProcessVariablesGrid.GetGridCursorRow()
+        colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
+        if (keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and 
+            (colname.startswith("Read from") or colname.startswith("Write to"))):
+            self.ProcessVariablesTable.SetValue(row, col, "")
+            self.SaveProcessVariables()
+            wx.CallAfter(self.ProcessVariablesTable.ResetView, self.ProcessVariablesGrid)
+        else:
+            event.Skip()
+    
+    def OnStartupCommandsGridEditorShow(self, event):
+        self.CellShown = event.GetRow(), event.GetCol()
+        event.Skip()
+    
+    def OnStartupCommandsGridCellChange(self, event):
+        row, col = event.GetRow(), event.GetCol()
+        if self.CellShown == (row, col):
+            self.CellShown = None
+            colname = self.StartupCommandsTable.GetColLabelValue(col, False)
+            value = self.StartupCommandsTable.GetValue(row, col)
+            message = None
+            if colname == "Position":
+                if value not in self.Controler.GetSlaves():
+                    message = _("No slave defined at position %d!") % value
+                old_value = self.StartupCommandsTable.GetOldValue()
+                command = self.StartupCommandsTable.GetRow(row)
+                if message is None and old_value != command["Position"]:
+                    self.Controler.RemoveStartupCommand(
+                        self.StartupCommandsTable.GetOldValue(),
+                        command["command_idx"], False)
+                    command_idx = self.Controler.AppendStartupCommand(command)
+                    wx.CallAfter(self.RefreshStartupCommands, command["Position"], command_idx)
+            else:
+                command = self.StartupCommandsTable.GetRow(row)
+                self.Controler.SetStartupCommandInfos(command)
+                if colname in ["Index", "SubIndex"]: 
+                    wx.CallAfter(self.RefreshStartupCommands, command["Position"], command["command_idx"])
+            if message is None:
+                self.RefreshBuffer()
+                event.Skip()
+            else:
+                dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+                dialog.ShowModal()
+                dialog.Destroy()
+                event.Veto()
+        else:
+            event.Veto()
+    
+    def OnResize(self, event):
+        self.EthercatMasterEditor.GetBestSize()
+        xstart, ystart = self.EthercatMasterEditor.GetViewStart()
+        window_size = self.EthercatMasterEditor.GetClientSize()
+        maxx, maxy = self.EthercatMasterEditorSizer.GetMinSize()
+        posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
+        posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
+        self.EthercatMasterEditor.Scroll(posx, posy)
+        self.EthercatMasterEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
+                maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
+        event.Skip()
+        
+    #def OnButtonClick(self, event):
+    #    self.MasterState = self.Controler.getMasterState()
+    #    if self.MasterState:
+    #        self.Phase.SetValue(self.MasterState["phase"])
+    #        self.Active.SetValue(self.MasterState["active"])
+    #        self.SlaveCount.SetValue(self.MasterState["slave"])
+    #        self.MacAddress.SetValue(self.MasterState["MAC"])
+    #        self.LinkState.SetValue(self.MasterState["link"])
+    #        self.TxFrames.SetValue(self.MasterState["TXframe"])
+    #        self.RxFrames.SetValue(self.MasterState["RXframe"])
+    #        self.TxByte.SetValue(self.MasterState["TXbyte"])
+    #        self.TxError.SetValue(self.MasterState["TXerror"])
+    #        self.LostFrames.SetValue(self.MasterState["lost"])
+            
+    #        self.TxFrameRate1.SetValue(self.MasterState["TXframerate1"])
+    #        self.TxFrameRate2.SetValue(self.MasterState["TXframerate2"])
+    #        self.TxFrameRate3.SetValue(self.MasterState["TXframerate3"])
+    #        self.TxRate1.SetValue(self.MasterState["TXrate1"])
+    #        self.TxRate2.SetValue(self.MasterState["TXrate2"])
+    #        self.TxRate3.SetValue(self.MasterState["TXrate3"])
+    #        self.LossRate1.SetValue(self.MasterState["loss1"])
+    #        self.LossRate2.SetValue(self.MasterState["loss2"])
+    #        self.LossRate3.SetValue(self.MasterState["loss3"])
+    #        self.FrameLoss1.SetValue(self.MasterState["frameloss1"])
+    #        self.FrameLoss2.SetValue(self.MasterState["frameloss2"])
+    #        self.FrameLoss3.SetValue(self.MasterState["frameloss3"])
+    
+class LibraryEditorSizer(wx.FlexGridSizer):
+    
+    def __init__(self, parent, module_library, buttons):
+        wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=4, vgap=5)
+        
+        self.ModuleLibrary = module_library
+        self.ParentWindow = parent
+        
+        self.AddGrowableCol(0)
+        self.AddGrowableRow(1)
+        self.AddGrowableRow(3)
+        
+        ESI_files_label = wx.StaticText(parent, 
+            label=_("ESI Files:"))
+        self.AddWindow(ESI_files_label, border=10, 
+            flag=wx.TOP|wx.LEFT|wx.RIGHT)
+        
+        folder_tree_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=0)
+        folder_tree_sizer.AddGrowableCol(0)
+        folder_tree_sizer.AddGrowableRow(0)
+        self.AddSizer(folder_tree_sizer, border=10, 
+            flag=wx.GROW|wx.LEFT|wx.RIGHT)
+        
+        self.ESIFiles = FolderTree(parent, self.GetPath(), editable=False)
+        self.ESIFiles.SetFilter(".xml")
+        folder_tree_sizer.AddWindow(self.ESIFiles, flag=wx.GROW)
+        
+        buttons_sizer = wx.BoxSizer(wx.VERTICAL)
+        folder_tree_sizer.AddSizer(buttons_sizer, 
+            flag=wx.ALIGN_CENTER_VERTICAL)
+        
+        for idx, (name, bitmap, help, callback) in enumerate(buttons):
+            button = wx.lib.buttons.GenBitmapButton(parent, 
+                  bitmap=GetBitmap(bitmap), 
+                  size=wx.Size(28, 28), style=wx.NO_BORDER)
+            button.SetToolTipString(help)
+            setattr(self, name, button)
+            if idx > 0:
+                flag = wx.TOP
+            else:
+                flag = 0
+            if callback is None:
+                callback = getattr(self, "On" + name, None)
+            if callback is not None:
+                parent.Bind(wx.EVT_BUTTON, callback, button)
+            buttons_sizer.AddWindow(button, border=10, flag=flag)
+        
+        modules_label = wx.StaticText(parent, 
+            label=_("Modules library:"))
+        self.AddSizer(modules_label, border=10, 
+            flag=wx.LEFT|wx.RIGHT)
+        
+        self.ModulesGrid = wx.gizmos.TreeListCtrl(parent,
+              style=wx.TR_DEFAULT_STYLE |
+                    wx.TR_ROW_LINES |
+                    wx.TR_COLUMN_LINES |
+                    wx.TR_HIDE_ROOT |
+                    wx.TR_FULL_ROW_HIGHLIGHT)
+        self.ModulesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN,
+            self.OnModulesGridLeftDown)
+        self.ModulesGrid.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT,
+            self.OnModulesGridBeginLabelEdit)
+        self.ModulesGrid.Bind(wx.EVT_TREE_END_LABEL_EDIT,
+            self.OnModulesGridEndLabelEdit)
+        self.ModulesGrid.GetHeaderWindow().Bind(wx.EVT_MOTION, 
+            self.OnModulesGridHeaderMotion)
+        self.AddWindow(self.ModulesGrid, border=10, 
+            flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+        
+        for colname, colsize, colalign in zip(
+                [_("Name")] + [param_infos["column_label"] 
+                               for param, param_infos in 
+                               self.ModuleLibrary.MODULES_EXTRA_PARAMS],
+                [400] + [param_infos["column_size"] 
+                         for param, param_infos in 
+                         self.ModuleLibrary.MODULES_EXTRA_PARAMS],
+                [wx.ALIGN_LEFT] + [wx.ALIGN_RIGHT] * len(self.ModuleLibrary.MODULES_EXTRA_PARAMS)):
+            self.ModulesGrid.AddColumn(_(colname), colsize, colalign, edit=True)
+        self.ModulesGrid.SetMainColumn(0)
+        
+        self.CurrentSelectedCol = None
+        self.LastToolTipCol = None
+    
+    def GetPath(self):
+        return self.ModuleLibrary.GetPath()
+    
+    def SetControlMinSize(self, size):
+        self.ESIFiles.SetMinSize(size)
+        self.ModulesGrid.SetMinSize(size)
+        
+    def GetSelectedFilePath(self):
+        return self.ESIFiles.GetPath()
+    
+    def RefreshView(self):
+        self.ESIFiles.RefreshTree()
+        self.RefreshModulesGrid()
+    
+    def RefreshModulesGrid(self):
+        root = self.ModulesGrid.GetRootItem()
+        if not root.IsOk():
+            root = self.ModulesGrid.AddRoot("Modules")
+        self.GenerateModulesGridBranch(root, 
+            self.ModuleLibrary.GetModulesLibrary(), 
+            GetVariablesTableColnames())
+        self.ModulesGrid.Expand(root)
+            
+    def GenerateModulesGridBranch(self, root, modules, colnames):
+        item, root_cookie = self.ModulesGrid.GetFirstChild(root)
+        
+        no_more_items = not item.IsOk()
+        for module in modules:
+            if no_more_items:
+                item = self.ModulesGrid.AppendItem(root, "")
+            self.ModulesGrid.SetItemText(item, module["name"], 0)
+            if module["infos"] is not None:
+                for param_idx, (param, param_infos) in enumerate(self.ModuleLibrary.MODULES_EXTRA_PARAMS):
+                    self.ModulesGrid.SetItemText(item, 
+                                                 str(module["infos"][param]), 
+                                                 param_idx + 1)
+            else:
+                self.ModulesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY)
+            self.ModulesGrid.SetItemPyData(item, module["infos"])
+            self.GenerateModulesGridBranch(item, module["children"], colnames)
+            if not no_more_items:
+                item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
+                no_more_items = not item.IsOk()
+        
+        if not no_more_items:
+            to_delete = []
+            while item.IsOk():
+                to_delete.append(item)
+                item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
+            for item in to_delete:
+                self.ModulesGrid.Delete(item)
+    
+    def OnImportButton(self, event):
+        dialog = wx.FileDialog(self.ParentWindow,
+             _("Choose an XML file"), 
+             os.getcwd(), "",  
+             _("XML files (*.xml)|*.xml|All files|*.*"), wx.OPEN)
+        
+        if dialog.ShowModal() == wx.ID_OK:
+            filepath = dialog.GetPath()
+            if self.ModuleLibrary.ImportModuleLibrary(filepath):
+                wx.CallAfter(self.RefreshView)
+            else:
+                message = wx.MessageDialog(self, 
+                    _("No such XML file: %s\n") % filepath, 
+                    _("Error"), wx.OK|wx.ICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+        dialog.Destroy()
+        
+        event.Skip()
+    
+    def OnDeleteButton(self, event):
+        filepath = self.GetSelectedFilePath()
+        if os.path.isfile(filepath):
+            folder, filename = os.path.split(filepath)
+            
+            dialog = wx.MessageDialog(self.ParentWindow, 
+                  _("Do you really want to delete the file '%s'?") % filename, 
+                  _("Delete File"), wx.YES_NO|wx.ICON_QUESTION)
+            remove = dialog.ShowModal() == wx.ID_YES
+            dialog.Destroy()
+            
+            if remove:
+                os.remove(filepath)
+                self.ModuleLibrary.LoadModules()
+                wx.CallAfter(self.RefreshView)
+        event.Skip()
+    
+    def OnModulesGridLeftDown(self, event):
+        item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
+        if item.IsOk():
+            entry_infos = self.ModulesGrid.GetItemPyData(item)
+            if entry_infos is not None and col > 0:
+                self.CurrentSelectedCol = col
+            else:
+                self.CurrentSelectedCol = None
+        else:
+            self.CurrentSelectedCol = None
+        event.Skip()
+
+    def OnModulesGridBeginLabelEdit(self, event):
+        item = event.GetItem()
+        if item.IsOk():
+            entry_infos = self.ModulesGrid.GetItemPyData(item)
+            if entry_infos is not None:
+                event.Skip()
+            else:
+                event.Veto()
+        else:
+            event.Veto()
+
+    def OnModulesGridEndLabelEdit(self, event):
+        item = event.GetItem()
+        if item.IsOk() and self.CurrentSelectedCol is not None:
+            entry_infos = self.ModulesGrid.GetItemPyData(item)
+            if entry_infos is not None and self.CurrentSelectedCol > 0:
+                param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[self.CurrentSelectedCol - 1]
+                stripped_column_label = param_infos["column_label"].split('(')[0].strip()
+                try:
+                    self.ModuleLibrary.SetModuleExtraParam(
+                        entry_infos["vendor"],
+                        entry_infos["product_code"],
+                        entry_infos["revision_number"],
+                        param,
+                        int(event.GetLabel()))
+                    wx.CallAfter(self.RefreshModulesGrid)
+                    event.Skip()
+                except ValueError:
+                    message = wx.MessageDialog(self, 
+                        _("Module %s must be an integer!") % stripped_column_label, 
+                        _("Error"), wx.OK|wx.ICON_ERROR)
+                    message.ShowModal()
+                    message.Destroy()
+                    event.Veto()
+            else:
+                event.Veto()
+        else:
+            event.Veto()
+                
+    def OnModulesGridHeaderMotion(self, event):
+        item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
+        if col != self.LastToolTipCol and self.LastToolTipCol is not None:
+            self.ModulesGrid.GetHeaderWindow().SetToolTip(None)
+            self.LastToolTipCol = None
+        if col > 0 and self.LastToolTipCol != col:
+            self.LastToolTipCol = col
+            param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[col - 1]
+            wx.CallAfter(self.ModulesGrid.GetHeaderWindow().SetToolTipString, 
+                         param_infos["description"])
+        event.Skip()
+
+class DatabaseManagementDialog(wx.Dialog):
+    
+    def __init__(self, parent, database):
+        wx.Dialog.__init__(self, parent,
+              size=wx.Size(700, 500), title=_('ESI Files Database management'),
+              style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
+        
+        main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
+        main_sizer.AddGrowableCol(0)
+        main_sizer.AddGrowableRow(0)
+        
+        self.DatabaseSizer = LibraryEditorSizer(self, database,
+            [("ImportButton", "ImportESI", _("Import file to ESI files database"), None),
+             ("DeleteButton", "remove_element", _("Remove file from database"), None)])
+        self.DatabaseSizer.SetControlMinSize(wx.Size(0, 0))
+        main_sizer.AddSizer(self.DatabaseSizer, border=10,
+            flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+        
+        button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+        button_sizer.GetAffirmativeButton().SetLabel(_("Add file to project"))
+        button_sizer.GetCancelButton().SetLabel(_("Close"))
+        main_sizer.AddSizer(button_sizer, border=10, 
+              flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+        
+        self.SetSizer(main_sizer)
+        
+        self.DatabaseSizer.RefreshView()
+        
+    def GetValue(self):
+        return self.DatabaseSizer.GetSelectedFilePath()
+
+class LibraryEditor(ConfTreeNodeEditor):
+    
+    CONFNODEEDITOR_TABS = [
+        (_("Modules Library"), "_create_ModuleLibraryEditor")]
+    
+    def _create_ModuleLibraryEditor(self, prnt):
+        self.ModuleLibraryEditor = wx.ScrolledWindow(prnt,
+            style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
+        self.ModuleLibraryEditor.Bind(wx.EVT_SIZE, self.OnResize)
+        
+        self.ModuleLibrarySizer = LibraryEditorSizer(self.ModuleLibraryEditor,
+            self.Controler.GetModulesLibraryInstance(),
+            [("ImportButton", "ImportESI", _("Import ESI file"), None),
+             ("AddButton", "ImportDatabase", _("Add file from ESI files database"), self.OnAddButton),
+             ("DeleteButton", "remove_element", _("Remove file from library"), None)])
+        self.ModuleLibrarySizer.SetControlMinSize(wx.Size(0, 200))
+        self.ModuleLibraryEditor.SetSizer(self.ModuleLibrarySizer)
+        
+        return self.ModuleLibraryEditor
+
+    def __init__(self, parent, controler, window):
+        ConfTreeNodeEditor.__init__(self, parent, controler, window)
+    
+        self.RefreshView()
+    
+    def RefreshView(self):
+        ConfTreeNodeEditor.RefreshView(self)
+        self.ModuleLibrarySizer.RefreshView()
+
+    def OnAddButton(self, event):
+        dialog = DatabaseManagementDialog(self, 
+            self.Controler.GetModulesDatabaseInstance())
+        
+        if dialog.ShowModal() == wx.ID_OK:
+            module_library = self.Controler.GetModulesLibraryInstance()
+            module_library.ImportModuleLibrary(dialog.GetValue())
+            
+        dialog.Destroy()
+        
+        wx.CallAfter(self.ModuleLibrarySizer.RefreshView)
+        
+        event.Skip()
+
+    def OnResize(self, event):
+        self.ModuleLibraryEditor.GetBestSize()
+        xstart, ystart = self.ModuleLibraryEditor.GetViewStart()
+        window_size = self.ModuleLibraryEditor.GetClientSize()
+        maxx, maxy = self.ModuleLibraryEditor.GetMinSize()
+        posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
+        posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
+        self.ModuleLibraryEditor.Scroll(posx, posy)
+        self.ModuleLibraryEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
+                maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
+        event.Skip()
+        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EtherCATBase.xsd	Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,654 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSpy v2006 sp2 U (http://www.altova.com) by Beckmann (BECKHOFF Automation GmbH) -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:complexType name="AccessType">
+		<xs:simpleContent>
+			<xs:extension base="xs:NMTOKEN">
+				<xs:attribute name="ReadRestrictions">
+					<xs:simpleType>
+						<xs:restriction base="xs:NMTOKEN">
+							<xs:enumeration value="PreOp"/>
+							<xs:enumeration value="PreOP_SafeOP"/>
+							<xs:enumeration value="PreOP_OP"/>
+							<xs:enumeration value="SafeOP"/>
+							<xs:enumeration value="SafeOP_OP"/>
+							<xs:enumeration value="OP"/>
+						</xs:restriction>
+					</xs:simpleType>
+				</xs:attribute>
+				<xs:attribute name="WriteRestrictions">
+					<xs:simpleType>
+						<xs:restriction base="xs:NMTOKEN">
+							<xs:enumeration value="PreOp"/>
+							<xs:enumeration value="PreOP_SafeOP"/>
+							<xs:enumeration value="PreOP_OP"/>
+							<xs:enumeration value="SafeOP"/>
+							<xs:enumeration value="SafeOP_OP"/>
+							<xs:enumeration value="OP"/>
+						</xs:restriction>
+					</xs:simpleType>
+				</xs:attribute>
+			</xs:extension>
+		</xs:simpleContent>
+	</xs:complexType>
+	<xs:complexType name="ArrayInfoType">
+		<xs:sequence>
+			<xs:element name="LBound" type="xs:integer"/>
+			<xs:element name="Elements" type="xs:integer"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="DataTypeType">
+		<xs:sequence>
+			<xs:element name="Index" type="HexDecValue" minOccurs="0"/>
+			<xs:element name="Name" type="xs:string"/>
+			<xs:element name="BaseType" type="xs:string" minOccurs="0"/>
+			<xs:element name="Comment" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="BitSize" type="xs:int"/>
+			<xs:choice minOccurs="0">
+				<xs:element name="ArrayInfo" type="ArrayInfoType" minOccurs="0" maxOccurs="3"/>
+				<xs:element name="SubItem" type="SubItemType" minOccurs="0" maxOccurs="unbounded"/>
+				<xs:element name="EnumInfo" type="EnumInfoType" minOccurs="0" maxOccurs="unbounded"/>
+			</xs:choice>
+			<xs:element name="Properties" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Xml" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="PropertyType">
+		<xs:sequence>
+			<xs:element name="Name" type="xs:string"/>
+			<xs:element name="Value" type="xs:string" minOccurs="0"/>
+			<xs:element name="Desc" type="NameType" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="SubItemType">
+		<xs:sequence>
+			<xs:element name="SubIdx" type="HexDecValue" minOccurs="0"/>
+			<xs:element name="Name" type="xs:string"/>
+			<xs:element name="DisplayName" type="NameType" minOccurs="0" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation>for future use</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Type" type="xs:string"/>
+			<xs:element name="Comment" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="BitSize" type="xs:int"/>
+			<xs:element name="BitOffs" type="xs:int"/>
+			<xs:choice minOccurs="0">
+				<xs:element name="DefaultString" type="xs:string" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>obsolete</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="DefaultData" type="xs:hexBinary" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>obsolete</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:sequence minOccurs="0">
+					<xs:element name="MinValue" type="HexDecValue" minOccurs="0">
+						<xs:annotation>
+							<xs:documentation>obsolete</xs:documentation>
+						</xs:annotation>
+					</xs:element>
+					<xs:element name="MaxValue" type="HexDecValue" minOccurs="0">
+						<xs:annotation>
+							<xs:documentation>obsolete</xs:documentation>
+						</xs:annotation>
+					</xs:element>
+					<xs:element name="DefaultValue" type="HexDecValue" minOccurs="0">
+						<xs:annotation>
+							<xs:documentation>obsolete</xs:documentation>
+						</xs:annotation>
+					</xs:element>
+				</xs:sequence>
+			</xs:choice>
+			<xs:element name="Flags" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Access" minOccurs="0">
+							<xs:complexType>
+								<xs:simpleContent>
+									<xs:restriction base="AccessType">
+										<xs:pattern value="ro"/>
+										<xs:pattern value="rw"/>
+										<xs:pattern value="wo"/>
+									</xs:restriction>
+								</xs:simpleContent>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="Category" minOccurs="0">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="m"/>
+									<xs:enumeration value="o"/>
+									<xs:enumeration value="c"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="PdoMapping" minOccurs="0">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="T"/>
+									<xs:enumeration value="R"/>
+									<xs:enumeration value="TR"/>
+									<xs:enumeration value="RT"/>
+									<xs:enumeration value="t"/>
+									<xs:enumeration value="r"/>
+									<xs:enumeration value="tr"/>
+									<xs:enumeration value="rt"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="SafetyMapping" minOccurs="0">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="si"/>
+									<xs:enumeration value="SI"/>
+									<xs:enumeration value="so"/>
+									<xs:enumeration value="SO"/>
+									<xs:enumeration value="sio"/>
+									<xs:enumeration value="SIO"/>
+									<xs:enumeration value="sp"/>
+									<xs:enumeration value="SP"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="Attribute" type="HexDecValue" minOccurs="0"/>
+						<xs:element name="Backup" type="xs:int" minOccurs="0"/>
+						<xs:element name="Setting" type="xs:int" minOccurs="0"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="Xml" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>obsolete</xs:documentation>
+				</xs:annotation>
+				<xs:complexType>
+					<xs:sequence>
+						<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="EnumInfoType">
+		<xs:sequence>
+			<xs:element name="Text" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="Enum" type="xs:int"/>
+			<xs:element name="Comment" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="NameType">
+		<xs:simpleContent>
+			<xs:extension base="xs:string">
+				<xs:attribute name="LcId" type="xs:integer" use="optional" default="1033"/>
+			</xs:extension>
+		</xs:simpleContent>
+	</xs:complexType>
+	<xs:complexType name="DictionaryType">
+		<xs:sequence>
+			<xs:element name="DataTypes" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="DataType" type="DataTypeType" minOccurs="0" maxOccurs="unbounded">
+							<xs:key name="SubItemKey">
+								<xs:selector xpath="./SubItem"/>
+								<xs:field xpath="Name"/>
+							</xs:key>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+				<xs:key name="DataTypeKey">
+					<xs:selector xpath="./DataType"/>
+					<xs:field xpath="Name"/>
+				</xs:key>
+				<xs:keyref name="BaseTypeRef" refer="DataTypeKey">
+					<xs:selector xpath="./DataType"/>
+					<xs:field xpath="BaseType"/>
+				</xs:keyref>
+				<xs:keyref name="SubItemTypeRef" refer="DataTypeKey">
+					<xs:selector xpath="./DataType/SubItem"/>
+					<xs:field xpath="Type"/>
+				</xs:keyref>
+			</xs:element>
+			<xs:element name="Objects">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Object" type="ObjectType" minOccurs="0" maxOccurs="unbounded"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:simpleType name="HexDecValue">
+		<xs:restriction base="xs:string">
+			<xs:pattern value="[+-]?[0-9]{1,}"/>
+			<xs:pattern value="#x[0-9|a-f|A-F]{1,}"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="ObjectType">
+		<xs:sequence>
+			<xs:element name="Index">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="HexDecValue">
+							<xs:attribute name="DependOnSlot" type="xs:boolean" use="optional"/>
+							<xs:attribute name="DependOnSlotGroup" type="xs:boolean" use="optional"/>
+							<xs:attribute name="OverwrittenByModule" type="xs:boolean" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Name" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="Comment" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="Type" type="xs:string"/>
+			<xs:element name="BitSize" type="xs:int"/>
+			<xs:element name="Info" type="ObjectInfoType" minOccurs="0"/>
+			<xs:element name="Flags" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Access" minOccurs="0">
+							<xs:complexType>
+								<xs:simpleContent>
+									<xs:restriction base="AccessType">
+										<xs:pattern value="ro"/>
+										<xs:pattern value="rw"/>
+										<xs:pattern value="wo"/>
+									</xs:restriction>
+								</xs:simpleContent>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="Category" minOccurs="0">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="m"/>
+									<xs:enumeration value="o"/>
+									<xs:enumeration value="c"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="PdoMapping" minOccurs="0">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="T"/>
+									<xs:enumeration value="R"/>
+									<xs:enumeration value="TR"/>
+									<xs:enumeration value="RT"/>
+									<xs:enumeration value="t"/>
+									<xs:enumeration value="r"/>
+									<xs:enumeration value="tr"/>
+									<xs:enumeration value="rt"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="SafetyMapping" minOccurs="0">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="si"/>
+									<xs:enumeration value="SI"/>
+									<xs:enumeration value="so"/>
+									<xs:enumeration value="SO"/>
+									<xs:enumeration value="sio"/>
+									<xs:enumeration value="SIO"/>
+									<xs:enumeration value="sp"/>
+									<xs:enumeration value="SP"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="Attribute" type="HexDecValue" minOccurs="0"/>
+						<xs:element name="Transition" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>obsolete</xs:documentation>
+							</xs:annotation>
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="IP"/>
+									<xs:enumeration value="PS"/>
+									<xs:enumeration value="SO"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="SdoAccess" minOccurs="0">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="CompleteAccess"/>
+									<xs:enumeration value="SubIndexAccess"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Properties" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Xml" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="ObjectInfoType">
+		<xs:sequence minOccurs="0">
+			<xs:choice>
+				<xs:element name="DefaultString" type="xs:string" minOccurs="0"/>
+				<xs:sequence minOccurs="0">
+					<xs:element name="MinData" type="xs:hexBinary" minOccurs="0"/>
+					<xs:element name="MaxData" type="xs:hexBinary" minOccurs="0"/>
+					<xs:element name="DefaultData" type="xs:hexBinary" minOccurs="0"/>
+				</xs:sequence>
+				<xs:sequence minOccurs="0">
+					<xs:element name="MinValue" type="HexDecValue" minOccurs="0"/>
+					<xs:element name="MaxValue" type="HexDecValue" minOccurs="0"/>
+					<xs:element name="DefaultValue" type="HexDecValue" minOccurs="0"/>
+				</xs:sequence>
+				<xs:element name="SubItem" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="Name" type="xs:string"/>
+							<xs:element name="Info" type="ObjectInfoType"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:choice>
+			<xs:element name="Unit" type="HexDecValue" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="EntryType">
+		<xs:sequence>
+			<xs:element name="Index">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="HexDecValue">
+							<xs:attribute name="DependOnSlot" type="xs:boolean" use="optional"/>
+							<xs:attribute name="DependOnSlotGroup" type="xs:boolean" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="SubIndex" type="HexDecValue" minOccurs="0"/>
+			<xs:element name="BitLen" type="xs:int"/>
+			<xs:element name="Name" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+			<xs:element name="DataType" minOccurs="0">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="DScale" use="optional">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="+/-10"/>
+										<xs:enumeration value="0-10"/>
+										<xs:enumeration value="0-20"/>
+										<xs:enumeration value="4-20"/>
+										<xs:enumeration value="0.1°"/>
+										<xs:enumeration value="0-10(16)"/>
+										<xs:enumeration value="0-20(16)"/>
+										<xs:enumeration value="4-20(16)"/>
+										<xs:enumeration value="0.01°"/>
+										<xs:enumeration value="0-5"/>
+										<xs:enumeration value="0-30"/>
+										<xs:enumeration value="0-50"/>
+										<xs:enumeration value="+/-5"/>
+										<xs:enumeration value="+/-2.5"/>
+										<xs:enumeration value="+/-100"/>
+										<xs:enumeration value="0-5(16)"/>
+										<xs:enumeration value="0-30(16)"/>
+										<xs:enumeration value="0-50(16)"/>
+										<xs:enumeration value="+/-75mV"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:attribute>
+							<xs:attribute name="SwapData" use="optional">
+								<xs:simpleType>
+									<xs:restriction base="xs:NMTOKEN">
+										<xs:enumeration value="Swap_HB_LB"/>
+										<xs:enumeration value="Swap_HW_LW"/>
+										<xs:enumeration value="Swap_HB_LB_HW_LW"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="PdoType">
+		<xs:sequence>
+			<xs:element name="Index">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="HexDecValue">
+							<xs:attribute name="DependOnSlot" type="xs:boolean" use="optional"/>
+							<xs:attribute name="DependOnSlotGroup" type="xs:boolean" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Name" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="Exclude" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="HexDecValue">
+							<xs:attribute name="DependOnSlot" type="xs:boolean" use="optional"/>
+							<xs:attribute name="DependOnSlotGroup" type="xs:boolean" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Entry" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:complexContent>
+						<xs:extension base="EntryType">
+							<xs:attribute name="Fixed" type="xs:boolean" use="optional"/>
+						</xs:extension>
+					</xs:complexContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="ExcludedSm" type="xs:int" minOccurs="0" maxOccurs="unbounded"/>
+		</xs:sequence>
+		<xs:attribute name="Fixed" type="xs:boolean" use="optional"/>
+		<xs:attribute name="Mandatory" type="xs:boolean" use="optional"/>
+		<xs:attribute name="Virtual" type="xs:boolean" use="optional"/>
+		<xs:attribute name="Sm" type="xs:int" use="optional"/>
+		<xs:attribute name="Su" type="xs:int" use="optional"/>
+		<xs:attribute name="PdoOrder" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>obsolete</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="OSFac" type="xs:int" use="optional"/>
+		<xs:attribute name="OSMin" type="xs:int" use="optional"/>
+		<xs:attribute name="OSMax" type="xs:int" use="optional"/>
+		<xs:attribute name="OSIndexInc" type="xs:int" use="optional"/>
+		<xs:attribute name="OverwrittenByModule" type="xs:boolean" use="optional"/>
+	</xs:complexType>
+	<xs:complexType name="VendorSpecificType">
+		<xs:sequence>
+			<xs:any namespace="##any" processContents="skip" maxOccurs="unbounded"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="ProfileType">
+		<xs:sequence>
+			<xs:element name="ProfileNo" type="xs:int" minOccurs="0"/>
+			<xs:element name="AddInfo" type="xs:int" minOccurs="0"/>
+			<xs:choice minOccurs="0">
+				<xs:element name="ChannelCount" type="xs:int"/>
+				<xs:element name="ChannelInfo" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="ProfileNo" type="xs:int"/>
+							<xs:element name="AddInfo" type="xs:int" minOccurs="0"/>
+							<xs:element name="DisplayName" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+						</xs:sequence>
+						<xs:attribute name="OverwrittenByModule" type="xs:boolean" use="optional"/>
+					</xs:complexType>
+				</xs:element>
+			</xs:choice>
+			<xs:choice minOccurs="0">
+				<xs:element name="DictionaryFile" type="xs:string" minOccurs="0"/>
+				<xs:element name="Dictionary" type="DictionaryType" minOccurs="0">
+					<xs:keyref name="ObjectTypesRef" refer="DataTypesKey">
+						<xs:selector xpath="./Objects/Object"/>
+						<xs:field xpath="Type"/>
+					</xs:keyref>
+					<xs:key name="DataTypesKey">
+						<xs:selector xpath="./DataTypes/DataType"/>
+						<xs:field xpath="Name"/>
+					</xs:key>
+				</xs:element>
+			</xs:choice>
+			<xs:element name="DiagMessages" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="DiagMessage" maxOccurs="unbounded">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="TextId" type="HexDecValue"/>
+									<xs:element name="MessageText" type="NameType" maxOccurs="unbounded"/>
+								</xs:sequence>
+							</xs:complexType>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="VendorType">
+		<xs:sequence>
+			<xs:element name="Id" type="HexDecValue"/>
+			<xs:element name="Name" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="Comment" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="URL" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="DescriptionURL" type="xs:string" minOccurs="0"/>
+			<xs:choice>
+				<xs:element name="Image16x14" type="xs:string" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>obsolete</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="ImageFile16x14" type="xs:string" minOccurs="0"/>
+				<xs:element name="ImageData16x14" type="xs:hexBinary" minOccurs="0"/>
+			</xs:choice>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+		</xs:sequence>
+		<xs:attribute name="UniqueName" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>obsolete</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+	</xs:complexType>
+	<xs:complexType name="ModuleType">
+		<xs:sequence>
+			<xs:element name="Type">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="ModuleIdent" type="HexDecValue" use="required"/>
+							<xs:attribute name="ModuleClass" type="xs:string" use="optional"/>
+							<xs:attribute name="ModulePdoGroup" type="xs:int" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Name" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="RxPdo" type="PdoType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="TxPdo" type="PdoType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="SafetyParaMapping" type="PdoType" minOccurs="0"/>
+			<xs:element name="Mailbox" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="CoE" minOccurs="0">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="InitCmd" minOccurs="0" maxOccurs="unbounded">
+										<xs:complexType>
+											<xs:sequence>
+												<xs:element name="Transition" maxOccurs="unbounded">
+													<xs:simpleType>
+														<xs:restriction base="xs:NMTOKEN">
+															<xs:enumeration value="PS"/>
+															<xs:enumeration value="SO"/>
+															<xs:enumeration value="SP"/>
+															<xs:enumeration value="OP"/>
+															<xs:enumeration value="OS"/>
+														</xs:restriction>
+													</xs:simpleType>
+												</xs:element>
+												<xs:element name="Index">
+													<xs:complexType>
+														<xs:simpleContent>
+															<xs:extension base="HexDecValue">
+																<xs:attribute name="DependOnSlot" type="xs:boolean" use="optional"/>
+																<xs:attribute name="DependOnSlotGroup" type="xs:boolean" use="optional"/>
+															</xs:extension>
+														</xs:simpleContent>
+													</xs:complexType>
+												</xs:element>
+												<xs:element name="SubIndex" type="HexDecValue"/>
+												<xs:element name="Data">
+													<xs:complexType>
+														<xs:simpleContent>
+															<xs:extension base="xs:hexBinary">
+																<xs:attribute name="AdaptAutomatically" type="xs:boolean" use="optional"/>
+															</xs:extension>
+														</xs:simpleContent>
+													</xs:complexType>
+												</xs:element>
+												<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+											</xs:sequence>
+											<xs:attribute name="Fixed" type="xs:boolean" use="optional"/>
+											<xs:attribute name="CompleteAccess" type="xs:boolean" use="optional"/>
+										</xs:complexType>
+									</xs:element>
+								</xs:sequence>
+								<xs:attribute name="SdoInfo" type="xs:boolean" use="optional"/>
+								<xs:attribute name="PdoAssign" type="xs:boolean" use="optional"/>
+								<xs:attribute name="PdoConfig" type="xs:boolean" use="optional"/>
+								<xs:attribute name="PdoUpload" type="xs:boolean" use="optional"/>
+								<xs:attribute name="CompleteAccess" type="xs:boolean" use="optional"/>
+								<xs:attribute name="EdsFile" type="xs:string" use="optional"/>
+								<xs:attribute name="SegmentedSdo" type="xs:boolean" use="optional"/>
+								<xs:attribute name="ModuleOD" type="xs:boolean" use="optional"/>
+							</xs:complexType>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Profile" type="ProfileType" minOccurs="0"/>
+			<xs:element name="DcOpModeName" type="xs:string" minOccurs="0"/>
+			<xs:choice minOccurs="0">
+				<xs:element name="Image16x14" type="xs:string" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>obsolete</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="ImageFile16x14" type="xs:string" minOccurs="0"/>
+				<xs:element name="ImageData16x14" type="xs:hexBinary" minOccurs="0"/>
+			</xs:choice>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+</xs:schema>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EtherCATConfig.xsd	Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,1122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:element name="EtherCATConfig">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="Config">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="Master">
+								<xs:annotation>
+									<xs:documentation>Description of the master </xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="Info">
+											<xs:annotation>
+												<xs:documentation>General information abaout the master</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="Name" type="xs:string">
+														<xs:annotation>
+															<xs:documentation>name of the master</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Destination" type="xs:hexBinary">
+														<xs:annotation>
+															<xs:documentation>destination MAC address</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Source" type="xs:hexBinary">
+														<xs:annotation>
+															<xs:documentation>source MAC address</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="EtherType" type="xs:hexBinary" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>Ether type.</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="MailboxStates" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>If this tag exists the master checks the mailbox of one or more slaves for new messages during the cylcic process data communication.</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="StartAddr" type="xs:int">
+														<xs:annotation>
+															<xs:documentation>Start address of the logical address area, that is configured to the written bit of the input mailibox sync manager. In the cyclic frame the master will then include a LRD command with laddr = StartAddr.</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Count" type="xs:int">
+														<xs:annotation>
+															<xs:documentation>Number of slave devices of which the state of the mailbox is tested by the master.</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="EoE" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Ethernet over EtherCAT settings</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="MaxPorts" type="xs:int"/>
+													<xs:element name="MaxFrames" type="xs:int"/>
+													<xs:element name="MaxMACs" type="xs:int"/>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="InitCmds" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Initialization commands that are directed at all slaves.</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="InitCmd" type="ECatCmdType" minOccurs="0" maxOccurs="unbounded"/>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="Slave" minOccurs="0" maxOccurs="unbounded">
+								<xs:annotation>
+									<xs:documentation>Description of one or more EtherCAT slave devices.</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="Info">
+											<xs:annotation>
+												<xs:documentation>General information about the EtherCAT slave device</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="Name" type="xs:string">
+														<xs:annotation>
+															<xs:documentation>Name of  the slave device. </xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:sequence minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>Slave device has EtherCAT Slave Controller</xs:documentation>
+														</xs:annotation>
+														<xs:element name="PhysAddr" type="xs:int">
+															<xs:annotation>
+																<xs:documentation>Fixed EtherCAT address of the slave device.</xs:documentation>
+															</xs:annotation>
+														</xs:element>
+														<xs:element name="AutoIncAddr" type="xs:int">
+															<xs:annotation>
+																<xs:documentation>Auto Increment address of the slave device.</xs:documentation>
+															</xs:annotation>
+														</xs:element>
+														<xs:element name="Physics" type="PhysicsType">
+															<xs:annotation>
+																<xs:documentation>Physics at the individual ports(A,B,C,D) of the slave.</xs:documentation>
+															</xs:annotation>
+														</xs:element>
+													</xs:sequence>
+													<xs:element name="VendorId" type="xs:int">
+														<xs:annotation>
+															<xs:documentation>EtherCAT VendorId. VendorId, ProductCode and RevisionNo are used to identify a specific slave.</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="ProductCode" type="xs:int"/>
+													<xs:element name="RevisionNo" type="xs:int"/>
+													<xs:element name="SerialNo" type="xs:int"/>
+													<xs:element name="ProductRevision" type="xs:string" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>User friendly name generated from ProductCode  and RevisionNo with the help of a vendor specific algorithmn</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="ProcessData" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Description of the process data of this slave</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="Send" minOccurs="0" maxOccurs="unbounded">
+														<xs:annotation>
+															<xs:documentation>Description of the output process data</xs:documentation>
+														</xs:annotation>
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="BitStart" type="xs:int">
+																	<xs:annotation>
+																		<xs:documentation>Start address of the process data of this slave in the output image of the master</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+																<xs:element name="BitLength" type="xs:int">
+																	<xs:annotation>
+																		<xs:documentation>Length of the send process data</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="Recv" minOccurs="0" maxOccurs="unbounded">
+														<xs:annotation>
+															<xs:documentation>Description of the input process data</xs:documentation>
+														</xs:annotation>
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="BitStart" type="xs:int">
+																	<xs:annotation>
+																		<xs:documentation>Start address of the process data of this slave in the inpute image of the master</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+																<xs:element name="BitLength" type="xs:int">
+																	<xs:annotation>
+																		<xs:documentation>Length of the recv process data</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="Sm0" type="SyncManagerSettings" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>Settings of sync manager 0</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Sm1" type="SyncManagerSettings" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>Settings of sync manager 1</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Sm2" type="SyncManagerSettings" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>Settings of sync manager 2</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Sm3" type="SyncManagerSettings" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>Settings of sync manager 3</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:choice minOccurs="0" maxOccurs="unbounded">
+														<xs:element name="RxPdo" type="PdoType">
+															<xs:annotation>
+																<xs:documentation>Ouput Pdos</xs:documentation>
+															</xs:annotation>
+														</xs:element>
+														<xs:element name="TxPdo" type="PdoType">
+															<xs:annotation>
+																<xs:documentation>Input Pdos</xs:documentation>
+															</xs:annotation>
+														</xs:element>
+													</xs:choice>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="Mailbox" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Mailbox settings</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="Send" type="MailboxSendInfoType">
+														<xs:annotation>
+															<xs:documentation>Output mailbox settings</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Recv" type="MailboxRecvInfoType">
+														<xs:annotation>
+															<xs:documentation>Input mailbox settings</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="BootStrap" minOccurs="0">
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="Send" type="MailboxSendInfoType">
+																	<xs:annotation>
+																		<xs:documentation>Output mailbox settings for bootstrap state</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+																<xs:element name="Recv" type="MailboxRecvInfoType">
+																	<xs:annotation>
+																		<xs:documentation>Input mailbox settings for bootstrap state</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="Protocol" minOccurs="0" maxOccurs="unbounded">
+														<xs:annotation>
+															<xs:documentation>Supported protocols</xs:documentation>
+														</xs:annotation>
+														<xs:simpleType>
+															<xs:restriction base="xs:NMTOKEN">
+																<xs:enumeration value="AoE"/>
+																<xs:enumeration value="EoE"/>
+																<xs:enumeration value="CoE"/>
+																<xs:enumeration value="SoE"/>
+																<xs:enumeration value="FoE"/>
+																<xs:enumeration value="VoE"/>
+															</xs:restriction>
+														</xs:simpleType>
+													</xs:element>
+													<xs:element name="CoE" minOccurs="0">
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="InitCmds" minOccurs="0">
+																	<xs:complexType>
+																		<xs:sequence>
+																			<xs:element name="InitCmd" minOccurs="0" maxOccurs="unbounded">
+																				<xs:annotation>
+																					<xs:documentation>SDO download cmds</xs:documentation>
+																				</xs:annotation>
+																				<xs:complexType>
+																					<xs:sequence>
+																						<xs:element name="Transition" type="TransitionType" maxOccurs="unbounded">
+																							<xs:annotation>
+																								<xs:documentation>init cmd will be send at the defined transitions</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+																						<xs:element name="Timeout" type="xs:int">
+																							<xs:annotation>
+																								<xs:documentation>Timeout in ms</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="Ccs" type="xs:int"/>
+																						<xs:element name="Index" type="xs:int">
+																							<xs:annotation>
+																								<xs:documentation>SDO index</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="SubIndex" type="xs:int">
+																							<xs:annotation>
+																								<xs:documentation>SDO subindex</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="Data" type="xs:hexBinary" minOccurs="0">
+																							<xs:annotation>
+																								<xs:documentation>SDO data</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="Disabled" type="xs:boolean" minOccurs="0">
+																							<xs:annotation>
+																								<xs:documentation>If true the init command should not be sent</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																					</xs:sequence>
+																					<xs:attribute name="Fixed" type="xs:boolean" use="optional"/>
+																					<xs:attribute name="CompleteAccess" type="xs:boolean" use="optional"/>
+																				</xs:complexType>
+																			</xs:element>
+																		</xs:sequence>
+																	</xs:complexType>
+																</xs:element>
+																<xs:element name="Profile" type="ProfileType" minOccurs="0"/>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="SoE" minOccurs="0">
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="InitCmds" minOccurs="0">
+																	<xs:complexType>
+																		<xs:sequence>
+																			<xs:element name="InitCmd" minOccurs="0" maxOccurs="unbounded">
+																				<xs:annotation>
+																					<xs:documentation>service channel write req</xs:documentation>
+																				</xs:annotation>
+																				<xs:complexType>
+																					<xs:sequence>
+																						<xs:element name="Transition" maxOccurs="unbounded">
+																							<xs:annotation>
+																								<xs:documentation>init cmd will be send at the defined transitions</xs:documentation>
+																							</xs:annotation>
+																							<xs:simpleType>
+																								<xs:restriction base="xs:NMTOKEN">
+																									<xs:enumeration value="PS"/>
+																									<xs:enumeration value="SO"/>
+																									<xs:enumeration value="SP"/>
+																									<xs:enumeration value="OP"/>
+																									<xs:enumeration value="OS"/>
+																								</xs:restriction>
+																							</xs:simpleType>
+																						</xs:element>
+																						<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+																						<xs:element name="Timeout" type="xs:int">
+																							<xs:annotation>
+																								<xs:documentation>Timeout in ms</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="OpCode" type="xs:int">
+																							<xs:annotation>
+																								<xs:documentation>Op Code</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="DriveNo" type="xs:int">
+																							<xs:annotation>
+																								<xs:documentation>Drive number</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="IDN" type="xs:int">
+																							<xs:annotation>
+																								<xs:documentation>IDN to write</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="Elements" type="xs:int"/>
+																						<xs:element name="Attribute" type="xs:int"/>
+																						<xs:element name="Data" type="xs:hexBinary" minOccurs="0">
+																							<xs:annotation>
+																								<xs:documentation>data to write</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																						<xs:element name="Disabled" type="xs:boolean" minOccurs="0">
+																							<xs:annotation>
+																								<xs:documentation>If true the init command should not be sent</xs:documentation>
+																							</xs:annotation>
+																						</xs:element>
+																					</xs:sequence>
+																					<xs:attribute name="Fixed" type="xs:boolean" use="optional" default="0"/>
+																				</xs:complexType>
+																			</xs:element>
+																		</xs:sequence>
+																	</xs:complexType>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="AoE" minOccurs="0">
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="InitCmds" minOccurs="0">
+																	<xs:complexType>
+																		<xs:sequence>
+																			<xs:element name="InitCmd" type="MailboxCmdType" minOccurs="0" maxOccurs="unbounded"/>
+																		</xs:sequence>
+																	</xs:complexType>
+																</xs:element>
+																<xs:element name="NetId" type="xs:string" minOccurs="0"/>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="EoE" minOccurs="0">
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="InitCmds" minOccurs="0">
+																	<xs:complexType>
+																		<xs:sequence>
+																			<xs:element name="InitCmd" type="MailboxCmdType" minOccurs="0" maxOccurs="unbounded"/>
+																		</xs:sequence>
+																	</xs:complexType>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="FoE" minOccurs="0">
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="InitCmds" minOccurs="0">
+																	<xs:complexType>
+																		<xs:sequence>
+																			<xs:element name="InitCmd" type="MailboxCmdType" minOccurs="0" maxOccurs="unbounded"/>
+																		</xs:sequence>
+																	</xs:complexType>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+													<xs:element name="VoE" minOccurs="0">
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="InitCmds" minOccurs="0">
+																	<xs:complexType>
+																		<xs:sequence>
+																			<xs:element name="InitCmd" type="MailboxCmdType" minOccurs="0" maxOccurs="unbounded"/>
+																		</xs:sequence>
+																	</xs:complexType>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+												</xs:sequence>
+												<xs:attribute name="DataLinkLayer" type="xs:boolean"/>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="InitCmds" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Initialization commands that are necessary for the slave device to run-up.</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="InitCmd" type="ECatCmdType" minOccurs="0" maxOccurs="unbounded"/>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="PreviousPort" minOccurs="0" maxOccurs="unbounded">
+											<xs:annotation>
+												<xs:documentation>Possible previous port. The current previous port is set with the Selected attribute</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="DeviceId" type="xs:int" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>deprecated</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Port">
+														<xs:annotation>
+															<xs:documentation>Port of the previous slave device this device is connected to</xs:documentation>
+														</xs:annotation>
+														<xs:simpleType>
+															<xs:restriction base="xs:NMTOKEN">
+																<xs:enumeration value="B"/>
+																<xs:enumeration value="C"/>
+																<xs:enumeration value="D"/>
+															</xs:restriction>
+														</xs:simpleType>
+													</xs:element>
+													<xs:element name="PhysAddr" type="xs:int" minOccurs="0">
+														<xs:annotation>
+															<xs:documentation>Fixed EtherCAT Address of slave device</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+												<xs:attribute name="Selected" type="xs:int" use="optional" default="0"/>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="HotConnect" minOccurs="0">
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="GroupMemberCnt" type="xs:int"/>
+													<xs:element name="IdentifyCmd" type="ECatCmdType" maxOccurs="unbounded"/>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="DC" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Distributed clock settings</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="ReferenceClock" type="xs:boolean">
+														<xs:annotation>
+															<xs:documentation>Determines if this device is the reference clock</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="CycleTime0" type="xs:int"/>
+													<xs:element name="CycleTime1" type="xs:int"/>
+													<xs:element name="ShiftTime" type="xs:int"/>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="Cyclic" minOccurs="0" maxOccurs="unbounded">
+								<xs:annotation>
+									<xs:documentation>Cycles in which frames are sent</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+										<xs:element name="CycleTime" type="xs:int" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Cycle time of the task sending the frames</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="Priority" type="xs:int" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Priority of the task sending the frames</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="TaskId" type="xs:string" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Id of the task sending the frames</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="Frame" maxOccurs="unbounded">
+											<xs:annotation>
+												<xs:documentation>Frames to be sent in this cycle</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+													<xs:element name="Cmd" maxOccurs="unbounded">
+														<xs:annotation>
+															<xs:documentation>EtherCAT sub command</xs:documentation>
+														</xs:annotation>
+														<xs:complexType>
+															<xs:sequence>
+																<xs:element name="State" maxOccurs="4">
+																	<xs:annotation>
+																		<xs:documentation>Master state the command should be sent in. If the command should not be sent in the current master state one can either remove this command form the frame or set Cmd to Nop.</xs:documentation>
+																	</xs:annotation>
+																	<xs:simpleType>
+																		<xs:restriction base="xs:NMTOKEN">
+																			<xs:enumeration value="INIT"/>
+																			<xs:enumeration value="PREOP"/>
+																			<xs:enumeration value="SAFEOP"/>
+																			<xs:enumeration value="OP"/>
+																		</xs:restriction>
+																	</xs:simpleType>
+																</xs:element>
+																<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+																<xs:element name="Cmd" type="xs:int"/>
+																<xs:choice>
+																	<xs:sequence>
+																		<xs:element name="Adp" type="xs:int" minOccurs="0">
+																			<xs:annotation>
+																				<xs:documentation>Adress position. Either Auto Increment Address or fixed EtherCAT Address</xs:documentation>
+																			</xs:annotation>
+																		</xs:element>
+																		<xs:element name="Ado" type="xs:int">
+																			<xs:annotation>
+																				<xs:documentation>Offset in DPRAM of the EtherCAT Slave Controller</xs:documentation>
+																			</xs:annotation>
+																		</xs:element>
+																	</xs:sequence>
+																	<xs:element name="Addr" type="xs:int">
+																		<xs:annotation>
+																			<xs:documentation>Logical Address</xs:documentation>
+																		</xs:annotation>
+																	</xs:element>
+																</xs:choice>
+																<xs:choice>
+																	<xs:element name="Data" type="xs:hexBinary">
+																		<xs:annotation>
+																			<xs:documentation>Data that should sent</xs:documentation>
+																		</xs:annotation>
+																	</xs:element>
+																	<xs:element name="DataLength" type="xs:int">
+																		<xs:annotation>
+																			<xs:documentation>Length of the data that should be sent. The data is then filled with 0.</xs:documentation>
+																		</xs:annotation>
+																	</xs:element>
+																</xs:choice>
+																<xs:element name="Cnt" type="xs:int" minOccurs="0">
+																	<xs:annotation>
+																		<xs:documentation>Expected working counter.</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+																<xs:element name="InputOffs" type="xs:int">
+																	<xs:annotation>
+																		<xs:documentation>Offset in the input image</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+																<xs:element name="OutputOffs" type="xs:int">
+																	<xs:annotation>
+																		<xs:documentation>Offset in the output image</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+																<xs:element name="CopyInfos" type="CopyInfosType" minOccurs="0">
+																	<xs:annotation>
+																		<xs:documentation>Copy information for slave to slave communication. The master has to copy valid input data of this command from the source offest (bit offs in the complete process image) to a destination offset.</xs:documentation>
+																	</xs:annotation>
+																</xs:element>
+															</xs:sequence>
+														</xs:complexType>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="ProcessImage" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>Description of the process image of the master</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="Inputs" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Input process image of the master</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="ByteSize" type="xs:int">
+														<xs:annotation>
+															<xs:documentation>Size of the input image</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Variable" type="VariableType" minOccurs="0" maxOccurs="unbounded">
+														<xs:annotation>
+															<xs:documentation>Input variables</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="Outputs" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>Output process image of the master</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="ByteSize" type="xs:int">
+														<xs:annotation>
+															<xs:documentation>Size of the output image</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="Variable" type="VariableType" minOccurs="0" maxOccurs="unbounded">
+														<xs:annotation>
+															<xs:documentation>Output variables</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+			<xs:attribute name="Version" type="xs:string" use="optional">
+				<xs:annotation>
+					<xs:documentation>Schema version (actual 1.3)</xs:documentation>
+				</xs:annotation>
+			</xs:attribute>
+		</xs:complexType>
+	</xs:element>
+	<xs:complexType name="ECatCmdType">
+		<xs:sequence>
+			<xs:element name="Transition" type="TransitionType" minOccurs="0" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation>Transition this command should be sent in</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="BeforeSlave" type="xs:boolean" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>If BeforeSlave is true this command will be sent before the slave init commands defined for this transition</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+			<xs:element name="Requires" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>If Requires is set to cycle, this command has to be sent in a seperate cycle. If Requires is set to cycle, this command has to be sent in a seperate frame. </xs:documentation>
+				</xs:annotation>
+				<xs:simpleType>
+					<xs:restriction base="xs:NMTOKEN">
+						<xs:enumeration value="frame"/>
+						<xs:enumeration value="cycle"/>
+					</xs:restriction>
+				</xs:simpleType>
+			</xs:element>
+			<xs:element name="Cmd" type="xs:int">
+				<xs:annotation>
+					<xs:documentation>EtherCAT Command Id</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:choice>
+				<xs:sequence>
+					<xs:element name="Adp" type="xs:int" minOccurs="0">
+						<xs:annotation>
+							<xs:documentation>Adress position. Either Auto Increment Address or fixed EtherCAT Address</xs:documentation>
+						</xs:annotation>
+					</xs:element>
+					<xs:element name="Ado" type="xs:int">
+						<xs:annotation>
+							<xs:documentation>Offset in DPRAM of the EtherCAT Slave Controller</xs:documentation>
+						</xs:annotation>
+					</xs:element>
+				</xs:sequence>
+				<xs:element name="Addr" type="xs:int">
+					<xs:annotation>
+						<xs:documentation>Logical Address</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+			</xs:choice>
+			<xs:choice>
+				<xs:element name="Data" type="xs:hexBinary">
+					<xs:annotation>
+						<xs:documentation>Data that should sent</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="DataLength" type="xs:int">
+					<xs:annotation>
+						<xs:documentation>Length of the data that should be sent. The data is then filled with 0.</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+			</xs:choice>
+			<xs:element name="Cnt" type="xs:int" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>Expected working counter. If the returned working counter is not equal to this value the init command fails.</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Retries" type="xs:int" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>Defines how many times the master should retry sending the command before the init command fails.</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Validate" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>If validate is set the returned data has to be validated by the master.</xs:documentation>
+				</xs:annotation>
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Data" type="xs:hexBinary">
+							<xs:annotation>
+								<xs:documentation>Binary data with which the returned data has to be compared with.</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="DataMask" type="xs:hexBinary" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>If a data mask is set, the returned data and the data mask is combined with an AND operatore, before comparing the data.</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="Timeout" type="xs:int">
+							<xs:annotation>
+								<xs:documentation>Timeout in ms. Determis how long the master retries to read out the date, if the validation has failed.</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="SyncManagerSettings">
+		<xs:sequence>
+			<xs:element name="Type">
+				<xs:annotation>
+					<xs:documentation>Type of Sync Manager (e.g. Outputs)</xs:documentation>
+				</xs:annotation>
+				<xs:simpleType>
+					<xs:restriction base="xs:NMTOKEN">
+						<xs:enumeration value="MBoxOut"/>
+						<xs:enumeration value="MBoxIn"/>
+						<xs:enumeration value="Outputs"/>
+						<xs:enumeration value="Inputs"/>
+					</xs:restriction>
+				</xs:simpleType>
+			</xs:element>
+			<xs:element name="MinSize" type="xs:int" minOccurs="0"/>
+			<xs:element name="MaxSize" type="xs:int" minOccurs="0"/>
+			<xs:element name="DefaultSize" type="xs:int" minOccurs="0"/>
+			<xs:element name="StartAddress" type="xs:int"/>
+			<xs:element name="ControlByte" type="xs:int"/>
+			<xs:element name="Enable" type="xs:boolean"/>
+			<xs:element name="Virtual" type="xs:boolean" minOccurs="0"/>
+			<xs:element name="Watchdog" type="xs:int" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>Watchdog setting of the sync manager</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Pdo" type="xs:int" minOccurs="0" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation>Pdo indices</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:simpleType name="HexDecValue">
+		<xs:restriction base="xs:string">
+			<xs:pattern value="[+-]?[0-9]{1,}"/>
+			<xs:pattern value="#x[0-9|a-f|A-F]{1,}"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="NameType">
+		<xs:simpleContent>
+			<xs:extension base="xs:string">
+				<xs:attribute name="LcId" type="xs:integer" default="1033"/>
+			</xs:extension>
+		</xs:simpleContent>
+	</xs:complexType>
+	<xs:complexType name="PdoType">
+		<xs:sequence>
+			<xs:element name="Index">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="HexDecValue">
+							<xs:attribute name="DependOnSlot" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>The index of the PDO will be adapted depend on the slot number and the SlotPdoIncrement value in the Slots-part of the device description</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="DependOnSlotGroup" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>The index of the PDO will be adapted depend on the slot group number and the SlotGroupPdoIncrement value in the Slots-part of the device description</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Name" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="Exclude" minOccurs="0" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation>List of pdo indicies that are excluded if this pdo is in sync manager</xs:documentation>
+				</xs:annotation>
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="HexDecValue">
+							<xs:attribute name="DependOnSlot" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>The index of the Exclude PDO will be adapted depend on the slot number and the SlotPdoIncrement value in the Slots-part of the device description</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="DependOnSlotGroup" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>The index of the Exclude-PDO will be adapted depend on the slot group number and the SlotPdoIncrement value in the Slots-part of the device description</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Entry" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:complexContent>
+						<xs:extension base="EntryType">
+							<xs:attribute name="Fixed" type="xs:boolean"/>
+						</xs:extension>
+					</xs:complexContent>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+		<xs:attribute name="Fixed" type="xs:boolean" use="optional">
+			<xs:annotation>
+				<xs:documentation>pdo is not configurable</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="Mandatory" type="xs:boolean" use="optional">
+			<xs:annotation>
+				<xs:documentation>pdo must be configured in a sync manager</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="Virtual" type="xs:boolean" use="optional">
+			<xs:annotation>
+				<xs:documentation>pdo will be configured internally (based on the configured variables)</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="Sm" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>default sync manager for this pdo (if set, this PDO will be include in the process image)</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="Su" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>default sync unit for this pdo</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="PdoOrder" type="xs:int" use="optional"/>
+		<xs:attribute name="OSFac" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>default oversampling factor</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="OSMin" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>min. oversampling factor</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="OSMax" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>max. oversampling factor</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="OSIndexInc" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>oversampling increment for entry indicies</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="OverwrittenByModule" type="xs:boolean">
+			<xs:annotation>
+				<xs:documentation>If this attribute is True, the PDO shall not be considered if the configurator supports the modular device description because this PDO will be defined via the module definition (only for configurators supporting V1.3). </xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+	</xs:complexType>
+	<xs:complexType name="EntryType">
+		<xs:sequence>
+			<xs:element name="Index">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="HexDecValue">
+							<xs:attribute name="DependOnSlot" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>The index will be adapted depend on the slot number and the SlotIndexIncrement value in the Slots-part of the device description</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="DependOnSlotGroup" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>The index will be adapted depend on the slot group number and the SlotGroupIndexIncrement value in the Slots-part of the device description</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="SubIndex" type="HexDecValue" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>Default value = 0</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="BitLen" type="xs:int"/>
+			<xs:element name="Name" type="NameType" minOccurs="0" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation>Name is mandatory if Index != 0</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+			<xs:element name="DataType" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>DataType is mandatory if Index != 0</xs:documentation>
+				</xs:annotation>
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="DScale" use="optional">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="+/-10"/>
+										<xs:enumeration value="0-10"/>
+										<xs:enumeration value="0-20"/>
+										<xs:enumeration value="4-20"/>
+										<xs:enumeration value="0.1°"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:attribute>
+							<xs:attribute name="SwapData" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>1 = swap hi and lo bytes; 2 = swap hi and lo words; 3 =  swap both</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:simpleType name="TransitionType">
+		<xs:restriction base="xs:NMTOKEN">
+			<xs:enumeration value="II"/>
+			<xs:enumeration value="IP"/>
+			<xs:enumeration value="PP"/>
+			<xs:enumeration value="PO"/>
+			<xs:enumeration value="PS"/>
+			<xs:enumeration value="PI"/>
+			<xs:enumeration value="SS"/>
+			<xs:enumeration value="SP"/>
+			<xs:enumeration value="SO"/>
+			<xs:enumeration value="SI"/>
+			<xs:enumeration value="OS"/>
+			<xs:enumeration value="OP"/>
+			<xs:enumeration value="OI"/>
+			<xs:enumeration value="IB"/>
+			<xs:enumeration value="BI"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="VariableType">
+		<xs:sequence>
+			<xs:element name="Name" type="xs:string">
+				<xs:annotation>
+					<xs:documentation>Name of the variable</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+			<xs:element name="DataType" type="xs:string" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>Datatype of the variable</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="BitSize" type="xs:int">
+				<xs:annotation>
+					<xs:documentation>Size of the variable in bits</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="BitOffs" type="xs:int">
+				<xs:annotation>
+					<xs:documentation>Bit offset of the variable in the image</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="VendorSpecificType">
+		<xs:sequence>
+			<xs:any namespace="##any" processContents="skip" maxOccurs="unbounded"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="ProfileType">
+		<xs:sequence>
+			<xs:element name="ChannelInfo" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="ProfileNo" type="xs:int"/>
+						<xs:element name="AddInfo" type="xs:string" minOccurs="0"/>
+						<xs:element name="DisplayName" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+					</xs:sequence>
+					<xs:attribute name="OverwrittenByModule" type="xs:boolean">
+						<xs:annotation>
+							<xs:documentation>If this attribute is True, the object shall not be considered if the configurator supports the modular device description because this object will be defined via the module definition (only for configurators supporting V1.3). </xs:documentation>
+						</xs:annotation>
+					</xs:attribute>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:simpleType name="PhysicsType">
+		<xs:restriction base="xs:string">
+			<xs:pattern value="[Y,K, ,B]{0,4}"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="MailboxCmdType">
+		<xs:sequence>
+			<xs:element name="Transition" type="TransitionType" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation>init cmd will be send at the defined transitions</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+			<xs:element name="Timeout" type="xs:int">
+				<xs:annotation>
+					<xs:documentation>Timeout in ms</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Data" type="xs:hexBinary">
+				<xs:annotation>
+					<xs:documentation>data of the mailbox cmd (excl. the mailbox)</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="Disabled" type="xs:boolean" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>If true the init command should not be sent</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+		</xs:sequence>
+		<xs:attribute name="Fixed" type="xs:boolean" use="optional" default="0"/>
+	</xs:complexType>
+	<xs:complexType name="MailboxSendInfoType">
+		<xs:sequence>
+			<xs:element name="Start" type="xs:int"/>
+			<xs:element name="Length" type="xs:int"/>
+			<xs:element name="ShortSend" type="xs:boolean" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="MailboxRecvInfoType">
+		<xs:sequence>
+			<xs:element name="Start" type="xs:int"/>
+			<xs:element name="Length" type="xs:int"/>
+			<xs:element name="PollTime" type="xs:int" minOccurs="0"/>
+			<xs:element name="StatusBitAddr" type="xs:int" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="CopyInfosType">
+		<xs:sequence>
+			<xs:element name="CopyInfo" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="SrcBitOffs" type="HexDecValue"/>
+						<xs:element name="DstBitOffs" type="HexDecValue"/>
+						<xs:element name="BitSize" type="HexDecValue"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+</xs:schema>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EtherCATInfo.xsd	Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,955 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:include schemaLocation="EtherCATBase.xsd"/>
+	<xs:element name="EtherCATInfo">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="InfoReference" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+				<xs:element name="Vendor">
+					<xs:complexType>
+						<xs:complexContent>
+							<xs:extension base="VendorType">
+								<xs:attribute name="FileVersion" type="xs:int"/>
+							</xs:extension>
+						</xs:complexContent>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="Descriptions">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="Groups">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="Group" minOccurs="0" maxOccurs="unbounded">
+											<xs:complexType>
+												<xs:complexContent>
+													<xs:extension base="GroupType">
+														<xs:attribute name="SortOrder" type="xs:int">
+															<xs:annotation>
+																<xs:documentation>Helps to display multiple groups in the order intended by the vendor</xs:documentation>
+															</xs:annotation>
+														</xs:attribute>
+														<xs:attribute name="ParentGroup" type="xs:string">
+															<xs:annotation>
+																<xs:documentation>Type of an optional parent group - only for additional display order possibilities</xs:documentation>
+															</xs:annotation>
+														</xs:attribute>
+													</xs:extension>
+												</xs:complexContent>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="Devices">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="Device" minOccurs="0" maxOccurs="unbounded">
+											<xs:complexType>
+												<xs:complexContent>
+													<xs:extension base="DeviceType">
+														<xs:attribute name="Invisible" type="xs:boolean" use="optional"/>
+														<xs:attribute name="Physics" type="PhysicsType" use="required"/>
+														<xs:attribute name="Crc32" type="HexDecValue" use="optional"/>
+													</xs:extension>
+												</xs:complexContent>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="Modules" minOccurs="0">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="Module" minOccurs="0" maxOccurs="unbounded">
+											<xs:complexType>
+												<xs:complexContent>
+													<xs:extension base="ModuleType">
+														<xs:attribute name="Crc32" type="HexDecValue" use="optional"/>
+													</xs:extension>
+												</xs:complexContent>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+			<xs:attribute name="Version" type="xs:string" use="optional">
+				<xs:annotation>
+					<xs:documentation>Schema version (1.4)</xs:documentation>
+				</xs:annotation>
+			</xs:attribute>
+		</xs:complexType>
+	</xs:element>
+	<xs:complexType name="DeviceType">
+		<xs:sequence>
+			<xs:element name="Type">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="ProductCode" type="HexDecValue" use="optional"/>
+							<xs:attribute name="RevisionNo" type="HexDecValue" use="optional"/>
+							<xs:attribute name="SerialNo" type="HexDecValue" use="optional"/>
+							<xs:attribute name="CheckProductCode" use="optional">
+								<xs:simpleType>
+									<xs:restriction base="xs:NMTOKEN">
+										<xs:enumeration value="NONE"/>
+										<xs:enumeration value="EQ"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:attribute>
+							<xs:attribute name="CheckRevisionNo" use="optional">
+								<xs:simpleType>
+									<xs:restriction base="xs:NMTOKEN">
+										<xs:enumeration value="NONE"/>
+										<xs:enumeration value="EQ"/>
+										<xs:enumeration value="EQ_OR_G"/>
+										<xs:enumeration value="LW_EQ"/>
+										<xs:enumeration value="LW_EQ_HW_EQ_OR_G"/>
+										<xs:enumeration value="HW_EQ"/>
+										<xs:enumeration value="HW_EQ_LW_EQ_OR_G"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:attribute>
+							<xs:attribute name="CheckSerialNo" use="optional">
+								<xs:simpleType>
+									<xs:restriction base="xs:NMTOKEN">
+										<xs:enumeration value="NONE"/>
+										<xs:enumeration value="EQ"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:attribute>
+							<xs:attribute name="TcSmClass" type="xs:string" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="TcCfgModeSafeOp" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="UseLrdLwr" type="xs:boolean" use="optional"/>
+							<xs:attribute name="ModulePdoGroup" type="xs:int" use="optional"/>
+							<xs:attribute name="DownloadModuleList" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>for future use</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="HideType" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="ProductCode" type="HexDecValue" use="optional"/>
+							<xs:attribute name="RevisionNo" type="HexDecValue" use="optional"/>
+							<xs:attribute name="ProductRevision" type="xs:string" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="AlternativeType" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="ProductCode" type="HexDecValue" use="optional">
+								<xs:annotation>
+									<xs:documentation>for future use</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="RevisionNo" type="HexDecValue" use="optional">
+								<xs:annotation>
+									<xs:documentation>for future use</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="SubDevice" minOccurs="0" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation> </xs:documentation>
+				</xs:annotation>
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="ProductCode" type="HexDecValue" use="optional">
+								<xs:annotation>
+									<xs:documentation>for future use</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="RevisionNo" type="HexDecValue" use="optional">
+								<xs:annotation>
+									<xs:documentation>for future use</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="PreviousDevice" type="xs:int" use="optional"/>
+							<xs:attribute name="PreviousPortNo" type="xs:int" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Name" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="Comment" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="URL" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="Info" type="InfoType" minOccurs="0"/>
+			<xs:element name="GroupType" type="xs:string"/>
+			<xs:element name="Profile" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:complexContent>
+						<xs:extension base="ProfileType">
+							<xs:attribute name="Channel" type="xs:int" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:complexContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Fmmu" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="OpOnly" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="Sm" type="xs:int" use="optional"/>
+							<xs:attribute name="Su" type="xs:int" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Sm" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="MinSize" type="HexDecValue" use="optional"/>
+							<xs:attribute name="MaxSize" type="HexDecValue" use="optional"/>
+							<xs:attribute name="DefaultSize" type="HexDecValue" use="optional"/>
+							<xs:attribute name="StartAddress" type="HexDecValue" use="optional"/>
+							<xs:attribute name="ControlByte" type="HexDecValue" use="optional"/>
+							<xs:attribute name="Enable" type="HexDecValue" use="optional"/>
+							<xs:attribute name="OneByteMode" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="Virtual" type="xs:boolean" use="optional"/>
+							<xs:attribute name="Watchdog" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="OpOnly" type="xs:boolean" use="optional"/>
+							<xs:attribute name="FixedAssignment" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>obsolete</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Su" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:simpleContent>
+						<xs:extension base="xs:string">
+							<xs:attribute name="SeparateSu" type="xs:boolean" use="optional"/>
+							<xs:attribute name="SeparateFrame" type="xs:boolean" use="optional"/>
+							<xs:attribute name="DependOnInputState" type="xs:boolean" use="optional">
+								<xs:annotation>
+									<xs:documentation>for future use</xs:documentation>
+								</xs:annotation>
+							</xs:attribute>
+							<xs:attribute name="FrameRepeatSupport" type="xs:boolean" use="optional"/>
+						</xs:extension>
+					</xs:simpleContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="RxPdo" type="PdoType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="TxPdo" type="PdoType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:element name="Mailbox" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="AoE" minOccurs="0">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="InitCmd" minOccurs="0" maxOccurs="unbounded">
+										<xs:complexType>
+											<xs:sequence>
+												<xs:element name="Transition" maxOccurs="unbounded">
+													<xs:simpleType>
+														<xs:restriction base="xs:NMTOKEN">
+															<xs:enumeration value="PS"/>
+															<xs:enumeration value="SO"/>
+															<xs:enumeration value="SP"/>
+															<xs:enumeration value="OP"/>
+															<xs:enumeration value="OS"/>
+														</xs:restriction>
+													</xs:simpleType>
+												</xs:element>
+												<xs:element name="Data" type="xs:hexBinary"/>
+												<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+											</xs:sequence>
+										</xs:complexType>
+									</xs:element>
+								</xs:sequence>
+								<xs:attribute name="AdsRouter" type="xs:boolean" use="optional"/>
+								<xs:attribute name="GenerateOwnNetId" type="xs:boolean" use="optional"/>
+								<xs:attribute name="InitializeOwnNetId" type="xs:boolean" use="optional"/>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="EoE" minOccurs="0">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="InitCmd" minOccurs="0" maxOccurs="unbounded">
+										<xs:complexType>
+											<xs:sequence>
+												<xs:element name="Transition" maxOccurs="unbounded">
+													<xs:simpleType>
+														<xs:restriction base="xs:NMTOKEN">
+															<xs:enumeration value="PS"/>
+															<xs:enumeration value="SO"/>
+															<xs:enumeration value="SP"/>
+															<xs:enumeration value="OP"/>
+															<xs:enumeration value="OS"/>
+														</xs:restriction>
+													</xs:simpleType>
+												</xs:element>
+												<xs:element name="Type" type="xs:int"/>
+												<xs:element name="Data" type="xs:hexBinary"/>
+												<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+											</xs:sequence>
+										</xs:complexType>
+									</xs:element>
+								</xs:sequence>
+								<xs:attribute name="IP" type="xs:boolean" use="optional" default="0"/>
+								<xs:attribute name="MAC" type="xs:boolean" use="optional" default="0"/>
+								<xs:attribute name="TimeStamp" type="xs:boolean" use="optional" default="0"/>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="CoE" minOccurs="0">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="Object" minOccurs="0" maxOccurs="unbounded">
+										<xs:annotation>
+											<xs:documentation>obsolete</xs:documentation>
+										</xs:annotation>
+										<xs:complexType>
+											<xs:sequence>
+												<xs:element name="Index" type="xs:int">
+													<xs:annotation>
+														<xs:documentation>obsolete</xs:documentation>
+													</xs:annotation>
+												</xs:element>
+												<xs:element name="SubIndex" type="xs:int">
+													<xs:annotation>
+														<xs:documentation>obsolete</xs:documentation>
+													</xs:annotation>
+												</xs:element>
+												<xs:element name="Data" type="xs:hexBinary">
+													<xs:annotation>
+														<xs:documentation>obsolete</xs:documentation>
+													</xs:annotation>
+												</xs:element>
+												<xs:element name="Comment" type="xs:string" minOccurs="0">
+													<xs:annotation>
+														<xs:documentation>obsolete</xs:documentation>
+													</xs:annotation>
+												</xs:element>
+											</xs:sequence>
+										</xs:complexType>
+									</xs:element>
+									<xs:element name="InitCmd" minOccurs="0" maxOccurs="unbounded">
+										<xs:complexType>
+											<xs:sequence>
+												<xs:element name="Transition" maxOccurs="unbounded">
+													<xs:simpleType>
+														<xs:restriction base="xs:NMTOKEN">
+															<xs:enumeration value="PS"/>
+															<xs:enumeration value="SO"/>
+															<xs:enumeration value="SP"/>
+															<xs:enumeration value="OP"/>
+															<xs:enumeration value="OS"/>
+														</xs:restriction>
+													</xs:simpleType>
+												</xs:element>
+												<xs:element name="Index" type="HexDecValue"/>
+												<xs:element name="SubIndex" type="HexDecValue"/>
+												<xs:element name="Data">
+													<xs:complexType>
+														<xs:simpleContent>
+															<xs:extension base="xs:hexBinary">
+																<xs:attribute name="AdaptAutomatically" type="xs:boolean" use="optional"/>
+															</xs:extension>
+														</xs:simpleContent>
+													</xs:complexType>
+												</xs:element>
+												<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+											</xs:sequence>
+											<xs:attribute name="Fixed" type="xs:boolean" use="optional">
+												<xs:annotation>
+													<xs:documentation>obsolete</xs:documentation>
+												</xs:annotation>
+											</xs:attribute>
+											<xs:attribute name="CompleteAccess" type="xs:boolean" use="optional"/>
+											<xs:attribute name="OverwrittenByModule" type="xs:boolean" use="optional"/>
+										</xs:complexType>
+									</xs:element>
+								</xs:sequence>
+								<xs:attribute name="SdoInfo" type="xs:boolean" use="optional"/>
+								<xs:attribute name="PdoAssign" type="xs:boolean" use="optional"/>
+								<xs:attribute name="PdoConfig" type="xs:boolean" use="optional"/>
+								<xs:attribute name="PdoUpload" type="xs:boolean" use="optional"/>
+								<xs:attribute name="CompleteAccess" type="xs:boolean" use="optional"/>
+								<xs:attribute name="EdsFile" type="xs:string" use="optional"/>
+								<xs:attribute name="DS402Channels" type="xs:int" use="optional">
+									<xs:annotation>
+										<xs:documentation>obsolete</xs:documentation>
+									</xs:annotation>
+								</xs:attribute>
+								<xs:attribute name="SegmentedSdo" type="xs:boolean" use="optional"/>
+								<xs:attribute name="DiagHistory" type="xs:boolean" use="optional"/>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="FoE" minOccurs="0"/>
+						<xs:element name="SoE" minOccurs="0">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="InitCmd" minOccurs="0" maxOccurs="unbounded">
+										<xs:complexType>
+											<xs:sequence>
+												<xs:element name="Transition" maxOccurs="unbounded">
+													<xs:simpleType>
+														<xs:restriction base="xs:NMTOKEN">
+															<xs:enumeration value="PS"/>
+															<xs:enumeration value="SO"/>
+															<xs:enumeration value="SP"/>
+															<xs:enumeration value="OP"/>
+															<xs:enumeration value="OS"/>
+														</xs:restriction>
+													</xs:simpleType>
+												</xs:element>
+												<xs:element name="IDN" type="xs:int"/>
+												<xs:element name="Data" type="xs:hexBinary"/>
+												<xs:element name="Comment" type="xs:string" minOccurs="0"/>
+											</xs:sequence>
+											<xs:attribute name="Chn" type="xs:int" use="optional" default="0"/>
+										</xs:complexType>
+									</xs:element>
+								</xs:sequence>
+								<xs:attribute name="ChannelCount" type="xs:int" use="optional"/>
+								<xs:attribute name="DriveFollowsBit3Support" type="xs:boolean" use="optional"/>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="VoE" minOccurs="0">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:any minOccurs="0" maxOccurs="unbounded"/>
+								</xs:sequence>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+					</xs:sequence>
+					<xs:attribute name="DataLinkLayer" type="xs:boolean" use="optional" default="0"/>
+					<xs:attribute name="RealTimeMode" type="xs:boolean" use="optional" default="0">
+						<xs:annotation>
+							<xs:documentation>for future use</xs:documentation>
+						</xs:annotation>
+					</xs:attribute>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Dc" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="OpMode" minOccurs="0" maxOccurs="unbounded">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="Name" type="xs:string"/>
+									<xs:element name="Desc" type="xs:string" minOccurs="0"/>
+									<xs:element name="AssignActivate" type="HexDecValue"/>
+									<xs:element name="CycleTimeSync0" minOccurs="0">
+										<xs:complexType>
+											<xs:simpleContent>
+												<xs:extension base="xs:int">
+													<xs:attribute name="Factor" type="xs:int" use="optional"/>
+												</xs:extension>
+											</xs:simpleContent>
+										</xs:complexType>
+									</xs:element>
+									<xs:element name="ShiftTimeSync0" minOccurs="0">
+										<xs:complexType>
+											<xs:simpleContent>
+												<xs:extension base="xs:int">
+													<xs:attribute name="Factor" type="xs:int" use="optional"/>
+													<xs:attribute name="Input" type="xs:boolean" use="optional"/>
+													<xs:attribute name="OutputDelayTime" type="xs:int" use="optional"/>
+													<xs:attribute name="InputDelayTime" type="xs:int" use="optional"/>
+												</xs:extension>
+											</xs:simpleContent>
+										</xs:complexType>
+									</xs:element>
+									<xs:element name="CycleTimeSync1" minOccurs="0">
+										<xs:complexType>
+											<xs:simpleContent>
+												<xs:extension base="xs:int">
+													<xs:attribute name="Factor" type="xs:int" use="optional"/>
+												</xs:extension>
+											</xs:simpleContent>
+										</xs:complexType>
+									</xs:element>
+									<xs:element name="ShiftTimeSync1" minOccurs="0">
+										<xs:complexType>
+											<xs:simpleContent>
+												<xs:extension base="xs:int">
+													<xs:attribute name="Factor" type="xs:int" use="optional">
+														<xs:annotation>
+															<xs:documentation>for future use</xs:documentation>
+														</xs:annotation>
+													</xs:attribute>
+													<xs:attribute name="Input" type="xs:boolean" use="optional"/>
+													<xs:attribute name="OutputDelayTime" type="xs:int" use="optional"/>
+													<xs:attribute name="InputDelayTime" type="xs:int" use="optional"/>
+												</xs:extension>
+											</xs:simpleContent>
+										</xs:complexType>
+									</xs:element>
+									<xs:element name="Sm" minOccurs="0" maxOccurs="unbounded">
+										<xs:complexType>
+											<xs:sequence>
+												<xs:element name="SyncType" type="xs:int" minOccurs="0">
+													<xs:annotation>
+														<xs:documentation>obsolete</xs:documentation>
+													</xs:annotation>
+												</xs:element>
+												<xs:element name="CycleTime" minOccurs="0">
+													<xs:annotation>
+														<xs:documentation>obsolete</xs:documentation>
+													</xs:annotation>
+													<xs:complexType>
+														<xs:simpleContent>
+															<xs:extension base="xs:int">
+																<xs:attribute name="Factor" type="xs:int" use="optional">
+																	<xs:annotation>
+																		<xs:documentation>obsolete</xs:documentation>
+																	</xs:annotation>
+																</xs:attribute>
+															</xs:extension>
+														</xs:simpleContent>
+													</xs:complexType>
+												</xs:element>
+												<xs:element name="ShiftTime" minOccurs="0">
+													<xs:annotation>
+														<xs:documentation>obsolete</xs:documentation>
+													</xs:annotation>
+													<xs:complexType>
+														<xs:simpleContent>
+															<xs:extension base="xs:int">
+																<xs:attribute name="MinAfterSync" type="xs:int" use="optional">
+																	<xs:annotation>
+																		<xs:documentation>obsolete</xs:documentation>
+																	</xs:annotation>
+																</xs:attribute>
+																<xs:attribute name="MinBeforeFrame" type="xs:int" use="optional">
+																	<xs:annotation>
+																		<xs:documentation>obsolete</xs:documentation>
+																	</xs:annotation>
+																</xs:attribute>
+															</xs:extension>
+														</xs:simpleContent>
+													</xs:complexType>
+												</xs:element>
+												<xs:element name="Pdo" minOccurs="0" maxOccurs="unbounded">
+													<xs:complexType>
+														<xs:simpleContent>
+															<xs:extension base="HexDecValue">
+																<xs:attribute name="OSFac" type="xs:int"/>
+															</xs:extension>
+														</xs:simpleContent>
+													</xs:complexType>
+												</xs:element>
+											</xs:sequence>
+											<xs:attribute name="No" type="xs:int" use="required"/>
+										</xs:complexType>
+									</xs:element>
+									<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+								</xs:sequence>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+					</xs:sequence>
+					<xs:attribute name="UnknownFRMW" type="xs:boolean" use="optional"/>
+					<xs:attribute name="Unknown64Bit" type="xs:boolean" use="optional"/>
+					<xs:attribute name="ExternalRefClock" type="xs:boolean" use="optional"/>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Slots" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Slot" type="SlotType" minOccurs="0" maxOccurs="unbounded"/>
+						<xs:element name="ModulePdoGroup" minOccurs="0" maxOccurs="unbounded">
+							<xs:complexType>
+								<xs:simpleContent>
+									<xs:extension base="xs:string">
+										<xs:attribute name="Alignment" type="xs:int" use="optional"/>
+										<xs:attribute name="RxPdo" type="HexDecValue" use="optional"/>
+										<xs:attribute name="TxPdo" type="HexDecValue" use="optional"/>
+									</xs:extension>
+								</xs:simpleContent>
+							</xs:complexType>
+						</xs:element>
+					</xs:sequence>
+					<xs:attribute name="MaxSlotCount" type="HexDecValue" use="optional"/>
+					<xs:attribute name="MaxSlotGroupCount" type="HexDecValue" use="optional"/>
+					<xs:attribute name="SlotPdoIncrement" type="HexDecValue" use="optional"/>
+					<xs:attribute name="SlotGroupPdoIncrement" type="HexDecValue" use="optional"/>
+					<xs:attribute name="SlotIndexIncrement" type="HexDecValue" use="optional"/>
+					<xs:attribute name="SlotGroupIndexIncrement" type="HexDecValue" use="optional"/>
+					<xs:attribute name="IdentifyModuleBy">
+						<xs:annotation>
+							<xs:documentation>obsolete</xs:documentation>
+						</xs:annotation>
+						<xs:simpleType>
+							<xs:restriction base="xs:NMTOKEN">
+								<xs:enumeration value="ModuleIdent"/>
+								<xs:enumeration value="IdentityObjekt"/>
+							</xs:restriction>
+						</xs:simpleType>
+					</xs:attribute>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="ESC" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Reg0108" type="HexDecValue" minOccurs="0"/>
+						<xs:element name="Reg0400" type="HexDecValue" minOccurs="0"/>
+						<xs:element name="Reg0410" type="HexDecValue" minOccurs="0"/>
+						<xs:element name="Reg0420" type="HexDecValue" minOccurs="0"/>
+						<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Eeprom" minOccurs="0">
+				<xs:complexType>
+					<xs:complexContent>
+						<xs:extension base="EepromType">
+							<xs:attribute name="AssignToPdi" type="xs:boolean"/>
+						</xs:extension>
+					</xs:complexContent>
+				</xs:complexType>
+			</xs:element>
+			<xs:choice minOccurs="0">
+				<xs:element name="Image16x14" type="xs:string" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>obsolete</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="ImageFile16x14" type="xs:string" minOccurs="0"/>
+				<xs:element name="ImageData16x14" type="xs:hexBinary" minOccurs="0"/>
+			</xs:choice>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="GroupType">
+		<xs:sequence>
+			<xs:element name="Type" type="xs:string"/>
+			<xs:element name="Name" type="NameType" maxOccurs="unbounded"/>
+			<xs:element name="Comment" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:choice>
+				<xs:element name="Image16x14" type="xs:string" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>obsolete</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="ImageFile16x14" type="xs:string" minOccurs="0"/>
+				<xs:element name="ImageData16x14" type="xs:hexBinary" minOccurs="0"/>
+			</xs:choice>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="EepromType">
+		<xs:sequence>
+			<xs:choice>
+				<xs:element name="Data" type="xs:hexBinary"/>
+				<xs:sequence>
+					<xs:element name="ByteSize" type="xs:int"/>
+					<xs:element name="ConfigData" type="xs:hexBinary"/>
+					<xs:element name="BootStrap" type="xs:hexBinary" minOccurs="0"/>
+					<xs:element name="Category" minOccurs="0" maxOccurs="unbounded">
+						<xs:complexType>
+							<xs:sequence>
+								<xs:element name="CatNo">
+									<xs:complexType>
+										<xs:simpleContent>
+											<xs:extension base="xs:int"/>
+										</xs:simpleContent>
+									</xs:complexType>
+								</xs:element>
+								<xs:choice>
+									<xs:element name="Data" type="xs:hexBinary"/>
+									<xs:element name="DataString" type="xs:string"/>
+									<xs:element name="DataUINT" type="xs:int"/>
+									<xs:element name="DataUDINT" type="xs:int"/>
+								</xs:choice>
+							</xs:sequence>
+							<xs:attribute name="PreserveOnlineData" type="xs:boolean" use="optional"/>
+						</xs:complexType>
+					</xs:element>
+				</xs:sequence>
+			</xs:choice>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="InfoType">
+		<xs:sequence>
+			<xs:element name="Electrical" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="EBusCurrent" type="xs:int"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="StateMachine" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Timeout" minOccurs="0">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="PreopTimeout" type="xs:int"/>
+									<xs:element name="SafeopOpTimeout" type="xs:int"/>
+									<xs:element name="BackToInitTimeout" type="xs:int"/>
+									<xs:element name="BackToSafeopTimeout" type="xs:int"/>
+								</xs:sequence>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="Behavior" minOccurs="0">
+							<xs:complexType>
+								<xs:attribute name="StartToInit" type="xs:boolean" use="optional"/>
+								<xs:attribute name="StartToPreop" type="xs:boolean" use="optional"/>
+								<xs:attribute name="StartToSafeop" type="xs:boolean" use="optional"/>
+								<xs:attribute name="StartToSafeopNoSync" type="xs:boolean" use="optional"/>
+							</xs:complexType>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Mailbox" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Timeout">
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="RequestTimeout" type="xs:int"/>
+									<xs:element name="ResponseTimeout" type="xs:int"/>
+								</xs:sequence>
+							</xs:complexType>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="EtherCATController" minOccurs="0">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="DpramSize" type="xs:int" default="4096" minOccurs="0"/>
+						<xs:element name="SmCount" type="xs:int" minOccurs="0"/>
+						<xs:element name="FmmuCount" type="xs:int" minOccurs="0"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="Port" minOccurs="0" maxOccurs="4">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Type">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="MII"/>
+									<xs:enumeration value="EBUS"/>
+									<xs:enumeration value="NONE"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="Connector" type="xs:string" minOccurs="0"/>
+						<xs:element name="Label" type="xs:string" minOccurs="0"/>
+						<xs:element name="RxDelay" type="xs:int" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>in 100ps</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="TxDelay" type="xs:int" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>in 100ps</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="PhysicalPhyAddr" type="xs:int" minOccurs="0"/>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="ExecutionUnit" minOccurs="0" maxOccurs="2">
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Type">
+							<xs:simpleType>
+								<xs:restriction base="xs:NMTOKEN">
+									<xs:enumeration value="PRIMARY"/>
+									<xs:enumeration value="SECONDARY"/>
+									<xs:enumeration value="NONE"/>
+								</xs:restriction>
+							</xs:simpleType>
+						</xs:element>
+						<xs:element name="RxDelay" type="xs:int" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>in 100ps</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="TxDelay" type="xs:int" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>in 100ps</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="VendorSpecific" type="VendorSpecificType" minOccurs="0"/>
+			<xs:element name="StationAliasSupported" minOccurs="0">
+				<xs:annotation>
+					<xs:documentation>obsolete</xs:documentation>
+				</xs:annotation>
+				<xs:simpleType>
+					<xs:restriction base="xs:NMTOKEN">
+						<xs:enumeration value="NO_SUPPORT"/>
+						<xs:enumeration value="REGISTER_SUPPORT"/>
+						<xs:enumeration value="PROCESSDATA_SUPPORT"/>
+					</xs:restriction>
+				</xs:simpleType>
+			</xs:element>
+			<xs:element name="IdentificationAdo" type="HexDecValue" minOccurs="0"/>
+			<xs:element name="DeviceFeature" minOccurs="0" maxOccurs="unbounded">
+				<xs:annotation>
+					<xs:documentation>for future use</xs:documentation>
+				</xs:annotation>
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="Name" type="xs:string">
+							<xs:annotation>
+								<xs:documentation>for future use</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="Value" type="xs:string" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>for future use</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="Description" type="xs:string" minOccurs="0">
+							<xs:annotation>
+								<xs:documentation>for future use</xs:documentation>
+							</xs:annotation>
+						</xs:element>
+						<xs:element name="Register" minOccurs="0" maxOccurs="unbounded">
+							<xs:annotation>
+								<xs:documentation>for future use</xs:documentation>
+							</xs:annotation>
+							<xs:complexType>
+								<xs:sequence>
+									<xs:element name="StartAddress" type="xs:int">
+										<xs:annotation>
+											<xs:documentation>for future use;
+in bytes</xs:documentation>
+										</xs:annotation>
+									</xs:element>
+									<xs:element name="Length" type="xs:int">
+										<xs:annotation>
+											<xs:documentation>for future use;
+in bytes</xs:documentation>
+										</xs:annotation>
+									</xs:element>
+									<xs:element name="BitMask" type="HexDecValue" minOccurs="0">
+										<xs:annotation>
+											<xs:documentation>for future use</xs:documentation>
+										</xs:annotation>
+									</xs:element>
+								</xs:sequence>
+							</xs:complexType>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:simpleType name="PhysicsType">
+		<xs:restriction base="xs:string">
+			<xs:pattern value="[Y,K, ]{0,4}"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="SlotType">
+		<xs:sequence>
+			<xs:element name="Name" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+			<xs:choice>
+				<xs:element name="ModuleIdent" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:simpleContent>
+							<xs:extension base="HexDecValue">
+								<xs:attribute name="Default" type="HexDecValue" use="optional"/>
+							</xs:extension>
+						</xs:simpleContent>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="ModuleClass" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="Class" type="xs:string"/>
+							<xs:element name="VendorId" type="HexDecValue" minOccurs="0"/>
+							<xs:element name="Name" type="NameType" minOccurs="0" maxOccurs="unbounded"/>
+							<xs:choice minOccurs="0">
+								<xs:element name="Image16x14" type="xs:string" minOccurs="0">
+									<xs:annotation>
+										<xs:documentation>obsolete</xs:documentation>
+									</xs:annotation>
+								</xs:element>
+								<xs:element name="ImageFile16x14" type="xs:string" minOccurs="0"/>
+								<xs:element name="ImageData16x14" type="xs:hexBinary" minOccurs="0"/>
+							</xs:choice>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:choice>
+			<xs:choice minOccurs="0">
+				<xs:element name="Image16x14" type="xs:string" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>obsolete</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="ImageFile16x14" type="xs:string" minOccurs="0"/>
+				<xs:element name="ImageData16x14" type="xs:hexBinary" minOccurs="0"/>
+			</xs:choice>
+		</xs:sequence>
+		<xs:attribute name="SlotGroup" type="HexDecValue" use="optional"/>
+		<xs:attribute name="MinInstances" type="HexDecValue" use="required"/>
+		<xs:attribute name="MaxInstances" type="HexDecValue" use="required"/>
+		<xs:attribute name="SlotPdoIncrement" type="HexDecValue" use="optional"/>
+		<xs:attribute name="SlotGroupPdoIncrement" type="HexDecValue" use="optional"/>
+		<xs:attribute name="SlotIndexIncrement" type="HexDecValue" use="optional"/>
+		<xs:attribute name="SlotGroupIndexIncrement" type="HexDecValue" use="optional"/>
+		<xs:attribute name="TreeView" use="optional">
+			<xs:simpleType>
+				<xs:restriction base="xs:NMTOKEN">
+					<xs:enumeration value="SLOTGROUP"/>
+					<xs:enumeration value="SLOT"/>
+					<xs:enumeration value="PDO"/>
+				</xs:restriction>
+			</xs:simpleType>
+		</xs:attribute>
+	</xs:complexType>
+</xs:schema>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EtherCATManagementEditor.py	Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,2207 @@
+#!/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
+#
+# See COPYING file for copyrights details.
+
+import os
+
+import wx
+import wx.grid
+import wx.gizmos
+import wx.lib.buttons
+
+# --------------------------------------------------------------------
+from controls import CustomGrid, CustomTable
+# --------------------------------------------------------------------
+
+# ------------ for SDO Management --------------------
+import string
+import wx.grid as gridlib
+#-------------------------------------------------------------
+
+# ------------ for register management --------------- 
+from xml.dom import minidom
+#-------------------------------------------------------------
+
+# ----------------------------- For Sync Manager Table -----------------------------------
+def GetSyncManagersTableColnames():
+    """
+    Returns column names of SyncManager Table in Slave state panel.
+    """
+    _ = lambda x : x
+    return ["#", _("Name"), _("Start Address"), _("Default Size"), _("Control Byte"), _("Enable")]
+
+#-------------------------------------------------------------------------------
+#                    Sync Managers Table
+#-------------------------------------------------------------------------------
+class SyncManagersTable(CustomTable):
+    def GetValue(self, row, col): 
+        if row < self.GetNumberRows():
+            if col == 0:
+                return row
+            return self.data[row].get(self.GetColLabelValue(col, False), "")
+
+#-------------------------------------------------------------------------------
+#                    EtherCAT Management Treebook
+#-------------------------------------------------------------------------------
+class EtherCATManagementTreebook(wx.Treebook):
+    def __init__(self, parent, controler, node_editor):
+        """
+        Constructor
+        @param parent: Reference to the parent wx.ScrolledWindow object
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        @param node_editor: Reference to Beremiz frame
+        """
+        wx.Treebook.__init__(self, parent, -1, size=wx.DefaultSize, style=wx.BK_DEFAULT)
+        self.parent = parent
+        self.Controler = controler
+        self.NodeEditor = node_editor
+        
+        self.EtherCATManagementClassObject = {}
+        
+        # fill EtherCAT Management Treebook
+        for pname, pclass, subs in [
+            ("Slave State",        SlaveStatePanelClass, []),
+            ("SDO Management",     SDOPanelClass, []),
+            ("PDO Monitoring",     PDOPanelClass, []),
+            ("ESC Management",     EEPROMAccessPanel, [        
+                    ("Smart View", SlaveSiiSmartView),
+                    ("Hex View", HexView)]),
+            ("Register Access",     RegisterAccessPanel, [])]:
+                self.AddPage(pclass(self, self.Controler), pname)
+                for spname, spclass in subs:
+                    self.AddSubPage(spclass(self, self.Controler), spname)
+
+        self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGING, self.OnPageChanging)
+        
+    def OnPageChanged(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = event.GetSelection()
+        event.Skip()
+        
+    def OnPageChanging(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = event.GetSelection()
+        event.Skip()    
+        
+#-------------------------------------------------------------------------------
+#                    For SlaveState Panel
+#-------------------------------------------------------------------------------        
+class SlaveStatePanelClass(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent EtherCATManagementTreebook class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Panel.__init__(self, parent, -1, (0, 0), size=wx.DefaultSize, style = wx.SUNKEN_BORDER)
+        self.Controler = controler
+        self.parent = parent
+        
+        # initialize SlaveStatePanel UI dictionaries
+        self.StaticBoxDic = {}
+        self.StaticTextDic = {}
+        self.TextCtrlDic = {}
+        self.ButtonDic = {}
+        
+        # iniitalize BoxSizer and FlexGridSizer
+        self.SizerDic = {
+            "SlaveState_main_sizer" : wx.BoxSizer(wx.VERTICAL),
+            "SlaveState_inner_main_sizer" : wx.FlexGridSizer(cols=1, hgap=50, rows=3, vgap=10),
+            "SlaveInfosDetailsInnerSizer" : wx.FlexGridSizer(cols=4, hgap=10, rows=2, vgap=10),
+            "SyncManagerInnerSizer" : wx.FlexGridSizer(cols=1, hgap=5, rows=1, vgap=5),
+            "SlaveState_sizer" : wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10),
+            "SlaveState_up_sizer" : wx.FlexGridSizer(cols=4, hgap=10, rows=2, vgap=10),
+            "SlaveState_down_sizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10)}
+        
+        # initialize StaticBox and StaticBoxSizer
+        for box_name, box_label in [
+                ("SlaveInfosDetailsBox", "Slave Informations"),
+                ("SyncManagerBox", "Sync Manager"),
+                ("SlaveStateBox", "Slave State Transition && Monitoring")]:
+            self.StaticBoxDic[box_name] = wx.StaticBox(self, label=_(box_label))
+            self.SizerDic[box_name] = wx.StaticBoxSizer(self.StaticBoxDic[box_name])  
+        
+        for statictext_name, statictext_label, textctrl_name in [
+                ("VendorLabel", "Vendor:", "vendor"),
+                ("ProductcodeLabel", "Product code:", "product_code"),
+                ("RevisionnumberLabel", "Slave Count:", "revision_number"),
+                ("PhysicsLabel", "Physics:", "physics")]:
+            self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
+            self.TextCtrlDic[textctrl_name] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
+            self.SizerDic["SlaveInfosDetailsInnerSizer"].AddMany([self.StaticTextDic[statictext_name], 
+                                                               self.TextCtrlDic[textctrl_name]])    
+        
+        self.SizerDic["SlaveInfosDetailsBox"].AddSizer(self.SizerDic["SlaveInfosDetailsInnerSizer"])
+        
+        self.SyncManagersGrid = CustomGrid(self, size=wx.Size(605,155), style=wx.VSCROLL)      
+               
+        self.SizerDic["SyncManagerInnerSizer"].Add(self.SyncManagersGrid)    
+        self.SizerDic["SyncManagerBox"].Add(self.SizerDic["SyncManagerInnerSizer"])
+        
+        for button_name, button_id, button_label, button_tooltipstring, event_method, sub_item in [
+                ("InitButton",   0, "INIT", "State Transition to \"Init\" State",     self.OnButtonClick, []),
+                ("PreOPButton",  1, "PREOP", "State Transition to \"PreOP\" State",   self.OnButtonClick, [
+                        ("TargetStateLabel", "Target State:" , "TargetState")]),
+                ("SafeOPButton", 2, "SAFEOP", "State Transition to \"SafeOP\" State", self.OnButtonClick, []),
+                ("OPButton",     3, "OP",  "State Transition to \"OP\" State",        self.OnButtonClick, [
+                        ("CurrentStateLabel", "Current State:", "CurrentState")])]:
+            self.ButtonDic[button_name] = wx.Button(self, id=button_id ,label=_(button_label))
+            self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method)
+            self.ButtonDic[button_name].SetToolTipString(button_tooltipstring)
+            self.SizerDic["SlaveState_up_sizer"].Add(self.ButtonDic[button_name])
+            for statictext_name, statictext_label, textctrl_name in sub_item :
+                self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
+                self.TextCtrlDic[textctrl_name] = wx.TextCtrl(self, size=wx.DefaultSize, style=wx.TE_READONLY)
+                self.SizerDic["SlaveState_up_sizer"].AddMany([self.StaticTextDic[statictext_name], 
+                                                               self.TextCtrlDic[textctrl_name]])
+                
+        for button_name, button_label, button_tooltipstring, event_method in [
+                ("StartTimerButton", "Start State Monitoring", "Slave State Update Restart", self.StartTimer),
+                ("StopTimerButton", "Stop State Monitoring", "Slave State Update Stop", self.CurrentStateThreadStop)]:
+            self.ButtonDic[button_name] = wx.Button(self, label=_(button_label))
+            self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method)
+            self.ButtonDic[button_name].SetToolTipString(button_tooltipstring)
+            self.SizerDic["SlaveState_down_sizer"].Add(self.ButtonDic[button_name])   
+        
+        self.SizerDic["SlaveState_sizer"].AddMany([self.SizerDic["SlaveState_up_sizer"], 
+            self.SizerDic["SlaveState_down_sizer"]])
+        
+        self.SizerDic["SlaveStateBox"].Add(self.SizerDic["SlaveState_sizer"])
+        
+        self.SizerDic["SlaveState_inner_main_sizer"].AddMany([
+            self.SizerDic["SlaveInfosDetailsBox"], self.SizerDic["SyncManagerBox"],
+            self.SizerDic["SlaveStateBox"]])
+        
+        self.SizerDic["SlaveState_main_sizer"].Add(self.SizerDic["SlaveState_inner_main_sizer"])
+        
+        self.SetSizer(self.SizerDic["SlaveState_main_sizer"])
+        
+        # register a timer for periodic exectuion of slave state update (period: 1000 ms)
+        self.Bind(wx.EVT_TIMER, self.GetCurrentState)
+        
+        self.CreateSyncManagerTable()
+        
+        self.Centre()
+    
+    def CreateSyncManagerTable(self):
+        """
+        Create grid for "SyncManager"
+        """
+        # declare Table object 
+        self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames())
+        self.SyncManagersGrid.SetTable(self.SyncManagersTable)
+        # set grid alignment attr. (CENTER)
+        self.SyncManagersGridColAlignements = [wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, 
+                                               wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE]
+        # set grid size
+        self.SyncManagersGridColSizes = [40, 150, 100, 100, 100, 100]
+        self.SyncManagersGrid.SetRowLabelSize(0)
+        for col in range(self.SyncManagersTable.GetNumberCols()):
+            attr = wx.grid.GridCellAttr()
+            attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTRE)
+            self.SyncManagersGrid.SetColAttr(col, attr)
+            self.SyncManagersGrid.SetColMinimalWidth(col, self.SyncManagersGridColSizes[col])
+            self.SyncManagersGrid.AutoSizeColumn(col, False) 
+        
+        self.RefreshSlaveInfos()
+        
+    def RefreshSlaveInfos(self):
+        """
+        Fill data in "Slave Information" and "SyncManager"
+        """
+        slave_infos = self.Controler.GetSlaveInfos()
+        sync_manager_section = ["vendor", "product_code", "revision_number", "physics"]
+        if slave_infos is not None:
+            # this method is same as "TextCtrl.SetValue" 
+            for textctrl_name in sync_manager_section:
+                self.TextCtrlDic[textctrl_name].SetValue(slave_infos[textctrl_name])
+            self.SyncManagersTable.SetData(slave_infos["sync_managers"])
+            self.SyncManagersTable.ResetView(self.SyncManagersGrid)
+        else:
+            for textctrl_name in sync_manager_section:
+                self.TextCtrlDic[textctrl_name].SetValue("")
+            self.SyncManagersTable.SetData([])
+            self.SyncManagersTable.ResetView(self.SyncManagersGrid)
+        
+    def OnButtonClick(self, event):
+        """
+        Event handler for slave state transition button click (Init, PreOP, SafeOP, OP button)
+        @param event : wx.EVT_BUTTON object
+        """
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        if check_connect_flag :
+            state_dic = ["INIT", "PREOP", "SAFEOP", "OP"]
+              
+            # If target state is one of {INIT, PREOP, SAFEOP}, request slave state transition immediately.
+            if event.GetId() < 3 :
+                self.Controler.CommonMethod.RequestSlaveState(state_dic[event.GetId()])
+                self.TextCtrlDic["TargetState"].SetValue(state_dic[event.GetId()])
+
+            # If target state is OP, first check "PLC status".
+            #  (1) If current PLC status is "Started", then request slave state transition
+            #  (2) Otherwise, show error message and return
+            else :
+                status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
+                if status == "Started" :
+                    self.Controler.CommonMethod.RequestSlaveState("OP")
+                    self.TextCtrlDic["TargetState"].SetValue("OP")
+                else :
+                    self.Controler.CommonMethod.CreateErrorDialog("PLC is Not Started")  
+     
+    def GetCurrentState(self, event):
+        """
+        Timer event handler for periodic slave state monitoring (Default period: 1 sec = 1000 msec).
+        @param event : wx.TIMER object
+        """
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(True)
+        if check_connect_flag:
+            returnVal = self.Controler.CommonMethod.GetSlaveStateFromSlave()
+            line = returnVal.split("\n")
+            try :
+                self.SetCurrentState(line[self.Controler.GetSlavePos()])
+            except :
+                pass  
+            
+    def SetCurrentState(self, line):
+        """
+        Show current slave state using the executiob result of "ethercat slaves" command.
+        @param line : result of "ethercat slaves" command
+        """
+        state_array = ["INIT", "PREOP", "SAFEOP", "OP"]
+        try :
+            # parse the execution result of  "ethercat slaves" command
+            # Result example : 0  0:0  PREOP  +  EL9800 (V4.30) (PIC24, SPI, ET1100)
+            token = line.split("  ")
+            if token[2] in state_array:
+                self.TextCtrlDic["CurrentState"].SetValue(token[2])           
+        except :
+            pass     
+        
+    def StartTimer(self, event):
+        """
+        Event handler for "Start State Monitoring" button.
+          - start slave state monitoring thread
+        @param event : wx.EVT_BUTTON object
+        """
+        self.SlaveStateThread = wx.Timer(self)
+        # set timer period (1000 ms)
+        self.SlaveStateThread.Start(1000)
+        
+    def CurrentStateThreadStop(self, event):
+        """
+        Event handler for "Stop State Monitoring" button.
+          - stop slave state monitoring thread
+        @param event : wx.EVT_BUTTON object
+        """
+        try:
+            self.SlaveStateThread.Stop()
+        except:
+            pass
+        
+#-------------------------------------------------------------------------------
+#                    For SDO Management Panel
+#-------------------------------------------------------------------------------  
+class SDOPanelClass(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent EtherCATManagementTreebook class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Panel.__init__(self, parent, -1)
+        
+        self.DatatypeDescription, self.CommunicationObject, self.ManufacturerSpecific, \
+        self.ProfileSpecific, self.Reserved, self.AllSDOData = range(6)
+        
+        self.Controler = controler
+        
+        self.SDOManagementMainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.SDOManagementInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
+             
+        self.SDOUpdate = wx.Button(self, label=_('update'))          
+        self.SDOUpdate.Bind(wx.EVT_BUTTON, self.SDOInfoUpdate)
+        
+        self.CallSDONoteBook = SDONoteBook(self, controler=self.Controler)
+        self.SDOManagementInnerMainSizer.Add(self.SDOUpdate)
+        self.SDOManagementInnerMainSizer.Add(self.CallSDONoteBook, wx.ALL | wx.EXPAND)           
+
+        self.SDOManagementMainSizer.Add(self.SDOManagementInnerMainSizer)
+        
+        self.SetSizer(self.SDOManagementMainSizer)
+        
+    def SDOInfoUpdate(self, event):
+        """
+        Evenet handler for SDO "update" button.
+          - Load SDO data from current slave 
+        @param event : wx.EVT_BUTTON object
+        """     
+        self.Controler.CommonMethod.SaveSDOData = []
+        self.Controler.CommonMethod.ClearSDODataSet()
+        self.SDOFlag = False
+        
+        # Check whether beremiz connected or not.
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        if check_connect_flag:
+            self.SDOs = self.Controler.CommonMethod.GetSlaveSDOFromSlave()
+            # SDOFlag is "False", user click "Cancel" button
+            self.SDOFlag = self.SDOParser() 
+
+            if self.SDOFlag :
+                self.CallSDONoteBook.CreateNoteBook()      
+                self.Refresh()
+    
+    def SDOParser(self):  
+        """
+        Parse SDO data set that obtain "SDOInfoUpdate" Method
+        @return True or False 
+        """       
+
+        slaveSDO_progress = wx.ProgressDialog("Slave SDO Monitoring", "Now Uploading...",
+                               maximum = len(self.SDOs.splitlines()), parent=self,
+                               style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | 
+                                       wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME | 
+                                       wx.PD_AUTO_HIDE | wx.PD_SMOOTH)        
+        
+        # If keep_going flag is False, SDOParser method is stop and return "False".
+        keep_going = True
+        count = 0
+             
+        # SDO data example 
+        # SDO 0x1000, "Device type"
+        # 0x1000:00,r-r-r-,uint32,32 bit,"Device type",0x00020192, 131474
+        for details_line in self.SDOs.splitlines():
+            count += 1
+            line_token = details_line.split("\"")
+            # len(line_token[2]) case : SDO 0x1000, "Device type"
+            if len(line_token[2]) == 0:
+                title_name = line_token[1]
+            # else case : 0x1000:00,r-r-r-,uint32,32 bit,"Device type",0x00020192, 131474
+            else :
+                # line_token = ['0x1000:00,r-r-r-,uint32,32 bit,', 'Device type', ',0x00020192, 131474']
+                token_head, name, token_tail = line_token
+                
+                # token_head = ['0x1000:00', 'r-r-r-', 'uint32', '32 bit', '']
+                token_head = token_head.split(",")
+                ful_idx, access, type, size, empty = token_head
+                # ful_idx.split(":") = ['0x1000', '00']
+                idx, sub_idx = ful_idx.split(":")
+                
+                # token_tail = ['', '0x00020192', '131474']
+                token_tail = token_tail.split(",")
+                try :
+                    empty, hex_val, dec_val = token_tail
+                    
+                # SDO data is not return "dec value"
+                # line example : 
+                # 0x1702:01,rwr-r-,uint32,32 bit," 1st mapping", ---- 
+                except :
+                    empty, hex_val = token_tail
+                
+                name_after_check = self.StringTest(name)
+                
+                # convert hex type
+                sub_idx = "0x" + sub_idx
+
+                if type == "octet_string":
+                    hex_val = ' ---- '
+            
+                # SResult of SlaveSDO data parsing. (data type : dictionary)
+                self.Data = {'idx':idx.strip(), 'subIdx':sub_idx.strip(), 'access':access.strip(), 
+                             'type':type.strip(), 'size':size.strip(),  'name':name_after_check.strip("\""), 
+                             'value':hex_val.strip(), "category":title_name.strip("\"")}
+                
+                category_divide_value = [0x1000, 0x2000, 0x6000, 0xa000, 0xffff]
+
+                for count in range(len(category_divide_value)) :
+                    if int(idx, 0) < category_divide_value[count]:
+                        self.Controler.CommonMethod.SaveSDOData[count].append(self.Data)
+                        break
+                
+                self.Controler.CommonMethod.SaveSDOData[self.AllSDOData].append(self.Data)
+                      
+            if count >= len(self.SDOs.splitlines()) / 2:
+                (keep_going, skip) = slaveSDO_progress.Update(count, "Please waiting a moment!!")
+            else:
+                (keep_going, skip) = slaveSDO_progress.Update(count)
+                
+            # If user click "Cancel" loop suspend immediately 
+            if (keep_going == False):
+                break
+            
+        slaveSDO_progress.Destroy()      
+        return keep_going  
+
+    def StringTest(self, check_string):
+        """
+        Test value 'name' is alphanumeric  
+        @param check_string : input data for check 
+        @return result : output data after check
+        """  
+        # string.printable is print this result
+        #'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+        #!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c
+        allow_range = string.printable
+        result = check_string
+        for i in range(0, len(check_string)):
+            # string.isalnum() is check whether string is alphanumeric or not
+            if check_string[len(check_string)-1-i:len(check_string)-i] in allow_range :
+                result = check_string[:len(check_string) - i]
+                break
+        return result
+    
+    
+#-------------------------------------------------------------------------------
+#                    For SDO Notebook (divide category)
+#-------------------------------------------------------------------------------  
+class SDONoteBook(wx.Notebook):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent SDOPanelClass class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Notebook.__init__(self, parent, id = -1, size=(850,500))      
+        self.Controler = controler
+        self.parent = parent
+        
+        self.CreateNoteBook()
+        
+        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
+        
+    def CreateNoteBook(self): 
+        """
+        Create each NoteBook page, divided SDO index
+        According to EtherCAT Communication(03/2011), 158p
+        """   
+        self.Data = []
+        count = 1
+        
+        page_texts = [("all", self.parent.AllSDOData),
+                     ("0x0000 - 0x0ff", self.parent.DatatypeDescription),
+                     ("0x1000 - 0x1fff", self.parent.CommunicationObject),
+                     ("0x2000 - 0x5fff", self.parent.ManufacturerSpecific),
+                     ("0x6000 - 0x9fff", self.parent.ProfileSpecific),
+                     ("0xa000 - 0xffff", self.parent.Reserved)]
+
+        page_tooltip_string = ["SDO Index 0x0000 - 0x0fff : Data Type Description",
+                               "SDO Index 0x1000 - 0x1fff : Communication object",
+                               "SDO Index 0x2000 - 0x5fff : Manufacturer specific",
+                               "SDO Index 0x6000 - 0x9fff : Profile specific",
+                               "SDO Index 0xa000 - 0xffff : Reserved",
+                               "All SDO Object"]
+
+        self.DeleteAllPages()
+        
+        for txt, count in page_texts:
+            self.Data = self.Controler.CommonMethod.SaveSDOData[count]
+            self.Win = SlaveSDOTable(self, self.Data) 
+            self.AddPage(self.Win, txt)
+        
+    def OnPageChanged(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()
+
+#-------------------------------------------------------------------------------
+#                    For SDO Grid (fill index, subindex, etc...)
+#-------------------------------------------------------------------------------  
+class SlaveSDOTable(wx.grid.Grid):  
+    def __init__(self, parent, data):
+        """
+        Constructor
+        @param parent: Reference to the parent SDOPanelClass class
+        @param data: SDO data after parsing "SDOParser" method
+        """
+        wx.grid.Grid.__init__(self, parent, -1, size=(830,490), 
+                              style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+        
+        self.Controler = parent.Controler
+        self.parent = parent
+        self.SDOFlag = True
+        if data is None :
+            self.SDOs = []
+        else :
+            self.SDOs = data
+        
+        self.CreateGrid(len(self.SDOs), 8)
+        SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 55), 
+                         (4, 40), (5, 200), (6, 250), (7, 85)]
+        
+        for (index, size) in SDOCellSize:
+            self.SetColSize(index, size)
+        
+        self.SetRowLabelSize(0)
+        
+        SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
+                         (3, "Type"), (4, "Size"), (5, "Category"),
+                         (6, "Name"), (7, "Value")]
+        
+        for (index, label) in SDOTableLabel:
+            self.SetColLabelValue(index, label)
+            self.SetColLabelAlignment(index, wx.ALIGN_CENTRE)
+            
+        attr = wx.grid.GridCellAttr()
+
+        # for SDO download 
+        self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.SDOModifyDialog)
+        
+        for i in range(7): 
+            self.SetColAttr(i,attr)                   
+        
+        self.SetColLabelAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)
+            
+        self.SetTableValue()  
+             
+    def SetTableValue(self):
+        """
+        Cell is filled by new parsing data
+        """
+        sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'category', 'name', 'value']
+        for row_idx in range(len(self.SDOs)):
+            for col_idx in range(len(self.SDOs[row_idx])):          
+                self.SetCellValue(row_idx, col_idx, self.SDOs[row_idx][sdo_list[col_idx]])
+                self.SetReadOnly(row_idx, col_idx, True)
+                if col_idx < 5 :
+                    self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
+        
+    def CheckSDODataAccess(self, row):
+        """
+        CheckSDODataAccess method is checking that access data has "w"
+        Access field consist 6 char, if mean
+           rw      rw     rw
+        (preop) (safeop) (op) 
+        Example Access field : rwrwrw, rwrw-- 
+        @param row : Selected cell by user
+        @return Write_flag : If data has "w", flag is true
+        """
+        write_flag = False
+        check = self.SDOs[row]['access']
+        if check[1:2] == 'w' :
+            self.Controler.CommonMethod.Check_PREOP = True
+            write_flag = True
+        if check[3:4] == 'w' : 
+            self.Controler.CommonMethod.Check_SAFEOP = True
+            write_flag = True
+        if check[5:] =='w' :
+            self.Controler.CommonMethod.Check_OP = True
+            write_flag = True
+            
+        return write_flag
+    
+    def DecideSDODownload(self, state):
+        """
+        compare current state and "access" field, 
+        result notify SDOModifyDialog method
+        @param state : current slave state
+        @return True or False
+        """
+        # Example of 'state' parameter : "0  0:0  PREOP  +  EL9800 (V4.30) (PIC24, SPI, ET1100)" 
+        state = state[self.Controler.GetSlavePos()].split("  ")[2]
+        if state == "PREOP" and self.Controler.CommonMethod.Check_PREOP :
+            return True
+        elif state == "SAFEOP" and self.Controler.CommonMethod.Check_SAFEOP :
+            return True
+        elif state == "OP" and self.Controler.CommonMethod.Check_OP :
+            return True
+        
+        return False
+    
+    def ClearStateFlag(self):
+        """
+        Initialize StateFlag
+        StateFlag is notice SDOData access each slave state
+        """
+        self.Controler.CommonMethod.Check_PREOP = False
+        self.Controler.CommonMethod.Check_SAFEOP = False
+        self.Controler.CommonMethod.Check_OP = False
+    
+    def SDOModifyDialog (self, event):
+        """
+        Create dialog for SDO value modify
+        if user enter data, perform command "ethercat download"  
+        @param event : gridlib.EVT_GRID_CELL_LEFT_DCLICK object
+        """
+        self.ClearStateFlag()
+        
+        # CheckSDODataAccess is checking that OD(Object Dictionary) has "w" 
+        if event.GetCol() == 7 and self.CheckSDODataAccess(event.GetRow()) :    
+            dlg = wx.TextEntryDialog (self, "Enter hex or dec value (if enter dec value, it automatically conversed hex value)",
+                                      "SDOModifyDialog", style = wx.OK | wx.CANCEL)
+
+            start_value = self.GetCellValue(event.GetRow(), event.GetCol()) 
+            dlg.SetValue(start_value)
+            
+            if dlg.ShowModal() == wx.ID_OK:
+                try :
+                    int(dlg.GetValue(), 0)
+                    # check "Access" field
+                    if self.DecideSDODownload(self.Controler.CommonMethod.SlaveState[self.Controler.GetSlavePos()]) :
+                        # Request "SDODownload"
+                        self.Controler.CommonMethod.SDODownload(self.SDOs[event.GetRow()]['type'], self.SDOs[event.GetRow()]['idx'], 
+                                                   self.SDOs[event.GetRow()]['subIdx'], dlg.GetValue())
+                        self.SetCellValue(event.GetRow(), event.GetCol(), hex(int(dlg.GetValue(), 0)))
+                    else :
+                        self.Controler.CommonMethod.CreateErrorDialog('You cannot SDO download this state')                  
+                # Error occured process of "int(variable)"
+                # User input is not hex, dec value
+                except ValueError:
+                    self.Controler.CommonMethod.CreateErrorDialog('You can input only hex, dec value')    
+
+
+#-------------------------------------------------------------------------------
+#                 For PDO Monitoring Panel
+# PDO Class UI  : Panel -> Choicebook (RxPDO, TxPDO) -> 
+#                 Notebook (PDO Index) -> Grid (PDO entry)
+#-------------------------------------------------------------------------------  
+class PDOPanelClass(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent EtherCATManagementTreebook class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Panel.__init__(self, parent, -1)
+        self.Controler = controler
+
+        self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
+        
+        self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)   
+        self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)    
+        
+        self.PDOMonitoringEditorMainSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
+        
+        self.SetSizer(self.PDOMonitoringEditorMainSizer)
+
+    def PDOInfoUpdate(self):
+        """
+        Call RequestPDOInfo method and create Choicebook
+        """
+        self.Controler.CommonMethod.RequestPDOInfo()
+        self.CallPDOChoicebook.Destroy()
+        self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)
+        self.Refresh()
+
+
+#-------------------------------------------------------------------------------
+#                    For PDO Choicebook (divide Tx, Rx PDO)
+#-------------------------------------------------------------------------------  
+class PDOChoicebook(wx.Choicebook):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent PDOPanelClass class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Choicebook.__init__(self, parent, id=-1, size=(500, 500), style=wx.CHB_DEFAULT)
+        self.Controler = controler
+        
+        RxWin = PDONoteBook(self, controler=self.Controler, name="Rx")
+        TxWin = PDONoteBook(self, controler=self.Controler, name="Tx")
+        self.AddPage(RxWin, "RxPDO")
+        self.AddPage(TxWin, "TxPDO")
+        
+        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
+        
+    def OnPageChanged(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()     
+
+
+#-------------------------------------------------------------------------------
+#                    For PDO Notebook (divide PDO index)
+#-------------------------------------------------------------------------------  
+class PDONoteBook(wx.Notebook):
+    def __init__(self, parent, name, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent PDOChoicebook class
+        @param name: identifier whether RxPDO or TxPDO
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Notebook.__init__(self, parent, id=-1, size=(640, 400))
+        self.Controler = controler
+        
+        count = 0
+        page_texts = []
+        
+        self.Controler.CommonMethod.RequestPDOInfo()
+        
+        if name == "Tx" :
+            # obtain pdo_info and pdo_entry
+            # pdo_info include (PDO index, name, number of entry)
+            pdo_info =  self.Controler.CommonMethod.GetTxPDOCategory()
+            pdo_entry = self.Controler.CommonMethod.GetTxPDOInfo()
+            for tmp in pdo_info :
+                title = str(hex(tmp['pdo_index']))
+                page_texts.append(title)
+        # RX PDO case
+        else :  
+            pdo_info = self.Controler.CommonMethod.GetRxPDOCategory()
+            pdo_entry = self.Controler.CommonMethod.GetRxPDOInfo()
+            for tmp in pdo_info :
+                title = str(hex(tmp['pdo_index']))
+                page_texts.append(title)
+               
+        # Add page depending on the number of pdo_info
+        for txt in page_texts:
+            win = PDOEntryTable(self, pdo_info, pdo_entry, count)
+            self.AddPage(win, txt)
+            count += 1  
+
+        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
+        
+    def OnPageChanged(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()     
+
+
+#-------------------------------------------------------------------------------
+#                    For PDO Grid (fill entry index, subindex etc...)
+#-------------------------------------------------------------------------------  
+class PDOEntryTable(wx.grid.Grid):
+    def __init__(self, parent, info, entry, count):
+        """
+        Constructor
+        @param parent: Reference to the parent PDONoteBook class
+        @param info : data structure including entry index, sub index, name, length, type
+        @param entry : data structure including index, name, entry number
+        @param count : page number
+        """
+        wx.grid.Grid.__init__(self, parent, -1, size=(500, 400), pos=wx.Point(0,0), 
+                              style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+        
+        self.Controler = parent.Controler
+        
+        self.PDOInfo = info
+        self.PDOEntry = entry
+        self.Count = count
+        
+        self.CreateGrid(self.PDOInfo[self.Count]['number_of_entry'], 5)
+        self.SetColLabelSize(25)   
+        self.SetRowLabelSize(0)
+        
+        PDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Length"),
+                         (3, "Type"), (4, "Name")]
+        
+        for (index, label) in PDOTableLabel:
+            self.SetColLabelValue(index, label)
+        
+        PDOCellSize = [(0, 45), (1, 65), (2, 55), (3, 40), (4, 300)]
+        
+        for (index, size) in PDOCellSize:
+            self.SetColSize(index, size)
+            self.SetColLabelAlignment(index, wx.ALIGN_LEFT)
+        
+        attr = wx.grid.GridCellAttr()
+        
+        for i in range(5):
+            self.SetColAttr(i, attr)
+         
+        self.SetTableValue()
+            
+    def SetTableValue(self):
+        """
+        Cell is filled by new parsing data in XML
+        """
+        list_index = 0
+        # number of entry
+        for i in range(self.Count + 1) :
+            list_index += self.PDOInfo[i]['number_of_entry']
+
+        start_value = list_index - self.PDOInfo[self.Count]['number_of_entry']
+        
+        pdo_list = ['entry_index', 'subindex', 'bitlen', 'type', 'name']
+        for row_idx in range(self.PDOInfo[self.Count]['number_of_entry']):
+            for col_idx in range(len(self.PDOEntry[row_idx])):
+                # entry index is converted hex value.
+                if col_idx == 0 :
+                    self.SetCellValue(row_idx, col_idx, hex(self.PDOEntry[start_value][pdo_list[col_idx]]))
+                else :
+                    self.SetCellValue(row_idx, col_idx, str(self.PDOEntry[start_value][pdo_list[col_idx]]))
+                if col_idx != 4 :
+                    self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
+                else :
+                    self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
+                self.SetReadOnly(row_idx, col_idx, True)
+                self.SetRowSize(row_idx, 25)
+            start_value += 1
+
+
+#-------------------------------------------------------------------------------
+#                    For EEPROM Access Main Panel 
+#                 (This class explain EEPROM Access)
+#-------------------------------------------------------------------------------  
+class EEPROMAccessPanel(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent EtherCATManagementTreebook class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Panel.__init__(self, parent, -1)
+        sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
+        
+        line = wx.StaticText(self, -1, "\n  EEPROM Access is composed to SmartView and HexView. \
+                                              \n\n   - SmartView shows Config Data, Device Identity, Mailbox settings, etc. \
+                                              \n\n   - HexView shows EEPROM's contents.")
+        
+        sizer.Add(line)
+        
+        self.SetSizer(sizer)
+
+
+#-------------------------------------------------------------------------------
+#                    For Smart View Panel 
+#-------------------------------------------------------------------------------  
+class SlaveSiiSmartView(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent EtherCATManagementTreebook class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Panel.__init__(self, parent, -1)
+        self.parent = parent
+        self.Controler = controler
+        
+        self.PDIType = {0  :['none', '00000000'], 
+                        4  :['Digital I/O', '00000100'],
+                        5  :['SPI Slave', '00000101'],
+                        7  :['EtherCAT Bridge (port3)', '00000111'],
+                        8  :['uC async. 16bit', '00001000'],
+                        9  :['uC async. 8bit', '00001001'],
+                        10 :['uC sync. 16bit', '00001010'],
+                        11 :['uC sync. 8bit', '00001011'],
+                        16 :['32 Digtal Input and 0 Digital Output', '00010000'],
+                        17 :['24 Digtal Input and 8 Digital Output', '00010001'],
+                        18 :['16 Digtal Input and 16 Digital Output','00010010'],
+                        19 :['8 Digtal Input and 24 Digital Output', '00010011'],
+                        20 :['0 Digtal Input and 32 Digital Output', '00010100'],
+                        128:['On-chip bus', '11111111']
+                        }
+        
+        sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5)
+        button_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5)
+
+        for button, mapping_method in [("Write EEPROM", self.WriteToEEPROM),
+                                       ("Read EEPROM", self.ReadFromEEPROM)]:
+            btn = wx.Button(self, -1, button, size=(150, 40))
+            button_sizer.Add(btn, border=10, flag=wx.ALL)
+            btn.Bind(wx.EVT_BUTTON, mapping_method)
+        
+        self.TreeListCtrl = SmartViewTreeListCtrl(self, self.Controler)
+        
+        sizer.Add(button_sizer, border=10, flag=wx.ALL)
+        sizer.Add(self.TreeListCtrl, border=10, flag=wx.ALL)
+        self.SetSizer(sizer)
+        
+        self.Create_SmartView()
+        
+    def Create_SmartView(self):
+        """
+        SmartView shows information based on XML as initial value.
+        """  
+        self.Controler.CommonMethod.SmartViewInfosFromXML = self.Controler.CommonMethod.GetSmartViewInfos()
+        self.SetXMLData()
+                
+    def WriteToEEPROM(self, event):
+        """
+        Open binary file (user select) and write the selected binary data to EEPROM
+        @param event : wx.EVT_BUTTON object
+        """  
+        # Check whether beremiz connected or not, and whether status is "Started" or not.
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        if check_connect_flag:
+            status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
+            if status is not "Started":
+                dialog = wx.FileDialog(self, _("Choose a binary file"), os.getcwd(), "",  _("bin files (*.bin)|*.bin"), wx.OPEN)
+                
+                if dialog.ShowModal() == wx.ID_OK:
+                    filepath = dialog.GetPath()
+                    try:
+                        binfile = open(filepath,"rb")
+                        self.SiiBinary = binfile.read()
+                        dialog.Destroy()
+                        
+                        self.Controler.CommonMethod.SiiWrite(self.SiiBinary)
+                        # refresh data structure kept by master
+                        self.Controler.CommonMethod.Rescan()
+                        # save binary data as inner global data of beremiz 
+                        # for fast loading when slave plugin node is reopened.
+                        self.Controler.CommonMethod.SiiData = self.SiiBinary
+                        self.SetEEPROMData()
+                    except:
+                        self.Controler.CommonMethod.CreateErrorDialog('The file does not exist!')
+                        dialog.Destroy()
+    
+    def ReadFromEEPROM(self, event):
+        """
+        Refresh displayed data based on slave EEPROM and save binary file through dialog
+        @param event : wx.EVT_BUTTON object
+        """  
+        # Check whether beremiz connected or not.
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        if check_connect_flag:
+            self.SiiBinary = self.Controler.CommonMethod.LoadData()
+            self.SetEEPROMData()
+            dialog = wx.FileDialog(self, _("Save as..."), os.getcwd(), 
+                                   "slave0.bin",  _("bin files (*.bin)|*.bin|All files|*.*"), 
+                                   wx.SAVE|wx.OVERWRITE_PROMPT)
+        
+            if dialog.ShowModal() == wx.ID_OK:
+                filepath = dialog.GetPath()
+                binfile = open(filepath,"wb")
+                binfile.write(self.SiiBinary)
+                binfile.close()
+    
+            dialog.Destroy()
+    
+    def SetXMLData(self):
+        """
+        Set data based on XML initially
+        """  
+        # Config Data: EEPROM Size, PDI Type, Device Emulation
+        # Find PDI Type in pdiType dictionary
+        cnt_pdi_type = self.Controler.CommonMethod.SmartViewInfosFromXML["pdi_type"]
+        for i in self.PDIType.keys():
+            if cnt_pdi_type == i:
+                cnt_pdi_type = self.PDIType[i][0]
+                break
+        #  Set Config Data
+        for treelist, data in [("EEPROM Size (Bytes)", 
+                                str(self.Controler.CommonMethod.SmartViewInfosFromXML["eeprom_size"])),
+                               ("PDI Type", 
+                                cnt_pdi_type),
+                               ("Device Emulation", 
+                                self.Controler.CommonMethod.SmartViewInfosFromXML["device_emulation"])]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
+        
+        # Device Identity: Vendor ID, Product Code, Revision No., Serial No.
+        #  Set Device Identity
+        for treelist, data in [("Vendor ID", self.Controler.CommonMethod.SmartViewInfosFromXML["vendor_id"]),
+                               ("Product Code", self.Controler.CommonMethod.SmartViewInfosFromXML["product_code"]),
+                               ("Revision No.", self.Controler.CommonMethod.SmartViewInfosFromXML["revision_no"]),
+                               ("Serial No.", self.Controler.CommonMethod.SmartViewInfosFromXML["serial_no"])]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
+             
+        # Mailbox: Supported Mailbox, Bootstrap Configuration, Standard Configuration
+        #  Set Mailbox
+        for treelist, data in [("Supported Mailbox", self.Controler.CommonMethod.SmartViewInfosFromXML["supported_mailbox"]),
+                               ("Bootstrap Configuration", ""),
+                               ("Standard Configuration", "")]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)       
+        #  Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+        for treelist, data in [("Receive Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outstart"]),
+                               ("Receive Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outlength"]),
+                               ("Send Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_instart"]),
+                               ("Send Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_inlength"])]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.BootstrapConfig[treelist], data, 1)      
+        #  Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+        for treelist, data in [("Receive Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_outstart"]),
+                               ("Receive Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_outlength"]),
+                               ("Send Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_instart"]),
+                               ("Send Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_inlength"])]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.StandardConfig[treelist], data, 1)
+        
+    def SetEEPROMData(self):
+        """
+        Set data based on slave EEPROM.
+        """  
+        # sii_dict = { Parameter : (WordAddress, WordSize) }
+        sii_dict= { 'PDIControl' :                          ( '0', 1),
+                    'PDIConfiguration' :                    ( '1', 1),
+                    'PulseLengthOfSYNCSignals' :            ( '2', 1),
+                    'ExtendedPDIConfiguration' :            ( '3', 1),
+                    'ConfiguredStationAlias' :              ( '4', 1),
+                    'Checksum' :                            ( '7', 1),
+                    'VendorID' :                            ( '8', 2),
+                    'ProductCode' :                         ( 'a', 2),
+                    'RevisionNumber' :                      ( 'c', 2),
+                    'SerialNumber' :                        ( 'e', 2),
+                    'Execution Delay' :                     ('10', 1),
+                    'Port0Delay' :                          ('11', 1),
+                    'Port1Delay' :                          ('12', 1),
+                    'BootstrapReceiveMailboxOffset' :       ('14', 1),
+                    'BootstrapReceiveMailboxSize' :         ('15', 1),
+                    'BootstrapSendMailboxOffset' :          ('16', 1),
+                    'BootstrapSendMailboxSize' :            ('17', 1),
+                    'StandardReceiveMailboxOffset' :        ('18', 1),
+                    'StandardReceiveMailboxSize' :          ('19', 1),
+                    'StandardSendMailboxOffset' :           ('1a', 1),
+                    'StandardSendMailboxSize' :             ('1b', 1),
+                    'MailboxProtocol' :                     ('1c', 1),
+                    'Size' :                                ('3e', 1),
+                    'Version' :                             ('3f', 1),
+                    'First Category Type/Vendor Specific' : ('40', 1),
+                    'Following Category Word Size' :        ('41', 1),
+                    'Category Data' :                       ('42', 1),
+                }
+        
+        # Config Data: EEPROM Size, PDI Type, Device Emulation
+        # EEPROM's data in address '0x003f' is Size of EEPROM in KBit-1
+        eeprom_size = str((int(self.GetWordAddressData( sii_dict.get('Size'),10 ))+1)/8*1024)
+        # Find PDI Type in pdiType dictionary
+        cnt_pdi_type = int(self.GetWordAddressData( sii_dict.get('PDIControl'),16 ).split('x')[1][2:4], 16)
+        for i in self.PDIType.keys():
+            if cnt_pdi_type == i:
+                cnt_pdi_type = self.PDIType[i][0]
+                break
+        #  Get Device Emulation
+        device_emulation = str(bool(int("{:0>16b}".format(int(self.GetWordAddressData( sii_dict.get('PDIControl'),16 ), 16))[7])))    
+        #  Set Config Data
+        for treelist, data in [("EEPROM Size (Bytes)", eeprom_size),
+                               ("PDI Type", cnt_pdi_type),
+                               ("Device Emulation", device_emulation)]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
+        
+        # Device Identity: Vendor ID, Product Code, Revision No., Serial No.
+        #  Set Device Identity
+        for treelist, data in [("Vendor ID", self.GetWordAddressData( sii_dict.get('VendorID'),16 )),
+                               ("Product Code", self.GetWordAddressData( sii_dict.get('ProductCode'),16 )),
+                               ("Revision No.", self.GetWordAddressData( sii_dict.get('RevisionNumber'),16 )),
+                               ("Serial No.", self.GetWordAddressData( sii_dict.get('SerialNumber'),16 ))]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
+      
+        # Mailbox
+        # EEORPOM's word address '1c' indicates supported mailbox protocol.
+        # each value of mailbox protocol : 
+        # VoE(0x0020), SoE(0x0010), FoE(0x0008), CoE(0x0004), EoE(0x0002), AoE(0x0001)
+        supported_mailbox = ""
+        mailbox_protocol=["VoE,  ", "SoE,  ", "FoE,  ", "CoE,  ", "EoE,  ", "AoE,  "]
+        mailbox_data = "{:0>8b}".format(int(self.GetWordAddressData( sii_dict.get('MailboxProtocol'),16 ), 16))
+        for protocol in range(6):
+            if mailbox_data[protocol+2] == '1':
+                supported_mailbox += mailbox_protocol[protocol]
+        supported_mailbox = supported_mailbox.strip(",  ")
+        #  Set Mailbox
+        for treelist, data in [("Supported Mailbox", supported_mailbox),
+                               ("Bootstrap Configuration", ""),
+                               ("Standard Configuration", "")]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)       
+        #  Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+        for treelist, data in [("Receive Offset", self.GetWordAddressData( sii_dict.get('BootstrapReceiveMailboxOffset'),10 )),
+                               ("Receive Size", self.GetWordAddressData( sii_dict.get('BootstrapReceiveMailboxSize'),10 )),
+                               ("Send Offset", self.GetWordAddressData( sii_dict.get('BootstrapSendMailboxOffset'),10 )),
+                               ("Send Size", self.GetWordAddressData( sii_dict.get('BootstrapSendMailboxSize'),10 ))]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.BootstrapConfig[treelist], data, 1)      
+        #  Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
+        for treelist, data in [("Receive Offset", self.GetWordAddressData( sii_dict.get('StandardReceiveMailboxOffset'),10 )),
+                               ("Receive Size", self.GetWordAddressData( sii_dict.get('StandardReceiveMailboxSize'),10 )),
+                               ("Send Offset", self.GetWordAddressData( sii_dict.get('StandardSendMailboxOffset'),10 )),
+                               ("Send Size", self.GetWordAddressData( sii_dict.get('StandardSendMailboxSize'),10 ))]:
+            self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.StandardConfig[treelist], data, 1)         
+                
+    def MakeStaticBoxSizer(self, boxlabel):
+        """
+        Make StaticBoxSizer
+        @param boxlabel : label of box sizer
+        @return sizer : the StaticBoxSizer labeled 'boxlabel'
+        """
+        box = wx.StaticBox(self, -1, boxlabel)
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        return sizer
+        
+    def GetWordAddressData(self, dict_tuple, format):
+        """
+        This method converts word address data from EEPROM binary.
+        @param dict_tuple : element of 'sii_dict' dictionary in SetEEPROMData()
+        @param format : format of data. It can be 16(hex), 10(decimal) and 2(binary).
+        @return formatted value
+        """  
+        offset = int(str(dict_tuple[0]), 16) * 2
+        length = int(str(dict_tuple[1]), 16) * 2
+        list = []
+        data = ''
+        for index in range(length):
+            hexdata = hex(ord(self.SiiBinary[offset + index]))[2:]
+            list.append(hexdata.zfill(2))
+            
+        list.reverse()
+        data = list[0:length]
+
+        if format == 16:
+            return '0x' + ''.join(data) 
+        elif format == 10:
+            return str(int(str(''.join(data)), 16))
+        elif format == 2: 
+            ''.join(data)           
+
+
+#-------------------------------------------------------------------------------
+#                    For Smart View TreeListCtrl
+#-------------------------------------------------------------------------------  
+class SmartViewTreeListCtrl(wx.Panel):
+    def __init__(self, parent, Controler):
+        """
+        Constructor
+        @param parent: Reference to the parent SlaveSiiSmartView class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+
+        wx.Panel.__init__(self, parent, -1, size=(350, 500))
+        
+        self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=(350, 500), 
+                                           style=wx.TR_DEFAULT_STYLE
+                                                |wx.TR_FULL_ROW_HIGHLIGHT
+                                                |wx.TR_HIDE_ROOT
+                                                |wx.TR_COLUMN_LINES
+                                                |wx.TR_ROW_LINES)
+        
+        self.Tree.AddColumn("Description", width=200)
+        self.Tree.AddColumn("Value", width=140)
+        self.Tree.SetMainColumn(0)
+        
+        self.Root = self.Tree.AddRoot("")
+        
+        # Add item
+        #  Level 1 nodes
+        self.Level1Nodes = {}
+        for lv1 in ["Config Data", "Device Identity", "Mailbox"]:
+            self.Level1Nodes[lv1] = self.Tree.AppendItem(self.Root, lv1)
+        
+        #  Level 2 nodes
+        #   Config Data
+        self.ConfigData = {}
+        for lv2 in ["EEPROM Size (Bytes)", "PDI Type", "Device Emulation"]:
+            self.ConfigData[lv2] = self.Tree.AppendItem(self.Level1Nodes["Config Data"], lv2)
+        #   Device Identity
+        self.DeviceIdentity = {}
+        for lv2 in ["Vendor ID", "Product Code", "Revision No.", "Serial No."]:
+            self.DeviceIdentity[lv2] = self.Tree.AppendItem(self.Level1Nodes["Device Identity"], lv2)
+        #   Mailbox
+        self.Mailbox = {}
+        for lv2 in ["Supported Mailbox", "Bootstrap Configuration", "Standard Configuration"]:
+            self.Mailbox[lv2] = self.Tree.AppendItem(self.Level1Nodes["Mailbox"], lv2)
+        
+        #  Level 3 nodes
+        #   Children of Bootstrap Configuration
+        self.BootstrapConfig = {}
+        for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
+            self.BootstrapConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Bootstrap Configuration"], lv3)
+        #   Children of Standard Configuration
+        self.StandardConfig = {}
+        for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
+            self.StandardConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Standard Configuration"], lv3)
+        
+        # Expand Tree
+        for tree in [self.Root, 
+                     self.Level1Nodes["Config Data"], 
+                     self.Level1Nodes["Device Identity"], 
+                     self.Level1Nodes["Mailbox"],
+                     self.Mailbox["Bootstrap Configuration"], 
+                     self.Mailbox["Standard Configuration"]]:
+            self.Tree.Expand(tree)
+
+
+#-------------------------------------------------------------------------------
+#                         For Hex View Panel
+#            shows EEPROM binary as hex data and characters.
+#-------------------------------------------------------------------------------  
+class HexView(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the parent EtherCATManagementTreebook class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Panel.__init__(self, parent, -1)
+        self.parent = parent
+        self.Controler = controler
+                
+        self.HexRow = 8
+        self.HexCol = 17
+        
+        self.HexViewSizer = {"view" : wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10),
+                             "siiButton" : wx.BoxSizer()}
+        self.HexViewButton = {}
+
+        for key, evt_handler in [("Sii Upload", self.OnButtonSiiUpload),
+                                ("Sii Download", self.OnButtonSiiDownload),
+                                ("Write to File", self.OnButtonWriteToBinFile),
+                                ("Read from File", self.OnButtonReadFromBinFile),
+                                ("XML to EEPROM Image", self.OnButtonXmlToEEPROMImg)]:
+            self.HexViewButton[key] = wx.Button(self, -1, key) 
+            self.HexViewButton[key].Bind(wx.EVT_BUTTON, evt_handler)
+            self.HexViewSizer["siiButton"].Add(self.HexViewButton[key])
+
+        self.SiiBinary = self.Controler.CommonMethod.XmlToEeprom()
+        self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
+        self.SiiGrid = SiiGridTable(self, self.Controler, self.HexRow, self.HexCol)
+        self.HexViewSizer["view"].AddMany([self.HexViewSizer["siiButton"], self.SiiGrid]) 
+        self.SiiGrid.CreateGrid(self.HexRow, self.HexCol)
+        self.SetSizer(self.HexViewSizer["view"])     
+        self.HexViewSizer["view"].FitInside(self.parent.parent)
+        self.parent.parent.FitInside()
+        self.SiiGrid.SetValue(self.HexCode)
+        self.SiiGrid.Update()
+
+    def UpdateSiiGridTable(self, row, col):
+        """
+        Destroy existing grid and recreate
+        @param row, col : Hex View grid size
+        """  
+        self.HexViewSizer["view"].Detach(self.SiiGrid)
+        self.SiiGrid.Destroy()
+        self.SiiGrid = SiiGridTable(self, self.Controler, row, col)
+        self.HexViewSizer["view"].Add(self.SiiGrid)
+        self.SiiGrid.CreateGrid(row, col)
+        self.SetSizer(self.HexViewSizer["view"])
+        self.HexViewSizer["view"].FitInside(self.parent.parent)
+        self.parent.parent.FitInside()
+
+    def OnButtonSiiUpload(self, event):
+        """
+        Load EEPROM data from slave and refresh Hex View grid
+        Binded to 'Sii Upload' button.
+        @param event : wx.EVT_BUTTON object
+        """  
+        # Check whether beremiz connected or not.
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        if check_connect_flag:
+            # load from EEPROM data and parsing
+            self.SiiBinary = self.Controler.CommonMethod.LoadData()
+            self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
+            self.UpdateSiiGridTable(self.HexRow, self.HexCol)
+            self.SiiGrid.SetValue(self.HexCode)
+            self.SiiGrid.Update()
+            
+    def OnButtonSiiDownload(self, event):
+        """
+        Write current EEPROM data to slave and refresh data structure kept by master 
+        Binded to 'Sii Download' button.
+        @param event : wx.EVT_BUTTON object
+        """  
+        # Check whether beremiz connected or not, 
+        # and whether status is "Started" or not. 
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        if check_connect_flag:
+            status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
+            if status is not "Started":
+                self.Controler.CommonMethod.SiiWrite(self.SiiBinary)
+                self.Controler.CommonMethod.Rescan()
+        
+    def OnButtonWriteToBinFile(self, event):
+        """ 
+        Save current EEPROM data to binary file through FileDialog
+        Binded to 'Write to File' button.
+        @param event : wx.EVT_BUTTON object
+        """ 
+        dialog = wx.FileDialog(self, _("Save as..."), os.getcwd(), "slave0.bin",  
+                               _("bin files (*.bin)|*.bin|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT)
+
+        if dialog.ShowModal() == wx.ID_OK:
+            filepath = dialog.GetPath()
+            binfile = open(filepath,"wb")
+            binfile.write(self.SiiBinary)
+            binfile.close()
+    
+        dialog.Destroy()  
+    
+    def OnButtonReadFromBinFile(self, event):
+        """
+        Load binary file through FileDialog
+        Binded to 'Read from File' button.
+        @param event : wx.EVT_BUTTON object
+        """
+        dialog = wx.FileDialog(self, _("Choose a binary file"), os.getcwd(), "",  
+                               _("bin files (*.bin)|*.bin"), wx.OPEN)
+        
+        if dialog.ShowModal() == wx.ID_OK:
+            filepath = dialog.GetPath()
+            
+            try:
+                binfile = open(filepath, "rb")
+                self.SiiBinary = binfile.read()
+                self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
+                self.UpdateSiiGridTable(self.HexRow, self.HexCol)
+                self.SiiGrid.SetValue(self.HexCode)
+                self.SiiGrid.Update()
+            except:
+                self.Controler.CommonMethod.CreateErrorDialog('The file does not exist!')
+            
+        dialog.Destroy()
+            
+    def OnButtonXmlToEEPROMImg(self, event):
+        """
+        Create EEPROM data based XML data that current imported
+        Binded to 'XML to EEPROM' button.
+        @param event : wx.EVT_BUTTON object
+        """
+        self.SiiBinary = self.Controler.CommonMethod.XmlToEeprom()
+        self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
+        self.UpdateSiiGridTable(self.HexRow, self.HexCol)
+        self.SiiGrid.SetValue(self.HexCode)
+        self.SiiGrid.Update()
+
+
+#-------------------------------------------------------------------------------
+#                    For Hex View grid (fill hex data)
+#-------------------------------------------------------------------------------  
+class SiiGridTable(wx.grid.Grid):  
+    def __init__(self, parent, controler, row, col):
+        """
+        Constructor
+        @param parent: Reference to the parent HexView class
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        @param row, col: Hex View grid size
+        """
+        self.parent = parent
+        self.Controler = controler
+        self.Row = row
+        self.Col = col    
+        
+        wx.grid.Grid.__init__(self, parent, -1, size=(830,450), 
+                              style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
+
+    def SetValue(self, value):
+        """
+        Set data in the table
+        @param value: EEPROM data list of which element is 1 Byte hex data
+        """
+        # set label name and size
+        self.SetRowLabelSize(100)
+        for col in range(self.Col):
+            if col == 16:
+                self.SetColLabelValue(16, "Text View")
+                self.SetColSize(16, (self.GetSize().x-120)*4/20)
+            else:
+                self.SetColLabelValue(col, '%s'%col)
+                self.SetColSize(col, (self.GetSize().x-120)/20)
+            
+        # set data into table
+        row = col = 0
+        for row_idx in value: 
+            col = 0
+            self.SetRowLabelValue(row, "0x"+"{:0>4x}".format(row*(self.Col-1)))
+            for hex in row_idx:
+                self.SetCellValue(row, col, hex)
+                
+                if col == 16: 
+                    self.SetCellAlignment(row, col, wx.ALIGN_LEFT, wx.ALIGN_CENTER)
+                else:
+                    self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
+                    
+                self.SetReadOnly(row, col, True)
+                col = col + 1
+            row = row + 1
+        
+
+#-------------------------------------------------------------------------------
+#                    For Register Access Panel
+#-------------------------------------------------------------------------------  
+class RegisterAccessPanel(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+	    Constructor
+	    @param parent: EEPROMAccessPanel object
+	    @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+	    """
+        self.parent = parent
+        self.Controler = controler
+        self.__init_data()
+        
+        wx.Panel.__init__(self, parent, -1)
+        
+        sizer = wx.FlexGridSizer(cols=1, hgap=20, rows=2, vgap=5)
+        button_sizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10)
+        
+        self.ReloadButton = wx.Button(self, -1, "Reload")
+        self.CompactViewCheckbox = wx.CheckBox(self, -1, "Compact View")        
+        self.RegisterNotebook = RegisterNotebook(self, self.Controler)
+        
+        button_sizer.AddMany([self.ReloadButton, self.CompactViewCheckbox])
+        sizer.AddMany([button_sizer, self.RegisterNotebook])
+        self.SetSizer(sizer)
+        
+        self.ReloadButton.Bind(wx.EVT_BUTTON, self.OnReloadButton)
+        self.CompactViewCheckbox.Bind(wx.EVT_CHECKBOX, self.ToggleCompactViewCheckbox)
+        
+        for index in range(4):
+            self.RegisterNotebook.RegPage[index].MainTable.CreateGrid(self.MainRow[index], self.MainCol)
+            self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, 0, index*512, (index+1)*512)
+        
+        # data default setting
+        if self.Controler.CommonMethod.RegData == "": 
+            self.CompactViewCheckbox.Disable() 
+            for index in range(4): 
+                self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, 0, index*512, (index+1)*512)
+        else: # If data was saved,
+            self.BasicSetData()
+            self.ParseData()
+            for index in range(4):
+                self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, self.RegMonitorData, index*512, (index+1)*512)
+
+    def __init_data(self):
+        """
+	    Declare initial data.
+	    """
+        # flag for compact view
+        self.CompactFlag = False
+        
+        # main grid의 rows and cols
+        self.MainRow = [512, 512, 512, 512]
+        self.MainCol = 4
+        
+        # main grids' data range
+        self.PageRange = []
+        for index in range(4):
+            self.PageRange.append([512*index, 512*(index+1)])
+        
+        #  Previous value of register data for register description configuration
+        self.PreRegSpec = {"ESCType": "",
+                           "FMMUNumber": "",
+                           "SMNumber": "",
+                           "PDIType": ""}
+        
+    def LoadData(self):
+        """
+        Get data from the register.
+        """
+        self.Controler.CommonMethod.RegData = ""
+        #ethercat reg_read
+        #ex : ethercat reg_read -p 0 0x0000 0x0001
+        #return value : 0x11
+        for index in range(4):
+            self.Controler.CommonMethod.RegData = self.Controler.CommonMethod.RegData + " " + self.Controler.CommonMethod.RegRead("0x"+"{:0>4x}".format(index*1024), "0x0400")
+        
+        # store previous value 
+        # (ESC type, port number of FMMU, port number of SM, and PDI type))
+        for reg_spec in ["ESCType","FMMUNumber","SMNumber", "PDIType"]:
+            self.PreRegSpec[reg_spec] = self.Controler.CommonMethod.CrtRegSpec[reg_spec]
+        
+        # update registers' description 
+        # (ESC type, port number of FMMU, port number of SM, and PDI type)
+        for reg_spec, address in [("ESCType", "0x0000"),
+                                  ("FMMUNumber", "0x0004"),
+                                  ("SMNumber", "0x0005"),
+                                  ("PDIType", "0x0140")]:
+            self.Controler.CommonMethod.CrtRegSpec[reg_spec] = self.Controler.CommonMethod.RegRead(address, "0x0001")
+                 
+        # Enable compactView checkbox
+        self.CompactViewCheckbox.Enable()
+    
+    def BasicSetData(self):
+        """
+        Get and save the description of registers. 
+        It's done by parsing register_information.xml.
+        """
+        # parse the above register's value
+        # If the value is 0x12, the result is 12
+        self.ESCType = self.Controler.CommonMethod.CrtRegSpec["ESCType"].split('x')[1]
+        self.PDIType = self.Controler.CommonMethod.CrtRegSpec["PDIType"].split('x')[1]
+        # If the value is 0x12, the result is 18 (It's converted to decimal value)
+        self.FMMUNumber = int(self.Controler.CommonMethod.CrtRegSpec["FMMUNumber"], 16)
+        self.SMNumber = int(self.Controler.CommonMethod.CrtRegSpec["SMNumber"], 16)
+        
+        # initialize description dictionary of register main table and register sub table.
+        self.RegisterDescriptionDict = {}
+        self.RegisterSubGridDict = {}
+        
+        # ./EthercatMaster/register_information.xml contains register description.
+        if wx.Platform == '__WXMSW__':
+            reg_info_file = open("../../EthercatMaster/register_information.xml", 'r')
+        else:
+            reg_info_file = open("./EthercatMaster/register_information.xml", 'r')
+        reg_info_tree = minidom.parse(reg_info_file)
+        reg_info_file.close()
+        
+        # parse register description
+        for register_info in reg_info_tree.childNodes:
+            for register in register_info.childNodes:
+                if register.nodeType == reg_info_tree.ELEMENT_NODE and register.nodeName == "Register":
+                    # If it depends on the property(ESC type, PDI type, FMMU number, SM number)
+                    for property, type, value in [("esc", "type", self.ESCType),
+                                                  ("pdi", "type", self.PDIType),
+                                                  ("fmmu", "number", self.FMMUNumber),
+                                                  ("sm", "number", self.SMNumber)]:
+                        if property in register.attributes.keys(): 
+                            if type == "type":
+                                if register.attributes[property].value == value:
+                                    self.GetRegisterInfo(reg_info_tree, register)
+                                    break
+                            else: # type == "number"
+                                if register.attributes[property].value < value:
+                                    self.GetRegisterInfo(reg_info_tree, register)
+                                    break
+                        else:
+                            self.GetRegisterInfo(reg_info_tree, register)
+                            break
+                            
+    def GetRegisterInfo(self, reg_info_tree, register):
+        """
+        Save the register's description into the dictionary.
+        reg_info_tree is based on the register_information.xml.
+        @param reg_info_tree: XML tree
+        @param register: register which you want to get the description
+        """
+        # temporary variables for register main table idescription dictionary
+        reg_index = ""
+        reg_main_description = ""
+        
+        for data in register.childNodes:
+            if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Index":
+                for index in data.childNodes:
+                    reg_index = index.nodeValue
+            if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Description":
+                for description in data.childNodes:
+                    reg_main_description = description.nodeValue
+                    
+            # Add description for register main table 
+            if reg_index is not "" and reg_main_description is not "":
+                self.RegisterDescriptionDict[reg_index] = reg_main_description
+                    
+            if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Details":
+                # declare register sub table description dictionary about this index
+                self.RegisterSubGridDict[reg_index] = []
+                
+                for detail in data.childNodes:
+                    if detail.nodeType == reg_info_tree.ELEMENT_NODE and detail.nodeName == "Detail":
+                        # If it depends on the property(ESC type, PDI type, FMMU number, SM number)
+                        for property, type, value in [("esc", "type", self.ESCType),
+                                                      ("pdi", "type", self.PDIType),
+                                                      ("fmmu", "number", self.FMMUNumber),
+                                                      ("sm", "number", self.SMNumber)]:
+                            if property in detail.attributes.keys(): 
+                                if type == "type":
+                                    if detail.attributes[property].value == value:
+                                        self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
+                                        break
+                                else: # type == "number"
+                                    if detail.attributes[property].value < value:
+                                        self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
+                                        break
+                            else:
+                                self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
+                                break
+                                          
+    def GetRegisterDetailInfo(self, reg_info_tree, reg_index, detail):
+        """
+        Get the resgister's detailed description(for sub table) from the reg_info_tree.
+        @param reg_info_tree: XML tree (register_information.xml)
+        @param reg_index: index of the register
+        @param detail: description of the register
+        """
+        # temporary variables for register sub table description dictionary 
+        # - It is initialized in every sub description 
+        reg_bit_range = ""
+        reg_sub_description = ""
+        reg_enum_dictionary = {}
+        
+        for detail_data in detail.childNodes:
+            if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Range":                                            
+                for range in detail_data.childNodes:
+                    reg_bit_range = range.nodeValue
+            if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Description":
+                for description in detail_data.childNodes:
+                    reg_sub_description = description.nodeValue
+                    
+            if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Enum":
+                for enum in detail_data.childNodes:
+                    if enum.nodeType == reg_info_tree.ELEMENT_NODE and enum.nodeName == "item":
+                        
+                        # temporary variables for a description of each value 
+                        # For example, if the bit is 1, it is 'enabled'('On', 'True', etc.), 
+                        # otherwise 'disabled'('Off', 'False', etc.). 
+                        reg_sub_value = ""
+                        reg_sub_value_description = ""
+                        
+                        for item in enum.childNodes:
+                            if item.nodeType == reg_info_tree.ELEMENT_NODE and item.nodeName == "value":
+                                for value in item.childNodes:
+                                    reg_sub_value = value.nodeValue
+                            if item.nodeType == reg_info_tree.ELEMENT_NODE and item.nodeName == "Description":
+                                for description in item.childNodes:
+                                    reg_sub_value_description = description.nodeValue
+                                    
+                            # Add a description of each value to register enum dictionary
+                            if reg_sub_value is not "" and reg_sub_value_description is not "":
+                                reg_enum_dictionary[reg_sub_value] = reg_sub_value_description
+                            
+        # add a description to register sub table description dictionary
+        if reg_bit_range is not "" and reg_sub_description is not "":
+            self.RegisterSubGridDict[reg_index].append([reg_bit_range, 
+                                                         reg_sub_description, reg_enum_dictionary])
+    
+    def ParseData(self):
+        """
+        Transform the data into dec, hex, string, and description
+        """
+        row_data = []
+        self.RegMonitorData = []
+        reg_word = ""
+        
+        reg_data = self.Controler.CommonMethod.RegData.split()
+        
+        # loop for register(0x0000:0x0fff)
+        for address in range(0x1000):
+            # arrange 2 Bytes of register data 
+            reg_word = reg_data[address].split('x')[1] + reg_word
+            if (address%2) == 1:
+                # append address
+                hex_address = "{:0>4x}".format(address-1)
+                row_data.append(hex_address)
+                
+                # append description
+                if self.RegisterDescriptionDict.has_key(hex_address):
+                    row_data.append(self.RegisterDescriptionDict[hex_address])
+                else:
+                    row_data.append("")
+                    
+                # append Decimal value
+                row_data.append(str(int(reg_word, 16)))
+                
+                # append Hex value
+                row_data.append('0x'+reg_word)
+                
+                # append ASCII value
+                char_data = ""
+                for iter in range(2):
+                    if int(reg_word[iter*2:iter*2+2], 16)>=32 and int(reg_word[iter*2:iter*2+2], 16)<=126:
+                        char_data = char_data + chr(int(reg_word[iter*2:iter*2+2], 16))
+                    else:
+                        char_data = char_data + "."
+                row_data.append(char_data)
+                
+                self.RegMonitorData.append(row_data)
+                reg_word = "" # initialize regWord
+                row_data = []
+    
+    def OnReloadButton(self, event):
+        """
+        Handle the click event of the 'Reload' button.
+        Get the data from registers again, and update the table.
+        @param event: wx.EVT_BUTTON object
+        """
+        # Check whether beremiz connected or not.
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        if check_connect_flag:
+            self.LoadData()
+            self.BasicSetData()
+            self.ParseData()
+            # set data into UI
+            if self.CompactFlag:
+                self.ToggleCompactViewCheckbox(True)
+            else : 
+                for index in range(4):
+                    self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, 
+                                                                         self.PageRange[index][0], self.PageRange[index][1], 
+                                                                         self.RegMonitorData)
+
+    def ToggleCompactViewCheckbox(self, event):
+        """
+        Handles the event of the 'Compact view' check box.
+        If it's checked, show only the registers that have a description.
+        If not, show all the registers.
+        @param event: wx.EVT_CHECKBOX object
+        """
+        
+        # If "Compact View" Checkbox is True
+        ## 'event' is argument of this method or event of checkbox.
+        if event==True or event.GetEventObject().GetValue():
+            self.CompactFlag = True
+            
+            reg_compact_data = []
+            page_row = [0, 0, 0, 0]
+            for index in range(4):
+                self.PageRange[index] = [0, 0]
+
+            for reg_row_data in self.RegMonitorData:
+                if reg_row_data[1] is not "":
+                    # data structure for "compact view"
+                    reg_compact_data.append(reg_row_data)
+                    # count for each register notebooks' row
+                    # It compare with register's address.
+                    for index in range(4):
+                        if int('0x'+reg_row_data[0], 16) < (index+1)*1024:
+                            page_row[index] += 1
+                            break
+
+            # Setting tables' rows and cols, range for compact view
+            for index in range(4):
+                self.MainRow[index] = page_row[index]
+                self.PageRange[index][1] = page_row[index]
+                for iter in range(index):
+                    self.PageRange[index][0] += page_row[iter]
+                    self.PageRange[index][1] += page_row[iter] 
+                          
+            # Update table
+            for index in range(4):
+                self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, 
+                                                                      self.PageRange[index][0], self.PageRange[index][1], 
+                                                                      reg_compact_data)
+            
+        # Compact View Checkbox is False    
+        else:
+            self.CompactFlag = False
+            # Setting original rows, cols and range
+            self.MainRow = [512, 512, 512, 512]
+            self.PageRange = []
+            
+            for index in range(4):
+                self.PageRange.append([512*index, 512*(index+1)])
+            
+            # Update table 
+            for index in range(4):
+                self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, 
+                                                                      self.PageRange[index][0], self.PageRange[index][1], 
+                                                                      self.RegMonitorData)
+                
+
+#-------------------------------------------------------------------------------
+#                    For Register Access Notebook (divide index range)
+#-------------------------------------------------------------------------------  
+class RegisterNotebook(wx.Notebook):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: RegisterAccessPanel object
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Notebook.__init__(self, parent, id = -1)
+        
+        self.parent = parent
+        self.Controler = controler
+        
+        # Initialize pages
+        self.RegPage = []
+        for iter in range(4):
+            self.RegPage.append(None)
+        
+        for index in range(4):
+            self.RegPage[index] = RegisterNotebookPanel(self, self.Controler, 
+                                                    parent.MainRow[index], parent.MainCol)
+            self.AddPage(self.RegPage[index], 
+                         "0x"+"{:0>4x}".format(index*1024)+" - 0x"+"{:0>4x}".format((index+1)*1024-1))
+        
+        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
+
+    def OnPageChanged(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        old = event.GetOldSelection()
+        new = event.GetSelection()
+        sel = self.GetSelection()
+        event.Skip()
+
+
+#-------------------------------------------------------------------------------
+#                    For Register Access Notebook Panel 
+#                  (Main UI : including main, sub table)
+#-------------------------------------------------------------------------------  
+class RegisterNotebookPanel(wx.Panel):
+    def __init__(self, parent, controler, row, col):
+        """
+        Constructor
+        @param parent: RegisterAccessPanel object
+        @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        @param row, col: size of the table
+    	"""
+        wx.Panel.__init__(self, parent, -1)
+        
+        self.parent = parent
+        self.Controler = controler
+        self.Row = row
+        self.Col = col
+        sub_row = 0
+        sub_col = 4
+        
+        self.Sizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=30)
+        
+        self.MainTable = RegisterMainTable(self, self.Row, self.Col, self.Controler)
+        self.SubTable = RegisterSubTable(self, sub_row, sub_col)
+        
+        self.SubTable.CreateGrid(sub_row, sub_col)
+        self.SubTable.SetValue(self, [])
+        
+        self.Sizer.AddMany([self.MainTable, self.SubTable])
+        
+        self.SetSizer(self.Sizer)
+     
+    def UpdateMainTable(self, row, col, low_index, high_index, data):
+        """
+        Updates main table.
+        It's done by deleting the main table and creating it again.
+        @param row, col: size of the table
+        @param low_index: the lowest index of the page
+        @param high_index: the highest index of the page
+        @param data: data
+    	"""
+        self.MainTable.Destroy()
+        self.MainTable = RegisterMainTable(self, row, col, self.Controler)
+        self.Sizer.Detach(self.SubTable)
+        self.Sizer.AddMany([self.MainTable, self.SubTable])
+        self.SetSizer(self.Sizer)
+        self.MainTable.CreateGrid(row, col)
+        self.MainTable.SetValue(self, data, low_index, high_index)
+        self.MainTable.Update()
+
+    def UpdateSubTable(self, row, col, data):
+        """
+        Updates sub table.
+        It's done by deleting the sub table and creating it again.
+        @param row, col: size of the table
+        @param data: data
+    	"""
+        self.SubTable.Destroy()
+        self.SubTable = RegisterSubTable(self, row, col)
+        self.Sizer.Detach(self.MainTable)
+        self.Sizer.AddMany([self.MainTable, self.SubTable])
+        self.Sizer.Layout()
+        self.SetSizer(self.Sizer)
+        self.SubTable.CreateGrid(row, col)
+        self.SubTable.SetValue(self, data)
+        self.SubTable.Update()
+        
+
+#-------------------------------------------------------------------------------
+#                    For Register Access Notebook Panel (Main Table)
+#-------------------------------------------------------------------------------  
+class RegisterMainTable(wx.grid.Grid):
+    def __init__(self, parent, row, col, controler):        
+        """
+	    Constructor
+	    @param parent: RegisterNotebook object
+	    @param row, col: size of the table
+	    @param controler: _EthercatSlaveCTN class in EthercatSlave.py
+	    """
+        self.parent = parent
+        self.Data = {}
+        self.Row = row
+        self.Col = col
+        self.Controler = controler
+        self.RegisterAccessPanel = self.parent.parent.parent
+        
+        wx.grid.Grid.__init__(self, parent, -1, size=(820,300), 
+                              style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
+        
+        for evt, mapping_method in [(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
+                                    (gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
+                                    (gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnRegModifyDialog)]:
+            self.Bind(evt, mapping_method)
+       
+    def SetValue(self, parent, reg_monitor_data, low_index, high_index):  
+        """
+	    Set the RegMonitorData into the main table.
+	    @param parent: RegisterNotebook object
+	    @param reg_monitor_data: data
+	    @param low_index: the lowest index of the page
+	    @param high_index: the highest index of the page
+	    """
+        self.RegMonitorData = reg_monitor_data
+        
+        # set label name and size
+        register_maintable_label = [(0, "Description"), (1, "Dec"), 
+                                    (2, "Hex"), (3, "Char")]
+        
+        for (index, label) in register_maintable_label:
+            self.SetColLabelValue(index, label)
+        
+        self.SetColSize(0, 200)
+    
+        # if reg_monitor_data is 0, it is initialization of register access.
+        if reg_monitor_data == 0:
+            return 0
+    
+        # set data into UI 
+        row = col = 0
+        for row_index in reg_monitor_data[low_index:high_index]:
+            col = 0
+            self.SetRowLabelValue(row, row_index[0])
+            for data_index in range(4):
+                self.SetCellValue(row, col, row_index[data_index+1])
+                self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
+                self.SetReadOnly(row, col, True)
+                col = col + 1
+            row = row + 1
+    
+    def OnSelectCell(self, event): 
+        """
+	    Handles the event of the cell of the main table.
+	    @param event: gridlib object (left click)
+	    """
+        # if reg_monitor_data is 0, it is initialization of register access.
+        if self.RegMonitorData == 0:
+            event.Skip()
+            return 0
+        
+        sub_row = 0
+        sub_col = 4
+        
+        address = self.GetRowLabelValue(event.GetRow())
+        
+        reg_sub_grid_data = []
+        
+        BIT_RANGE, NAME, DESCRIPTIONS = range(3)
+        
+        # Check if this register's detail description is exist or not, 
+        # and create data structure for the detail description table ; sub grid
+        if address in self.RegisterAccessPanel.RegisterSubGridDict:
+            for element in self.RegisterAccessPanel.RegisterSubGridDict[address]:
+                row_data =[]
+                row_data.append(element[BIT_RANGE])
+                row_data.append(element[NAME])
+                bin_data = "{:0>16b}".format(int(self.GetCellValue(event.GetRow(), 1)))
+                value_range = element[BIT_RANGE].split('-')
+                value = (bin_data[8:16][::-1]+bin_data[0:8][::-1])[int(value_range[0]):(int(value_range[-1])+1)][::-1]
+                row_data.append(str(int(('0b'+str(value)), 2)))
+                if value in element[DESCRIPTIONS]:
+                    row_data.append(element[DESCRIPTIONS][value])
+                else:
+                    row_data.append('')
+                reg_sub_grid_data.append(row_data)
+                sub_row = sub_row + 1
+        
+        self.parent.UpdateSubTable(sub_row, sub_col, reg_sub_grid_data)
+        # event.Skip() updates UI of selecting cell
+        event.Skip()
+    
+    def OnRegModifyDialog(self, event):
+        """
+        Handle the event of the cell of the main table.
+        Display the window where the user modifies the value of the cell.
+        @param event: gridlib object (double click)
+	    """
+        # user can enter a value in case that user double-clicked 'Dec' or 'Hex' value.
+        if event.GetCol() == 1 or event.GetCol() == 2:
+            dlg = wx.TextEntryDialog(self, "Enter hex(0xnnnn) or dec(n) value", 
+                                     "Register Modify Dialog", style = wx.OK|wx.CANCEL)
+            
+            # Setting value in initial dialog value
+            start_value = self.GetCellValue(event.GetRow(), event.GetCol())
+            dlg.SetValue(start_value)
+        
+            if dlg.ShowModal() == wx.ID_OK:
+                try:
+                    # It int(input) success, this input is dev or hex value. 
+                    # Otherwise, it's error, so it goes except.
+                    int(dlg.GetValue(), 0)
+
+                    # reg_write
+                    # ex) ethercat reg_write -p 0 -t uint16 0x0000 0x0000
+                    return_val = self.Controler.CommonMethod.RegWrite('0x'+self.GetRowLabelValue(event.GetRow()), dlg.GetValue())
+
+                    if len(return_val)==0:
+                        # set dec
+                        self.SetCellValue(event.GetRow(), 1, str(int(dlg.GetValue(), 0))) 
+                        # set hex
+                        hex_data = '0x'+"{:0>4x}".format(int(dlg.GetValue(), 0))
+                        self.SetCellValue(event.GetRow(), 2, hex_data)
+                        # set char
+                        char_data = ""
+                        # If hex_data is been able to convert to ascii code, append ascii code.
+                        for iter in range(2):
+                            if int(hex_data[(iter+1)*2:(iter+2)*2], 16)>=32 and int(hex_data[(iter+1)*2:(iter+2)*2], 16)<=126:
+                                char_data = char_data + chr(int(hex_data[(iter+1)*2:(iter+2)*2], 16))
+                            else:
+                                char_data = char_data + "."
+                            
+                        self.SetCellValue(event.GetRow(), 3, char_data) 
+                    
+                    else:
+                        self.Controler.CommonMethod.CreateErrorDialog('You can\'t modify it. This register is read-only or it\'s not connected.')
+                
+                except ValueError:
+                    self.Controler.CommonMethod.CreateErrorDialog('You entered wrong value. You can enter dec or hex value only.')
+        
+    
+#-------------------------------------------------------------------------------
+#                    For Register Access Notebook Panel (Sub Table)
+#-------------------------------------------------------------------------------  
+class RegisterSubTable(wx.grid.Grid):
+    def __init__(self, parent, row, col):
+        """
+    	 Constructor
+    	 @param parent: RegisterNotebook object
+    	 @param row, col: size of the table
+    	"""
+        self.parent = parent
+        self.Data = {}
+        self.Row = row
+        self.Col = col
+
+        wx.grid.Grid.__init__(self, parent, -1, size=(820,150), 
+                              style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
+
+    def SetValue(self, parent, data):
+        """
+	    Set the data into the subtable.
+	    @param parent: RegisterNotebook object
+	    @param data: data
+	    """
+        # lset label name and size
+        Register_SubTable_Label = [(0, "Bits"), (1, "Name"), 
+                                    (2, "Value"), (3, "Enum")]
+        
+        for (index, label) in Register_SubTable_Label:
+            self.SetColLabelValue(index, label)
+        
+        self.SetColSize(1, 200)
+        self.SetColSize(3, 200)
+            
+        # set data into table
+        row = col = 0
+        for rowData in data: 
+            col = 0     
+            for element in rowData:
+                self.SetCellValue(row, col, element)
+                self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
+                self.SetReadOnly(row, col, True)
+                col = col + 1
+            row = row + 1
+                
+
+#-------------------------------------------------------------------------------
+#                    For Master State Panel
+#-------------------------------------------------------------------------------  
+class MasterStatePanelClass(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: wx.ScrollWindow object
+        @Param controler: _EthercatSlaveCTN class in EthercatSlave.py
+        """
+        wx.Panel.__init__(self, parent, -1, (0, 0), 
+                          size=wx.DefaultSize, style = wx.SUNKEN_BORDER)
+        self.Controler = controler
+        self.parent = parent
+        self.StaticBox = {}
+        self.StaticText = {}
+        self.TextCtrl = {}
+          
+        # ----------------------- Main Sizer and Update Button --------------------------------------------
+        self.MasterStateSizer = {"main" : wx.BoxSizer(wx.VERTICAL)}
+        for key, attr in [
+            ("innerMain",           [1, 10, 2, 10]),
+            ("innerTopHalf",        [2, 10, 1, 10]),
+            ("innerBottomHalf",     [2, 10, 1, 10]),
+            ("innerMasterState",    [2, 10, 3, 10]),
+            ("innerDeviceInfo",     [4, 10, 3, 10]),
+            ("innerFrameInfo",      [4, 10, 5, 10])]:
+            self.MasterStateSizer[key] = wx.FlexGridSizer(cols=attr[0], hgap=attr[1], rows=attr[2], vgap=attr[3])
+
+
+        self.UpdateButton = wx.Button(self, label=_('Update'))
+        self.UpdateButton.Bind(wx.EVT_BUTTON, self.OnButtonClick)
+       
+        for key, label in [                
+            ('masterState', 'EtherCAT Master State'),
+            ('deviceInfo', 'Ethernet Network Card Information'),
+            ('frameInfo', 'Network Frame Information')]:
+            self.StaticBox[key] = wx.StaticBox(self, label=_(label))
+            self.MasterStateSizer[key] = wx.StaticBoxSizer(self.StaticBox[key])
+        
+        
+        # ----------------------- Master State -----------------------------------------------------------
+        for key, label in [
+            ('Phase', 'Phase:'),
+            ('Active', 'Active:'),
+            ('Slaves', 'Slave Count:')]:
+            self.StaticText[key] = wx.StaticText(self, label=_(label))
+            self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
+            self.MasterStateSizer['innerMasterState'].AddMany([self.StaticText[key], self.TextCtrl[key]])    
+        
+        self.MasterStateSizer['masterState'].AddSizer(self.MasterStateSizer['innerMasterState'])
+        
+        # ----------------------- Ethernet Network Card Information --------------------------------------- 
+        for key, label in [
+            ('Main', 'MAC Address:'),
+            ('Link', 'Link State:'),
+            ('Tx frames', 'Tx Frames:'),
+            ('Rx frames', 'Rx Frames:'),
+            ('Lost frames', 'Lost Frames:')]:
+            self.StaticText[key] = wx.StaticText(self, label=_(label))
+            self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
+            self.MasterStateSizer['innerDeviceInfo'].AddMany([self.StaticText[key], self.TextCtrl[key]])
+        
+        self.MasterStateSizer['deviceInfo'].AddSizer(self.MasterStateSizer['innerDeviceInfo'])
+        
+        # ----------------------- Network Frame Information -----------------------------------------------
+        for key, label in [
+            ('Tx frame rate [1/s]', 'Tx Frame Rate [1/s]:'), 
+            ('Rx frame rate [1/s]', 'Tx Rate [kByte/s]:'), 
+            ('Loss rate [1/s]', 'Loss Rate [1/s]:'),
+            ('Frame loss [%]', 'Frame Loss [%]:')]:
+            self.StaticText[key] = wx.StaticText(self, label=_(label))
+            self.MasterStateSizer['innerFrameInfo'].Add(self.StaticText[key])
+            self.TextCtrl[key] = {} 
+            for index in ['0', '1', '2']:                
+                self.TextCtrl[key][index] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
+                self.MasterStateSizer['innerFrameInfo'].Add(self.TextCtrl[key][index])
+        
+        self.MasterStateSizer['frameInfo'].AddSizer(self.MasterStateSizer['innerFrameInfo'])
+        
+        # --------------------------------- Main Sizer ----------------------------------------------------
+        for key, sub, in [
+            ('innerTopHalf', [
+                    'masterState', 'deviceInfo']),
+            ('innerBottomHalf', [
+                    'frameInfo']),
+            ('innerMain', [
+                    'innerTopHalf', 'innerBottomHalf'])]:
+            for key2 in sub:
+                self.MasterStateSizer[key].AddSizer(self.MasterStateSizer[key2])
+
+        self.MasterStateSizer['main'].AddSizer(self.UpdateButton)
+        self.MasterStateSizer['main'].AddSizer(self.MasterStateSizer['innerMain'])
+        
+        self.SetSizer(self.MasterStateSizer['main'])
+
+    def OnButtonClick(self, event):
+        """
+        Handle the event of the 'Update' button.
+        Update the data of the master state.
+        @param event: wx.EVT_BUTTON object
+        """
+        if self.Controler.GetCTRoot()._connector is not None:
+            self.MasterState = self.Controler.CommonMethod.GetMasterState()
+            # Update each TextCtrl
+            if self.MasterState:
+                for key in self.TextCtrl:
+                    if isinstance(self.TextCtrl[key], dict):
+                        for index in self.TextCtrl[key]:
+                            self.TextCtrl[key][index].SetValue(self.MasterState[key][int(index)])
+                    else:
+                        self.TextCtrl[key].SetValue(self.MasterState[key][0])
+        else :
+            self.Controler.CommonMethod.CreateErrorDialog('PLC not connected!')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EthercatCFileGenerator.py	Sat Jun 23 09:08:13 2018 +0200
@@ -0,0 +1,568 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz
+#
+# Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT
+#                          RTES Lab : CRKim, JBLee, youcu
+#                          Higen Motor : Donggu Kang
+#
+# See COPYING file for copyrights details.
+
+import os
+
+from EthercatSlave import ExtractHexDecValue, DATATYPECONVERSION, ExtractName
+
+SLAVE_PDOS_CONFIGURATION_DECLARATION = """
+/* Slave %(slave)d, "%(device_type)s"
+ * Vendor ID:       0x%(vendor).8x
+ * Product code:    0x%(product_code).8x
+ * Revision number: 0x%(revision_number).8x
+ */
+
+ec_pdo_entry_info_t slave_%(slave)d_pdo_entries[] = {
+%(pdos_entries_infos)s
+};
+
+ec_pdo_info_t slave_%(slave)d_pdos[] = {
+%(pdos_infos)s
+};
+
+ec_sync_info_t slave_%(slave)d_syncs[] = {
+%(pdos_sync_infos)s
+    {0xff}
+};
+"""
+
+SLAVE_CONFIGURATION_TEMPLATE = """
+    if (!(slave%(slave)d = ecrt_master_slave_config(master, %(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x))) {
+        SLOGF(LOG_CRITICAL, "EtherCAT failed to get slave %(device_type)s configuration at alias %(alias)d and position %(position)d.");
+        goto ecat_failed;
+    }
+
+    if (ecrt_slave_config_pdos(slave%(slave)d, EC_END, slave_%(slave)d_syncs)) {
+        SLOGF(LOG_CRITICAL, "EtherCAT failed to configure PDOs for slave %(device_type)s at alias %(alias)d and position %(position)d.");
+        goto ecat_failed;
+    }
+"""
+
+SLAVE_INITIALIZATION_TEMPLATE = """
+    {
+        uint8_t value[%(data_size)d];
+        EC_WRITE_%(data_type)s((uint8_t *)value, %(data)s);
+        if (ecrt_master_sdo_download(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &abort_code)) {
+            SLOGF(LOG_CRITICAL, "EtherCAT Failed to initialize slave %(device_type)s at alias %(alias)d and position %(position)d. Error: %%d", abort_code);
+            goto ecat_failed;
+        }
+    }
+"""
+
+SLAVE_OUTPUT_PDO_DEFAULT_VALUE = """
+    {
+        uint8_t value[%(data_size)d];
+        if (ecrt_master_sdo_upload(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &result_size, &abort_code)) {
+            SLOGF(LOG_CRITICAL, "EtherCAT failed to get default value for output PDO in slave %(device_type)s at alias %(alias)d and position %(position)d. Error: %%ud", abort_code);
+            goto ecat_failed;
+        }
+        %(real_var)s = EC_READ_%(data_type)s((uint8_t *)value);
+    }
+"""
+
+def ConfigureVariable(entry_infos, str_completion):
+    entry_infos["data_type"] = DATATYPECONVERSION.get(entry_infos["var_type"], None)
+    if entry_infos["data_type"] is None:
+        raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"]
+    
+    if not entry_infos.get("no_decl", False):
+        if entry_infos.has_key("real_var"):
+            str_completion["located_variables_declaration"].append(
+                "IEC_%(var_type)s %(real_var)s;" % entry_infos)
+        else:
+            entry_infos["real_var"] = "beremiz" + entry_infos["var_name"]
+            str_completion["located_variables_declaration"].extend(
+                ["IEC_%(var_type)s %(real_var)s;" % entry_infos,
+                 "IEC_%(var_type)s *%(var_name)s = &%(real_var)s;" % entry_infos])
+        for declaration in entry_infos.get("extra_declarations", []):
+            entry_infos["extra_decl"] = declaration
+            str_completion["located_variables_declaration"].append(
+                 "IEC_%(var_type)s *%(extra_decl)s = &%(real_var)s;" % entry_infos)
+    elif not entry_infos.has_key("real_var"):
+        entry_infos["real_var"] = "beremiz" + entry_infos["var_name"]
+    
+    str_completion["used_pdo_entry_offset_variables_declaration"].append(
+        "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos)
+    
+    if entry_infos["data_type"] == "BIT":
+        str_completion["used_pdo_entry_offset_variables_declaration"].append(
+            "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos)
+        
+        str_completion["used_pdo_entry_configuration"].append(
+             ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + 
+              "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + 
+              "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos)
+        
+        if entry_infos["dir"] == "I":
+            str_completion["retrieve_variables"].append(
+              ("    %(real_var)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
+               "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos)
+        elif entry_infos["dir"] == "Q":
+            str_completion["publish_variables"].append(
+              ("    EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
+               "slave%(slave)d_%(index).4x_%(subindex).2x_bit, %(real_var)s);") % entry_infos)
+    
+    else:
+        str_completion["used_pdo_entry_configuration"].append(
+            ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + 
+             "%(subindex)d, &slave%(slave