3 from xml.dom import minidom |
3 from xml.dom import minidom |
4 |
4 |
5 import wx |
5 import wx |
6 |
6 |
7 from xmlclass import * |
7 from xmlclass import * |
|
8 from plugger import PlugTemplate |
8 from PLCControler import UndoBuffer, LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY |
9 from PLCControler import UndoBuffer, LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY |
9 from ConfigEditor import ConfigEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE |
10 from ConfigEditor import ConfigEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE |
|
11 |
|
12 #-------------------------------------------------- |
|
13 # Ethercat DS402 Node |
|
14 #-------------------------------------------------- |
|
15 |
|
16 NODE_VARIABLES = [ |
|
17 ("ControlWord", 0x6040, 0x00, "UINT", "Q"), |
|
18 ("StatusWord", 0x6041, 0x00, "UINT", "I"), |
|
19 ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"), |
|
20 ("ErrorCode", 0x603f, 0x00, "UINT", "I"), |
|
21 ] |
|
22 |
|
23 class _EthercatDS402SlavePlug: |
|
24 XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?> |
|
25 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
26 <xsd:element name="EtherlabDS402Slave"> |
|
27 <xsd:complexType> |
|
28 <xsd:attribute name="Node_Type" type="xsd:string" use="optional"/> |
|
29 </xsd:complexType> |
|
30 </xsd:element> |
|
31 </xsd:schema> |
|
32 """ |
|
33 |
|
34 def _GetChildBySomething(self, something, toks): |
|
35 return self |
|
36 |
|
37 def GetParamsAttributes(self, path = None): |
|
38 infos = PlugTemplate.GetParamsAttributes(self, path = None) |
|
39 for element in infos: |
|
40 if element["name"] == "EtherlabDS402Slave": |
|
41 for child in element["children"]: |
|
42 if child["name"] == "Node_Type": |
|
43 child["type"] = [module[0] for module in self.PlugParent.GetModulesByProfile(402)] |
|
44 return infos |
|
45 |
|
46 def GetAllChannels(self): |
|
47 AllChannels = PlugTemplate.GetAllChannels(self) |
|
48 for slave_pos in self.PlugParent.GetSlaves(): |
|
49 if slave_pos[0] not in AllChannels: |
|
50 AllChannels.append(slave_pos[0]) |
|
51 AllChannels.sort() |
|
52 return AllChannels |
|
53 |
|
54 def GetCurrentLocation(self): |
|
55 """ |
|
56 @return: Tupple containing plugin IEC location of current plugin : %I0.0.4.5 => (0,0,4,5) |
|
57 """ |
|
58 return self.PlugParent.GetCurrentLocation() + (self.BaseParams.getIEC_Channel(), 0) |
|
59 |
|
60 def GetSlaveInfos(self): |
|
61 slave_type = self.EtherlabDS402Slave.getNode_Type() |
|
62 |
|
63 for module_type, vendor_id, product_code, revision_number in self.PlugParent.GetModulesByProfile(402): |
|
64 if module_type == slave_type: |
|
65 return {"device_type": module_type, |
|
66 "vendor": GenerateHexDecValue(vendor_id), |
|
67 "product_code": GenerateHexDecValue(product_code, 16), |
|
68 "revision_number": GenerateHexDecValue(revision_number, 16)} |
|
69 |
|
70 return None |
|
71 |
|
72 def GetVariableLocationTree(self): |
|
73 slave_infos = self.GetSlaveInfos() |
|
74 vars = [] |
|
75 if slave_infos is not None: |
|
76 vars = self.PlugParent.GetDeviceLocationTree(self.GetCurrentLocation(), slave_infos) |
|
77 |
|
78 return {"name": self.BaseParams.getName(), |
|
79 "type": LOCATION_PLUGIN, |
|
80 "location": self.GetFullIEC_Channel(), |
|
81 "children": vars} |
|
82 |
|
83 def PlugGenerate_C(self, buildpath, locations): |
|
84 """ |
|
85 Generate C code |
|
86 @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) |
|
87 @param locations: List of complete variables locations \ |
|
88 [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) |
|
89 "NAME" : name of the variable (generally "__IW0_1_2" style) |
|
90 "DIR" : direction "Q","I" or "M" |
|
91 "SIZE" : size "X", "B", "W", "D", "L" |
|
92 "LOC" : tuple of interger for IEC location (0,1,2,...) |
|
93 }, ...] |
|
94 @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND |
|
95 """ |
|
96 current_location = self.GetCurrentLocation() |
|
97 |
|
98 location_str = "_".join(map(lambda x:str(x), current_location)) |
|
99 |
|
100 slave_pos = current_location[-2:] |
|
101 |
|
102 slave_infos = self.GetSlaveInfos() |
|
103 device = None |
|
104 if slave_infos is not None: |
|
105 device = self.PlugParent.GetModuleInfos(slave_infos) |
|
106 |
|
107 if device is None: |
|
108 raise (ValueError, |
|
109 _("No information found for DS402 node \"%s\" at location %s!") % ( |
|
110 slave_infos["device_type"], ".".join(current_location))) |
|
111 |
|
112 slave_idx = self.PlugParent.FileGenerator.DeclareSlave(slave_pos, slave_infos) |
|
113 |
|
114 plc_ds402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_ds402node.c") |
|
115 plc_ds402node_file = open(plc_ds402node_filepath, 'r') |
|
116 plc_ds402node_code = plc_ds402node_file.read() |
|
117 plc_ds402node_file.close() |
|
118 |
|
119 str_completion = { |
|
120 "location": location_str, |
|
121 "MCL_includes": "", |
|
122 "located_variables_declaration": [], |
|
123 "entry_variables": [], |
|
124 "extern_pdo_entry_configuration": [], |
|
125 "retrieve_variables": [], |
|
126 "publish_variables": [], |
|
127 } |
|
128 |
|
129 variables = {} |
|
130 for variable in NODE_VARIABLES: |
|
131 var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable)) |
|
132 var_infos["location"] = location_str |
|
133 var_infos["slave"] = slave_idx |
|
134 var_infos["var_size"] = self.PlugParent.GetSizeOfType(var_infos["var_type"]) |
|
135 var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos |
|
136 var_infos["real_var"] = "__DS402Node_%(location)s.%(name)s" % var_infos |
|
137 var_infos.update(slave_infos) |
|
138 |
|
139 variables[(var_infos["index"], var_infos["subindex"])] = var_infos["name"] |
|
140 |
|
141 str_completion["entry_variables"].append(" IEC_%(var_type)s %(name)s;" % var_infos) |
|
142 |
|
143 ConfigureVariable(var_infos, str_completion) |
|
144 |
|
145 str_completion["extern_pdo_entry_configuration"].append( |
|
146 "extern unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % var_infos) |
|
147 |
|
148 if var_infos["var_type"] == "BOOL": |
|
149 str_completion["extern_pdo_entry_configuration"].append( |
|
150 "extern unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % var_infos) |
|
151 |
|
152 self.PlugParent.FileGenerator.DeclareVariable( |
|
153 slave_pos, var_infos["index"], var_infos["subindex"], |
|
154 var_infos["var_type"], var_infos["dir"], var_infos["var_name"], False) |
|
155 |
|
156 for element in ["located_variables_declaration", |
|
157 "entry_variables", |
|
158 "extern_pdo_entry_configuration", |
|
159 "retrieve_variables", |
|
160 "publish_variables"]: |
|
161 str_completion[element] = "\n".join(str_completion[element]) |
|
162 |
|
163 Gen_DS402Nodefile_path = os.path.join(buildpath, "ds402node_%s.c"%location_str) |
|
164 ds402nodefile = open(Gen_DS402Nodefile_path, 'w') |
|
165 ds402nodefile.write(plc_ds402node_code % str_completion) |
|
166 ds402nodefile.close() |
|
167 |
|
168 for location in locations: |
|
169 loc = location["LOC"][len(current_location):] |
|
170 if variables.get(loc, None) is None: |
|
171 self.PlugParent.FileGenerator.DeclareVariable( |
|
172 slave_pos, loc[0], loc[1], location["IEC_TYPE"], location["DIR"], location["NAME"]) |
|
173 |
|
174 return [(Gen_DS402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))],"",True |
|
175 |
|
176 |
10 |
177 |
11 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", |
178 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", |
12 "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", |
179 "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", |
13 "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"} |
180 "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"} |
14 |
181 |
15 DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64", |
182 DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64", |
16 "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", |
183 "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", |
17 "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"} |
184 "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"} |
18 |
185 |
19 VARCLASSCONVERSION = {"ro": LOCATION_VAR_INPUT, "wo": LOCATION_VAR_OUTPUT, "rw": LOCATION_VAR_MEMORY} |
186 VARCLASSCONVERSION = {"T": LOCATION_VAR_INPUT, "R": LOCATION_VAR_OUTPUT, "RT": LOCATION_VAR_MEMORY} |
20 |
187 |
21 #-------------------------------------------------- |
188 #-------------------------------------------------- |
22 # Ethercat MASTER |
189 # Ethercat MASTER |
23 #-------------------------------------------------- |
190 #-------------------------------------------------- |
24 |
191 |
376 fprintf(stderr, "Failed to configure PDOs for slave %(device_type)s at alias %(alias)d and position %(position)d.\\n"); |
581 fprintf(stderr, "Failed to configure PDOs for slave %(device_type)s at alias %(alias)d and position %(position)d.\\n"); |
377 return -1; |
582 return -1; |
378 } |
583 } |
379 """ |
584 """ |
380 |
585 |
|
586 SLAVE_INITIALIZATION_TEMPLATE = """ |
|
587 { |
|
588 uint8_t value[] = {%(data)s}; |
|
589 if (ecrt_master_sdo_download(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &abort_code)) { |
|
590 fprintf(stderr, "Failed to initialize slave %(device_type)s at alias %(alias)d and position %(position)d.\\nError: %%d\\n", abort_code); |
|
591 return -1; |
|
592 } |
|
593 } |
|
594 """ |
|
595 |
381 def ConfigureVariable(entry_infos, str_completion): |
596 def ConfigureVariable(entry_infos, str_completion): |
382 data_type = DATATYPECONVERSION.get(entry_infos["var_type"], None) |
597 entry_infos["data_type"] = DATATYPECONVERSION.get(entry_infos["var_type"], None) |
383 if data_type is None: |
598 if entry_infos["data_type"] is None: |
384 raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"] |
599 raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"] |
385 |
600 |
386 str_completion["located_variables_declaration"].extend( |
601 if not entry_infos.has_key("real_var"): |
387 ["IEC_%(var_type)s beremiz%(var_name)s;" % entry_infos, |
602 entry_infos["real_var"] = "beremiz" + entry_infos["var_name"] |
388 "IEC_%(var_type)s *%(var_name)s = &beremiz%(var_name)s;" % entry_infos]) |
603 str_completion["located_variables_declaration"].append( |
389 |
604 "IEC_%(var_type)s %(real_var)s;" % entry_infos) |
390 if data_type == "BIT": |
605 str_completion["located_variables_declaration"].append( |
391 str_completion["used_pdo_entry_offset_variables_declaration"].extend( |
606 "IEC_%(var_type)s *%(var_name)s = &%(real_var)s;" % entry_infos) |
392 ["static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos, |
607 |
393 "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos]) |
608 if entry_infos["data_type"] == "BIT": |
|
609 if entry_infos["dir"] == "I": |
|
610 str_completion["retrieve_variables"].append( |
|
611 (" %(real_var)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + |
|
612 "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos) |
|
613 elif entry_infos["dir"] == "Q": |
|
614 str_completion["publish_variables"].append( |
|
615 (" EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + |
|
616 "slave%(slave)d_%(index).4x_%(subindex).2x_bit, %(real_var)s);") % entry_infos) |
|
617 |
|
618 else: |
|
619 if entry_infos["dir"] == "I": |
|
620 str_completion["retrieve_variables"].append( |
|
621 (" %(real_var)s = EC_READ_%(data_type)s(domain1_pd + " + |
|
622 "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos) |
|
623 elif entry_infos["dir"] == "Q": |
|
624 str_completion["publish_variables"].append( |
|
625 (" EC_WRITE_%(data_type)s(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + |
|
626 "%(real_var)s);") % entry_infos) |
|
627 |
|
628 def ConfigurePDO(entry_infos, str_completion): |
|
629 str_completion["used_pdo_entry_offset_variables_declaration"].append( |
|
630 "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos) |
|
631 |
|
632 if entry_infos["var_type"] == "BOOL": |
|
633 str_completion["used_pdo_entry_offset_variables_declaration"].append( |
|
634 "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos) |
394 |
635 |
395 str_completion["used_pdo_entry_configuration"].append( |
636 str_completion["used_pdo_entry_configuration"].append( |
396 (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + |
637 (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + |
397 "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + |
638 "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + |
398 "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos) |
639 "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos) |
399 |
640 |
400 if entry_infos["dir"] == "I": |
|
401 str_completion["retrieve_variables"].append( |
|
402 (" beremiz%(name)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + |
|
403 "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos) |
|
404 elif entry_infos["dir"] == "Q": |
|
405 str_completion["publish_variables"].append( |
|
406 (" EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + |
|
407 "slave%(slave)d_%(index).4x_%(subindex).2x_bit, beremiz%(var_name)s);") % entry_infos) |
|
408 |
|
409 else: |
641 else: |
410 entry_infos["data_type"] = data_type |
|
411 |
|
412 str_completion["used_pdo_entry_offset_variables_declaration"].append( |
|
413 "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos) |
|
414 |
642 |
415 str_completion["used_pdo_entry_configuration"].append( |
643 str_completion["used_pdo_entry_configuration"].append( |
416 (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + |
644 (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + |
417 "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos) |
645 "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos) |
418 |
|
419 if entry_infos["dir"] == "I": |
|
420 str_completion["retrieve_variables"].append( |
|
421 (" beremiz%(var_name)s = EC_READ_%(data_type)s(domain1_pd + " + |
|
422 "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos) |
|
423 elif entry_infos["dir"] == "Q": |
|
424 str_completion["publish_variables"].append( |
|
425 (" EC_WRITE_%(data_type)s(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + |
|
426 "beremiz%(var_name)s);") % entry_infos) |
|
427 |
|
428 |
646 |
429 class _EthercatCFileGenerator: |
647 class _EthercatCFileGenerator: |
430 |
648 |
431 def __init__(self, controler, filepath): |
649 def __init__(self, controler): |
432 self.Controler = controler |
650 self.Controler = controler |
433 self.FilePath = filepath |
651 |
434 |
652 self.Slaves = [] |
435 self.UsedVariables = {} |
653 self.UsedVariables = {} |
436 |
654 |
437 def __del__(self): |
655 def __del__(self): |
438 self.Controler = None |
656 self.Controler = None |
439 |
657 |
440 def DeclareVariable(self, slave_identifier, index, subindex, iec_type, dir, name): |
658 def DeclareSlave(self, slave_identifier, slave): |
|
659 self.Slaves.append((slave_identifier, slave)) |
|
660 self.Slaves.sort() |
|
661 return self.Slaves.index((slave_identifier, slave)) |
|
662 |
|
663 def DeclareVariable(self, slave_identifier, index, subindex, iec_type, dir, name, configure=True): |
441 slave_variables = self.UsedVariables.setdefault(slave_identifier, {}) |
664 slave_variables = self.UsedVariables.setdefault(slave_identifier, {}) |
442 |
665 |
443 entry_infos = slave_variables.get((index, subindex), None) |
666 entry_infos = slave_variables.get((index, subindex), None) |
444 if entry_infos is None: |
667 if entry_infos is None: |
445 slave_variables[(index, subindex)] = { |
668 slave_variables[(index, subindex)] = { |
446 "infos": (iec_type, dir, name), |
669 "infos": (iec_type, dir, name), |
|
670 "configure": configure, |
447 "mapped": False} |
671 "mapped": False} |
448 elif entry_infos["infos"] != (iec_type, dir, name): |
672 elif entry_infos["infos"] != (iec_type, dir, name): |
449 raise ValueError, _("Definition conflict for location \"%s\"") % name |
673 raise ValueError, _("Definition conflict for location \"%s\"") % name |
450 |
674 |
451 def GenerateCFile(self): |
675 def GenerateCFile(self, filepath, location_str, etherlab_node_infos): |
452 |
|
453 current_location = self.Controler.GetCurrentLocation() |
|
454 # define a unique name for the generated C file |
|
455 location_str = "_".join(map(lambda x:str(x), current_location)) |
|
456 |
676 |
457 plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c") |
677 plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c") |
458 plc_etherlab_file = open(plc_etherlab_filepath, 'r') |
678 plc_etherlab_file = open(plc_etherlab_filepath, 'r') |
459 plc_etherlab_code = plc_etherlab_file.read() |
679 plc_etherlab_code = plc_etherlab_file.read() |
460 plc_etherlab_file.close() |
680 plc_etherlab_file.close() |
461 |
681 |
462 str_completion = { |
682 str_completion = { |
463 "location": location_str, |
683 "location": location_str, |
464 "configure_pdos": int(self.Controler.EtherlabNode.getConfigurePDOs()), |
684 "configure_pdos": int(etherlab_node_infos.getConfigurePDOs()), |
465 "master_number": self.Controler.EtherlabNode.getMasterNumber(), |
685 "master_number": etherlab_node_infos.getMasterNumber(), |
466 "located_variables_declaration": [], |
686 "located_variables_declaration": [], |
467 "used_pdo_entry_offset_variables_declaration": [], |
687 "used_pdo_entry_offset_variables_declaration": [], |
468 "used_pdo_entry_configuration": [], |
688 "used_pdo_entry_configuration": [], |
469 "pdos_configuration_declaration": "", |
689 "pdos_configuration_declaration": "", |
470 "slaves_declaration": "", |
690 "slaves_declaration": "", |
471 "slaves_configuration": "", |
691 "slaves_configuration": "", |
|
692 "slaves_initialization": "", |
472 "retrieve_variables": [], |
693 "retrieve_variables": [], |
473 "publish_variables": [], |
694 "publish_variables": [], |
474 } |
695 } |
475 |
696 |
476 for slave_entries in self.UsedVariables.itervalues(): |
697 for slave_entries in self.UsedVariables.itervalues(): |
477 for entry_infos in slave_entries.itervalues(): |
698 for entry_infos in slave_entries.itervalues(): |
478 entry_infos["mapped"] = False |
699 entry_infos["mapped"] = False |
479 |
700 |
480 for slave_idx, slave_pos in enumerate(self.Controler.GetSlaves()): |
701 for slave_idx, (slave_pos, type_infos) in enumerate(self.Slaves): |
481 |
702 |
482 slave = self.Controler.GetSlave(slave_pos) |
703 device = self.Controler.GetModuleInfos(type_infos) |
483 if slave is not None: |
704 if device is not None: |
484 type_infos = slave.getType() |
705 |
|
706 slave_variables = self.UsedVariables.get(slave_pos, {}) |
|
707 device_entries = device.GetEntriesList() |
485 |
708 |
486 device = self.Controler.GetModuleInfos(type_infos) |
709 if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0: |
487 if device is not None: |
|
488 slave_variables = self.UsedVariables.get(slave_pos, {}) |
|
489 device_entries = device.GetEntriesList() |
|
490 |
710 |
491 if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0: |
711 for element in ["vendor", "product_code", "revision_number"]: |
|
712 type_infos[element] = ExtractHexDecValue(type_infos[element]) |
|
713 type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos))) |
|
714 |
|
715 str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos |
|
716 str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos |
|
717 |
|
718 for initCmd in device.getInitCmd(): |
|
719 index = ExtractHexDecValue(initCmd.getIndex()) |
|
720 subindex = ExtractHexDecValue(initCmd.getSubIndex()) |
|
721 entry = device_entries.get((index, subindex), None) |
|
722 if entry is not None: |
|
723 data_size = entry["BitSize"] / 8 |
|
724 data = ("%%.%dx" % (data_size * 2)) % initCmd.getData().getcontent() |
|
725 data_str = ",".join(["0x%s" % data[i:i+2] for i in xrange(0, data_size * 2, 2)]) |
|
726 init_cmd_infos = { |
|
727 "index": index, |
|
728 "subindex": subindex, |
|
729 "data": data_str, |
|
730 "data_size": data_size |
|
731 } |
|
732 init_cmd_infos.update(type_infos) |
|
733 str_completion["slaves_initialization"] += SLAVE_INITIALIZATION_TEMPLATE % init_cmd_infos |
|
734 |
|
735 pdos_infos = { |
|
736 "pdos_entries_infos": [], |
|
737 "pdos_infos": [], |
|
738 "pdos_sync_infos": [], |
|
739 } |
|
740 pdos_infos.update(type_infos) |
|
741 |
|
742 sync_managers = [] |
|
743 for sync_manager_idx, sync_manager in enumerate(device.getSm()): |
|
744 sync_manager_infos = { |
|
745 "index": sync_manager_idx, |
|
746 "name": sync_manager.getcontent(), |
|
747 "slave": slave_idx, |
|
748 "pdos": [], |
|
749 "pdos_number": 0, |
|
750 } |
492 |
751 |
493 for element in ["vendor", "product_code", "revision_number"]: |
752 sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) |
494 type_infos[element] = ExtractHexDecValue(type_infos[element]) |
753 sync_manager_direction = sync_manager_control_byte & 0x0c |
495 type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos))) |
754 sync_manager_watchdog = sync_manager_control_byte & 0x40 |
|
755 if sync_manager_direction: |
|
756 sync_manager_infos["sync_manager_type"] = "EC_DIR_OUTPUT" |
|
757 else: |
|
758 sync_manager_infos["sync_manager_type"] = "EC_DIR_INPUT" |
|
759 if sync_manager_watchdog: |
|
760 sync_manager_infos["watchdog"] = "EC_WD_ENABLE" |
|
761 else: |
|
762 sync_manager_infos["watchdog"] = "EC_WD_DISABLE" |
|
763 |
|
764 sync_managers.append(sync_manager_infos) |
496 |
765 |
497 str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos |
766 pdos_index = [] |
498 str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos |
767 for only_mandatory in [True, False]: |
499 |
768 for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] + |
500 pdos_infos = { |
769 [(pdo, "Outputs") for pdo in device.getRxPdo()]): |
501 "pdos_entries_infos": [], |
770 entries = pdo.getEntry() |
502 "pdos_infos": [], |
771 |
503 "pdos_sync_infos": [], |
772 pdo_needed = pdo.getMandatory() |
504 } |
773 if pdo_needed is None: |
505 pdos_infos.update(type_infos) |
774 pdo_needed = False |
506 |
775 if only_mandatory != pdo_needed: |
507 sync_managers = [] |
776 continue |
508 for sync_manager_idx, sync_manager in enumerate(device.getSm()): |
777 |
509 sync_manager_infos = { |
778 pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) |
510 "index": sync_manager_idx, |
779 pdos_index.append(pdo_index) |
511 "name": sync_manager.getcontent(), |
780 entries_infos = [] |
512 "slave": slave_idx, |
781 |
513 "pdos": [], |
782 for entry in entries: |
514 "pdos_number": 0, |
783 index = ExtractHexDecValue(entry.getIndex().getcontent()) |
515 } |
784 subindex = ExtractHexDecValue(entry.getSubIndex()) |
516 |
|
517 sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) |
|
518 sync_manager_direction = sync_manager_control_byte & 0x0c |
|
519 sync_manager_watchdog = sync_manager_control_byte & 0x40 |
|
520 if sync_manager_direction: |
|
521 sync_manager_infos["sync_manager_type"] = "EC_DIR_OUTPUT" |
|
522 else: |
|
523 sync_manager_infos["sync_manager_type"] = "EC_DIR_INPUT" |
|
524 if sync_manager_watchdog: |
|
525 sync_manager_infos["watchdog"] = "EC_WD_ENABLE" |
|
526 else: |
|
527 sync_manager_infos["watchdog"] = "EC_WD_DISABLE" |
|
528 |
|
529 sync_managers.append(sync_manager_infos) |
|
530 |
|
531 pdos_index = [] |
|
532 for only_mandatory in [True, False]: |
|
533 for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] + |
|
534 [(pdo, "Outputs") for pdo in device.getRxPdo()]): |
|
535 entries = pdo.getEntry() |
|
536 |
|
537 pdo_needed = pdo.getMandatory() |
|
538 if only_mandatory != pdo_needed: |
|
539 continue |
|
540 |
|
541 pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) |
|
542 pdos_index.append(pdo_index) |
|
543 entries_infos = [] |
|
544 |
|
545 for entry in entries: |
|
546 index = ExtractHexDecValue(entry.getIndex().getcontent()) |
|
547 subindex = ExtractHexDecValue(entry.getSubIndex()) |
|
548 entry_infos = { |
|
549 "index": index, |
|
550 "subindex": subindex, |
|
551 "name": ExtractName(entry.getName()), |
|
552 "bitlen": entry.getBitLen(), |
|
553 } |
|
554 entry_infos.update(type_infos) |
|
555 entries_infos.append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos) |
|
556 |
|
557 entry_declaration = slave_variables.get((index, subindex), None) |
|
558 if entry_declaration is not None and not entry_declaration["mapped"]: |
|
559 pdo_needed = True |
|
560 |
|
561 entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"]))) |
|
562 entry_declaration["mapped"] = True |
|
563 |
|
564 if entry_infos["var_type"] != entry.getDataType().getcontent(): |
|
565 raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"] |
|
566 |
|
567 if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or |
|
568 entry_infos["dir"] == "Q" and pdo_type != "Outputs"): |
|
569 raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"] |
|
570 |
|
571 ConfigureVariable(entry_infos, str_completion) |
|
572 |
|
573 if pdo_needed: |
|
574 sm = pdo.getSm() |
|
575 if sm is None: |
|
576 for sm_idx, sync_manager in enumerate(sync_managers): |
|
577 if sync_manager["name"] == pdo_type: |
|
578 sm = sm_idx |
|
579 if sm is None: |
|
580 raise ValueError, _("No sync manager available for %s pdo!") % pdo_type |
|
581 |
|
582 sync_managers[sm]["pdos_number"] += 1 |
|
583 sync_managers[sm]["pdos"].append( |
|
584 {"slave": slave_idx, |
|
585 "index": pdo_index, |
|
586 "name": ExtractName(pdo.getName()), |
|
587 "type": pdo_type, |
|
588 "entries": entries_infos, |
|
589 "entries_number": len(entries_infos), |
|
590 "fixed": pdo.getFixed() == True}) |
|
591 |
|
592 dynamic_pdos = {} |
|
593 dynamic_pdos_number = 0 |
|
594 for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), |
|
595 ("Outputs", 0x1a00, 0x1C00)]: |
|
596 for sync_manager in sync_managers: |
|
597 if sync_manager["name"] == category: |
|
598 category_infos = dynamic_pdos.setdefault(category, {}) |
|
599 category_infos["sync_manager"] = sync_manager |
|
600 category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"] |
|
601 if not pdo["fixed"] and pdo["type"] == category] |
|
602 category_infos["current_index"] = min_index |
|
603 category_infos["max_index"] = max_index |
|
604 break |
|
605 |
|
606 for (index, subindex), entry_declaration in slave_variables.iteritems(): |
|
607 |
|
608 if not entry_declaration["mapped"]: |
|
609 entry = device_entries.get((index, subindex), None) |
|
610 if entry is None: |
|
611 raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \ |
|
612 (index, subindex, type_infos["device_type"]) |
|
613 |
|
614 entry_infos = { |
785 entry_infos = { |
615 "index": index, |
786 "index": index, |
616 "subindex": subindex, |
787 "subindex": subindex, |
617 "name": entry["Name"], |
788 "name": ExtractName(entry.getName()), |
618 "bitlen": entry["BitSize"], |
789 "bitlen": entry.getBitLen(), |
619 } |
790 } |
620 entry_infos.update(type_infos) |
791 entry_infos.update(type_infos) |
|
792 entries_infos.append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos) |
621 |
793 |
622 entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"]))) |
794 entry_declaration = slave_variables.get((index, subindex), None) |
623 entry_declaration["mapped"] = True |
795 if entry_declaration is not None and not entry_declaration["mapped"]: |
|
796 pdo_needed = True |
|
797 |
|
798 entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"]))) |
|
799 entry_declaration["mapped"] = True |
|
800 |
|
801 if entry_infos["var_type"] != entry.getDataType().getcontent(): |
|
802 raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"] |
|
803 |
|
804 if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or |
|
805 entry_infos["dir"] == "Q" and pdo_type != "Outputs"): |
|
806 raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"] |
|
807 |
|
808 if entry_declaration["configure"]: |
|
809 ConfigureVariable(entry_infos, str_completion) |
|
810 ConfigurePDO(entry_infos, str_completion) |
|
811 |
|
812 if pdo_needed: |
|
813 sm = pdo.getSm() |
|
814 if sm is None: |
|
815 for sm_idx, sync_manager in enumerate(sync_managers): |
|
816 if sync_manager["name"] == pdo_type: |
|
817 sm = sm_idx |
|
818 if sm is None: |
|
819 raise ValueError, _("No sync manager available for %s pdo!") % pdo_type |
|
820 |
|
821 sync_managers[sm]["pdos_number"] += 1 |
|
822 sync_managers[sm]["pdos"].append( |
|
823 {"slave": slave_idx, |
|
824 "index": pdo_index, |
|
825 "name": ExtractName(pdo.getName()), |
|
826 "type": pdo_type, |
|
827 "entries": entries_infos, |
|
828 "entries_number": len(entries_infos), |
|
829 "fixed": pdo.getFixed() == True}) |
|
830 |
|
831 dynamic_pdos = {} |
|
832 dynamic_pdos_number = 0 |
|
833 for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), |
|
834 ("Outputs", 0x1a00, 0x1C00)]: |
|
835 for sync_manager in sync_managers: |
|
836 if sync_manager["name"] == category: |
|
837 category_infos = dynamic_pdos.setdefault(category, {}) |
|
838 category_infos["sync_manager"] = sync_manager |
|
839 category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"] |
|
840 if not pdo["fixed"] and pdo["type"] == category] |
|
841 category_infos["current_index"] = min_index |
|
842 category_infos["max_index"] = max_index |
|
843 break |
|
844 |
|
845 for (index, subindex), entry_declaration in slave_variables.iteritems(): |
|
846 |
|
847 if not entry_declaration["mapped"]: |
|
848 entry = device_entries.get((index, subindex), None) |
|
849 if entry is None: |
|
850 raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \ |
|
851 (index, subindex, type_infos["device_type"]) |
|
852 |
|
853 entry_infos = { |
|
854 "index": index, |
|
855 "subindex": subindex, |
|
856 "name": entry["Name"], |
|
857 "bitlen": entry["BitSize"], |
|
858 } |
|
859 entry_infos.update(type_infos) |
|
860 |
|
861 entry_infos.update(dict(zip(["var_type", "dir", "var_name", "real_var"], entry_declaration["infos"]))) |
|
862 entry_declaration["mapped"] = True |
|
863 |
|
864 if entry_infos["var_type"] != entry["Type"]: |
|
865 raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"] |
|
866 |
|
867 if entry_infos["dir"] == "I" and entry["PDOMapping"] in ["T", "RT"]: |
|
868 pdo_type = "Inputs" |
|
869 elif entry_infos["dir"] == "Q" and entry["PDOMapping"] in ["R", "RT"]: |
|
870 pdo_type = "Outputs" |
|
871 else: |
|
872 raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"] |
|
873 |
|
874 if not dynamic_pdos.has_key(pdo_type): |
|
875 raise ValueError, _("No Sync manager defined for %s!") % pdo_type |
|
876 |
|
877 if entry_declaration["configure"]: |
|
878 ConfigureVariable(entry_infos, str_completion) |
|
879 ConfigurePDO(entry_infos, str_completion) |
|
880 |
|
881 if len(dynamic_pdos[pdo_type]["pdos"]) > 0: |
|
882 pdo = dynamic_pdos[pdo_type]["pdos"][0] |
|
883 else: |
|
884 while dynamic_pdos[pdo_type]["current_index"] in pdos_index: |
|
885 dynamic_pdos[pdo_type]["current_index"] += 1 |
|
886 if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]: |
|
887 raise ValueError, _("No more free PDO index available for %s!") % pdo_type |
|
888 pdos_index.append(dynamic_pdos[pdo_type]["current_index"]) |
624 |
889 |
625 if entry_infos["var_type"] != entry["Type"]: |
890 dynamic_pdos_number += 1 |
626 raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"] |
891 pdo = {"slave": slave_idx, |
627 |
892 "index": dynamic_pdos[pdo_type]["current_index"], |
628 if entry_infos["dir"] == "I" and entry["Access"] in ["ro", "rw"]: |
893 "name": "Dynamic PDO %d" % dynamic_pdos_number, |
629 pdo_type = "Inputs" |
894 "type": pdo_type, |
630 elif entry_infos["dir"] == "Q" and entry["Access"] in ["wo", "rw"]: |
895 "entries": [], |
631 pdo_type = "Outputs" |
896 "entries_number": 0, |
632 else: |
897 "fixed": False} |
633 raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"] |
898 dynamic_pdos[pdo_type]["sync_manager"]["pdos_number"] += 1 |
634 |
899 dynamic_pdos[pdo_type]["sync_manager"]["pdos"].append(pdo) |
635 if not dynamic_pdos.has_key(pdo_type): |
900 dynamic_pdos[pdo_type]["pdos"].append(pdo) |
636 raise ValueError, _("No Sync manager defined for %s!") % pdo_type |
901 |
637 |
902 pdo["entries"].append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos) |
638 ConfigureVariable(entry_infos, str_completion) |
903 pdo["entries_number"] += 1 |
639 |
904 |
640 if len(dynamic_pdos[pdo_type]["pdos"]) > 0: |
905 if pdo["entries_number"] == 255: |
641 pdo = dynamic_pdos[pdo_type]["pdos"][0] |
906 dynamic_pdos[pdo_type]["pdos"].pop(0) |
642 else: |
907 |
643 while dynamic_pdos[pdo_type]["current_index"] in pdos_index: |
908 pdo_offset = 0 |
644 dynamic_pdos[pdo_type]["current_index"] += 1 |
909 entry_offset = 0 |
645 if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]: |
910 for sync_manager_infos in sync_managers: |
646 raise ValueError, _("No more free PDO index available for %s!") % pdo_type |
|
647 pdos_index.append(dynamic_pdos[pdo_type]["current_index"]) |
|
648 |
|
649 dynamic_pdos_number += 1 |
|
650 pdo = {"slave": slave_idx, |
|
651 "index": dynamic_pdos[pdo_type]["current_index"], |
|
652 "name": "Dynamic PDO %d" % dynamic_pdos_number, |
|
653 "type": pdo_type, |
|
654 "entries": [], |
|
655 "entries_number": 0, |
|
656 "fixed": False} |
|
657 dynamic_pdos[pdo_type]["sync_manager"]["pdos_number"] += 1 |
|
658 dynamic_pdos[pdo_type]["sync_manager"]["pdos"].append(pdo) |
|
659 dynamic_pdos[pdo_type]["pdos"].append(pdo) |
|
660 |
|
661 pdo["entries"].append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos) |
|
662 pdo["entries_number"] += 1 |
|
663 |
|
664 if pdo["entries_number"] == 255: |
|
665 dynamic_pdos[pdo_type]["pdos"].pop(0) |
|
666 |
|
667 pdo_offset = 0 |
|
668 entry_offset = 0 |
|
669 for sync_manager_infos in sync_managers: |
|
670 |
|
671 for pdo_infos in sync_manager_infos["pdos"]: |
|
672 pdo_infos["offset"] = entry_offset |
|
673 pdo_entries = pdo_infos["entries"] |
|
674 pdos_infos["pdos_infos"].append( |
|
675 (" {0x%(index).4x, %(entries_number)d, " + |
|
676 "slave_%(slave)d_pdo_entries + %(offset)d}, /* %(name)s */") % pdo_infos) |
|
677 entry_offset += len(pdo_entries) |
|
678 pdos_infos["pdos_entries_infos"].extend(pdo_entries) |
|
679 |
|
680 sync_manager_infos["offset"] = pdo_offset |
|
681 pdos_infos["pdos_sync_infos"].append( |
|
682 (" {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " + |
|
683 "slave_%(slave)d_pdos + %(offset)d, %(watchdog)s},") % sync_manager_infos) |
|
684 pdo_offset += sync_manager_infos["pdos_number"] |
|
685 |
911 |
686 for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]: |
912 for pdo_infos in sync_manager_infos["pdos"]: |
687 pdos_infos[element] = "\n".join(pdos_infos[element]) |
913 pdo_infos["offset"] = entry_offset |
|
914 pdo_entries = pdo_infos["entries"] |
|
915 pdos_infos["pdos_infos"].append( |
|
916 (" {0x%(index).4x, %(entries_number)d, " + |
|
917 "slave_%(slave)d_pdo_entries + %(offset)d}, /* %(name)s */") % pdo_infos) |
|
918 entry_offset += len(pdo_entries) |
|
919 pdos_infos["pdos_entries_infos"].extend(pdo_entries) |
688 |
920 |
689 str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos |
921 sync_manager_infos["offset"] = pdo_offset |
|
922 pdos_infos["pdos_sync_infos"].append( |
|
923 (" {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " + |
|
924 "slave_%(slave)d_pdos + %(offset)d, %(watchdog)s},") % sync_manager_infos) |
|
925 pdo_offset += sync_manager_infos["pdos_number"] |
|
926 |
|
927 for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]: |
|
928 pdos_infos[element] = "\n".join(pdos_infos[element]) |
|
929 |
|
930 str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos |
690 |
931 |
691 for element in ["used_pdo_entry_offset_variables_declaration", |
932 for element in ["used_pdo_entry_offset_variables_declaration", |
692 "used_pdo_entry_configuration", |
933 "used_pdo_entry_configuration", |
693 "located_variables_declaration", |
934 "located_variables_declaration", |
694 "retrieve_variables", |
935 "retrieve_variables", |
695 "publish_variables"]: |
936 "publish_variables"]: |
696 str_completion[element] = "\n".join(str_completion[element]) |
937 str_completion[element] = "\n".join(str_completion[element]) |
697 |
938 |
698 etherlabfile = open(self.FilePath,'w') |
939 etherlabfile = open(filepath, 'w') |
699 etherlabfile.write(plc_etherlab_code % str_completion) |
940 etherlabfile.write(plc_etherlab_code % str_completion) |
700 etherlabfile.close() |
941 etherlabfile.close() |
701 |
942 |
702 #-------------------------------------------------- |
943 #-------------------------------------------------- |
703 # Ethercat Plugin |
944 # Ethercat Plugin |