EtherCat master plugin : commit changes recovered from KOSMOS 2018 installer, unkown author(s). ethercat_from_kosmos
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Wed, 20 Nov 2019 16:57:15 +0100
branchethercat_from_kosmos
changeset 2641 c9deff128c37
parent 2192 09d5d1456616
child 2642 65701f40d970
child 2643 b98d9e08231f
EtherCat master plugin : commit changes recovered from KOSMOS 2018 installer, unkown author(s).
etherlab/CommonEtherCATFunction.py
etherlab/ConfigEditor.py
etherlab/EtherCATManagementEditor.py
etherlab/EthercatCFileGenerator.py
etherlab/EthercatCIA402Slave.py
etherlab/EthercatMaster.py
etherlab/EthercatSlave.py
etherlab/entries_list.xslt
etherlab/entries_list.ysl2
etherlab/etherlab.py
etherlab/images/genicons.sh
etherlab/plc_cia402node.c
etherlab/plc_etherlab.c
etherlab/pous.xml
etherlab/runtime_etherlab.py
--- a/etherlab/CommonEtherCATFunction.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/CommonEtherCATFunction.py	Wed Nov 20 16:57:15 2019 +0100
@@ -10,8 +10,9 @@
 
 import os
 import wx
-
-mailbox_protocols =  ["AoE", "EoE", "CoE", "FoE", "SoE", "VoE"]
+import re
+
+from lxml import objectify
 
 def ExtractHexDecValue(value):
     """
@@ -77,18 +78,21 @@
 returnVal = result 
 """
 
-# ethercat sdos -p (slave position)
-SLAVE_SDO = """
+# ethercat upload -p (slave position) -t (type) (index) (sub index)
+SDO_UPLOAD = """
 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 
+sdo_data = []
+input_data = "%s"
+slave_pos = %d
+command_string = ""
+for sdo_token in input_data.split(","):  
+    if len(sdo_token) > 1:
+        sdo_token = sdo_token.strip()
+        type, idx, subidx = sdo_token.split(" ")
+        command_string = "ethercat upload -p " + str(slave_pos) + " -t " + type + " " + idx + " " + subidx
+        result = commands.getoutput(command_string)
+        sdo_data.append(result)
+returnVal =sdo_data
 """
 
 # ethercat download -p (slave position) (main index) (sub index) (value)
@@ -112,6 +116,25 @@
 returnVal =result 
 """
 
+# ethercat reg_read -p (slave position) (address) (size)
+MULTI_REG_READ = """ 
+import commands
+output = []
+addr, size = range(2)
+slave_num = %d 
+reg_info_str = "%s"
+reg_info_list = reg_info_str.split("|")
+for slave_idx in range(slave_num):
+    for reg_info in reg_info_list:
+        param = reg_info.split(",")
+        result = commands.getoutput("ethercat reg_read -p "
+                                    + str(slave_idx) + " "
+                                    + param[addr] + " "
+                                    + param[size])
+        output.append(str(slave_idx) + "," + param[addr] + "," + result)
+returnVal = output
+"""
+
 # ethercat sii_write -p (slave position) - (contents)
 SII_WRITE = """ 
 import subprocess 
@@ -136,6 +159,13 @@
 returnVal =result 
 """
 
+# ethercat pdos
+PDOS = """
+import commands
+result = commands.getoutput("ethercat pdos -p 0")
+returnVal =result  
+"""
+
 #--------------------------------------------------
 #    Common Method For EtherCAT Management 
 #--------------------------------------------------
@@ -144,12 +174,38 @@
     # ----- Data Structure for ethercat management ----
     SlaveState = ""
 
+    # SDO base data type for Ethercatmaster
+    BaseDataTypes = {
+            "bool": ["BOOLEAN", "BOOL", "BIT"],
+            "uint8": ["BYTE", "USINT", "BIT1", "BIT2", "BIT3", "BIT4", "BIT5", "BIT6",
+                      "BIT7", "BIT8", "BITARR8", "UNSIGNED8"],
+            "uint16": ["BITARR16", "UNSIGNED16", "UINT"],
+            "uint32": ["BITARR32", "UNSIGNED24", "UINT24", "UNSIGNED32", "UDINT"],
+            "uint64": ["UNSINED40", "UINT40", "UNSIGNED48", "UINT48", "UNSIGNED56", 
+                       "UINT56", "UNSIGNED64", "ULINT"],
+            "int8": ["INTEGER8", "SINT"],
+            "int16": ["INTEGER16", "INT"],
+            "int32": ["INTEGER24", "INT24", "INTEGER32", "DINT"],
+            "int64": ["INTEGER40", "INT40", "INTEGER48", "INT48", "INTEGER56", "INT56",
+                      "INTEGER64", "LINT"],
+            "float": ["REAL", "REAL32"],
+            "double": ["LREAL", "REAL64"],
+            "string": ["VISUBLE_STRING", "STRING(n)"],
+            "octet_string": ["OCTET_STRING"],
+            "unicode_string": ["UNICODE_STRING"]
+            }
+    
     # category of SDO data
     DatatypeDescription, CommunicationObject, ManufacturerSpecific, \
     ProfileSpecific, Reserved, AllSDOData = range(6)
     
-    # store the execution result of "ethercat sdos" command into SaveSDOData.
-    SaveSDOData = []
+    # SDO data informations: index, sub-index, type, bit size, category-name 
+    SDOVariables = []
+    SDOSubEntryData = []
+    
+    # defalut value of SDO data in XML
+    # Not Used
+    DefaultValueDic = {}
     
     # Flags for checking "write" permission of OD entries 
     CheckPREOP = False
@@ -180,7 +236,7 @@
         self.Controler = controler
          
         self.ClearSDODataSet()
-    
+
     #-------------------------------------------------------------------------------
     #                        Used Master State
     #-------------------------------------------------------------------------------
@@ -189,7 +245,6 @@
         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 = {}
@@ -226,20 +281,11 @@
         """ 
         error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val = None)
         self.SlaveState = return_val
-        return 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.
@@ -248,8 +294,11 @@
         @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)
+        """ 
+        valid_type = self.GetValidDataType(data_type)
+        error, return_val = self.Controler.RemoteExec(SDO_DOWNLOAD%(valid_type, self.Controler.GetSlavePos(), idx, sub_idx, value), return_val = None)
+        
+        return return_val
     
     def BackupSDODataSet(self):
         """
@@ -268,14 +317,318 @@
         Clear the specified SDO entry information.
         """ 
         for count in range(6):
-            self.SaveSDOData.append([])
-    
+            self.SDOVariables.append([])
+    
+    def GetAllSDOValuesFromSlave(self):
+        """
+        Get SDO values of All SDO entries.
+        @return return_val: list of result of "SDO_UPLOAD"
+        """
+        entry_infos = ""
+        alldata_idx = len(self.SDOVariables)
+        counter = 0
+        for category in self.SDOVariables:
+            counter +=1
+            # for avoid redundant repetition 
+            if counter == alldata_idx:
+                continue
+            
+            for entry in category:
+                valid_type = self.GetValidDataType(entry["type"])
+                for_command_string = "%s %s %s ," % \
+                        (valid_type, entry["idx"], entry["subIdx"])
+                entry_infos += for_command_string
+             
+        error, return_val = self.Controler.RemoteExec(SDO_UPLOAD%(entry_infos, self.Controler.GetSlavePos()), return_val = None)
+        
+        return return_val
+
+    def GetSDOValuesFromSlave(self, entries_info):
+        """
+        Get SDO values of some SDO entries.
+        @param entries_info: dictionary of SDO entries that is wanted to know the value. 
+        @return return_val: list of result of "SDO_UPLOAD"
+        """
+        entry_infos = ""
+
+        entries_info_list = entries_info.items()
+        entries_info_list.sort()
+        
+        for (idx, subIdx), entry in entries_info_list:
+            valid_type = self.GetValidDataType(entry["type"])
+            for_command_string = "%s %s %s ," % \
+                        (valid_type, str(idx), str(subIdx))
+            entry_infos += for_command_string
+
+        error, return_val = self.Controler.RemoteExec(SDO_UPLOAD%(entry_infos, self.Controler.GetSlavePos()), return_val = None)
+        
+        return return_val
+
+    def ExtractObjects(self):
+        """
+        Extract object type items from imported ESI xml.
+        And they are stuctured as dictionary.
+        @return objects: dictionary of objects
+        """
+        objects = {}
+
+        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 :
+            for dictionary in device.GetProfileDictionaries():
+                dictionary.load()
+                for object in dictionary.getObjects().getObject():
+                    object_index = ExtractHexDecValue(object.getIndex().getcontent())
+                    objects[(object_index)] = object
+        
+        return objects
+
+    def ExtractAllDataTypes(self):
+        """
+        Extract all data types from imported ESI xml.
+        @return dataTypes: dictionary of datatypes 
+        """
+        dataTypes = {}
+        
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        type_infos = slave.getType()
+        device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+
+        for dictionary in device.GetProfileDictionaries():
+            dictionary.load()
+        
+            datatypes = dictionary.getDataTypes()
+            if datatypes is not None:
+
+                for datatype in datatypes.getDataType():
+                    dataTypes[datatype.getName()] = datatype
+        return dataTypes
+    
+    def IsBaseDataType(self, datatype):
+        """
+        Check if the datatype is a base data type.
+        @return baseTypeFlag: true if datatype is a base data type, unless false
+        """
+        baseTypeFlag = False
+        for baseDataTypeList in self.BaseDataTypes.values():
+            if datatype in baseDataTypeList:
+                baseTypeFlag = True
+                break
+        return baseTypeFlag
+
+    def GetBaseDataType(self, datatype):
+        """
+        Get a base data type corresponding the datatype.
+        @param datatype: Some data type (string format)
+        @return base data type
+        """
+        if self.IsBaseDataType(datatype):
+            return datatype
+        elif not datatype.find("STRING") == -1:
+            return datatype
+        else:
+            datatypes = self.ExtractAllDataTypes()
+            base_datatype = datatypes[datatype].getBaseType()
+            return self.GetBaseDataType(base_datatype)
+
+    def GetValidDataType(self, datatype):
+        """
+        Convert the datatype into a data type that is possible to download/upload 
+        in etherlab master stack.
+        @param datatype: Some data type (string format)
+        @return base_type: vaild data type
+        """
+        base_type = self.GetBaseDataType(datatype)
+
+        if re.match("STRING\([0-9]*\)", datatype) is not None:
+            return "string"
+        else:
+            for key, value in self.BaseDataTypes.items():
+                if base_type in value:
+                    return key
+        return base_type 
+
+    # Not Used 
+    def GetAllEntriesList(self):
+        """
+        Get All entries information that includes index, sub-index, name,
+        type, bit size, PDO mapping, and default value.
+        @return self.entries: dictionary of entry
+        """
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        type_infos = slave.getType()
+        device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+        self.entries = device.GetEntriesList()
+        datatypes = self.ExtractAllDataTypes()
+        objects = self.ExtractObjects()
+        entries_list = self.entries.items()
+        entries_list.sort()
+
+        # append sub entries
+        for (index, subidx), entry in entries_list:
+            # entry_* is string type
+            entry_type = entry["Type"]
+            entry_index = entry["Index"]
+            
+            try:
+                object_info = objects[index].getInfo()
+            except:
+                continue
+            
+            if object_info is not None:
+                obj_content = object_info.getcontent()
+            
+            typeinfo = datatypes.get(entry_type, None)
+            bitsize = typeinfo.getBitSize()
+            type_content = typeinfo.getcontent()
+           
+            # ArrayInfo type
+            if type_content is not None and type_content["name"] == "ArrayInfo":
+                for arrayinfo in type_content["value"]:
+                    element_num = arrayinfo.getElements()
+                    first_subidx = arrayinfo.getLBound()
+                    for offset in range(element_num):
+                        new_subidx = int(first_subidx) + offset
+                        entry_subidx = hex(new_subidx)
+                        if obj_content["value"][new_subidx]["name"] == "SubItem":
+                            subitem = obj_content["value"][new_subidx]["value"]
+                            subname = subitem[new_subidx].getName()
+                        if subname is not None:
+                            entry_name = "%s - %s" % \
+                                    (ExtractName(objects[index].getName()), subname)
+                        else:
+                            entry_name = ExtractName(objects[index].getName()) 
+                        self.entries[(index, new_subidx)] = {
+                                "Index": entry_index,
+                                "SubIndex": entry_subidx,
+                                "Name": entry_name,
+                                "Type": typeinfo.getBaseType(),
+                                "BitSize": str(bitsize/element_num),
+                                "Access": entry["Access"],
+                                "PDOMapping": entry["PDOMapping"]}
+                        try:
+                            value_info = subitem[new_subidx].getInfo().getcontent()\
+                                                            ["value"][0]["value"][0]
+                            self.AppendDefaultValue(index, new_subidx, value_info)
+                        except:
+                            pass
+
+                try:
+                    value_info = subitem[subidx].getInfo().getcontent()\
+                                                            ["value"][0]["value"][0]
+                    self.AppendDefaultValue(index, subidx, value_info)
+                except:
+                    pass
+            
+            # EnumInfo type
+            elif type_content is not None and type_content["name"] == "EnumInfo":
+                self.entries[(index, subidx)]["EnumInfo"] = {}
+                
+                for enuminfo in type_content["value"]:
+                    text = enuminfo.getText()
+                    enum = enuminfo.getEnum()
+                    self.entries[(index, subidx)]["EnumInfo"][str(enum)] = text
+
+                self.entries[(index, subidx)]["DefaultValue"] = "0x00" 
+            
+            # another types
+            else:
+                if subidx == 0x00:
+                    tmp_subidx = 0x00
+
+                try:
+                    if obj_content["value"][tmp_subidx]["name"] == "SubItem":
+                        sub_name = entry["Name"].split(" - ")[1]
+                        for num in range(len(obj_content["value"])):
+                            if sub_name == \
+                                    obj_content["value"][num]["value"][num].getName():
+                                subitem_content = obj_content["value"][tmp_subidx]\
+                                                             ["value"][tmp_subidx]
+                                value_info = subitem_content.getInfo().getcontent()\
+                                                             ["value"][0]["value"][0]
+                                tmp_subidx += 1
+                                break
+                            else:
+                                value_info = None
+                        
+                    else:
+                        value_info = \
+                                obj_content["value"][tmp_subidx]["value"][tmp_subidx]
+
+                    self.AppendDefaultValue(index, subidx, value_info)
+
+                except:
+                    pass
+
+        return self.entries
+                   
+    # Not Used  
+    def AppendDefaultValue(self, index, subidx, value_info=None):
+        """
+        Get the default value from the ESI xml
+        @param index: entry index
+        @param subidx: entry sub index
+        @param value_info: dictionary of infomation about default value
+
+        """
+        # there is not default value.
+        if value_info == None:
+            return
+
+        raw_value = value_info["value"]
+        
+        # default value is hex binary type.
+        if value_info["name"]  == "DefaultData":
+            raw_value_bit = list(hex(raw_value).split("0x")[1])
+             
+            datatype = self.GetValidDataType(self.entries[(index, subidx)]["Type"])
+            if datatype is "string" or datatype is "octet_string":
+
+                if "L" in raw_value_bit:
+                    raw_value_bit.remove("L")
+
+                default_value = "".join(raw_value_bit).decode("hex")
+           
+            elif datatype is "unicode_string":
+                default_value = "".join(raw_value_bit).decode("hex").\
+                                                           decode("utf-8")
+            
+            else:   
+                bit_num = len(raw_value_bit)
+                # padding 
+                if not bit_num%2 == 0:
+                    raw_value_bit.insert(0, "0")
+
+                default_value_bit = []
+            
+                # little endian -> big endian
+                for num in range(bit_num):
+                    if num%2 == 0:
+                        default_value_bit.insert(0, raw_value_bit[num])
+                        default_value_bit.insert(1, raw_value_bit[num+1])
+                
+                default_value = "0x%s" % "".join(default_value_bit)
+
+        # default value is string type.
+        # this case is not tested yet.
+        elif value_info["name"] == "DefaultString":
+            default_value = raw_value
+
+        # default value is Hex or Dec type.
+        elif value_info["name"] == "DefaultValue":
+            default_value = "0x" + hex(ExtractHexDecValue(raw_value))
+
+        self.entries[(index, subidx)]["DefaultValue"] = default_value
+
     #-------------------------------------------------------------------------------
     #                        Used PDO Monitoring
     #-------------------------------------------------------------------------------
     def RequestPDOInfo(self):
         """
-        Load slave information from RootClass (XML data) and parse the information (calling SlavePDOData() method).
+        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())
@@ -292,7 +645,7 @@
     def SavePDOData(self, device):
         """
         Parse PDO data and store the results in TXPDOCategory and RXPDOCategory
