edouard@2165: #!/usr/bin/env python
edouard@2165: # -*- coding: utf-8 -*-
edouard@2165: 
edouard@2165: # This file is part of Beremiz
edouard@2165: #
edouard@2165: # Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT
edouard@2165: #                          RTES Lab : CRKim, JBLee, youcu
edouard@2165: #                          Higen Motor : Donggu Kang
edouard@2165: #
edouard@2165: # See COPYING file for copyrights details.
edouard@2165: 
andrej@2405: from __future__ import absolute_import
andrej@2357: import os
andrej@2357: import shutil
andrej@2390: import csv
andrej@2434: from builtins import str as text
andrej@2434: 
Laurent@2157: from lxml import etree
laurent@2022: import wx
laurent@2022: 
laurent@2022: from xmlclass import *
Laurent@2111: 
andrej@2396: from ConfigTreeNode import XSDSchemaErrorMessage
Laurent@2111: 
andrej@2405: from etherlab.EthercatSlave import ExtractHexDecValue, ExtractName
andrej@2405: from etherlab.EthercatMaster import _EthercatCTN
andrej@2405: from etherlab.ConfigEditor import LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
laurent@2022: 
Laurent@2157: ScriptDirectory = os.path.split(os.path.realpath(__file__))[0]
Laurent@2157: 
andrej@2356: # --------------------------------------------------
Edouard@2048: #                 Ethercat ConfNode
andrej@2356: # --------------------------------------------------
laurent@2022: 
andrej@2355: EtherCATInfoParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd"))
andrej@2376: 
andrej@2376: 
andrej@2376: def EtherCATInfo_XPath(xpath):
andrej@2376:     return etree.XPath(xpath)
Laurent@2157: 
Laurent@2157: 
edouard@2641: EtherCATBaseParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATBase.xsd"))
edouard@2643: 
edouard@2643: 
edouard@2643: def EtherCATBase_XPath(xpath):
edouard@2643:     return etree.XPath(xpath)
edouard@2643: 
edouard@2641: 
Laurent@2162: def HexDecValue(context, *args):
Laurent@2162:     return str(ExtractHexDecValue(args[0][0]))
Laurent@2162: 
andrej@2360: 
Laurent@2162: def EntryName(context, *args):
andrej@2381:     return ExtractName(args[0], args[1][0] if len(args) > 1 else None)
Laurent@2162: 
andrej@2370: 
Laurent@2162: ENTRY_INFOS_KEYS = [
Laurent@2162:     ("Index", lambda x: "#x%4.4X" % int(x), "#x0000"),
Laurent@2162:     ("SubIndex", str, "0"),
Laurent@2162:     ("Name", str, ""),
Laurent@2162:     ("Type", str, ""),
Laurent@2162:     ("BitSize", int, 0),
Laurent@2162:     ("Access", str, ""),
Laurent@2162:     ("PDOMapping", str, ""),
Laurent@2162:     ("PDO index", str, ""),
Laurent@2162:     ("PDO name", str, ""),
Laurent@2162:     ("PDO type", str, "")]
Laurent@2162: 
edouard@2641: # Read DefaultValue from ESI file
edouard@2641: # Add by jblee 151229
edouard@2641: ENTRY_INFOS_KEYS_FOR_DV = [
edouard@2641:     ("Index", lambda x: "#x%4.4X" % int(x), "#x0000"),
edouard@2641:     ("SubIndex", str, "0"),
edouard@2641:     ("Name", str, ""),
edouard@2641:     ("Type", str, ""),
edouard@2641:     ("BitSize", int, 0),
edouard@2641:     ("Access", str, ""),
edouard@2641:     ("PDOMapping", str, ""),
edouard@2641:     ("DefaultValue", str, ""),
edouard@2641:     ("Sub_entry_flag", str, "0")]
edouard@2641: 
andrej@2397: class EntryListFactory(object):
Laurent@2157: 
Laurent@2157:     def __init__(self, entries):
Laurent@2157:         self.Entries = entries
andrej@2355: 
Laurent@2162:     def AddEntry(self, context, *args):
Laurent@2162:         index, subindex = map(lambda x: int(x[0]), args[:2])
edouard@2641:         if len(args) > 9:
edouard@2641: 		    new_entry_infos = {
Laurent@2162:             key: translate(arg[0]) if len(arg) > 0 else default
Laurent@2162:             for (key, translate, default), arg
Laurent@2162:             in zip(ENTRY_INFOS_KEYS, args)}
edouard@2641:         else:
edouard@2641:             new_entry_infos = {
edouard@2641:             key: translate(arg[0]) if len(arg) > 0 else default
edouard@2641:             for (key, translate, default), arg
edouard@2641:             in zip(ENTRY_INFOS_KEYS_FOR_DV, args)}			
edouard@2641: 			
Laurent@2157:         if (index, subindex) != (0, 0):
Laurent@2157:             entry_infos = self.Entries.get((index, subindex))
Laurent@2157:             if entry_infos is not None:
Laurent@2162:                 for param in ["PDO index", "PDO name", "PDO type"]:
Laurent@2162:                     value = new_entry_infos.get(param)
Laurent@2162:                     if value is not None:
Laurent@2162:                         entry_infos[param] = value
Laurent@2157:             else:
Laurent@2157:                 self.Entries[(index, subindex)] = new_entry_infos
Laurent@2157: 
andrej@2370: 
Laurent@2157: entries_list_xslt = etree.parse(
Laurent@2157:     os.path.join(ScriptDirectory, "entries_list.xslt"))
Laurent@2157: 
Laurent@2157: cls = EtherCATInfoParser.GetElementClass("DeviceType")
Laurent@2074: if cls:
edouard@2641:     cls.DataTypes = None
Laurent@2157:     
Laurent@2157:     profile_numbers_xpath = EtherCATInfo_XPath("Profile/ProfileNo")
andrej@2387: 
laurent@2032:     def GetProfileNumbers(self):
Laurent@2157:         return [number.text for number in profile_numbers_xpath(self)]
laurent@2032:     setattr(cls, "GetProfileNumbers", GetProfileNumbers)
andrej@2355: 
Laurent@2079:     def getCoE(self):
laurent@2032:         mailbox = self.getMailbox()
Laurent@2079:         if mailbox is not None:
Laurent@2079:             return mailbox.getCoE()
Laurent@2079:         return None
Laurent@2079:     setattr(cls, "getCoE", getCoE)
laurent@2032: 
edouard@2641:     # Modify by jblee
edouard@2641:     def ExtractDataTypes(self):
edouard@2641:         #self.DataTypes = {}
edouard@2641:         #self.DT = {}
edouard@2641:         DT = {}
edouard@2641:         objects = []
edouard@2641: 
edouard@2641:         # get Profile Field
edouard@2641:         for profile in self.getProfile():
edouard@2641:             # get each (ProfileNo, Dictionary) Field as child
edouard@2641:             for child in profile.getchildren():
edouard@2641:                 # child.text is not None -> ProfileNo, is None -> Dictionary
edouard@2641:                 if child.text is None:
edouard@2641:                     # get each (DataTypes, Objects) Field 
edouard@2641:                     dataTypes = child.getDataTypes()
edouard@2641:                     objects = child.getObjects()
edouard@2641:                                 
edouard@2641:                     for dataType in dataTypes.getDataType():
edouard@2641:                         #if dataType.getName() is not None:
edouard@2641:                         #    print dataType.getName(), dataType
edouard@2641:                         DT[dataType.getName()] = dataType
edouard@2641: 
edouard@2641:         return DT, objects
edouard@2641:     setattr(cls, "ExtractDataTypes", ExtractDataTypes)
edouard@2641: 
Laurent@2098:     def GetEntriesList(self, limits=None):
edouard@2641:         DataTypes, objects = self.ExtractDataTypes()
edouard@2641: 
laurent@2029:         entries = {}
edouard@2641: 
edouard@2641:         # get each Object Field
edouard@2641:         for object in objects:
edouard@2641:             # Object Field mendatory : Index, Name, Type, BitSize
edouard@2641:             # Frequently Use : Info, Flags
edouard@2641:             # Info Field -> DefaultData, SubItem
edouard@2641:             # Flags Field -> Access, Category, PdoMapping
edouard@2641:             object_index = object.getIndex().getcontent()
edouard@2641:             index = ExtractHexDecValue(object_index)
edouard@2641:             if limits is None or limits[0] <= index <= limits[1]:
edouard@2641:                 object_type = object.getType()
edouard@2641:                 object_name = ExtractName(object.getName())
edouard@2641:                 object_size = object.getBitSize()
edouard@2641:                 defaultData = ""
edouard@2641:                 object_access = ""
edouard@2641:                 object_PDOMapping_data = ""
edouard@2641: 
edouard@2641:                 object_type_infos = DataTypes.get(object_type, None)
edouard@2641:                 subItem_infos = object_type_infos.getchildren()
edouard@2641:                 countSubIndex = 0
edouard@2641:                 if len(subItem_infos) > 2:
edouard@2641:                     for subItem_info in subItem_infos:
edouard@2641:                         if subItem_info.tag == "SubItem" : 
edouard@2641:                             subItemName = subItem_info.getName()
edouard@2641:                             subIdx = subItem_info.getSubIdx()
edouard@2641:                             if subIdx is not None:
edouard@2641:                                 object_subidx = ExtractHexDecValue(subIdx)
edouard@2641:                             else:
edouard@2641:                                 object_subidx = ExtractHexDecValue(countSubIndex)
edouard@2641:                             subType = subItem_info.getType()
edouard@2641:                             subBitSize = subItem_info.getBitSize()
edouard@2641:                             subFlags = subItem_info.getFlags()
edouard@2641:                             subAccess = ""
edouard@2641:                             subPDOMapping_data = ""
edouard@2641:                             if subFlags is not None:
edouard@2641:                                 subAccess = subFlags.getAccess().getcontent()
edouard@2641:                                 subPDOMapping = subFlags.getPdoMapping()                                                        
edouard@2641:                                 if subPDOMapping is not None:
edouard@2641:                                     subPDOMapping_data = subFlags.getPdoMapping().upper()
edouard@2641: 
edouard@2641:                             entries[(index, object_subidx)] = {
edouard@2641:                                 "Index": object_index,
edouard@2641:                                 "SubIndex": subIdx,
edouard@2641:                                 "Name": "%s - %s" % 
edouard@2641:                                     (object_name.decode("utf-8"),
edouard@2641:                                      subItemName.decode("utf-8")),
edouard@2641:                                 "Type": subType,
edouard@2641:                                 "BitSize": subBitSize,
edouard@2641:                                 "Access": subAccess, 
edouard@2641:                                 "PDOMapping": subPDOMapping_data}
edouard@2641: 
edouard@2641:                             countSubIndex += 1
edouard@2641: 
edouard@2641:                     info = object.getInfo()
edouard@2641:                     # subItemTest : check subItem 
edouard@2641:                     countSubIndex = 0
edouard@2641:                     if info is not None:
edouard@2641:                         subItems = info.getchildren()
edouard@2641:                         if len(subItems) > 1:
edouard@2641:                             for subItem in subItems:
edouard@2641:                                 defaultdata_subidx = ExtractHexDecValue(countSubIndex)
edouard@2641:                                 defaultData = subItem.getchildren()[1].findtext("DefaultData")
edouard@2641:                                 entry = entries.get((index, defaultdata_subidx), None)
edouard@2641:                                 if entry is not None:
edouard@2641:                                     entry["DefaultData"] = defaultData
edouard@2641:                                 countSubIndex += 1
edouard@2641: 
edouard@2641:                 else :
edouard@2641:                     info = object.getInfo()
edouard@2641:                     if info is not None:
edouard@2641:                         subItems = info.getchildren()
edouard@2641:                         if len(subItems) <= 1:
edouard@2641:                             defaultData = subItems[0].text
edouard@2641:                                 
edouard@2641:                     object_flag = object.getFlags()
edouard@2641:                     object_access = object_flag.getAccess().getcontent()
edouard@2641:                     object_PDOMapping = object_flag.getPdoMapping()
edouard@2641:                     if object_PDOMapping is not None:
edouard@2641:                         object_PDOMapping_data = object_flag.getPdoMapping().upper()
edouard@2641:                     entries[(index, 0)] = {
edouard@2641:                         "Index": object_index,
edouard@2641:                         "SubIndex": "0",
edouard@2641:                         "Name": object_name,                                                               
edouard@2641:                         "Type": object_type,
edouard@2641:                         "BitSize": object_size,
edouard@2641:                         "DefaultData" : defaultData,
edouard@2641:                         "Access": object_access, 
edouard@2641:                         "PDOMapping": object_PDOMapping_data}
edouard@2641: 
edouard@2641:         for TxPdo in self.getTxPdo():
edouard@2641:             ExtractPdoInfos(TxPdo, "Transmit", entries, limits)
edouard@2641:         for RxPdo in self.getRxPdo():
edouard@2641:             ExtractPdoInfos(RxPdo, "Receive", entries, limits)
laurent@2029:         
laurent@2029:         return entries
laurent@2029:     setattr(cls, "GetEntriesList", GetEntriesList)
Laurent@2157: 
edouard@2641: #    def GetEntriesList(self, limits=None):
edouard@2641: #        entries = {}
edouard@2641:         
edouard@2641: #        factory = EntryListFactory(entries)
edouard@2641:         
edouard@2641: #        entries_list_xslt_tree = etree.XSLT(
edouard@2641: #            entries_list_xslt, extensions = {
edouard@2641: #                ("entries_list_ns", "AddEntry"): factory.AddEntry,
edouard@2641: #                ("entries_list_ns", "HexDecValue"): HexDecValue,
edouard@2641: #                ("entries_list_ns", "EntryName"): EntryName})
edouard@2641: #        entries_list_xslt_tree(self, **dict(zip(
edouard@2641: #            ["min_index", "max_index"], 
edouard@2641: #            map(lambda x: etree.XSLT.strparam(str(x)),
edouard@2641: #                limits if limits is not None else [0x0000, 0xFFFF])
edouard@2641: #            )))
edouard@2641: #        
edouard@2641: #        return entries
edouard@2641: #    setattr(cls, "GetEntriesList", GetEntriesList)
edouard@2641: 
laurent@2029:     def GetSyncManagers(self):
laurent@2029:         sync_managers = []
laurent@2029:         for sync_manager in self.getSm():
laurent@2029:             sync_manager_infos = {}
laurent@2029:             for name, value in [("Name", sync_manager.getcontent()),
laurent@2029:                                 ("Start Address", sync_manager.getStartAddress()),
laurent@2029:                                 ("Default Size", sync_manager.getDefaultSize()),
laurent@2029:                                 ("Control Byte", sync_manager.getControlByte()),
laurent@2029:                                 ("Enable", sync_manager.getEnable())]:
laurent@2029:                 if value is None:
andrej@2365:                     value = ""
laurent@2029:                 sync_manager_infos[name] = value
laurent@2029:             sync_managers.append(sync_manager_infos)
laurent@2029:         return sync_managers
laurent@2029:     setattr(cls, "GetSyncManagers", GetSyncManagers)
laurent@2029: 
edouard@2641: 
laurent@2022: def GroupItemCompare(x, y):
laurent@2022:     if x["type"] == y["type"]:
laurent@2022:         if x["type"] == ETHERCAT_GROUP:
laurent@2031:             return cmp(x["order"], y["order"])
laurent@2022:         else:
laurent@2031:             return cmp(x["name"], y["name"])
laurent@2022:     elif x["type"] == ETHERCAT_GROUP:
laurent@2022:         return -1
laurent@2022:     return 1
laurent@2022: 
andrej@2360: 
laurent@2022: def SortGroupItems(group):
laurent@2022:     for item in group["children"]:
laurent@2022:         if item["type"] == ETHERCAT_GROUP:
laurent@2022:             SortGroupItems(item)
laurent@2022:     group["children"].sort(GroupItemCompare)
laurent@2022: 
edouard@2641: def ExtractPdoInfos(pdo, pdo_type, entries, limits=None):
edouard@2641:     pdo_index = pdo.getIndex().getcontent()
edouard@2641:     pdo_name = ExtractName(pdo.getName())
edouard@2641:     exclude = pdo.getExclude()
edouard@2641:     for pdo_entry in pdo.getEntry():
edouard@2641:         entry_index = pdo_entry.getIndex().getcontent()
edouard@2641:         entry_subindex = pdo_entry.getSubIndex()
edouard@2641:         index = ExtractHexDecValue(entry_index)
edouard@2641:         subindex = ExtractHexDecValue(entry_subindex)
edouard@2641:         object_size = pdo_entry.getBitLen()
edouard@2641: 
edouard@2641:         if limits is None or limits[0] <= index <= limits[1]:
edouard@2641:             entry = entries.get((index, subindex), None)
edouard@2641:             if entry is not None:
edouard@2641:                 entry["PDO index"] = pdo_index
edouard@2641:                 entry["PDO name"] = pdo_name
edouard@2641:                 entry["PDO type"] = pdo_type
edouard@2641:             else:
edouard@2641:                 entry_type = pdo_entry.getDataType()
edouard@2641:                 if entry_type is not None:
edouard@2641:                     if pdo_type == "Transmit":
edouard@2641:                         access = "ro"
edouard@2641:                         pdomapping = "T"
edouard@2641:                     else:
edouard@2641:                         access = "wo"
edouard@2641:                         pdomapping = "R"
edouard@2641:                     entries[(index, subindex)] = {
edouard@2641:                         "Index": entry_index,
edouard@2641:                         "SubIndex": entry_subindex,
edouard@2641:                         "Name": ExtractName(pdo_entry.getName()),
edouard@2641:                         "Type": entry_type.getcontent(),
edouard@2641:                         "BitSize": object_size,
edouard@2641:                         "Access": access,
edouard@2641:                         "PDOMapping": pdomapping}
edouard@2641: 
andrej@2397: class ModulesLibrary(object):
Laurent@2137: 
Laurent@2137:     MODULES_EXTRA_PARAMS = [
andrej@2384:         (
andrej@2384:             "pdo_alignment",
andrej@2384:             {
andrej@2384:                 "column_label": _("PDO alignment"),
andrej@2384:                 "column_size": 150,
andrej@2384:                 "default": 8,
andrej@2384:                 "description": _("Minimal size in bits between 2 pdo entries")
andrej@2384:             }
andrej@2384:         ),
andrej@2384:         (
andrej@2384:             "max_pdo_size",
andrej@2384:             {
andrej@2384:                 "column_label": _("Max entries by PDO"),
andrej@2384:                 "column_size": 150,
andrej@2384:                 "default": 255,
andrej@2384:                 "description": _("""Maximal number of entries mapped in a PDO
andrej@2384: including empty entries used for PDO alignment""")
andrej@2384:             }
andrej@2384:         ),
andrej@2384:         (
andrej@2384:             "add_pdo",
andrej@2384:             {
andrej@2384:                 "column_label": _("Creating new PDO"),
andrej@2384:                 "column_size": 150,
andrej@2384:                 "default": 0,
andrej@2384:                 "description": _("""Adding a PDO not defined in default configuration
Laurent@2138: for mapping needed location variables
andrej@2384: (1 if possible)""")
andrej@2384:             }
andrej@2384:         )
Laurent@2137:     ]
andrej@2355: 
Laurent@2097:     def __init__(self, path, parent_library=None):
Laurent@2097:         self.Path = path
Laurent@2097:         if not os.path.exists(self.Path):
Laurent@2097:             os.makedirs(self.Path)
Laurent@2097:         self.ParentLibrary = parent_library
andrej@2355: 
Laurent@2098:         if parent_library is not None:
Laurent@2098:             self.LoadModules()
Laurent@2098:         else:
Laurent@2098:             self.Library = None
Laurent@2137:         self.LoadModulesExtraParams()
edouard@2641: 
Laurent@2097:     def GetPath(self):
Laurent@2097:         return self.Path
andrej@2355: 
Laurent@2137:     def GetModulesExtraParamsFilePath(self):
Laurent@2137:         return os.path.join(self.Path, "modules_extra_params.cfg")
andrej@2355: 
Laurent@2157:     groups_xpath = EtherCATInfo_XPath("Descriptions/Groups/Group")
Laurent@2157:     devices_xpath = EtherCATInfo_XPath("Descriptions/Devices/Device")
edouard@2641:     module_xpath = EtherCATBase_XPath("Descriptions/Modules/Module")
edouard@2641: 
Laurent@2097:     def LoadModules(self):
Laurent@2097:         self.Library = {}
edouard@2641:         # add by jblee for Modular Device Profile
edouard@2641:         self.MDPList = []
edouard@2641:         self.ModuleList = []
edouard@2641:         self.MDPEntryList = {}
edouard@2641:         dtDic = {}
edouard@2641:         self.idxIncrement = 0
edouard@2641:         self.slotIncrement = 0
edouard@2641:         # add by jblee for PDO Mapping
edouard@2641:         self.DataTypes = {}
edouard@2641:         self.ObjectDictionary = {}
Laurent@2097:         
Laurent@2097:         files = os.listdir(self.Path)
laurent@2022:         for file in files:
Laurent@2097:             filepath = os.path.join(self.Path, file)
laurent@2022:             if os.path.isfile(filepath) and os.path.splitext(filepath)[-1] == ".xml":
Laurent@2157:                 self.modules_infos = None
andrej@2355: 
laurent@2022:                 xmlfile = open(filepath, 'r')
Laurent@2157:                 try:
Laurent@2160:                     self.modules_infos, error = EtherCATInfoParser.LoadXMLString(xmlfile.read())
edouard@2643:                     # if error is not None:
edouard@2643:                     #     self.GetCTRoot().logger.write_warning(
edouard@2643:                     #         XSDSchemaErrorMessage % (filepath + error))
andrej@2418:                 except Exception as exc:
andrej@2434:                     self.modules_infos, error = None, text(exc)
laurent@2022:                 xmlfile.close()
edouard@2641: 
Edouard@2152:                 if self.modules_infos is not None:
Edouard@2152:                     vendor = self.modules_infos.getVendor()
andrej@2355: 
Laurent@2157:                     vendor_category = self.Library.setdefault(
andrej@2355:                         ExtractHexDecValue(vendor.getId()),
andrej@2355:                         {"name": ExtractName(vendor.getName(), _("Miscellaneous")),
Laurent@2157:                          "groups": {}})
andrej@2355: 
Laurent@2157:                     for group in self.groups_xpath(self.modules_infos):
laurent@2022:                         group_type = group.getType()
edouard@2641:                         # add for XmlToEeprom Func by jblee.
edouard@2641:                         self.LcId_data = group.getchildren()[1]
edouard@2641:                         self.Image16x14_data = group.getchildren()[2]
andrej@2355: 
andrej@2381:                         vendor_category["groups"].setdefault(
andrej@2381:                             group_type,
andrej@2381:                             {
andrej@2381:                                 "name": ExtractName(group.getName(), group_type),
andrej@2381:                                 "parent": group.getParentGroup(),
andrej@2381:                                 "order": group.getSortOrder(),
andrej@2381:                                 "devices": [],
edouard@2643:                                 # add jblee for support Moduler Device Profile (MDP)
edouard@2643:                                 "modules": []})
andrej@2381:                             })
andrej@2359: 
Laurent@2157:                     for device in self.devices_xpath(self.modules_infos):
laurent@2022:                         device_group = device.getGroupType()
andrej@2377:                         if device_group not in vendor_category["groups"]:
andrej@2412:                             raise ValueError("Not such group \"%s\"" % device_group)
Laurent@2157:                         vendor_category["groups"][device_group]["devices"].append(
Laurent@2157:                             (device.getType().getcontent(), device))
edouard@2641: 
edouard@2641:                         # ------------------ Test Section --------------------#
edouard@2641:                         slots = device.getSlots()
edouard@2641:                         if slots is not None:
edouard@2641:                             for slot in slots.getSlot():
edouard@2641:                                 self.idxIncrement = slot.getSlotIndexIncrement()
edouard@2641:                                 self.slotIncrement = slot.getSlotPdoIncrement()
edouard@2641:                                 for child in slot.getchildren():
edouard@2641:                                     if child.tag == "ModuleClass":
edouard@2641:                                         child_class = child.getClass()
edouard@2641:                                         child_name = child.getName()
edouard@2641: 
edouard@2641:                     # -------------------- Test Section ----------------------------------# 
edouard@2641:                         LocalMDPList = []
edouard@2641:                         for module in self.module_xpath(self.modules_infos):
edouard@2641:                             module_type = module.getType().getModuleClass()
edouard@2641:                             module_name = module.getName()
edouard@2641:                             LocalMDPData = ExtractName(module_name) + " (" + module_type + ")"
edouard@2641:                             
edouard@2641:                             self.ModuleList.append(module)
edouard@2641:                             try :
edouard@2641:                                 module_pdos = module.getTxPdo()
edouard@2641:                                 module_pdos += module.getRxPdo()
edouard@2641:                                 for module_pdo in module_pdos:
edouard@2641:                                     device_name = ExtractName(module_name)
edouard@2641:                                     pdo_index = module_pdo.getIndex().getcontent()
edouard@2641:                                     pdo_name = ExtractName(module_pdo.getName())
edouard@2641:                                     pdo_entry = module_pdo.getEntry()
edouard@2641:                                     if module_pdo.tag == "TxPdo":
edouard@2641:                                         mapping_type = "T"
edouard@2641:                                     else :
edouard@2641:                                         mapping_type = "R"
edouard@2641: 
edouard@2641:                                     LocalMDPEntry = []
edouard@2641:                                     for entry in pdo_entry:
edouard@2641:                                         entry_index = entry.getIndex().getcontent()
edouard@2641:                                         entry_subidx = entry.getSubIndex()
edouard@2641:                                         entry_name = ExtractName(entry.getName())
edouard@2641:                                         entry_bitsize = entry.getBitLen()
edouard@2641:                                         try :
edouard@2641:                                            entry_type = entry.getDataType().getcontent()
edouard@2641:                                         except :
edouard@2641:                                            entry_type = ""
edouard@2641: 
edouard@2641:                                         LocalMDPEntry.append({
edouard@2641:                                             "Index": entry_index,
edouard@2641:                                             "SubIndex": entry_subidx,
edouard@2641:                                             "Name": "%s - %s" % (pdo_name, entry_name),
edouard@2641:                                             "Type": entry_type,
edouard@2641:                                             "BitSize": entry_bitsize,
edouard@2641:                                             "Access": "", 
edouard@2641:                                             "PDOMapping": mapping_type})
edouard@2641:                                 
edouard@2641:                                     self.MDPEntryList[device_name] = LocalMDPEntry
edouard@2641: 
edouard@2641:                                 LocalMDPList.append([LocalMDPData, module, LocalMDPEntry])
edouard@2641:                             except :
edouard@2641:                                 LocalMDPList.append([LocalMDPData, module, []])
edouard@2641:                            
edouard@2641:                         if LocalMDPList:
edouard@2641:                             vendor_category["groups"][device_group]["modules"].append(
edouard@2641:                                 (device.getType().getcontent(), LocalMDPList, self.idxIncrement, self.slotIncrement))
edouard@2641:                             #self.MDPList.append([device.getType().getcontent(), LocalMDPList,
edouard@2641:                             #                     self.idxIncrement, self.slotIncrement])
edouard@2641: 
edouard@2641:                     # --------------------------------------------------------------------- #
edouard@2641: 
edouard@2643:                 # else:
edouard@2643:                 #     self.GetCTRoot().logger.write_error(
edouard@2643:                 #         _("Couldn't load {a1} XML file:\n{a2}").format(a1=filepath, a2=error))
andrej@2355: 
Laurent@2160:         return self.Library
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetMDPList(self):
edouard@2641:         return self.MDPList
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetSelectModule(self, idx):
edouard@2641:         return self.ModuleList[idx]
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetModuleEntryList(self):
edouard@2641:         return self.MDPEntryList
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetModuleIncrement(self):
edouard@2641:         return (self.idxIncrement, self.slotIncrement)
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     #def GetEntriesList(self):
edouard@2641:     #    return self.ObjectDictionary
edouard@2641:     
laurent@2041:     def GetModulesLibrary(self, profile_filter=None):
Laurent@2098:         if self.Library is None:
Laurent@2098:             self.LoadModules()
laurent@2022:         library = []
Laurent@2097:         for vendor_id, vendor in self.Library.iteritems():
laurent@2022:             groups = []
Laurent@2073:             children_dict = {}
laurent@2022:             for group_type, group in vendor["groups"].iteritems():
laurent@2022:                 group_infos = {"name": group["name"],
laurent@2022:                                "order": group["order"],
laurent@2022:                                "type": ETHERCAT_GROUP,
laurent@2041:                                "infos": None,
laurent@2022:                                "children": children_dict.setdefault(group_type, [])}
laurent@2022:                 device_dict = {}
laurent@2022:                 for device_type, device in group["devices"]:
laurent@2041:                     if profile_filter is None or profile_filter in device.GetProfileNumbers():
Laurent@2097:                         product_code = device.getType().getProductCode()
Laurent@2097:                         revision_number = device.getType().getRevisionNo()
Laurent@2137:                         module_infos = {"device_type": device_type,
Laurent@2137:                                         "vendor": vendor_id,
Laurent@2137:                                         "product_code": product_code,
Laurent@2137:                                         "revision_number": revision_number}
Laurent@2137:                         module_infos.update(self.GetModuleExtraParams(vendor_id, product_code, revision_number))
laurent@2041:                         device_infos = {"name": ExtractName(device.getName()),
laurent@2041:                                         "type": ETHERCAT_DEVICE,
Laurent@2137:                                         "infos": module_infos,
laurent@2041:                                         "children": []}
laurent@2041:                         group_infos["children"].append(device_infos)
laurent@2041:                         device_type_occurrences = device_dict.setdefault(device_type, [])
laurent@2041:                         device_type_occurrences.append(device_infos)
laurent@2022:                 for device_type_occurrences in device_dict.itervalues():
laurent@2022:                     if len(device_type_occurrences) > 1:
laurent@2022:                         for occurrence in device_type_occurrences:
laurent@2022:                             occurrence["name"] += _(" (rev. %s)") % occurrence["infos"]["revision_number"]
laurent@2041:                 if len(group_infos["children"]) > 0:
laurent@2041:                     if group["parent"] is not None:
laurent@2041:                         parent_children = children_dict.setdefault(group["parent"], [])
laurent@2041:                         parent_children.append(group_infos)
laurent@2041:                     else:
laurent@2041:                         groups.append(group_infos)
laurent@2041:             if len(groups) > 0:
laurent@2041:                 library.append({"name": vendor["name"],
laurent@2041:                                 "type": ETHERCAT_VENDOR,
laurent@2041:                                 "infos": None,
laurent@2041:                                 "children": groups})
laurent@2031:         library.sort(lambda x, y: cmp(x["name"], y["name"]))
laurent@2022:         return library
Laurent@2097: 
Laurent@2098:     def GetVendors(self):
Laurent@2098:         return [(vendor_id, vendor["name"]) for vendor_id, vendor in self.Library.items()]
andrej@2355: 
Laurent@2097:     def GetModuleInfos(self, module_infos):
Laurent@2097:         vendor = ExtractHexDecValue(module_infos["vendor"])
Laurent@2097:         vendor_infos = self.Library.get(vendor)
Laurent@2097:         if vendor_infos is not None:
andrej@2406:             for _group_name, group_infos in vendor_infos["groups"].iteritems():
Laurent@2097:                 for device_type, device_infos in group_infos["devices"]:
Laurent@2097:                     product_code = ExtractHexDecValue(device_infos.getType().getProductCode())
Laurent@2097:                     revision_number = ExtractHexDecValue(device_infos.getType().getRevisionNo())
andrej@2379:                     if product_code == ExtractHexDecValue(module_infos["product_code"]) and \
andrej@2379:                        revision_number == ExtractHexDecValue(module_infos["revision_number"]):
andrej@2355:                         self.cntdevice = device_infos
andrej@2355:                         self.cntdeviceType = device_type
Laurent@2137:                         return device_infos, self.GetModuleExtraParams(vendor, product_code, revision_number)
Laurent@2097:         return None, None
edouard@2641: 
edouard@2641:     # add jblee for MDP
edouard@2641:     def GetMDPInfos(self, module_infos):
edouard@2641:         vendor = ExtractHexDecValue(module_infos["vendor"])
edouard@2641:         vendor_infos = self.Library.get(vendor)
edouard@2641:         if vendor_infos is not None:
edouard@2641:             for group_name, group_infos in vendor_infos["groups"].iteritems():
edouard@2641:                 return group_infos["modules"]
edouard@2641:                 #for device_type, module_list, idx_inc, slot_inc in group_infos["modules"]:
edouard@2641:                 #    return module_list, idx_inc, slot_inc
edouard@2641: 
edouard@2641:         #return None, None, None
Laurent@2097:     
Laurent@2097:     def ImportModuleLibrary(self, filepath):
Laurent@2097:         if os.path.isfile(filepath):
Laurent@2097:             shutil.copy(filepath, self.Path)
Laurent@2097:             self.LoadModules()
Laurent@2097:             return True
Laurent@2097:         return False
andrej@2355: 
Laurent@2137:     def LoadModulesExtraParams(self):
Laurent@2137:         self.ModulesExtraParams = {}
andrej@2355: 
Laurent@2137:         csvfile_path = self.GetModulesExtraParamsFilePath()
Laurent@2097:         if os.path.exists(csvfile_path):
Laurent@2097:             csvfile = open(csvfile_path, "rb")
Laurent@2097:             sample = csvfile.read(1024)
Laurent@2097:             csvfile.seek(0)
Laurent@2097:             dialect = csv.Sniffer().sniff(sample)
Laurent@2097:             has_header = csv.Sniffer().has_header(sample)
Laurent@2097:             reader = csv.reader(csvfile, dialect)
Laurent@2097:             for row in reader:
Laurent@2097:                 if has_header:
Laurent@2097:                     has_header = False
Laurent@2097:                 else:
Laurent@2138:                     params_values = {}
andrej@2406:                     for (param, _param_infos), value in zip(
andrej@2379:                             self.MODULES_EXTRA_PARAMS, row[3:]):
Laurent@2138:                         if value != "":
Laurent@2138:                             params_values[param] = int(value)
Laurent@2138:                     self.ModulesExtraParams[
Laurent@2138:                         tuple(map(int, row[:3]))] = params_values
Laurent@2097:             csvfile.close()
andrej@2355: 
Laurent@2137:     def SaveModulesExtraParams(self):
Laurent@2137:         csvfile = open(self.GetModulesExtraParamsFilePath(), "wb")
andrej@2406:         extra_params = [param for param, _params_infos in self.MODULES_EXTRA_PARAMS]
Laurent@2097:         writer = csv.writer(csvfile, delimiter=';')
Laurent@2137:         writer.writerow(['Vendor', 'product_code', 'revision_number'] + extra_params)
Laurent@2137:         for (vendor, product_code, revision_number), module_extra_params in self.ModulesExtraParams.iteritems():
andrej@2355:             writer.writerow([vendor, product_code, revision_number] +
andrej@2355:                             [module_extra_params.get(param, '')
Laurent@2137:                              for param in extra_params])
Laurent@2097:         csvfile.close()
andrej@2355: 
Laurent@2137:     def SetModuleExtraParam(self, vendor, product_code, revision_number, param, value):
Laurent@2097:         vendor = ExtractHexDecValue(vendor)
Laurent@2097:         product_code = ExtractHexDecValue(product_code)
Laurent@2097:         revision_number = ExtractHexDecValue(revision_number)
andrej@2355: 
Laurent@2138:         module_infos = (vendor, product_code, revision_number)
Laurent@2138:         self.ModulesExtraParams.setdefault(module_infos, {})
Laurent@2138:         self.ModulesExtraParams[module_infos][param] = value
andrej@2355: 
Laurent@2137:         self.SaveModulesExtraParams()
andrej@2355: 
Laurent@2137:     def GetModuleExtraParams(self, vendor, product_code, revision_number):
Laurent@2097:         vendor = ExtractHexDecValue(vendor)
Laurent@2097:         product_code = ExtractHexDecValue(product_code)
Laurent@2097:         revision_number = ExtractHexDecValue(revision_number)
andrej@2355: 
Laurent@2097:         if self.ParentLibrary is not None:
Laurent@2137:             extra_params = self.ParentLibrary.GetModuleExtraParams(vendor, product_code, revision_number)
Laurent@2137:         else:
Laurent@2137:             extra_params = {}
andrej@2355: 
Laurent@2138:         extra_params.update(self.ModulesExtraParams.get((vendor, product_code, revision_number), {}))
andrej@2355: 
Laurent@2137:         for param, param_infos in self.MODULES_EXTRA_PARAMS:
Laurent@2137:             extra_params.setdefault(param, param_infos["default"])
andrej@2355: 
Laurent@2137:         return extra_params
Laurent@2097: 
andrej@2370: 
Laurent@2097: USERDATA_DIR = wx.StandardPaths.Get().GetUserDataDir()
Laurent@2097: if wx.Platform != '__WXMSW__':
Laurent@2097:     USERDATA_DIR += '_files'
Laurent@2097: 
Laurent@2097: ModulesDatabase = ModulesLibrary(
Laurent@2097:     os.path.join(USERDATA_DIR, "ethercat_modules"))
Laurent@2097: 
andrej@2360: 
andrej@2397: class RootClass(object):
andrej@2355: 
andrej@2363:     CTNChildrenTypes = [("EthercatNode", _EthercatCTN, "Ethercat Master")]
Laurent@2097:     EditorType = LibraryEditor
andrej@2355: 
Laurent@2097:     def __init__(self):
Laurent@2097:         self.ModulesLibrary = None
Laurent@2097:         self.LoadModulesLibrary()
andrej@2355: 
Laurent@2149:     def GetIconName(self):
Laurent@2149:         return "Ethercat"
andrej@2355: 
Laurent@2133:     def GetModulesLibraryPath(self, project_path=None):
Laurent@2133:         if project_path is None:
Laurent@2133:             project_path = self.CTNPath()
andrej@2355:         return os.path.join(project_path, "modules")
andrej@2355: 
Laurent@2133:     def OnCTNSave(self, from_project_path=None):
Laurent@2133:         if from_project_path is not None:
Laurent@2133:             shutil.copytree(self.GetModulesLibraryPath(from_project_path),
Laurent@2133:                             self.GetModulesLibraryPath())
Laurent@2133:         return True
andrej@2355: 
Laurent@2097:     def CTNGenerate_C(self, buildpath, locations):
andrej@2363:         return [], "", False
andrej@2355: 
Laurent@2097:     def LoadModulesLibrary(self):
Laurent@2097:         if self.ModulesLibrary is None:
Laurent@2097:             self.ModulesLibrary = ModulesLibrary(self.GetModulesLibraryPath(), ModulesDatabase)
Laurent@2097:         else:
Laurent@2097:             self.ModulesLibrary.LoadModulesLibrary()
andrej@2355: 
Laurent@2097:     def GetModulesDatabaseInstance(self):
Laurent@2097:         return ModulesDatabase
andrej@2355: 
Laurent@2097:     def GetModulesLibraryInstance(self):
Laurent@2097:         return self.ModulesLibrary
andrej@2355: 
Laurent@2097:     def GetModulesLibrary(self, profile_filter=None):
Laurent@2097:         return self.ModulesLibrary.GetModulesLibrary(profile_filter)
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetMDPList(self):
edouard@2641:         return self.ModulesLibrary.GetMDPList()
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetSelectModule(self, idx):
edouard@2641:         return self.ModulesLibrary.GetSelectModule(idx)
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetModuleEntryList(self):
edouard@2641:         return self.ModulesLibrary.GetModuleEntryList()
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     def GetModuleIncrement(self):
edouard@2641:         return self.ModulesLibrary.GetModuleIncrement()
edouard@2641: 
edouard@2641:     # add jblee
edouard@2641:     #def GetEntriesList(self, limits = None):
edouard@2641:     #    return self.ModulesLibrary.GetEntriesList()
edouard@2641: 
Laurent@2098:     def GetVendors(self):
Laurent@2098:         return self.ModulesLibrary.GetVendors()
andrej@2355: 
Laurent@2097:     def GetModuleInfos(self, module_infos):
Laurent@2097:         return self.ModulesLibrary.GetModuleInfos(module_infos)
laurent@2041: 
edouard@2641:     def GetMDPInfos(self, module_infos):
edouard@2641:         return self.ModulesLibrary.GetMDPInfos(module_infos)