diff -r 1b4b335e19ea -r b98d9e08231f etherlab/etherlab.py --- a/etherlab/etherlab.py Wed Nov 13 11:21:04 2019 +0100 +++ b/etherlab/etherlab.py Mon Nov 25 08:10:45 2019 +0100 @@ -39,6 +39,13 @@ return etree.XPath(xpath) +EtherCATBaseParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATBase.xsd")) + + +def EtherCATBase_XPath(xpath): + return etree.XPath(xpath) + + def HexDecValue(context, *args): return str(ExtractHexDecValue(args[0][0])) @@ -59,6 +66,18 @@ ("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(object): @@ -67,11 +86,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: @@ -88,7 +113,8 @@ cls = EtherCATInfoParser.GetElementClass("DeviceType") if cls: - + cls.DataTypes = None + profile_numbers_xpath = EtherCATInfo_XPath("Profile/ProfileNo") def GetProfileNumbers(self): @@ -102,25 +128,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(): @@ -155,6 +307,40 @@ 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} class ModulesLibrary(object): @@ -211,10 +397,21 @@ 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: filepath = os.path.join(self.Path, file) @@ -224,9 +421,9 @@ 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 as exc: self.modules_infos, error = None, text(exc) xmlfile.close() @@ -241,6 +438,9 @@ 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, @@ -248,8 +448,9 @@ "name": ExtractName(group.getName(), group_type), "parent": group.getParentGroup(), "order": group.getSortOrder(), - # "value": group.getcontent()["value"], "devices": [], + # add jblee for support Moduler Device Profile (MDP) + "modules": []}) }) for device in self.devices_xpath(self.modules_infos): @@ -259,13 +460,98 @@ vendor_category["groups"][device_group]["devices"].append( (device.getType().getcontent(), device)) - else: - - self.GetCTRoot().logger.write_error( - _("Couldn't load {a1} XML file:\n{a2}").format(a1=filepath, a2=error)) + # ------------------ 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 {a1} XML file:\n{a2}").format(a1=filepath, a2=error)) return self.Library + # 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() @@ -332,6 +618,18 @@ 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): shutil.copy(filepath, self.Path) @@ -452,8 +750,31 @@ 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)