SVGHMI: HMI_LABEL and HMI_CLASS become HMI_NODE. svghmi
authorEdouard Tisserant
Wed, 13 Nov 2019 11:22:53 +0100
branchsvghmi
changeset 2814 2cabc4773885
parent 2813 ac736a878188
child 2815 77b2a3757e66
SVGHMI: HMI_LABEL and HMI_CLASS become HMI_NODE.
- Name of parent POU becomes HMI tree node name,
- Name of HMI_NODE variable becomes class of the node.
svghmi/gen_index_xhtml.xslt
svghmi/gen_index_xhtml.ysl2
svghmi/pous.xml
svghmi/svghmi.py
tests/svghmi/plc.xml
tests/svghmi/svghmi_0@svghmi/svghmi.svg
--- a/svghmi/gen_index_xhtml.xslt	Wed Nov 13 11:21:04 2019 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Wed Nov 13 11:22:53 2019 +0100
@@ -33,10 +33,7 @@
       <xsl:text>HMI_ROOT</xsl:text>
     </noindex>
     <noindex>
-      <xsl:text>HMI_LABEL</xsl:text>
-    </noindex>
-    <noindex>
-      <xsl:text>HMI_CLASS</xsl:text>
+      <xsl:text>HMI_NODE</xsl:text>
     </noindex>
     <noindex>
       <xsl:text>HMI_PLC_STATUS</xsl:text>
@@ -123,6 +120,15 @@
     <xsl:comment>
       <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text>
     </xsl:comment>
+    <xsl:comment>
+      <xsl:apply-templates mode="testgeo" select="$hmi_geometry"/>
+    </xsl:comment>
+    <xsl:comment>
+      <xsl:apply-templates mode="testtree" select="$hmitree"/>
+    </xsl:comment>
+    <xsl:comment>
+      <xsl:apply-templates mode="testtree" select="$indexed_hmitree"/>
+    </xsl:comment>
     <html xmlns="http://www.w3.org/1999/xhtml">
       <head/>
       <body style="margin:0;overflow:hidden;">
@@ -225,9 +231,9 @@
         <xsl:variable name="hmitree_match" select="$indexed_hmitree/*[@hmipath = $hmipath]"/>
         <xsl:if test="count($hmitree_match) = 0">
           <xsl:message terminate="yes">
-            <xsl:text>No match for HMI </xsl:text>
+            <xsl:text>No match for path "</xsl:text>
             <xsl:value-of select="$hmipath"/>
-            <xsl:text>;</xsl:text>
+            <xsl:text>" in HMI tree</xsl:text>
           </xsl:message>
         </xsl:if>
         <xsl:text>        </xsl:text>
@@ -799,6 +805,40 @@
     <xsl:text>//})();
 </xsl:text>
   </xsl:template>
+  <xsl:template mode="testgeo" match="bbox">
+    <xsl:text>ID: </xsl:text>
+    <xsl:value-of select="@Id"/>
+    <xsl:text> x: </xsl:text>
+    <xsl:value-of select="@x"/>
+    <xsl:text> y: </xsl:text>
+    <xsl:value-of select="@y"/>
+    <xsl:text> w: </xsl:text>
+    <xsl:value-of select="@w"/>
+    <xsl:text> h: </xsl:text>
+    <xsl:value-of select="@h"/>
+    <xsl:text>
+</xsl:text>
+  </xsl:template>
+  <xsl:template mode="testtree" match="*">
+    <xsl:param name="indent" select="''"/>
+    <xsl:value-of select="$indent"/>
+    <xsl:text> </xsl:text>
+    <xsl:value-of select="local-name()"/>
+    <xsl:text> </xsl:text>
+    <xsl:for-each select="@*">
+      <xsl:value-of select="local-name()"/>
+      <xsl:text>=</xsl:text>
+      <xsl:value-of select="."/>
+      <xsl:text> </xsl:text>
+    </xsl:for-each>
+    <xsl:text>
+</xsl:text>
+    <xsl:apply-templates mode="testtree" select="*">
+      <xsl:with-param name="indent">
+        <xsl:value-of select="concat($indent,'&gt;')"/>
+      </xsl:with-param>
+    </xsl:apply-templates>
+  </xsl:template>
   <xsl:template name="defs_by_labels">
     <xsl:param name="labels" select="''"/>
     <xsl:param name="mandatory" select="'yes'"/>
--- a/svghmi/gen_index_xhtml.ysl2	Wed Nov 13 11:21:04 2019 +0100
+++ b/svghmi/gen_index_xhtml.ysl2	Wed Nov 13 11:22:53 2019 +0100
@@ -55,8 +55,7 @@
 
     const "_categories" {
         noindex > HMI_ROOT
-        noindex > HMI_LABEL
-        noindex > HMI_CLASS
+        noindex > HMI_NODE
         noindex > HMI_PLC_STATUS
         noindex > HMI_CURRENT_PAGE
     }