-        Tx(Rx)PDOCategory : index, name, entry number
+        Tx(Rx)PDOCategory : index, name, entry number, exclude list, Sm
         Tx(Rx)Info : entry index, sub index, name, length, type
         @param device : Slave information extracted from ESI XML file
         """ 
@@ -302,10 +655,17 @@
             pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
             entries = pdo.getEntry()
             pdo_name = ExtractName(pdo.getName())
-            
+            excludes = pdo.getExclude()
+            exclude_list = []
+            Sm = pdo.getSm()
+
+            if excludes :
+                for exclude in excludes:
+                    exclude_list.append(ExtractHexDecValue(exclude.getcontent()))
+
             # Initialize entry number count
             count = 0
-            
+
             # Parse entries
             for entry in entries:
                 # Save index and subindex
@@ -317,13 +677,14 @@
                                 "entry_index" : index,
                                 "subindex" : subindex,
                                 "name" : ExtractName(entry.getName()),
-                                "bitlen" : entry.getBitLen(),
-                                "type" : entry.getDataType().getcontent()
-                                    }
+                                "bitlen" : entry.getBitLen()}
+                    if entry.getDataType() is not None:
+                        entry_infos["type"] = entry.getDataType().getcontent()
                     self.TxPDOInfo.append(entry_infos)
                     count += 1
-              
-            categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}  
+
+            categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "sm" : Sm,
+                         "number_of_entry" : count, "exclude_list" : exclude_list}  
             self.TxPDOCategory.append(categorys)
 
         # Parsing RxPDO entries
@@ -332,7 +693,14 @@
             pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
             entries = pdo.getEntry()
             pdo_name = ExtractName(pdo.getName())
-            
+            excludes = pdo.getExclude()
+            exclude_list = []
+            Sm = pdo.getSm()
+
+            if excludes :
+                for exclude in excludes:
+                    exclude_list.append(ExtractHexDecValue(exclude.getcontent()))
+
             # Initialize entry number count
             count = 0          
 
@@ -347,13 +715,14 @@
                                 "entry_index" : index,
                                 "subindex" : subindex,
                                 "name" : ExtractName(entry.getName()),
-                                "bitlen" : str(entry.getBitLen()),
-                                "type" : entry.getDataType().getcontent()
-                                    }
+                                "bitlen" : entry.getBitLen()}
+                    if entry.getDataType() is not None:
+                        entry_infos["type"] = entry.getDataType().getcontent()
                     self.RxPDOInfo.append(entry_infos)
                     count += 1
     
-            categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count}  
+            categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "sm" : Sm,
+                         "number_of_entry" : count, "exclude_list" : exclude_list}
             self.RxPDOCategory.append(categorys) 
 
     def GetTxPDOCategory(self):
@@ -392,10 +761,10 @@
         """
         Initialize PDO management data structure.
         """ 
-        self.TxPDOInfos = []
-        self.TxPDOCategorys = []
-        self.RxPDOInfos = []
-        self.RxPDOCategorys = []
+        self.TxPDOInfo = []
+        self.TxPDOCategory = []
+        self.RxPDOInfo = []
+        self.RxPDOCategory = []
                
     #-------------------------------------------------------------------------------
     #                        Used EEPROM Management
@@ -460,23 +829,33 @@
         type_infos = slave.getType()
         device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
 
+        #from decimal import Decimal
+
         # 'device' represents current slave device selected by user
         if device is not None:
-            for eeprom_element in device.getEeprom().getcontent():
+            # dir() method print available method list
+            #print  dir(device.getEeprom().getchildren()[1])
+
+            # success get subitem second object
+            #print objectify.fromstring(device.getEeprom().getchildren()[1].tostring()).text
+            
+            for eeprom_element in device.getEeprom().getchildren():
                 # get EEPROM size; <Device>-<Eeprom>-<ByteSize>
-                if eeprom_element["name"] == "ByteSize":
-                    smartview_infos["eeprom_size"] = eeprom_element
+                if eeprom_element.tag == "ByteSize":
+                    smartview_infos["eeprom_size"] = objectify.fromstring(eeprom_element.tostring()).text
                         
-                elif eeprom_element["name"] == "ConfigData":
-                    configData_data = self.DecimalToHex(eeprom_element)
+                elif eeprom_element.tag == "ConfigData":
+                    # ConfigData Field Datatype???
+                    #print type(objectify.fromstring(eeprom_element.tostring()).text)
+                    configData_data = self.DecimalToHex(objectify.fromstring(eeprom_element.tostring()).text)
                     # 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':
+                    if len(configData_data) > 3 and "{: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)
+                elif eeprom_element.tag == "BootStrap":
+                    bootstrap_data = "{:0>16x}".format(int(objectify.fromstring(eeprom_element.tostring()).text, 16))
                     # get bootstrap configuration; <Device>-<Eeprom>-<BootStrap>
                     for cfg, iter in [("mailbox_bootstrapconf_outstart", 0), 
                                       ("mailbox_bootstrapconf_outlength", 1),
@@ -484,12 +863,34 @@
                                       ("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))
             
+            """
+            for eeprom_element in device.getEeprom().getcontent()["value"]:
+                # get EEPROM size; <Device>-<Eeprom>-<ByteSize>
+                if eeprom_element["name"] == "ByteSize":
+                    smartview_infos["eeprom_size"] = eeprom_element["value"]
+                        
+                elif eeprom_element["name"] == "ConfigData":
+                    configData_data = self.DecimalToHex(eeprom_element["value"])
+                    # 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["value"])
+                    # 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
+            for mailbox_protocol in ["VoE", "SoE", "FoE", "CoE", "EoE", "AoE"]:
+                if device.getMailbox() is not None and eval("device.getMailbox().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>
@@ -504,24 +905,24 @@
                     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.
+            # 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; 
+            # 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; 
+            # 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;
+            # 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))
@@ -537,14 +938,14 @@
         @param decnum : decimal value
         @return hex_data : hexadecimal representation of input value in decimal
         """ 
-        value = "%x" % decnum
+        value = "%x" % int(decnum, 16)
         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)
+
+        hex_data = ("{:0>"+str(hex_len)+"x}").format(int(decnum, 16))
         
         return hex_data
 
@@ -668,12 +1069,13 @@
         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)
+            # Modify by jblee because of update IDE module (minidom -> lxml) 
+            for eeprom_element in device.getEeprom().getchildren():
+                if eeprom_element.tag == "ConfigData":
+                    data = self.DecimalToHex(objectify.fromstring(eeprom_element.tostring()).text)
             eeprom += self.GenerateEEPROMList(data, 0, 28)
             
             # calculate CRC for EEPROM offset 0x000e-0x000f
@@ -732,19 +1134,20 @@
             eeprom.append("00")
             eeprom.append("00")
 
+            data = ""
             # 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)
+            # Modify by jblee because of update IDE module (minidom -> lxml) 
+            for eeprom_element in device.getEeprom().getchildren():
+                if eeprom_element.tag == "BootStrap":
+                    data = "{:0>16x}".format(int(objectify.fromstring(eeprom_element.tostring()).text, 16))
             eeprom += self.GenerateEEPROMList(data, 0, 16)
             
             # get Standard Mailbox for EEPROM offset 0x0030-0x0037; <Device>-<sm>
             data = ""
+            standard_receive_mailbox_offset = None
+            standard_receive_mailbox_size = None
             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()))
@@ -780,10 +1183,14 @@
             
             # 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:
+            if device.getMailbox() is not None:
+                for mbox, bit in [(device.getMailbox().getAoE(), 0),
+                              (device.getMailbox().getEoE(), 1),
+                              (device.getMailbox().getCoE(), 2),
+                              (device.getMailbox().getFoE(), 3),
+                              (device.getMailbox().getSoE(), 4),
+                              (device.getMailbox().getVoE(), 5)]:
+                    if mbox is not None:
                         data += 1<<bit
             data = "{:0>4x}".format(data)
             eeprom.append(data[2:4])
@@ -794,12 +1201,13 @@
                 eeprom.append("00")
             
             # get EEPROM size for EEPROM offset 0x007c-0x007d;
+            # Modify by jblee because of update IDE module (minidom -> lxml) 
             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)
-
+            for eeprom_element in device.getEeprom().getchildren():
+                if eeprom_element.tag == "ByteSize":
+                    eeprom_size = int(objectify.fromstring(eeprom_element.tostring()).text)
+                    data = "{:0>4x}".format(eeprom_size/1024*8-1)
+            
             if data == "":
                 eeprom.append("00")
                 eeprom.append("00")
@@ -808,7 +1216,7 @@
                 eeprom.append(data[0:2])
                 
             # Version for EEPROM 0x007e-0x007f; 
-            #  According to "EtherCAT Slave Device Description(V0.3.0)"
+            # According to "EtherCAT Slave Device Description(V0.3.0)"
             eeprom.append("01")
             eeprom.append("00")
             
@@ -877,14 +1285,16 @@
         imageflag = False
         
         # vendor specific data
-        #   element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type>
-        #   vendor_specific_data : vendor specific data (binary type)
+        # element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type>
+        # vendor_specific_data : vendor specific data (binary type)
+        # Modify by jblee because of update IDE module (minidom -> lxml) 
         vendor_specific_data = ""
-        #   vendor_spec_strings : list of vendor specific "strings" for preventing duplicated strings
+        # 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:
+        # retrun type change unicode -> str
+        if data is not "" and type(data) == str:
             for vendor_spec_string in vendor_spec_strings: 
                 if data == vendor_spec_string:
                     self.OrderIdx = vendor_spec_strings.index(data)+1
@@ -901,9 +1311,11 @@
                     vendor_specific_data += "{:0>2x}".format(ord(data[character]))
         data = ""
         
-        #  element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType>
+        # element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType>
+        # Modify by jblee because of update IDE module (minidom -> lxml) 
         data = device.getGroupType()
-        if data is not None and type(data) == unicode:
+        # retrun type change unicode -> str
+        if data is not None and type(data) == str:
             for vendor_spec_string in vendor_spec_strings:
                 if data == vendor_spec_string:
                     self.GroupIdx = vendor_spec_strings.index(data)+1
@@ -920,7 +1332,7 @@
                 for character in range(len(data)):
                     vendor_specific_data += "{:0>2x}".format(ord(data[character]))
         
-        #  element2-2; <EtherCATInfo>-<Groups>-<Group>-<Type>            
+        # 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():
@@ -945,8 +1357,30 @@
                         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")>
+
+        # element3; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Name(LcId is "1033")>
+        # Modify by jblee because of update IDE module (minidom -> lxml) 
+        if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+            LcId_obj = self.Controler.CTNParent.CTNParent.ModulesLibrary.LcId_data
+            data = LcId_obj.getcontent()
+
+        # retrun type change unicode -> str
+        if data is not "" and type(data) == str:
+            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]))
+        
+        """
+        # 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():
@@ -966,13 +1400,17 @@
                 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"?)>
+        # element4; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Name(LcId is "1033" or "1"?)>
+        # Modify by jblee because of update IDE module (minidom -> lxml) 
         for element in device.getName():
             if element.getLcId() == 1 or element.getLcId()==1033:
                 data = element.getcontent()
-        if data is not "" and type(data) == unicode:
+        # retrun type change unicode -> str
+        if data is not "" and type(data) == str:
             for vendor_spec_string in vendor_spec_strings:
                 if data == vendor_spec_string:
                     self.NameIdx = vendor_spec_strings.index(data)+1
@@ -987,12 +1425,18 @@
                 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>
+        # 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:
+            #data = device.getcontent()["value"]
+            # mod by jblee 151224
+            # xml module change minidom -> lxml
+            # use lxml objectify module
+            data = objectify.fromstring(device.getcontent().tostring()).text
+            # retrun type change unicode -> str
+            if data is not None and type(data) == str:
                 for vendor_spec_string in vendor_spec_strings:
                     if data == vendor_spec_string:
                         self.ImgIdx = vendor_spec_strings.index(data)+1
@@ -1007,16 +1451,43 @@
                     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>
+        
+        # element5-2; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Image16x14>
+        # Modify by jblee because of update IDE module (minidom -> lxml) 
+        if imageflag is False:
+            if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None:
+                data_obj = self.Controler.CTNParent.CTNParent.ModulesLibrary.Image16x14_data
+                data = data_obj.text
+
+                # retrun type change unicode -> str
+                if data is not None and type(data) == str:
+                    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:
+                                print group_etc
+                                data = group_etc["value"]
+                # retrun type change unicode -> str
+                if data is not None and type(data) == str:
                     for vendor_spec_string in vendor_spec_strings:
                         if data == vendor_spec_string:
                             self.ImgIdx = vendor_spec_strings.index(data)+1
@@ -1031,10 +1502,11 @@
                         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>
+        # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Dc>-<OpMode>-<Name>
         dc_related_elements = ""
         if device.getDc() is not None:
             for element in device.getDc().getOpMode():
@@ -1048,7 +1520,7 @@
                     data = ""
         
         # Input elements(TxPDO)
-        #  <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name
+        # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name
         input_elements = ""
         inputs = []
         for element in device.getTxPdo():
@@ -1081,7 +1553,7 @@
                     data = ""
         
         # Output elements(RxPDO)
-        #  <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name
+        # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name
         output_elements = ""
         outputs = []
         for element in device.getRxPdo():
@@ -1114,10 +1586,10 @@
                     data = ""     
         
         # form eeprom data
-        #  category header
+        # 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
+        # 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
@@ -1126,7 +1598,7 @@
             padflag = True
         eeprom.append("{:0>4x}".format(length/4)[2:4])
         eeprom.append("{:0>4x}".format(length/4)[0:2])
-        #  total numbers of strings
+        # total numbers of strings
         eeprom.append("{:0>2x}".format(count))
         for element in [vendor_specific_data,
                         dc_related_elements,
@@ -1171,48 +1643,48 @@
         
         # 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; <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        
+        if device.getMailbox() is not None and device.getMailbox().getCoE() is not None:
+            coe_details = 1 # sdo enabled
+            for attr, bit in [(device.getMailbox().getCoE().getSdoInfo(), 1),
+                               (device.getMailbox().getCoE().getPdoAssign(), 2),
+                               (device.getMailbox().getCoE().getPdoConfig(), 3),
+                               (device.getMailbox().getCoE().getPdoUpload(), 4),
+                               (device.getMailbox().getCoE().getCompleteAccess(), 5)]:
+                if attr==1 or attr==True:
+                    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:
+        # FoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<FoE>
+        if device.getMailbox() is not None and device.getMailbox().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:
+        # EoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<EoE>
+        if device.getMailbox() is not None and device.getMailbox().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:
+        # SoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<SoE>
+        if device.getMailbox() is not None and device.getMailbox().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")
+        # DS402Channels; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>: DS402Channels
+        if device.getMailbox() is not None and \
+           (device.getMailbox().getCoE().getDS402Channels() == True \
+            or device.getMailbox().getCoE().getDS402Channels() == 1):
+            eeprom.append("01")
+        else:
+            eeprom.append("00")
             
         # word 6 : SysmanClass(reserved) and Flags
         eeprom.append("00") # reserved
-        #  Flags 
+        # Flags 
         en_safeop = False
         en_lrw = False
         if device.getType().getTcCfgModeSafeOp() == True \
@@ -1272,10 +1744,10 @@
         
         # construct of EEPROM data
         if data is not "":
-            #  category header
+            # category header
             eeprom.append("28")
             eeprom.append("00")
-            #  category length
+            # category length
             if count%2 == 1:
                 padflag = True
                 eeprom.append("{:0>4x}".format((count+1)/2)[2:4])
@@ -1289,7 +1761,7 @@
                 else:
                     eeprom.append(data[0:2])
                 data = data[2:len(data)]
-            #  padding if length is odd bytes 
+            # padding if length is odd bytes 
             if padflag is True:
                 eeprom.append("ff")       
             
@@ -1321,10 +1793,10 @@
             data += number[sm.getcontent()]
             
         if data is not "":
-            #  category header
+            # category header
             eeprom.append("29")
             eeprom.append("00")
-            #  category length 
+            # 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):
@@ -1351,19 +1823,19 @@
         en_virtual = False
         
         for element in eval("device.get%s()"%pdotype):
-            #  PDO Index
+            # 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
+            # Number of Entries
             data += "{:0>2x}".format(len(element.getEntry()))
-            #  About Sync Manager
+            # 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
+            # Reference to DC Synch (according to ET1100 documentation) - assume 0
             data += "00"
-            #  Name Index
+            # Name Index
             objname = ""
             for name in element.getName():
                 objname = name.getcontent()
@@ -1376,7 +1848,7 @@
             else:
                 data += "{:0>2x}".format(count)
             count = 0
-            #  Flags; by Fixed, Mandatory, Virtual attributes ?
+            # Flags; by Fixed, Mandatory, Virtual attributes ?
             if element.getFixed() == True or 1:
                 en_fixed = True
             if element.getMandatory() == True or 1:
@@ -1386,12 +1858,12 @@
             data += str(int(en_fixed)) + str(int(en_mandatory)) + str(int(en_virtual)) + "0"
             
             for entry in element.getEntry():
-                #   Entry Index
+                # Entry Index
                 data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[2:4]
                 data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[0:2]
-                #   Subindex
+                # Subindex
                 data += "{:0>2x}".format(int(entry.getSubIndex()))
-                #   Entry Name Index
+                # Entry Name Index
                 objname = ""
                 for name in entry.getName():
                     objname = name.getcontent()
@@ -1404,7 +1876,7 @@
                 else:
                     data += "{:0>2x}".format(count)
                 count = 0
-                #   DataType
+                # DataType
                 if entry.getDataType() is not None:
                     if entry.getDataType().getcontent() in self.BaseDataTypeDict:
                         data += self.BaseDataTypeDict[entry.getDataType().getcontent()]
@@ -1412,19 +1884,19 @@
                         data += "00"
                 else:
                     data += "00"
-                #   BitLen
+                # BitLen
                 if entry.getBitLen() is not None:
                     data += "{:0>2x}".format(int(entry.getBitLen()))
                 else:
                     data += "00"
-                #   Flags; by Fixed attributes ?
+                # 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
+            # category header
             if pdotype == "TxPdo":
                 eeprom.append("32")
             elif pdotype == "RxPdo":
@@ -1432,7 +1904,7 @@
             else:
                 eeprom.append("00")
             eeprom.append("00")
-            #  category length 
+            # 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())
@@ -1459,7 +1931,7 @@
         if device.getDc() is not None:
             for element in device.getDc().getOpMode():
                 count += 1
-                #  assume that word 1-7 are 0x0000
+                # assume that word 1-7 are 0x0000
                 data += "0000"
                 data += "0000"
                 data += "0000"
@@ -1467,14 +1939,14 @@
                 data += "0000"
                 data += "0000"
                 data += "0000"
-                #  word 8-10
-                #  AssignActivate
+                # 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?
+                # 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()))
@@ -1483,8 +1955,8 @@
                         data += "0100"
                 else:
                     data += "0100"
-                #  Index of Name in STRINGS Category
-                #  Name Index
+                # Index of Name in STRINGS Category
+                # Name Index
                 objname = ""
                 for name in element.getName():
                     objname += name
@@ -1498,15 +1970,15 @@
                     data += "{:0>2x}".format(namecount)
                 namecount = 0
                 data += "00"
-                #  assume that word 11-12 are 0x0000
+                # assume that word 11-12 are 0x0000
                 data += "0000"
                 data += "0000"
                 
         if data is not "":
-            #  category header
+            # category header
             eeprom.append("3c")
             eeprom.append("00")
-            #  category length 
+            # 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())
@@ -1533,6 +2005,24 @@
         error, return_val = self.Controler.RemoteExec(REG_READ%(self.Controler.GetSlavePos(), offset, length), return_val = None)
         return return_val   
     
+    def MultiRegRead(self, slave_num, reg_infos):
+        """
+        
+        @slave_num:
+        @param addr_info:
+        @return return_val: 
+        """
+        reg_info_str = ""
+        for reg_info in reg_infos:
+            reg_info_str = reg_info_str + "%s|" % reg_info
+        reg_info_str = reg_info_str.strip("|")
+
+        error, return_val = self.Controler.RemoteExec(\
+                MULTI_REG_READ%(slave_num, reg_info_str),
+                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.
@@ -1550,6 +2040,40 @@
         Command example : "ethercat rescan -p 0"
         """ 
         error, return_val = self.Controler.RemoteExec(RESCAN%(self.Controler.GetSlavePos()), return_val = None)
+
+    #-------------------------------------------------------------------------------
+    #                        Used DC Configuration
+    #-------------------------------------------------------------------------------
+    def LoadESIData(self):
+        return_data = []
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        type_infos = slave.getType()
+        device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+        if device.getDc() is not None:
+            for OpMode in device.getDc().getOpMode():
+                temp_data = {
+                    "desc" : OpMode.getDesc() if OpMode.getDesc() is not None else "Unused",
+                    "assign_activate" : OpMode.getAssignActivate() \
+                        if OpMode.getAssignActivate() is not None else "#x0000",
+                    "cycletime_sync0" : OpMode.getCycleTimeSync0().getcontent() \
+                        if OpMode.getCycleTimeSync0() is not None else None,
+                    "shifttime_sync0" : OpMode.getShiftTimeSync0().getcontent() \
+                        if OpMode.getShiftTimeSync0() is not None else None,
+                    "cycletime_sync1" : OpMode.getShiftTimeSync1().getcontent() \
+                        if OpMode.getShiftTimeSync1() is not None else None,
+                    "shifttime_sync1" : OpMode.getShiftTimeSync1().getcontent() \
+                        if OpMode.getShiftTimeSync1() is not None else None
+                }
+
+                if OpMode.getCycleTimeSync0() is not None:
+                    temp_data["cycletime_sync0_factor"] = OpMode.getCycleTimeSync0().getFactor()
+
+                if OpMode.getCycleTimeSync1() is not None:
+                    temp_data["cycletime_sync1_factor"] = OpMode.getCycleTimeSync1().getFactor()
+
+                return_data.append(temp_data)
+
+        return return_data
     
     #-------------------------------------------------------------------------------
     #                        Common Use Methods
@@ -1559,7 +2083,7 @@
         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"
--- a/etherlab/ConfigEditor.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/ConfigEditor.py	Wed Nov 20 16:57:15 2019 +0100
@@ -25,9 +25,9 @@
 from controls.CustomStyledTextCtrl import NAVIGATION_KEYS
 
 # -----------------------------------------------------------------------
-from EtherCATManagementEditor import EtherCATManagementTreebook, MasterStatePanelClass
-# -----------------------------------------------------------------------
-
+from EtherCATManagementEditor import EtherCATManagementTreebook, MasterStatePanelClass
+# -----------------------------------------------------------------------
+
 [ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE] = range(3)
 
 def AppendMenu(parent, help, id, kind, text):
@@ -141,6 +141,9 @@
                     self.VariablesGrid.SetItemText(item, str(idx), 0)
                 else:
                     value = entry.get(colname, "")
+                    # add jblee
+                    if value is None:
+                        value = ""
                     if colname == "Access":
                         value = GetAccessValue(value, entry.get("PDOMapping", ""))
                     self.VariablesGrid.SetItemText(item, value, col)
@@ -284,7 +287,7 @@
         
         # add Contoler for use EthercatSlave.py Method
         self.Controler = controler
-        
+
     def GetBufferState(self):
         return False, False
         
@@ -299,17 +302,35 @@
             style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
         self.EtherCATManagementEditor.Bind(wx.EVT_SIZE, self.OnResize)
 
+        #self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+
         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)
-          
+        #except:
+        #try:
+        #    self.EtherCATManagementTreebook = EtherCATManagementTreebook(self.EtherCATManagementEditor, self.Controler, self)
+        #except:
+        #    self.EtherCATManagementTreebook = wx.Treebook(self.EtherCATManagementEditor, -1)
+        #    self.Controler.CommonMethod.CreateErrorDialog(\
+        #        "failed to open EtherCAT Management.\nplease remove the slave and try it again.")
+
         self.EtherCATManagermentEditor_Main_Sizer.AddSizer(self.EtherCATManagementTreebook, border=10, flag=wx.GROW)
 
         self.EtherCATManagementEditor.SetSizer(self.EtherCATManagermentEditor_Main_Sizer)
         return self.EtherCATManagementEditor
     
+    """
+    def OnPageChanged(self, event):
+        try:
+            print "OnPageChanged"
+            self.EtherCATManagementTreebook.SDOPanel.SDOMonitorThread.Stop();
+        except:
+            pass
+    """
+
     def OnResize(self, event):
         self.EtherCATManagementEditor.GetBestSize()
         xstart, ystart = self.EtherCATManagementEditor.GetViewStart()
@@ -595,20 +616,18 @@
     
     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.Bind(wx.EVT_SIZE, self.OnResize2)
+        
+        self.MasterStateEditor_Panel_Main_Sizer = wx.BoxSizer(wx.VERTICAL)
+
         self.MasterStateEditor_Panel = MasterStatePanelClass(self.MasterStateEditor, self.Controler)
         
-        self.MasterStateEditor_Panel_Main_Sizer.AddSizer(self.MasterStateEditor_Panel, border=10, flag=wx.GROW)
+        self.MasterStateEditor_Panel_Main_Sizer.AddSizer(self.MasterStateEditor_Panel, border=10, flag=wx.EXPAND)
          
         self.MasterStateEditor.SetSizer(self.MasterStateEditor_Panel_Main_Sizer)
         return self.MasterStateEditor
     
-    def OnResize(self, event):
+    def OnResize2(self, event):
         self.MasterStateEditor.GetBestSize()
         xstart, ystart = self.MasterStateEditor.GetViewStart()
         window_size = self.MasterStateEditor.GetClientSize()
@@ -1019,6 +1038,7 @@
                 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(
@@ -1054,33 +1074,6 @@
                 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):
--- a/etherlab/EtherCATManagementEditor.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/EtherCATManagementEditor.py	Wed Nov 20 16:57:15 2019 +0100
@@ -21,6 +21,18 @@
 # ------------ for SDO Management --------------------
 import string
 import wx.grid as gridlib
+try:
+    from agw import pyprogress as PP
+except ImportError:
+    import wx.lib.agw.pyprogress as PP
+try:
+    from agw import genericmessagedialog as GMD
+except ImportError:
+    import wx.lib.agw.genericmessagedialog as GMD
+
+from threading import Timer, Thread, Lock
+#from time import localtime
+import time
 #-------------------------------------------------------------
 
 # ------------ for register management --------------- 
@@ -60,37 +72,42 @@
         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 Mapping",     PDOPanelClass, []),
+        #    ("ESC Management",     EEPROMAccessPanel, [        
+        #            ("Smart View",  SlaveSiiSmartView),
+        #            ("Hex View",    HexView)]),
+        #    ("Register Access",    RegisterAccessPanel, [])]:
+        #        pclass = pclass(self, self.Controler)
+        #        self.AddPage(pclass, pname)
+        #        for spname, spclass in subs:
+        #            spclass = spclass(self, self.Controler)
+        #            self.AddSubPage(spclass, spname)
+
         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)
+            ("PDO Mapping",     PDOPanelClass, [
+                    ("Rx PDO", RxPDOPanelClass),
+                    ("Tx PDO", TxPDOPanelClass)]),
+            ("MDP Setting",		MDPPanel, []),
+            ("ESC Management",     EEPROMAccessPanel, [
+                    ("Smart View",  SlaveSiiSmartView),
+                    ("Hex View",    HexView)]),
+            ("Register Access",    RegisterAccessPanel, []),
+            ("DC Configuration",    DCConfigPanel, [])
+            ]:
+                pclass = pclass(self, self.Controler)
+                self.AddPage(pclass, 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()    
-        
+                    spclass = spclass(self, self.Controler)
+                    self.AddSubPage(spclass, spname)
+
 #-------------------------------------------------------------------------------
 #                    For SlaveState Panel
 #-------------------------------------------------------------------------------        
@@ -184,7 +201,7 @@
         
         self.SetSizer(self.SizerDic["SlaveState_main_sizer"])
         
-        # register a timer for periodic exectuion of slave state update (period: 1000 ms)
+        # register a timer for periodic exectuion of slave state update (period: 2000 ms)
         self.Bind(wx.EVT_TIMER, self.GetCurrentState)
         
         self.CreateSyncManagerTable()
@@ -199,14 +216,14 @@
         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]
+        self.SyncManagersGridColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_CENTER, wx.ALIGN_CENTER, 
+                                               wx.ALIGN_CENTER, wx.ALIGN_CENTER, wx.ALIGN_CENTER]
         # 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)
+            attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTER)
             self.SyncManagersGrid.SetColAttr(col, attr)
             self.SyncManagersGrid.SetColMinimalWidth(col, self.SyncManagersGridColSizes[col])
             self.SyncManagersGrid.AutoSizeColumn(col, False) 
@@ -236,7 +253,9 @@
         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)
+        # Check whether beremiz connected or not.
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
         if check_connect_flag :
             state_dic = ["INIT", "PREOP", "SAFEOP", "OP"]
               
@@ -258,10 +277,15 @@
      
     def GetCurrentState(self, event):
         """
-        Timer event handler for periodic slave state monitoring (Default period: 1 sec = 1000 msec).
+        Timer event handler for periodic slave state monitoring (Default period: 1 sec = 2000 msec).
         @param event : wx.TIMER object
         """
-        check_connect_flag = self.Controler.CommonMethod.CheckConnect(True)
+        if self.IsShownOnScreen() is False:
+            return
+
+        # Check whether beremiz connected or not.
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = True)
         if check_connect_flag:
             returnVal = self.Controler.CommonMethod.GetSlaveStateFromSlave()
             line = returnVal.split("\n")
@@ -291,9 +315,15 @@
           - 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)
+        # Check whether beremiz connected or not.
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
+        if check_connect_flag:
+            self.SlaveStateThread = wx.Timer(self)
+            # set timer period (2000 ms)
+            self.SlaveStateThread.Start(2000)
+        else:
+            pass
         
     def CurrentStateThreadStop(self, event):
         """
@@ -309,7 +339,7 @@
 #-------------------------------------------------------------------------------
 #                    For SDO Management Panel
 #-------------------------------------------------------------------------------  
-class SDOPanelClass(wx.Panel):
+class SDOPanelClass(wx.ScrolledWindow):
     def __init__(self, parent, controler):
         """
         Constructor
@@ -322,141 +352,217 @@
         self.ProfileSpecific, self.Reserved, self.AllSDOData = range(6)
         
         self.Controler = controler
-        
+
+        self.SDOMonitorEntries = {}
+        #----------------------------- SDO Monitor -------------------------------#
+        self.RBList = ["ON","OFF"]
+        
+        self.SDOMonitorRB = wx.RadioBox(self, label=_("monitoring"),
+                                        choices=self.RBList, majorDimension=2)
+        
+        self.SDOMonitorRB.SetSelection(1)
+        self.Bind(wx.EVT_RADIOBOX, self.OnRadioBox, self.SDOMonitorRB)
+       
+        self.SDOMonitorGrid = wx.grid.Grid(self,size=wx.Size(850,150),style=wx.EXPAND
+                                                        |wx.ALIGN_CENTER_HORIZONTAL
+                                                        |wx.ALIGN_CENTER_VERTICAL) 
+        self.SDOMonitorGrid.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, 
+                                                    self.onMonitorGridDoubleClick)
+
+        #----------------------------- SDO Entries ----------------------------#
+        self.SDOUpdateBtn = wx.Button(self, label=_("update"))         
+        self.SDOUpdateBtn.Bind(wx.EVT_BUTTON, self.OnSDOUpdate)
+        
+        self.SDOTraceThread = None
+        self.SDOMonitoringFlag = False
+        self.SDOValuesList = []
+        # Default SDO Page Number
+        self.SDOPageNum = 2
+
+        #----------------------------- Sizer --------------------------------------#
         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.SDOInfoBox = wx.StaticBox(self, label=_("SDO Entries"))
+        self.SDOMonitorBox = wx.StaticBox(self, label=_("SDO Monitor"))
+
+        self.SDONoteBook = SDONoteBook(self, controler=self.Controler)
+        self.SDOInfoBoxSizer = wx.StaticBoxSizer(self.SDOInfoBox, orient=wx.VERTICAL)
+        self.SDOMonitorBoxSizer = wx.StaticBoxSizer(self.SDOMonitorBox, 
+                                                                    orient=wx.VERTICAL)
+        self.SDOInfoBoxSizer.Add(self.SDOUpdateBtn)
+        
+        self.SDOInfoBoxSizer.Add(self.SDONoteBook, wx.ALL|wx.EXPAND)
+        self.SDOMonitorBoxSizer.Add(self.SDOMonitorRB)
+        self.SDOMonitorBoxSizer.Add(self.SDOMonitorGrid)
+        self.SDOManagementMainSizer.AddMany([self.SDOInfoBoxSizer, 
+                                             self.SDOMonitorBoxSizer])
         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 = []
+        #----------------------------- fill the contents --------------------------# 
+        #self.entries = self.Controler.CTNParent.CTNParent.GetEntriesList()
+
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        type_infos = slave.getType()
+        device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos)
+        self.entries = device.GetEntriesList()
+
+        self.Controler.CommonMethod.SDOVariables = []
+        self.Controler.CommonMethod.SDOSubEntryData = []
         self.Controler.CommonMethod.ClearSDODataSet()
-        self.SDOFlag = False
-        
-        # Check whether beremiz connected or not.
-        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        self.SDOParserXML(self.entries)
+        self.SDONoteBook.CreateNoteBook()      
+        self.CreateSDOMonitorGrid()
+        self.Refresh()
+
+    def OnSDOUpdate(self, event):
+        SlavePos = self.Controler.GetSlavePos()
+        num = self.SDOPageNum - 1
+        if num < 0:
+            for i in range(len(self.Controler.CommonMethod.SDOVariables)):
+                data = self.Controler.GetCTRoot()._connector.GetSDOEntriesData(
+                           self.Controler.CommonMethod.SDOVariables[i], SlavePos)
+                self.Controler.CommonMethod.SDOVariables[i] = data
+        else :
+            SDOUploadEntries = self.Controler.CommonMethod.SDOVariables[num]        
+            data = self.Controler.GetCTRoot()._connector.GetSDOEntriesData(SDOUploadEntries, SlavePos)
+            self.Controler.CommonMethod.SDOVariables[num] = data
+
+        self.SDONoteBook.CreateNoteBook()      
+        self.Refresh()
+
+    def OnRadioBox(self, event):
+        """
+        There are two selections that are on and off.
+        If the on is selected, the monitor thread begins to run.
+        If the off is selected, the monitor thread gets off.
+        @param event: wx.EVT_RADIOBOX object 
+        """
+        on, off = range(2)
+
+        if event.GetInt() == on:
+            CheckThreadFlag = self.SDOMonitoringThreadOn()
+            if not CheckThreadFlag:
+                self.SDOMonitorRB.SetSelection(off)
+        elif event.GetInt() == off:
+            self.SDOMonitoringThreadOff()
+
+    def SDOMonitoringThreadOn(self):
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = 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
+            self.SetSDOTraceValues(self.SDOMonitorEntries)
+            self.Controler.GetCTRoot()._connector.GetSDOData()
+            self.SDOTraceThread = Thread(target=self.SDOMonitorThreadProc)
+            self.SDOMonitoringFlag = True
+            self.SDOTraceThread.start()
+        return check_connect_flag
+
+    def SDOMonitoringThreadOff(self):
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
+        if check_connect_flag:
+            self.SDOMonitoringFlag = False
+            if self.SDOTraceThread is not None:
+                self.SDOTraceThread.join()
+            self.SDOTraceThread = None
+            self.Controler.GetCTRoot()._connector.StopSDOThread()
+
+    def SetSDOTraceValues(self, SDOMonitorEntries):
+        SlavePos = self.Controler.GetSlavePos()
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = True)
+        if check_connect_flag:
+            self.Controler.GetCTRoot()._connector.SetSDOTraceValues(SDOMonitorEntries, SlavePos)
+
+    def SDOMonitorThreadProc(self):
+        while self.SDOMonitoringFlag and self.Controler.GetCTRoot()._connector.PLCStatus != "Started":
+            self.SDOValuesList = self.Controler.GetCTRoot()._connector.GetSDOData()
+            LocalData = self.SDOValuesList[0].items()
+            LocalData.sort()
+            if self.SDOValuesList[1] != self.Controler.GetSlavePos():
+                continue
+            row = 0
+            for (idx, subidx), data in LocalData:
+                self.SDOMonitorGrid.SetCellValue(row, 6, str(data["value"]))
+                row += 1
+            time.sleep(0.5)
+
+    def CreateSDOMonitorGrid(self):
+        """
+        It creates SDO Monitor table and specifies cell size and labels.
+        """
+        self.SDOMonitorGrid.CreateGrid(0,7) 
+        SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 70), 
+                         (4, 40), (5, 450), (6, 85)]
+
+        for (index, size) in SDOCellSize:
+            self.SDOMonitorGrid.SetColSize(index, size)
+        
+        self.SDOMonitorGrid.SetRowLabelSize(0)
+
+        SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
+                         (3, "Type"), (4, "Size"), (5, "Name"), (6, "Value")]
+        
+        for (index, label) in SDOTableLabel:
+            self.SDOMonitorGrid.SetColLabelValue(index, label)
+            self.SDOMonitorGrid.SetColLabelAlignment(index, wx.ALIGN_CENTER)
+
+    def onMonitorGridDoubleClick(self, event):
+        """
+        Event Handler for double click on the SDO entries table.
+        It adds the entry into the SDO monitor table.
+        If the entry is already in the SDO monitor table, 
+        then it's removed from the SDO monitor table.
+        @pram event: gridlib.EVT_GRID_CELL_LEFT_DCLICK object
+        """
+        row = event.GetRow()
+        idx = self.SDOMonitorGrid.GetCellValue(row, 0)
+        subIdx = self.SDOMonitorGrid.GetCellValue(row, 1)
+        
+        del self.SDOMonitorEntries[(idx, subIdx)]
+        self.SDOMonitorGrid.DeleteRows(row, 1)
+        # add jblee
+        self.SetSDOTraceValues(self.SDOMonitorEntries)
+        self.SDOMonitorGrid.Refresh()
+
+    def SDOParserXML(self, entries):
+        """
+        Parse SDO data set that obtain "ESI file"
+        @param entries: SDO entry list 
+        """  
+        entries_list = entries.items()
+        entries_list.sort()
+        self.ForDefaultValueFlag = False
+        self.CompareValue = ""
+        self.sub_entry_value_list = []
+
+        for (index, subidx), entry in entries_list:
+            # exclude entry that isn't in the objects
+            check_mapping = entry["PDOMapping"]
+            if check_mapping is "T" or check_mapping is "R":
+                if "PDO index" not in entry.keys():
+                    continue
+
+            idx = "0" + entry["Index"].strip("#")
+            #subidx = hex(int(entry["SubIndex"], 0))
+            try :        
+                subidx = "0x" + entry["SubIndex"]
+            except :
+                subidx = "0x0"
+            datatype = entry["Type"]
+
+            try :
+                default_value = entry["DefaultData"]
+            except :
+                default_value = " --- "
+            # Result of SlaveSDO data parsing. (data type : dictionary)
+            self.Data = {'idx':idx, 'subIdx':subidx, 'access':entry["Access"], 
+                         'type':datatype, 'size': str(entry["BitSize"]), 
+                         'name':entry["Name"], 'value':default_value}
+            category_divide_value = [0x1000, 0x2000, 0x6000, 0xa000, 0xffff]
                 
-                # 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 count in range(len(category_divide_value)) :
+                if int(idx, 0) < category_divide_value[count]:
+                    self.Controler.CommonMethod.SDOVariables[count].append(self.Data)
+                    break
+
+        self.Controler.CommonMethod.SDOSubEntryData = self.sub_entry_value_list
     
 #-------------------------------------------------------------------------------
 #                    For SDO Notebook (divide category)
@@ -468,14 +574,14 @@
         @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))      
+        wx.Notebook.__init__(self, parent, id = -1, size=(850, 350))
         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)
+
+        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
         
     def CreateNoteBook(self): 
         """
@@ -500,48 +606,57 @@
                                "All SDO Object"]
 
         self.DeleteAllPages()
-        
+
+        self.Controler.CommonMethod.SDOVariables[5] = []
+        for i in range(4):
+            self.Controler.CommonMethod.SDOVariables[5] += self.Controler.CommonMethod.SDOVariables[i]
+            
         for txt, count in page_texts:
-            self.Data = self.Controler.CommonMethod.SaveSDOData[count]
-            self.Win = SlaveSDOTable(self, self.Data) 
+            self.Data = self.Controler.CommonMethod.SDOVariables[count]
+            self.SubEntryData = self.Controler.CommonMethod.SDOSubEntryData
+            self.Win = SlaveSDOTable(self, self.Data, self.SubEntryData)
             self.AddPage(self.Win, txt)
-        
+
+    # add jblee
     def OnPageChanged(self, event):
         old = event.GetOldSelection()
         new = event.GetSelection()
         sel = self.GetSelection()
+        self.parent.SDOPageNum = new
         event.Skip()
 
     def OnPageChanging(self, event):
         old = event.GetOldSelection()
         new = event.GetSelection()
-        sel = self.GetSelection()
+        sel = self.GetSelection()        
         event.Skip()
 
 #-------------------------------------------------------------------------------
 #                    For SDO Grid (fill index, subindex, etc...)
 #-------------------------------------------------------------------------------  
 class SlaveSDOTable(wx.grid.Grid):  
-    def __init__(self, parent, data):
+    def __init__(self, parent, data, fixed_value):
         """
         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)
+                              style=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
         
         self.Controler = parent.Controler
         self.parent = parent
         self.SDOFlag = True
         if data is None :
             self.SDOs = []
+            self.sub_entry_value = []
         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)]
+            self.sub_entry_value = fixed_value
+        
+        self.CreateGrid(len(self.SDOs), 7)
+        SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 70), 
+                         (4, 40), (5, 400), (6, 135)]
         
         for (index, size) in SDOCellSize:
             self.SetColSize(index, size)
@@ -549,17 +664,16 @@
         self.SetRowLabelSize(0)
         
         SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
-                         (3, "Type"), (4, "Size"), (5, "Category"),
-                         (6, "Name"), (7, "Value")]
+                         (3, "Type"), (4, "Size"), (5, "Name"), (6, "Value")]
         
         for (index, label) in SDOTableLabel:
             self.SetColLabelValue(index, label)
-            self.SetColLabelAlignment(index, wx.ALIGN_CENTRE)
+            self.SetColLabelAlignment(index, wx.ALIGN_CENTER)
             
         attr = wx.grid.GridCellAttr()
 
-        # for SDO download 
-        self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.SDOModifyDialog)
+        # for SDO download and monitoring 
+        self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.onGridDoubleClick)
         
         for i in range(7): 
             self.SetColAttr(i,attr)                   
@@ -572,55 +686,45 @@
         """
         Cell is filled by new parsing data
         """
-        sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'category', 'name', 'value']
+        sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'name', 'value']
+        count = 0
         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]])
+            for col_idx in range(len(self.SDOs[row_idx])):
+                
+                # the top entries that have sub index is shaded.
+                if int(self.SDOs[row_idx]['subIdx'], 16) == 0x00:
+                    try:
+                        if int(self.SDOs[row_idx + 1]['subIdx'], 16) is not 0x00:
+                            self.SetCellBackgroundColour(row_idx, col_idx, \
+                                                                wx.LIGHT_GREY)
+                    except:
+                        pass
+
+                if self.SDOs[row_idx][sdo_list[col_idx]] == "modifying":
+                    if len(self.sub_entry_value) == count:
+                        continue
+                    self.SetCellValue(row_idx, col_idx, self.sub_entry_value[count])
+                    count += 1
+                else :
+                    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)
+                    self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTER, wx.ALIGN_CENTER)
         
     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-- 
+        check that access field has "rw"
         @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 :
+        if check == "rw":
             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
+        else:
+            return False
     
     def ClearStateFlag(self):
         """
@@ -631,7 +735,7 @@
         self.Controler.CommonMethod.Check_SAFEOP = False
         self.Controler.CommonMethod.Check_OP = False
     
-    def SDOModifyDialog (self, event):
+    def onGridDoubleClick (self, event):
         """
         Create dialog for SDO value modify
         if user enter data, perform command "ethercat download"  
@@ -640,32 +744,100 @@
         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)
+        if event.GetCol() == 6 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()]) :
+                # Check whether beremiz connected or not.
+                # If this method is called cyclically, set the cyclic flag true
+                check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
+                if check_connect_flag:
+                    try :
+                        input_val = hex(int(dlg.GetValue(), 0))
                         # 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')    
-
+                        return_val = self.Controler.CommonMethod.SDODownload(
+                                                self.SDOs[event.GetRow()]["type"], 
+                                                self.SDOs[event.GetRow()]["idx"], 
+                                                self.SDOs[event.GetRow()]["subIdx"], 
+                                                dlg.GetValue())
+                        if return_val is "":
+                            SDOUploadEntry = {"idx" : self.SDOs[event.GetRow()]["idx"],
+                                              "subIdx" : self.SDOs[event.GetRow()]["subIdx"],
+                                              "size" : self.SDOs[event.GetRow()]["size"]
+                                             }
+                            data = self.Controler.GetCTRoot()._connector.GetSDOEntryData(
+                                SDOUploadEntry, self.Controler.GetSlavePos())
+                            hex_val = hex(data)[:-1]                           
+
+                            # download data check
+                            if input_val == hex_val:
+                                display_val = "%s(%d)" % (hex_val, data) 
+                                self.SetCellValue(event.GetRow(), event.GetCol(), 
+                                                  display_val)
+                            else :
+                                self.Controler.CommonMethod.CreateErrorDialog(\
+                                            'SDO Value not completely download, please try again')    
+                        else:
+                            self.Controler.GetCTRoot().logger.write_error(return_val)
+                            
+                    # 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')    
+        else:
+            SDOPanel = self.parent.parent
+            row = event.GetRow() 
+            
+            idx = self.SDOs[row]["idx"]
+            subIdx = self.SDOs[row]["subIdx"]
+            SDOPanel.SDOMonitorEntries[(idx, subIdx)] = {
+                                                "access": self.SDOs[row]["access"],
+                                                "type": self.SDOs[row]["type"],
+                                                "size": self.SDOs[row]["size"],
+                                                "name": self.SDOs[row]["name"],
+                                                # add jblee
+                                                "value": ""}
+            
+            del_rows = SDOPanel.SDOMonitorGrid.GetNumberRows()
+            
+            try: 
+                SDOPanel.SDOMonitorGrid.DeleteRows(0, del_rows)
+            except:
+                pass
+
+            SDOPanel.SDOMonitorGrid.AppendRows(len(SDOPanel.SDOMonitorEntries))
+            SDOPanel.SetSDOTraceValues(SDOPanel.SDOMonitorEntries)
+            
+            SME_list = SDOPanel.SDOMonitorEntries.items()
+            SME_list.sort()
+
+            gridRow = 0
+            for (idx, subIdx), entry in SME_list:
+                SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, 0, str(idx))
+                SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, 1, str(subIdx))
+                for col, key in [(2, "access"),
+                                 (3, "type"),
+                                 (4, "size"),
+                                 (5, "name")]:
+                    SDOPanel.SDOMonitorGrid.SetCellValue(gridRow, col, entry[key])
+                for col in range(7):
+                    SDOPanel.SDOMonitorGrid.SetReadOnly(gridRow, col, True)
+                    if col < 5 :
+                        SDOPanel.SDOMonitorGrid.SetCellAlignment(\
+                                        gridRow, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER)
+                gridRow += 1
+            
+            SDOPanel.SDOMonitorGrid.Refresh()
 
 #-------------------------------------------------------------------------------
-#                 For PDO Monitoring Panel
+#                 For PDO Mapping Panel
 # PDO Class UI  : Panel -> Choicebook (RxPDO, TxPDO) -> 
 #                 Notebook (PDO Index) -> Grid (PDO entry)
 #-------------------------------------------------------------------------------  
@@ -678,16 +850,152 @@
         """
         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)
+        sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
+        line = wx.StaticText(self, -1, "\n In order to control Ethercat device, user must select proper PDO set.\
+                                        \n Each PDO sets describe operation modes (CSP, CSV, CST) supported by Ethercat devices.\
+                                      \n\n PDOs have two types, RxPDO and TxPDO.\
+                                        \n  - RxPDO refers to the Receive Process Data Object. It means the control parameters which sent from controller to the EtherCAT Slave device.\
+                                        \n    In general, ControlWord (0x6040), Modes of Operations (0x6060), and TargetPosition (0x607A) are regarded as RxPDO.\
+                                        \n  - TxPDO refers to the Transmit Process Data Object. It used to report status of EtherCAT Slave device to the controller in order to calibrate their next actuation.\
+                                        \n    StatusWord (0x6041), Modes of Operation Display (0x6061), and ActualPosition (0x607A) include in TxPDO.\
+                                      \n\n PDO Mapping feature provides available RxPDO and TxPDO sets which defined in Ethercat slave description XML.\
+                                        \n If there is no selection of PDO set, first set (0x1600, 0x1A00) will be chosen as default configuration.")
+        
+        sizer.Add(line)
+        self.SetSizer(sizer)
+
+class RxPDOPanelClass(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
+
+        # add jblee
+        #self.PDOIndexList = ["RxPDO"]
+        self.PDOIndexList = []
+        self.LoadPDOSelectData()
+
+        #HSAHN ADD. 2015.7.26 PDO Select Function ADD
+        self.Controler.CommonMethod.RequestPDOInfo()
+        self.PDOcheckBox = []
+        self.rx_pdo_entries = self.Controler.CommonMethod.GetRxPDOCategory()
+        if len(self.rx_pdo_entries):
+            for i in range(len(self.rx_pdo_entries)):
+                self.PDOcheckBox.append(wx.CheckBox(self, label=str(hex(self.rx_pdo_entries[i]['pdo_index'])), size=(120,15)))
+                if not self.Controler.SelectedRxPDOIndex and self.rx_pdo_entries[i]['sm'] is not None:
+                    self.PDOcheckBox[-1].SetValue(True)
+                    self.Controler.SelectedRxPDOIndex.append(int(self.PDOcheckBox[-1].GetLabel(), 0))
+                    self.InitSavePDO()
+                elif self.rx_pdo_entries[i]['pdo_index'] in self.Controler.SelectedRxPDOIndex:
+                    self.PDOIndexList.append(str(hex(self.rx_pdo_entries[i]['pdo_index'])))
+                    self.PDOcheckBox[-1].SetValue(True)
+                    
+            for cb in self.PDOcheckBox:
+                self.Bind(wx.EVT_CHECKBOX, self.PDOSelectCheck, cb)
+
+            self.PDOListBox = wx.StaticBox(self, label=_("PDO Mapping Select"))
+            self.PDOListBoxSizer = wx.StaticBoxSizer(self.PDOListBox, orient=wx.HORIZONTAL)
+            self.RxPDOListBox = wx.StaticBox(self, label=_("RxPDO"))
+            self.RxPDOListBoxSizer = wx.StaticBoxSizer(self.RxPDOListBox, orient=wx.VERTICAL)
+            self.RxPDOListBoxInnerSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=10, vgap=5)
+            self.RxPDOListBoxInnerSizer.AddMany(self.PDOcheckBox[0:len(self.rx_pdo_entries)])
+            self.RxPDOListBoxSizer.Add(self.RxPDOListBoxInnerSizer)
+            self.PDOListBoxSizer.Add(self.RxPDOListBoxSizer)
+            self.PDOWarningText = wx.StaticText(self, -1,
+                       "  *Warning*\n\n By default configuration, \n\n first mapping set is selected. \n\n Choose the PDO mapping!",
+                       size=(220, -1))
+            self.PDOListBoxSizer.Add(self.PDOWarningText)
+
+            self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
+            self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
+
+        
+            self.CallPDOChoicebook = PDONoteBook(self, controler=self.Controler, name="Rx")
+            self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)
+
+            self.PDOInformationBox = wx.StaticBox(self, label=_("RxPDO Mapping List"))
+            self.PDOInformationBoxSizer = wx.StaticBoxSizer(self.PDOInformationBox, orient=wx.VERTICAL)
+            self.PDOInformationBoxSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
+
+            self.PDOMonitoringEditorMainSizer.Add(self.PDOListBoxSizer)
+            self.PDOMonitoringEditorMainSizer.Add(self.PDOInformationBoxSizer)
+            self.SetSizer(self.PDOMonitoringEditorMainSizer)
+
+            # add jblee
+            self.PDOExcludeCheck()
+        else:
+            sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
+            line = wx.StaticText(self, -1, "\n  This device does not support RxPDO.")
+        
+            sizer.Add(line)
+            self.SetSizer(sizer)
+
+    def LoadPDOSelectData(self):
+        RxPDOData = self.Controler.BaseParams.getRxPDO()
+        RxPDOs = []
+        if RxPDOData != "None":
+            RxPDOs = RxPDOData.split()
+        if RxPDOs :
+            for RxPDO in RxPDOs :
+                self.Controler.SelectedRxPDOIndex.append(int(RxPDO, 0))
+
+    def PDOSelectCheck(self, event):
+        # add jblee for Save User Select
+        cb = event.GetEventObject()
+                         # prevent duplicated check
+        if cb.GetValue() and int(cb.GetLabel(), 0) not in self.Controler.SelectedRxPDOIndex:
+            self.Controler.SelectedRxPDOIndex.append(int(cb.GetLabel(), 0))
+            self.PDOIndexList.append(cb.GetLabel())
+        else:
+            self.Controler.SelectedRxPDOIndex.remove(int(cb.GetLabel(), 0))
+            self.PDOIndexList.remove(cb.GetLabel())
+
+        data = ""
+        for PDOIndex in self.PDOIndexList:            
+            data = data + " " + PDOIndex
+
+        self.Controler.BaseParams.setRxPDO(data)
+        self.Controler.GetCTRoot().CTNRequestSave()
+
+        self.PDOExcludeCheck()
+
+    def InitSavePDO(self):
+        for PDOIndex in self.Controler.SelectedRxPDOIndex:
+            self.PDOIndexList.append(str(hex(PDOIndex)))
+
+        data = ""
+        for PDOIndex in self.PDOIndexList:            
+            data = data + " " + PDOIndex
+
+        self.Controler.BaseParams.setRxPDO(data)
+
+    # 2016.06.21
+    # add jblee for check exclude pdo list
+    def PDOExcludeCheck(self):
+        #files = os.listdir(self.Controler.CTNPath())
+        #filepath = os.path.join(self.Controler.CTNPath(), "DataForPDO.txt")
+        CurIndexs = self.Controler.SelectedRxPDOIndex
+        for CB in self.PDOcheckBox:
+            if len(CB.GetLabel().split()) > 1:
+                CB.Enable()
+                CB.SetLabel(CB.GetLabel().split()[0])
+
+        for pdo in self.rx_pdo_entries:
+            for CurIndex in CurIndexs:
+                if pdo["pdo_index"] == CurIndex:
+                    ex_list = pdo["exclude_list"]
+                    for ex_item in ex_list:
+                        for CB in self.PDOcheckBox:
+                            if CB.GetLabel() == hex(ex_item):
+                                CB.SetLabel(CB.GetLabel() + " (Excluded)")
+                                CB.Disable()
+
+    def RefreshPDOInfo(self):
+        pass
 
     def PDOInfoUpdate(self):
         """
@@ -695,43 +1003,142 @@
         """
         self.Controler.CommonMethod.RequestPDOInfo()
         self.CallPDOChoicebook.Destroy()
