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: |
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 |