etherlab/etherlab.py
changeset 2097 58d07e039896
parent 2096 c9b0340ea0f5
child 2098 392791b5cc04
equal deleted inserted replaced
2096:c9b0340ea0f5 2097:58d07e039896
     1 import os, shutil
     1 import os, shutil
     2 import cPickle
     2 import cPickle
     3 from xml.dom import minidom
     3 from xml.dom import minidom
     4 
     4 
     5 import wx
     5 import wx
       
     6 import csv
     6 
     7 
     7 from xmlclass import *
     8 from xmlclass import *
     8 from POULibrary import POULibrary
     9 from POULibrary import POULibrary
     9 from ConfigTreeNode import ConfigTreeNode
    10 from ConfigTreeNode import ConfigTreeNode
    10 from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    11 from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    11 from ConfigEditor import NodeEditor, CIA402NodeEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
    12 from ConfigEditor import NodeEditor, CIA402NodeEditor, LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
    12 
    13 
    13 try:
    14 try:
    14     from MotionLibrary import Headers, AxisXSD
    15     from MotionLibrary import Headers, AxisXSD
    15     HAS_MCL = True
    16     HAS_MCL = True
    16 except:
    17 except:
   569                     type_infos = {
   570                     type_infos = {
   570                         "vendor": slave["vendor_id"],
   571                         "vendor": slave["vendor_id"],
   571                         "product_code": slave["product_code"],
   572                         "product_code": slave["product_code"],
   572                         "revision_number":slave["revision_number"],
   573                         "revision_number":slave["revision_number"],
   573                     }
   574                     }
   574                     device = self.GetModuleInfos(type_infos)
   575                     device, alignment = self.GetModuleInfos(type_infos)
   575                     if device is not None:
   576                     if device is not None:
   576                         if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers():
   577                         if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers():
   577                             CTNType = "EthercatCIA402Slave"
   578                             CTNType = "EthercatCIA402Slave"
   578                         else:
   579                         else:
   579                             CTNType = "EthercatSlave"
   580                             CTNType = "EthercatSlave"
   649     
   650     
   650     def GetSlaveInfos(self, slave_pos):
   651     def GetSlaveInfos(self, slave_pos):
   651         slave = self.GetSlave(slave_pos)
   652         slave = self.GetSlave(slave_pos)
   652         if slave is not None:
   653         if slave is not None:
   653             type_infos = slave.getType()
   654             type_infos = slave.getType()
   654             device = self.GetModuleInfos(type_infos)
   655             device, alignement = self.GetModuleInfos(type_infos)
   655             if device is not None:
   656             if device is not None:
   656                 infos = type_infos.copy()
   657                 infos = type_infos.copy()
   657                 entries = device.GetEntriesList()
   658                 entries = device.GetEntriesList()
   658                 entries_list = entries.items()
   659                 entries_list = entries.items()
   659                 entries_list.sort()
   660                 entries_list.sort()
   686         slave = self.GetSlave(slave_pos)
   687         slave = self.GetSlave(slave_pos)
   687         vars = []    
   688         vars = []    
   688         if slave is not None:
   689         if slave is not None:
   689             type_infos = slave.getType()
   690             type_infos = slave.getType()
   690         
   691         
   691             device = self.GetModuleInfos(type_infos)
   692             device, alignement = self.GetModuleInfos(type_infos)
   692             if device is not None:
   693             if device is not None:
   693                 sync_managers = []
   694                 sync_managers = []
   694                 for sync_manager in device.getSm():
   695                 for sync_manager in device.getSm():
   695                     sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
   696                     sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
   696                     sync_manager_direction = sync_manager_control_byte & 0x0c
   697                     sync_manager_direction = sync_manager_control_byte & 0x0c
  1014             else:
  1015             else:
  1015                 alias[slave_alias] = 0
  1016                 alias[slave_alias] = 0
  1016             slave_pos = (slave_alias, alias[slave_alias])
  1017             slave_pos = (slave_alias, alias[slave_alias])
  1017             
  1018             
  1018             # Extract slave device informations
  1019             # Extract slave device informations
  1019             device = self.Controler.GetModuleInfos(type_infos)
  1020             device, alignement = self.Controler.GetModuleInfos(type_infos)
  1020             if device is not None:
  1021             if device is not None:
  1021                 
  1022                 
  1022                 # Extract slaves variables to be mapped
  1023                 # Extract slaves variables to be mapped
  1023                 slave_variables = self.UsedVariables.get(slave_idx, {})
  1024                 slave_variables = self.UsedVariables.get(slave_idx, {})
  1024                 
  1025                 
  1471                                      ExtractName(subitem.getDisplayName(), 
  1472                                      ExtractName(subitem.getDisplayName(), 
  1472                                                  subitem.getName()).decode("utf-8")),
  1473                                                  subitem.getName()).decode("utf-8")),
  1473                             "Type": subitem.getType(),
  1474                             "Type": subitem.getType(),
  1474                             "BitSize": subitem.getBitSize(),
  1475                             "BitSize": subitem.getBitSize(),
  1475                             "Access": subitem_access, 
  1476                             "Access": subitem_access, 
  1476                             "PDOMapping": subitem_pdomapping, 
  1477                             "PDOMapping": subitem_pdomapping}
  1477                             "PDO index": "", 
       
  1478                             "PDO name": "", 
       
  1479                             "PDO type": ""}
       
  1480                 else:
  1478                 else:
  1481                     entry_access = ""
  1479                     entry_access = ""
  1482                     entry_pdomapping = ""
  1480                     entry_pdomapping = ""
  1483                     entry_flags = object.getFlags()
  1481                     entry_flags = object.getFlags()
  1484                     if entry_flags is not None:
  1482                     if entry_flags is not None:
  1493                          "SubIndex": "0",
  1491                          "SubIndex": "0",
  1494                          "Name": entry_name,
  1492                          "Name": entry_name,
  1495                          "Type": entry_type,
  1493                          "Type": entry_type,
  1496                          "BitSize": object.getBitSize(),
  1494                          "BitSize": object.getBitSize(),
  1497                          "Access": entry_access,
  1495                          "Access": entry_access,
  1498                          "PDOMapping": entry_pdomapping, 
  1496                          "PDOMapping": entry_pdomapping}
  1499                          "PDO index": "", 
       
  1500                          "PDO name": "", 
       
  1501                          "PDO type": ""}
       
  1502         
  1497         
  1503         for TxPdo in self.getTxPdo():
  1498         for TxPdo in self.getTxPdo():
  1504             ExtractPdoInfos(TxPdo, "Transmit", entries)
  1499             ExtractPdoInfos(TxPdo, "Transmit", entries)
  1505         for RxPdo in self.getRxPdo():
  1500         for RxPdo in self.getRxPdo():
  1506             ExtractPdoInfos(RxPdo, "Receive", entries)
  1501             ExtractPdoInfos(RxPdo, "Receive", entries)
  1576                     "Index": entry_index,
  1571                     "Index": entry_index,
  1577                     "SubIndex": entry_subindex,
  1572                     "SubIndex": entry_subindex,
  1578                     "Name": ExtractName(pdo_entry.getName()),
  1573                     "Name": ExtractName(pdo_entry.getName()),
  1579                     "Type": entry_type.getcontent(),
  1574                     "Type": entry_type.getcontent(),
  1580                     "Access": access,
  1575                     "Access": access,
  1581                     "PDOMapping": pdomapping,
  1576                     "PDOMapping": pdomapping}
  1582                     "PDO index": pdo_index, 
  1577 
  1583                     "PDO name": pdo_name, 
  1578 DEFAULT_ALIGNMENT = 8
  1584                     "PDO type": pdo_type}
  1579 
  1585 
  1580 class ModulesLibrary:
  1586 class RootClass:
  1581     
  1587     
  1582     def __init__(self, path, parent_library=None):
  1588     CTNChildrenTypes = [("EthercatNode",_EthercatCTN,"Ethercat Master")]
  1583         self.Path = path
  1589     
  1584         if not os.path.exists(self.Path):
  1590     def __init__(self):
  1585             os.makedirs(self.Path)
  1591         self.LoadModulesLibrary()
  1586         self.ParentLibrary = parent_library
  1592     
  1587         
  1593     def GetModulesLibraryPath(self):
  1588         self.LoadModules()
  1594         library_path = os.path.join(self.CTNPath(), "modules")
  1589         self.LoadAlignments()
  1595         if not os.path.exists(library_path):
  1590     
  1596             os.mkdir(library_path)
  1591     def GetPath(self):
  1597         return library_path
  1592         return self.Path
  1598     
  1593     
  1599     def _ImportModuleLibrary(self):
  1594     def GetAlignmentFilePath(self):
  1600         dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose an XML file"), os.getcwd(), "",  _("XML files (*.xml)|*.xml|All files|*.*"), wx.OPEN)
  1595         return os.path.join(self.Path, "alignments.cfg")
  1601         if dialog.ShowModal() == wx.ID_OK:
  1596     
  1602             filepath = dialog.GetPath()
  1597     def LoadModules(self):
  1603             if os.path.isfile(filepath):
  1598         self.Library = {}
  1604                 shutil.copy(filepath, self.GetModulesLibraryPath())
  1599         
  1605                 self.LoadModulesLibrary()
  1600         files = os.listdir(self.Path)
  1606             else:
       
  1607                 self.GetCTRoot().logger.write_error(_("No such XML file: %s\n") % filepath)
       
  1608         dialog.Destroy()  
       
  1609     
       
  1610     ConfNodeMethods = [
       
  1611         {"bitmap" : "ImportESI",
       
  1612          "name" : _("Import module library"), 
       
  1613          "tooltip" : _("Import module library"),
       
  1614          "method" : "_ImportModuleLibrary"},
       
  1615     ]
       
  1616     
       
  1617     def CTNGenerate_C(self, buildpath, locations):
       
  1618         return [],"",False
       
  1619     
       
  1620     def LoadModulesLibrary(self):
       
  1621         self.ModulesLibrary = {}
       
  1622         
       
  1623         library_path = self.GetModulesLibraryPath()
       
  1624         
       
  1625         files = os.listdir(library_path)
       
  1626         for file in files:
  1601         for file in files:
  1627             filepath = os.path.join(library_path, file)
  1602             filepath = os.path.join(self.Path, file)
  1628             if os.path.isfile(filepath) and os.path.splitext(filepath)[-1] == ".xml":
  1603             if os.path.isfile(filepath) and os.path.splitext(filepath)[-1] == ".xml":
  1629                 xmlfile = open(filepath, 'r')
  1604                 xmlfile = open(filepath, 'r')
  1630                 xml_tree = minidom.parse(xmlfile)
  1605                 xml_tree = minidom.parse(xmlfile)
  1631                 xmlfile.close()
  1606                 xmlfile.close()
  1632                 
  1607                 
  1637                         modules_infos.loadXMLTree(child)
  1612                         modules_infos.loadXMLTree(child)
  1638                 
  1613                 
  1639                 if modules_infos is not None:
  1614                 if modules_infos is not None:
  1640                     vendor = modules_infos.getVendor()
  1615                     vendor = modules_infos.getVendor()
  1641                     
  1616                     
  1642                     vendor_category = self.ModulesLibrary.setdefault(ExtractHexDecValue(vendor.getId()), 
  1617                     vendor_category = self.Library.setdefault(ExtractHexDecValue(vendor.getId()), 
  1643                                                                      {"name": ExtractName(vendor.getName(), _("Miscellaneous")), 
  1618                                                               {"name": ExtractName(vendor.getName(), _("Miscellaneous")), 
  1644                                                                       "groups": {}})
  1619                                                                "groups": {}})
  1645                     
  1620                     
  1646                     for group in modules_infos.getDescriptions().getGroups().getGroup():
  1621                     for group in modules_infos.getDescriptions().getGroups().getGroup():
  1647                         group_type = group.getType()
  1622                         group_type = group.getType()
  1648                         
  1623                         
  1649                         vendor_category["groups"].setdefault(group_type, {"name": ExtractName(group.getName(), group_type), 
  1624                         vendor_category["groups"].setdefault(group_type, {"name": ExtractName(group.getName(), group_type), 
  1654                     for device in modules_infos.getDescriptions().getDevices().getDevice():
  1629                     for device in modules_infos.getDescriptions().getDevices().getDevice():
  1655                         device_group = device.getGroupType()
  1630                         device_group = device.getGroupType()
  1656                         if not vendor_category["groups"].has_key(device_group):
  1631                         if not vendor_category["groups"].has_key(device_group):
  1657                             raise ValueError, "Not such group \"%\"" % device_group
  1632                             raise ValueError, "Not such group \"%\"" % device_group
  1658                         vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device))
  1633                         vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device))
  1659     
  1634 
  1660     def GetModulesLibrary(self, profile_filter=None):
  1635     def GetModulesLibrary(self, profile_filter=None):
  1661         library = []
  1636         library = []
  1662         for vendor_id, vendor in self.ModulesLibrary.iteritems():
  1637         for vendor_id, vendor in self.Library.iteritems():
  1663             groups = []
  1638             groups = []
  1664             children_dict = {}
  1639             children_dict = {}
  1665             for group_type, group in vendor["groups"].iteritems():
  1640             for group_type, group in vendor["groups"].iteritems():
  1666                 group_infos = {"name": group["name"],
  1641                 group_infos = {"name": group["name"],
  1667                                "order": group["order"],
  1642                                "order": group["order"],
  1669                                "infos": None,
  1644                                "infos": None,
  1670                                "children": children_dict.setdefault(group_type, [])}
  1645                                "children": children_dict.setdefault(group_type, [])}
  1671                 device_dict = {}
  1646                 device_dict = {}
  1672                 for device_type, device in group["devices"]:
  1647                 for device_type, device in group["devices"]:
  1673                     if profile_filter is None or profile_filter in device.GetProfileNumbers():
  1648                     if profile_filter is None or profile_filter in device.GetProfileNumbers():
       
  1649                         product_code = device.getType().getProductCode()
       
  1650                         revision_number = device.getType().getRevisionNo()
       
  1651                         alignment = self.GetAlignment(vendor_id, product_code, revision_number)
  1674                         device_infos = {"name": ExtractName(device.getName()),
  1652                         device_infos = {"name": ExtractName(device.getName()),
  1675                                         "type": ETHERCAT_DEVICE,
  1653                                         "type": ETHERCAT_DEVICE,
  1676                                         "infos": {"device_type": device_type,
  1654                                         "infos": {"device_type": device_type,
  1677                                                   "vendor": vendor_id,
  1655                                                   "vendor": vendor_id,
  1678                                                   "product_code": device.getType().getProductCode(),
  1656                                                   "product_code": product_code,
  1679                                                   "revision_number": device.getType().getRevisionNo()},
  1657                                                   "revision_number": revision_number,
       
  1658                                                   "alignment": alignment},
  1680                                         "children": []}
  1659                                         "children": []}
  1681                         group_infos["children"].append(device_infos)
  1660                         group_infos["children"].append(device_infos)
  1682                         device_type_occurrences = device_dict.setdefault(device_type, [])
  1661                         device_type_occurrences = device_dict.setdefault(device_type, [])
  1683                         device_type_occurrences.append(device_infos)
  1662                         device_type_occurrences.append(device_infos)
  1684                 for device_type_occurrences in device_dict.itervalues():
  1663                 for device_type_occurrences in device_dict.itervalues():
  1696                                 "type": ETHERCAT_VENDOR,
  1675                                 "type": ETHERCAT_VENDOR,
  1697                                 "infos": None,
  1676                                 "infos": None,
  1698                                 "children": groups})
  1677                                 "children": groups})
  1699         library.sort(lambda x, y: cmp(x["name"], y["name"]))
  1678         library.sort(lambda x, y: cmp(x["name"], y["name"]))
  1700         return library
  1679         return library
  1701     
  1680 
  1702     def GetModuleInfos(self, type_infos):
  1681     def GetModuleInfos(self, module_infos):
  1703         vendor = self.ModulesLibrary.get(ExtractHexDecValue(type_infos["vendor"]), None)
  1682         vendor = ExtractHexDecValue(module_infos["vendor"])
  1704         if vendor is not None:
  1683         vendor_infos = self.Library.get(vendor)
  1705             for group_name, group in vendor["groups"].iteritems():
  1684         if vendor_infos is not None:
  1706                 for device_type, device in group["devices"]:
  1685             for group_name, group_infos in vendor_infos["groups"].iteritems():
  1707                     product_code = ExtractHexDecValue(device.getType().getProductCode())
  1686                 for device_type, device_infos in group_infos["devices"]:
  1708                     revision_number = ExtractHexDecValue(device.getType().getRevisionNo())
  1687                     product_code = ExtractHexDecValue(device_infos.getType().getProductCode())
  1709                     if (product_code == ExtractHexDecValue(type_infos["product_code"]) and
  1688                     revision_number = ExtractHexDecValue(device_infos.getType().getRevisionNo())
  1710                         revision_number == ExtractHexDecValue(type_infos["revision_number"])):
  1689                     if (product_code == ExtractHexDecValue(module_infos["product_code"]) and
  1711                         return device
  1690                         revision_number == ExtractHexDecValue(module_infos["revision_number"])):
  1712         return None
  1691                         return device_infos, self.GetAlignment(vendor, product_code, revision_number)
       
  1692         return None, None
       
  1693     
       
  1694     def ImportModuleLibrary(self, filepath):
       
  1695         if os.path.isfile(filepath):
       
  1696             shutil.copy(filepath, self.Path)
       
  1697             self.LoadModules()
       
  1698             return True
       
  1699         return False
       
  1700     
       
  1701     def LoadAlignments(self):
       
  1702         self.Alignments = {}
       
  1703         
       
  1704         csvfile_path = self.GetAlignmentFilePath()
       
  1705         if os.path.exists(csvfile_path):
       
  1706             csvfile = open(csvfile_path, "rb")
       
  1707             sample = csvfile.read(1024)
       
  1708             csvfile.seek(0)
       
  1709             dialect = csv.Sniffer().sniff(sample)
       
  1710             has_header = csv.Sniffer().has_header(sample)
       
  1711             reader = csv.reader(csvfile, dialect)
       
  1712             for row in reader:
       
  1713                 if has_header:
       
  1714                     has_header = False
       
  1715                 else:
       
  1716                     try:
       
  1717                         self.Alignments[tuple(map(int, row[:3]))] = row[3]
       
  1718                     except:
       
  1719                         pass
       
  1720             csvfile.close()
       
  1721         
       
  1722     def SaveAlignments(self):
       
  1723         csvfile = open(self.GetAlignmentFilePath(), "wb")
       
  1724         writer = csv.writer(csvfile, delimiter=';')
       
  1725         writer.writerow(['Vendor', 'product_code', 'revision_number', 'alignment'])
       
  1726         for (vendor, product_code, revision_number), alignment in self.Alignments.iteritems():
       
  1727             writer.writerow([vendor, product_code, revision_number, alignment])
       
  1728         csvfile.close()
       
  1729     
       
  1730     def SetAlignment(self, vendor, product_code, revision_number, alignment):
       
  1731         vendor = ExtractHexDecValue(vendor)
       
  1732         product_code = ExtractHexDecValue(product_code)
       
  1733         revision_number = ExtractHexDecValue(revision_number)
       
  1734         
       
  1735         self.Alignments[tuple([vendor, product_code, revision_number])] = alignment
       
  1736         self.SaveAlignments()
       
  1737     
       
  1738     def GetAlignment(self, vendor, product_code, revision_number):
       
  1739         vendor = ExtractHexDecValue(vendor)
       
  1740         product_code = ExtractHexDecValue(product_code)
       
  1741         revision_number = ExtractHexDecValue(revision_number)
       
  1742         
       
  1743         alignment = self.Alignments.get(tuple([vendor, product_code, revision_number]))
       
  1744         if alignment is not None:
       
  1745             return alignment
       
  1746         
       
  1747         if self.ParentLibrary is not None:
       
  1748             return self.ParentLibrary.GetAlignment(vendor, product_code, revision_number)
       
  1749         return DEFAULT_ALIGNMENT
       
  1750 
       
  1751 USERDATA_DIR = wx.StandardPaths.Get().GetUserDataDir()
       
  1752 if wx.Platform != '__WXMSW__':
       
  1753     USERDATA_DIR += '_files'
       
  1754 
       
  1755 ModulesDatabase = ModulesLibrary(
       
  1756     os.path.join(USERDATA_DIR, "ethercat_modules"))
       
  1757 
       
  1758 class RootClass:
       
  1759     
       
  1760     CTNChildrenTypes = [("EthercatNode",_EthercatCTN,"Ethercat Master")]
       
  1761     EditorType = LibraryEditor
       
  1762     
       
  1763     def __init__(self):
       
  1764         self.ModulesLibrary = None
       
  1765         self.LoadModulesLibrary()
       
  1766     
       
  1767     def GetModulesLibraryPath(self):
       
  1768         return os.path.join(self.CTNPath(), "modules") 
       
  1769     
       
  1770     def CTNGenerate_C(self, buildpath, locations):
       
  1771         return [],"",False
       
  1772     
       
  1773     def LoadModulesLibrary(self):
       
  1774         if self.ModulesLibrary is None:
       
  1775             self.ModulesLibrary = ModulesLibrary(self.GetModulesLibraryPath(), ModulesDatabase)
       
  1776         else:
       
  1777             self.ModulesLibrary.LoadModulesLibrary()
       
  1778     
       
  1779     def GetModulesDatabaseInstance(self):
       
  1780         return ModulesDatabase
       
  1781     
       
  1782     def GetModulesLibraryInstance(self):
       
  1783         return self.ModulesLibrary
       
  1784     
       
  1785     def GetModulesLibrary(self, profile_filter=None):
       
  1786         return self.ModulesLibrary.GetModulesLibrary(profile_filter)
       
  1787     
       
  1788     def GetModuleInfos(self, module_infos):
       
  1789         return self.ModulesLibrary.GetModuleInfos(module_infos)
  1713 
  1790 
  1714             
  1791