-        self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)
+        self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler, name="Rx")
         self.Refresh()
 
-
-#-------------------------------------------------------------------------------
-#                    For PDO Choicebook (divide Tx, Rx PDO)
-#-------------------------------------------------------------------------------  
-class PDOChoicebook(wx.Choicebook):
+class TxPDOPanelClass(wx.Panel):
     def __init__(self, parent, controler):
         """
         Constructor
-        @param parent: Reference to the parent PDOPanelClass class
+        @param parent: Reference to the parent EtherCATManagementTreebook class
         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
         """
-        wx.Choicebook.__init__(self, parent, id=-1, size=(500, 500), style=wx.CHB_DEFAULT)
+        wx.Panel.__init__(self, parent, -1)
         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()     
-
+
+        # add jblee
+        self.PDOIndexList = []
+        self.LoadPDOSelectData()
+
+        #HSAHN ADD. 2015.7.26 PDO Select Function ADD
+        self.Controler.CommonMethod.RequestPDOInfo()
+        self.PDOcheckBox = []
+        self.tx_pdo_entries = self.Controler.CommonMethod.GetTxPDOCategory()
+        if len(self.tx_pdo_entries):
+            for i in range(len(self.tx_pdo_entries)):
+                self.PDOcheckBox.append(wx.CheckBox(self, label=str(hex(self.tx_pdo_entries[i]['pdo_index'])), size=(120,15)))
+                if not self.Controler.SelectedTxPDOIndex and self.tx_pdo_entries[i]['sm'] is not None:
+                    self.PDOcheckBox[-1].SetValue(True)
+                    self.Controler.SelectedTxPDOIndex.append(int(self.PDOcheckBox[-1].GetLabel(), 0))
+                    self.InitSavePDO()
+                elif self.tx_pdo_entries[i]['pdo_index'] in self.Controler.SelectedTxPDOIndex:
+                    self.PDOIndexList.append(str(hex(self.tx_pdo_entries[i]['pdo_index'])))
+                    self.PDOcheckBox[-1].SetValue(True)
+            for cb in self.PDOcheckBox:
+                self.Bind(wx.EVT_CHECKBOX, self.PDOSelectCheck, cb)
+        
+            self.PDOListBox = wx.StaticBox(self, label=_("PDO Mapping Select"))
+            self.PDOListBoxSizer = wx.StaticBoxSizer(self.PDOListBox, orient=wx.HORIZONTAL)
+            self.TxPDOListBox = wx.StaticBox(self, label=_("TxPDO"))
+            self.TxPDOListBoxSizer = wx.StaticBoxSizer(self.TxPDOListBox, orient=wx.VERTICAL)
+            self.TxPDOListBoxInnerSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=10, vgap=5)
+            self.TxPDOListBoxInnerSizer.AddMany(self.PDOcheckBox[0:len(self.tx_pdo_entries)])
+            self.TxPDOListBoxSizer.Add(self.TxPDOListBoxInnerSizer)
+            self.PDOListBoxSizer.Add(self.TxPDOListBoxSizer)
+            self.PDOWarningText = wx.StaticText(self, -1,
+                       "  *Warning*\n\n By default configuration, \n\n first mapping set is selected. \n\n Choose the PDO mapping!",
+                       size=(220, -1))
+            self.PDOListBoxSizer.Add(self.PDOWarningText)
+
+            self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
+            self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
+
+            self.CallPDOChoicebook = PDONoteBook(self, controler=self.Controler, name="Tx")
+            self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)
+
+            self.PDOInformationBox = wx.StaticBox(self, label=_("TxPDO Mapping List"))
+            self.PDOInformationBoxSizer = wx.StaticBoxSizer(self.PDOInformationBox, orient=wx.VERTICAL)
+            self.PDOInformationBoxSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
+
+            self.PDOMonitoringEditorMainSizer.Add(self.PDOListBoxSizer)
+            self.PDOMonitoringEditorMainSizer.Add(self.PDOInformationBoxSizer)
+            self.SetSizer(self.PDOMonitoringEditorMainSizer)
+
+            # add jblee
+            self.PDOExcludeCheck()
+        else:
+            sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
+            line = wx.StaticText(self, -1, "\n  This device does not support TxPDO.")
+        
+            sizer.Add(line)
+            self.SetSizer(sizer)
+
+    def LoadPDOSelectData(self):
+        TxPDOData = self.Controler.BaseParams.getTxPDO()
+        TxPDOs = []
+        if TxPDOData != "None":
+            TxPDOs = TxPDOData.split()
+        if TxPDOs :
+            for TxPDO in TxPDOs :
+                self.Controler.SelectedTxPDOIndex.append(int(TxPDO, 0))
+
+    def PDOSelectCheck(self, event):
+        # add jblee for Save User Select
+        cb = event.GetEventObject()
+                         # prevent duplicated check
+        if cb.GetValue() and int(cb.GetLabel(), 0) not in self.Controler.SelectedTxPDOIndex:
+            self.Controler.SelectedTxPDOIndex.append(int(cb.GetLabel(), 0))
+            self.PDOIndexList.append(cb.GetLabel())
+        else:
+            self.Controler.SelectedTxPDOIndex.remove(int(cb.GetLabel(), 0))
+            self.PDOIndexList.remove(cb.GetLabel())
+
+        data = ""
+        for PDOIndex in self.PDOIndexList:            
+            data = data + " " + PDOIndex
+
+        self.Controler.BaseParams.setTxPDO(data)
+        self.Controler.GetCTRoot().CTNRequestSave()
+
+        self.PDOExcludeCheck()
+
+    def InitSavePDO(self):
+        for PDOIndex in self.Controler.SelectedTxPDOIndex:
+            self.PDOIndexList.append(str(hex(PDOIndex)))
+
+        data = ""
+        for PDOIndex in self.PDOIndexList:            
+            data = data + " " + PDOIndex
+
+        self.Controler.BaseParams.setTxPDO(data)
+
+    # 2016.06.21
+    # add jblee for check exclude pdo list
+    def PDOExcludeCheck(self):
+        CurIndexs = self.Controler.SelectedTxPDOIndex
+        for CB in self.PDOcheckBox:
+            if len(CB.GetLabel().split()) > 1:
+                CB.Enable()
+                CB.SetLabel(CB.GetLabel().split()[0])
+
+        for pdo in self.tx_pdo_entries:
+            for CurIndex in CurIndexs:
+                if pdo["pdo_index"] == CurIndex:
+                    ex_list = pdo["exclude_list"]
+                    for ex_item in ex_list:
+                        for CB in self.PDOcheckBox:
+                            if CB.GetLabel() == hex(ex_item):
+                                CB.SetLabel(CB.GetLabel() + " (Excluded)")
+                                CB.Disable()
+
+    def PDOInfoUpdate(self):
+        """
+        Call RequestPDOInfo method and create Choicebook
+        """
+        self.Controler.CommonMethod.RequestPDOInfo()
+        self.CallPDOChoicebook.Destroy()
+        self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler, name="Tx")
+        self.Refresh()
 
 #-------------------------------------------------------------------------------
 #                    For PDO Notebook (divide PDO index)
@@ -744,14 +1151,12 @@
         @param name: identifier whether RxPDO or TxPDO
         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
         """
-        wx.Notebook.__init__(self, parent, id=-1, size=(640, 400))
+        wx.Notebook.__init__(self, parent, id=-1, size=(600, 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)
@@ -774,22 +1179,6 @@
             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...)
 #-------------------------------------------------------------------------------  
@@ -803,7 +1192,7 @@
         @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)
+                              style=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
         
         self.Controler = parent.Controler
         
@@ -854,13 +1243,190 @@
                 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)
+                    self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTER, wx.ALIGN_CENTER)
                 else :
-                    self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
+                    self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_LEFT, wx.ALIGN_CENTER)
                 self.SetReadOnly(row_idx, col_idx, True)
                 self.SetRowSize(row_idx, 25)
             start_value += 1
 
+#-------------------------------------------------------------------------------
+#                    For MDP Main Panel         
+#-------------------------------------------------------------------------------  
+class MDPPanel(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
+
+        sizer = wx.FlexGridSizer(cols=3, hgap=20, rows=1, vgap=20)
+
+        # Include Module ListBox
+        leftInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10)
+        # Include Add, Delete Button
+        middleInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10)
+        # Include Slot ListBox
+        rightInnerSizer = wx.FlexGridSizer(cols=1, hgap=10,rows=2, vgap=10)
+        
+        # Get Module Name as Array
+        # MDPArray = {SlaveName, [data0, data1, ...], SlotIndexIncrement, SlotPdoIncrement}
+        # data = [ModuleName, ModuleInfo, [PDOInfo1, PDOInfo2, ...]]
+        # PDOInfo = {Index, Name, BitSize, Access, PDOMapping, SubIndex, Type}
+        slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos())
+        type_infos = slave.getType()
+        MDPArray = self.Controler.CTNParent.CTNParent.GetMDPInfos(type_infos)
+
+        NameSet = []
+        if MDPArray:
+            for info in MDPArray[0][1]:
+                NameSet.append(info[0])
+
+        # Module ListBox
+        self.ModuleLabel = wx.StaticText(self, -1, "Module")
+        self.ModuleListBox = wx.ListBox(self, size = (150, 200), choices = NameSet)
+        #self.ModuleListBox = wx.ListBox(self, size = (150, 200), choices = [])
+        self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnModuleListBoxDCClick, self.ModuleListBox)
+
+        # Button
+        self.AddButton = wx.Button(self, label=_(" Add Module  "))
+        self.DeleteButton = wx.Button(self, label=_("Delete Module"))
+
+        # Button Event Mapping
+        self.AddButton.Bind(wx.EVT_BUTTON, self.OnAddButton)
+        self.DeleteButton.Bind(wx.EVT_BUTTON, self.OnDeleteButton)
+
+        # Slot ListBox
+        self.SlotLabel = wx.StaticText(self, -1, "Slot")
+        self.SlotListBox = wx.ListBox(self, size = (150, 200))
+        self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnSlotListBoxDCClick, self.SlotListBox)
+        self.SelectModule = []
+
+        # Add Object Each Sizer
+        leftInnerSizer.AddMany([self.ModuleLabel, self.ModuleListBox])
+        middleInnerSizer.Add(self.AddButton, 0, wx.TOP, 100)
+        middleInnerSizer.Add(self.DeleteButton, 0, wx.BOTTOM, 120)
+        rightInnerSizer.AddMany([self.SlotLabel, self.SlotListBox])
+        
+        sizer.AddMany([leftInnerSizer, middleInnerSizer, rightInnerSizer])
+        
+        self.SetSizer(sizer)
+
+        self.InitMDPSet()
+
+    def InitMDPSet(self):
+        files = os.listdir(self.Controler.CTNPath())
+        filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
+        try:
+            moduleDataFile = open(filepath, 'r')
+            lines = moduleDataFile.readlines()
+
+            for line in lines:
+                if line == "\n":
+                    continue
+                module_pos = line.split()[-1]
+                name_len_limit = len(line) - len(module_pos) - 2
+                module_name = line[0:name_len_limit]
+                
+                self.SelectModule.append((module_name, int(module_pos)))
+
+            localModuleInfo = []        
+            count = 1
+            for (item, pos) in self.SelectModule:
+                slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
+                localModuleInfo.append(slotString)
+                count += 1
+            self.SlotListBox.SetItems(localModuleInfo)
+
+        except:
+            moduleDataFile = open(filepath, 'w')
+
+        moduleDataFile.close()
+
+    def OnAddButton(self, event):
+        files = os.listdir(self.Controler.CTNPath())
+        filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
+        moduleDataFile = open(filepath, 'w')
+
+        selectNum = self.ModuleListBox.GetSelection()
+        if selectNum >= 0:
+            selectStr = self.ModuleListBox.GetString(selectNum)
+            self.SelectModule.append((selectStr, selectNum))
+            localModuleInfo = []
+            count = 1
+            for (item, pos) in self.SelectModule:
+                slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
+                localModuleInfo.append(slotString)
+                count += 1
+            self.SlotListBox.SetItems(localModuleInfo)
+
+        moduleDataFile.close()
+        
+    def OnDeleteButton(self, event):
+        files = os.listdir(self.Controler.CTNPath())
+        filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
+        moduleDataFile = open(filepath, 'w')
+
+        selectNum = self.SlotListBox.GetSelection()
+        if selectNum >= 0:
+            selectStr = self.SlotListBox.GetString(selectNum)
+            self.SelectModule.pop(selectNum)
+            localModuleInfo = []
+            count = 1
+            for (item, pos) in self.SelectModule:
+                moduleDataFile.write(item + " " + str(pos) + "\n")
+                slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
+                localModuleInfo.append(slotString)
+                count += 1
+            self.SlotListBox.SetItems(localModuleInfo)
+
+        moduleDataFile.close()
+
+    def OnModuleListBoxDCClick(self, event):
+        files = os.listdir(self.Controler.CTNPath())
+        filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
+        moduleDataFile = open(filepath, 'w')
+
+        selectNum = self.ModuleListBox.GetSelection()
+        if selectNum >= 0:
+            selectStr = self.ModuleListBox.GetString(selectNum)
+            self.SelectModule.append((selectStr, selectNum))
+            localModuleInfo = []
+            count = 1
+            for (item, pos) in self.SelectModule:
+                moduleDataFile.write(item + " " + str(pos) + "\n")
+                slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
+                localModuleInfo.append(slotString)
+                module = self.Controler.CTNParent.CTNParent.GetSelectModule(pos)
+                self.Controler.CommonMethod.SavePDOData(module)
+                count += 1
+            self.SlotListBox.SetItems(localModuleInfo)
+
+        moduleDataFile.close()
+
+    def OnSlotListBoxDCClick(self, event):
+        files = os.listdir(self.Controler.CTNPath())
+        filepath = os.path.join(self.Controler.CTNPath(), "DataForMDP.txt")
+        moduleDataFile = open(filepath, 'w')
+
+        selectNum = self.SlotListBox.GetSelection()
+        if selectNum >= 0:
+            selectStr = self.SlotListBox.GetString(selectNum)
+            self.SelectModule.pop(selectNum)
+            localModuleInfo = []
+            count = 1
+            for (item, pos) in self.SelectModule:
+                moduleDataFile.write(item + " " + str(pos) + "\n")
+                slotString = "Slot %d %s : " % (count, item.split()[1]) + item.split()[0]
+                localModuleInfo.append(slotString)
+                count += 1
+            self.SlotListBox.SetItems(localModuleInfo)
+
+        moduleDataFile.close()
 
 #-------------------------------------------------------------------------------
 #                    For EEPROM Access Main Panel 
@@ -899,7 +1465,9 @@
         self.parent = parent
         self.Controler = controler
         
+        # PDI Type 1, 13 unknown Type, Fix Future
         self.PDIType = {0  :['none', '00000000'], 
+                        1  :['unknown', '00000000'],
                         4  :['Digital I/O', '00000100'],
                         5  :['SPI Slave', '00000101'],
                         7  :['EtherCAT Bridge (port3)', '00000111'],
@@ -907,6 +1475,7 @@
                         9  :['uC async. 8bit', '00001001'],
                         10 :['uC sync. 16bit', '00001010'],
                         11 :['uC sync. 8bit', '00001011'],
+                        13 :['unknown', '00000000'],
                         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'],
@@ -944,8 +1513,9 @@
         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)
+        # Check whether beremiz connected or not. 
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
         if check_connect_flag:
             status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
             if status is not "Started":
@@ -975,7 +1545,8 @@
         @param event : wx.EVT_BUTTON object
         """  
         # Check whether beremiz connected or not.
-        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
         if check_connect_flag:
             self.SiiBinary = self.Controler.CommonMethod.LoadData()
             self.SetEEPROMData()
@@ -1002,7 +1573,7 @@
             if cnt_pdi_type == i:
                 cnt_pdi_type = self.PDIType[i][0]
                 break
