1 #!/usr/bin/env python |
1 #!/usr/bin/env python |
2 # -*- coding: utf-8 -*- |
2 # -*- coding: utf-8 -*- |
3 |
3 |
4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor |
4 # This file is part of Beremiz, a Integrated Development Environment for |
5 #based on the plcopen standard. |
5 # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. |
6 # |
6 # |
7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
7 # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
8 # |
8 # |
9 #See COPYING file for copyrights details. |
9 # See COPYING file for copyrights details. |
10 # |
10 # |
11 #This library is free software; you can redistribute it and/or |
11 # This program is free software; you can redistribute it and/or |
12 #modify it under the terms of the GNU General Public |
12 # modify it under the terms of the GNU General Public License |
13 #License as published by the Free Software Foundation; either |
13 # as published by the Free Software Foundation; either version 2 |
14 #version 2.1 of the License, or (at your option) any later version. |
14 # of the License, or (at your option) any later version. |
15 # |
15 # |
16 #This library is distributed in the hope that it will be useful, |
16 # This program is distributed in the hope that it will be useful, |
17 #but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 #General Public License for more details. |
19 # GNU General Public License for more details. |
20 # |
20 # |
21 #You should have received a copy of the GNU General Public |
21 # You should have received a copy of the GNU General Public License |
22 #License along with this library; if not, write to the Free Software |
22 # along with this program; if not, write to the Free Software |
23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
24 |
24 |
25 from plcopen import PLCOpenParser |
25 from plcopen import PLCOpenParser |
26 from plcopen.structures import * |
26 from plcopen.structures import * |
27 from types import * |
27 from types import * |
28 import re |
28 import re |
391 ("(", ())] |
391 ("(", ())] |
392 args = [] |
392 args = [] |
393 single = task.getsingle() |
393 single = task.getsingle() |
394 # Single argument if exists |
394 # Single argument if exists |
395 if single is not None: |
395 if single is not None: |
|
396 if len(single) == 0: |
|
397 msg = _("Source signal has to be defined for single task '{a1}' in resource '{a2}.{a3}'.").\ |
|
398 format(a1 = task.getname(), a2 = config_name, a3 = resource.getname()) |
|
399 raise PLCGenException, msg |
|
400 |
396 if single[0]=='[' and single[-1]==']' : |
401 if single[0]=='[' and single[-1]==']' : |
397 SNGLKW = "MULTI" |
402 SNGLKW = "MULTI" |
398 else: |
403 else: |
399 SNGLKW = "SINGLE" |
404 SNGLKW = "SINGLE" |
400 resrce += [(SNGLKW + " := ", ()), |
405 resrce += [(SNGLKW + " := ", ()), |
761 self.ConnectionTypes[related] = "BOOL" |
766 self.ConnectionTypes[related] = "BOOL" |
762 elif isinstance(instance, TransitionClass): |
767 elif isinstance(instance, TransitionClass): |
763 content = instance.getconditionContent() |
768 content = instance.getconditionContent() |
764 if content["type"] == "connection": |
769 if content["type"] == "connection": |
765 self.ConnectionTypes[content["value"]] = "BOOL" |
770 self.ConnectionTypes[content["value"]] = "BOOL" |
766 for link in content["value"].getconnections(): |
771 connections = content["value"].getconnections() |
|
772 if not connections: |
|
773 raise PLCGenException, _("SFC transition in POU \"%s\" must be connected.") % self.Name |
|
774 for link in connections: |
767 connected = self.GetLinkedConnector(link, body) |
775 connected = self.GetLinkedConnector(link, body) |
768 if connected is not None and not self.ConnectionTypes.has_key(connected): |
776 if connected is not None and not self.ConnectionTypes.has_key(connected): |
769 for related in self.ExtractRelatedConnections(connected): |
777 for related in self.ExtractRelatedConnections(connected): |
770 self.ConnectionTypes[related] = "BOOL" |
778 self.ConnectionTypes[related] = "BOOL" |
771 elif isinstance(instance, ContinuationClass): |
779 elif isinstance(instance, ContinuationClass): |
773 connector = None |
781 connector = None |
774 var_type = "ANY" |
782 var_type = "ANY" |
775 for element in body.getcontentInstances(): |
783 for element in body.getcontentInstances(): |
776 if isinstance(element, ConnectorClass) and element.getname() == name: |
784 if isinstance(element, ConnectorClass) and element.getname() == name: |
777 if connector is not None: |
785 if connector is not None: |
778 raise PLCGenException, _("More than one connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) |
786 msg = _("More than one connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name) |
|
787 raise PLCGenException, msg |
779 connector = element |
788 connector = element |
780 if connector is not None: |
789 if connector is not None: |
781 undefined = [instance.connectionPointOut, connector.connectionPointIn] |
790 undefined = [instance.connectionPointOut, connector.connectionPointIn] |
782 connected = self.GetConnectedConnector(connector.connectionPointIn, body) |
791 connected = self.GetConnectedConnector(connector.connectionPointIn, body) |
783 if connected is not None: |
792 if connected is not None: |
792 self.RelatedConnections.append(related) |
801 self.RelatedConnections.append(related) |
793 else: |
802 else: |
794 for connection in related: |
803 for connection in related: |
795 self.ConnectionTypes[connection] = var_type |
804 self.ConnectionTypes[connection] = var_type |
796 else: |
805 else: |
797 raise PLCGenException, _("No connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) |
806 msg = _("No connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name) |
|
807 raise PLCGenException, msg |
798 elif isinstance(instance, BlockClass): |
808 elif isinstance(instance, BlockClass): |
799 block_infos = self.GetBlockType(instance.gettypeName(), "undefined") |
809 block_infos = self.GetBlockType(instance.gettypeName(), "undefined") |
800 if block_infos is not None: |
810 if block_infos is not None: |
801 self.ComputeBlockInputTypes(instance, block_infos, body) |
811 self.ComputeBlockInputTypes(instance, block_infos, body) |
802 else: |
812 else: |
946 self.ParentGenerator.GeneratePouProgram(block_type) |
956 self.ParentGenerator.GeneratePouProgram(block_type) |
947 block_infos = self.GetBlockType(block_type, tuple([self.ConnectionTypes.get(variable.connectionPointIn, "ANY") for variable in instance.inputVariables.getvariable() if variable.getformalParameter() != "EN"])) |
957 block_infos = self.GetBlockType(block_type, tuple([self.ConnectionTypes.get(variable.connectionPointIn, "ANY") for variable in instance.inputVariables.getvariable() if variable.getformalParameter() != "EN"])) |
948 if block_infos is None: |
958 if block_infos is None: |
949 block_infos = self.GetBlockType(block_type) |
959 block_infos = self.GetBlockType(block_type) |
950 if block_infos is None: |
960 if block_infos is None: |
951 raise PLCGenException, _("Undefined block type \"%s\" in \"%s\" POU")%(block_type, self.Name) |
961 raise PLCGenException, _("Undefined block type \"{a1}\" in \"{a2}\" POU").format(a1 = block_type, a2 = self.Name) |
952 try: |
962 try: |
953 self.GenerateBlock(instance, block_infos, body, None) |
963 self.GenerateBlock(instance, block_infos, body, None) |
954 except ValueError, e: |
964 except ValueError, e: |
955 raise PLCGenException, e.message |
965 raise PLCGenException, e.message |
956 elif isinstance(instance, ConnectorClass): |
966 elif isinstance(instance, ConnectorClass): |
1086 (type, (self.TagName, "block", block.getlocalId(), "type")), |
1096 (type, (self.TagName, "block", block.getlocalId(), "type")), |
1087 ("(", ())] |
1097 ("(", ())] |
1088 self.Program += JoinList([(", ", ())], vars) |
1098 self.Program += JoinList([(", ", ())], vars) |
1089 self.Program += [(");\n", ())] |
1099 self.Program += [(");\n", ())] |
1090 else: |
1100 else: |
1091 self.Warnings.append(_("\"%s\" function cancelled in \"%s\" POU: No input connected")%(type, self.TagName.split("::")[-1])) |
1101 msg = _("\"{a1}\" function cancelled in \"{a2}\" POU: No input connected").format(a1 = type, a2 = self.TagName.split("::")[-1]) |
|
1102 self.Warnings.append(msg) |
1092 elif block_infos["type"] == "functionBlock": |
1103 elif block_infos["type"] == "functionBlock": |
1093 if not self.ComputedBlocks.get(block, False) and not order: |
1104 if not self.ComputedBlocks.get(block, False) and not order: |
1094 self.ComputedBlocks[block] = True |
1105 self.ComputedBlocks[block] = True |
1095 vars = [] |
1106 vars = [] |
1096 offset_idx = 0 |
1107 offset_idx = 0 |
1175 return output_name |
1186 return output_name |
1176 if link is not None: |
1187 if link is not None: |
1177 if output_parameter is None: |
1188 if output_parameter is None: |
1178 output_parameter = "" |
1189 output_parameter = "" |
1179 if name: |
1190 if name: |
1180 blockname = "%s(%s)" % (name, type) |
1191 blockname = "{a1}({a2})".format(a1 = name, a2 = type) |
1181 else: |
1192 else: |
1182 blockname = type |
1193 blockname = type |
1183 raise ValueError, _("No output %s variable found in block %s in POU %s. Connection must be broken") % \ |
1194 msg = _("No output {a1} variable found in block {a2} in POU {a3}. Connection must be broken").\ |
1184 (output_parameter, blockname, self.Name) |
1195 format(a1 = output_parameter, a2 = blockname, a3 = self.Name) |
|
1196 raise ValueError, msg |
1185 |
1197 |
1186 def GeneratePaths(self, connections, body, order = False, to_inout = False): |
1198 def GeneratePaths(self, connections, body, order = False, to_inout = False): |
1187 paths = [] |
1199 paths = [] |
1188 for connection in connections: |
1200 for connection in connections: |
1189 localId = connection.getrefLocalId() |
1201 localId = connection.getrefLocalId() |
1197 self.ParentGenerator.GeneratePouProgram(block_type) |
1209 self.ParentGenerator.GeneratePouProgram(block_type) |
1198 block_infos = self.GetBlockType(block_type, tuple([self.ConnectionTypes.get(variable.connectionPointIn, "ANY") for variable in next.inputVariables.getvariable() if variable.getformalParameter() != "EN"])) |
1210 block_infos = self.GetBlockType(block_type, tuple([self.ConnectionTypes.get(variable.connectionPointIn, "ANY") for variable in next.inputVariables.getvariable() if variable.getformalParameter() != "EN"])) |
1199 if block_infos is None: |
1211 if block_infos is None: |
1200 block_infos = self.GetBlockType(block_type) |
1212 block_infos = self.GetBlockType(block_type) |
1201 if block_infos is None: |
1213 if block_infos is None: |
1202 raise PLCGenException, _("Undefined block type \"%s\" in \"%s\" POU")%(block_type, self.Name) |
1214 msg = _("Undefined block type \"{a1}\" in \"{a2}\" POU").format(a1 = block_type, a2 = self.Name) |
|
1215 raise PLCGenException, msg |
1203 try: |
1216 try: |
1204 paths.append(str(self.GenerateBlock(next, block_infos, body, connection, order, to_inout))) |
1217 paths.append(str(self.GenerateBlock(next, block_infos, body, connection, order, to_inout))) |
1205 except ValueError, e: |
1218 except ValueError, e: |
1206 raise PLCGenException, e.message |
1219 raise PLCGenException, e.message |
1207 elif isinstance(next, ContinuationClass): |
1220 elif isinstance(next, ContinuationClass): |
1212 else: |
1225 else: |
1213 connector = None |
1226 connector = None |
1214 for instance in body.getcontentInstances(): |
1227 for instance in body.getcontentInstances(): |
1215 if isinstance(instance, ConnectorClass) and instance.getname() == name: |
1228 if isinstance(instance, ConnectorClass) and instance.getname() == name: |
1216 if connector is not None: |
1229 if connector is not None: |
1217 raise PLCGenException, _("More than one connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) |
1230 msg = _("More than one connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name) |
|
1231 raise PLCGenException, msg |
1218 connector = instance |
1232 connector = instance |
1219 if connector is not None: |
1233 if connector is not None: |
1220 connections = connector.connectionPointIn.getconnections() |
1234 connections = connector.connectionPointIn.getconnections() |
1221 if connections is not None: |
1235 if connections is not None: |
1222 expression = self.ComputeExpression(body, connections, order) |
1236 expression = self.ComputeExpression(body, connections, order) |
1223 if expression is not None: |
1237 if expression is not None: |
1224 self.ComputedConnectors[name] = expression |
1238 self.ComputedConnectors[name] = expression |
1225 paths.append(str(expression)) |
1239 paths.append(str(expression)) |
1226 else: |
1240 else: |
1227 raise PLCGenException, _("No connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) |
1241 msg = _("No connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name) |
|
1242 raise PLCGenException, msg |
1228 elif isinstance(next, ContactClass): |
1243 elif isinstance(next, ContactClass): |
1229 contact_info = (self.TagName, "contact", next.getlocalId()) |
1244 contact_info = (self.TagName, "contact", next.getlocalId()) |
1230 variable = str(self.ExtractModifier(next, [(next.getvariable(), contact_info + ("reference",))], contact_info)) |
1245 variable = str(self.ExtractModifier(next, [(next.getvariable(), contact_info + ("reference",))], contact_info)) |
1231 result = self.GeneratePaths(next.connectionPointIn.getconnections(), body, order) |
1246 result = self.GeneratePaths(next.connectionPointIn.getconnections(), body, order) |
1232 if len(result) > 1: |
1247 if len(result) > 1: |
1370 target_info = (self.TagName, "transition", instance.getlocalId(), "to", step_infos["id"]) |
1385 target_info = (self.TagName, "transition", instance.getlocalId(), "to", step_infos["id"]) |
1371 self.SFCNetworks["Transitions"][instance]["to"].append([(step_name, target_info)]) |
1386 self.SFCNetworks["Transitions"][instance]["to"].append([(step_name, target_info)]) |
1372 |
1387 |
1373 def GenerateSFCJump(self, jump, pou): |
1388 def GenerateSFCJump(self, jump, pou): |
1374 jump_target = jump.gettargetName() |
1389 jump_target = jump.gettargetName() |
|
1390 if not pou.hasstep(jump_target): |
|
1391 pname = pou.getname() |
|
1392 msg = _("SFC jump in pou \"{a1}\" refers to non-existent SFC step \"{a2}\"").format( a1 = pname, a2 = jump_target) |
|
1393 raise PLCGenException, msg |
1375 if jump.connectionPointIn is not None: |
1394 if jump.connectionPointIn is not None: |
1376 instances = [] |
1395 instances = [] |
1377 connections = jump.connectionPointIn.getconnections() |
1396 connections = jump.connectionPointIn.getconnections() |
1378 if connections is not None and len(connections) == 1: |
1397 if connections is not None and len(connections) == 1: |
1379 instanceLocalId = connections[0].getrefLocalId() |
1398 instanceLocalId = connections[0].getrefLocalId() |
1574 self.Program += JoinList([(", ", ())], transition_infos["from"]) |
1593 self.Program += JoinList([(", ", ())], transition_infos["from"]) |
1575 self.Program += [(")", ())] |
1594 self.Program += [(")", ())] |
1576 elif len(transition_infos["from"]) == 1: |
1595 elif len(transition_infos["from"]) == 1: |
1577 self.Program += transition_infos["from"][0] |
1596 self.Program += transition_infos["from"][0] |
1578 else: |
1597 else: |
1579 raise PLCGenException, _("Transition with content \"%s\" not connected to a previous step in \"%s\" POU")%(transition_infos["content"], self.Name) |
1598 msg = _("Transition with content \"{a1}\" not connected to a previous step in \"{a2}\" POU").\ |
|
1599 format(a1 = transition_infos["content"], a2 = self.Name) |
|
1600 raise PLCGenException, msg |
1580 self.Program += [(" TO ", ())] |
1601 self.Program += [(" TO ", ())] |
1581 if len(transition_infos["to"]) > 1: |
1602 if len(transition_infos["to"]) > 1: |
1582 self.Program += [("(", ())] |
1603 self.Program += [("(", ())] |
1583 self.Program += JoinList([(", ", ())], transition_infos["to"]) |
1604 self.Program += JoinList([(", ", ())], transition_infos["to"]) |
1584 self.Program += [(")", ())] |
1605 self.Program += [(")", ())] |
1585 elif len(transition_infos["to"]) == 1: |
1606 elif len(transition_infos["to"]) == 1: |
1586 self.Program += transition_infos["to"][0] |
1607 self.Program += transition_infos["to"][0] |
1587 else: |
1608 else: |
1588 raise PLCGenException, _("Transition with content \"%s\" not connected to a next step in \"%s\" POU")%(transition_infos["content"], self.Name) |
1609 msg = _("Transition with content \"{a1}\" not connected to a next step in \"{a2}\" POU").\ |
|
1610 format(a1 = transition_infos["content"], a2 = self.Name) |
|
1611 raise PLCGenException, msg |
1589 self.Program += transition_infos["content"] |
1612 self.Program += transition_infos["content"] |
1590 self.Program += [("%sEND_TRANSITION\n\n"%self.CurrentIndent, ())] |
1613 self.Program += [("%sEND_TRANSITION\n\n"%self.CurrentIndent, ())] |
1591 for [(step_name, step_infos)] in transition_infos["to"]: |
1614 for [(step_name, step_infos)] in transition_infos["to"]: |
1592 self.ComputeSFCStep(step_name) |
1615 self.ComputeSFCStep(step_name) |
1593 |
1616 |