@@ -122,7 +121,7 @@
     /* copy root node and add geometry as comment for a test */
     template "/" { 
         comment > Made with SVGHMI. https://beremiz.org
-        /* DEBUG DATA
+        /* DEBUG DATA */
         comment {
             apply "$hmi_geometry", mode="testgeo";
         }
@@ -132,7 +131,7 @@
         comment {
             apply "$indexed_hmitree", mode="testtree";
         }
-        */
+        /**/
         html xmlns="http://www.w3.org/1999/xhtml" {
             head;
             body style="margin:0;overflow:hidden;" {
@@ -229,7 +228,7 @@
                 const "hmipath","@value";
                 const "hmitree_match","$indexed_hmitree/*[@hmipath = $hmipath]";
                 if "count($hmitree_match) = 0"
-                    error > No match for HMI «$hmipath»;
+                    error > No match for path "«$hmipath»" in HMI tree
             |         «$hmitree_match/@index»`if "position()!=last()" > ,`
             }
             |     ],
@@ -307,7 +306,7 @@
     // }
 
 
-    /*
+    /**/
     template "bbox", mode="testgeo"{
         | ID: «@Id» x: «@x» y: «@y» w: «@w» h: «@h»
     }
@@ -321,7 +320,7 @@
             with "indent" value "concat($indent,'>')"
         };
     }
-    */
+    /**/
 
     function "defs_by_labels" {
         param "labels","''";
--- a/svghmi/pous.xml	Wed Nov 13 11:21:04 2019 +0100
+++ b/svghmi/pous.xml	Wed Nov 13 11:22:53 2019 +0100
@@ -36,12 +36,7 @@
           <BOOL/>
         </baseType>
       </dataType>
-      <dataType name="HMI_CLASS">
-        <baseType>
-          <BOOL/>
-        </baseType>
-      </dataType>
-      <dataType name="HMI_LABEL">
+      <dataType name="HMI_NODE">
         <baseType>
           <BOOL/>
         </baseType>
--- a/svghmi/svghmi.py	Wed Nov 13 11:21:04 2019 +0100
+++ b/svghmi/svghmi.py	Wed Nov 13 11:22:53 2019 +0100
@@ -25,8 +25,7 @@
 import targets
 
 HMI_TYPES_DESC = {
-    "HMI_CLASS":{},
-    "HMI_LABEL":{},
+    "HMI_NODE":{},
     "HMI_STRING":{},
     "HMI_INT":{},
     "HMI_REAL":{}
@@ -35,19 +34,21 @@
 HMI_TYPES = HMI_TYPES_DESC.keys()
 
 from XSLTransform import XSLTransform
+from lxml.etree import XSLTApplyError
 
 ScriptDirectory = paths.AbsDir(__file__)
 
 class HMITreeNode(object):
-    def __init__(self, path, name, nodetype, iectype = None, vartype = None):
+    def __init__(self, path, name, nodetype, iectype = None, vartype = None, hmiclass = None):
         self.path = path
         self.name = name
         self.nodetype = nodetype
+        self.hmiclass = hmiclass
 
         if iectype is not None:
             self.iectype = iectype
             self.vartype = vartype
-        if nodetype in ["HMI_LABEL", "HMI_ROOT"]:
+        if nodetype in ["HMI_NODE", "HMI_ROOT"]:
             self.children = []
 
     def pprint(self, indent = 0):
@@ -73,7 +74,7 @@
                 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":
+        if best_child is not None and best_child.nodetype == "HMI_NODE":
             best_child.place_node(node)
         else:
             self.children.append(node)
@@ -136,12 +137,12 @@
            +->v1 HMI_INT
            +->v2 HMI_INT
            +->fb0 (type mhoo)
-           |   +->va HMI_LABEL
+           |   +->va HMI_NODE
            |   +->v3 HMI_INT
            |   +->v4 HMI_INT
            |
            +->fb1 (type mhoo)
-           |   +->va HMI_LABEL
+           |   +->va HMI_NODE
            |   +->v3 HMI_INT
            |   +->v4 HMI_INT
            |
@@ -152,11 +153,11 @@
           hmi0
            +->v1
            +->v2
-           +->fb0_va
+           +->fb0 class:va
            |   +-> v3
            |   +-> v4
            |
-           +->fb1_va
+           +->fb1 class:va
            |   +-> v3
            |   +-> v4
            |
@@ -180,7 +181,14 @@
             # ignores variables starting with _TMP_
             if path[-1].startswith("_TMP_"):
                 continue
-            new_node = HMITreeNode(path, path[-1], v["derived"], v["type"], v["vartype"])
+            derived = v["derived"]
+            kwargs={}
+            if derived == "HMI_NODE":
+                name = path[-2]
+                kwargs['hmiclass'] = path[-1]
+            else:
+                name = path[-1]
+            new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], **kwargs)
             hmi_tree_root.place_node(new_node)
 
         variable_decl_array = []