-        #  Set Config Data
+        # Set Config Data
         for treelist, data in [("EEPROM Size (Bytes)", 
                                 str(self.Controler.CommonMethod.SmartViewInfosFromXML["eeprom_size"])),
                                ("PDI Type", 
@@ -1012,7 +1583,7 @@
             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
         
         # Device Identity: Vendor ID, Product Code, Revision No., Serial No.
-        #  Set Device Identity
+        # 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"]),
@@ -1020,18 +1591,18 @@
             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
              
         # Mailbox: Supported Mailbox, Bootstrap Configuration, Standard Configuration
-        #  Set Mailbox
+        # 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
+        # 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
+        # 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"]),
@@ -1042,7 +1613,6 @@
         """
         Set data based on slave EEPROM.
         """  
-        # sii_dict = { Parameter : (WordAddress, WordSize) }
         sii_dict= { 'PDIControl' :                          ( '0', 1),
                     'PDIConfiguration' :                    ( '1', 1),
                     'PulseLengthOfSYNCSignals' :            ( '2', 1),
@@ -1081,16 +1651,16 @@
             if cnt_pdi_type == i:
                 cnt_pdi_type = self.PDIType[i][0]
                 break
-        #  Get Device Emulation
+        # Get Device Emulation
         device_emulation = str(bool(int("{:0>16b}".format(int(self.GetWordAddressData( sii_dict.get('PDIControl'),16 ), 16))[7])))    
-        #  Set Config Data
+        # 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
+        # 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 )),
@@ -1108,18 +1678,18 @@
             if mailbox_data[protocol+2] == '1':
                 supported_mailbox += mailbox_protocol[protocol]
         supported_mailbox = supported_mailbox.strip(",  ")
-        #  Set Mailbox
+        # 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
+        # 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
+        # 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 )),
@@ -1190,31 +1760,31 @@
         self.Root = self.Tree.AddRoot("")
         
         # Add item
-        #  Level 1 nodes
+        # 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
+        # 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
+        # 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
+        # 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
+        # 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
+        # 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)
@@ -1292,7 +1862,8 @@
         @param event : wx.EVT_BUTTON object
         """  
         # Check whether beremiz connected or not.
-        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
         if check_connect_flag:
             # load from EEPROM data and parsing
             self.SiiBinary = self.Controler.CommonMethod.LoadData()
@@ -1307,9 +1878,9 @@
         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)
+        # Check whether beremiz connected or not.
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
         if check_connect_flag:
             status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
             if status is not "Started":
@@ -1387,7 +1958,7 @@
         self.Col = col    
         
         wx.grid.Grid.__init__(self, parent, -1, size=(830,450), 
-                              style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
+                              style=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
 
     def SetValue(self, value):
         """
@@ -1415,7 +1986,7 @@
                 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.SetCellAlignment(row, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER)
                     
                 self.SetReadOnly(row, col, True)
                 col = col + 1
@@ -1428,10 +1999,10 @@
 class RegisterAccessPanel(wx.Panel):
     def __init__(self, parent, controler):
         """
-	    Constructor
-	    @param parent: EEPROMAccessPanel object
-	    @param controler: _EthercatSlaveCTN class in EthercatSlave.py
-	    """
+	Constructor
+	@param parent: EEPROMAccessPanel object
+	@param controler: _EthercatSlaveCTN class in EthercatSlave.py
+	"""
         self.parent = parent
         self.Controler = controler
         self.__init_data()
@@ -1474,7 +2045,7 @@
         # flag for compact view
         self.CompactFlag = False
         
-        # main grid의 rows and cols
+        # main grid��rows and cols
         self.MainRow = [512, 512, 512, 512]
         self.MainCol = 4
         
@@ -1483,7 +2054,7 @@
         for index in range(4):
             self.PageRange.append([512*index, 512*(index+1)])
         
-        #  Previous value of register data for register description configuration
+        # Previous value of register data for register description configuration
         self.PreRegSpec = {"ESCType": "",
                            "FMMUNumber": "",
                            "SMNumber": "",
@@ -1494,9 +2065,9 @@
         Get data from the register.
         """
         self.Controler.CommonMethod.RegData = ""
-        #ethercat reg_read
-        #ex : ethercat reg_read -p 0 0x0000 0x0001
-        #return value : 0x11
+        # 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")
         
@@ -1709,7 +2280,8 @@
         @param event: wx.EVT_BUTTON object
         """
         # Check whether beremiz connected or not.
-        check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
+        # If this method is called cyclically, set the cyclic flag true
+        check_connect_flag = self.Controler.CommonMethod.CheckConnect(cyclic_flag = False)
         if check_connect_flag:
             self.LoadData()
             self.BasicSetData()
@@ -1809,21 +2381,6 @@
             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 
@@ -1900,20 +2457,19 @@
 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
-	    """
+	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)        
+                              style=wx.EXPAND|wx.ALIGN_CENTER_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),
@@ -1922,12 +2478,12 @@
        
     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
-	    """
+	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
@@ -1950,16 +2506,16 @@
             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.SetCellAlignment(row, col, wx.ALIGN_CENTER, 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)
-	    """
+	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()
@@ -2051,9 +2607,9 @@
 class RegisterSubTable(wx.grid.Grid):
     def __init__(self, parent, row, col):
         """
-    	 Constructor
-    	 @param parent: RegisterNotebook object
-    	 @param row, col: size of the table
+    	Constructor
+    	@param parent: RegisterNotebook object
+    	@param row, col: size of the table
     	"""
         self.parent = parent
         self.Data = {}
@@ -2061,14 +2617,14 @@
         self.Col = col
 
         wx.grid.Grid.__init__(self, parent, -1, size=(820,150), 
-                              style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
+                              style=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
 
     def SetValue(self, parent, data):
         """
-	    Set the data into the subtable.
-	    @param parent: RegisterNotebook object
-	    @param data: 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")]
@@ -2085,7 +2641,7 @@
             col = 0     
             for element in rowData:
                 self.SetCellValue(row, col, element)
-                self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
+                self.SetCellAlignment(row, col, wx.ALIGN_CENTER, wx.ALIGN_CENTER)
                 self.SetReadOnly(row, col, True)
                 col = col + 1
             row = row + 1
@@ -2099,97 +2655,107 @@
         """
         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)
+        @Param controler: _EthercatCTN class in EthercatMaster.py
+        """
+        wx.Panel.__init__(self, parent)
         self.Controler = controler
         self.parent = parent
         self.StaticBox = {}
         self.StaticText = {}
         self.TextCtrl = {}
           
-        # ----------------------- Main Sizer and Update Button --------------------------------------------
+        # ---------------------------- Main Sizer and Buttons --------------------------------------------
         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]),
+            ("innerTop",            [2, 10, 1, 10]),
+            ("innerMiddle",         [1, 10, 1, 10]),
+            ("innerBottom",         [1, 10, 1, 10]),
             ("innerMasterState",    [2, 10, 3, 10]),
             ("innerDeviceInfo",     [4, 10, 3, 10]),
-            ("innerFrameInfo",      [4, 10, 5, 10])]:
+            ("innerFrameInfo",      [4, 10, 5, 10]),
+            ("innerSlaveInfo",     [1, 10, 2, 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)
-       
+        self.MSUpdateButton = wx.Button(self, label=_("Update"))
+        self.MSUpdateButton.Bind(wx.EVT_BUTTON, self.OnMSUpdateButtonClick)
+        self.SIUpdateButton = wx.Button(self, label=_("Update"))
+        self.SIUpdateButton.Bind(wx.EVT_BUTTON, self.OnSIUpdateButtonClick)
+        
         for key, label in [                
-            ('masterState', 'EtherCAT Master State'),
-            ('deviceInfo', 'Ethernet Network Card Information'),
-            ('frameInfo', 'Network Frame Information')]:
+            ("masterState", "EtherCAT Master State"),
+            ("deviceInfo", "Ethernet Network Card Information"),
+            ("frameInfo", "Network Frame Information"),
+            ("slaveInfo", "Slave 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:')]:
+            ("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'])
+            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:')]:
+            ("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'])
+            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 [%]:')]:
+            ("Tx frame rate [1/s]", "Tx Frame Rate [1/s]:"), 
+            ("Tx rate [KByte/s]", "Tx Rate [KByte/s]:"), 
+            ("Rx frame rate [1/s]", "Rx Frame Rate [1/s]:"), 
+            ("Rx rate [KByte/s]", "Rx 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.MasterStateSizer["innerFrameInfo"].Add(self.StaticText[key])
             self.TextCtrl[key] = {} 
-            for index in ['0', '1', '2']:                
+            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'])
-        
+                self.MasterStateSizer["innerFrameInfo"].Add(self.TextCtrl[key][index])
+        
+        self.MasterStateSizer["frameInfo"].AddSizer(self.MasterStateSizer["innerFrameInfo"])
+        
+        # ------------------------------- Slave Information  -----------------------------------------------
+        self.SITreeListCtrl = SITreeListCtrl(self, self.Controler) 
+        self.MasterStateSizer["innerSlaveInfo"].AddMany([self.SIUpdateButton,
+                                                               self.SITreeListCtrl])
+        self.MasterStateSizer["slaveInfo"].AddSizer(
+                self.MasterStateSizer["innerSlaveInfo"]) 
+
         # --------------------------------- Main Sizer ----------------------------------------------------
+        self.MasterStateSizer["main"].Add(self.MSUpdateButton)
         for key, sub, in [
-            ('innerTopHalf', [
-                    'masterState', 'deviceInfo']),
-            ('innerBottomHalf', [
-                    'frameInfo']),
-            ('innerMain', [
-                    'innerTopHalf', 'innerBottomHalf'])]:
+            ("innerTop", [
+                    "masterState", "deviceInfo"]),
+            ("innerMiddle", [
+                    "frameInfo"]),
+            ("innerBottom", [
+                    "slaveInfo"]),
+            ("main", [
+                    "innerTop", "innerMiddle", "innerBottom"])]:
             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.
+        self.SetSizer(self.MasterStateSizer["main"])
+    
+    def OnMSUpdateButtonClick(self, event):
+        """
+        Handle the event of the "Update" button.
         Update the data of the master state.
         @param event: wx.EVT_BUTTON object
         """
@@ -2203,5 +2769,821 @@
                             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!')
+
+    def OnSIUpdateButtonClick(self, event):
+        """
+        Handle the event of the radio box in the slave information 
+        @param event: wx.EVT_RADIOBOX object
+        """
+        if self.Controler.GetCTRoot()._connector is not None:
+            self.SITreeListCtrl.UpdateSI()
+        
+        else :
+            self.Controler.CommonMethod.CreateErrorDialog('PLC not connected!')
+    
+
+#-------------------------------------------------------------------------------
+#                    For Slave Information  Panel
+#------------------------------------------------------------------------------- 
+class SITreeListCtrl(wx.Panel):
+    
+    EC_Addrs = ["0x0300", "0x0302", "0x0304", "0x0306", "0x0301", "0x0303", "0x0305", 
+                "0x0307", "0x0308", "0x0309", "0x030A", "0x030B", "0x030C", "0x030D",
+                "0x0310", "0x0311", "0x0312", "0x0313", "0x0442", "0x0443"]
+
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the MasterStatePanel class
+        @param Controler: _EthercatCTN class in EthercatMaster.py
+        """
+
+        wx.Panel.__init__(self, parent, -1, size=wx.Size(750, 350))
+
+        self.Controler=controler
+        
+        self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=wx.Size(750,350), 
+                                                            style=wx.TR_HAS_BUTTONS
+                                                            |wx.TR_HIDE_ROOT
+                                                            |wx.TR_ROW_LINES
+                                                            |wx.TR_COLUMN_LINES
+                                                            |wx.TR_FULL_ROW_HIGHLIGHT)
+        for label, width in [
+                ("name",        400),
+                ("position",    100),
+                ("state",       100),
+                ("error",       100)]:
+            self.Tree.AddColumn(label, width=width)
+        
+        self.Tree.SetMainColumn(0)
+        
+    def UpdateSI(self):
+        """
+        Update the data of the slave information.
+        """
+        position, not_used, state, not_used, name = range(5)
+        
+        slave_node = []
+        slave_info_list = []
+        error_counter= []
+        
+        # get slave informations (name, position, state)
+        slaves_infos = self.Controler.CommonMethod.GetSlaveStateFromSlave()
+        slave_info_lines = slaves_infos.splitlines()
+        
+        for line in slave_info_lines:
+            slave_info_list.append(line.split(None,4))
+
+        slave_num = len(slave_info_lines)
+        
+        reg_info = []
+        for ec in self.EC_Addrs:
+            reg_info.append(ec + ",0x001")
+        
+        # get error counts of slaves
+        err_count_list = self.Controler.CommonMethod.MultiRegRead(slave_num, reg_info)
+                
+        self.Tree.DeleteAllItems()
+        
+        root = self.Tree.AddRoot("") 
+        ec_list_idx = 0
+
+        for slave_idx in range(slave_num):
+            slave_node = self.Tree.AppendItem(root, "")
+            
+            # set name, postion, state 
+            col_num = 0 
+            for info_idx in [name, position, state]:
+                self.Tree.SetItemText(slave_node, 
+                                      slave_info_list[slave_idx][info_idx], col_num)
+                col_num += 1
+
+            error_counter = {}
+            ec_idx = 0
+            
+            # set error counter's name and default value 
+            for ec, sub_ecs in [("Port Error Counters 0/1/2/3",[
+                                    "Invaild Frame Counter 0/1/2/3",
+                                    "RX Error Counter 0/1/2/3"]),
+                                ("Forward RX Error Counter 0/1/2/3", []),       
+                                ("ECAT Processing Unit Error Counter", []),
+                                ("PDI Error Counter", []),
+                                ("Lost Link Counter 0/1/2/3", []),
+                                ("Watchdog Counter Process Data", []),
+                                ("Watchdog Counter PDI", [])]:
+                ec_sub_idx = 0
+                ec_name = ec
+                tree_node = self.Tree.AppendItem(slave_node, "%s" % ec)
+                
+                if ec_name.find("0/1/2/3") > 0:
+                    num_ports = 4
+                    err_count = [0, 0, 0, 0]
+                else:
+                    num_ports = 1
+                    err_count = [0]
+
+                error_counter[(ec_idx, ec_sub_idx)] = {
+                        "name": ec_name,
+                        "tree_node": tree_node,
+                        "num_ports": num_ports,
+                        "err_count": err_count}
+
+                for sub_ec in sub_ecs:
+                    ec_sub_idx += 1
+                    ec_name = sub_ec
+                    tree_node = self.Tree.AppendItem(\
+                        error_counter[(ec_idx, 0)]["tree_node"], 
+                            "%s" % sub_ec)
+                    
+                    if ec_name.find("0/1/2/3") > 0:
+                        num_ports = 4
+                        err_count = [0, 0, 0, 0]
+                    else:
+                        num_ports = 1
+                        err_count = [0]
+
+                    error_counter[(ec_idx, ec_sub_idx)] = {
+                            "name": ec_name,
+                            "tree_node": tree_node, 
+                            "num_ports": num_ports,
+                            "err_count": err_count}
+
+                    for port_num in range(num_ports):
+                        try:
+                            error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] += \
+                                    int(err_count_list[ec_list_idx].split(",")[2], 16)
+                        except:
+                            error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] = -1
+
+                        ec_list_idx += 1
+                
+                if ec_sub_idx > 0:
+                    for port_num in range(num_ports):
+                        err_sum = 0
+                        for sub_idx in range(1, ec_sub_idx+1):
+                            err_sum += error_counter[(ec_idx, sub_idx)]\
+                                                ["err_count"][port_num]
+                        error_counter[(ec_idx, 0)]["err_count"][port_num] = err_sum
+                        
+                else:
+                    for port_num in range(num_ports):
+                        try:
+                            error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] += \
+                                    int(err_count_list[ec_list_idx].split(",")[2], 16)
+                        except:
+                            error_counter[(ec_idx, ec_sub_idx)]["err_count"][port_num] = -1
+                        ec_list_idx += 1
+
+                ec_idx += 1
+            
+            # set texts in "error" column. 
+            ec_info_list = error_counter.items()
+            ec_info_list.sort()
+            
+            err_checker = "none"
+           
+            for (idx, sub_idx), ec_info in ec_info_list:
+                ec_text = ""
+                for port_num in range(ec_info["num_ports"]):
+                    if ec_info["err_count"][port_num] != 0:
+                        err_checker = "occurred"
+
+                    if ec_info["err_count"][port_num] < 0:
+                        ec_text = "reg I/O error"
+                    else:
+                        ec_text = ec_text + "%d/" % ec_info["err_count"][port_num]
+
+                ec_text = ec_text.strip("/")
+                
+                self.Tree.SetItemText(ec_info["tree_node"], ec_text, col_num)
+            
+            self.Tree.SetItemText(slave_node, err_checker, col_num)
+
+class DCConfigPanel(wx.Panel):
+    def __init__(self, parent, controler):
+        """
+        Constructor
+        @param parent: Reference to the MasterStatePanel class
+        @param Controler: _EthercatCTN class in EthercatMaster.py
+        """
+
+        wx.Panel.__init__(self, parent, -1, size=wx.Size(750, 350))
+
+        self.Controler = controler
+        self.parent = parent
+
+        self.ESI_DC_Data = self.Controler.CommonMethod.LoadESIData()
+
+        # initialize SlaveStatePanel UI dictionaries
+        self.StaticBoxDic = {}
+        self.StaticTextDic = {}
+        self.TextCtrlDic = {}
+        self.ComboBoxDic = {}
+        self.CheckBoxDic = {}
+        self.RadioButtonDic = {}
+        OperationModeComboList = []
+        Sync1CycleComboList = []
+        
+        for ESI_Data in self.ESI_DC_Data:
+            OperationModeComboList.append(ESI_Data["desc"])
+
+        UnitComboList = [ "/100", "/ 50", "/ 40", "/ 30", "/ 25", "/ 20", "/16",
+            "/ 10", "/ 8", "/ 5", "/ 4", "/ 3", "/ 2", "x 1", "x 2", "x 3", "x 4", 
+            "x 5", "x 8", "x 10", "x 16", "x 20", "x 25", "x 30", "x 40", "x 50", 
+            "x 100"
+        ]
+
+        UnitComboListPlus = [ "/100", "/ 50", "/ 40", "/ 30", "/ 25", "/ 20", "/16",
+            "/ 10", "/ 8", "/ 5", "/ 4", "/ 3", "/ 2", "x 0", "x 1", "x 2", "x 3", 
+            "x 4", "x 5", "x 8", "x 10", "x 16", "x 20", "x 25", "x 30", "x 40", 
+            "x 50", "x 100"
+        ]
+
+        for i in range(1024):
+            Sync1CycleComboList.append("x " + str(i + 1))
+        
+        # iniitalize BoxSizer and FlexGridSizer
+        self.SizerDic = {
+            "DCConfig_main_sizer" : wx.BoxSizer(wx.VERTICAL),
+            "DCConfig_inner_main_sizer" : wx.FlexGridSizer(cols=1, hgap=50, rows=2, vgap=10),
+            "CyclicMode_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5),
+            "SyncMode_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5),
+            "OperationMode_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=100, rows=2, vgap=10),
+            "CheckEnable_InnerSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10),
+            "Sync0_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=15, rows=3, vgap=10),
+            "Sync0_CycleTimeSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=2, vgap=5),
+            "Sync0_ShiftTimeSizer" : wx.FlexGridSizer(cols=2, hgap=20, rows=2, vgap=5),
+            "Sync1_InnerSizer" : wx.FlexGridSizer(cols=1, hgap=15, rows=3, vgap=10),
+            "Sync1_CycleTimeSizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=2, vgap=5),
+            "Sync1_ShiftTimeSizer" : wx.FlexGridSizer(cols=2, hgap=20, rows=2, vgap=5)
+        }
+        
+        # initialize StaticBox and StaticBoxSizer
+        for box_name, box_label in [
+                ("CyclicModeBox", "Cyclic Mode"),
+                ("Sync0Box", "Sync0"),
+                ("Sync0CycleTimeBox", "Cycle Time (us):"),
+                ("Sync0ShiftTimeBox", "Shift Time (us):"),
+                ("Sync1Box", "Sync1"),
+                ("Sync1CycleTimeBox", "Cycle Time (us):"),
+                ("Sync1ShiftTimeBox", "Shift Time (us):")
+            ]:
+            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 in [
+                ("MainLabel", "Distributed Clock"),
+                ("OperationModeLabel", "Operation Mode:"),
+                ("SyncUnitCycleLabel", "Sync Unit Cycle (us)"),
+                ("Sync0ShiftTimeUserDefinedLabel", "User Defined"),
+                ("Sync1ShiftTimeUserDefinedLabel", "User Defined"),
+                ("BlankObject", ""),
+                ("BlankObject1", "")
+            ]:
+            self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
+
+        for textctl_name in [
+                ("SyncUnitCycle_Ctl"),
+                ("Sync0CycleTimeUserDefined_Ctl"),
+                ("Sync0ShiftTimeUserDefined_Ctl"),
+                ("Sync1CycleTimeUserDefined_Ctl"),
+                ("Sync1ShiftTimeUserDefined_Ctl"),
+            ]:
+            self.TextCtrlDic[textctl_name] = wx.TextCtrl(
+                self, size=wx.Size(130, 24), style=wx.TE_READONLY)
+
+        for checkbox_name, checkbox_label in [
+                ("DCEnable", "Enable"),
+                ("Sync0Enable", "Enable Sync0"),
+                ("Sync1Enable", "Enable Sync1")
+            ]:
+            self.CheckBoxDic[checkbox_name] = wx.CheckBox(self, -1, checkbox_label)
+
+        for combobox_name, combobox_list, size in [
+                ("OperationModeChoice", OperationModeComboList, 250),
+                ("Sync0UnitCycleChoice", UnitComboList, 130),
+                ("Sync1UnitCycleChoice", UnitComboList, 130)
+            ]:
+            self.ComboBoxDic[combobox_name] = wx.ComboBox(self, size=wx.Size(size, 24), 
+                choices = combobox_list, style = wx.CB_DROPDOWN | wx.CB_READONLY)
+
+        for radiobutton_name, radiobutton_label in [
+                ("Sync0CycleTimeUnitRadioButton", "Sync Unit Cycle"),
+                ("Sync0CycleTimeUserDefinedRadioButton", "User Defined"),
+                ("Sync1CycleTimeUnitRadioButton", "Sync Unit Cycle"),
+                ("Sync1CycleTimeUserDefinedRadioButton", "User Defined")
+            ]:
+            self.RadioButtonDic[radiobutton_name] = wx.RadioButton(
+                self, label = radiobutton_label, style = wx.RB_SINGLE)
+
+
+        self.ApplyButton = wx.Button(self, label="Apply")
+
+        # binding event
+        self.Bind(wx.EVT_CHECKBOX, self.CheckDCEnable, self.CheckBoxDic["DCEnable"])
+        #self.Bind(wx.EVT_COMBOBOX, self.SelectOperationMode, self.ComboBoxDic["OperationModeChoice"])
+        #self.Bind(wx.EVT_COMBOBOX, self.SelectUnitCycle, self.ComboBoxDic["Sync0UnitChoice"])
+        self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync0CycleTime, 
+            self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"])
+        self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync0CycleTime, 
+            self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"])
+        self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync1CycleTime, 
+            self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"])
+        self.Bind(wx.EVT_RADIOBUTTON, self.SelectSync1CycleTime, 
+            self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"])
+        self.Bind(wx.EVT_CHECKBOX, self.CheckSync0Enable, self.CheckBoxDic["Sync0Enable"])
+        self.Bind(wx.EVT_CHECKBOX, self.CheckSync1Enable, self.CheckBoxDic["Sync1Enable"])
+        self.Bind(wx.EVT_BUTTON, self.OnClickApplyButton, self.ApplyButton)
+
+        # sync1 shifttime box contents
+        self.SizerDic["Sync1_ShiftTimeSizer"].AddMany([
+            self.StaticTextDic["Sync1ShiftTimeUserDefinedLabel"],
+            self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"]
+        ])
+
+        # sync1 shifttime box
+        self.SizerDic["Sync1ShiftTimeBox"].Add(self.SizerDic["Sync1_ShiftTimeSizer"])
+        
+        # sync1 cycletime box contents
+        self.SizerDic["Sync1_CycleTimeSizer"].AddMany([
+            self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"], 
+            self.ComboBoxDic["Sync1UnitCycleChoice"],
+            self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"],
+            self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"]
+        ])
+
+        # sync0 cycletime box
+        self.SizerDic["Sync1CycleTimeBox"].Add(self.SizerDic["Sync1_CycleTimeSizer"])
+
+        self.SizerDic["Sync1_InnerSizer"].AddMany([
+            self.CheckBoxDic["Sync1Enable"], self.SizerDic["Sync1CycleTimeBox"], 
+            self.SizerDic["Sync1ShiftTimeBox"]
+        ])
+
+        # sync1 box
+        self.SizerDic["Sync1Box"].Add(self.SizerDic["Sync1_InnerSizer"])
+
+        # sync0 shifttime box contents
+        self.SizerDic["Sync0_ShiftTimeSizer"].AddMany([
+            self.StaticTextDic["Sync0ShiftTimeUserDefinedLabel"],
+            self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"]
+        ])
+
+        # sync0 shifttime box
+        self.SizerDic["Sync0ShiftTimeBox"].Add(self.SizerDic["Sync0_ShiftTimeSizer"])
+        
+        # sync0 cycletime box contents
+        self.SizerDic["Sync0_CycleTimeSizer"].AddMany([
+            self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"], 
+            self.ComboBoxDic["Sync0UnitCycleChoice"],
+            self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"],
+            self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"]
+        ])
+
+        # sync0 cycletime box
+        self.SizerDic["Sync0CycleTimeBox"].Add(self.SizerDic["Sync0_CycleTimeSizer"])
+
+        self.SizerDic["Sync0_InnerSizer"].AddMany([
+            self.CheckBoxDic["Sync0Enable"], self.SizerDic["Sync0CycleTimeBox"], 
+            self.SizerDic["Sync0ShiftTimeBox"]
+        ])
+
+        # sync0 box
+        self.SizerDic["Sync0Box"].Add(self.SizerDic["Sync0_InnerSizer"])
+
+        # sync0, sync1 box
+        self.SizerDic["SyncMode_InnerSizer"].AddMany([
+            self.SizerDic["Sync0Box"], self.SizerDic["Sync1Box"]
+        ])
+
+        # CyclicMode Box
+        self.SizerDic["CheckEnable_InnerSizer"].AddMany([
+            self.StaticTextDic["SyncUnitCycleLabel"], 
+            self.TextCtrlDic["SyncUnitCycle_Ctl"]
+        ])
+
+        self.SizerDic["OperationMode_InnerSizer"].AddMany([
+            self.StaticTextDic["OperationModeLabel"], 
+            self.ComboBoxDic["OperationModeChoice"],
+            self.CheckBoxDic["DCEnable"], self.SizerDic["CheckEnable_InnerSizer"]
+        ])
+
+        self.SizerDic["CyclicMode_InnerSizer"].AddMany([
+            self.SizerDic["OperationMode_InnerSizer"], 
+            self.SizerDic["SyncMode_InnerSizer"]
+        ])
+
+        self.SizerDic["CyclicModeBox"].Add(self.SizerDic["CyclicMode_InnerSizer"])
+
+        # Main Sizer
+        self.SizerDic["DCConfig_inner_main_sizer"].AddMany([
+            self.StaticTextDic["MainLabel"], self.ApplyButton,
+            self.SizerDic["CyclicModeBox"]
+        ])
+        
+        self.SizerDic["DCConfig_main_sizer"].Add(self.SizerDic["DCConfig_inner_main_sizer"])
+        
+        self.SetSizer(self.SizerDic["DCConfig_main_sizer"])
+        
+        self.Centre()
+
+        self.UIOnOffSet(False)
+        self.LoadProjectDCData()
+
+    def UIOnOffSet(self, activate):
+        if activate :
+            for object in self.RadioButtonDic:
+                self.RadioButtonDic[object].Enable()
+
+            for object in self.ComboBoxDic:
+                if object == "OperationModeChoice":
+                    continue
+                self.ComboBoxDic[object].Enable()
+
+            for object in self.TextCtrlDic:
+                if object in ["SyncUnitCycle_Ctl", "InputReference_Ctl"]:
+                    continue
+                self.TextCtrlDic[object].Enable()
+
+            for object in self.CheckBoxDic:
+                if object == "DCEnable":
+                    continue
+                self.CheckBoxDic[object].Enable()
+
+        # initial set or DC enable uncheck
+        else :
+            for object in self.RadioButtonDic:
+                self.RadioButtonDic[object].Disable()
+
+            for object in self.ComboBoxDic:
+                if object == "OperationModeChoice":
+                    continue
+                self.ComboBoxDic[object].Disable()
+
+            for object in self.TextCtrlDic:
+                if object == "SyncUnitCycle_Ctl":
+                    continue
+                self.TextCtrlDic[object].Disable()
+
+            for object in self.CheckBoxDic:
+                if object == "DCEnable":
+                    continue
+                self.CheckBoxDic[object].Disable()
+
+            for data in self.ESI_DC_Data:
+                index = self.Controler.ExtractHexDecValue(data["assign_activate"])
+                if index == 0:
+                    config_name = data["desc"]
+                    self.ComboBoxDic["OperationModeChoice"].SetStringSelection(config_name)
+
+    def CheckSync0Enable(self, evt):
+        if evt.GetInt():
+            self.ComboBoxDic["Sync0UnitCycleChoice"].Enable()
+            self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].Enable()
+            self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].Enable()
+            self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Enable()
+            self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].Enable()
+        else :
+            self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
+            self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].Disable()
+            self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].Disable()
+            self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
+            self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].Disable()
+            self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
+            self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
+            self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue("")
+            self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue("")
+
+    def CheckSync1Enable(self, evt):
+        if evt.GetInt():
+            self.ComboBoxDic["Sync1UnitCycleChoice"].Enable()
+            self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Enable()
+            self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Enable()
+            self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Enable()
+            self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Enable()
+        else :
+            self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
+            self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable()
+            self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable()
+            self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
+            self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable()
+            self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
+            self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
+            self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue("")
+            self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue("")
+
+    def CheckDCEnable(self, evt):
+        ns_mode = 1
+        task_cycle_ns = self.GetInterval(ns_mode)
+        sync0_cycle_factor = None
+        sync1_cycle_factor = None
+
+        #task_cycle_ns = self.Controler.GetCTRoot()._Ticktime
+        if (task_cycle_ns > 0):
+            self.UIOnOffSet(evt.GetInt())
+
+            if evt.GetInt():
+                # default select DC enable sync0
+                default_list_num = 0
+                config_name = self.ESI_DC_Data[default_list_num]["desc"]
+                assign_act = self.ESI_DC_Data[default_list_num]["assign_activate"]
+                sync0_cycle_time_ns = self.ESI_DC_Data[default_list_num]["cycletime_sync0"]
+                if sync0_cycle_time_ns == 0 :
+                    sync0_cycle_factor = self.ESI_DC_Data[default_list_num]["cycletime_sync0_factor"]
+                sync0_shift_time_ns = self.ESI_DC_Data[default_list_num]["shifttime_sync0"]
+                sync1_cycle_time_ns = self.ESI_DC_Data[default_list_num]["cycletime_sync1"]
+                if sync1_cycle_time_ns == 0 :
+                    sync1_cycle_factor = self.ESI_DC_Data[default_list_num]["cycletime_sync1_factor"]
+                sync1_shift_time_ns = self.ESI_DC_Data[default_list_num]["shifttime_sync1"]
+
+                cal_assign_act = self.Controler.ExtractHexDecValue(assign_act)
+                sync0_cycle_time_us = str(int(sync0_cycle_time_ns) / 1000)
+                sync0_shift_time_us = str(int(sync0_shift_time_ns) / 1000)
+                sync1_cycle_time_us = str(int(sync1_cycle_time_ns) / 1000)
+                sync1_shift_time_us = str(int(sync1_shift_time_ns) / 1000)
+
+                task_cycle_to_us = str(int(task_cycle_ns) / 1000)
+
+                # DC sync0 mode
+                if cal_assign_act == 768:
+                    # Disable About Sync1 Objects
+                    self.CheckBoxDic["Sync1Enable"].SetValue(False)
+                    self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable()
+                    self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
+                    self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable()
+                    self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
+                    self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable()
+
+                else :
+                    self.CheckBoxDic["Sync1Enable"].SetValue(True)
+                    if sync1_cycle_factor is not None:
+                        self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(True)
+                        self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
+                        self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
+                        self.SetSyncUnitCycle(sync1_cycle_factor, 
+                            self.ComboBoxDic["Sync1UnitCycleChoice"])
+                    else :
+                        self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
+                        self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(True)
+                        self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
+                        self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue(sync1_cycle_time_us)
+
+                    self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue(sync1_shift_time_us)
+
+                # Set Sync0 Objects
+                self.CheckBoxDic["Sync0Enable"].SetValue(True)
+                if sync0_cycle_factor is not None:
+                    self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(True)
+                    self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
+                    self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
+                    self.SetSyncUnitCycle(sync0_cycle_factor, 
+                        self.ComboBoxDic["Sync0UnitCycleChoice"])
+                else :
+                    self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
+                    self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(True)
+                    self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
+                    self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue(sync0_cycle_time_us)
+
+                self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue(sync0_shift_time_us)
+
+                self.ComboBoxDic["OperationModeChoice"].SetStringSelection(config_name)
+                self.TextCtrlDic["SyncUnitCycle_Ctl"].SetValue(task_cycle_to_us)
+            else :
+                self.CheckBoxDic["Sync0Enable"].SetValue(False)
+                self.CheckBoxDic["Sync1Enable"].SetValue(False)
+                self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
+                self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
+                self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
+                self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
+                self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue("")
+                self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue("")
+                self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue("")
+                self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue("")
+
+        else :
+            self.UIOnOffSet(False)
+            #error_str = "DC Enable is not possble, please set task interval"
+            error_str = "Can't Set DC Enable"
+            self.Controler.CommonMethod.CreateErrorDialog(error_str)
+
+    def SetSyncUnitCycle(self, factor, object):
+        # factor > 0 ==> * factor, factor < 0 ==> / factor
+        factor_to_int = int(factor)
+        if factor_to_int > 0:
+            lists = object.GetStrings()
+
+            for token in lists:
+                temp = token.split(" ")
+                if (temp[0] == "x") and (int(temp[1]) == factor_to_int):
+                    object.SetStringSelection(token)
+                    return True
+
+        else : 
+            lists = object.GetStrings()
+
+            for token in lists:
+                temp = token.split(" ")
+                if (temp[0] == "/") and (int(temp[1]) == factor_to_int):
+                    object.SetStringSelection(token)
+                    return True
+
+        return False
+
+    def GetInterval(self, mode):
+        project_infos = self.Controler.GetCTRoot().GetProjectInfos()
+        for project_info_list in project_infos["values"]:
+            if project_info_list["name"] == "Resources" :
+                token = project_info_list["values"][0]["tagname"]
+       
+        tasks, instances = self.Controler.GetCTRoot().GetEditedResourceInfos(token)
+        try:
+            task_cycle_ns = self.ParseTime(tasks[0]["Interval"])
+        except :
+            task_cycle_ns = 0
+        task_cycle_us = int(task_cycle_ns) / 1000
+
+        # mode == 1 ==> return ns
+        # mode == 2 ==> return us
+
+        if mode == 1:
+            return task_cycle_ns
+        if mode == 2:
+            return str(task_cycle_us)
+
+    def ParseTime(self, input):
+        # input example : 't#1ms'
+        # temp.split('#') -> ['t', '1ms']
+        temp = input.split('#')
+         
+        # temp[1] : '1ms'
+        # temp[-2:] : 'ms'
+        # temp[:-2] : '1'
+        if temp[1][-2:] == "ms":
+           # convert nanosecond unit
+           result = int(temp[1][:-2]) * 1000000
+        elif temp[1][-2:] == "us":
+           result = int(temp[1][:-2]) * 1000
+
+        return str(result)
+
+    def SelectSync0CycleTime(self, evt):
+        selected_object = evt.GetEventObject()
+
+        if selected_object.GetLabel() == "User Defined" :
+            self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(False)
+            self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Enable()
+            self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
+        elif selected_object.GetLabel() == "Sync Unit Cycle" :
+            self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(False)
+            self.ComboBoxDic["Sync0UnitCycleChoice"].Enable()
+            self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
+
+    def SelectSync1CycleTime(self, evt):
+        selected_object = evt.GetEventObject()
+
+        if selected_object.GetLabel() == "User Defined" :
+            self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(False)
+            self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Enable()
+            self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
+        elif selected_object.GetLabel() == "Sync Unit Cycle" :
+            self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(False)
+            self.ComboBoxDic["Sync1UnitCycleChoice"].Enable()
+            self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
+
+    def GetCycle(self, period, section):
+        temp = section.split(" ")
+
+        if temp[0] == "x":
+            result = int(period) * int(temp[1])
+        elif temp[0] == "/" :
+            result = int(period) / int(temp[1])
+        else :
+            result = ""
+
+        return result
+
+    def OnClickApplyButton(self, evt):
+        us_mode = 2
+        dc_enable = self.CheckBoxDic["DCEnable"].GetValue()
+        dc_desc = self.ComboBoxDic["OperationModeChoice"].GetStringSelection()
+        dc_assign_activate = self.ESI_DC_Data[0]["assign_activate"]
+        dc_assign_activate_mod = dc_assign_activate.split('x')[1]
+
+        if self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].GetValue():
+            temp = self.ComboBoxDic["Sync0UnitCycleChoice"].GetStringSelection()
+            dc_sync0_cycle = "1_" + str(self.GetCycle(self.GetInterval(us_mode), temp))
+        elif  self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].GetValue():
+            dc_sync0_cycle = "2_" + self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].GetValue()
+        else :
+            dc_sync0_cycle = ""
+
+        if self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].GetValue():
+            temp = self.ComboBoxDic["Sync1UnitCycleChoice"].GetStringSelection()
+            dc_sync1_cycle = "1_" + self.GetCycle(self.GetInterval(us_mode), temp)
+        elif  self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].GetValue():
+            dc_sync1_cycle = "2_" + self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].GetValue()
+        else :
+            dc_sync1_cycle = ""
+
+        dc_sync0_shift = self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].GetValue()
+        dc_sync1_shift = self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].GetValue()
+
+        self.Controler.BaseParams.setDC_Enable(dc_enable)
+        self.Controler.BaseParams.setDC_Desc(dc_desc)
+        self.Controler.BaseParams.setDC_Assign_Activate(dc_assign_activate_mod)
+        if dc_sync0_cycle:
+            self.Controler.BaseParams.setDC_Sync0_Cycle_Time(dc_sync0_cycle)
+        if dc_sync0_shift:
+            self.Controler.BaseParams.setDC_Sync0_Shift_Time(dc_sync0_shift)
+        if dc_sync1_cycle:
+            self.Controler.BaseParams.setDC_Sync1_Cycle_Time(dc_sync1_cycle)
+        if dc_sync1_shift:
+            self.Controler.BaseParams.setDC_Sync1_Shift_Time(dc_sync1_shift)
+        project_infos = self.Controler.GetCTRoot().CTNRequestSave()
+
+    def GetSymbol(self, period, cycle):
+        cmp1 = int(period)
+        cmp2 = int(cycle)
+
+        if cmp1 == cmp2 :
+            return "x 1"
+        elif cmp2 > cmp1 :
+            temp = cmp2 / cmp1
+            result = "x " + str(temp)
+        else :
+            temp = cmp1 / cmp2
+            result = "/ " + str(temp)
+
+        return result
+
+    def SetSyncCycle(self, period, sync0_cycle, sync1_cycle):
+        if sync0_cycle != "None":
+            self.CheckBoxDic["Sync0Enable"].SetValue(True)               
+            temp = sync0_cycle.split("_")
+            if temp[0] == "1":
+                symbol = self.GetSymbol(period, temp[1])
+                self.ComboBoxDic["Sync0UnitCycleChoice"].SetStringSelection(symbol)
+                self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].Disable()
+                self.RadioButtonDic["Sync0CycleTimeUnitRadioButton"].SetValue(True)
+            else :
+                self.TextCtrlDic["Sync0CycleTimeUserDefined_Ctl"].SetValue(temp[1])
+                self.ComboBoxDic["Sync0UnitCycleChoice"].Disable()
+                self.RadioButtonDic["Sync0CycleTimeUserDefinedRadioButton"].SetValue(True)
+
+        if sync1_cycle != "None":
+            self.CheckBoxDic["Sync1Enable"].SetValue(True)
+            temp = sync1_cycle.split("_")
+            if temp[0] == "1":
+                symbol = self.GetSymbol(period, temp[1])
+                self.ComboBoxDic["Sync1UnitChoice"].SetStringSelection(symbol)
+                self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
+                self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].SetValue(True)
+            else :
+                self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].SetValue(temp[1])
+                self.ComboBoxDic["Sync1UnitChoice"].Disable()
+                self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].SetValue(True)
+
+    def LoadProjectDCData(self):
+        ns_mode = 1
+        task_cycle_ns = self.GetInterval(ns_mode)
+        task_cycle_to_us = int(task_cycle_ns) / 1000
+        dc_enable = self.Controler.BaseParams.getDC_Enable()
+        dc_desc = self.Controler.BaseParams.getDC_Desc()
+        dc_assign_activate = self.Controler.BaseParams.getDC_Assign_Activate()
+        dc_sync0_cycle = self.Controler.BaseParams.getDC_Sync0_Cycle_Time()
+        dc_sync0_shift = self.Controler.BaseParams.getDC_Sync0_Shift_Time()
+        dc_sync1_cycle = self.Controler.BaseParams.getDC_Sync1_Cycle_Time()
+        dc_sync1_shift = self.Controler.BaseParams.getDC_Sync1_Shift_Time()
+
+        self.UIOnOffSet(dc_enable)
+
+        if dc_enable:
+            self.CheckBoxDic["DCEnable"].SetValue(dc_enable)
+            self.ComboBoxDic["OperationModeChoice"].SetStringSelection(dc_desc)
+            self.TextCtrlDic["SyncUnitCycle_Ctl"].SetValue(str(task_cycle_to_us))
+            self.SetSyncCycle(str(task_cycle_to_us), dc_sync0_cycle, dc_sync1_cycle)
+            if dc_sync0_shift != "None":
+                self.TextCtrlDic["Sync0ShiftTimeUserDefined_Ctl"].SetValue(dc_sync0_shift)
+            if dc_sync1_shift != "None":
+                self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].SetValue(dc_sync1_shift)
+
+            if dc_assign_activate == "300":
+                self.CheckBoxDic["Sync1Enable"].SetValue(False)
+                self.RadioButtonDic["Sync1CycleTimeUnitRadioButton"].Disable()
+                self.ComboBoxDic["Sync1UnitCycleChoice"].Disable()
+                self.RadioButtonDic["Sync1CycleTimeUserDefinedRadioButton"].Disable()
+                self.TextCtrlDic["Sync1CycleTimeUserDefined_Ctl"].Disable()
+                self.TextCtrlDic["Sync1ShiftTimeUserDefined_Ctl"].Disable()
+
+
+
+
+
+
+
+
+
+        
--- a/etherlab/EthercatCFileGenerator.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/EthercatCFileGenerator.py	Wed Nov 20 16:57:15 2019 +0100
@@ -68,6 +68,38 @@
     }
 """
 
+SLAVE_OUTPUT_PDO_DEFAULT_VALUE_BIT = """
+    {
+        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, %(subindex)d);
+    }
+"""
+
+
+SLAVE_INPUT_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 input 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);
+    }
+"""
+
+DC_VARIABLE ="""
+#define DC_ENABLE       %(dc_flag)d
+"""
+
+CONFIG_DC = """
+    ecrt_slave_config_dc (slave%(slave)d, 0x0%(assign_activate)ld, %(sync0_cycle_time)d, %(sync0_shift_time)d, %(sync1_cycle_time)d, %(sync1_shift_time)d);
+"""
+
+
 def ConfigureVariable(entry_infos, str_completion):
     entry_infos["data_type"] = DATATYPECONVERSION.get(entry_infos["var_type"], None)
     if entry_infos["data_type"] is None:
@@ -167,7 +199,6 @@
             raise ValueError, _("Definition conflict for location \"%s\"") % name 
         
     def GenerateCFile(self, filepath, location_str, master_number):
-        
         # Extract etherlab master code template
         plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c")
         plc_etherlab_file = open(plc_etherlab_filepath, 'r')
@@ -184,10 +215,15 @@
             "pdos_configuration_declaration": "",
             "slaves_declaration": "",
             "slaves_configuration": "",
+            # add jblee
+            "slaves_input_pdos_default_values_extraction": "",
             "slaves_output_pdos_default_values_extraction": "",
             "slaves_initialization": "",
             "retrieve_variables": [],
             "publish_variables": [],
+            #-----------This Code templete for dc -------------------#
+            "dc_variable" : "",
+            "config_dc": ""
         }
         
         # Initialize variable storing variable mapping state
@@ -199,6 +235,9 @@
         self.Slaves.sort()
         # Initialize dictionary storing alias auto-increment position values
         alias = {}
+
+        # add jblee
+        slotNumber = 1
         
         # Generating code for each slave
         for (slave_idx, slave_alias, slave) in self.Slaves:
@@ -221,6 +260,7 @@
             
             # Extract slave device object dictionary entries
             device_entries = device.GetEntriesList()
+            #device_entries = self.Controler.CTNParent.GetEntriesList()
             
             # Adding code for declaring slave in master code template strings
             for element in ["vendor", "product_code", "revision_number"]:
@@ -230,15 +270,17 @@
             # Extract slave device CoE informations
             device_coe = device.getCoE()
             if device_coe is not None:
-                
                 # If device support CanOpen over Ethernet, adding code for calling 
                 # init commands when initializing slave in master code template strings
                 initCmds = []
+                
                 for initCmd in device_coe.getInitCmd():
                     initCmds.append({
                         "Index": ExtractHexDecValue(initCmd.getIndex()),
                         "Subindex": ExtractHexDecValue(initCmd.getSubIndex()),
-                        "Value": initCmd.getData().getcontent()})
+                        #"Value": initCmd.getData().getcontent()})
+                        "Value": int(initCmd.getData().text, 16)})
+                
                 initCmds.extend(slave.getStartupCommands())
                 for initCmd in initCmds:
                     index = initCmd["Index"]
@@ -264,11 +306,11 @@
                 PdoAssign = PdoConfig = False
             
             # Test if slave has a configuration or need one
-            if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 and PdoConfig and PdoAssign:
-                
+            #if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 and PdoConfig and PdoAssign:
+            if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 or device.getSlots() is not None:
                 str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos
                 str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos
-                
+
                 # Initializing 
                 pdos_infos = {
                     "pdos_entries_infos": [],
@@ -304,28 +346,122 @@
                 pdos_index = []
                 exclusive_pdos = {}
                 selected_pdos = []
-                for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
-                                      [(pdo, "Outputs") for pdo in device.getRxPdo()]):
-                    
+
+                # add jblee
+                TxPdoData = []
+                RxPdoData = []
+                PdoData = []
+
+                # add jblee
+                if len(device.getTxPdo() + device.getRxPdo()) > 0:
+                    for pdo in device.getTxPdo():
+                        PdoData.append((pdo, "Inputs"))
+                    for pdo in device.getRxPdo():
+                        PdoData.append((pdo, "Outputs"))               
+
+                # mod jblee
+                #for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
+                #                      [(pdo, "Outputs") for pdo in device.getRxPdo()]):
+                #for pdo, pdo_type in (TxPdoData + RxPdoData):
+                data_files = os.listdir(self.Controler.CTNPath())
+                PDODataList = []
+                MDPData = []
+                RxPDOData = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getRxPDO()
+                TxPDOData = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getTxPDO()
+                PDOList = RxPDOData.split() + TxPDOData.split()
+                for PDOIndex in PDOList:
+                    if PDOIndex in ["RxPDO", "TxPDO", "None"]:
+                        continue
+                    PDODataList.append(int(PDOIndex, 0))
+
+                # add jblee for DC Configuration
+                dc_enable = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Enable()
+                sync0_cycle_time = 0
+                sync0_shift_time = 0
+                sync1_cycle_time = 0
+                sync1_shift_time = 0
+                if dc_enable :
+                    sync0_cycle_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync0_Cycle_Time()
+                    if sync0_cycle_token != "None":
+                        sync0_cycle_time = int(sync0_cycle_token.split("_")[1]) * 1000
+                    sync0_shift_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync0_Shift_Time()
+                    if sync0_shift_token != "None":
+                        sync0_shift_time = int(sync0_shift_token) * 1000
+                    sync1_cycle_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync1_Cycle_Time()
+                    if sync1_cycle_token != "None":
+                        sync1_cycle_time = int(sync1_cycle_token.split("_")[1]) * 1000
+                    sync1_shift_token = self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Sync1_Shift_Time()
+                    if sync1_shift_token != "None":
+                        sync1_shift_time = int(sync1_shift_token) * 1000
+                    
+                    dc_config_data = {
+                        "slave" : slave_idx,
+                        "assign_activate" : int(self.Controler.GetChildByIECLocation((slave_idx,)).BaseParams.getDC_Assign_Activate()),
+                        "sync0_cycle_time" : sync0_cycle_time,
+                        "sync0_shift_time" : sync0_shift_time,
+                        "sync1_cycle_time" : sync1_cycle_time,
+                        "sync1_shift_time" : sync1_shift_time,
+                    }
+
+                    if dc_enable and not str_completion["dc_variable"] :
+                        str_completion["dc_variable"] += DC_VARIABLE % {"dc_flag" : dc_enable}
+                    str_completion["config_dc"] += CONFIG_DC % dc_config_data
+
+                for data_file in data_files:
+                    slave_path = os.path.join(self.Controler.CTNPath(), data_file)
+                    if os.path.isdir(slave_path):
+                        CheckConfNodePath = os.path.join(slave_path, "baseconfnode.xml")
+                        confNodeFile = open(CheckConfNodePath, 'r')
+                        checklines = confNodeFile.readlines()
+                        confNodeFile.close()
+                        # checklines(ex) : <BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="EthercatSlave_0"/>
+                        # checklines[1].split() : [<BaseParams, xmlns:xsd="http://www.w3.org/2001/XMLSchema",
+                        #                           IEC_Channel="0", Name="EthercatSlave_0"/>]
+                        # checklines[1].split()[2] : IEC_Channel="0"
+                        # checklines[1].split()[2].split("\"") = [IEC_Channel=, 0, ]
+                        pos_check = int(checklines[1].split()[2].split("\"")[1])
+                        if slave_idx == pos_check:
+                            MDPDataFilePath = os.path.join(slave_path, "DataForMDP.txt")
+                            if os.path.isfile(MDPDataFilePath):
+                                MDPDataFile = open(MDPDataFilePath, 'r')
+                                MDPData = MDPDataFile.readlines()
+                                MDPDataFile.close()
+
+                        for MDPLine in MDPData:
+                            if MDPLine == "\n":
+                                continue
+                            module_pos = int(MDPLine.split()[-1])
+                            module = self.Controler.CTNParent.GetSelectModule(module_pos)
+                            for pdo in module.getTxPdo():
+                                PdoData.append((pdo, "Inputs"))
+                                PDODataList.append(ExtractHexDecValue(pdo.getIndex().getcontent()))
+                            for pdo in module.getRxPdo():
+                                PdoData.append((pdo, "Outputs"))
+                                PDODataList.append(ExtractHexDecValue(pdo.getIndex().getcontent()))
+
+                for pdo, pdo_type in PdoData:
                     pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
                     pdos_index.append(pdo_index)
-                    
+
+                    if PDODataList and (pdo_index in PDODataList):
+                        continue
+
                     excluded_list = pdo.getExclude()
                     if len(excluded_list) > 0:
                         exclusion_list = [pdo_index]
                         for excluded in excluded_list:
                             exclusion_list.append(ExtractHexDecValue(excluded.getcontent()))
-                        exclusion_list.sort()
-                        
-                        exclusion_scope = exclusive_pdos.setdefault(tuple(exclusion_list), [])
-                        
+                        exclusion_list.sort()                     
+                        exclusion_scope = exclusive_pdos.setdefault(tuple(exclusion_list), [])                   
                         entries = pdo.getEntry()
+
                         pdo_mapping_match = {
                             "index": pdo_index, 
                             "matching": 0, 
                             "count": len(entries), 
                             "assigned": pdo.getSm() is not None
                         }
+
                         exclusion_scope.append(pdo_mapping_match)
                         
                         for entry in entries:
@@ -352,30 +488,57 @@
                     excluded_pdos.extend([pdo["index"] 
                         for pdo in exclusion_scope[start_excluding_index:] 
                         if PdoAssign or not pdo["assigned"]])
-                
-                for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
-                                      [(pdo, "Outputs") for pdo in device.getRxPdo()]):
-                    entries = pdo.getEntry()
+
+                # mod jblee
+                #for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
+                #                      [(pdo, "Outputs") for pdo in device.getRxPdo()]):
+                #for pdo, pdo_type in (TxPdoData + RxPdoData):
+                entry_check_list = []
+                index_padding = 1
+                for pdo, pdo_type in PdoData:
+                    entries = pdo.getEntry()                   
                     
                     pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
                     if pdo_index in excluded_pdos:
                         continue
-                    
-                    pdo_needed = pdo_index in selected_pdos
-                    
-                    entries_infos = []
-                    
+                    if PDODataList and (pdo_index not in PDODataList):
+                        continue
+                    
+                    #pdo_needed = pdo_index in selected_pdos
+                    pdo_needed = pdo_index in PDODataList
+
+                    if len(MDPData) > 0:
+                        pdo_index += index_padding
+                        index_padding += 1
+
+                    entries_infos = []                   
                     for entry in entries:
                         index = ExtractHexDecValue(entry.getIndex().getcontent())
                         subindex = ExtractHexDecValue(entry.getSubIndex())
+
+                        # add jblee
+                        if len(MDPData) > 0:
+                            increse = self.Controler.CTNParent.GetMDPInfos(type_infos)                          
+                            if increse and index != 0:
+                                index += int(increse[0][2]) * slotNumber
+                                
                         entry_infos = {
                             "index": index,
                             "subindex": subindex,
                             "name": ExtractName(entry.getName()),
                             "bitlen": entry.getBitLen(),
                         }
+
                         entry_infos.update(type_infos)
+                        #temp_data = "    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos
+                        check_data = "{0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}" % entry_infos
+                        if entry_check_list and check_data in entry_check_list:
+                            if (entry_infos["index"] == 0) or (entry_infos["name"] == None):
+                                pass
+                            else: 
+                                continue
                         entries_infos.append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
+                        entry_check_list.append(check_data)
                         
                         entry_declaration = slave_variables.get((index, subindex), None)
                         if entry_declaration is not None and not entry_declaration["mapped"]:
@@ -399,7 +562,7 @@
                                 raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
                             
                             ConfigureVariable(entry_infos, str_completion)
-                        
+                            
                         elif pdo_type == "Outputs" and entry.getDataType() is not None and device_coe is not None:
                             data_type = entry.getDataType().getcontent()
                             entry_infos["dir"] = "Q"
@@ -409,16 +572,34 @@
                             entry_infos["real_var"] = "slave%(slave)d_%(index).4x_%(subindex).2x_default" % entry_infos
                             
                             ConfigureVariable(entry_infos, str_completion)
-                            
-                            str_completion["slaves_output_pdos_default_values_extraction"] += \
-                                SLAVE_OUTPUT_PDO_DEFAULT_VALUE % entry_infos
-                            
+
+                            if entry_infos["data_type"] == "BIT" :
+                                str_completion["slaves_output_pdos_default_values_extraction"] += \
+                                    SLAVE_OUTPUT_PDO_DEFAULT_VALUE_BIT % entry_infos
+                            else :
+                                str_completion["slaves_output_pdos_default_values_extraction"] += \
+                                    SLAVE_OUTPUT_PDO_DEFAULT_VALUE % entry_infos
+
+                        elif pdo_type == "Inputs" and entry.getDataType() is not None and device_coe is not None:
+                            data_type = entry.getDataType().getcontent()
+                            entry_infos["dir"] = "I"
+                            entry_infos["data_size"] = max(1, entry_infos["bitlen"] / 8)
+                            entry_infos["data_type"] = DATATYPECONVERSION.get(data_type)
+                            entry_infos["var_type"] = data_type
+                            entry_infos["real_var"] = "slave%(slave)d_%(index).4x_%(subindex).2x_default" % entry_infos
+                            
+                            ConfigureVariable(entry_infos, str_completion)
+                            
+                            str_completion["slaves_input_pdos_default_values_extraction"] += \
+                                SLAVE_INPUT_PDO_DEFAULT_VALUE % entry_infos
+                    
                     if pdo_needed:
                         for excluded in pdo.getExclude():
                             excluded_index = ExtractHexDecValue(excluded.getcontent())
                             if excluded_index not in excluded_pdos:
                                 excluded_pdos.append(excluded_index)
                         
+                        ############################################################
                         sm = pdo.getSm()
                         if sm is None:
                             for sm_idx, sync_manager in enumerate(sync_managers):
@@ -426,7 +607,7 @@
                                     sm = sm_idx
                         if sm is None:
                             raise ValueError, _("No sync manager available for %s pdo!") % pdo_type
-                            
+                        
                         sync_managers[sm]["pdos_number"] += 1
                         sync_managers[sm]["pdos"].append(
                             {"slave": slave_idx,
@@ -436,6 +617,10 @@
                              "entries": entries_infos,
                              "entries_number": len(entries_infos),
                              "fixed": pdo.getFixed() == True})
+                        #############################################################
+
+                    # for MDP
+                    slotNumber += 1
             
                 if PdoConfig and PdoAssign:
                     dynamic_pdos = {}
@@ -459,7 +644,7 @@
                             if entry is None:
                                 raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \
                                                  (index, subindex, type_infos["device_type"])
