|
1 #!/usr/bin/env python |
|
2 # -*- coding: utf-8 -*- |
|
3 |
|
4 # This file is part of Beremiz |
|
5 # |
|
6 # Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT |
|
7 # RTES Lab : CRKim, JBLee, youcu |
|
8 # Higen Motor : Donggu Kang |
|
9 # |
|
10 # See COPYING file for copyrights details. |
|
11 |
|
12 import os |
|
13 import cPickle |
|
14 from lxml import etree |
|
15 from copy import deepcopy |
|
16 |
|
17 import wx |
|
18 |
|
19 from xmlclass import * |
|
20 |
|
21 from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY |
|
22 from ConfigTreeNode import ConfigTreeNode |
|
23 from dialogs import BrowseValuesLibraryDialog |
|
24 from IDEFrame import TITLE, FILEMENU, PROJECTTREE |
|
25 |
|
26 from EthercatSlave import _EthercatSlaveCTN, ExtractHexDecValue, GenerateHexDecValue, TYPECONVERSION, VARCLASSCONVERSION, _CommonSlave |
|
27 from EthercatCFileGenerator import _EthercatCFileGenerator |
|
28 from ConfigEditor import MasterEditor |
|
29 from POULibrary import POULibrary |
|
30 |
|
31 try: |
|
32 from EthercatCIA402Slave import _EthercatCIA402SlaveCTN |
|
33 HAS_MCL = True |
|
34 except: |
|
35 HAS_MCL = False |
|
36 |
|
37 #-------------------------------------------------- |
|
38 # Remote Exec Etherlab Commands |
|
39 #-------------------------------------------------- |
|
40 |
|
41 SCAN_COMMAND = """ |
|
42 import commands |
|
43 result = commands.getoutput("ethercat slaves") |
|
44 slaves = [] |
|
45 for slave_line in result.splitlines(): |
|
46 chunks = slave_line.split() |
|
47 idx, pos, state, flag = chunks[:4] |
|
48 name = " ".join(chunks[4:]) |
|
49 alias, position = pos.split(":") |
|
50 slave = {"idx": int(idx), |
|
51 "alias": int(alias), |
|
52 "position": int(position), |
|
53 "name": name} |
|
54 details = commands.getoutput("ethercat slaves -p %d -v" % slave["idx"]) |
|
55 for details_line in details.splitlines(): |
|
56 details_line = details_line.strip() |
|
57 for header, param in [("Vendor Id:", "vendor_id"), |
|
58 ("Product code:", "product_code"), |
|
59 ("Revision number:", "revision_number")]: |
|
60 if details_line.startswith(header): |
|
61 slave[param] = details_line.split()[-1] |
|
62 break |
|
63 slaves.append(slave) |
|
64 returnVal = slaves |
|
65 """ |
|
66 |
|
67 #-------------------------------------------------- |
|
68 # Etherlab Specific Blocks Library |
|
69 #-------------------------------------------------- |
|
70 |
|
71 def GetLocalPath(filename): |
|
72 return os.path.join(os.path.split(__file__)[0], filename) |
|
73 |
|
74 class EtherlabLibrary(POULibrary): |
|
75 def GetLibraryPath(self): |
|
76 return GetLocalPath("pous.xml") |
|
77 |
|
78 def Generate_C(self, buildpath, varlist, IECCFLAGS): |
|
79 etherlab_ext_file = open(GetLocalPath("etherlab_ext.c"), 'r') |
|
80 etherlab_ext_code = etherlab_ext_file.read() |
|
81 etherlab_ext_file.close() |
|
82 |
|
83 Gen_etherlabfile_path = os.path.join(buildpath, "etherlab_ext.c") |
|
84 ethelabfile = open(Gen_etherlabfile_path,'w') |
|
85 ethelabfile.write(etherlab_ext_code) |
|
86 ethelabfile.close() |
|
87 |
|
88 runtimefile_path = os.path.join(os.path.split(__file__)[0], "runtime_etherlab.py") |
|
89 return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", |
|
90 ("runtime_etherlab.py", file(GetLocalPath("runtime_etherlab.py")))) |
|
91 |
|
92 #-------------------------------------------------- |
|
93 # Ethercat MASTER |
|
94 #-------------------------------------------------- |
|
95 |
|
96 EtherCATConfigParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATConfig.xsd")) |
|
97 |
|
98 def sort_commands(x, y): |
|
99 if x["Index"] == y["Index"]: |
|
100 return cmp(x["Subindex"], y["Subindex"]) |
|
101 return cmp(x["Index"], y["Index"]) |
|
102 |
|
103 cls = EtherCATConfigParser.GetElementClass("Slave", "Config") |
|
104 if cls: |
|
105 |
|
106 def getType(self): |
|
107 slave_info = self.getInfo() |
|
108 return {"device_type": slave_info.getName(), |
|
109 "vendor": GenerateHexDecValue(slave_info.getVendorId()), |
|
110 "product_code": GenerateHexDecValue(slave_info.getProductCode(), 16), |
|
111 "revision_number": GenerateHexDecValue(slave_info.getRevisionNo(), 16)} |
|
112 setattr(cls, "getType", getType) |
|
113 |
|
114 def setType(self, type_infos): |
|
115 slave_info = self.getInfo() |
|
116 slave_info.setName(type_infos["device_type"]) |
|
117 slave_info.setVendorId(ExtractHexDecValue(type_infos["vendor"])) |
|
118 slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"])) |
|
119 slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"])) |
|
120 setattr(cls, "setType", setType) |
|
121 |
|
122 def getInitCmds(self, create_default=False): |
|
123 Mailbox = self.getMailbox() |
|
124 if Mailbox is None: |
|
125 if create_default: |
|
126 self.addMailbox() |
|
127 Mailbox = self.getMailbox() |
|
128 else: |
|
129 return None |
|
130 CoE = Mailbox.getCoE() |
|
131 if CoE is None: |
|
132 if create_default: |
|
133 Mailbox.addCoE() |
|
134 CoE = Mailbox.getCoE() |
|
135 else: |
|
136 return None |
|
137 InitCmds = CoE.getInitCmds() |
|
138 if InitCmds is None and create_default: |
|
139 CoE.addInitCmds() |
|
140 InitCmds = CoE.getInitCmds() |
|
141 return InitCmds |
|
142 setattr(cls, "getInitCmds", getInitCmds) |
|
143 |
|
144 def getStartupCommands(self): |
|
145 pos = self.getInfo().getPhysAddr() |
|
146 InitCmds = self.getInitCmds() |
|
147 if InitCmds is None: |
|
148 return [] |
|
149 commands = [] |
|
150 for idx, InitCmd in enumerate(InitCmds.getInitCmd()): |
|
151 comment = InitCmd.getComment() |
|
152 if comment is None: |
|
153 comment = "" |
|
154 commands.append({ |
|
155 "command_idx": idx, |
|
156 "Position": pos, |
|
157 "Index": InitCmd.getIndex(), |
|
158 "Subindex": InitCmd.getSubIndex(), |
|
159 "Value": InitCmd.getData(), |
|
160 "Description": comment}) |
|
161 commands.sort(sort_commands) |
|
162 return commands |
|
163 setattr(cls, "getStartupCommands", getStartupCommands) |
|
164 |
|
165 def appendStartupCommand(self, command_infos): |
|
166 InitCmds = self.getInitCmds(True) |
|
167 command = EtherCATConfigParser.CreateElement("InitCmd", "InitCmds", 1) |
|
168 InitCmds.appendInitCmd(command) |
|
169 command.setIndex(command_infos["Index"]) |
|
170 command.setSubIndex(command_infos["Subindex"]) |
|
171 command.setData(command_infos["Value"]) |
|
172 command.setComment(command_infos["Description"]) |
|
173 return len(InitCmds.getInitCmd()) - 1 |
|
174 setattr(cls, "appendStartupCommand", appendStartupCommand) |
|
175 |
|
176 def setStartupCommand(self, command_infos): |
|
177 InitCmds = self.getInitCmds() |
|
178 if InitCmds is not None: |
|
179 commands = InitCmds.getInitCmd() |
|
180 if command_infos["command_idx"] < len(commands): |
|
181 command = commands[command_infos["command_idx"]] |
|
182 command.setIndex(command_infos["Index"]) |
|
183 command.setSubIndex(command_infos["Subindex"]) |
|
184 command.setData(command_infos["Value"]) |
|
185 command.setComment(command_infos["Description"]) |
|
186 setattr(cls, "setStartupCommand", setStartupCommand) |
|
187 |
|
188 def removeStartupCommand(self, command_idx): |
|
189 InitCmds = self.getInitCmds() |
|
190 if InitCmds is not None: |
|
191 if command_idx < len(InitCmds.getInitCmd()): |
|
192 InitCmds.removeInitCmd(command_idx) |
|
193 setattr(cls, "removeStartupCommand", removeStartupCommand) |
|
194 |
|
195 ProcessVariablesXSD = """<?xml version="1.0" encoding="ISO-8859-1" ?> |
|
196 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
197 <xsd:element name="ProcessVariables"> |
|
198 <xsd:complexType> |
|
199 <xsd:sequence> |
|
200 <xsd:element name="variable" minOccurs="0" maxOccurs="unbounded"> |
|
201 <xsd:complexType> |
|
202 <xsd:sequence> |
|
203 <xsd:element name="ReadFrom" type="LocationDesc" minOccurs="0"/> |
|
204 <xsd:element name="WriteTo" type="LocationDesc" minOccurs="0"/> |
|
205 </xsd:sequence> |
|
206 <xsd:attribute name="Name" type="xsd:string" use="required"/> |
|
207 <xsd:attribute name="Comment" type="xsd:string" use="required"/> |
|
208 </xsd:complexType> |
|
209 </xsd:element> |
|
210 </xsd:sequence> |
|
211 </xsd:complexType> |
|
212 </xsd:element> |
|
213 <xsd:complexType name="LocationDesc"> |
|
214 <xsd:attribute name="Position" type="xsd:integer" use="required"/> |
|
215 <xsd:attribute name="Index" type="xsd:integer" use="required"/> |
|
216 <xsd:attribute name="SubIndex" type="xsd:integer" use="required"/> |
|
217 </xsd:complexType> |
|
218 </xsd:schema> |
|
219 """ |
|
220 |
|
221 ProcessVariablesParser = GenerateParserFromXSDstring(ProcessVariablesXSD) |
|
222 |
|
223 class _EthercatCTN: |
|
224 |
|
225 CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")] |
|
226 if HAS_MCL: |
|
227 CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave")) |
|
228 EditorType = MasterEditor |
|
229 |
|
230 def __init__(self): |
|
231 config_filepath = self.ConfigFileName() |
|
232 config_is_saved = False |
|
233 self.Config = None |
|
234 if os.path.isfile(config_filepath): |
|
235 config_xmlfile = open(config_filepath, 'r') |
|
236 try: |
|
237 self.Config, error = \ |
|
238 EtherCATConfigParser.LoadXMLString(config_xmlfile.read()) |
|
239 if error is None: |
|
240 config_is_saved = True |
|
241 except Exception, e: |
|
242 error = e.message |
|
243 config_xmlfile.close() |
|
244 |
|
245 if error is not None: |
|
246 self.GetCTRoot().logger.write_error( |
|
247 _("Couldn't load %s network configuration file.") % CTNName) |
|
248 |
|
249 if self.Config is None: |
|
250 self.Config = EtherCATConfigParser.CreateElement("EtherCATConfig") |
|
251 |
|
252 process_filepath = self.ProcessVariablesFileName() |
|
253 process_is_saved = False |
|
254 self.ProcessVariables = None |
|
255 if os.path.isfile(process_filepath): |
|
256 process_xmlfile = open(process_filepath, 'r') |
|
257 try: |
|
258 self.ProcessVariables, error = \ |
|
259 ProcessVariablesParser.LoadXMLString(process_xmlfile.read()) |
|
260 if error is None: |
|
261 process_is_saved = True |
|
262 except Exception, e: |
|
263 error = e.message |
|
264 process_xmlfile.close() |
|
265 |
|
266 if error is not None: |
|
267 self.GetCTRoot().logger.write_error( |
|
268 _("Couldn't load %s network process variables file.") % CTNName) |
|
269 |
|
270 if self.ProcessVariables is None: |
|
271 self.ProcessVariables = ProcessVariablesParser.CreateElement("ProcessVariables") |
|
272 |
|
273 if config_is_saved and process_is_saved: |
|
274 self.CreateBuffer(True) |
|
275 else: |
|
276 self.CreateBuffer(False) |
|
277 self.OnCTNSave() |
|
278 |
|
279 # ----------- call ethercat mng. function -------------- |
|
280 self.CommonMethod = _CommonSlave(self) |
|
281 |
|
282 def GetIconName(self): |
|
283 return "Ethercat" |
|
284 |
|
285 def GetContextualMenuItems(self): |
|
286 return [("Add Ethercat Slave", "Add Ethercat Slave to Master", self.OnAddEthercatSlave)] |
|
287 |
|
288 def OnAddEthercatSlave(self, event): |
|
289 app_frame = self.GetCTRoot().AppFrame |
|
290 dialog = BrowseValuesLibraryDialog(app_frame, |
|
291 "Ethercat Slave Type", self.GetSlaveTypesLibrary()) |
|
292 if dialog.ShowModal() == wx.ID_OK: |
|
293 type_infos = dialog.GetValueInfos() |
|
294 device, module_extra_params = self.GetModuleInfos(type_infos) |
|
295 if device is not None: |
|
296 if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): |
|
297 ConfNodeType = "EthercatCIA402Slave" |
|
298 else: |
|
299 ConfNodeType = "EthercatSlave" |
|
300 new_child = self.CTNAddChild("%s_0" % ConfNodeType, ConfNodeType) |
|
301 new_child.SetParamsAttribute("SlaveParams.Type", type_infos) |
|
302 self.CTNRequestSave() |
|
303 new_child._OpenView() |
|
304 app_frame._Refresh(TITLE, FILEMENU, PROJECTTREE) |
|
305 dialog.Destroy() |
|
306 |
|
307 def ExtractHexDecValue(self, value): |
|
308 return ExtractHexDecValue(value) |
|
309 |
|
310 def GetSizeOfType(self, type): |
|
311 return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None) |
|
312 |
|
313 def ConfigFileName(self): |
|
314 return os.path.join(self.CTNPath(), "config.xml") |
|
315 |
|
316 def ProcessVariablesFileName(self): |
|
317 return os.path.join(self.CTNPath(), "process_variables.xml") |
|
318 |
|
319 def FilterSlave(self, slave, vendor=None, slave_pos=None, slave_profile=None): |
|
320 if slave_pos is not None and slave.getInfo().getPhysAddr() != slave_pos: |
|
321 return False |
|
322 type_infos = slave.getType() |
|
323 if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: |
|
324 return False |
|
325 device, module_extra_params = self.GetModuleInfos(type_infos) |
|
326 if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): |
|
327 return False |
|
328 return True |
|
329 |
|
330 def GetSlaveName(self, slave_pos): |
|
331 CTNChild = self.GetChildByIECLocation((slave_pos,)) |
|
332 if CTNChild is not None: |
|
333 return CTNChild.CTNName() |
|
334 return self.CTNName() |
|
335 |
|
336 def GetSlaves(self, vendor=None, slave_pos=None, slave_profile=None): |
|
337 slaves = [] |
|
338 for slave in self.Config.getConfig().getSlave(): |
|
339 if self.FilterSlave(slave, vendor, slave_pos, slave_profile): |
|
340 slaves.append(slave.getInfo().getPhysAddr()) |
|
341 slaves.sort() |
|
342 return slaves |
|
343 |
|
344 def GetSlave(self, slave_pos): |
|
345 for slave in self.Config.getConfig().getSlave(): |
|
346 slave_info = slave.getInfo() |
|
347 if slave_info.getPhysAddr() == slave_pos: |
|
348 return slave |
|
349 return None |
|
350 |
|
351 def GetStartupCommands(self, vendor=None, slave_pos=None, slave_profile=None): |
|
352 commands = [] |
|
353 for slave in self.Config.getConfig().getSlave(): |
|
354 if self.FilterSlave(slave, vendor, slave_pos, slave_profile): |
|
355 commands.append((slave.getInfo().getPhysAddr(), slave.getStartupCommands())) |
|
356 commands.sort() |
|
357 return reduce(lambda x, y: x + y[1], commands, []) |
|
358 |
|
359 def AppendStartupCommand(self, command_infos): |
|
360 slave = self.GetSlave(command_infos["Position"]) |
|
361 if slave is not None: |
|
362 command_idx = slave.appendStartupCommand(command_infos) |
|
363 self.BufferModel() |
|
364 return command_idx |
|
365 return None |
|
366 |
|
367 def SetStartupCommandInfos(self, command_infos): |
|
368 slave = self.GetSlave(command_infos["Position"]) |
|
369 if slave is not None: |
|
370 slave.setStartupCommand(command_infos) |
|
371 self.BufferModel() |
|
372 |
|
373 def RemoveStartupCommand(self, slave_pos, command_idx, buffer=True): |
|
374 slave = self.GetSlave(slave_pos) |
|
375 if slave is not None: |
|
376 slave.removeStartupCommand(command_idx) |
|
377 if buffer: |
|
378 self.BufferModel() |
|
379 |
|
380 def SetProcessVariables(self, variables): |
|
381 vars = [] |
|
382 for var in variables: |
|
383 variable = ProcessVariablesParser.CreateElement("variable", "ProcessVariables") |
|
384 variable.setName(var["Name"]) |
|
385 variable.setComment(var["Description"]) |
|
386 if var["ReadFrom"] != "": |
|
387 position, index, subindex = var["ReadFrom"] |
|
388 if variable.getReadFrom() is None: |
|
389 variable.addReadFrom() |
|
390 read_from = variable.getReadFrom() |
|
391 read_from.setPosition(position) |
|
392 read_from.setIndex(index) |
|
393 read_from.setSubIndex(subindex) |
|
394 elif variable.getReadFrom() is not None: |
|
395 variable.deleteReadFrom() |
|
396 if var["WriteTo"] != "": |
|
397 position, index, subindex = var["WriteTo"] |
|
398 if variable.getWriteTo() is None: |
|
399 variable.addWriteTo() |
|
400 write_to = variable.getWriteTo() |
|
401 write_to.setPosition(position) |
|
402 write_to.setIndex(index) |
|
403 write_to.setSubIndex(subindex) |
|
404 elif variable.getWriteTo() is not None: |
|
405 variable.deleteWriteTo() |
|
406 vars.append(variable) |
|
407 self.ProcessVariables.setvariable(vars) |
|
408 self.BufferModel() |
|
409 |
|
410 def GetProcessVariables(self): |
|
411 variables = [] |
|
412 idx = 0 |
|
413 for variable in self.ProcessVariables.getvariable(): |
|
414 var = {"Name": variable.getName(), |
|
415 "Number": idx, |
|
416 "Description": variable.getComment()} |
|
417 read_from = variable.getReadFrom() |
|
418 if read_from is not None: |
|
419 var["ReadFrom"] = (read_from.getPosition(), |
|
420 read_from.getIndex(), |
|
421 read_from.getSubIndex()) |
|
422 else: |
|
423 var["ReadFrom"] = "" |
|
424 write_to = variable.getWriteTo() |
|
425 if write_to is not None: |
|
426 var["WriteTo"] = (write_to.getPosition(), |
|
427 write_to.getIndex(), |
|
428 write_to.getSubIndex()) |
|
429 else: |
|
430 var["WriteTo"] = "" |
|
431 variables.append(var) |
|
432 idx += 1 |
|
433 return variables |
|
434 |
|
435 def _ScanNetwork(self): |
|
436 app_frame = self.GetCTRoot().AppFrame |
|
437 |
|
438 execute = True |
|
439 if len(self.Children) > 0: |
|
440 dialog = wx.MessageDialog(app_frame, |
|
441 _("The current network configuration will be deleted.\nDo you want to continue?"), |
|
442 _("Scan Network"), |
|
443 wx.YES_NO|wx.ICON_QUESTION) |
|
444 execute = dialog.ShowModal() == wx.ID_YES |
|
445 dialog.Destroy() |
|
446 |
|
447 if execute: |
|
448 error, returnVal = self.RemoteExec(SCAN_COMMAND, returnVal = None) |
|
449 if error != 0: |
|
450 dialog = wx.MessageDialog(app_frame, returnVal, "Error", wx.OK|wx.ICON_ERROR) |
|
451 dialog.ShowModal() |
|
452 dialog.Destroy() |
|
453 elif returnVal is not None: |
|
454 for child in self.IECSortedChildren(): |
|
455 self._doRemoveChild(child) |
|
456 |
|
457 for slave in returnVal: |
|
458 type_infos = { |
|
459 "vendor": slave["vendor_id"], |
|
460 "product_code": slave["product_code"], |
|
461 "revision_number":slave["revision_number"], |
|
462 } |
|
463 device, module_extra_params = self.GetModuleInfos(type_infos) |
|
464 if device is not None: |
|
465 if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): |
|
466 CTNType = "EthercatCIA402Slave" |
|
467 else: |
|
468 CTNType = "EthercatSlave" |
|
469 self.CTNAddChild("slave%s" % slave["idx"], CTNType, slave["idx"]) |
|
470 self.SetSlaveAlias(slave["idx"], slave["alias"]) |
|
471 type_infos["device_type"] = device.getType().getcontent() |
|
472 self.SetSlaveType(slave["idx"], type_infos) |
|
473 |
|
474 if app_frame: |
|
475 app_frame.RefreshProjectTree() |
|
476 |
|
477 def CTNAddChild(self, CTNName, CTNType, IEC_Channel=0): |
|
478 """ |
|
479 Create the confnodes that may be added as child to this node self |
|
480 @param CTNType: string desining the confnode class name (get name from CTNChildrenTypes) |
|
481 @param CTNName: string for the name of the confnode instance |
|
482 """ |
|
483 newConfNodeOpj = ConfigTreeNode.CTNAddChild(self, CTNName, CTNType, IEC_Channel) |
|
484 |
|
485 slave = self.GetSlave(newConfNodeOpj.BaseParams.getIEC_Channel()) |
|
486 if slave is None: |
|
487 slave = EtherCATConfigParser.CreateElement("Slave", "Config") |
|
488 self.Config.getConfig().appendSlave(slave) |
|
489 slave_infos = slave.getInfo() |
|
490 slave_infos.setName("undefined") |
|
491 slave_infos.setPhysAddr(newConfNodeOpj.BaseParams.getIEC_Channel()) |
|
492 slave_infos.setAutoIncAddr(0) |
|
493 self.BufferModel() |
|
494 self.OnCTNSave() |
|
495 |
|
496 return newConfNodeOpj |
|
497 |
|
498 def _doRemoveChild(self, CTNInstance): |
|
499 slave_pos = CTNInstance.GetSlavePos() |
|
500 config = self.Config.getConfig() |
|
501 for idx, slave in enumerate(config.getSlave()): |
|
502 slave_infos = slave.getInfo() |
|
503 if slave_infos.getPhysAddr() == slave_pos: |
|
504 config.removeSlave(idx) |
|
505 self.BufferModel() |
|
506 self.OnCTNSave() |
|
507 ConfigTreeNode._doRemoveChild(self, CTNInstance) |
|
508 |
|
509 def SetSlavePosition(self, slave_pos, new_pos): |
|
510 slave = self.GetSlave(slave_pos) |
|
511 if slave is not None: |
|
512 slave_info = slave.getInfo() |
|
513 slave_info.setPhysAddr(new_pos) |
|
514 for variable in self.ProcessVariables.getvariable(): |
|
515 read_from = variable.getReadFrom() |
|
516 if read_from is not None and read_from.getPosition() == slave_pos: |
|
517 read_from.setPosition(new_pos) |
|
518 write_to = variable.getWriteTo() |
|
519 if write_to is not None and write_to.getPosition() == slave_pos: |
|
520 write_to.setPosition(new_pos) |
|
521 self.CreateBuffer(True) |
|
522 self.CTNRequestSave() |
|
523 if self._View is not None: |
|
524 self._View.RefreshView() |
|
525 self._View.RefreshBuffer() |
|
526 |
|
527 def GetSlaveAlias(self, slave_pos): |
|
528 slave = self.GetSlave(slave_pos) |
|
529 if slave is not None: |
|
530 slave_info = slave.getInfo() |
|
531 return slave_info.getAutoIncAddr() |
|
532 return None |
|
533 |
|
534 def SetSlaveAlias(self, slave_pos, alias): |
|
535 slave = self.GetSlave(slave_pos) |
|
536 if slave is not None: |
|
537 slave_info = slave.getInfo() |
|
538 slave_info.setAutoIncAddr(alias) |
|
539 self.BufferModel() |
|
540 |
|
541 def GetSlaveType(self, slave_pos): |
|
542 slave = self.GetSlave(slave_pos) |
|
543 if slave is not None: |
|
544 return slave.getType() |
|
545 return None |
|
546 |
|
547 def SetSlaveType(self, slave_pos, type_infos): |
|
548 slave = self.GetSlave(slave_pos) |
|
549 if slave is not None: |
|
550 slave.setType(type_infos) |
|
551 self.BufferModel() |
|
552 |
|
553 def GetSlaveInfos(self, slave_pos): |
|
554 slave = self.GetSlave(slave_pos) |
|
555 if slave is not None: |
|
556 type_infos = slave.getType() |
|
557 device, module_extra_params = self.GetModuleInfos(type_infos) |
|
558 if device is not None: |
|
559 infos = type_infos.copy() |
|
560 infos.update({"physics": device.getPhysics(), |
|
561 "sync_managers": device.GetSyncManagers(), |
|
562 "entries": self.GetSlaveVariables(device)}) |
|
563 return infos |
|
564 return None |
|
565 |
|
566 def GetSlaveVariables(self, slave_pos=None, limits=None, device=None): |
|
567 if device is None and slave_pos is not None: |
|
568 slave = self.GetSlave(slave_pos) |
|
569 if slave is not None: |
|
570 type_infos = slave.getType() |
|
571 device, module_extra_params = self.GetModuleInfos(type_infos) |
|
572 if device is not None: |
|
573 entries = device.GetEntriesList(limits) |
|
574 #print entries |
|
575 entries_list = entries.items() |
|
576 entries_list.sort() |
|
577 entries = [] |
|
578 current_index = None |
|
579 current_entry = None |
|
580 for (index, subindex), entry in entries_list: |
|
581 entry["children"] = [] |
|
582 if slave_pos is not None: |
|
583 entry["Position"] = str(slave_pos) |
|
584 entry |
|
585 if index != current_index: |
|
586 current_index = index |
|
587 current_entry = entry |
|
588 entries.append(entry) |
|
589 elif current_entry is not None: |
|
590 current_entry["children"].append(entry) |
|
591 else: |
|
592 entries.append(entry) |
|
593 return entries |
|
594 return [] |
|
595 |
|
596 def GetSlaveVariableDataType(self, slave_pos, index, subindex): |
|
597 slave = self.GetSlave(slave_pos) |
|
598 if slave is not None: |
|
599 device, module_extra_params = self.GetModuleInfos(slave.getType()) |
|
600 if device is not None: |
|
601 entries = device.GetEntriesList() |
|
602 entry_infos = entries.get((index, subindex)) |
|
603 if entry_infos is not None: |
|
604 return entry_infos["Type"] |
|
605 return None |
|
606 |
|
607 def GetNodesVariables(self, vendor=None, slave_pos=None, slave_profile=None, limits=None): |
|
608 entries = [] |
|
609 for slave_position in self.GetSlaves(): |
|
610 if slave_pos is not None and slave_position != slave_pos: |
|
611 continue |
|
612 slave = self.GetSlave(slave_position) |
|
613 type_infos = slave.getType() |
|
614 if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: |
|
615 continue |
|
616 device, module_extra_params = self.GetModuleInfos(type_infos) |
|
617 if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): |
|
618 continue |
|
619 entries.extend(self.GetSlaveVariables(slave_position, limits, device)) |
|
620 return entries |
|
621 |
|
622 def GetModuleInfos(self, type_infos): |
|
623 return self.CTNParent.GetModuleInfos(type_infos) |
|
624 |
|
625 def GetSlaveTypesLibrary(self, profile_filter=None): |
|
626 return self.CTNParent.GetModulesLibrary(profile_filter) |
|
627 |
|
628 def GetLibraryVendors(self): |
|
629 return self.CTNParent.GetVendors() |
|
630 |
|
631 def GetDeviceLocationTree(self, slave_pos, current_location, device_name): |
|
632 slave = self.GetSlave(slave_pos) |
|
633 vars = [] |
|
634 if slave is not None: |
|
635 type_infos = slave.getType() |
|
636 |
|
637 device, module_extra_params = self.GetModuleInfos(type_infos) |
|
638 if device is not None: |
|
639 sync_managers = [] |
|
640 for sync_manager in device.getSm(): |
|
641 sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) |
|
642 sync_manager_direction = sync_manager_control_byte & 0x0c |
|
643 if sync_manager_direction: |
|
644 sync_managers.append(LOCATION_VAR_OUTPUT) |
|
645 else: |
|
646 sync_managers.append(LOCATION_VAR_INPUT) |
|
647 |
|
648 entries = device.GetEntriesList().items() |
|
649 entries.sort() |
|
650 for (index, subindex), entry in entries: |
|
651 var_size = self.GetSizeOfType(entry["Type"]) |
|
652 if var_size is not None: |
|
653 var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None) |
|
654 if var_class is not None: |
|
655 if var_class == LOCATION_VAR_INPUT: |
|
656 var_dir = "%I" |
|
657 else: |
|
658 var_dir = "%Q" |
|
659 |
|
660 vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]), |
|
661 "type": var_class, |
|
662 "size": var_size, |
|
663 "IEC_type": entry["Type"], |
|
664 "var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex), |
|
665 "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + |
|
666 (index, subindex)))), |
|
667 "description": "", |
|
668 "children": []}) |
|
669 |
|
670 return vars |
|
671 |
|
672 def CTNTestModified(self): |
|
673 return self.ChangesToSave or not self.ModelIsSaved() |
|
674 |
|
675 def OnCTNSave(self, from_project_path=None): |
|
676 config_filepath = self.ConfigFileName() |
|
677 |
|
678 config_xmlfile = open(config_filepath,"w") |
|
679 config_xmlfile.write(etree.tostring( |
|
680 self.Config, |
|
681 pretty_print=True, |
|
682 xml_declaration=True, |
|
683 encoding='utf-8')) |
|
684 config_xmlfile.close() |
|
685 |
|
686 process_filepath = self.ProcessVariablesFileName() |
|
687 |
|
688 process_xmlfile = open(process_filepath,"w") |
|
689 process_xmlfile.write(etree.tostring( |
|
690 self.ProcessVariables, |
|
691 pretty_print=True, |
|
692 xml_declaration=True, |
|
693 encoding='utf-8')) |
|
694 process_xmlfile.close() |
|
695 |
|
696 self.Buffer.CurrentSaved() |
|
697 return True |
|
698 |
|
699 def GetProcessVariableName(self, location, var_type): |
|
700 return "__M%s_%s" % (self.GetSizeOfType(var_type), "_".join(map(str, location))) |
|
701 |
|
702 def _Generate_C(self, buildpath, locations): |
|
703 current_location = self.GetCurrentLocation() |
|
704 # define a unique name for the generated C file |
|
705 location_str = "_".join(map(lambda x:str(x), current_location)) |
|
706 |
|
707 Gen_Ethercatfile_path = os.path.join(buildpath, "ethercat_%s.c"%location_str) |
|
708 |
|
709 self.FileGenerator = _EthercatCFileGenerator(self) |
|
710 |
|
711 LocationCFilesAndCFLAGS, LDFLAGS, extra_files = ConfigTreeNode._Generate_C(self, buildpath, locations) |
|
712 |
|
713 for idx, variable in enumerate(self.ProcessVariables.getvariable()): |
|
714 name = None |
|
715 var_type = None |
|
716 read_from = variable.getReadFrom() |
|
717 write_to = variable.getWriteTo() |
|
718 if read_from is not None: |
|
719 pos = read_from.getPosition() |
|
720 index = read_from.getIndex() |
|
721 subindex = read_from.getSubIndex() |
|
722 location = current_location + (idx, ) |
|
723 var_type = self.GetSlaveVariableDataType(pos, index, subindex) |
|
724 name = self.FileGenerator.DeclareVariable( |
|
725 pos, index, subindex, var_type, "I", |
|
726 self.GetProcessVariableName(location, var_type)) |
|
727 if write_to is not None: |
|
728 pos = write_to.getPosition() |
|
729 index = write_to.getIndex() |
|
730 subindex = write_to.getSubIndex() |
|
731 if name is None: |
|
732 location = current_location + (idx, ) |
|
733 var_type = self.GetSlaveVariableDataType(pos, index, subindex) |
|
734 name = self.GetProcessVariableName(location, var_type) |
|
735 self.FileGenerator.DeclareVariable( |
|
736 pos, index, subindex, var_type, "Q", name, True) |
|
737 |
|
738 self.FileGenerator.GenerateCFile(Gen_Ethercatfile_path, location_str, self.BaseParams.getIEC_Channel()) |
|
739 |
|
740 LocationCFilesAndCFLAGS.insert(0, |
|
741 (current_location, |
|
742 [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))], |
|
743 True)) |
|
744 LDFLAGS.append("-lethercat_rtdm -lrtdm") |
|
745 |
|
746 return LocationCFilesAndCFLAGS, LDFLAGS, extra_files |
|
747 |
|
748 ConfNodeMethods = [ |
|
749 {"bitmap" : "ScanNetwork", |
|
750 "name" : _("Scan Network"), |
|
751 "tooltip" : _("Scan Network"), |
|
752 "method" : "_ScanNetwork"}, |
|
753 ] |
|
754 |
|
755 def CTNGenerate_C(self, buildpath, locations): |
|
756 current_location = self.GetCurrentLocation() |
|
757 |
|
758 slaves = self.GetSlaves() |
|
759 for slave_pos in slaves: |
|
760 slave = self.GetSlave(slave_pos) |
|
761 if slave is not None: |
|
762 self.FileGenerator.DeclareSlave(slave_pos, slave) |
|
763 |
|
764 for location in locations: |
|
765 loc = location["LOC"][len(current_location):] |
|
766 slave_pos = loc[0] |
|
767 if slave_pos in slaves and len(loc) == 3 and location["DIR"] != "M": |
|
768 self.FileGenerator.DeclareVariable( |
|
769 slave_pos, loc[1], loc[2], location["IEC_TYPE"], location["DIR"], location["NAME"]) |
|
770 |
|
771 return [],"",False |
|
772 |
|
773 #------------------------------------------------------------------------------- |
|
774 # Current Buffering Management Functions |
|
775 #------------------------------------------------------------------------------- |
|
776 |
|
777 """ |
|
778 Return a copy of the config |
|
779 """ |
|
780 def Copy(self, model): |
|
781 return deepcopy(model) |
|
782 |
|
783 def CreateBuffer(self, saved): |
|
784 self.Buffer = UndoBuffer( |
|
785 (EtherCATConfigParser.Dumps(self.Config), |
|
786 ProcessVariablesParser.Dumps(self.ProcessVariables)), |
|
787 saved) |
|
788 |
|
789 def BufferModel(self): |
|
790 self.Buffer.Buffering( |
|
791 (EtherCATConfigParser.Dumps(self.Config), |
|
792 ProcessVariablesParser.Dumps(self.ProcessVariables))) |
|
793 |
|
794 def ModelIsSaved(self): |
|
795 if self.Buffer is not None: |
|
796 return self.Buffer.IsCurrentSaved() |
|
797 else: |
|
798 return True |
|
799 |
|
800 def LoadPrevious(self): |
|
801 config, process_variables = self.Buffer.Previous() |
|
802 self.Config = EtherCATConfigParser.Loads(config) |
|
803 self.ProcessVariables = ProcessVariablesParser.Loads(process_variables) |
|
804 |
|
805 def LoadNext(self): |
|
806 config, process_variables = self.Buffer.Next() |
|
807 self.Config = EtherCATConfigParser.Loads(config) |
|
808 self.ProcessVariables = ProcessVariablesParser.Loads(process_variables) |
|
809 |
|
810 def GetBufferState(self): |
|
811 first = self.Buffer.IsFirst() |
|
812 last = self.Buffer.IsLast() |
|
813 return not first, not last |
|
814 |