@@ -189,7 +197,7 @@
         item_count = 0
         for node in hmi_tree_root.traverse():
             if hasattr(node, "iectype") and \
-               node.nodetype not in ["HMI_CLASS", "HMI_LABEL"]:
+               node.nodetype not in ["HMI_NODE"]:
                 sz = DebugTypesSize.get(node.iectype, 0)
                 variable_decl_array += [
                     "{&(" + ".".join(node.path) + "), " + node.iectype + {
@@ -357,7 +365,10 @@
             svgdom = etree.parse(svgfile)
 
             # call xslt transform on Inkscape's SVG to generate XHTML
-            result = transform.transform(svgdom)
+            try:
+                result = transform.transform(svgdom)
+            except XSLTApplyError as e:
+                self.FatalError("SVGHMI " + view_name  + ": " + e.message)
            
             result.write(target_file, encoding="utf-8")
             # print(str(result))
--- a/tests/svghmi/plc.xml	Wed Nov 13 11:21:04 2019 +0100
+++ b/tests/svghmi/plc.xml	Wed Nov 13 11:22:53 2019 +0100
@@ -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-10-27T21:48:33">
+  <contentHeader name="Unnamed" modificationDateTime="2019-11-12T13:19:15">
     <coordinateInfo>
       <fbd>
         <scaling x="5" y="5"/>
@@ -30,6 +30,11 @@
                 <derived name="PumpControl"/>
               </type>
             </variable>
+            <variable name="Pump1">
+              <type>
+                <derived name="PumpControl"/>
+              </type>
+            </variable>
           </localVars>
         </interface>
         <body>
@@ -57,6 +62,24 @@
               </connectionPointOut>
               <expression>TargetPressure</expression>
             </inVariable>
+            <block localId="1" typeName="PumpControl" instanceName="Pump1" executionOrderId="0" height="40" width="127">
+              <position x="605" y="145"/>
+              <inputVariables>
+                <variable formalParameter="TargetPressure">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="5">
+                      <position x="605" y="175"/>
+                      <position x="587" y="175"/>
+                      <position x="587" y="80"/>
+                      <position x="570" y="80"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables/>
+            </block>
           </FBD>
         </body>
       </pou>
@@ -65,7 +88,7 @@
           <localVars>
             <variable name="Pump">
               <type>
-                <derived name="HMI_LABEL"/>
+                <derived name="HMI_NODE"/>
               </type>
             </variable>
             <variable name="Pressure">
--- a/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Wed Nov 13 11:21:04 2019 +0100
+++ b/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Wed Nov 13 11:22:53 2019 +0100
@@ -113,12 +113,12 @@
      inkscape:pageopacity="0"
      inkscape:pageshadow="2"
      inkscape:document-units="px"
-     inkscape:current-layer="g110"
+     inkscape:current-layer="hmi0"
      showgrid="false"
      units="px"
      inkscape:zoom="0.8046875"
-     inkscape:cx="478.76479"
-     inkscape:cy="-403.42943"
+     inkscape:cx="959.69683"
+     inkscape:cy="656.6094"
      inkscape:window-width="1600"
      inkscape:window-height="886"
      inkscape:window-x="0"
@@ -321,7 +321,7 @@
        inkscape:label="=0" />
   </g>
   <text
-     inkscape:label="HMI:Display@/PUMP/PRESSURE"
+     inkscape:label="HMI:Display@/PUMP0/PRESSURE"
      id="text823"
      y="218.24219"
      x="756.32812"
@@ -335,7 +335,7 @@
   <g
      id="g4523"
      transform="matrix(3.7795276,0,0,3.7795276,308.51002,630.30393)"
-     inkscape:label="HMI:Meter@/PUMP/SLOTH">
+     inkscape:label="HMI:Meter@/PUMP0/SLOTH">
     <path
        style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#3ee800;stroke-width:26.45833397;stroke-miterlimit:4;stroke-dasharray:2.64583333, 2.64583333;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
        id="path4499"
@@ -635,7 +635,7 @@
          sodipodi:role="line">Home</tspan></text>
   </g>
   <g
-     inkscape:label="HMI:Meter@/PUMP/SLOTH"
+     inkscape:label="HMI:Meter@/PUMP0/SLOTH"
      transform="matrix(7.5590552,0,0,7.5590552,-244.3956,1321.2434)"
      id="g110">
     <path
@@ -892,7 +892,7 @@
      x="736.32812"
      y="1478.2422"
      id="text995"
-     inkscape:label="HMI:Display@/PUMP/PRESSURE"><tspan
+     inkscape:label="HMI:Display@/PUMP0/PRESSURE"><tspan
        sodipodi:role="line"
        id="tspan993"
        x="736.32812"