SVGHMI: added deduction of HMI tree from list of HMI_* instances.
--- a/svghmi/svghmi.py Mon Aug 12 13:09:55 2019 +0200
+++ b/svghmi/svghmi.py Tue Aug 13 14:04:13 2019 +0200
@@ -9,6 +9,8 @@
from __future__ import absolute_import
import os
import shutil
+from itertools import izip
+from pprint import pprint, pformat
import wx
@@ -33,16 +35,100 @@
ScriptDirectory = paths.AbsDir(__file__)
+class HMITreeNode(object):
+ def __init__(self, path, name, nodetype):
+ self.path = path
+ self.name = name
+ self.nodetype = nodetype
+ if nodetype in ["HMI_LABEL", "HMI_ROOT"]:
+ self.children = []
+
+ def pprint(self, indent = 0):
+ res = ">"*indent + pformat(self.__dict__, indent = indent, depth = 1) + "\n"
+ if hasattr(self, "children"):
+ res += "\n".join([child.pprint(indent = indent + 1)
+ for child in self.children])
+ res += "\n"
+
+ return res
+
+ def place_node(self, node):
+ best_child = None
+ known_best_match = 0
+ for child in self.children:
+ in_common = 0
+ for child_path_item, node_path_item in izip(child.path, node.path):
+ if child_path_item == node_path_item:
+ in_common +=1
+ else:
+ break
+ if in_common > known_best_match:
+ known_best_match = in_common
+ best_child = child
+ if best_child is not None and best_child.nodetype == "HMI_LABEL":
+ best_child.place_node(node)
+ else:
+ self.children.append(node)
+
+
class SVGHMILibrary(POULibrary):
def GetLibraryPath(self):
return paths.AbsNeighbourFile(__file__, "pous.xml")
def Generate_C(self, buildpath, varlist, IECCFLAGS):
+ """
+ PLC Instance Tree:
+ prog0
+ +->v1 HMI_INT
+ +->v2 HMI_INT
+ +->fb0 (type mhoo)
+ | +->va HMI_LABEL
+ | +->v3 HMI_INT
+ | +->v4 HMI_INT
+ |
+ +->fb1 (type mhoo)
+ | +->va HMI_LABEL
+ | +->v3 HMI_INT
+ | +->v4 HMI_INT
+ |
+ +->fb2
+ +->v5 HMI_IN
+
+ HMI tree:
+ hmi0
+ +->v1
+ +->v2
+ +->fb0_va
+ | +-> v3
+ | +-> v4
+ |
+ +->fb1_va
+ | +-> v3
+ | +-> v4
+ |
+ +->v5
+
+ """
+
# Filter known HMI types
hmi_types_instances = [v for v in varlist if v["derived"] in HMI_TYPES]
-
- # TODO deduce HMI tree
+ # TODO XXX !!! filter intermediate variables added for FBD feedback loop
+
+ hmi_tree_root = HMITreeNode(None, "hmi0", "HMI_ROOT")
+
+ # TODO add always available variables here ?
+ # - plc status
+ # - current page
+ # - ...
+
+ # deduce HMI tree from PLC HMI_* instances
+ for v in hmi_types_instances:
+ path = v["IEC_path"].split(".")
+ new_node = HMITreeNode(path, path[-1], v["derived"])
+ hmi_tree_root.place_node(new_node)
+
+ print(hmi_tree_root.pprint())
# TODO generate C code to observe/access HMI tree variables
svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c")
--- a/tests/svghmi/plc.xml Mon Aug 12 13:09:55 2019 +0200
+++ b/tests/svghmi/plc.xml Tue Aug 13 14:04:13 2019 +0200
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201">
<fileHeader companyName="Unknown" productName="Unnamed" productVersion="1" creationDateTime="2019-08-06T14:23:42"/>
- <contentHeader name="Unnamed" modificationDateTime="2019-08-09T11:20:07">
+ <contentHeader name="Unnamed" modificationDateTime="2019-08-13T10:34:09">
<coordinateInfo>
<fbd>
<scaling x="5" y="5"/>
@@ -22,7 +22,12 @@
<localVars>
<variable name="LocalVar0">
<type>
- <DINT/>
+ <derived name="HMI_INT"/>
+ </type>
+ </variable>
+ <variable name="Pump0">
+ <type>
+ <derived name="Pump"/>
</type>
</variable>
</localVars>
@@ -85,7 +90,93 @@
<connectionPointOut>
<relPosition x="60" y="10"/>
</connectionPointOut>
- <expression>DINT#1</expression>
+ <expression>1</expression>
+ </inVariable>
+ <block localId="4" typeName="Pump" instanceName="Pump0" executionOrderId="0" height="20" width="45">
+ <position x="595" y="50"/>
+ <inputVariables/>
+ <inOutVariables/>
+ <outputVariables/>
+ </block>
+ </FBD>
+ </body>
+ </pou>
+ <pou name="Pump" pouType="functionBlock">
+ <interface>
+ <localVars>
+ <variable name="hmi">
+ <type>
+ <derived name="HMI_LABEL"/>
+ </type>
+ </variable>
+ <variable name="Pressure">
+ <type>
+ <derived name="HMI_INT"/>
+ </type>
+ </variable>
+ </localVars>
+ </interface>
+ <body>
+ <FBD>
+ <inOutVariable localId="1" executionOrderId="0" height="30" width="75" negatedOut="false" negatedIn="false">
+ <position x="285" y="105"/>
+ <connectionPointIn>
+ <relPosition x="0" y="15"/>
+ <connection refLocalId="2" formalParameter="OUT">
+ <position x="285" y="120"/>
+ <position x="275" y="120"/>
+ <position x="275" y="95"/>
+ <position x="550" y="95"/>
+ <position x="550" y="135"/>
+ <position x="540" y="135"/>
+ </connection>
+ </connectionPointIn>
+ <connectionPointOut>
+ <relPosition x="75" y="15"/>
+ </connectionPointOut>
+ <expression>Pressure</expression>
+ </inOutVariable>
+ <block localId="2" typeName="ADD" executionOrderId="0" height="60" width="65">
+ <position x="475" y="105"/>
+ <inputVariables>
+ <variable formalParameter="IN1">
+ <connectionPointIn>
+ <relPosition x="0" y="30"/>
+ <connection refLocalId="1">
+ <position x="475" y="135"/>
+ <position x="417" y="135"/>
+ <position x="417" y="120"/>
+ <position x="360" y="120"/>
+ </connection>
+ </connectionPointIn>
+ </variable>
+ <variable formalParameter="IN2">
+ <connectionPointIn>
+ <relPosition x="0" y="50"/>
+ <connection refLocalId="3">
+ <position x="475" y="155"/>
+ <position x="432" y="155"/>
+ <position x="432" y="150"/>
+ <position x="410" y="150"/>
+ </connection>
+ </connectionPointIn>
+ </variable>
+ </inputVariables>
+ <inOutVariables/>
+ <outputVariables>
+ <variable formalParameter="OUT">
+ <connectionPointOut>
+ <relPosition x="65" y="30"/>
+ </connectionPointOut>
+ </variable>
+ </outputVariables>
+ </block>
+ <inVariable localId="3" executionOrderId="0" height="25" width="30" negated="false">
+ <position x="380" y="140"/>
+ <connectionPointOut>
+ <relPosition x="30" y="10"/>
+ </connectionPointOut>
+ <expression>23</expression>
</inVariable>
</FBD>
</body>