PLCGenerator.py
changeset 1911 c1298e7ffe3a
parent 1626 0779c1b18c01
child 1730 64d8f52bc8c8
equal deleted inserted replaced
1910:a375e31bf312 1911:c1298e7ffe3a
     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