-                            
+
                             entry_infos = {
                                 "index": index,
                                 "subindex": subindex,
@@ -526,8 +711,8 @@
                 
                 pdo_offset = 0
                 entry_offset = 0
+                slotNumber = 1
                 for sync_manager_infos in sync_managers:
-                
                     for pdo_infos in sync_manager_infos["pdos"]:
                         pdo_infos["offset"] = entry_offset
                         pdo_entries = pdo_infos["entries"]
@@ -550,11 +735,11 @@
                 
                 str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos
             
-            for (index, subindex), entry_declaration in slave_variables.iteritems():
-                if not entry_declaration["mapped"]:
-                    message = _("Entry index 0x%4.4x, subindex 0x%2.2x not mapped for device %s") % \
-                                    (index, subindex, type_infos["device_type"])
-                    self.Controler.GetCTRoot().logger.write_warning(_("Warning: ") + message + "\n")
+            #for (index, subindex), entry_declaration in slave_variables.iteritems():
+            #    if not entry_declaration["mapped"]:
+            #        message = _("Entry index 0x%4.4x, subindex 0x%2.2x not mapped for device %s") % \
+            #                        (index, subindex, type_infos["device_type"])
+            #        self.Controler.GetCTRoot().logger.write_warning(_("Warning: ") + message + "\n")
                     
         for element in ["used_pdo_entry_offset_variables_declaration", 
                         "used_pdo_entry_configuration", 
--- a/etherlab/EthercatCIA402Slave.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/EthercatCIA402Slave.py	Wed Nov 20 16:57:15 2019 +0100
@@ -13,28 +13,35 @@
 
 import wx
 
-from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
+from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, \
+    LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
 
 from MotionLibrary import Headers, AxisXSD
 from EthercatSlave import _EthercatSlaveCTN, _CommonSlave
 from ConfigEditor import CIA402NodeEditor
 
-# Definition of node variables that have to be mapped in PDO
-# [(name, index, subindex, type, 
-#   direction for master ('I': input, 'Q': output)),...]
+#HSAHN 2015.07.26
+#remove NODE_VARIABLES's optional items.
+#As for now, optional items will be added dynamicaly.
 NODE_VARIABLES = [
-    ("ControlWord",             0x6040, 0x00, "UINT", "Q"),
-    ("TargetPosition",          0x607a, 0x00, "DINT", "Q"),
-    ("TargetVelocity",          0x60ff, 0x00, "DINT", "Q"),
-    ("TargetTorque",            0x6071, 0x00, "INT",  "Q"),
-    ("ModesOfOperation",        0x6060, 0x00, "SINT", "Q"),
-    ("StatusWord",              0x6041, 0x00, "UINT", "I"),
+    ("ControlWord", 0x6040, 0x00, "UINT", "Q"),
+    ("ModesOfOperation", 0x6060, 0x00, "SINT", "Q"),
+    ("StatusWord", 0x6041, 0x00, "UINT", "I"),
     ("ModesOfOperationDisplay", 0x6061, 0x00, "SINT", "I"),
-    ("ActualPosition",          0x6064, 0x00, "DINT", "I"),
-    ("ActualVelocity",          0x606c, 0x00, "DINT", "I"),
-    ("ActualTorque",            0x6077, 0x00, "INT",  "I"),
 ]
 
+#HSAHN 2015.07.26
+#reference variable
+ADD_NODE_VARIABLES = ({'name':"TargetPosition"   , 'index':0x607a, 'sub-index':0x00, 'type':"DINT", 'direction':"Q"},
+                      {'name':"TargetVelocity"   , 'index':0x60ff, 'sub-index':0x00, 'type':"DINT", 'direction':"Q"},
+                      {'name':"TargetTorque"     , 'index':0x6071, 'sub-index':0x00, 'type':"INT",  'direction':"Q"},
+                      {'name':"ActualPosition"   , 'index':0x6064, 'sub-index':0x00, 'type':"DINT", 'direction':"I"},
+                      {'name':"ActualVelocity"   , 'index':0x606c, 'sub-index':0x00, 'type':"DINT", 'direction':"I"},
+                      {'name':"ActualTorque"     , 'index':0x6077, 'sub-index':0x00, 'type':"INT",  'direction':"I"})
+
+DEFAULT_RETRIEVE = "    __CIA402Node_%(location)s.axis->%(name)s = *(__CIA402Node_%(location)s.%(name)s);"
+DEFAULT_PUBLISH = "    *(__CIA402Node_%(location)s.%(name)s) = __CIA402Node_%(location)s.axis->%(name)s;"
+
 # Definition of optional node variables that can be added to PDO mapping.
 # A checkbox will be displayed for each section in node configuration panel to
 # enable them
@@ -46,6 +53,7 @@
 #     'publish', string_template_for_publish_variable (None: not published, 
 #                                 default string template if not defined),
 #    },...]
+
 EXTRA_NODE_VARIABLES = [
     ("ErrorCode", [
         {"description": ("ErrorCode", 0x603F, 0x00, "UINT", "I"),
@@ -56,8 +64,8 @@
          "publish": None}
         ]),
     ("DigitalOutputs", [
-        {"description": ("DigitalOutputs", 0x60FE, 0x00, "UDINT", "Q"),
-         "retrieve": None}
+        {"description": ("DigitalOutputs", 0x60FE, 0x01, "UDINT", "I"),
+         "publish": None}
         ]),
     ("TouchProbe", [
         {"description": ("TouchProbeFunction", 0x60B8, 0x00, "UINT", "Q"),
@@ -77,7 +85,23 @@
     "Enable" + name: params 
     for name, params in EXTRA_NODE_VARIABLES}
 
-# List of block to define to interface MCL to fieldbus for specific functions
+BLOCK_INPUT_TEMPLATE = "    __SET_VAR(%(blockname)s->,%(input_name)s, %(input_value)s);"
+BLOCK_OUTPUT_TEMPLATE = "    __SET_VAR(data__->,%(output_name)s, __GET_VAR(%(blockname)s->%(output_name)s));"
+
+BLOCK_FUNCTION_TEMPLATE = """
+extern void ETHERLAB%(ucase_blocktype)s_body__(ETHERLAB%(ucase_blocktype)s* data__);
+void __%(blocktype)s_%(location)s(MC_%(ucase_blocktype)s *data__) {
+__DECLARE_GLOBAL_PROTOTYPE(ETHERLAB%(ucase_blocktype)s, %(blockname)s);
+ETHERLAB%(ucase_blocktype)s* %(blockname)s = __GET_GLOBAL_%(blockname)s();
+__SET_VAR(%(blockname)s->, POS, AxsPub.axis->NetworkPosition);
+%(extract_inputs)s
+ETHERLAB%(ucase_blocktype)s_body__(%(blockname)s);
+%(return_outputs)s
+}
+"""
+
+BLOCK_FUNTION_DEFINITION_TEMPLATE = "        __CIA402Node_%(location)s.axis->__mcl_func_MC_%(blocktype)s = __%(blocktype)s_%(location)s;"
+
 FIELDBUS_INTERFACE_GLOBAL_INSTANCES = [
     {"blocktype": "GetTorqueLimit", 
      "inputs": [],
@@ -89,6 +113,44 @@
      "outputs": []},
 ]
 
+# add jblee
+MODEOFOP_HOMING_METHOD_TEMPLATE = """
+	if(*(AxsPub.ModesOfOperation) == 0x06){
+		IEC_BOOL homing = AxsPub.axis->HomingOperationStart;
+		if(power){
+			if (homing)
+				CW |= Homing_OperationStart_Origin;
+			else
+				CW &= ~(Homing_OperationStart_Origin);
+		}
+		else{
+			if (homing)
+				CW |= Homing_OperationStart_Edit;
+			else
+				CW &= ~(EnableOperation);
+		}
+
+	}
+"""
+
+MODEOFOP_COMPUTATION_MODE_TEMPLATE = """
+	switch (AxsPub.axis->AxisMotionMode) {
+		//ssh_add
+		case mc_mode_hm:
+			*(AxsPub.ModesOfOperation) = 0x06;
+			break;
+		case mc_mode_cst:
+			*(AxsPub.ModesOfOperation) = 0x0a;
+			break;
+		case mc_mode_csv:
+			*(AxsPub.ModesOfOperation) = 0x09;
+			break;
+		default:
+			*(AxsPub.ModesOfOperation) = 0x08;
+			break;
+	}
+"""
+
 #--------------------------------------------------
 #                 Ethercat CIA402 Node
 #--------------------------------------------------
@@ -131,6 +193,13 @@
         # ----------- call ethercat mng. function --------------
         self.CommonMethod = _CommonSlave(self)
     
+        #HSAHN
+        # Select PDO Mapping
+        self.SelectedPDOIndex = []
+        self.SelectedRxPDOIndex = []
+        self.SelectedTxPDOIndex = []
+        #HSAHN END
+
     def GetIconName(self):
         return "CIA402Slave"
     
@@ -186,147 +255,274 @@
         self.StartDragNDrop(
             ("%%IW%s.402" % ".".join(map(str, self.GetCurrentLocation())), 
              "location", "AXIS_REF", self.CTNName(), ""))
+
+    # add jblee
+    """
+    def LoadPDOSelectData(self):
+        ReadData = []
+        files = os.listdir(self.CTNPath())
+        filepath = os.path.join(self.CTNPath(), "DataForPDO.txt")
+        if os.path.isfile(filepath):
+            PDODataRead = open(filepath, 'r')
+            ReadData = PDODataRead.readlines()
+            PDODataRead.close()
+
+        if len(ReadData) > 1:
+            for data in ReadData[0].split() :
+                if data == "RxPDO":
+                    continue
+                self.SelectedRxPDOIndex.append(int(data, 0))
+
+            for data in ReadData[1].split() :
+                if data == "TxPDO":
+                    continue
+                self.SelectedTxPDOIndex.append(int(data, 0))
+    """
+
+    def LoadPDOSelectData(self):
+        RxPDOData = self.BaseParams.getRxPDO()
+        RxPDOs = []
+        if RxPDOData != "None":
+            RxPDOs = RxPDOData.split()
+        if RxPDOs :
+            for RxPDO in RxPDOs :
+                self.SelectedRxPDOIndex.append(int(RxPDO, 0))
+
+        TxPDOData = self.BaseParams.getTxPDO()
+        TxPDOs = []
+        if TxPDOData != "None":
+            TxPDOs = TxPDOData.split()
+        if TxPDOs :
+            for TxPDO in TxPDOs :
+                self.SelectedTxPDOIndex.append(int(TxPDO, 0))
+
+    def LoadDefaultPDOSet(self):
+        ReturnData = []
+        rx_pdo_entries = self.CommonMethod.GetRxPDOCategory()
+        if len(rx_pdo_entries):
+            for i in range(len(rx_pdo_entries)):
+                if rx_pdo_entries[i]['sm'] is not None:
+                    ReturnData.append(rx_pdo_entries[i]['pdo_index'])
+
+        tx_pdo_entries = self.CommonMethod.GetTxPDOCategory()
+        if len(tx_pdo_entries):
+            for i in range(len(tx_pdo_entries)):
+                if tx_pdo_entries[i]['sm'] is not None:
+                    ReturnData.append(tx_pdo_entries[i]['pdo_index'])
+
+        if ReturnData :
+            return ReturnData
+        else :
+            return [5632, 6656]
         
     def CTNGenerate_C(self, buildpath, locations):
         current_location = self.GetCurrentLocation()
         
         location_str = "_".join(map(lambda x:str(x), current_location))
-        slave_pos = self.GetSlavePos()
-        MCL_headers = Headers
-        
-        # Open CIA402 node code template file 
-        plc_cia402node_filepath = os.path.join(os.path.split(__file__)[0], 
-                                               "plc_cia402node.c")
+        
+        plc_cia402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_cia402node.c")
         plc_cia402node_file = open(plc_cia402node_filepath, 'r')
         plc_cia402node_code = plc_cia402node_file.read()
         plc_cia402node_file.close()
-        
-        # Init list of generated strings for each code template file section
-        fieldbus_interface_declaration = []
-        fieldbus_interface_definition = []
-        init_axis_params = []
-        extra_variables_retrieve = []
-        extra_variables_publish = []
-        extern_located_variables_declaration = []
-        entry_variables = []
-        init_entry_variables = []
-        
-        # Fieldbus interface code sections
+        # HSAHN 150726
+        # add "default_variables_retrieve": [], "default_variables_publish": [],
+		# As PDO mapping object, it will add auto-complete code.
+        # add "modeofop_homing_method", "modeofop_computation_mode" by jblee
+        str_completion = {
+            "slave_pos": self.GetSlavePos(),
+            "location": location_str,
+            "MCL_headers": Headers,
+            "extern_located_variables_declaration": [],
+            "fieldbus_interface_declaration": [],
+            "fieldbus_interface_definition": [],
+            "entry_variables": [],
+            "init_axis_params": [],
+            "init_entry_variables": [],
+            "default_variables_retrieve": [],
+            "default_variables_publish": [],
+            "extra_variables_retrieve": [],
+            "extra_variables_publish": [],
+            "modeofop_homing_method": [],
+            "modeofop_computation_mode": []
+        }
+        
         for blocktype_infos in FIELDBUS_INTERFACE_GLOBAL_INSTANCES:
-            blocktype = blocktype_infos["blocktype"]
-            ucase_blocktype = blocktype.upper()
-            blockname = "_".join([ucase_blocktype, location_str])
+            texts = {
+                "blocktype": blocktype_infos["blocktype"],
+                "ucase_blocktype": blocktype_infos["blocktype"].upper(),
+                "location": "_".join(map(str, current_location))
+            }
+            texts["blockname"] = "%(ucase_blocktype)s_%(location)s" % texts
             
-            extract_inputs = "\n".join(["""\
-    __SET_VAR(%s->, %s,, %s);""" % (blockname, input_name, input_value)
-                for (input_name, input_value) in [
-                    ("EXECUTE", "__GET_VAR(data__->EXECUTE)")] + [
-                    (input["name"].upper(), 
-                     "__GET_VAR(data__->%s)" % input["name"].upper())
-                    for input in blocktype_infos["inputs"]]
-                ])
+            inputs = [{"input_name": "POS", "input_value": str(self.GetSlavePos())},
+                      {"input_name": "EXECUTE", "input_value": "__GET_VAR(data__->EXECUTE)"}] +\
+                     [{"input_name": input["name"].upper(), 
+                       "input_value": "__GET_VAR(data__->%s)" % input["name"].upper()}
+                      for input in blocktype_infos["inputs"]]
+            input_texts = []
+            for input_infos in inputs:
+                input_infos.update(texts)
+                input_texts.append(BLOCK_INPUT_TEMPLATE % input_infos)
+            texts["extract_inputs"] = "\n".join(input_texts)
             
+            outputs = [{"output_name": output} for output in ["DONE", "BUSY", "ERROR"]] + \
+                      [{"output_name": output["name"].upper()} for output in blocktype_infos["outputs"]]
+            output_texts = []
+            for output_infos in outputs:
+                output_infos.update(texts)
+                output_texts.append(BLOCK_OUTPUT_TEMPLATE % output_infos)
+            texts["return_outputs"] = "\n".join(output_texts)
             
-            return_outputs = "\n".join(["""\
-    __SET_VAR(data__->,%(output_name)s,, 
-              __GET_VAR(%(blockname)s->%(output_name)s));""" % locals()
-                    for output_name in ["DONE", "BUSY", "ERROR"] + [
-                        output["name"].upper()
-                        for output in blocktype_infos["outputs"]]
-                ])
+            str_completion["fieldbus_interface_declaration"].append(
+                    BLOCK_FUNCTION_TEMPLATE % texts)
+            
+            str_completion["fieldbus_interface_definition"].append(
+                    BLOCK_FUNTION_DEFINITION_TEMPLATE % texts)
+
+        variables = NODE_VARIABLES[:]
+
+#HSAHN
+#2015. 7. 24 PDO Variable
+        #if PDO is not selected, use 1st PDO set
+        self.LoadPDOSelectData()
+        if not self.SelectedRxPDOIndex and not self.SelectedTxPDOIndex :
+            self.SelectedPDOIndex = self.LoadDefaultPDOSet()
+        else :
+            self.SelectedPDOIndex = self.SelectedRxPDOIndex + self.SelectedTxPDOIndex
+
+        add_idx = []
+        for i in range(len(ADD_NODE_VARIABLES)):
+            add_idx.append(ADD_NODE_VARIABLES[i]['index'])
+
+        self.CommonMethod.RequestPDOInfo()
+        pdo_info = self.CommonMethod.GetRxPDOCategory() + self.CommonMethod.GetTxPDOCategory()
+        pdo_entry = self.CommonMethod.GetRxPDOInfo() + self.CommonMethod.GetTxPDOInfo()
+        list_index = 0
+        ModeOfOpFlag = False
+        ModeOfOpDisplayFlag = False
+        for i in range(len(pdo_info)):
+            #if pdo_index is in the SelectedPDOIndex: put the PDO mapping information intto the "used" object
+            if pdo_info[i]['pdo_index'] in self.SelectedPDOIndex:
+                used = pdo_entry[list_index:list_index + pdo_info[i]['number_of_entry']]
+                for used_data in used:
+                    # 24672 -> 0x6060, Mode of Operation
+                    if used_data['entry_index'] == 24672:
+                        ModeOfOpFlag = True
+                    # 24673 -> 0x6061, Mode of Operation Display
+                    elif used_data["entry_index"] == 24673:
+                        ModeOfOpDisplayFlag = True
+
+                    if used_data['entry_index'] in add_idx:
+                        idx = add_idx.index(used_data['entry_index'])
+                        adder = list([ADD_NODE_VARIABLES[idx]['name'], ADD_NODE_VARIABLES[idx]['index'], \
+                                     ADD_NODE_VARIABLES[idx]['sub-index'], ADD_NODE_VARIABLES[idx]['type'], \
+                                     ADD_NODE_VARIABLES[idx]['direction']])
+                        variables.append(adder)
+                        if ADD_NODE_VARIABLES[idx]['direction'] == "Q":                           
+                            parsed_string = ADD_NODE_VARIABLES[idx]['name'].replace("Target", "")
+                            # add jblee
+                            check_q_data = "    *(AxsPub.Target%s) = AxsPub.axis->Raw%sSetPoint;" %(parsed_string, parsed_string)
+                            if check_q_data not in str_completion["default_variables_publish"]:
+                                str_completion["default_variables_publish"].append(check_q_data)
+                        elif ADD_NODE_VARIABLES[idx]['direction'] == "I":
+                            parsed_string = ADD_NODE_VARIABLES[idx]['name'].replace("Actual", "")
+                            # add jblee
+                            check_i_data = "    AxsPub.axis->ActualRaw%s = *(AxsPub.Actual%s);" %(parsed_string, parsed_string)
+                            if check_i_data not in str_completion["default_variables_retrieve"]:
+                                str_completion["default_variables_retrieve"].append(check_i_data)
+            list_index += pdo_info[i]['number_of_entry']
+#HSAHN END
+
+        params = self.CTNParams[1].getElementInfos(self.CTNParams[0])
+        for param in params["children"]:
+            if param["name"] in EXTRA_NODE_VARIABLES_DICT:
+                if param["value"]:
+                    extra_variables = EXTRA_NODE_VARIABLES_DICT.get(param["name"])
+                    for variable_infos in extra_variables:
+                        var_infos = {
+                            "location": location_str,
+                            "name": variable_infos["description"][0]
+                        }
+                        variables.append(variable_infos["description"])
+                        retrieve_template = variable_infos.get("retrieve", DEFAULT_RETRIEVE)
+                        publish_template = variable_infos.get("publish", DEFAULT_PUBLISH)
                         
-            fieldbus_interface_declaration.append("""
-extern void ETHERLAB%(ucase_blocktype)s_body__(ETHERLAB%(ucase_blocktype)s* data__);
-void __%(blocktype)s_%(location_str)s(MC_%(ucase_blocktype)s *data__) {
-__DECLARE_GLOBAL_PROTOTYPE(ETHERLAB%(ucase_blocktype)s, %(blockname)s);
-ETHERLAB%(ucase_blocktype)s* %(blockname)s = __GET_GLOBAL_%(blockname)s();
-__SET_VAR(%(blockname)s->, POS,, AxsPub.axis->NetworkPosition);
-%(extract_inputs)s
-ETHERLAB%(ucase_blocktype)s_body__(%(blockname)s);
-%(return_outputs)s
-}""" % locals())
-            
-            fieldbus_interface_definition.append("""\
-        AxsPub.axis->__mcl_func_MC_%(blocktype)s = __%(blocktype)s_%(location_str)s;\
-""" % locals())
-        
-        # Get a copy list of default variables to map
-        variables = NODE_VARIABLES[:]
-        
-        # Set AxisRef public struct members value
-        node_params = self.CTNParams[1].getElementInfos(self.CTNParams[0])
-        for param in node_params["children"]:
-            param_name = param["name"]
-            
-            # Param is optional variables section enable flag
-            extra_node_variable_infos = EXTRA_NODE_VARIABLES_DICT.get(param_name)
-            if extra_node_variable_infos is not None:
-                param_name = param_name.replace("Enable", "") + "Enabled"
-                
-                if not param["value"]:
-                    continue
-                
-                # Optional variables section is enabled
-                for variable_infos in extra_node_variable_infos:
-                    var_name = variable_infos["description"][0]
-                    
-                    # Add each variables defined in section description to the
-                    # list of variables to map
-                    variables.append(variable_infos["description"])
-                    
-                    # Add code to publish or retrive variable
-                    for var_exchange_dir, str_list, default_template in [
-                         ("retrieve", extra_variables_retrieve,
-                          "    AxsPub.axis->%(var_name)s = *(AxsPub.%(var_name)s);"),
-                         ("publish", extra_variables_publish,
-                          "    *(AxsPub.%(var_name)s) = AxsPub.axis->%(var_name)s;")]:
-                        
-                        template = variable_infos.get(var_exchange_dir, 
-                                                      default_template)
-                        if template is not None:
-                            extra_variables_publish.append(template % locals())
-            
-            # Set AxisRef public struct member value if defined
+                        if retrieve_template is not None:
+                            str_completion["extra_variables_retrieve"].append(
+                                retrieve_template % var_infos)
+                        if publish_template is not None:
+                            str_completion["extra_variables_publish"].append(
+                                publish_template % var_infos)
+
+            #elif param["value"] is not None:
             if param["value"] is not None:
-                param_value = ({True: "1", False: "0"}[param["value"]]
-                               if param["type"] == "boolean"
-                               else str(param["value"]))
-                
-                init_axis_params.append("""\
-        AxsPub.axis->%(param_name)s = %(param_value)s;""" % locals())
-        
-        # Add each variable in list of variables to map to master list of
-        # variables to add to network configuration
-        for name, index, subindex, var_type, dir in variables:
-            var_size = self.GetSizeOfType(var_type)
-            var_name = """\
-__%(dir)s%(var_size)s%(location_str)s_%(index)d_%(subindex)d""" % locals()
-            
-            extern_located_variables_declaration.append(
-                    "IEC_%(var_type)s *%(var_name)s;" % locals())
-            entry_variables.append(
-                    "    IEC_%(var_type)s *%(name)s;" % locals())
-            init_entry_variables.append(
-                    "    AxsPub.%(name)s = %(var_name)s;" % locals())
+                param_infos = {
+                    "location": location_str,
+                    "param_name": param["name"],
+                }
+                if param["type"] == "boolean":
+                    param_infos["param_value"] = {True: "1", False: "0"}[param["value"]]
+                    param_infos["param_name"] = param["name"].replace("Enable", "") + "Enabled"
+                    if param["value"] == False:
+                        continue
+                else:
+                    param_infos["param_value"] = str(param["value"])
+                # param_name = param_name.replace("Enable", "") + "Enabled"
+                str_completion["init_axis_params"].append(
+                    "        __CIA402Node_%(location)s.axis->%(param_name)s = %(param_value)s;" % param_infos)
+        
+        check_variable = []
+        for variable in variables:
+            # add jblee
+            if variable in check_variable:
+                continue
+
+            var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable))
+            var_infos["location"] = location_str
+            var_infos["var_size"] = self.GetSizeOfType(var_infos["var_type"])
+            var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos
+
+            # add jblee
+            if var_infos["index"] in [24672] and ModeOfOpFlag:
+                str_completion["modeofop_homing_method"].append(MODEOFOP_HOMING_METHOD_TEMPLATE)
+                str_completion["modeofop_computation_mode"].append(MODEOFOP_COMPUTATION_MODE_TEMPLATE)
+
+            # add jblee
+            if var_infos["index"] in [24672, 24673] and (not ModeOfOpFlag or not ModeOfOpDisplayFlag):
+                continue
+
+            str_completion["extern_located_variables_declaration"].append(
+                    "IEC_%(var_type)s *%(var_name)s;" % var_infos)
+            str_completion["entry_variables"].append(
+                    "    IEC_%(var_type)s *%(name)s;" % var_infos)
+            str_completion["init_entry_variables"].append(
+                    "    __CIA402Node_%(location)s.%(name)s = %(var_name)s;" % var_infos)
             
             self.CTNParent.FileGenerator.DeclareVariable(
-                    slave_pos, index, subindex, var_type, dir, var_name)
-        
-        # Add newline between string in list of generated strings for sections
-        [fieldbus_interface_declaration, fieldbus_interface_definition,
-         init_axis_params, extra_variables_retrieve, extra_variables_publish,
-         extern_located_variables_declaration, entry_variables, 
-         init_entry_variables] = map(lambda l: "\n".join(l), [
-            fieldbus_interface_declaration, fieldbus_interface_definition,
-            init_axis_params, extra_variables_retrieve, extra_variables_publish,
-            extern_located_variables_declaration, entry_variables, 
-            init_entry_variables])
-        
-        # Write generated content to CIA402 node file
-        Gen_CIA402Nodefile_path = os.path.join(buildpath, 
-                                "cia402node_%s.c"%location_str)
+                    self.GetSlavePos(), var_infos["index"], var_infos["subindex"], 
+                    var_infos["var_type"], var_infos["dir"], var_infos["var_name"])
+
+            # add jblee
+            check_variable.append(variable)
+        
+        for element in ["extern_located_variables_declaration", 
+                        "fieldbus_interface_declaration",
+                        "fieldbus_interface_definition",
+                        "entry_variables", 
+                        "init_axis_params", 
+                        "init_entry_variables",
+                        "default_variables_retrieve",
+                        "default_variables_publish",
+                        "extra_variables_retrieve",
+                        "extra_variables_publish",
+                        "modeofop_homing_method",
+                        "modeofop_computation_mode"]:
+            str_completion[element] = "\n".join(str_completion[element])
+        
+        Gen_CIA402Nodefile_path = os.path.join(buildpath, "cia402node_%s.c"%location_str)
         cia402nodefile = open(Gen_CIA402Nodefile_path, 'w')
-        cia402nodefile.write(plc_cia402node_code % locals())
+        cia402nodefile.write(plc_cia402node_code % str_completion)
         cia402nodefile.close()
         
         return [(Gen_CIA402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))],"",True
+    
--- a/etherlab/EthercatMaster.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/EthercatMaster.py	Wed Nov 20 16:57:15 2019 +0100
@@ -85,9 +85,12 @@
         ethelabfile.write(etherlab_ext_code)
         ethelabfile.close()
         
-        runtimefile_path = os.path.join(os.path.split(__file__)[0], "runtime_etherlab.py")
-        return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", 
+        try:
+            return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", 
                 ("runtime_etherlab.py", file(GetLocalPath("runtime_etherlab.py"))))
+        except:
+            return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", 
+                ("runtime_etherlab.pyc", file(GetLocalPath("runtime_etherlab.pyc"))))
     
 #--------------------------------------------------
 #                 Ethercat MASTER
@@ -221,7 +224,7 @@
 ProcessVariablesParser = GenerateParserFromXSDstring(ProcessVariablesXSD) 
 
 class _EthercatCTN:
-
+    
     CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")]
     if HAS_MCL:
         CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave"))
@@ -231,20 +234,21 @@
         config_filepath = self.ConfigFileName()
         config_is_saved = False
         self.Config = None
-        if os.path.isfile(config_filepath):
-            config_xmlfile = open(config_filepath, 'r')
-            try:
-                self.Config, error = \
-                    EtherCATConfigParser.LoadXMLString(config_xmlfile.read())
-                if error is None:
-                    config_is_saved = True
-            except Exception, e:
-                error = e.message
-            config_xmlfile.close()
+
+        #if os.path.isfile(config_filepath):
+        #    config_xmlfile = open(config_filepath, 'r')
+        #    try:
+        #        self.Config, error = \
+        #            EtherCATConfigParser.LoadXMLString(config_xmlfile.read())
+        #        if error is None:
+        #            config_is_saved = True
+        #    except Exception, e:
+        #        error = e.message
+        #    config_xmlfile.close()
             
-            if error is not None:
-                self.GetCTRoot().logger.write_error(
-                    _("Couldn't load %s network configuration file.") % CTNName)    
+        #    if error is not None:
+        #        self.GetCTRoot().logger.write_error(
+        #            _("Couldn't load %s network configuration file.") % CTNName)    
             
         if self.Config is None:
             self.Config = EtherCATConfigParser.CreateElement("EtherCATConfig")
@@ -270,14 +274,32 @@
         if self.ProcessVariables is None:
             self.ProcessVariables = ProcessVariablesParser.CreateElement("ProcessVariables")
         
-        if config_is_saved and process_is_saved:
+        #if config_is_saved and process_is_saved:
+        if process_is_saved:
             self.CreateBuffer(True)
         else:
             self.CreateBuffer(False)
             self.OnCTNSave()
-         
+
+        if os.path.isfile(config_filepath):
+            config_xmlfile = open(config_filepath, 'r')
+            try:
+                self.Config, error = \
+                    EtherCATConfigParser.LoadXMLString(config_xmlfile.read())
+                if error is None:
+                    config_is_saved = True
+            except Exception, e:
+                error = e.message
+            config_xmlfile.close()
+            
+            if error is not None:
+                self.GetCTRoot().logger.write_error(
+                    _("Couldn't load %s network configuration file.") % CTNName)
+
         # ----------- call ethercat mng. function --------------
         self.CommonMethod = _CommonSlave(self)
+        
+        ###################################### Test Section #########################################
     
     def GetIconName(self):
         return "Ethercat"
@@ -293,7 +315,10 @@
             type_infos = dialog.GetValueInfos()
             device, module_extra_params = self.GetModuleInfos(type_infos)
             if device is not None:
-                if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers():
+                # device.GetProfileNumbers() return type is string
+                # _EthercatCIA402SlaveCTN.NODE_PROFILE change to string
+                # 151224 jblee
+                if HAS_MCL and str(_EthercatCIA402SlaveCTN.NODE_PROFILE) in device.GetProfileNumbers():
                     ConfNodeType = "EthercatCIA402Slave"
                 else:
                     ConfNodeType = "EthercatSlave"
@@ -563,6 +588,7 @@
                 return infos
         return None
     
+    """
     def GetSlaveVariables(self, slave_pos=None, limits=None, device=None):
         if device is None and slave_pos is not None:
             slave = self.GetSlave(slave_pos)
@@ -571,7 +597,6 @@
                 device, module_extra_params = self.GetModuleInfos(type_infos)
         if device is not None:
             entries = device.GetEntriesList(limits)
-            #print entries
             entries_list = entries.items()
             entries_list.sort()
             entries = []
@@ -592,6 +617,128 @@
                     entries.append(entry)
             return entries
         return []
+    #"""
+
+    def GetSlaveVariables(self, slave_pos=None, limits=None, device=None, module=None):
+        # add jblee
+        files = os.listdir(self.CTNPath())
+        moduleNames = []
+        modulePos = 1
+        for file in files:
+            filepath = os.path.join(self.CTNPath(), file)
+            if os.path.isdir(filepath):
+                MDPFilePath = os.path.join(filepath, "DataForMDP.txt")
+                CheckConfNodePath = os.path.join(filepath, "baseconfnode.xml")
+
+                try :
+                    moduleDataFile = open(MDPFilePath, 'r')
+                    confNodeFile = open(CheckConfNodePath, 'r')
+
+                    lines = moduleDataFile.readlines()
+                    checklines = confNodeFile.readlines()
+
+                    moduleDataFile.close()
+                    confNodeFile.close()
+
+                    module_info = self.GetModuleEntryList()
+                    # checklines(ex) : <BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="EthercatSlave_0"/>
+                    # checklines[1].split() : [<BaseParams, xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+                    #                           IEC_Channel="0", Name="EthercatSlave_0"/>]
+                    # checklines[1].split()[2] : IEC_Channel="0"
+                    # checklines[1].split()[2].split("\"") = [IEC_Channel=, 0, ]
+                    pos_check = int(checklines[1].split()[2].split("\"")[1])
+
+                    if slave_pos != pos_check:
+                        continue
+
+                    for line in lines:
+                        if line == "\n":
+                            continue
+                        # module_name : ST-1214, ST-2314, ...
+                        # if user add module => ST-1214 3EA, ST-2314 3EA
+                        # each result_module_name : 
+                        #    (ST-1214, Module 1), (ST-1214, Module 2), (ST-1214, Module 3)
+                        #    (ST-2314, Module 4), (ST-2314, Module 5), (ST-2314, Module 6)  
+                        module_name = line.split()[0]
+                        result_module_name = module_name + ", Module %d" % modulePos
+                        moduleNames.append(result_module_name)
+                        modulePos += 1
+                except :
+                    pass
+
+        if device is None and slave_pos is not None:
+            slave = self.GetSlave(slave_pos)
+            if slave is not None:
+                type_infos = slave.getType()
+                device, module_extra_params = self.GetModuleInfos(type_infos)
+                
+        if device is not None:
+            # Test OD
+            entries = device.GetEntriesList(limits)
+            #entries = self.CTNParent.GetEntriesList()
+            entries_list = entries.items()
+            entries_list.sort()
+            entries = []
+            current_index = None
+            current_entry = None
+            for (index, subindex), entry in entries_list:
+                entry["children"] = []
+                if slave_pos is not None:
+                    entry["Position"] = str(slave_pos)
+                entry
+                if index != current_index:
+                    current_index = index
+                    current_entry = entry
+                    entries.append(entry)
+                elif current_entry is not None:
+                    current_entry["children"].append(entry)
+                else:
+                    entries.append(entry)
+
+            increment = self.CTNParent.GetModuleIncrement()[0]
+            count = 1
+            #print module_info
+            # moduleNameAndPos : (ST-1214, Module 1), (ST-1214, Module 2), ... ,
+            # moduleNameAndPos.split(",") : ["ST-1214", " Module 1"]
+            # moduleNameAndPos.split(",")[0] : "ST-1214"
+            for moduleNameAndPos in moduleNames:
+                moduleName = moduleNameAndPos.split(",")[0]
+                modulePosName = moduleNameAndPos.split(",")[1]
+                idx_increment = int(increment) * count
+                
+                for MDP_entry in module_info.get(moduleName):
+                    LocalMDPEntry = []
+                    #print MDP_entry
+                    local_idx = MDP_entry["Index"]
+                    if ExtractHexDecValue(local_idx) == 0: #and local_idx[0] == "#":
+                        temp_index = ExtractHexDecValue(local_idx)
+                    else :
+                        temp_index = ExtractHexDecValue(MDP_entry["Index"]) + idx_increment
+                    #temp_index = ExtractHexDecValue(MDP_entry["Index"]) + idx_increment
+                    entry_index = hex(temp_index)
+                    entry_subidx = MDP_entry["SubIndex"]
+                    entry_name = MDP_entry["Name"] + ", " + " " + \
+                                 moduleName + " - " + modulePosName
+                    entry_type = MDP_entry["Type"]
+                    entry_bitsize = MDP_entry["BitSize"]
+                    entry_access = MDP_entry["Access"]
+                    mapping_type = MDP_entry["PDOMapping"]
+
+                    LocalMDPEntry.append({
+                        "Index": entry_index,
+                        "SubIndex": entry_subidx,
+                        "Name": entry_name,
+                        "Type": entry_type,
+                        "BitSize": entry_bitsize,
+                        "Access": entry_access, 
+                        "PDOMapping": mapping_type,
+                        "children": ""})
+                    entries.append(LocalMDPEntry[0])
+                count += 1
+            
+            #print entries
+            return entries
+        return []
     
     def GetSlaveVariableDataType(self, slave_pos, index, subindex):
         slave = self.GetSlave(slave_pos)
@@ -599,6 +746,7 @@
             device, module_extra_params = self.GetModuleInfos(slave.getType())
             if device is not None:
                 entries = device.GetEntriesList()
+                #entries = self.CTNParent.GetEntriesList()
                 entry_infos = entries.get((index, subindex))
                 if entry_infos is not None:
                     return entry_infos["Type"]
