|
1 #!/usr/bin/env python |
|
2 # -*- coding: utf-8 -*- |
|
3 |
|
4 |
|
5 # This file is part of Beremiz |
|
6 # |
|
7 # Copyright (C) 2013: Real-Time & Embedded Systems (RTES) Lab. University of Seoul, Korea |
|
8 # |
|
9 # See COPYING file for copyrights details. |
|
10 |
|
11 import os |
|
12 import wx |
|
13 |
|
14 mailbox_protocols = ["AoE", "EoE", "CoE", "FoE", "SoE", "VoE"] |
|
15 |
|
16 def ExtractHexDecValue(value): |
|
17 """ |
|
18 convert numerical value in string format into decimal or hex format. |
|
19 @param value : hex or decimal data |
|
20 @return integer data |
|
21 """ |
|
22 try: |
|
23 return int(value) |
|
24 except: |
|
25 pass |
|
26 try: |
|
27 return int(value.replace("#", "0"), 16) |
|
28 |
|
29 except: |
|
30 raise ValueError, "Invalid value for HexDecValue \"%s\"" % value |
|
31 |
|
32 def ExtractName(names, default=None): |
|
33 """ |
|
34 Extract "name" field from XML entries. |
|
35 @param names : XML entry |
|
36 @default : if it fails to extract from the designated XML entry, return the default value ("None"). |
|
37 @return default or the name extracted |
|
38 """ |
|
39 if len(names) == 1: |
|
40 return names[0].getcontent() |
|
41 else: |
|
42 for name in names: |
|
43 if name.getLcId() == 1033: |
|
44 return name.getcontent() |
|
45 return default |
|
46 |
|
47 #-------------------------------------------------- |
|
48 # Remote Exec Etherlab Commands |
|
49 #-------------------------------------------------- |
|
50 |
|
51 # --------------------- for master --------------------------- |
|
52 MASTER_STATE = """ |
|
53 import commands |
|
54 result = commands.getoutput("ethercat master") |
|
55 returnVal =result |
|
56 """ |
|
57 |
|
58 # --------------------- for slave ---------------------------- |
|
59 # ethercat state -p (slave position) (state (INIT, PREOP, SAFEOP, OP)) |
|
60 SLAVE_STATE = """ |
|
61 import commands |
|
62 result = commands.getoutput("ethercat state -p %d %s") |
|
63 returnVal = result |
|
64 """ |
|
65 |
|
66 # ethercat slave |
|
67 GET_SLAVE = """ |
|
68 import commands |
|
69 result = commands.getoutput("ethercat slaves") |
|
70 returnVal =result |
|
71 """ |
|
72 |
|
73 # ethercat xml -p (slave position) |
|
74 SLAVE_XML = """ |
|
75 import commands |
|
76 result = commands.getoutput("ethercat xml -p %d") |
|
77 returnVal = result |
|
78 """ |
|
79 |
|
80 # ethercat sdos -p (slave position) |
|
81 SLAVE_SDO = """ |
|
82 import commands |
|
83 result = commands.getoutput("ethercat sdos -p %d") |
|
84 returnVal =result |
|
85 """ |
|
86 |
|
87 # ethercat upload -p (slave position) (main index) (sub index) |
|
88 GET_SLOW_SDO = """ |
|
89 import commands |
|
90 result = commands.getoutput("ethercat upload -p %d %s %s") |
|
91 returnVal =result |
|
92 """ |
|
93 |
|
94 # ethercat download -p (slave position) (main index) (sub index) (value) |
|
95 SDO_DOWNLOAD = """ |
|
96 import commands |
|
97 result = commands.getoutput("ethercat download --type %s -p %d %s %s %s") |
|
98 returnVal =result |
|
99 """ |
|
100 |
|
101 # ethercat sii_read -p (slave position) |
|
102 SII_READ = """ |
|
103 import commands |
|
104 result = commands.getoutput("ethercat sii_read -p %d") |
|
105 returnVal =result |
|
106 """ |
|
107 |
|
108 # ethercat reg_read -p (slave position) (address) (size) |
|
109 REG_READ = """ |
|
110 import commands |
|
111 result = commands.getoutput("ethercat reg_read -p %d %s %s") |
|
112 returnVal =result |
|
113 """ |
|
114 |
|
115 # ethercat sii_write -p (slave position) - (contents) |
|
116 SII_WRITE = """ |
|
117 import subprocess |
|
118 process = subprocess.Popen( |
|
119 ["ethercat", "-f", "sii_write", "-p", "%d", "-"], |
|
120 stdin=subprocess.PIPE) |
|
121 process.communicate(sii_data) |
|
122 returnVal = process.returncode |
|
123 """ |
|
124 |
|
125 # ethercat reg_write -p (slave position) -t (uinit16) (address) (data) |
|
126 REG_WRITE = """ |
|
127 import commands |
|
128 result = commands.getoutput("ethercat reg_write -p %d -t uint16 %s %s") |
|
129 returnVal =result |
|
130 """ |
|
131 |
|
132 # ethercat rescan -p (slave position) |
|
133 RESCAN = """ |
|
134 import commands |
|
135 result = commands.getoutput("ethercat rescan -p %d") |
|
136 returnVal =result |
|
137 """ |
|
138 |
|
139 #-------------------------------------------------- |
|
140 # Common Method For EtherCAT Management |
|
141 #-------------------------------------------------- |
|
142 class _CommonSlave: |
|
143 |
|
144 # ----- Data Structure for ethercat management ---- |
|
145 SlaveState = "" |
|
146 |
|
147 # category of SDO data |
|
148 DatatypeDescription, CommunicationObject, ManufacturerSpecific, \ |
|
149 ProfileSpecific, Reserved, AllSDOData = range(6) |
|
150 |
|
151 # store the execution result of "ethercat sdos" command into SaveSDOData. |
|
152 SaveSDOData = [] |
|
153 |
|
154 # Flags for checking "write" permission of OD entries |
|
155 CheckPREOP = False |
|
156 CheckSAFEOP = False |
|
157 CheckOP = False |
|
158 |
|
159 # Save PDO Data |
|
160 TxPDOInfo = [] |
|
161 TxPDOCategory = [] |
|
162 RxPDOInfo = [] |
|
163 RxPDOCategory = [] |
|
164 |
|
165 # Save EEPROM Data |
|
166 SiiData = "" |
|
167 |
|
168 # Save Register Data |
|
169 RegData = "" |
|
170 CrtRegSpec = {"ESCType": "", |
|
171 "FMMUNumber": "", |
|
172 "SMNumber": "", |
|
173 "PDIType": ""} |
|
174 |
|
175 def __init__(self, controler): |
|
176 """ |
|
177 Constructor |
|
178 @param controler: _EthercatSlaveCTN class in EthercatSlave.py |
|
179 """ |
|
180 self.Controler = controler |
|
181 |
|
182 self.ClearSDODataSet() |
|
183 |
|
184 #------------------------------------------------------------------------------- |
|
185 # Used Master State |
|
186 #------------------------------------------------------------------------------- |
|
187 def GetMasterState(self): |
|
188 """ |
|
189 Execute "ethercat master" command and parse the execution result |
|
190 @return MasterState |
|
191 """ |
|
192 |
|
193 # exectute "ethercat master" command |
|
194 error, return_val = self.Controler.RemoteExec(MASTER_STATE, return_val = None) |
|
195 master_state = {} |
|
196 # parse the reslut |
|
197 for each_line in return_val.splitlines(): |
|
198 if len(each_line) > 0 : |
|
199 chunks = each_line.strip().split(':', 1) |
|
200 key = chunks[0] |
|
201 value = [] |
|
202 if len(chunks) > 1 : |
|
203 value = chunks[1].split() |
|
204 if '(attached)' in value: |
|
205 value.remove('(attached)') |
|
206 master_state[key] = value |
|
207 |
|
208 return master_state |
|
209 |
|
210 #------------------------------------------------------------------------------- |
|
211 # Used Slave State |
|
212 #------------------------------------------------------------------------------- |
|
213 def RequestSlaveState(self, command): |
|
214 """ |
|
215 Set slave state to the specified one using "ethercat states -p %d %s" command. |
|
216 Command example : "ethercat states -p 0 PREOP" (target slave position and target state are given.) |
|
217 @param command : target slave state |
|
218 """ |
|
219 error, return_val = self.Controler.RemoteExec(SLAVE_STATE%(self.Controler.GetSlavePos(), command), return_val = None) |
|
220 |
|
221 def GetSlaveStateFromSlave(self): |
|
222 """ |
|
223 Get slave information using "ethercat slaves" command and store the information into internal data structure |
|
224 (self.SlaveState) for "Slave State" |
|
225 return_val example : 0 0:0 PREOP + EL9800 (V4.30) (PIC24, SPI, ET1100) |
|
226 """ |
|
227 error, return_val = self.Controler.RemoteExec(GET_SLAVE, return_val = None) |
|
228 self.SlaveState = return_val |
|
229 return return_val |
|
230 |
|
231 #------------------------------------------------------------------------------- |
|
232 # Used SDO Management |
|
233 #------------------------------------------------------------------------------- |
|
234 def GetSlaveSDOFromSlave(self): |
|
235 """ |
|
236 Get SDO objects information of current slave using "ethercat sdos -p %d" command. |
|
237 Command example : "ethercat sdos -p 0" |
|
238 @return return_val : execution results of "ethercat sdos" command (need to be parsed later) |
|
239 """ |
|
240 error, return_val = self.Controler.RemoteExec(SLAVE_SDO%(self.Controler.GetSlavePos()), return_val = None) |
|
241 return return_val |
|
242 |
|
243 def SDODownload(self, data_type, idx, sub_idx, value): |
|
244 """ |
|
245 Set an SDO object value to user-specified value using "ethercat download" command. |
|
246 Command example : "ethercat download --type int32 -p 0 0x8020 0x12 0x00000000" |
|
247 @param data_type : data type of SDO entry |
|
248 @param idx : index of the SDO entry |
|
249 @param sub_idx : subindex of the SDO entry |
|
250 @param value : value of SDO entry |
|
251 """ |
|
252 error, return_val = self.Controler.RemoteExec(SDO_DOWNLOAD%(data_type, self.Controler.GetSlavePos(), idx, sub_idx, value), return_val = None) |
|
253 |
|
254 def BackupSDODataSet(self): |
|
255 """ |
|
256 Back-up current SDO entry information to restore the SDO data |
|
257 in case that the user cancels SDO update operation. |
|
258 """ |
|
259 self.BackupDatatypeDescription = self.SaveDatatypeDescription |
|
260 self.BackupCommunicationObject = self.SaveCommunicationObject |
|
261 self.BackupManufacturerSpecific = self.SaveManufacturerSpecific |
|
262 self.BackupProfileSpecific = self.SaveProfileSpecific |
|
263 self.BackupReserved = self.SaveReserved |
|
264 self.BackupAllSDOData = self.SaveAllSDOData |
|
265 |
|
266 def ClearSDODataSet(self): |
|
267 """ |
|
268 Clear the specified SDO entry information. |
|
269 """ |
|
270 for count in range(6): |
|
271 self.SaveSDOData.append([]) |
|
272 |
|
273 #------------------------------------------------------------------------------- |
|
274 # Used PDO Monitoring |
|
275 #------------------------------------------------------------------------------- |
|
276 def RequestPDOInfo(self): |
|
277 """ |
|
278 Load slave information from RootClass (XML data) and parse the information (calling SlavePDOData() method). |
|
279 """ |
|
280 # Load slave information from ESI XML file (def EthercatMaster.py) |
|
281 slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) |
|
282 |
|
283 type_infos = slave.getType() |
|
284 device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) |
|
285 # Initialize PDO data set |
|
286 self.ClearDataSet() |
|
287 |
|
288 # if 'device' object is valid, call SavePDOData() to parse PDO data |
|
289 if device is not None : |
|
290 self.SavePDOData(device) |
|
291 |
|
292 def SavePDOData(self, device): |
|
293 """ |
|
294 Parse PDO data and store the results in TXPDOCategory and RXPDOCategory |
|
295 Tx(Rx)PDOCategory : index, name, entry number |
|
296 Tx(Rx)Info : entry index, sub index, name, length, type |
|
297 @param device : Slave information extracted from ESI XML file |
|
298 """ |
|
299 # Parsing TXPDO entries |
|
300 for pdo, pdo_info in ([(pdo, "Inputs") for pdo in device.getTxPdo()]): |
|
301 # Save pdo_index, entry, and name of each entry |
|
302 pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) |
|
303 entries = pdo.getEntry() |
|
304 pdo_name = ExtractName(pdo.getName()) |
|
305 |
|
306 # Initialize entry number count |
|
307 count = 0 |
|
308 |
|
309 # Parse entries |
|
310 for entry in entries: |
|
311 # Save index and subindex |
|
312 index = ExtractHexDecValue(entry.getIndex().getcontent()) |
|
313 subindex = ExtractHexDecValue(entry.getSubIndex()) |
|
314 # if entry name exists, save entry data |
|
315 if ExtractName(entry.getName()) is not None : |
|
316 entry_infos = { |
|
317 "entry_index" : index, |
|
318 "subindex" : subindex, |
|
319 "name" : ExtractName(entry.getName()), |
|
320 "bitlen" : entry.getBitLen(), |
|
321 "type" : entry.getDataType().getcontent() |
|
322 } |
|
323 self.TxPDOInfo.append(entry_infos) |
|
324 count += 1 |
|
325 |
|
326 categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count} |
|
327 self.TxPDOCategory.append(categorys) |
|
328 |
|
329 # Parsing RxPDO entries |
|
330 for pdo, pdo_info in ([(pdo, "Outputs") for pdo in device.getRxPdo()]): |
|
331 # Save pdo_index, entry, and name of each entry |
|
332 pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) |
|
333 entries = pdo.getEntry() |
|
334 pdo_name = ExtractName(pdo.getName()) |
|
335 |
|
336 # Initialize entry number count |
|
337 count = 0 |
|
338 |
|
339 # Parse entries |
|
340 for entry in entries: |
|
341 # Save index and subindex |
|
342 index = ExtractHexDecValue(entry.getIndex().getcontent()) |
|
343 subindex = ExtractHexDecValue(entry.getSubIndex()) |
|
344 # if entry name exists, save entry data |
|
345 if ExtractName(entry.getName()) is not None : |
|
346 entry_infos = { |
|
347 "entry_index" : index, |
|
348 "subindex" : subindex, |
|
349 "name" : ExtractName(entry.getName()), |
|
350 "bitlen" : str(entry.getBitLen()), |
|
351 "type" : entry.getDataType().getcontent() |
|
352 } |
|
353 self.RxPDOInfo.append(entry_infos) |
|
354 count += 1 |
|
355 |
|
356 categorys = {"pdo_index" : pdo_index, "name" : pdo_name, "number_of_entry" : count} |
|
357 self.RxPDOCategory.append(categorys) |
|
358 |
|
359 def GetTxPDOCategory(self): |
|
360 """ |
|
361 Get TxPDOCategory data structure (Meta informaton of TxPDO). |
|
362 TxPDOCategorys : index, name, number of entries |
|
363 @return TxPDOCategorys |
|
364 """ |
|
365 return self.TxPDOCategory |
|
366 |
|
367 def GetRxPDOCategory(self): |
|
368 """ |
|
369 Get RxPDOCategory data structure (Meta information of RxPDO). |
|
370 RxPDOCategorys : index, name, number of entries |
|
371 @return RxPDOCategorys |
|
372 """ |
|
373 return self.RxPDOCategory |
|
374 |
|
375 def GetTxPDOInfo(self): |
|
376 """ |
|
377 Get TxPDOInfo data structure (Detailed information on TxPDO entries). |
|
378 TxPDOInfos : entry index, sub index, name, length, type |
|
379 @return TxPDOInfos |
|
380 """ |
|
381 return self.TxPDOInfo |
|
382 |
|
383 def GetRxPDOInfo(self): |
|
384 """ |
|
385 Get RxPDOInfo data structure (Detailed information on RxPDO entries). |
|
386 RxPDOInfos : entry index, sub index, name, length, type |
|
387 @return RxPDOInfos |
|
388 """ |
|
389 return self.RxPDOInfo |
|
390 |
|
391 def ClearDataSet(self): |
|
392 """ |
|
393 Initialize PDO management data structure. |
|
394 """ |
|
395 self.TxPDOInfos = [] |
|
396 self.TxPDOCategorys = [] |
|
397 self.RxPDOInfos = [] |
|
398 self.RxPDOCategorys = [] |
|
399 |
|
400 #------------------------------------------------------------------------------- |
|
401 # Used EEPROM Management |
|
402 #------------------------------------------------------------------------------- |
|
403 # Base data types in ETG2000; format = {"Name": "BitSize"} |
|
404 BaseDataTypeDict = {"BOOL": "01", |
|
405 "SINT": "02", |
|
406 "INT": "03", |
|
407 "DINT": "04", |
|
408 "USINT": "05", |
|
409 "UINT": "06", |
|
410 "UDINT": "07", |
|
411 "REAL": "08", |
|
412 "INT24": "10", |
|
413 "LREAL": "11", |
|
414 "INT40": "12", |
|
415 "INT48": "13", |
|
416 "INT56": "14", |
|
417 "LINT": "15", |
|
418 "UINT24": "16", |
|
419 "UINT40": "18", |
|
420 "UINT48": "19", |
|
421 "UINT56": "1a", |
|
422 "ULINT": "1b", |
|
423 "USINT": "1e", |
|
424 "BITARR8": "2d", |
|
425 "BITARR16": "2e", |
|
426 "BITARR32": "2f", |
|
427 "BIT1": "30", |
|
428 "BIT2": "31", |
|
429 "BIT3": "32", |
|
430 "BIT4": "33", |
|
431 "BIT5": "34", |
|
432 "BIT6": "35", |
|
433 "BIT7": "36", |
|
434 "BIT8": "37"} |
|
435 |
|
436 def GetSmartViewInfos(self): |
|
437 """ |
|
438 Parse XML data for "Smart View" of EEPROM contents. |
|
439 @return smartview_infos : EEPROM contents dictionary |
|
440 """ |
|
441 |
|
442 smartview_infos = {"eeprom_size": 128, |
|
443 "pdi_type": 0, |
|
444 "device_emulation": "False", |
|
445 "vendor_id": '0x00000000', |
|
446 "product_code": '0x00000000', |
|
447 "revision_no": '0x00000000', |
|
448 "serial_no": '0x00000000', |
|
449 "supported_mailbox": "", |
|
450 "mailbox_bootstrapconf_outstart": '0', |
|
451 "mailbox_bootstrapconf_outlength": '0', |
|
452 "mailbox_bootstrapconf_instart": '0', |
|
453 "mailbox_bootstrapconf_inlength": '0', |
|
454 "mailbox_standardconf_outstart": '0', |
|
455 "mailbox_standardconf_outlength": '0', |
|
456 "mailbox_standardconf_instart": '0', |
|
457 "mailbox_standardconf_inlength": '0'} |
|
458 |
|
459 slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) |
|
460 type_infos = slave.getType() |
|
461 device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) |
|
462 |
|
463 # 'device' represents current slave device selected by user |
|
464 if device is not None: |
|
465 for eeprom_element in device.getEeprom().getcontent(): |
|
466 # get EEPROM size; <Device>-<Eeprom>-<ByteSize> |
|
467 if eeprom_element["name"] == "ByteSize": |
|
468 smartview_infos["eeprom_size"] = eeprom_element |
|
469 |
|
470 elif eeprom_element["name"] == "ConfigData": |
|
471 configData_data = self.DecimalToHex(eeprom_element) |
|
472 # get PDI type; <Device>-<Eeprom>-<ConfigData> address 0x00 |
|
473 smartview_infos["pdi_type"] = int(configData_data[0:2], 16) |
|
474 # get state of device emulation; <Device>-<Eeprom>-<ConfigData> address 0x01 |
|
475 if "{:0>8b}".format(int(configData_data[2:4], 16))[7] == '1': |
|
476 smartview_infos["device_emulation"] = "True" |
|
477 |
|
478 elif eeprom_element["name"] == "BootStrap": |
|
479 bootstrap_data = "{:0>16x}".format(eeprom_element) |
|
480 # get bootstrap configuration; <Device>-<Eeprom>-<BootStrap> |
|
481 for cfg, iter in [("mailbox_bootstrapconf_outstart", 0), |
|
482 ("mailbox_bootstrapconf_outlength", 1), |
|
483 ("mailbox_bootstrapconf_instart", 2), |
|
484 ("mailbox_bootstrapconf_inlength", 3)]: |
|
485 smartview_infos[cfg] = str(int(bootstrap_data[4*iter+2:4*(iter+1)]+bootstrap_data[4*iter:4*iter+2], 16)) |
|
486 |
|
487 # get protocol (profile) types supported by mailbox; <Device>-<Mailbox> |
|
488 mb = device.getMailbox() |
|
489 if mb is not None: |
|
490 for mailbox_protocol in mailbox_protocols: |
|
491 if getattr(mb,"get%s"%mailbox_protocol)() is not None: |
|
492 smartview_infos["supported_mailbox"] += "%s, "%mailbox_protocol |
|
493 smartview_infos["supported_mailbox"] = smartview_infos["supported_mailbox"].strip(", ") |
|
494 |
|
495 # get standard configuration of mailbox; <Device>-<Sm> |
|
496 for sm_element in device.getSm(): |
|
497 if sm_element.getcontent() == "MBoxOut": |
|
498 smartview_infos["mailbox_standardconf_outstart"] = str(ExtractHexDecValue(sm_element.getStartAddress())) |
|
499 smartview_infos["mailbox_standardconf_outlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize())) |
|
500 elif sm_element.getcontent() == "MBoxIn": |
|
501 smartview_infos["mailbox_standardconf_instart"] = str(ExtractHexDecValue(sm_element.getStartAddress())) |
|
502 smartview_infos["mailbox_standardconf_inlength"] = str(ExtractHexDecValue(sm_element.getDefaultSize())) |
|
503 else: |
|
504 pass |
|
505 |
|
506 # get device identity from <Device>-<Type> |
|
507 # vendor ID; by default, pre-defined value in self.ModulesLibrary |
|
508 # if device type in 'vendor' item equals to actual slave device type, set 'vendor_id' to vendor ID. |
|
509 for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): |
|
510 for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]: |
|
511 if available_device[0] == type_infos["device_type"]: |
|
512 smartview_infos["vendor_id"] = "0x" + "{:0>8x}".format(vendor_id) |
|
513 |
|
514 # product code; |
|
515 if device.getType().getProductCode() is not None: |
|
516 product_code = device.getType().getProductCode() |
|
517 smartview_infos["product_code"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(product_code)) |
|
518 |
|
519 # revision number; |
|
520 if device.getType().getRevisionNo() is not None: |
|
521 revision_no = device.getType().getRevisionNo() |
|
522 smartview_infos["revision_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(revision_no)) |
|
523 |
|
524 # serial number; |
|
525 if device.getType().getSerialNo() is not None: |
|
526 serial_no = device.getType().getSerialNo() |
|
527 smartview_infos["serial_no"] = "0x"+"{:0>8x}".format(ExtractHexDecValue(serial_no)) |
|
528 |
|
529 return smartview_infos |
|
530 |
|
531 else: |
|
532 return None |
|
533 |
|
534 def DecimalToHex(self, decnum): |
|
535 """ |
|
536 Convert decimal value into hexadecimal representation. |
|
537 @param decnum : decimal value |
|
538 @return hex_data : hexadecimal representation of input value in decimal |
|
539 """ |
|
540 value = "%x" % decnum |
|
541 value_len = len(value) |
|
542 if (value_len % 2) == 0: |
|
543 hex_len = value_len |
|
544 else: |
|
545 hex_len = (value_len / 2) * 2 + 2 |
|
546 |
|
547 hex_data = ("{:0>"+str(hex_len)+"x}").format(decnum) |
|
548 |
|
549 return hex_data |
|
550 |
|
551 def SiiRead(self): |
|
552 """ |
|
553 Get slave EEPROM contents maintained by master device using "ethercat sii_read -p %d" command. |
|
554 Command example : "ethercat sii_read -p 0" |
|
555 @return return_val : result of "ethercat sii_read" (binary data) |
|
556 """ |
|
557 error, return_val = self.Controler.RemoteExec(SII_READ%(self.Controler.GetSlavePos()), return_val = None) |
|
558 self.SiiData = return_val |
|
559 return return_val |
|
560 |
|
561 def SiiWrite(self, binary): |
|
562 """ |
|
563 Overwrite slave EEPROM contents using "ethercat sii_write -p %d" command. |
|
564 Command example : "ethercat sii_write -p 0 - (binary contents)" |
|
565 @param binary : EEPROM contents in binary data format |
|
566 @return return_val : result of "ethercat sii_write" (If it succeeds, the return value is NULL.) |
|
567 """ |
|
568 error, return_val = self.Controler.RemoteExec(SII_WRITE%(self.Controler.GetSlavePos()), return_val = None, sii_data = binary) |
|
569 return return_val |
|
570 |
|
571 def LoadData(self): |
|
572 """ |
|
573 Loading data from EEPROM use Sii_Read Method |
|
574 @return self.BinaryCode : slave EEPROM data in binary format (zero-padded) |
|
575 """ |
|
576 return_val = self.Controler.CommonMethod.SiiRead() |
|
577 self.BinaryCode = return_val |
|
578 self.Controler.SiiData = self.BinaryCode |
|
579 |
|
580 # append zero-filled padding data up to EEPROM size |
|
581 for index in range(self.SmartViewInfosFromXML["eeprom_size"] - len(self.BinaryCode)): |
|
582 self.BinaryCode = self.BinaryCode +'ff'.decode('hex') |
|
583 |
|
584 return self.BinaryCode |
|
585 |
|
586 def HexRead(self, binary): |
|
587 """ |
|
588 Convert binary digit representation into hexadecimal representation for "Hex View" menu. |
|
589 @param binary : binary digits |
|
590 @return hexCode : hexadecimal digits |
|
591 @return hexview_table_row, hexview_table_col : Grid size for "Hex View" UI |
|
592 """ |
|
593 row_code = [] |
|
594 row_text = "" |
|
595 row = 0 |
|
596 hex_code = [] |
|
597 |
|
598 hexview_table_col = 17 |
|
599 |
|
600 for index in range(0, len(binary)) : |
|
601 if len(binary[index]) != 1: |
|
602 break |
|
603 else: |
|
604 digithexstr = hex(ord(binary[index])) |
|
605 |
|
606 tempvar2 = digithexstr[2:4] |
|
607 if len(tempvar2) == 1: |
|
608 tempvar2 = "0" + tempvar2 |
|
609 row_code.append(tempvar2) |
|
610 |
|
611 if int(digithexstr, 16)>=32 and int(digithexstr, 16)<=126: |
|
612 row_text = row_text + chr(int(digithexstr, 16)) |
|
613 else: |
|
614 row_text = row_text + "." |
|
615 |
|
616 if index != 0 : |
|
617 if len(row_code) == (hexview_table_col - 1): |
|
618 row_code.append(row_text) |
|
619 hex_code.append(row_code) |
|
620 row_text = "" |
|
621 row_code = [] |
|
622 row = row + 1 |
|
623 |
|
624 hexview_table_row = row |
|
625 |
|
626 return hex_code, hexview_table_row, hexview_table_col |
|
627 |
|
628 def GenerateEEPROMList(self, data, direction, length): |
|
629 """ |
|
630 Generate EEPROM data list by reconstructing 'data' string. |
|
631 example : data="12345678", direction=0, length=8 -> eeprom_list=['12', '34', '56', '78'] |
|
632 data="12345678", direction=1, length=8 -> eeprom_list=['78', '56', '34', '12'] |
|
633 @param data : string to be reconstructed |
|
634 @param direction : endianness |
|
635 @param length : data length |
|
636 @return eeprom_list : reconstructed list data structure |
|
637 """ |
|
638 eeprom_list = [] |
|
639 |
|
640 if direction is 0 or 1: |
|
641 for i in range(length/2): |
|
642 if data == "": |
|
643 eeprom_list.append("00") |
|
644 else: |
|
645 eeprom_list.append(data[direction*(length-2):direction*(length-2)+2]) |
|
646 data = data[(1-direction)*2:length-direction*2] |
|
647 length -= 2 |
|
648 return eeprom_list |
|
649 |
|
650 def XmlToEeprom(self): |
|
651 """ |
|
652 Extract slave EEPROM contents using slave ESI XML file. |
|
653 - Mandatory parts |
|
654 - String category : ExtractEEPROMStringCategory() |
|
655 - General category : ExtractEEPROMGeneralCategory() |
|
656 - FMMU category : ExtractEEPROMFMMUCategory |
|
657 - SyncM category : ExtractEEPROMSyncMCategory() |
|
658 - Tx/RxPDO category : ExtractEEPROMPDOCategory() |
|
659 - DC category : ExtractEEPROMDCCategory() |
|
660 @return eeprom_binary |
|
661 """ |
|
662 eeprom = [] |
|
663 data = "" |
|
664 eeprom_size = 0 |
|
665 eeprom_binary = "" |
|
666 |
|
667 # 'device' is the slave device of the current EtherCAT slave plugin |
|
668 slave = self.Controler.CTNParent.GetSlave(self.Controler.GetSlavePos()) |
|
669 type_infos = slave.getType() |
|
670 device, alignment = self.Controler.CTNParent.GetModuleInfos(type_infos) |
|
671 |
|
672 if device is not None: |
|
673 # get ConfigData for EEPROM offset 0x0000-0x000d; <Device>-<Eeprom>-<ConfigData> |
|
674 for eeprom_element in device.getEeprom().getcontent(): |
|
675 if eeprom_element["name"] == "ConfigData": |
|
676 data = self.DecimalToHex(eeprom_element) |
|
677 eeprom += self.GenerateEEPROMList(data, 0, 28) |
|
678 |
|
679 # calculate CRC for EEPROM offset 0x000e-0x000f |
|
680 crc = 0x48 |
|
681 for segment in eeprom: |
|
682 for i in range(8): |
|
683 bit = crc & 0x80 |
|
684 crc = (crc << 1) | ((int(segment, 16) >> (7 - i)) & 0x01) |
|
685 if bit: |
|
686 crc ^= 0x07 |
|
687 for k in range(8): |
|
688 bit = crc & 0x80 |
|
689 crc <<= 1 |
|
690 if bit: |
|
691 crc ^= 0x07 |
|
692 eeprom.append(hex(crc)[len(hex(crc))-3:len(hex(crc))-1]) |
|
693 eeprom.append("00") |
|
694 |
|
695 # get VendorID for EEPROM offset 0x0010-0x0013; |
|
696 data = "" |
|
697 for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): |
|
698 for available_device in vendor["groups"][vendor["groups"].keys()[0]]["devices"]: |
|
699 if available_device[0] == type_infos["device_type"]: |
|
700 data = "{:0>8x}".format(vendor_id) |
|
701 eeprom += self.GenerateEEPROMList(data, 1, 8) |
|
702 |
|
703 # get Product Code for EEPROM offset 0x0014-0x0017; |
|
704 data = "" |
|
705 if device.getType().getProductCode() is not None: |
|
706 data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getProductCode())) |
|
707 eeprom += self.GenerateEEPROMList(data, 1, 8) |
|
708 |
|
709 # get Revision Number for EEPROM offset 0x0018-0x001b; |
|
710 data = "" |
|
711 if device.getType().getRevisionNo() is not None: |
|
712 data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getRevisionNo())) |
|
713 eeprom += self.GenerateEEPROMList(data, 1, 8) |
|
714 |
|
715 # get Serial Number for EEPROM 0x001c-0x001f; |
|
716 data = "" |
|
717 if device.getType().getSerialNo() is not None: |
|
718 data = "{:0>8x}".format(ExtractHexDecValue(device.getType().getSerialNo())) |
|
719 eeprom += self.GenerateEEPROMList(data, 1, 8) |
|
720 |
|
721 # get Execution Delay for EEPROM 0x0020-0x0021; not analyzed yet |
|
722 eeprom.append("00") |
|
723 eeprom.append("00") |
|
724 |
|
725 # get Port0/1 Delay for EEPROM offset 0x0022-0x0025; not analyzed yet |
|
726 eeprom.append("00") |
|
727 eeprom.append("00") |
|
728 eeprom.append("00") |
|
729 eeprom.append("00") |
|
730 |
|
731 # reserved for EEPROM offset 0x0026-0x0027; |
|
732 eeprom.append("00") |
|
733 eeprom.append("00") |
|
734 |
|
735 # get BootStrap for EEPROM offset 0x0028-0x002e; <Device>-<Eeprom>-<BootStrap> |
|
736 data = "" |
|
737 for eeprom_element in device.getEeprom().getcontent(): |
|
738 if eeprom_element["name"] == "BootStrap": |
|
739 data = "{:0>16x}".format(eeprom_element) |
|
740 eeprom += self.GenerateEEPROMList(data, 0, 16) |
|
741 |
|
742 # get Standard Mailbox for EEPROM offset 0x0030-0x0037; <Device>-<sm> |
|
743 data = "" |
|
744 standard_send_mailbox_offset = None |
|
745 standard_send_mailbox_size = None |
|
746 standard_receive_mailbox_offset = None |
|
747 standard_receive_mailbox_size = None |
|
748 for sm_element in device.getSm(): |
|
749 if sm_element.getcontent() == "MBoxOut": |
|
750 standard_receive_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress())) |
|
751 standard_receive_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize())) |
|
752 elif sm_element.getcontent() == "MBoxIn": |
|
753 standard_send_mailbox_offset = "{:0>4x}".format(ExtractHexDecValue(sm_element.getStartAddress())) |
|
754 standard_send_mailbox_size = "{:0>4x}".format(ExtractHexDecValue(sm_element.getDefaultSize())) |
|
755 |
|
756 if standard_receive_mailbox_offset is None: |
|
757 eeprom.append("00") |
|
758 eeprom.append("00") |
|
759 else: |
|
760 eeprom.append(standard_receive_mailbox_offset[2:4]) |
|
761 eeprom.append(standard_receive_mailbox_offset[0:2]) |
|
762 if standard_receive_mailbox_size is None: |
|
763 eeprom.append("00") |
|
764 eeprom.append("00") |
|
765 else: |
|
766 eeprom.append(standard_receive_mailbox_size[2:4]) |
|
767 eeprom.append(standard_receive_mailbox_size[0:2]) |
|
768 if standard_send_mailbox_offset is None: |
|
769 eeprom.append("00") |
|
770 eeprom.append("00") |
|
771 else: |
|
772 eeprom.append(standard_send_mailbox_offset[2:4]) |
|
773 eeprom.append(standard_send_mailbox_offset[0:2]) |
|
774 if standard_send_mailbox_size is None: |
|
775 eeprom.append("00") |
|
776 eeprom.append("00") |
|
777 else: |
|
778 eeprom.append(standard_send_mailbox_size[2:4]) |
|
779 eeprom.append(standard_send_mailbox_size[0:2]) |
|
780 |
|
781 # get supported mailbox protocols for EEPROM offset 0x0038-0x0039; |
|
782 data = 0 |
|
783 mb = device.getMailbox() |
|
784 if mb is not None : |
|
785 for bit,mbprot in enumerate(mailbox_protocols): |
|
786 if getattr(mb,"get%s"%mbprot)() is not None: |
|
787 data += 1<<bit |
|
788 data = "{:0>4x}".format(data) |
|
789 eeprom.append(data[2:4]) |
|
790 eeprom.append(data[0:2]) |
|
791 |
|
792 # resereved for EEPROM offset 0x003a-0x007b; |
|
793 for i in range(0x007b-0x003a+0x0001): |
|
794 eeprom.append("00") |
|
795 |
|
796 # get EEPROM size for EEPROM offset 0x007c-0x007d; |
|
797 data = "" |
|
798 for eeprom_element in device.getEeprom().getcontent(): |
|
799 if eeprom_element["name"] == "ByteSize": |
|
800 eeprom_size = int(str(eeprom_element)) |
|
801 data = "{:0>4x}".format(int(eeprom_element)/1024*8-1) |
|
802 |
|
803 if data == "": |
|
804 eeprom.append("00") |
|
805 eeprom.append("00") |
|
806 else: |
|
807 eeprom.append(data[2:4]) |
|
808 eeprom.append(data[0:2]) |
|
809 |
|
810 # Version for EEPROM 0x007e-0x007f; |
|
811 # According to "EtherCAT Slave Device Description(V0.3.0)" |
|
812 eeprom.append("01") |
|
813 eeprom.append("00") |
|
814 |
|
815 # append String Category data |
|
816 for data in self.ExtractEEPROMStringCategory(device): |
|
817 eeprom.append(data) |
|
818 |
|
819 # append General Category data |
|
820 for data in self.ExtractEEPROMGeneralCategory(device): |
|
821 eeprom.append(data) |
|
822 |
|
823 # append FMMU Category data |
|
824 for data in self.ExtractEEPROMFMMUCategory(device): |
|
825 eeprom.append(data) |
|
826 |
|
827 # append SyncM Category data |
|
828 for data in self.ExtractEEPROMSyncMCategory(device): |
|
829 eeprom.append(data) |
|
830 |
|
831 # append TxPDO Category data |
|
832 for data in self.ExtractEEPROMPDOCategory(device, "TxPdo"): |
|
833 eeprom.append(data) |
|
834 |
|
835 # append RxPDO Category data |
|
836 for data in self.ExtractEEPROMPDOCategory(device, "RxPdo"): |
|
837 eeprom.append(data) |
|
838 |
|
839 # append DC Category data |
|
840 for data in self.ExtractEEPROMDCCategory(device): |
|
841 eeprom.append(data) |
|
842 |
|
843 # append padding |
|
844 padding = eeprom_size-len(eeprom) |
|
845 for i in range(padding): |
|
846 eeprom.append("ff") |
|
847 |
|
848 # convert binary code |
|
849 for index in range(eeprom_size): |
|
850 eeprom_binary = eeprom_binary + eeprom[index].decode('hex') |
|
851 |
|
852 return eeprom_binary |
|
853 |
|
854 def ExtractEEPROMStringCategory(self, device): |
|
855 """ |
|
856 Extract "Strings" category data from slave ESI XML and generate EEPROM image data. |
|
857 @param device : 'device' object in the slave ESI XML |
|
858 @return eeprom : "Strings" category EEPROM image data |
|
859 """ |
|
860 eeprom = [] |
|
861 self.Strings = [] |
|
862 data = "" |
|
863 count = 0 # string counter |
|
864 padflag = False # padding flag if category length is odd |
|
865 |
|
866 # index information for General Category in EEPROM |
|
867 self.GroupIdx = 0 |
|
868 self.ImgIdx = 0 |
|
869 self.OrderIdx = 0 |
|
870 self.NameIdx = 0 |
|
871 |
|
872 # flag for preventing duplicated vendor specific data |
|
873 typeflag = False |
|
874 grouptypeflag = False |
|
875 groupnameflag = False |
|
876 devnameflag = False |
|
877 imageflag = False |
|
878 |
|
879 # vendor specific data |
|
880 # element1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Type> |
|
881 # vendor_specific_data : vendor specific data (binary type) |
|
882 vendor_specific_data = "" |
|
883 # vendor_spec_strings : list of vendor specific "strings" for preventing duplicated strings |
|
884 vendor_spec_strings = [] |
|
885 for element in device.getType().getcontent(): |
|
886 data += element |
|
887 if data is not "" and type(data) == unicode: |
|
888 for vendor_spec_string in vendor_spec_strings: |
|
889 if data == vendor_spec_string: |
|
890 self.OrderIdx = vendor_spec_strings.index(data)+1 |
|
891 typeflag = True |
|
892 break |
|
893 if typeflag is False: |
|
894 count += 1 |
|
895 self.Strings.append(data) |
|
896 vendor_spec_strings.append(data) |
|
897 typeflag = True |
|
898 self.OrderIdx = count |
|
899 vendor_specific_data += "{:0>2x}".format(len(data)) |
|
900 for character in range(len(data)): |
|
901 vendor_specific_data += "{:0>2x}".format(ord(data[character])) |
|
902 data = "" |
|
903 |
|
904 # element2-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<GroupType> |
|
905 data = device.getGroupType() |
|
906 if data is not None and type(data) == unicode: |
|
907 for vendor_spec_string in vendor_spec_strings: |
|
908 if data == vendor_spec_string: |
|
909 self.GroupIdx = vendor_spec_strings.index(data)+1 |
|
910 grouptypeflag = True |
|
911 break |
|
912 if grouptypeflag is False: |
|
913 grouptype = data |
|
914 count += 1 |
|
915 self.Strings.append(data) |
|
916 vendor_spec_strings.append(data) |
|
917 grouptypeflag = True |
|
918 self.GroupIdx = count |
|
919 vendor_specific_data += "{:0>2x}".format(len(data)) |
|
920 for character in range(len(data)): |
|
921 vendor_specific_data += "{:0>2x}".format(ord(data[character])) |
|
922 |
|
923 # element2-2; <EtherCATInfo>-<Groups>-<Group>-<Type> |
|
924 if grouptypeflag is False: |
|
925 if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: |
|
926 for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): |
|
927 for group_type, group_etc in vendor["groups"].iteritems(): |
|
928 for device_item in group_etc["devices"]: |
|
929 if device == device_item[1]: |
|
930 data = group_type |
|
931 if data is not None and type(data) == unicode: |
|
932 for vendor_spec_string in vendor_spec_strings: |
|
933 if data == vendor_spec_string: |
|
934 self.GroupIdx = vendor_spec_strings.index(data)+1 |
|
935 grouptypeflag = True |
|
936 break |
|
937 if grouptypeflag is False: |
|
938 grouptype = data |
|
939 count += 1 |
|
940 self.Strings.append(data) |
|
941 vendor_spec_strings.append(data) |
|
942 grouptypeflag = True |
|
943 self.GroupIdx = count |
|
944 vendor_specific_data += "{:0>2x}".format(len(data)) |
|
945 for character in range(len(data)): |
|
946 vendor_specific_data += "{:0>2x}".format(ord(data[character])) |
|
947 data = "" |
|
948 |
|
949 # element3; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Name(LcId is "1033")> |
|
950 if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: |
|
951 for vendorId, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): |
|
952 for group_type, group_etc in vendor["groups"].iteritems(): |
|
953 for device_item in group_etc["devices"]: |
|
954 if device == device_item[1]: |
|
955 data = group_etc["name"] |
|
956 if data is not "" and type(data) == unicode: |
|
957 for vendor_spec_string in vendor_spec_strings: |
|
958 if data == vendor_spec_string: |
|
959 groupnameflag = True |
|
960 break |
|
961 if groupnameflag is False: |
|
962 count += 1 |
|
963 self.Strings.append(data) |
|
964 vendor_spec_strings.append(data) |
|
965 groupnameflag = True |
|
966 vendor_specific_data += "{:0>2x}".format(len(data)) |
|
967 for character in range(len(data)): |
|
968 vendor_specific_data += "{:0>2x}".format(ord(data[character])) |
|
969 data = "" |
|
970 |
|
971 # element4; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Name(LcId is "1033" or "1"?)> |
|
972 for element in device.getName(): |
|
973 if element.getLcId() == 1 or element.getLcId()==1033: |
|
974 data = element.getcontent() |
|
975 if data is not "" and type(data) == unicode: |
|
976 for vendor_spec_string in vendor_spec_strings: |
|
977 if data == vendor_spec_string: |
|
978 self.NameIdx = vendor_spec_strings.index(data)+1 |
|
979 devnameflag = True |
|
980 break |
|
981 if devnameflag is False: |
|
982 count += 1 |
|
983 self.Strings.append(data) |
|
984 vendor_spec_strings.append(data) |
|
985 devnameflag = True |
|
986 self.NameIdx = count |
|
987 vendor_specific_data += "{:0>2x}".format(len(data)) |
|
988 for character in range(len(data)): |
|
989 vendor_specific_data += "{:0>2x}".format(ord(data[character])) |
|
990 data = "" |
|
991 |
|
992 # element5-1; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Image16x14> |
|
993 if device.getcontent() is not None: |
|
994 data = device.getcontent() |
|
995 if data is not None and type(data) == unicode: |
|
996 for vendor_spec_string in vendor_spec_strings: |
|
997 if data == vendor_spec_string: |
|
998 self.ImgIdx = vendor_spec_strings.index(data)+1 |
|
999 imageflag = True |
|
1000 break |
|
1001 if imageflag is False: |
|
1002 count += 1 |
|
1003 self.Strings.append(data) |
|
1004 vendor_spec_strings.append(data) |
|
1005 imageflag = True |
|
1006 self.ImgIdx = count |
|
1007 vendor_specific_data += "{:0>2x}".format(len(data)) |
|
1008 for character in range(len(data)): |
|
1009 vendor_specific_data += "{:0>2x}".format(ord(data[character])) |
|
1010 |
|
1011 # element5-2; <EtherCATInfo>-<Descriptions>-<Groups>-<Group>-<Image16x14> |
|
1012 if imageflag is False: |
|
1013 if self.Controler.CTNParent.CTNParent.ModulesLibrary.Library is not None: |
|
1014 for vendor_id, vendor in self.Controler.CTNParent.CTNParent.ModulesLibrary.Library.iteritems(): |
|
1015 for group_type, group_etc in vendor["groups"].iteritems(): |
|
1016 for device_item in group_etc["devices"]: |
|
1017 if device == device_item[1]: |
|
1018 data = group_etc |
|
1019 if data is not None and type(data) == unicode: |
|
1020 for vendor_spec_string in vendor_spec_strings: |
|
1021 if data == vendor_spec_string: |
|
1022 self.ImgIdx = vendor_spec_strings.index(data)+1 |
|
1023 imageflag = True |
|
1024 break |
|
1025 if imageflag is False: |
|
1026 count += 1 |
|
1027 self.Strings.append(data) |
|
1028 vendor_spec_strings.append(data) |
|
1029 imageflag = True |
|
1030 self.ImgIdx = count |
|
1031 vendor_specific_data += "{:0>2x}".format(len(data)) |
|
1032 for character in range(len(data)): |
|
1033 vendor_specific_data += "{:0>2x}".format(ord(data[character])) |
|
1034 data = "" |
|
1035 |
|
1036 # DC related elements |
|
1037 # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Dc>-<OpMode>-<Name> |
|
1038 dc_related_elements = "" |
|
1039 if device.getDc() is not None: |
|
1040 for element in device.getDc().getOpMode(): |
|
1041 data = element.getName() |
|
1042 if data is not "": |
|
1043 count += 1 |
|
1044 self.Strings.append(data) |
|
1045 dc_related_elements += "{:0>2x}".format(len(data)) |
|
1046 for character in range(len(data)): |
|
1047 dc_related_elements += "{:0>2x}".format(ord(data[character])) |
|
1048 data = "" |
|
1049 |
|
1050 # Input elements(TxPDO) |
|
1051 # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<TxPdo>; Name |
|
1052 input_elements = "" |
|
1053 inputs = [] |
|
1054 for element in device.getTxPdo(): |
|
1055 for name in element.getName(): |
|
1056 data = name.getcontent() |
|
1057 for input in inputs: |
|
1058 if data == input: |
|
1059 data = "" |
|
1060 if data is not "": |
|
1061 count += 1 |
|
1062 self.Strings.append(data) |
|
1063 inputs.append(data) |
|
1064 input_elements += "{:0>2x}".format(len(data)) |
|
1065 for character in range(len(data)): |
|
1066 input_elements += "{:0>2x}".format(ord(data[character])) |
|
1067 data = "" |
|
1068 for entry in element.getEntry(): |
|
1069 for name in entry.getName(): |
|
1070 data = name.getcontent() |
|
1071 for input in inputs: |
|
1072 if data == input: |
|
1073 data = "" |
|
1074 if data is not "": |
|
1075 count += 1 |
|
1076 self.Strings.append(data) |
|
1077 inputs.append(data) |
|
1078 input_elements += "{:0>2x}".format(len(data)) |
|
1079 for character in range(len(data)): |
|
1080 input_elements += "{:0>2x}".format(ord(data[character])) |
|
1081 data = "" |
|
1082 |
|
1083 # Output elements(RxPDO) |
|
1084 # <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<RxPdo>; Name |
|
1085 output_elements = "" |
|
1086 outputs = [] |
|
1087 for element in device.getRxPdo(): |
|
1088 for name in element.getName(): |
|
1089 data = name.getcontent() |
|
1090 for output in outputs: |
|
1091 if data == output: |
|
1092 data = "" |
|
1093 if data is not "": |
|
1094 count += 1 |
|
1095 self.Strings.append(data) |
|
1096 outputs.append(data) |
|
1097 output_elements += "{:0>2x}".format(len(data)) |
|
1098 for character in range(len(data)): |
|
1099 output_elements += "{:0>2x}".format(ord(data[character])) |
|
1100 data = "" |
|
1101 for entry in element.getEntry(): |
|
1102 for name in entry.getName(): |
|
1103 data = name.getcontent() |
|
1104 for output in outputs: |
|
1105 if data == output: |
|
1106 data = "" |
|
1107 if data is not "": |
|
1108 count += 1 |
|
1109 self.Strings.append(data) |
|
1110 outputs.append(data) |
|
1111 output_elements += "{:0>2x}".format(len(data)) |
|
1112 for character in range(len(data)): |
|
1113 output_elements += "{:0>2x}".format(ord(data[character])) |
|
1114 data = "" |
|
1115 |
|
1116 # form eeprom data |
|
1117 # category header |
|
1118 eeprom.append("0a") |
|
1119 eeprom.append("00") |
|
1120 # category length (word); 1 word is 4 bytes. "+2" is the length of string's total number |
|
1121 length = len(vendor_specific_data + dc_related_elements + input_elements + output_elements) + 2 |
|
1122 if length%4 == 0: |
|
1123 pass |
|
1124 else: |
|
1125 length +=length%4 |
|
1126 padflag = True |
|
1127 eeprom.append("{:0>4x}".format(length/4)[2:4]) |
|
1128 eeprom.append("{:0>4x}".format(length/4)[0:2]) |
|
1129 # total numbers of strings |
|
1130 eeprom.append("{:0>2x}".format(count)) |
|
1131 for element in [vendor_specific_data, |
|
1132 dc_related_elements, |
|
1133 input_elements, |
|
1134 output_elements]: |
|
1135 for iter in range(len(element)/2): |
|
1136 if element == "": |
|
1137 eeprom.append("00") |
|
1138 else: |
|
1139 eeprom.append(element[0:2]) |
|
1140 element = element[2:len(element)] |
|
1141 # padding if length is odd bytes |
|
1142 if padflag is True: |
|
1143 eeprom.append("ff") |
|
1144 |
|
1145 return eeprom |
|
1146 |
|
1147 def ExtractEEPROMGeneralCategory(self, device): |
|
1148 """ |
|
1149 Extract "General" category data from slave ESI XML and generate EEPROM image data. |
|
1150 @param device : 'device' object in the slave ESI XML |
|
1151 @return eeprom : "Strings" category EEPROM image data |
|
1152 """ |
|
1153 eeprom = [] |
|
1154 data = "" |
|
1155 |
|
1156 # category header |
|
1157 eeprom.append("1e") |
|
1158 eeprom.append("00") |
|
1159 |
|
1160 # category length |
|
1161 eeprom.append("10") |
|
1162 eeprom.append("00") |
|
1163 |
|
1164 # word 1 : Group Type index and Image index in STRINGS Category |
|
1165 eeprom.append("{:0>2x}".format(self.GroupIdx)) |
|
1166 eeprom.append("{:0>2x}".format(self.ImgIdx)) |
|
1167 |
|
1168 # word 2 : Device Type index and Device Name index in STRINGS Category |
|
1169 eeprom.append("{:0>2x}".format(self.OrderIdx)) |
|
1170 eeprom.append("{:0>2x}".format(self.NameIdx)) |
|
1171 |
|
1172 # word 3 : Physical Layer Port info. and CoE Details |
|
1173 eeprom.append("01") # Physical Layer Port info - assume 01 |
|
1174 # CoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE> |
|
1175 coe_details = 0 |
|
1176 mb = device.getMailbox() |
|
1177 coe_details = 1 # sdo enabled |
|
1178 if mb is not None : |
|
1179 coe = mb.getCoE() |
|
1180 if coe is not None: |
|
1181 for bit,flag in enumerate(["SdoInfo", "PdoAssign", "PdoConfig", |
|
1182 "PdoUpload", "CompleteAccess"]): |
|
1183 if getattr(coe,"get%s"%flag)() is not None: |
|
1184 coe_details += 1<<bit |
|
1185 eeprom.append("{:0>2x}".format(coe_details)) |
|
1186 |
|
1187 # word 4 : FoE Details and EoE Details |
|
1188 # FoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<FoE> |
|
1189 if mb is not None and mb.getFoE() is not None: |
|
1190 eeprom.append("01") |
|
1191 else: |
|
1192 eeprom.append("00") |
|
1193 # EoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<EoE> |
|
1194 if mb is not None and mb.getEoE() is not None: |
|
1195 eeprom.append("01") |
|
1196 else: |
|
1197 eeprom.append("00") |
|
1198 |
|
1199 # word 5 : SoE Channels(reserved) and DS402 Channels |
|
1200 # SoE Details; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<SoE> |
|
1201 if mb is not None and mb.getSoE() is not None: |
|
1202 eeprom.append("01") |
|
1203 else: |
|
1204 eeprom.append("00") |
|
1205 # DS402Channels; <EtherCATInfo>-<Descriptions>-<Devices>-<Device>-<Mailbox>-<CoE>: DS402Channels |
|
1206 ds402ch = False |
|
1207 if mb is not None : |
|
1208 coe = mb.getCoE() |
|
1209 if coe is not None : |
|
1210 ds402ch = coe.getDS402Channels() |
|
1211 eeprom.append("01" if ds402ch in [True,1] else "00") |
|
1212 |
|
1213 # word 6 : SysmanClass(reserved) and Flags |
|
1214 eeprom.append("00") # reserved |
|
1215 # Flags |
|
1216 en_safeop = False |
|
1217 en_lrw = False |
|
1218 if device.getType().getTcCfgModeSafeOp() == True \ |
|
1219 or device.getType().getTcCfgModeSafeOp() == 1: |
|
1220 en_safeop = True |
|
1221 if device.getType().getUseLrdLwr() == True \ |
|
1222 or device.getType().getUseLrdLwr() == 1: |
|
1223 en_lrw = True |
|
1224 |
|
1225 flags = "0b"+"000000"+str(int(en_lrw))+str(int(en_safeop)) |
|
1226 eeprom.append("{:0>2x}".format(int(flags, 2))) |
|
1227 |
|
1228 # word 7 : Current On EBus (assume 0x0000) |
|
1229 eeprom.append("00") |
|
1230 eeprom.append("00") |
|
1231 # after word 7; couldn't analyze yet |
|
1232 eeprom.append("03") |
|
1233 eeprom.append("00") |
|
1234 eeprom.append("11") |
|
1235 eeprom.append("00") |
|
1236 eeprom.append("00") |
|
1237 eeprom.append("00") |
|
1238 eeprom.append("00") |
|
1239 eeprom.append("00") |
|
1240 eeprom.append("00") |
|
1241 eeprom.append("00") |
|
1242 eeprom.append("00") |
|
1243 eeprom.append("00") |
|
1244 eeprom.append("00") |
|
1245 eeprom.append("00") |
|
1246 eeprom.append("00") |
|
1247 eeprom.append("00") |
|
1248 eeprom.append("00") |
|
1249 eeprom.append("00") |
|
1250 |
|
1251 return eeprom |
|
1252 |
|
1253 def ExtractEEPROMFMMUCategory(self, device): |
|
1254 """ |
|
1255 Extract "FMMU" category data from slave ESI XML and generate EEPROM image data. |
|
1256 @param device : 'device' object in the slave ESI XML |
|
1257 @return eeprom : "Strings" category EEPROM image data |
|
1258 """ |
|
1259 eeprom = [] |
|
1260 data = "" |
|
1261 count = 0 # number of FMMU |
|
1262 padflag = False |
|
1263 |
|
1264 for fmmu in device.getFmmu(): |
|
1265 count += 1 |
|
1266 if fmmu.getcontent() == "Outputs": |
|
1267 data += "01" |
|
1268 if fmmu.getcontent() == "Inputs": |
|
1269 data += "02" |
|
1270 if fmmu.getcontent() == "MBoxState": |
|
1271 data += "03" |
|
1272 |
|
1273 # construct of EEPROM data |
|
1274 if data is not "": |
|
1275 # category header |
|
1276 eeprom.append("28") |
|
1277 eeprom.append("00") |
|
1278 # category length |
|
1279 if count%2 == 1: |
|
1280 padflag = True |
|
1281 eeprom.append("{:0>4x}".format((count+1)/2)[2:4]) |
|
1282 eeprom.append("{:0>4x}".format((count+1)/2)[0:2]) |
|
1283 else: |
|
1284 eeprom.append("{:0>4x}".format((count)/2)[2:4]) |
|
1285 eeprom.append("{:0>4x}".format((count)/2)[0:2]) |
|
1286 for i in range(count): |
|
1287 if data == "": |
|
1288 eeprom.append("00") |
|
1289 else: |
|
1290 eeprom.append(data[0:2]) |
|
1291 data = data[2:len(data)] |
|
1292 # padding if length is odd bytes |
|
1293 if padflag is True: |
|
1294 eeprom.append("ff") |
|
1295 |
|
1296 return eeprom |
|
1297 |
|
1298 def ExtractEEPROMSyncMCategory(self, device): |
|
1299 """ |
|
1300 Extract "SyncM" category data from slave ESI XML and generate EEPROM image data. |
|
1301 @param device : 'device' object in the slave ESI XML |
|
1302 @return eeprom : "Strings" category EEPROM image data |
|
1303 """ |
|
1304 eeprom = [] |
|
1305 data = "" |
|
1306 number = {"MBoxOut":"01", "MBoxIn":"02", "Outputs":"03", "Inputs":"04"} |
|
1307 |
|
1308 for sm in device.getSm(): |
|
1309 for attr in [sm.getStartAddress(), |
|
1310 sm.getDefaultSize(), |
|
1311 sm.getControlByte()]: |
|
1312 if attr is not None: |
|
1313 data += "{:0>4x}".format(ExtractHexDecValue(attr))[2:4] |
|
1314 data += "{:0>4x}".format(ExtractHexDecValue(attr))[0:2] |
|
1315 else: |
|
1316 data += "0000" |
|
1317 if sm.getEnable() == "1" or sm.getEnable() == True: |
|
1318 data += "01" |
|
1319 else: |
|
1320 data += "00" |
|
1321 data += number[sm.getcontent()] |
|
1322 |
|
1323 if data is not "": |
|
1324 # category header |
|
1325 eeprom.append("29") |
|
1326 eeprom.append("00") |
|
1327 # category length |
|
1328 eeprom.append("{:0>4x}".format(len(data)/4)[2:4]) |
|
1329 eeprom.append("{:0>4x}".format(len(data)/4)[0:2]) |
|
1330 for i in range(len(data)/2): |
|
1331 if data == "": |
|
1332 eeprom.append("00") |
|
1333 else: |
|
1334 eeprom.append(data[0:2]) |
|
1335 data = data[2:len(data)] |
|
1336 |
|
1337 return eeprom |
|
1338 |
|
1339 def ExtractEEPROMPDOCategory(self, device, pdotype): |
|
1340 """ |
|
1341 Extract ""PDO (Tx, Rx)"" category data from slave ESI XML and generate EEPROM image data. |
|
1342 @param device : 'device' object in the slave ESI XML |
|
1343 @param pdotype : identifier whether "TxPDO" or "RxPDO". |
|
1344 @return eeprom : "Strings" category EEPROM image data |
|
1345 """ |
|
1346 eeprom = [] |
|
1347 data = "" |
|
1348 count = 0 |
|
1349 en_fixed = False |
|
1350 en_mandatory = False |
|
1351 en_virtual = False |
|
1352 |
|
1353 for element in eval("device.get%s()"%pdotype): |
|
1354 # PDO Index |
|
1355 data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[2:4] |
|
1356 data += "{:0>4x}".format(ExtractHexDecValue(element.getIndex().getcontent()))[0:2] |
|
1357 # Number of Entries |
|
1358 data += "{:0>2x}".format(len(element.getEntry())) |
|
1359 # About Sync Manager |
|
1360 if element.getSm() is not None: |
|
1361 data += "{:0>2x}".format(element.getSm()) |
|
1362 else: |
|
1363 data += "ff" |
|
1364 # Reference to DC Synch (according to ET1100 documentation) - assume 0 |
|
1365 data += "00" |
|
1366 # Name Index |
|
1367 objname = "" |
|
1368 for name in element.getName(): |
|
1369 objname = name.getcontent() |
|
1370 for name in self.Strings: |
|
1371 count += 1 |
|
1372 if objname == name: |
|
1373 break |
|
1374 if len(self.Strings)+1 == count: |
|
1375 data += "00" |
|
1376 else: |
|
1377 data += "{:0>2x}".format(count) |
|
1378 count = 0 |
|
1379 # Flags; by Fixed, Mandatory, Virtual attributes ? |
|
1380 if element.getFixed() == True or 1: |
|
1381 en_fixed = True |
|
1382 if element.getMandatory() == True or 1: |
|
1383 en_mandatory = True |
|
1384 if element.getVirtual() == True or element.getVirtual(): |
|
1385 en_virtual = True |
|
1386 data += str(int(en_fixed)) + str(int(en_mandatory)) + str(int(en_virtual)) + "0" |
|
1387 |
|
1388 for entry in element.getEntry(): |
|
1389 # Entry Index |
|
1390 data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[2:4] |
|
1391 data += "{:0>4x}".format(ExtractHexDecValue(entry.getIndex().getcontent()))[0:2] |
|
1392 # Subindex |
|
1393 data += "{:0>2x}".format(int(entry.getSubIndex())) |
|
1394 # Entry Name Index |
|
1395 objname = "" |
|
1396 for name in entry.getName(): |
|
1397 objname = name.getcontent() |
|
1398 for name in self.Strings: |
|
1399 count += 1 |
|
1400 if objname == name: |
|
1401 break |
|
1402 if len(self.Strings)+1 == count: |
|
1403 data += "00" |
|
1404 else: |
|
1405 data += "{:0>2x}".format(count) |
|
1406 count = 0 |
|
1407 # DataType |
|
1408 if entry.getDataType() is not None: |
|
1409 if entry.getDataType().getcontent() in self.BaseDataTypeDict: |
|
1410 data += self.BaseDataTypeDict[entry.getDataType().getcontent()] |
|
1411 else: |
|
1412 data += "00" |
|
1413 else: |
|
1414 data += "00" |
|
1415 # BitLen |
|
1416 if entry.getBitLen() is not None: |
|
1417 data += "{:0>2x}".format(int(entry.getBitLen())) |
|
1418 else: |
|
1419 data += "00" |
|
1420 # Flags; by Fixed attributes ? |
|
1421 en_fixed = False |
|
1422 if entry.getFixed() == True or entry.getFixed() == 1: |
|
1423 en_fixed = True |
|
1424 data += str(int(en_fixed)) + "000" |
|
1425 |
|
1426 if data is not "": |
|
1427 # category header |
|
1428 if pdotype == "TxPdo": |
|
1429 eeprom.append("32") |
|
1430 elif pdotype == "RxPdo": |
|
1431 eeprom.append("33") |
|
1432 else: |
|
1433 eeprom.append("00") |
|
1434 eeprom.append("00") |
|
1435 # category length |
|
1436 eeprom.append("{:0>4x}".format(len(data)/4)[2:4]) |
|
1437 eeprom.append("{:0>4x}".format(len(data)/4)[0:2]) |
|
1438 data = str(data.lower()) |
|
1439 for i in range(len(data)/2): |
|
1440 if data == "": |
|
1441 eeprom.append("00") |
|
1442 else: |
|
1443 eeprom.append(data[0:2]) |
|
1444 data = data[2:len(data)] |
|
1445 |
|
1446 return eeprom |
|
1447 |
|
1448 def ExtractEEPROMDCCategory(self, device): |
|
1449 """ |
|
1450 Extract "DC(Distributed Clock)" category data from slave ESI XML and generate EEPROM image data. |
|
1451 @param device : 'device' object in the slave ESI XML |
|
1452 @return eeprom : "Strings" category EEPROM image data |
|
1453 """ |
|
1454 eeprom = [] |
|
1455 data = "" |
|
1456 count = 0 |
|
1457 namecount = 0 |
|
1458 |
|
1459 if device.getDc() is not None: |
|
1460 for element in device.getDc().getOpMode(): |
|
1461 count += 1 |
|
1462 # assume that word 1-7 are 0x0000 |
|
1463 data += "0000" |
|
1464 data += "0000" |
|
1465 data += "0000" |
|
1466 data += "0000" |
|
1467 data += "0000" |
|
1468 data += "0000" |
|
1469 data += "0000" |
|
1470 # word 8-10 |
|
1471 # AssignActivate |
|
1472 if element.getAssignActivate() is not None: |
|
1473 data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[2:4] |
|
1474 data += "{:0>4x}".format(ExtractHexDecValue(element.getAssignActivate()))[0:2] |
|
1475 else: |
|
1476 data += "0000" |
|
1477 # Factor of CycleTimeSync0 ? and default is 1? |
|
1478 if element.getCycleTimeSync0() is not None: |
|
1479 if element.getCycleTimeSync0().getFactor() is not None: |
|
1480 data += "{:0>2x}".format(int(element.getCycleTimeSync0().getFactor())) |
|
1481 data += "00" |
|
1482 else: |
|
1483 data += "0100" |
|
1484 else: |
|
1485 data += "0100" |
|
1486 # Index of Name in STRINGS Category |
|
1487 # Name Index |
|
1488 objname = "" |
|
1489 for name in element.getName(): |
|
1490 objname += name |
|
1491 for name in self.Strings: |
|
1492 namecount += 1 |
|
1493 if objname == name: |
|
1494 break |
|
1495 if len(self.Strings)+1 == namecount: |
|
1496 data += "00" |
|
1497 else: |
|
1498 data += "{:0>2x}".format(namecount) |
|
1499 namecount = 0 |
|
1500 data += "00" |
|
1501 # assume that word 11-12 are 0x0000 |
|
1502 data += "0000" |
|
1503 data += "0000" |
|
1504 |
|
1505 if data is not "": |
|
1506 # category header |
|
1507 eeprom.append("3c") |
|
1508 eeprom.append("00") |
|
1509 # category length |
|
1510 eeprom.append("{:0>4x}".format(len(data)/4)[2:4]) |
|
1511 eeprom.append("{:0>4x}".format(len(data)/4)[0:2]) |
|
1512 data = str(data.lower()) |
|
1513 for i in range(len(data)/2): |
|
1514 if data == "": |
|
1515 eeprom.append("00") |
|
1516 else: |
|
1517 eeprom.append(data[0:2]) |
|
1518 data = data[2:len(data)] |
|
1519 |
|
1520 return eeprom |
|
1521 |
|
1522 #------------------------------------------------------------------------------- |
|
1523 # Used Register Access |
|
1524 #------------------------------------------------------------------------------- |
|
1525 def RegRead(self, offset, length): |
|
1526 """ |
|
1527 Read slave ESC register content using "ethercat reg_read -p %d %s %s" command. |
|
1528 Command example : "ethercat reg_read -p 0 0x0c00 0x0400" |
|
1529 @param offset : register address |
|
1530 @param length : register length |
|
1531 @return return_val : register data |
|
1532 """ |
|
1533 error, return_val = self.Controler.RemoteExec(REG_READ%(self.Controler.GetSlavePos(), offset, length), return_val = None) |
|
1534 return return_val |
|
1535 |
|
1536 def RegWrite(self, address, data): |
|
1537 """ |
|
1538 Write data to slave ESC register using "ethercat reg_write -p %d %s %s" command. |
|
1539 Command example : "ethercat reg_write -p 0 0x0c04 0x0001" |
|
1540 @param address : register address |
|
1541 @param data : data to write |
|
1542 @return return_val : the execution result of "ethercat reg_write" (for error check) |
|
1543 """ |
|
1544 error, return_val = self.Controler.RemoteExec(REG_WRITE%(self.Controler.GetSlavePos(), address, data), return_val = None) |
|
1545 return return_val |
|
1546 |
|
1547 def Rescan(self): |
|
1548 """ |
|
1549 Synchronize EEPROM data in master controller with the data in slave device after EEPROM write. |
|
1550 Command example : "ethercat rescan -p 0" |
|
1551 """ |
|
1552 error, return_val = self.Controler.RemoteExec(RESCAN%(self.Controler.GetSlavePos()), return_val = None) |
|
1553 |
|
1554 #------------------------------------------------------------------------------- |
|
1555 # Common Use Methods |
|
1556 #------------------------------------------------------------------------------- |
|
1557 def CheckConnect(self, cyclic_flag): |
|
1558 """ |
|
1559 Check connection status (1) between Beremiz and the master (2) between the master and the slave. |
|
1560 @param cyclic_flag: 0 - one shot, 1 - periodic |
|
1561 @return True or False |
|
1562 """ |
|
1563 if self.Controler.GetCTRoot()._connector is not None: |
|
1564 # Check connection between the master and the slave. |
|
1565 # Command example : "ethercat xml -p 0" |
|
1566 error, return_val = self.Controler.RemoteExec(SLAVE_XML%(self.Controler.GetSlavePos()), return_val = None) |
|
1567 number_of_lines = return_val.split("\n") |
|
1568 if len(number_of_lines) <= 2 : # No slave connected to the master controller |
|
1569 if not cyclic_flag : |
|
1570 self.CreateErrorDialog('No connected slaves') |
|
1571 return False |
|
1572 |
|
1573 elif len(number_of_lines) > 2 : |
|
1574 return True |
|
1575 else: |
|
1576 # The master controller is not connected to Beremiz host |
|
1577 if not cyclic_flag : |
|
1578 self.CreateErrorDialog('PLC not connected!') |
|
1579 return False |
|
1580 |
|
1581 def CreateErrorDialog(self, mention): |
|
1582 """ |
|
1583 Create a dialog to indicate error or warning. |
|
1584 @param mention : Error String |
|
1585 """ |
|
1586 app_frame = self.Controler.GetCTRoot().AppFrame |
|
1587 dlg = wx.MessageDialog (app_frame, mention, |
|
1588 ' Warning...', |
|
1589 wx.OK | wx.ICON_INFORMATION) |
|
1590 dlg.ShowModal() |
|
1591 dlg.Destroy() |