11 |
11 |
12 from EthercatSlave import ExtractHexDecValue, ExtractName |
12 from EthercatSlave import ExtractHexDecValue, ExtractName |
13 from EthercatMaster import _EthercatCTN |
13 from EthercatMaster import _EthercatCTN |
14 from ConfigEditor import LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE |
14 from ConfigEditor import LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE |
15 |
15 |
|
16 ScriptDirectory = os.path.split(os.path.realpath(__file__))[0] |
|
17 |
16 #-------------------------------------------------- |
18 #-------------------------------------------------- |
17 # Ethercat ConfNode |
19 # Ethercat ConfNode |
18 #-------------------------------------------------- |
20 #-------------------------------------------------- |
19 |
21 |
20 EtherCATInfoClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd")) |
22 EtherCATInfoParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd")) |
21 |
23 EtherCATInfo_XPath = lambda xpath: etree.XPath(xpath) |
22 cls = EtherCATInfoClasses["EtherCATBase.xsd"].get("DictionaryType", None) |
24 |
|
25 def extract_param(el): |
|
26 if el.tag == "Index": |
|
27 return "#x%4.4X" % int(el.text) |
|
28 if el.tag == "PDOMapping": |
|
29 if el.text is None: |
|
30 return "" |
|
31 return el.text.upper() |
|
32 if el.text is None: |
|
33 return "" |
|
34 return el.text |
|
35 |
|
36 def extract_pdo_infos(pdo_infos): |
|
37 return { |
|
38 pdo_infos.tag + " " + el.tag: extract_param(el) |
|
39 for el in pdo_infos} |
|
40 |
|
41 def HexDecValue(ctxt, values): |
|
42 return str(ExtractHexDecValue(values[0])) |
|
43 |
|
44 def EntryName(ctxt, values): |
|
45 default=None |
|
46 names = [] |
|
47 for element in values: |
|
48 if element.tag == "Default": |
|
49 default = element.text |
|
50 else: |
|
51 names.append(element) |
|
52 return ExtractName(names, default) |
|
53 |
|
54 class AddEntry(etree.XSLTExtension): |
|
55 |
|
56 def __init__(self, entries): |
|
57 etree.XSLTExtension.__init__(self) |
|
58 self.Entries = entries |
|
59 |
|
60 def execute(self, context, self_node, input_node, output_parent): |
|
61 infos = etree.Element('entry_infos') |
|
62 self.process_children(context, infos) |
|
63 index, subindex = map( |
|
64 lambda x: int(infos.find(x).text), |
|
65 ["Index", "SubIndex"]) |
|
66 new_entry_infos = { |
|
67 el.tag: extract_param(el) |
|
68 for el in infos if el.tag != "PDO"} |
|
69 if (index, subindex) != (0, 0): |
|
70 entry_infos = self.Entries.get((index, subindex)) |
|
71 if entry_infos is not None: |
|
72 PDO_infos = infos.find("PDO") |
|
73 if PDO_infos is not None: |
|
74 entry_infos.update(extract_pdo_infos(PDO_infos)) |
|
75 else: |
|
76 self.Entries[(index, subindex)] = new_entry_infos |
|
77 |
|
78 entries_list_xslt = etree.parse( |
|
79 os.path.join(ScriptDirectory, "entries_list.xslt")) |
|
80 |
|
81 cls = EtherCATInfoParser.GetElementClass("DeviceType") |
23 if cls: |
82 if cls: |
24 cls.loadXMLTreeArgs = None |
83 |
25 |
84 profile_numbers_xpath = EtherCATInfo_XPath("Profile/ProfileNo") |
26 setattr(cls, "_loadXMLTree", getattr(cls, "loadXMLTree")) |
|
27 |
|
28 def loadXMLTree(self, *args): |
|
29 self.loadXMLTreeArgs = args |
|
30 setattr(cls, "loadXMLTree", loadXMLTree) |
|
31 |
|
32 def load(self): |
|
33 if self.loadXMLTreeArgs is not None: |
|
34 self._loadXMLTree(*self.loadXMLTreeArgs) |
|
35 self.loadXMLTreeArgs = None |
|
36 setattr(cls, "load", load) |
|
37 |
|
38 cls = EtherCATInfoClasses["EtherCATInfo.xsd"].get("DeviceType", None) |
|
39 if cls: |
|
40 cls.DataTypes = None |
|
41 |
|
42 def GetProfileNumbers(self): |
85 def GetProfileNumbers(self): |
43 profiles = [] |
86 return [number.text for number in profile_numbers_xpath(self)] |
44 |
|
45 for profile in self.getProfile(): |
|
46 profile_content = profile.getcontent() |
|
47 if profile_content is None: |
|
48 continue |
|
49 |
|
50 for content_element in profile_content["value"]: |
|
51 if content_element["name"] == "ProfileNo": |
|
52 profiles.append(content_element["value"]) |
|
53 |
|
54 return profiles |
|
55 setattr(cls, "GetProfileNumbers", GetProfileNumbers) |
87 setattr(cls, "GetProfileNumbers", GetProfileNumbers) |
56 |
|
57 def GetProfileDictionaries(self): |
|
58 dictionaries = [] |
|
59 |
|
60 for profile in self.getProfile(): |
|
61 |
|
62 profile_content = profile.getcontent() |
|
63 if profile_content is None: |
|
64 continue |
|
65 |
|
66 for content_element in profile_content["value"]: |
|
67 if content_element["name"] == "Dictionary": |
|
68 dictionaries.append(content_element["value"]) |
|
69 elif content_element["name"] == "DictionaryFile": |
|
70 raise ValueError, "DictionaryFile for defining Device Profile is not yet supported!" |
|
71 |
|
72 return dictionaries |
|
73 setattr(cls, "GetProfileDictionaries", GetProfileDictionaries) |
|
74 |
|
75 def ExtractDataTypes(self): |
|
76 self.DataTypes = {} |
|
77 |
|
78 for dictionary in self.GetProfileDictionaries(): |
|
79 dictionary.load() |
|
80 |
|
81 datatypes = dictionary.getDataTypes() |
|
82 if datatypes is not None: |
|
83 |
|
84 for datatype in datatypes.getDataType(): |
|
85 content = datatype.getcontent() |
|
86 if content is not None and content["name"] == "SubItem": |
|
87 self.DataTypes[datatype.getName()] = datatype |
|
88 |
|
89 setattr(cls, "ExtractDataTypes", ExtractDataTypes) |
|
90 |
88 |
91 def getCoE(self): |
89 def getCoE(self): |
92 mailbox = self.getMailbox() |
90 mailbox = self.getMailbox() |
93 if mailbox is not None: |
91 if mailbox is not None: |
94 return mailbox.getCoE() |
92 return mailbox.getCoE() |
95 return None |
93 return None |
96 setattr(cls, "getCoE", getCoE) |
94 setattr(cls, "getCoE", getCoE) |
97 |
95 |
98 def GetEntriesList(self, limits=None): |
96 def GetEntriesList(self, limits=None): |
99 if self.DataTypes is None: |
|
100 self.ExtractDataTypes() |
|
101 |
|
102 entries = {} |
97 entries = {} |
103 |
98 |
104 for dictionary in self.GetProfileDictionaries(): |
99 entries_list_xslt_tree = etree.XSLT( |
105 dictionary.load() |
100 entries_list_xslt, extensions = { |
106 |
101 ("entries_list_ns", "add_entry"): AddEntry(entries), |
107 for object in dictionary.getObjects().getObject(): |
102 ("entries_list_ns", "HexDecValue"): HexDecValue, |
108 entry_index = object.getIndex().getcontent() |
103 ("entries_list_ns", "EntryName"): EntryName}) |
109 index = ExtractHexDecValue(entry_index) |
104 entries_list_xslt_tree(self, **dict(zip( |
110 if limits is None or limits[0] <= index <= limits[1]: |
105 ["min_index", "max_index"], |
111 entry_type = object.getType() |
106 map(lambda x: etree.XSLT.strparam(str(x)), |
112 entry_name = ExtractName(object.getName()) |
107 limits if limits is not None else [0x0000, 0xFFFF]) |
113 |
108 ))) |
114 entry_type_infos = self.DataTypes.get(entry_type, None) |
|
115 if entry_type_infos is not None: |
|
116 content = entry_type_infos.getcontent() |
|
117 for subitem in content["value"]: |
|
118 entry_subidx = subitem.getSubIdx() |
|
119 if entry_subidx is None: |
|
120 entry_subidx = "0" |
|
121 subidx = ExtractHexDecValue(entry_subidx) |
|
122 subitem_access = "" |
|
123 subitem_pdomapping = "" |
|
124 subitem_flags = subitem.getFlags() |
|
125 if subitem_flags is not None: |
|
126 access = subitem_flags.getAccess() |
|
127 if access is not None: |
|
128 subitem_access = access.getcontent() |
|
129 pdomapping = subitem_flags.getPdoMapping() |
|
130 if pdomapping is not None: |
|
131 subitem_pdomapping = pdomapping.upper() |
|
132 entries[(index, subidx)] = { |
|
133 "Index": entry_index, |
|
134 "SubIndex": entry_subidx, |
|
135 "Name": "%s - %s" % |
|
136 (entry_name.decode("utf-8"), |
|
137 ExtractName(subitem.getDisplayName(), |
|
138 subitem.getName()).decode("utf-8")), |
|
139 "Type": subitem.getType(), |
|
140 "BitSize": subitem.getBitSize(), |
|
141 "Access": subitem_access, |
|
142 "PDOMapping": subitem_pdomapping} |
|
143 else: |
|
144 entry_access = "" |
|
145 entry_pdomapping = "" |
|
146 entry_flags = object.getFlags() |
|
147 if entry_flags is not None: |
|
148 access = entry_flags.getAccess() |
|
149 if access is not None: |
|
150 entry_access = access.getcontent() |
|
151 pdomapping = entry_flags.getPdoMapping() |
|
152 if pdomapping is not None: |
|
153 entry_pdomapping = pdomapping.upper() |
|
154 entries[(index, 0)] = { |
|
155 "Index": entry_index, |
|
156 "SubIndex": "0", |
|
157 "Name": entry_name, |
|
158 "Type": entry_type, |
|
159 "BitSize": object.getBitSize(), |
|
160 "Access": entry_access, |
|
161 "PDOMapping": entry_pdomapping} |
|
162 |
|
163 for TxPdo in self.getTxPdo(): |
|
164 ExtractPdoInfos(TxPdo, "Transmit", entries, limits) |
|
165 for RxPdo in self.getRxPdo(): |
|
166 ExtractPdoInfos(RxPdo, "Receive", entries, limits) |
|
167 |
109 |
168 return entries |
110 return entries |
169 setattr(cls, "GetEntriesList", GetEntriesList) |
111 setattr(cls, "GetEntriesList", GetEntriesList) |
170 |
112 |
171 def GetSyncManagers(self): |
113 def GetSyncManagers(self): |
172 sync_managers = [] |
114 sync_managers = [] |
173 for sync_manager in self.getSm(): |
115 for sync_manager in self.getSm(): |
174 sync_manager_infos = {} |
116 sync_manager_infos = {} |
175 for name, value in [("Name", sync_manager.getcontent()), |
117 for name, value in [("Name", sync_manager.getcontent()), |
274 return self.Path |
184 return self.Path |
275 |
185 |
276 def GetModulesExtraParamsFilePath(self): |
186 def GetModulesExtraParamsFilePath(self): |
277 return os.path.join(self.Path, "modules_extra_params.cfg") |
187 return os.path.join(self.Path, "modules_extra_params.cfg") |
278 |
188 |
|
189 groups_xpath = EtherCATInfo_XPath("Descriptions/Groups/Group") |
|
190 devices_xpath = EtherCATInfo_XPath("Descriptions/Devices/Device") |
279 def LoadModules(self): |
191 def LoadModules(self): |
280 self.Library = {} |
192 self.Library = {} |
281 |
193 |
282 files = os.listdir(self.Path) |
194 files = os.listdir(self.Path) |
283 for file in files: |
195 for file in files: |
284 filepath = os.path.join(self.Path, file) |
196 filepath = os.path.join(self.Path, file) |
285 if os.path.isfile(filepath) and os.path.splitext(filepath)[-1] == ".xml": |
197 if os.path.isfile(filepath) and os.path.splitext(filepath)[-1] == ".xml": |
|
198 self.modules_infos = None |
|
199 |
286 xmlfile = open(filepath, 'r') |
200 xmlfile = open(filepath, 'r') |
287 xml_tree = minidom.parse(xmlfile) |
201 try: |
|
202 self.modules_infos = etree.fromstring( |
|
203 xmlfile.read(), EtherCATInfoParser) |
|
204 except: |
|
205 pass |
288 xmlfile.close() |
206 xmlfile.close() |
289 |
|
290 self.modules_infos = None |
|
291 for child in xml_tree.childNodes: |
|
292 if child.nodeType == xml_tree.ELEMENT_NODE and child.nodeName == "EtherCATInfo": |
|
293 self.modules_infos = EtherCATInfoClasses["EtherCATInfo.xsd"]["EtherCATInfo"]() |
|
294 self.modules_infos.loadXMLTree(child) |
|
295 |
207 |
296 if self.modules_infos is not None: |
208 if self.modules_infos is not None: |
297 vendor = self.modules_infos.getVendor() |
209 vendor = self.modules_infos.getVendor() |
298 |
210 |
299 vendor_category = self.Library.setdefault(ExtractHexDecValue(vendor.getId()), |
211 vendor_category = self.Library.setdefault( |
300 {"name": ExtractName(vendor.getName(), _("Miscellaneous")), |
212 ExtractHexDecValue(vendor.getId()), |
301 "groups": {}}) |
213 {"name": ExtractName(vendor.getName(), _("Miscellaneous")), |
|
214 "groups": {}}) |
302 |
215 |
303 for group in self.modules_infos.getDescriptions().getGroups().getGroup(): |
216 for group in self.groups_xpath(self.modules_infos): |
304 group_type = group.getType() |
217 group_type = group.getType() |
305 |
218 |
306 vendor_category["groups"].setdefault(group_type, {"name": ExtractName(group.getName(), group_type), |
219 vendor_category["groups"].setdefault(group_type, |
307 "parent": group.getParentGroup(), |
220 {"name": ExtractName(group.getName(), group_type), |
308 "order": group.getSortOrder(), |
221 "parent": group.getParentGroup(), |
309 "value": group.getcontent()["value"], |
222 "order": group.getSortOrder(), |
310 "devices": []}) |
223 #"value": group.getcontent()["value"], |
|
224 "devices": []}) |
311 |
225 |
312 for device in self.modules_infos.getDescriptions().getDevices().getDevice(): |
226 for device in self.devices_xpath(self.modules_infos): |
313 device_group = device.getGroupType() |
227 device_group = device.getGroupType() |
314 if not vendor_category["groups"].has_key(device_group): |
228 if not vendor_category["groups"].has_key(device_group): |
315 raise ValueError, "Not such group \"%\"" % device_group |
229 raise ValueError, "Not such group \"%\"" % device_group |
316 vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device)) |
230 vendor_category["groups"][device_group]["devices"].append( |
|
231 (device.getType().getcontent(), device)) |
317 |
232 |
318 return self.Library |
233 return self.Library |
319 |
234 |
320 def GetModulesLibrary(self, profile_filter=None): |
235 def GetModulesLibrary(self, profile_filter=None): |
321 if self.Library is None: |
236 if self.Library is None: |