@@ -621,6 +769,10 @@
      
     def GetModuleInfos(self, type_infos):
         return self.CTNParent.GetModuleInfos(type_infos)
+
+    # add jblee
+    def GetModuleEntryList(self):
+        return self.CTNParent.GetModuleEntryList()
     
     def GetSlaveTypesLibrary(self, profile_filter=None):
         return self.CTNParent.GetModulesLibrary(profile_filter)
@@ -630,7 +782,54 @@
     
     def GetDeviceLocationTree(self, slave_pos, current_location, device_name):
         slave = self.GetSlave(slave_pos)
-        vars = []    
+        vars = []
+
+        # add jblee
+        files = os.listdir(self.CTNPath())
+        moduleNames = []
+        modulePos = 1
+        for file in files:
+            filepath = os.path.join(self.CTNPath(), file)
+            if os.path.isdir(filepath):
+                MDPFilePath = os.path.join(filepath, "DataForMDP.txt")
+                CheckConfNodePath = os.path.join(filepath, "baseconfnode.xml")
+
+                try :
+                    moduleDataFile = open(MDPFilePath, 'r')
+                    confNodeFile = open(CheckConfNodePath, 'r')
+
+                    lines = moduleDataFile.readlines()
+                    checklines = confNodeFile.readlines()
+
+                    moduleDataFile.close()
+                    confNodeFile.close()
+
+                    module_info = self.GetModuleEntryList()
+                    # checklines(ex) : <BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="EthercatSlave_0"/>
+                    # checklines[1].split() : [<BaseParams, xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+                    #                           IEC_Channel="0", Name="EthercatSlave_0"/>]
+                    # checklines[1].split()[2] : IEC_Channel="0"
+                    # checklines[1].split()[2].split("\"") = [IEC_Channel=, 0, ]
+                    pos_check = int(checklines[1].split()[2].split("\"")[1])
+
+                    if slave_pos != pos_check:
+                        continue
+
+                    for line in lines:
+                        if line == "\n":
+                            continue
+                        # module_name : ST-1214, ST-2314, ...
+                        # if user add module => ST-1214 3EA, ST-2314 3EA
+                        # each result_module_name : 
+                        #    (ST-1214, Module 1), (ST-1214, Module 2), (ST-1214, Module 3)
+                        #    (ST-2314, Module 4), (ST-2314, Module 5), (ST-2314, Module 6)  
+                        module_name = line.split()[0]
+                        result_module_name = module_name + ", Module %d" % modulePos
+                        moduleNames.append(result_module_name)
+                        modulePos += 1
+                except :
+                    pass
+
         if slave is not None:
             type_infos = slave.getType()
         
@@ -645,8 +844,11 @@
                     else:
                         sync_managers.append(LOCATION_VAR_INPUT)
                 
+                # Test OD
                 entries = device.GetEntriesList().items()
+                #entries = self.CTNParent.GetEntriesList().items()
                 entries.sort()
+                
                 for (index, subindex), entry in entries:
                     var_size = self.GetSizeOfType(entry["Type"])
                     if var_size is not None:
@@ -666,7 +868,40 @@
                                                                                                     (index, subindex)))),
                                          "description": "",
                                          "children": []})
-        
+
+                # add jblee for MDP
+                if not entries :
+                    increment = self.CTNParent.GetModuleIncrement()[0]
+                    count = 1
+                    for moduleNameAndPos in moduleNames:
+                        moduleName = moduleNameAndPos.split(",")[0]
+                        idx_increment = int(increment) * count
+                        for MDP_entry in module_info.get(moduleName):
+                            local_idx = MDP_entry["Index"]
+                            if ExtractHexDecValue(local_idx) != 0 and local_idx[0] == "#":
+                                index = ExtractHexDecValue(local_idx) + idx_increment
+                            else :
+                                index = ExtractHexDecValue(MDP_entry["Index"])
+                            subindex = int(MDP_entry["SubIndex"])
+                            var_class = VARCLASSCONVERSION.get(MDP_entry["PDOMapping"], None)
+                            if var_class is not None:
+                                if var_class == LOCATION_VAR_INPUT:
+                                    var_dir = "%I"
+                                else:
+                                    var_dir = "%Q"
+                            var_size = self.GetSizeOfType(MDP_entry["Type"])
+                            result_name = MDP_entry["Name"] + ", " + moduleNameAndPos
+                            vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, result_name),
+                                         "type": var_class,
+                                         "size": var_size,
+                                         "IEC_type": MDP_entry["Type"],
+                                         "var_name": "%s_%4.4x_%2.2x" % ("_".join(moduleName.split()), index, subindex),
+                                         "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
+                                                                                                    (index, subindex)))),
+                                         "description": "",
+                                         "children": []})
+                        count += 1
+
         return vars
     
     def CTNTestModified(self):
@@ -674,7 +909,6 @@
 
     def OnCTNSave(self, from_project_path=None):
         config_filepath = self.ConfigFileName()
-        
         config_xmlfile = open(config_filepath,"w")
         config_xmlfile.write(etree.tostring(
             self.Config, 
--- a/etherlab/EthercatSlave.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/EthercatSlave.py	Wed Nov 20 16:57:15 2019 +0100
@@ -18,6 +18,7 @@
 
 #------------------------------------------
 from CommonEtherCATFunction import _CommonSlave 
+from dialogs import BrowseValuesLibraryDialog
 #------------------------------------------
 
 
@@ -70,6 +71,8 @@
     def __init__(self):
         # ----------- call ethercat mng. function --------------
         self.CommonMethod = _CommonSlave(self)
+        self.SelectedRxPDOIndex = []
+        self.SelectedTxPDOIndex = []
     
     def GetIconName(self):
         return "Slave"
@@ -119,7 +122,7 @@
     def SetParamsAttribute(self, path, value):
         self.GetSlaveInfos()
         position = self.BaseParams.getIEC_Channel()
-        
+
         if path == "SlaveParams.Type":
             self.CTNParent.SetSlaveType(position, value)
             slave_type = self.CTNParent.GetSlaveType(self.GetSlavePos())
--- a/etherlab/entries_list.xslt	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/entries_list.xslt	Wed Nov 20 16:57:15 2019 +0100
@@ -1,1 +1,1 @@
-<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:str="http://exslt.org/strings" xmlns:math="http://exslt.org/math" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="ns" xmlns:yml="http://fdik.org/yml" xmlns:set="http://exslt.org/sets" version="1.0" xmlns:ns="entries_list_ns" exclude-result-prefixes="ns" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="xml"/><xsl:variable name="space" select="'                                                                                                                                                                                                        '"/><xsl:param name="autoindent" select="4"/><xsl:param name="min_index"/><xsl:param name="max_index"/><xsl:template match="text()"><xsl:param name="_indent" select="0"/></xsl:template><xsl:template match="Device"><xsl:param name="_indent" select="0"/><xsl:apply-templates select="Profile/Dictionary/Objects/Object"><xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/></xsl:apply-templates><xsl:for-each select="RxPdo"><xsl:call-template name="pdo_entries"><xsl:with-param name="direction" select="'Receive'"/></xsl:call-template></xsl:for-each><xsl:for-each select="TxPdo"><xsl:call-template name="pdo_entries"><xsl:with-param name="direction" select="'Transmit'"/></xsl:call-template></xsl:for-each></xsl:template><xsl:template match="Object"><xsl:param name="_indent" select="0"/><xsl:variable name="index"><xsl:value-of select="ns:HexDecValue(Index/text())"/></xsl:variable><xsl:variable name="entry_name"><xsl:value-of select="ns:EntryName(Name)"/></xsl:variable><xsl:choose><xsl:when test="$index &gt;= $min_index and $index &lt;= $max_index"><xsl:variable name="datatype_name"><xsl:value-of select="Type/text()"/></xsl:variable><xsl:choose><xsl:when test="ancestor::Dictionary/child::DataTypes/DataType[Name/text()=$datatype_name][SubItem]"><xsl:apply-templates select="ancestor::Dictionary/child::DataTypes/DataType[Name/text()=$datatype_name][SubItem]"><xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/><xsl:with-param name="index"><xsl:value-of select="$index"/></xsl:with-param><xsl:with-param name="entry_name"><xsl:value-of select="$entry_name"/></xsl:with-param></xsl:apply-templates></xsl:when><xsl:otherwise><xsl:variable name="subindex"><xsl:text>0</xsl:text></xsl:variable><xsl:variable name="entry"><xsl:value-of select="ns:AddEntry($index, $subindex, $entry_name, $datatype_name, BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text())"/></xsl:variable></xsl:otherwise></xsl:choose></xsl:when></xsl:choose></xsl:template><xsl:template match="DataType"><xsl:param name="_indent" select="0"/><xsl:param name="index"/><xsl:param name="entry_name"/><xsl:for-each select="SubItem"><xsl:variable name="subindex"><xsl:value-of select="ns:HexDecValue(SubIdx/text())"/></xsl:variable><xsl:variable name="subentry_name"><xsl:value-of select="$entry_name"/><xsl:text> - </xsl:text><xsl:value-of select="ns:EntryName(DisplayName, Name/text())"/></xsl:variable><xsl:variable name="entry"><xsl:value-of select="ns:AddEntry($index, $subindex, $subentry_name, Type/text(), BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text())"/></xsl:variable></xsl:for-each></xsl:template><xsl:template name="pdo_entries"><xsl:param name="_indent" select="0"/><xsl:param name="direction"/><xsl:variable name="pdo_index"><xsl:value-of select="ns:HexDecValue(Index/text())"/></xsl:variable><xsl:variable name="pdo_name"><xsl:value-of select="ns:EntryName(Name)"/></xsl:variable><xsl:for-each select="Entry"><xsl:variable name="index"><xsl:value-of select="ns:HexDecValue(Index/text())"/></xsl:variable><xsl:choose><xsl:when test="$index &gt;= $min_index and $index &lt;= $max_index"><xsl:variable name="subindex"><xsl:value-of select="ns:HexDecValue(SubIndex/text())"/></xsl:variable><xsl:variable name="subentry_name"><xsl:value-of select="ns:EntryName(Name)"/></xsl:variable><xsl:variable name="access"><xsl:choose><xsl:when test="$direction='Transmit'"><xsl:text>ro</xsl:text></xsl:when><xsl:otherwise><xsl:text>wo</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:variable name="pdo_mapping"><xsl:choose><xsl:when test="$direction='Transmit'"><xsl:text>T</xsl:text></xsl:when><xsl:otherwise><xsl:text>R</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:variable name="entry"><xsl:value-of select="ns:AddEntry($index, $subindex, $subentry_name, DataType/text(), BitLen/text(), $access, $pdo_mapping, $pdo_index, $pdo_name, $direction)"/></xsl:variable></xsl:when></xsl:choose></xsl:for-each></xsl:template></xsl:stylesheet>
\ No newline at end of file
+<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:str="http://exslt.org/strings" xmlns:math="http://exslt.org/math" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="ns" xmlns:yml="http://fdik.org/yml" xmlns:set="http://exslt.org/sets" version="1.0" xmlns:ns="entries_list_ns" exclude-result-prefixes="ns" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="xml"/><xsl:variable name="space" select="'                                                                                                                                                                                                        '"/><xsl:param name="autoindent" select="4"/><xsl:param name="min_index"/><xsl:param name="max_index"/><xsl:template match="text()"><xsl:param name="_indent" select="0"/></xsl:template><xsl:template match="Device"><xsl:param name="_indent" select="0"/><xsl:apply-templates select="Profile/Dictionary/Objects/Object"><xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/></xsl:apply-templates><xsl:for-each select="RxPdo"><xsl:call-template name="pdo_entries"><xsl:with-param name="direction" select="'Receive'"/></xsl:call-template></xsl:for-each><xsl:for-each select="TxPdo"><xsl:call-template name="pdo_entries"><xsl:with-param name="direction" select="'Transmit'"/></xsl:call-template></xsl:for-each></xsl:template><xsl:template match="Object"><xsl:param name="_indent" select="0"/><xsl:variable name="index"><xsl:value-of select="ns:HexDecValue(Index/text())"/></xsl:variable><xsl:variable name="entry_name"><xsl:value-of select="ns:EntryName(Name)"/></xsl:variable><xsl:choose><xsl:when test="$index &gt;= $min_index and $index &lt;= $max_index"><xsl:variable name="datatype_name"><xsl:value-of select="Type/text()"/></xsl:variable><xsl:variable name="default_value"><xsl:value-of select="Info/DefaultData/text()"/></xsl:variable><xsl:choose><xsl:when test="ancestor::Dictionary/child::DataTypes/DataType[Name/text()=$datatype_name][SubItem]"><xsl:apply-templates select="ancestor::Dictionary/child::DataTypes/DataType[Name/text()=$datatype_name][SubItem]"><xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/><xsl:with-param name="index"><xsl:value-of select="$index"/></xsl:with-param><xsl:with-param name="entry_name"><xsl:value-of select="$entry_name"/></xsl:with-param><xsl:with-param name="sub_default_value"><xsl:value-of select="Info"/></xsl:with-param></xsl:apply-templates></xsl:when><xsl:otherwise><xsl:variable name="subindex"><xsl:text>0</xsl:text></xsl:variable><xsl:variable name="sub_entry_flag"><xsl:text>0</xsl:text></xsl:variable><xsl:variable name="entry"><xsl:value-of select="ns:AddEntry($index, $subindex, $entry_name, $datatype_name, BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text(), $default_value, $sub_entry_flag)"/></xsl:variable></xsl:otherwise></xsl:choose></xsl:when></xsl:choose></xsl:template><xsl:template match="DataType"><xsl:param name="_indent" select="0"/><xsl:param name="index"/><xsl:param name="entry_name"/><xsl:param name="sub_default_value"/><xsl:for-each select="SubItem"><xsl:variable name="subindex"><xsl:value-of select="ns:HexDecValue(SubIdx/text())"/></xsl:variable><xsl:variable name="subentry_name"><xsl:value-of select="$entry_name"/><xsl:text> - </xsl:text><xsl:value-of select="ns:EntryName(DisplayName, Name/text())"/></xsl:variable><xsl:variable name="sub_entry_flag"><xsl:text>1</xsl:text></xsl:variable><xsl:variable name="entry"><xsl:value-of select="ns:AddEntry($index, $subindex, $subentry_name, Type/text(), BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text(), $sub_default_value, $sub_entry_flag)"/></xsl:variable></xsl:for-each></xsl:template><xsl:template name="pdo_entries"><xsl:param name="_indent" select="0"/><xsl:param name="direction"/><xsl:variable name="pdo_index"><xsl:value-of select="ns:HexDecValue(Index/text())"/></xsl:variable><xsl:variable name="pdo_name"><xsl:value-of select="ns:EntryName(Name)"/></xsl:variable><xsl:for-each select="Entry"><xsl:variable name="index"><xsl:value-of select="ns:HexDecValue(Index/text())"/></xsl:variable><xsl:choose><xsl:when test="$index &gt;= $min_index and $index &lt;= $max_index"><xsl:variable name="subindex"><xsl:value-of select="ns:HexDecValue(SubIndex/text())"/></xsl:variable><xsl:variable name="subentry_name"><xsl:value-of select="ns:EntryName(Name)"/></xsl:variable><xsl:variable name="access"><xsl:choose><xsl:when test="$direction='Transmit'"><xsl:text>ro</xsl:text></xsl:when><xsl:otherwise><xsl:text>wo</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:variable name="pdo_mapping"><xsl:choose><xsl:when test="$direction='Transmit'"><xsl:text>T</xsl:text></xsl:when><xsl:otherwise><xsl:text>R</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:variable name="entry"><xsl:value-of select="ns:AddEntry($index, $subindex, $subentry_name, DataType/text(), BitLen/text(), $access, $pdo_mapping, $pdo_index, $pdo_name, $direction)"/></xsl:variable></xsl:when></xsl:choose></xsl:for-each></xsl:template></xsl:stylesheet>
\ No newline at end of file
--- a/etherlab/entries_list.ysl2	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/entries_list.ysl2	Wed Nov 20 16:57:15 2019 +0100
@@ -38,17 +38,20 @@
         choose {
             when "$index >= $min_index and $index <= $max_index" {
                 variable "datatype_name" > «Type/text()»
+                variable "default_value" > «Info/DefaultData/text()»
                 choose {
                     when "ancestor::Dictionary/child::DataTypes/DataType[Name/text()=$datatype_name][SubItem]" {
                         apply "ancestor::Dictionary/child::DataTypes/DataType[Name/text()=$datatype_name][SubItem]" {
                             with "index" > «$index»
                             with "entry_name" > «$entry_name»
+                            with "sub_default_value" > «Info/SubItem/Info/DefaultData/text()»
                         }
                     }
                     otherwise {
                         variable "subindex" > 0
+                        variable "sub_entry_flag" > 0
                         variable "entry" {
-                            > «ns:AddEntry($index, $subindex, $entry_name, $datatype_name, BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text())»
+                            > «ns:AddEntry($index, $subindex, $entry_name, $datatype_name, BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text(), $default_value, $sub_entry_flag)»
                         }
                     }
                 }
@@ -59,11 +62,13 @@
     template "DataType" {
         param "index";
         param "entry_name";
+        param "sub_default_value"
         foreach "SubItem" {
             variable "subindex" > «ns:HexDecValue(SubIdx/text())»
             variable "subentry_name" > «$entry_name» - «ns:EntryName(DisplayName, Name/text())»
+            variable "sub_entry_flag" > 1
             variable "entry" {
-                > «ns:AddEntry($index, $subindex, $subentry_name, Type/text(), BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text())»
+                > «ns:AddEntry($index, $subindex, $subentry_name, Type/text(), BitSize/text(), Flags/Access/text(), Flags/PdoMapping/text(), $sub_default_value, $sub_entry_flag)»
             }
         }
     }
--- a/etherlab/etherlab.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/etherlab.py	Wed Nov 20 16:57:15 2019 +0100
@@ -10,6 +10,8 @@
 # See COPYING file for copyrights details.
 
 import os, shutil
+
+#from xml.dom import minidom
 from lxml import etree
 
 import wx
@@ -33,13 +35,16 @@
 EtherCATInfoParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd")) 
 EtherCATInfo_XPath = lambda xpath: etree.XPath(xpath)
 
+EtherCATBaseParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATBase.xsd"))
+EtherCATBase_XPath = lambda xpath1: etree.XPath(xpath1)
+
 def HexDecValue(context, *args):
     return str(ExtractHexDecValue(args[0][0]))
 
 def EntryName(context, *args):
     return ExtractName(args[0], 
         args[1][0] if len(args) > 1 else None)
-
+        
 ENTRY_INFOS_KEYS = [
     ("Index", lambda x: "#x%4.4X" % int(x), "#x0000"),
     ("SubIndex", str, "0"),
@@ -52,6 +57,19 @@
     ("PDO name", str, ""),
     ("PDO type", str, "")]
 
+# Read DefaultValue from ESI file
+# Add by jblee 151229
+ENTRY_INFOS_KEYS_FOR_DV = [
+    ("Index", lambda x: "#x%4.4X" % int(x), "#x0000"),
+    ("SubIndex", str, "0"),
+    ("Name", str, ""),
+    ("Type", str, ""),
+    ("BitSize", int, 0),
+    ("Access", str, ""),
+    ("PDOMapping", str, ""),
+    ("DefaultValue", str, ""),
+    ("Sub_entry_flag", str, "0")]
+
 class EntryListFactory:
 
     def __init__(self, entries):
@@ -59,11 +77,17 @@
     
     def AddEntry(self, context, *args):
         index, subindex = map(lambda x: int(x[0]), args[:2])
-        new_entry_infos = {
+        if len(args) > 9:
+		    new_entry_infos = {
             key: translate(arg[0]) if len(arg) > 0 else default
             for (key, translate, default), arg
             in zip(ENTRY_INFOS_KEYS, args)}
-        
+        else:
+            new_entry_infos = {
+            key: translate(arg[0]) if len(arg) > 0 else default
+            for (key, translate, default), arg
+            in zip(ENTRY_INFOS_KEYS_FOR_DV, args)}			
+			
         if (index, subindex) != (0, 0):
             entry_infos = self.Entries.get((index, subindex))
             if entry_infos is not None:
@@ -79,6 +103,7 @@
 
 cls = EtherCATInfoParser.GetElementClass("DeviceType")
 if cls:
+    cls.DataTypes = None
     
     profile_numbers_xpath = EtherCATInfo_XPath("Profile/ProfileNo")
     def GetProfileNumbers(self):
@@ -92,25 +117,151 @@
         return None
     setattr(cls, "getCoE", getCoE)
 
+    # Modify by jblee
+    def ExtractDataTypes(self):
+        #self.DataTypes = {}
+        #self.DT = {}
+        DT = {}
+        objects = []
+
+        # get Profile Field
+        for profile in self.getProfile():
+            # get each (ProfileNo, Dictionary) Field as child
+            for child in profile.getchildren():
+                # child.text is not None -> ProfileNo, is None -> Dictionary
+                if child.text is None:
+                    # get each (DataTypes, Objects) Field 
+                    dataTypes = child.getDataTypes()
+                    objects = child.getObjects()
+                                
+                    for dataType in dataTypes.getDataType():
+                        #if dataType.getName() is not None:
+                        #    print dataType.getName(), dataType
+                        DT[dataType.getName()] = dataType
+
+        return DT, objects
+    setattr(cls, "ExtractDataTypes", ExtractDataTypes)
+
     def GetEntriesList(self, limits=None):
+        DataTypes, objects = self.ExtractDataTypes()
+
         entries = {}
-        
-        factory = EntryListFactory(entries)
-        
-        entries_list_xslt_tree = etree.XSLT(
-            entries_list_xslt, extensions = {
-                ("entries_list_ns", "AddEntry"): factory.AddEntry,
-                ("entries_list_ns", "HexDecValue"): HexDecValue,
-                ("entries_list_ns", "EntryName"): EntryName})
-        entries_list_xslt_tree(self, **dict(zip(
-            ["min_index", "max_index"], 
-            map(lambda x: etree.XSLT.strparam(str(x)),
-                limits if limits is not None else [0x0000, 0xFFFF])
-            )))
+
+        # get each Object Field
+        for object in objects:
+            # Object Field mendatory : Index, Name, Type, BitSize
+            # Frequently Use : Info, Flags
+            # Info Field -> DefaultData, SubItem
+            # Flags Field -> Access, Category, PdoMapping
+            object_index = object.getIndex().getcontent()
+            index = ExtractHexDecValue(object_index)
+            if limits is None or limits[0] <= index <= limits[1]:
+                object_type = object.getType()
+                object_name = ExtractName(object.getName())
+                object_size = object.getBitSize()
+                defaultData = ""
+                object_access = ""
+                object_PDOMapping_data = ""
+
+                object_type_infos = DataTypes.get(object_type, None)
+                subItem_infos = object_type_infos.getchildren()
+                countSubIndex = 0
+                if len(subItem_infos) > 2:
+                    for subItem_info in subItem_infos:
+                        if subItem_info.tag == "SubItem" : 
+                            subItemName = subItem_info.getName()
+                            subIdx = subItem_info.getSubIdx()
+                            if subIdx is not None:
+                                object_subidx = ExtractHexDecValue(subIdx)
+                            else:
+                                object_subidx = ExtractHexDecValue(countSubIndex)
+                            subType = subItem_info.getType()
+                            subBitSize = subItem_info.getBitSize()
+                            subFlags = subItem_info.getFlags()
+                            subAccess = ""
+                            subPDOMapping_data = ""
+                            if subFlags is not None:
+                                subAccess = subFlags.getAccess().getcontent()
+                                subPDOMapping = subFlags.getPdoMapping()                                                        
+                                if subPDOMapping is not None:
+                                    subPDOMapping_data = subFlags.getPdoMapping().upper()
+
+                            entries[(index, object_subidx)] = {
+                                "Index": object_index,
+                                "SubIndex": subIdx,
+                                "Name": "%s - %s" % 
+                                    (object_name.decode("utf-8"),
+                                     subItemName.decode("utf-8")),
+                                "Type": subType,
+                                "BitSize": subBitSize,
+                                "Access": subAccess, 
+                                "PDOMapping": subPDOMapping_data}
+
+                            countSubIndex += 1
+
+                    info = object.getInfo()
+                    # subItemTest : check subItem 
+                    countSubIndex = 0
+                    if info is not None:
+                        subItems = info.getchildren()
+                        if len(subItems) > 1:
+                            for subItem in subItems:
+                                defaultdata_subidx = ExtractHexDecValue(countSubIndex)
+                                defaultData = subItem.getchildren()[1].findtext("DefaultData")
+                                entry = entries.get((index, defaultdata_subidx), None)
+                                if entry is not None:
+                                    entry["DefaultData"] = defaultData
+                                countSubIndex += 1
+
+                else :
+                    info = object.getInfo()
+                    if info is not None:
+                        subItems = info.getchildren()
+                        if len(subItems) <= 1:
+                            defaultData = subItems[0].text
+                                
+                    object_flag = object.getFlags()
+                    object_access = object_flag.getAccess().getcontent()
+                    object_PDOMapping = object_flag.getPdoMapping()
+                    if object_PDOMapping is not None:
+                        object_PDOMapping_data = object_flag.getPdoMapping().upper()
+                    entries[(index, 0)] = {
+                        "Index": object_index,
+                        "SubIndex": "0",
+                        "Name": object_name,                                                               
+                        "Type": object_type,
+                        "BitSize": object_size,
+                        "DefaultData" : defaultData,
+                        "Access": object_access, 
+                        "PDOMapping": object_PDOMapping_data}
+
+        for TxPdo in self.getTxPdo():
+            ExtractPdoInfos(TxPdo, "Transmit", entries, limits)
+        for RxPdo in self.getRxPdo():
+            ExtractPdoInfos(RxPdo, "Receive", entries, limits)
         
         return entries
     setattr(cls, "GetEntriesList", GetEntriesList)
 
+#    def GetEntriesList(self, limits=None):
+#        entries = {}
+        
+#        factory = EntryListFactory(entries)
+        
+#        entries_list_xslt_tree = etree.XSLT(
+#            entries_list_xslt, extensions = {
+#                ("entries_list_ns", "AddEntry"): factory.AddEntry,
+#                ("entries_list_ns", "HexDecValue"): HexDecValue,
+#                ("entries_list_ns", "EntryName"): EntryName})
+#        entries_list_xslt_tree(self, **dict(zip(
+#            ["min_index", "max_index"], 
+#            map(lambda x: etree.XSLT.strparam(str(x)),
+#                limits if limits is not None else [0x0000, 0xFFFF])
+#            )))
+#        
+#        return entries
+#    setattr(cls, "GetEntriesList", GetEntriesList)
+
     def GetSyncManagers(self):
         sync_managers = []
         for sync_manager in self.getSm():
@@ -127,6 +278,8 @@
         return sync_managers
     setattr(cls, "GetSyncManagers", GetSyncManagers)
 
+cls2 = EtherCATInfoParser.GetElementClass("DeviceType")
+
 def GroupItemCompare(x, y):
     if x["type"] == y["type"]:
         if x["type"] == ETHERCAT_GROUP:
@@ -143,6 +296,50 @@
             SortGroupItems(item)
     group["children"].sort(GroupItemCompare)
 
+def ExtractPdoInfos(pdo, pdo_type, entries, limits=None):
+    pdo_index = pdo.getIndex().getcontent()
+    pdo_name = ExtractName(pdo.getName())
+    exclude = pdo.getExclude()
+    for pdo_entry in pdo.getEntry():
+        entry_index = pdo_entry.getIndex().getcontent()
+        entry_subindex = pdo_entry.getSubIndex()
+        index = ExtractHexDecValue(entry_index)
+        subindex = ExtractHexDecValue(entry_subindex)
+        object_size = pdo_entry.getBitLen()
+
+        if limits is None or limits[0] <= index <= limits[1]:
+            entry = entries.get((index, subindex), None)
+            if entry is not None:
+                entry["PDO index"] = pdo_index
+                entry["PDO name"] = pdo_name
+                entry["PDO type"] = pdo_type
+            else:
+                entry_type = pdo_entry.getDataType()
+                if entry_type is not None:
+                    if pdo_type == "Transmit":
+                        access = "ro"
+                        pdomapping = "T"
+                    else:
+                        access = "wo"
+                        pdomapping = "R"
+                    entries[(index, subindex)] = {
+                        "Index": entry_index,
+                        "SubIndex": entry_subindex,
+                        "Name": ExtractName(pdo_entry.getName()),
+                        "Type": entry_type.getcontent(),
+                        "BitSize": object_size,
+                        "Access": access,
+                        "PDOMapping": pdomapping}
+
+#cls3 = EtherCATBaseParser.GetElementClass("ModuleType")
+#if cls3:
+#    module_xpath = EtherCATBase_XPath("Descriptions/Modules/Module")
+#    def test(self):
+#        print module_xpath
+
+#    setattr(cls, "test", test)
+
+
 class ModulesLibrary:
 
     MODULES_EXTRA_PARAMS = [
@@ -180,7 +377,7 @@
         else:
             self.Library = None
         self.LoadModulesExtraParams()
-    
+
     def GetPath(self):
         return self.Path
     
@@ -189,8 +386,20 @@
     
     groups_xpath = EtherCATInfo_XPath("Descriptions/Groups/Group")
     devices_xpath = EtherCATInfo_XPath("Descriptions/Devices/Device")
+    module_xpath = EtherCATBase_XPath("Descriptions/Modules/Module")
+
     def LoadModules(self):
         self.Library = {}
+        # add by jblee for Modular Device Profile
+        self.MDPList = []
+        self.ModuleList = []
+        self.MDPEntryList = {}
+        dtDic = {}
+        self.idxIncrement = 0
+        self.slotIncrement = 0
+        # add by jblee for PDO Mapping
+        self.DataTypes = {}
+        self.ObjectDictionary = {}
         
         files = os.listdir(self.Path)
         for file in files:
@@ -201,13 +410,13 @@
                 xmlfile = open(filepath, 'r')
                 try:
                     self.modules_infos, error = EtherCATInfoParser.LoadXMLString(xmlfile.read())
-                    if error is not None:
-                        self.GetCTRoot().logger.write_warning(
-                            XSDSchemaErrorMessage % (filepath + error))
+                    #if error is not None:
+                    #    self.GetCTRoot().logger.write_warning(
+                    #        XSDSchemaErrorMessage % (filepath + error))
                 except Exception, exc:
                     self.modules_infos, error = None, unicode(exc)
                 xmlfile.close()
-                
+
                 if self.modules_infos is not None:
                     vendor = self.modules_infos.getVendor()
                     
@@ -218,13 +427,17 @@
                     
                     for group in self.groups_xpath(self.modules_infos):
                         group_type = group.getType()
+                        # add for XmlToEeprom Func by jblee.
+                        self.LcId_data = group.getchildren()[1]
+                        self.Image16x14_data = group.getchildren()[2]
                         
                         vendor_category["groups"].setdefault(group_type, 
                             {"name": ExtractName(group.getName(), group_type), 
                              "parent": group.getParentGroup(),
                              "order": group.getSortOrder(), 
-                             #"value": group.getcontent()["value"],
-                             "devices": []})
+                             "devices": [],
+                            # add jblee for support Moduler Device Profile (MDP)
+                             "modules": []})
                     
                     for device in self.devices_xpath(self.modules_infos):
                         device_group = device.getGroupType()
@@ -232,14 +445,101 @@
                             raise ValueError, "Not such group \"%\"" % device_group
                         vendor_category["groups"][device_group]["devices"].append(
                             (device.getType().getcontent(), device))
-                
+
+                        # ------------------ Test Section --------------------#
+                        slots = device.getSlots()
+                        if slots is not None:
+                            for slot in slots.getSlot():
+                                self.idxIncrement = slot.getSlotIndexIncrement()
+                                self.slotIncrement = slot.getSlotPdoIncrement()
+                                for child in slot.getchildren():
+                                    if child.tag == "ModuleClass":
+                                        child_class = child.getClass()
+                                        child_name = child.getName()
+
+                    # -------------------- Test Section ----------------------------------# 
+                        LocalMDPList = []
+                        for module in self.module_xpath(self.modules_infos):
+                            module_type = module.getType().getModuleClass()
+                            module_name = module.getName()
+                            LocalMDPData = ExtractName(module_name) + " (" + module_type + ")"
+                            
+                            self.ModuleList.append(module)
+                            try :
+                                module_pdos = module.getTxPdo()
+                                module_pdos += module.getRxPdo()
+                                for module_pdo in module_pdos:
+                                    device_name = ExtractName(module_name)
+                                    pdo_index = module_pdo.getIndex().getcontent()
+                                    pdo_name = ExtractName(module_pdo.getName())
+                                    pdo_entry = module_pdo.getEntry()
+                                    if module_pdo.tag == "TxPdo":
+                                        mapping_type = "T"
+                                    else :
+                                        mapping_type = "R"
+
+                                    LocalMDPEntry = []
+                                    for entry in pdo_entry:
+                                        entry_index = entry.getIndex().getcontent()
+                                        entry_subidx = entry.getSubIndex()
+                                        entry_name = ExtractName(entry.getName())
+                                        entry_bitsize = entry.getBitLen()
+                                        try :
+                                           entry_type = entry.getDataType().getcontent()
+                                        except :
+                                           entry_type = ""
+
+                                        LocalMDPEntry.append({
+                                            "Index": entry_index,
+                                            "SubIndex": entry_subidx,
+                                            "Name": "%s - %s" % (pdo_name, entry_name),
+                                            "Type": entry_type,
+                                            "BitSize": entry_bitsize,
+                                            "Access": "", 
+                                            "PDOMapping": mapping_type})
+                                
+                                    self.MDPEntryList[device_name] = LocalMDPEntry
+
+                                LocalMDPList.append([LocalMDPData, module, LocalMDPEntry])
+                            except :
+                                LocalMDPList.append([LocalMDPData, module, []])
+                           
+                        if LocalMDPList:
+                            vendor_category["groups"][device_group]["modules"].append(
+                                (device.getType().getcontent(), LocalMDPList, self.idxIncrement, self.slotIncrement))
+                            #self.MDPList.append([device.getType().getcontent(), LocalMDPList,
+                            #                     self.idxIncrement, self.slotIncrement])
+
+                    # --------------------------------------------------------------------- #
+
                 else:
-                        
-                    self.GetCTRoot().logger.write_error(
-                        _("Couldn't load %s XML file:\n%s") % (filepath, error))
-                
-        return self.Library
-
+                    pass                      
+                    #self.GetCTRoot().logger.write_error(
+                    #    _("Couldn't load %s XML file:\n%s") % (filepath, error))
+
+        #print self.ObjectDictionary
+        return self.Library ## add jblee
+
+    # add jblee
+    def GetMDPList(self):
+        return self.MDPList
+
+    # add jblee
+    def GetSelectModule(self, idx):
+        return self.ModuleList[idx]
+
+    # add jblee
+    def GetModuleEntryList(self):
+        return self.MDPEntryList
+
+    # add jblee
+    def GetModuleIncrement(self):
+        return (self.idxIncrement, self.slotIncrement)
+
+    # add jblee
+    #def GetEntriesList(self):
+    #    return self.ObjectDictionary
+    
     def GetModulesLibrary(self, profile_filter=None):
         if self.Library is None:
             self.LoadModules()
@@ -301,10 +601,22 @@
                     revision_number = ExtractHexDecValue(device_infos.getType().getRevisionNo())
                     if (product_code == ExtractHexDecValue(module_infos["product_code"]) and
                         revision_number == ExtractHexDecValue(module_infos["revision_number"])):
-                        self.cntdevice = device_infos 
-                        self.cntdeviceType = device_type  
+                        self.cntdevice = device_infos ## add by hwang 13.05.01.
+                        self.cntdeviceType = device_type  ## add by hwang 13.05.01.
                         return device_infos, self.GetModuleExtraParams(vendor, product_code, revision_number)
         return None, None
+
+    # add jblee for MDP
+    def GetMDPInfos(self, module_infos):
+        vendor = ExtractHexDecValue(module_infos["vendor"])
+        vendor_infos = self.Library.get(vendor)
+        if vendor_infos is not None:
+            for group_name, group_infos in vendor_infos["groups"].iteritems():
+                return group_infos["modules"]
+                #for device_type, module_list, idx_inc, slot_inc in group_infos["modules"]:
+                #    return module_list, idx_inc, slot_inc
+
+        #return None, None, None
     
     def ImportModuleLibrary(self, filepath):
         if os.path.isfile(filepath):
@@ -387,7 +699,6 @@
     
     CTNChildrenTypes = [("EthercatNode",_EthercatCTN,"Ethercat Master")]
     EditorType = LibraryEditor
-       
     
     def __init__(self):
         self.ModulesLibrary = None
@@ -424,10 +735,32 @@
     
     def GetModulesLibrary(self, profile_filter=None):
         return self.ModulesLibrary.GetModulesLibrary(profile_filter)
-    
+
+    # add jblee
+    def GetMDPList(self):
+        return self.ModulesLibrary.GetMDPList()
+
+    # add jblee
+    def GetSelectModule(self, idx):
+        return self.ModulesLibrary.GetSelectModule(idx)
+
+    # add jblee
+    def GetModuleEntryList(self):
+        return self.ModulesLibrary.GetModuleEntryList()
+
+    # add jblee
+    def GetModuleIncrement(self):
+        return self.ModulesLibrary.GetModuleIncrement()
+
+    # add jblee
+    #def GetEntriesList(self, limits = None):
+    #    return self.ModulesLibrary.GetEntriesList()
+
     def GetVendors(self):
         return self.ModulesLibrary.GetVendors()
     
     def GetModuleInfos(self, module_infos):
         return self.ModulesLibrary.GetModuleInfos(module_infos)
 
+    def GetMDPInfos(self, module_infos):
+        return self.ModulesLibrary.GetMDPInfos(module_infos)
--- a/etherlab/plc_cia402node.c	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/plc_cia402node.c	Wed Nov 20 16:57:15 2019 +0100
@@ -3,6 +3,8 @@
 Template C code used to produce target Ethercat C CIA402 code
 
 Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT
+                         RTES Lab : CRKim, JBLee, youcu
+                         Higen Motor : Donggu Kang
 
 Distributed under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2 of the License, or
@@ -33,7 +35,25 @@
 xxxx xxxx x0xx 1111 | Fault reaction active
 xxxx xxxx x0xx 1000 | Fault
 */
+
+//ssh_add
+/* From CiA402, Page 63 Statusword for homing mode
+
+		Table 106 - Definition of bit 10, bit 12, bit 13
+
+xx00 x0xx xxxx xxxx | Homing procedure is in progress
+xx00 x1xx xxxx xxxx | Homing procedure is interrupted or not started
+xx01 x0xx xxxx xxxx | Homing is attained, but target is not reached
+xx01 x1xx xxxx xxxx | Homing procedure is completed successfully
+xx10 x0xx xxxx xxxx | Homing error occurred, velocity is not 0
+xx10 x1xx xxxx xxxx | Homing error occurred, velocity is 0
+xx11 xxxx xxxx xxxx | reserved
+*/
+
 #define FSAFromStatusWord(SW) (SW & 0x006f)
+//ssh_add
+#define HomingStatusWord(SW) (SW & 0x3400)
+#define FaultFromStatusWord(SW) (SW & 0x0008)
 #define NotReadyToSwitchOn  0b00000000 FSA_sep 0b00100000
 #define SwitchOnDisabled    0b01000000 FSA_sep 0b01100000
 #define ReadyToSwitchOn     0b00100001
@@ -43,7 +63,16 @@
 #define FaultReactionActive 0b00001111 FSA_sep 0b00101111
 #define Fault               0b00001000 FSA_sep 0b00101000
 
-// SatusWord bits :
+//ssh_add
+#define HomingInProgress	0b0000000000000000
+#define HomingNotRunning	0b0000010000000000
+#define HomingNotReached	0b0001000000000000
+#define Homing_Completed	0b0001010000000000
+#define HomingErrorInVelo	0b0010000000000000
+#define HomingErrorNotVelo	0b0010010000000000
+#define HomingReserved		0b0011000000000000 FSA_sep 0b0011010000000000
+
+// StatusWord bits :
 #define SW_ReadyToSwitchOn     0x0001
 #define SW_SwitchedOn          0x0002
 #define SW_OperationEnabled    0x0004
@@ -56,6 +85,10 @@
 #define SW_TargetReached       0x0400
 #define SW_InternalLimitActive 0x0800
 
+//ssh_add
+#define SW_HomingAttained		0x1000
+#define SW_HomingError			0x2000
+
 // ControlWord bits :
 #define SwitchOn        0x0001
 #define EnableVoltage   0x0002
@@ -64,11 +97,15 @@
 #define FaultReset      0x0080
 #define Halt            0x0100
 
-
-IEC_INT beremiz__IW%(location_str)s = %(slave_pos)s;
-IEC_INT *__IW%(location_str)s = &beremiz__IW%(location_str)s;
-IEC_INT beremiz__IW%(location_str)s_402;
-IEC_INT *__IW%(location_str)s_402 = &beremiz__IW%(location_str)s_402;
+//ssh_add
+//#define Homing_OperationStart 0x0010
+#define Homing_OperationStart_Origin 0x0010
+#define Homing_OperationStart_Edit 0x001F
+
+IEC_INT beremiz__IW%(location)s = %(slave_pos)s;
+IEC_INT *__IW%(location)s = &beremiz__IW%(location)s;
+IEC_INT beremiz__IW%(location)s_402;
+IEC_INT *__IW%(location)s_402 = &beremiz__IW%(location)s_402;
 
 %(MCL_headers)s
 
@@ -79,7 +116,7 @@
     axis_s* axis;
 } __CIA402Node;
 
-#define AxsPub __CIA402Node_%(location_str)s
+#define AxsPub __CIA402Node_%(location)s
 
 static __CIA402Node AxsPub;
 
@@ -87,25 +124,24 @@
 
 %(fieldbus_interface_declaration)s
 
-int __init_%(location_str)s()
+int __init_%(location)s()
 {
     __FirstTick = 1;
 %(init_entry_variables)s
-	*(AxsPub.ModesOfOperation) = 0x08;
     return 0;
 }
 
-void __cleanup_%(location_str)s()
-{
-}
-
-void __retrieve_%(location_str)s()
+void __cleanup_%(location)s()
+{
+}
+
+void __retrieve_%(location)s()
 {
 	if (__FirstTick) {
-		*__IW%(location_str)s_402 = __MK_Alloc_AXIS_REF();
+		*__IW%(location)s_402 = __MK_Alloc_AXIS_REF();
 		AxsPub.axis = 
-            __MK_GetPublic_AXIS_REF(*__IW%(location_str)s_402);
-		AxsPub.axis->NetworkPosition = beremiz__IW%(location_str)s;
+            __MK_GetPublic_AXIS_REF(*__IW%(location)s_402);
+		AxsPub.axis->NetworkPosition = beremiz__IW%(location)s;
 %(init_axis_params)s
 %(fieldbus_interface_definition)s
 		__FirstTick = 0;
@@ -121,15 +157,13 @@
         AxsPub.axis->PowerFeedback = FSA == OperationEnabled;
     }
 #undef FSA_sep 
-	AxsPub.axis->ActualRawPosition = *(AxsPub.ActualPosition);
-	AxsPub.axis->ActualRawVelocity = *(AxsPub.ActualVelocity);
-	AxsPub.axis->ActualRawTorque = *(AxsPub.ActualTorque);
+%(default_variables_retrieve)s
 
 	// Extra variables retrieve
 %(extra_variables_retrieve)s
 }
 
-void __publish_%(location_str)s()
+void __publish_%(location)s()
 {
 	IEC_BOOL power = 
         ((*(AxsPub.StatusWord) & SW_VoltageEnabled) != 0) 
@@ -156,37 +190,61 @@
                 CW |= SwitchOn | EnableVoltage | QuickStop | EnableOperation;
 	    	}
 	    	break;
-	    case Fault :
-            /* TODO reset fault only when MC_Reset */
-            CW &= ~(SwitchOn | EnableVoltage | QuickStop | EnableOperation);
-            CW |= FaultReset;
-	    	break;
+			//ssh_check
+//	    case Fault :
+//            /* TODO reset fault only when MC_Reset */
+//	    	AxsPub.axis->DriveFault = 1;
+//            CW &= ~(SwitchOn | EnableVoltage | QuickStop | EnableOperation);
+//            CW |= FaultReset;
+//	    	break;
 	    default:
 	    	break;
 	}
+	//ssh_add
+	if(FaultFromStatusWord(*(AxsPub.StatusWord)) == SW_Fault)
+		AxsPub.axis->DriveFault = 1;
+	else{
+		AxsPub.axis->DriveFault = 0;
+		AxsPub.axis->DriveFaultReset = 0;
+	}
+	if(AxsPub.axis->DriveFaultReset){
+		CW &= ~(SwitchOn | EnableVoltage | QuickStop | EnableOperation);
+		CW |= FaultReset;
+	}
+
+	//ssh_add
+	switch (HomingStatusWord(*(AxsPub.StatusWord))) {
+		case HomingInProgress:
+			break;
+		case HomingNotRunning:
+			break;
+		case HomingNotReached:
+			break;
+		case Homing_Completed:
+			if(!AxsPub.axis->HomingCompleted)
+				AxsPub.axis->HomingCompleted = 1;
+			break;
+		case HomingErrorInVelo:
+		case HomingErrorNotVelo:
+			if(!AxsPub.axis->HomingCompleted)
+				AxsPub.axis->HomingCompleted = 1;
+			break;
+		case HomingReserved:
+			break;
+	}
 #undef FSA_sep 
-    *(AxsPub.ControlWord) = CW;
+
+	//ssh_add
+%(modeofop_homing_method)s
+
+	*(AxsPub.ControlWord) = CW;
+
 
 	// CIA402 node modes of operation computation according to axis motion mode
-	switch (AxsPub.axis->AxisMotionMode) {
-		case mc_mode_cst:
-			*(AxsPub.ModesOfOperation) = 0x0a;
-			break;
-		case mc_mode_csv:
-			*(AxsPub.ModesOfOperation) = 0x09;
-			break;
-		default:
-			*(AxsPub.ModesOfOperation) = 0x08;
-			break;
-	}
+%(modeofop_computation_mode)s
 
 	// Default variables publish
-	*(AxsPub.TargetPosition) = 
-            AxsPub.axis->RawPositionSetPoint;
-	*(AxsPub.TargetVelocity) = 
-            AxsPub.axis->RawVelocitySetPoint;
-	*(AxsPub.TargetTorque) = 
-            AxsPub.axis->RawTorqueSetPoint;
+%(default_variables_publish)s
 
 	// Extra variables publish
 %(extra_variables_publish)s
--- a/etherlab/plc_etherlab.c	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/plc_etherlab.c	Wed Nov 20 16:57:15 2019 +0100
@@ -32,6 +32,43 @@
 %(used_pdo_entry_configuration)s
     {}
 };
+
+// Distributed Clock variables;
+%(dc_variable)s
+unsigned long long comp_period_ns = 500000ULL;
+
+int comp_count = 1;
+int comp_count_max;
+
+#define DC_FILTER_CNT          1024
+
+// EtherCAT slave-time-based DC Synchronization variables.
+static uint64_t dc_start_time_ns = 0LL;
+static uint64_t dc_time_ns = 0;
+static uint8_t  dc_started = 0;
+static int32_t  dc_diff_ns = 0;
+static int32_t  prev_dc_diff_ns = 0;
+static int64_t  dc_diff_total_ns = 0LL;
+static int64_t  dc_delta_total_ns = 0LL;
+static int      dc_filter_idx = 0;
+static int64_t  dc_adjust_ns;
+static int64_t  system_time_base = 0LL;
+
+static uint64_t dc_first_app_time = 0LL;
+
+unsigned long long frame_period_ns = 0ULL;
+
+int debug_count = 0;
+int slave_dc_used = 0;
+
+void dc_init(void);
+uint64_t system_time_ns(void);
+RTIME system2count(uint64_t time);
+void sync_distributed_clocks(void);
+void update_master_clock(void);
+RTIME calculate_sleeptime(uint64_t wakeup_time);
+uint64_t calculate_first(void);
+
 /*****************************************************************************/
 
 %(pdos_configuration_declaration)s
@@ -50,7 +87,7 @@
     LogMessage(level, sbuf, slen);\
 }
 
