diff -r c9b0340ea0f5 -r 58d07e039896 etherlab/etherlab.py --- a/etherlab/etherlab.py Thu Feb 07 00:59:50 2013 +0100 +++ b/etherlab/etherlab.py Wed Feb 27 22:40:45 2013 +0100 @@ -3,12 +3,13 @@ from xml.dom import minidom import wx +import csv from xmlclass import * from POULibrary import POULibrary from ConfigTreeNode import ConfigTreeNode from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY -from ConfigEditor import NodeEditor, CIA402NodeEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE +from ConfigEditor import NodeEditor, CIA402NodeEditor, LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE try: from MotionLibrary import Headers, AxisXSD @@ -571,7 +572,7 @@ "product_code": slave["product_code"], "revision_number":slave["revision_number"], } - device = self.GetModuleInfos(type_infos) + device, alignment = self.GetModuleInfos(type_infos) if device is not None: if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): CTNType = "EthercatCIA402Slave" @@ -651,7 +652,7 @@ slave = self.GetSlave(slave_pos) if slave is not None: type_infos = slave.getType() - device = self.GetModuleInfos(type_infos) + device, alignement = self.GetModuleInfos(type_infos) if device is not None: infos = type_infos.copy() entries = device.GetEntriesList() @@ -688,7 +689,7 @@ if slave is not None: type_infos = slave.getType() - device = self.GetModuleInfos(type_infos) + device, alignement = self.GetModuleInfos(type_infos) if device is not None: sync_managers = [] for sync_manager in device.getSm(): @@ -1016,7 +1017,7 @@ slave_pos = (slave_alias, alias[slave_alias]) # Extract slave device informations - device = self.Controler.GetModuleInfos(type_infos) + device, alignement = self.Controler.GetModuleInfos(type_infos) if device is not None: # Extract slaves variables to be mapped @@ -1473,10 +1474,7 @@ "Type": subitem.getType(), "BitSize": subitem.getBitSize(), "Access": subitem_access, - "PDOMapping": subitem_pdomapping, - "PDO index": "", - "PDO name": "", - "PDO type": ""} + "PDOMapping": subitem_pdomapping} else: entry_access = "" entry_pdomapping = "" @@ -1495,10 +1493,7 @@ "Type": entry_type, "BitSize": object.getBitSize(), "Access": entry_access, - "PDOMapping": entry_pdomapping, - "PDO index": "", - "PDO name": "", - "PDO type": ""} + "PDOMapping": entry_pdomapping} for TxPdo in self.getTxPdo(): ExtractPdoInfos(TxPdo, "Transmit", entries) @@ -1578,53 +1573,33 @@ "Name": ExtractName(pdo_entry.getName()), "Type": entry_type.getcontent(), "Access": access, - "PDOMapping": pdomapping, - "PDO index": pdo_index, - "PDO name": pdo_name, - "PDO type": pdo_type} - -class RootClass: - - CTNChildrenTypes = [("EthercatNode",_EthercatCTN,"Ethercat Master")] - - def __init__(self): - self.LoadModulesLibrary() - - def GetModulesLibraryPath(self): - library_path = os.path.join(self.CTNPath(), "modules") - if not os.path.exists(library_path): - os.mkdir(library_path) - return library_path - - def _ImportModuleLibrary(self): - dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose an XML file"), os.getcwd(), "", _("XML files (*.xml)|*.xml|All files|*.*"), wx.OPEN) - if dialog.ShowModal() == wx.ID_OK: - filepath = dialog.GetPath() - if os.path.isfile(filepath): - shutil.copy(filepath, self.GetModulesLibraryPath()) - self.LoadModulesLibrary() - else: - self.GetCTRoot().logger.write_error(_("No such XML file: %s\n") % filepath) - dialog.Destroy() - - ConfNodeMethods = [ - {"bitmap" : "ImportESI", - "name" : _("Import module library"), - "tooltip" : _("Import module library"), - "method" : "_ImportModuleLibrary"}, - ] - - def CTNGenerate_C(self, buildpath, locations): - return [],"",False - - def LoadModulesLibrary(self): - self.ModulesLibrary = {} - - library_path = self.GetModulesLibraryPath() - - files = os.listdir(library_path) + "PDOMapping": pdomapping} + +DEFAULT_ALIGNMENT = 8 + +class ModulesLibrary: + + def __init__(self, path, parent_library=None): + self.Path = path + if not os.path.exists(self.Path): + os.makedirs(self.Path) + self.ParentLibrary = parent_library + + self.LoadModules() + self.LoadAlignments() + + def GetPath(self): + return self.Path + + def GetAlignmentFilePath(self): + return os.path.join(self.Path, "alignments.cfg") + + def LoadModules(self): + self.Library = {} + + files = os.listdir(self.Path) for file in files: - filepath = os.path.join(library_path, file) + filepath = os.path.join(self.Path, file) if os.path.isfile(filepath) and os.path.splitext(filepath)[-1] == ".xml": xmlfile = open(filepath, 'r') xml_tree = minidom.parse(xmlfile) @@ -1639,9 +1614,9 @@ if modules_infos is not None: vendor = modules_infos.getVendor() - vendor_category = self.ModulesLibrary.setdefault(ExtractHexDecValue(vendor.getId()), - {"name": ExtractName(vendor.getName(), _("Miscellaneous")), - "groups": {}}) + vendor_category = self.Library.setdefault(ExtractHexDecValue(vendor.getId()), + {"name": ExtractName(vendor.getName(), _("Miscellaneous")), + "groups": {}}) for group in modules_infos.getDescriptions().getGroups().getGroup(): group_type = group.getType() @@ -1656,10 +1631,10 @@ if not vendor_category["groups"].has_key(device_group): raise ValueError, "Not such group \"%\"" % device_group vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device)) - + def GetModulesLibrary(self, profile_filter=None): library = [] - for vendor_id, vendor in self.ModulesLibrary.iteritems(): + for vendor_id, vendor in self.Library.iteritems(): groups = [] children_dict = {} for group_type, group in vendor["groups"].iteritems(): @@ -1671,12 +1646,16 @@ device_dict = {} for device_type, device in group["devices"]: if profile_filter is None or profile_filter in device.GetProfileNumbers(): + product_code = device.getType().getProductCode() + revision_number = device.getType().getRevisionNo() + alignment = self.GetAlignment(vendor_id, product_code, revision_number) device_infos = {"name": ExtractName(device.getName()), "type": ETHERCAT_DEVICE, "infos": {"device_type": device_type, "vendor": vendor_id, - "product_code": device.getType().getProductCode(), - "revision_number": device.getType().getRevisionNo()}, + "product_code": product_code, + "revision_number": revision_number, + "alignment": alignment}, "children": []} group_infos["children"].append(device_infos) device_type_occurrences = device_dict.setdefault(device_type, []) @@ -1698,17 +1677,115 @@ "children": groups}) library.sort(lambda x, y: cmp(x["name"], y["name"])) return library - - def GetModuleInfos(self, type_infos): - vendor = self.ModulesLibrary.get(ExtractHexDecValue(type_infos["vendor"]), None) - if vendor is not None: - for group_name, group in vendor["groups"].iteritems(): - for device_type, device in group["devices"]: - product_code = ExtractHexDecValue(device.getType().getProductCode()) - revision_number = ExtractHexDecValue(device.getType().getRevisionNo()) - if (product_code == ExtractHexDecValue(type_infos["product_code"]) and - revision_number == ExtractHexDecValue(type_infos["revision_number"])): - return device - return None + + def GetModuleInfos(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(): + for device_type, device_infos in group_infos["devices"]: + product_code = ExtractHexDecValue(device_infos.getType().getProductCode()) + revision_number = ExtractHexDecValue(device_infos.getType().getRevisionNo()) + if (product_code == ExtractHexDecValue(module_infos["product_code"]) and + revision_number == ExtractHexDecValue(module_infos["revision_number"])): + return device_infos, self.GetAlignment(vendor, product_code, revision_number) + return None, None + + def ImportModuleLibrary(self, filepath): + if os.path.isfile(filepath): + shutil.copy(filepath, self.Path) + self.LoadModules() + return True + return False + + def LoadAlignments(self): + self.Alignments = {} + + csvfile_path = self.GetAlignmentFilePath() + if os.path.exists(csvfile_path): + csvfile = open(csvfile_path, "rb") + sample = csvfile.read(1024) + csvfile.seek(0) + dialect = csv.Sniffer().sniff(sample) + has_header = csv.Sniffer().has_header(sample) + reader = csv.reader(csvfile, dialect) + for row in reader: + if has_header: + has_header = False + else: + try: + self.Alignments[tuple(map(int, row[:3]))] = row[3] + except: + pass + csvfile.close() + + def SaveAlignments(self): + csvfile = open(self.GetAlignmentFilePath(), "wb") + writer = csv.writer(csvfile, delimiter=';') + writer.writerow(['Vendor', 'product_code', 'revision_number', 'alignment']) + for (vendor, product_code, revision_number), alignment in self.Alignments.iteritems(): + writer.writerow([vendor, product_code, revision_number, alignment]) + csvfile.close() + + def SetAlignment(self, vendor, product_code, revision_number, alignment): + vendor = ExtractHexDecValue(vendor) + product_code = ExtractHexDecValue(product_code) + revision_number = ExtractHexDecValue(revision_number) + + self.Alignments[tuple([vendor, product_code, revision_number])] = alignment + self.SaveAlignments() + + def GetAlignment(self, vendor, product_code, revision_number): + vendor = ExtractHexDecValue(vendor) + product_code = ExtractHexDecValue(product_code) + revision_number = ExtractHexDecValue(revision_number) + + alignment = self.Alignments.get(tuple([vendor, product_code, revision_number])) + if alignment is not None: + return alignment + + if self.ParentLibrary is not None: + return self.ParentLibrary.GetAlignment(vendor, product_code, revision_number) + return DEFAULT_ALIGNMENT + +USERDATA_DIR = wx.StandardPaths.Get().GetUserDataDir() +if wx.Platform != '__WXMSW__': + USERDATA_DIR += '_files' + +ModulesDatabase = ModulesLibrary( + os.path.join(USERDATA_DIR, "ethercat_modules")) + +class RootClass: + + CTNChildrenTypes = [("EthercatNode",_EthercatCTN,"Ethercat Master")] + EditorType = LibraryEditor + + def __init__(self): + self.ModulesLibrary = None + self.LoadModulesLibrary() + + def GetModulesLibraryPath(self): + return os.path.join(self.CTNPath(), "modules") + + def CTNGenerate_C(self, buildpath, locations): + return [],"",False + + def LoadModulesLibrary(self): + if self.ModulesLibrary is None: + self.ModulesLibrary = ModulesLibrary(self.GetModulesLibraryPath(), ModulesDatabase) + else: + self.ModulesLibrary.LoadModulesLibrary() + + def GetModulesDatabaseInstance(self): + return ModulesDatabase + + def GetModulesLibraryInstance(self): + return self.ModulesLibrary + + def GetModulesLibrary(self, profile_filter=None): + return self.ModulesLibrary.GetModulesLibrary(profile_filter) + + def GetModuleInfos(self, module_infos): + return self.ModulesLibrary.GetModuleInfos(module_infos)