# HG changeset patch
# User Andrey Skvortsov <andrej.skvortzov@gmail.com>
# Date 1533118185 -10800
# Node ID c9915bc620cd10f8c88037b1428f1d3f8506bd73
# Parent  eb6b68c4439fbeaed70f318b3cf9389107ccedd4
Fix wrong code generation if EN/ENO are used in FBD/LD/SFC

This problem appears for example here

                --------
 -------       |  MOVE  |
| MOVE1 |------|EN   ENO|
 -------       |        |
               |        |
 -------       |        |    -----------
|   23  |------|IN   OUT|---| LocalVar0 |
 -------        --------     -----------


                --------
 -------       |  MOVE  |
| MOVE2 |------|EN   ENO|
 -------       |        |
               |        |
 -------       |        |    -----------
|   15  |------|IN   OUT|---| LocalVar0 |
 -------        --------     -----------

Before wrong code was generated for this case:

  MOVE6_OUT := MOVE(EN := move1, IN := 23, ENO => MOVE6_ENO);
  LocalVar0 := MOVE6_OUT;
  MOVE4_OUT := MOVE(EN := move2, IN := 15, ENO => MOVE4_ENO);
  LocalVar0 := MOVE4_OUT;

With this patch now following code is generated:

  MOVE6_OUT := MOVE(EN := move1, IN := 23, ENO => MOVE6_ENO);
  IF MOVE6_ENO THEN
      LocalVar0 := MOVE6_OUT;
  END_IF;
  MOVE4_OUT := MOVE(EN := move2, IN := 15, ENO => MOVE4_ENO);
  IF MOVE4_ENO THEN
      LocalVar0 := MOVE4_OUT;
  END_IF;


See discussion here:
https://sourceforge.net/p/beremiz/mailman/message/36378805/

diff -r eb6b68c4439f -r c9915bc620cd PLCGenerator.py
--- a/PLCGenerator.py	Tue Jul 31 14:17:41 2018 +0300
+++ b/PLCGenerator.py	Wed Aug 01 13:09:45 2018 +0300
@@ -900,6 +900,42 @@
                 for connection in related:
                     self.ConnectionTypes[connection] = var_type
 
+    def GetUsedEno(self, body, connections):
+        """
+            Function checks whether value on given connection
+            comes from block, that has used EN input and
+            returns variable name for ENO output.
+
+            This is needed to avoid value propagation from blocks
+            with false signal on EN input.
+
+        :param body:
+            body of the block for that program is currently generated
+        :param connections:
+            connection, that's source is checked for EN/ENO usage
+        :return:
+            if EN/ENO are not used, then None is returned
+            Otherwise BOOL variable corresponding to ENO
+            output is returned.
+        """
+
+        if len(connections) != 1:
+            return None
+        ref_local_id = connections[0].getrefLocalId()
+        blk = body.getcontentInstance(ref_local_id)
+        if blk is None:
+            return None
+
+        for invar in blk.inputVariables.getvariable():
+            if invar.getformalParameter() == "EN":
+                if len(invar.getconnectionPointIn().getconnections()) > 0:
+                    if blk.getinstanceName() is None:
+                        var_name = "%s%d_ENO" % (blk.gettypeName(), blk.getlocalId())
+                    else:
+                        var_name = "%s.ENO" % blk.getinstanceName()
+                    return var_name
+        return None
+
     def ComputeProgram(self, pou):
         body = pou.getbody()
         if isinstance(body, ListType):
@@ -958,11 +994,21 @@
                     if connections is not None:
                         expression = self.ComputeExpression(body, connections)
                         if expression is not None:
+                            eno_var = self.GetUsedEno(body, connections)
+                            if eno_var is not None:
+                                self.Program += [(self.CurrentIndent + "IF %s" % eno_var, ())]
+                                self.Program += [(" THEN\n  ", ())]
+                                self.IndentRight()
+
                             self.Program += [(self.CurrentIndent, ()),
                                              (instance.getexpression(), (self.TagName, "io_variable", instance.getlocalId(), "expression")),
                                              (" := ", ())]
                             self.Program += expression
                             self.Program += [(";\n", ())]
+
+                            if eno_var is not None:
+                                self.IndentLeft()
+                                self.Program += [(self.CurrentIndent + "END_IF;\n", ())]
                 elif isinstance(instance, BlockClass):
                     block_type = instance.gettypeName()
                     self.ParentGenerator.GeneratePouProgram(block_type)