-/* Beremiz plugin functions */
+/* EtherCAT plugin functions */
 int __init_%(location)s(int argc,char **argv)
 {
     uint32_t abort_code;
@@ -81,10 +118,34 @@
     ecrt_master_set_send_interval(master, common_ticktime__);
 
     // slaves initialization
+/*
 %(slaves_initialization)s
+*/
+    // configure DC SYNC0/1 Signal
+%(config_dc)s
+
+    // select reference clock
+#if DC_ENABLE
+    {
+        int ret;
+        
+        ret = ecrt_master_select_reference_clock(master, slave0);
+        if (ret <0) {
+            fprintf(stderr, "Failed to select reference clock : %%s\n",
+                strerror(-ret));
+            return ret;
+        }
+    }
+#endif
 
     // extracting default value for not mapped entry in output PDOs
+/*
 %(slaves_output_pdos_default_values_extraction)s
+*/
+
+#if DC_ENABLE
+    dc_init();
+#endif
 
     if (ecrt_master_activate(master)){
         SLOGF(LOG_CRITICAL, "EtherCAT Master activation failed");
@@ -126,17 +187,20 @@
 
 }
 
+/*
 static RTIME _last_occur=0;
 static RTIME _last_publish=0;
 RTIME _current_lag=0;
 RTIME _max_jitter=0;
 static inline RTIME max(RTIME a,RTIME b){return a>b?a:b;}
+*/
 
 void __publish_%(location)s(void)
 {
 %(publish_variables)s
     ecrt_domain_queue(domain1);
     {
+        /*
         RTIME current_time = rt_timer_read();
         // Limit spining max 1/5 of common_ticktime
         RTIME maxdeadline = current_time + (common_ticktime__ / 5);
@@ -162,7 +226,281 @@
             //Consuming security margin ?
             _last_occur = current_time; //Drift forward
         }
-    }
+        */
+    }
+
+#if DC_ENABLE
+    if (comp_count == 0)
+        sync_distributed_clocks();
+#endif
+
     ecrt_master_send(master);
     first_sent = 1;
-}
+
+#if DC_ENABLE
+    if (comp_count == 0)
+        update_master_clock();
+
+    comp_count++;
+    
+    if (comp_count == comp_count_max)
+        comp_count = 0;
+#endif
+
+}
+
+/* Test Function For Parameter (SDO) Set */
+
+/*
+void GetSDOData(void){
+    uint32_t abort_code, test_value;
+    size_t result_size;
+    uint8_t value[4];
+
+    abort_code = 0;
+    result_size = 0;
+    test_value = 0;
+
+    if (ecrt_master_sdo_upload(master, 0, 0x1000, 0x0, (uint8_t *)value, 4, &result_size, &abort_code)) {
+        SLOGF(LOG_CRITICAL, "EtherCAT failed to get SDO Value");
+        }
+        test_value = EC_READ_S32((uint8_t *)value);
+        SLOGF(LOG_INFO, "SDO Value %%d", test_value);
+}
+*/
+
+int GetMasterData(void){
+    master = ecrt_open_master(0);
+    if (!master) {
+        SLOGF(LOG_CRITICAL, "EtherCAT master request failed!");
+        return -1;
+    }
+    return 0;
+}
+
+void ReleaseMasterData(void){
+    ecrt_release_master(master);
+}
+
+uint32_t GetSDOData(uint16_t slave_pos, uint16_t idx, uint8_t subidx, int size){
+    uint32_t abort_code, return_value;
+    size_t result_size;
+    uint8_t value[size];
+
+    abort_code = 0;
+    result_size = 0;
+
+    if (ecrt_master_sdo_upload(master, slave_pos, idx, subidx, (uint8_t *)value, size, &result_size, &abort_code)) {
+        SLOGF(LOG_CRITICAL, "EtherCAT failed to get SDO Value %%d %%d", idx, subidx);
+    }
+
+    return_value = EC_READ_S32((uint8_t *)value);
+    //SLOGF(LOG_INFO, "SDO Value %%d", return_value);
+
+    return return_value;
+}
+
+/*****************************************************************************/
+
+void dc_init(void)
+{
+    slave_dc_used = 1;
+
+    frame_period_ns = common_ticktime__;
+    if (frame_period_ns <= comp_period_ns) {
+        comp_count_max = comp_period_ns / frame_period_ns;
+        comp_count = 0;
+    } else  {
+        comp_count_max = 1;
+        comp_count = 0;
+    }
+
+    /* Set the initial master time */
+    dc_start_time_ns = system_time_ns();
+    dc_time_ns = dc_start_time_ns;
+
+    /* by woonggy */
+    dc_first_app_time = dc_start_time_ns;
+
+    /*
+     * Attention : The initial application time is also used for phase
+     * calculation for the SYNC0/1 interrupts. Please be sure to call it at
+     * the correct phase to the realtime cycle.
+     */
+    ecrt_master_application_time(master, dc_start_time_ns);
+}
+
+/****************************************************************************/
+
+/*
+ * Get the time in ns for the current cpu, adjusted by system_time_base.
+ *
+ * \attention Rather than calling rt_timer_read() directly, all application
+ * time calls should use this method instead.
+ *
+ * \ret The time in ns.
+ */
+uint64_t system_time_ns(void)
+{
+    RTIME time = rt_timer_read();   // wkk
+
+    if (unlikely(system_time_base > (SRTIME) time)) {
+        fprintf(stderr, "%%s() error: system_time_base greater than"
+                " system time (system_time_base: %%ld, time: %%llu\n",
+                __func__, system_time_base, time);
+        return time;
+    }
+    else {
+        return time - system_time_base;
+    }
+}
+
+/****************************************************************************/
+
+// Convert system time to Xenomai time in counts (via the system_time_base).
+RTIME system2count(uint64_t time)
+{
+    RTIME ret;
+
+    if ((system_time_base < 0) &&
+            ((uint64_t) (-system_time_base) > time)) {
+        fprintf(stderr, "%%s() error: system_time_base less than"
+                " system time (system_time_base: %%I64d, time: %%ld\n",
+                __func__, system_time_base, time);
+        ret = time;
+    }
+    else {
+        ret = time + system_time_base;
+    }
+
+    return (RTIME) rt_timer_ns2ticks(ret); // wkk
+}
+
+/*****************************************************************************/
+
+// Synchronise the distributed clocks
+void sync_distributed_clocks(void)
+{
+    uint32_t ref_time = 0;
+    RTIME prev_app_time = dc_time_ns;
+
+    // get reference clock time to synchronize master cycle
+    if(!ecrt_master_reference_clock_time(master, &ref_time)) {
+        dc_diff_ns = (uint32_t) prev_app_time - ref_time;
+    }
+    // call to sync slaves to ref slave
+    ecrt_master_sync_slave_clocks(master);
+    // set master time in nano-seconds
+    dc_time_ns = system_time_ns();
+    ecrt_master_application_time(master, dc_time_ns);
+}
+
+/*****************************************************************************/
+
+/*
+ * Return the sign of a number
+ * ie -1 for -ve value, 0 for 0, +1 for +ve value
+ * \ret val the sign of the value
+ */
+#define sign(val) \
+        ({ typeof (val) _val = (val); \
+        ((_val > 0) - (_val < 0)); })
+
+/*****************************************************************************/
+
+/*
+ * Update the master time based on ref slaves time diff
+ * called after the ethercat frame is sent to avoid time jitter in
+ * sync_distributed_clocks()
+ */
+void update_master_clock(void)
+{
+    // calc drift (via un-normalised time diff)
+    int32_t delta = dc_diff_ns - prev_dc_diff_ns;
+    prev_dc_diff_ns = dc_diff_ns;
+
+    // normalise the time diff
+    dc_diff_ns = dc_diff_ns >= 0 ?
+            ((dc_diff_ns + (int32_t)(frame_period_ns / 2)) %%
+                    (int32_t)frame_period_ns) - (frame_period_ns / 2) :
+                    ((dc_diff_ns - (int32_t)(frame_period_ns / 2)) %%
+                            (int32_t)frame_period_ns) - (frame_period_ns / 2) ;
+
+    // only update if primary master
+    if (dc_started) {
+        // add to totals
+        dc_diff_total_ns += dc_diff_ns;
+        dc_delta_total_ns += delta;
+        dc_filter_idx++;
+
+        if (dc_filter_idx >= DC_FILTER_CNT) {
+            dc_adjust_ns += dc_delta_total_ns >= 0 ?
+                    ((dc_delta_total_ns + (DC_FILTER_CNT / 2)) / DC_FILTER_CNT) :
+                    ((dc_delta_total_ns - (DC_FILTER_CNT / 2)) / DC_FILTER_CNT) ;
+
+            // and add adjustment for general diff (to pull in drift)
+            dc_adjust_ns += sign(dc_diff_total_ns / DC_FILTER_CNT);
+
+            // limit crazy numbers (0.1%% of std cycle time)
+            if (dc_adjust_ns < -1000) {
+                dc_adjust_ns = -1000;
+            }
+            if (dc_adjust_ns > 1000) {
+                dc_adjust_ns =  1000;
+            }
+            // reset
+            dc_diff_total_ns = 0LL;
+            dc_delta_total_ns = 0LL;
+            dc_filter_idx = 0;
+        }
+        // add cycles adjustment to time base (including a spot adjustment)
+        system_time_base += dc_adjust_ns + sign(dc_diff_ns);
+    }
+    else {
+        dc_started = (dc_diff_ns != 0);
+
+        if (dc_started) {
+#if DC_ENABLE && DEBUG_MODE
+            // output first diff
+            fprintf(stderr, "First master diff: %%d\n", dc_diff_ns);
+#endif
+            // record the time of this initial cycle
+            dc_start_time_ns = dc_time_ns;
+        }
+    }
+}
+
+/*****************************************************************************/
+
+/*
+ * Calculate the sleeptime
+ */
+RTIME calculate_sleeptime(uint64_t wakeup_time)
+{
+    RTIME wakeup_count = system2count (wakeup_time);
+    RTIME current_count = rt_timer_read();
+
+    if ((wakeup_count < current_count) || (wakeup_count > current_count + (50 * frame_period_ns)))  {
+        fprintf(stderr, "%%s(): unexpected wake time! wc = %%lld\tcc = %%lld\n", __func__, wakeup_count, current_count);
+    }
+
+    return wakeup_count;
+}
+
+/*****************************************************************************/
+
+/*
+ * Calculate the sleeptime
+ */
+uint64_t calculate_first(void)
+{
+    uint64_t dc_remainder = 0LL;
+    uint64_t dc_phase_set_time = 0LL;
+    
+    dc_phase_set_time = system_time_ns()+ frame_period_ns * 10;
+    dc_remainder = (dc_phase_set_time - dc_first_app_time) %% frame_period_ns;
+
+    return dc_phase_set_time + frame_period_ns - dc_remainder;
+}
+
+/*****************************************************************************/
--- a/etherlab/pous.xml	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/pous.xml	Wed Nov 20 16:57:15 2019 +0100
@@ -110,13 +110,13 @@
       VALUE := 'None';
     END_IF;
   1:
-    {if (AcquireSDOLock()) __SET_VAR(data__->,STATE,, 2)}
+    {if (AcquireSDOLock()) __SET_VAR(data__->,STATE, 2)}
   2:
     IF PY0.ACK THEN
       STATE := 3;
     END_IF;
   3:
-    {if (HasAnswer()) __SET_VAR(data__->,STATE,, 4)}
+    {if (HasAnswer()) __SET_VAR(data__->,STATE, 4)}
   4:
     IF PY1.ACK THEN
       ACK := 1;
@@ -231,13 +231,13 @@
       ERROR := 0;
     END_IF;
   1:
-    {if (AcquireSDOLock()) __SET_VAR(data__->,STATE,, 2)}
+    {if (AcquireSDOLock()) __SET_VAR(data__->,STATE, 2)}
   2:
     IF PY0.ACK THEN
       STATE := 3;
     END_IF;
   3:
-    {if (HasAnswer()) __SET_VAR(data__->,STATE,, 4)}
+    {if (HasAnswer()) __SET_VAR(data__->,STATE, 4)}
   4:
     IF PY1.ACK THEN
       ACK := 1;
--- a/etherlab/runtime_etherlab.py	Sat Jun 23 09:17:20 2018 +0200
+++ b/etherlab/runtime_etherlab.py	Wed Nov 20 16:57:15 2019 +0100
@@ -1,3 +1,14 @@
+#!/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,subprocess,sys,ctypes
 from threading import Thread
 import ctypes,time,re
@@ -42,7 +53,7 @@
         PLCObject.LogMessage(
             LogLevelsDict["WARNING"], 
             "%s : %s"%(command,output))
-    
+
 def EthercatSDOUpload(pos, index, subindex, var_type):
     global SDOThread
     SDOThread = Thread(target=SDOThreadProc, args=["upload", pos, var_type, index, subindex])