# HG changeset patch # User Edouard Tisserant # Date 1579274745 -3600 # Node ID 4c2c50f6073033f65a410ab18e6e5cf2e1c1704c # Parent be947a338760bbf2fbbf22b39d2fa3a4e1441433 SVGHMI : HMI_STRING now also supported from HMI to PLC diff -r be947a338760 -r 4c2c50f60730 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Wed Jan 15 11:13:39 2020 +0100 +++ b/svghmi/gen_index_xhtml.xslt Fri Jan 17 16:25:45 2020 +0100 @@ -470,7 +470,7 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text>// Register message reception handler + <xsl:text>// Register message reception handler </xsl:text> <xsl:text>ws.onmessage = function (evt) { </xsl:text> @@ -564,9 +564,29 @@ </xsl:text> <xsl:text>const typedarray_types = { </xsl:text> - <xsl:text> INT: Int16Array, -</xsl:text> - <xsl:text> BOOL: Uint8Array + <xsl:text> INT: (number) => new Int16Array([number]), +</xsl:text> + <xsl:text> BOOL: (truth) => new Int16Array([truth]), +</xsl:text> + <xsl:text> STRING: (str) => { +</xsl:text> + <xsl:text> // beremiz default string max size is 128 +</xsl:text> + <xsl:text> str = str.slice(0,128); +</xsl:text> + <xsl:text> binary = new Uint8Array(str.length + 1); +</xsl:text> + <xsl:text> binary[0] = str.length; +</xsl:text> + <xsl:text> for(var i = 0; i < str.length; i++){ +</xsl:text> + <xsl:text> binary[i+1] = str.charCodeAt(i); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> return binary; +</xsl:text> + <xsl:text> } </xsl:text> <xsl:text> /* TODO */ </xsl:text> @@ -600,7 +620,7 @@ </xsl:text> <xsl:text>// artificially subscribe the watchdog widget to "/heartbeat" hmi variable </xsl:text> - <xsl:text>// Since dispatch directly calls change_hmi_value, + <xsl:text>// Since dispatch directly calls change_hmi_value, </xsl:text> <xsl:text>// PLC will periodically send variable at given frequency </xsl:text> @@ -616,7 +636,7 @@ </xsl:text> <xsl:text> // console.log("Heartbeat" + value); </xsl:text> - <xsl:text> change_hmi_value(this.indexes[0], "+1"); + <xsl:text> change_hmi_value(heartbeat_index, "+1"); </xsl:text> <xsl:text> } </xsl:text> @@ -690,15 +710,15 @@ </xsl:text> <xsl:text> let iectype = hmitree_types[index]; </xsl:text> - <xsl:text> let jstype = typedarray_types[iectype]; + <xsl:text> let tobinary = typedarray_types[iectype]; </xsl:text> <xsl:text> send_blob([ </xsl:text> <xsl:text> new Uint8Array([0]), /* setval = 0 */ </xsl:text> - <xsl:text> new Uint32Array([index]), -</xsl:text> - <xsl:text> new jstype([value])]); + <xsl:text> new Uint32Array([index]), +</xsl:text> + <xsl:text> tobinary(value)]); </xsl:text> <xsl:text> </xsl:text> @@ -796,8 +816,6 @@ </xsl:text> <xsl:text> dispatch_value_to_widget(widget, index, cached_val, cached_val); </xsl:text> - <xsl:text> -</xsl:text> <xsl:text> } </xsl:text> <xsl:text> } @@ -967,6 +985,19 @@ <xsl:text>}, </xsl:text> </xsl:template> + <func:function name="func:escape_quotes"> + <xsl:param name="txt"/> + <xsl:variable name="frst" select="substring-before($txt,'"')"/> + <xsl:variable name="frstln" select="string-length($frst)"/> + <xsl:choose> + <xsl:when test="$frstln > 0 and string-length($txt) > $frstln"> + <func:result select="concat($frst,'\"',func:escape_quotes(substring-after($txt,'"')))"/> + </xsl:when> + <xsl:otherwise> + <func:result select="$txt"/> + </xsl:otherwise> + </xsl:choose> + </func:function> <xsl:template mode="widget_defs" match="widget[@type='Input']"> <xsl:param name="hmi_element"/> <xsl:text>frequency: 5, @@ -996,7 +1027,7 @@ <xsl:text> evt => alert('XXX TODO : Edit value')); </xsl:text> </xsl:if> - <xsl:for-each select="$hmi_element/*[regexp:test(@inkscape:label,'^[=+\-][0-9]+')]"> + <xsl:for-each select="$hmi_element/*[regexp:test(@inkscape:label,'^[=+\-].+')]"> <xsl:text> document.getElementById("</xsl:text> <xsl:value-of select="@id"/> <xsl:text>").addEventListener( @@ -1004,7 +1035,7 @@ <xsl:text> "click", </xsl:text> <xsl:text> evt => {let new_val = change_hmi_value(this.indexes[0], "</xsl:text> - <xsl:value-of select="@inkscape:label"/> + <xsl:value-of select="func:escape_quotes(@inkscape:label)"/> <xsl:text>"); </xsl:text> <xsl:text> this.value_elt.textContent = String(new_val);}); diff -r be947a338760 -r 4c2c50f60730 svghmi/gen_index_xhtml.ysl2 --- a/svghmi/gen_index_xhtml.ysl2 Wed Jan 15 11:13:39 2020 +0100 +++ b/svghmi/gen_index_xhtml.ysl2 Fri Jan 17 16:25:45 2020 +0100 @@ -373,6 +373,21 @@ | }, } + def "func:escape_quotes" { + param "txt"; + // have to use a python string to enter escaped quote + const "frst", !"substring-before($txt,'\"')"!; + const "frstln", "string-length($frst)"; + choose { + when "$frstln > 0 and string-length($txt) > $frstln" { + result !"concat($frst,'\\\"',func:escape_quotes(substring-after($txt,'\"')))"!; + } + otherwise { + result "$txt"; + } + } + } + template "widget[@type='Input']", mode="widget_defs" { param "hmi_element"; | frequency: 5, @@ -387,10 +402,10 @@ | "click", | evt => alert('XXX TODO : Edit value')); } - foreach "$hmi_element/*[regexp:test(@inkscape:label,'^[=+\-][0-9]+')]" { + foreach "$hmi_element/*[regexp:test(@inkscape:label,'^[=+\-].+')]" { | document.getElementById("«@id»").addEventListener( | "click", - | evt => {let new_val = change_hmi_value(this.indexes[0], "«@inkscape:label»"); + | evt => {let new_val = change_hmi_value(this.indexes[0], "«func:escape_quotes(@inkscape:label)»"); | this.value_elt.textContent = String(new_val);}); /* could gray out value until refreshed */ } diff -r be947a338760 -r 4c2c50f60730 svghmi/svghmi.c --- a/svghmi/svghmi.c Wed Jan 15 11:13:39 2020 +0100 +++ b/svghmi/svghmi.c Fri Jan 17 16:25:45 2020 +0100 @@ -300,7 +300,10 @@ void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); void *dst_p = &rbuf[dsc->buf_index]; uint32_t sz = __get_type_enum_size(dsc->type); -#warning TODO: size of string in recv + + if(__Is_a_string(dsc)){ + sz = ((STRING*)valptr)->len + 1; + } if((valptr + sz) <= end) { diff -r be947a338760 -r 4c2c50f60730 svghmi/svghmi.js --- a/svghmi/svghmi.js Wed Jan 15 11:13:39 2020 +0100 +++ b/svghmi/svghmi.js Fri Jan 17 16:25:45 2020 +0100 @@ -59,7 +59,7 @@ } }; -// Register message reception handler +// Register message reception handler ws.onmessage = function (evt) { let data = evt.data; @@ -106,8 +106,18 @@ }; const typedarray_types = { - INT: Int16Array, - BOOL: Uint8Array + INT: (number) => new Int16Array([number]), + BOOL: (truth) => new Int16Array([truth]), + STRING: (str) => { + // beremiz default string max size is 128 + str = str.slice(0,128); + binary = new Uint8Array(str.length + 1); + binary[0] = str.length; + for(var i = 0; i < str.length; i++){ + binary[i+1] = str.charCodeAt(i); + } + return binary; + } /* TODO */ }; @@ -124,7 +134,7 @@ var subscribers = hmitree_types.map(_ignored => new Set()); // artificially subscribe the watchdog widget to "/heartbeat" hmi variable -// Since dispatch directly calls change_hmi_value, +// Since dispatch directly calls change_hmi_value, // PLC will periodically send variable at given frequency subscribers[heartbeat_index].add({ /* type: "Watchdog", */ @@ -132,7 +142,7 @@ indexes: [heartbeat_index], dispatch: function(value) { // console.log("Heartbeat" + value); - change_hmi_value(this.indexes[0], "+1"); + change_hmi_value(heartbeat_index, "+1"); } }); @@ -169,11 +179,11 @@ function send_hmi_value(index, value) { let iectype = hmitree_types[index]; - let jstype = typedarray_types[iectype]; + let tobinary = typedarray_types[iectype]; send_blob([ new Uint8Array([0]), /* setval = 0 */ - new Uint32Array([index]), - new jstype([value])]); + new Uint32Array([index]), + tobinary(value)]); cache[index] = value; }; @@ -222,7 +232,6 @@ let cached_val = cache[index]; if(cached_val != undefined) dispatch_value_to_widget(widget, index, cached_val, cached_val); - } } svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); diff -r be947a338760 -r 4c2c50f60730 tests/svghmi/svghmi_0@svghmi/svghmi.svg --- a/tests/svghmi/svghmi_0@svghmi/svghmi.svg Wed Jan 15 11:13:39 2020 +0100 +++ b/tests/svghmi/svghmi_0@svghmi/svghmi.svg Fri Jan 17 16:25:45 2020 +0100 @@ -31,6 +31,17 @@ </metadata> <defs id="defs2"> + <inkscape:tag + id="Set 1" + inkscape:label="HMI:AccessList@Admin" + inkscape:expanded="true"> + <inkscape:tagref + xlink:href="#text995" + id="tagref192" /> + <inkscape:tagref + xlink:href="#g991" + id="tagref194" /> + </inkscape:tag> <linearGradient inkscape:collect="always" id="linearGradient962"> @@ -113,14 +124,14 @@ inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" - inkscape:current-layer="hmi0" + inkscape:current-layer="g208" showgrid="false" units="px" - inkscape:zoom="1.2321777" - inkscape:cx="398.68209" - inkscape:cy="328.86048" - inkscape:window-width="1920" - inkscape:window-height="2105" + inkscape:zoom="2" + inkscape:cx="275.28708" + inkscape:cy="344.53292" + inkscape:window-width="1600" + inkscape:window-height="886" inkscape:window-x="0" inkscape:window-y="27" inkscape:window-maximized="0" @@ -902,13 +913,13 @@ xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="98.164062" - y="489.12109" + y="469.12109" id="text134" inkscape:label="HMI:Display@/PUMP0/STROUT"><tspan sodipodi:role="line" id="tspan132" x="98.164062" - y="489.12109" + y="469.12109" style="fill:#ffffff;fill-opacity:1;stroke-width:0.5px">8888</tspan></text> <text inkscape:label="HMI:Display@/PUMP0/BOOLOUT" @@ -922,4 +933,194 @@ x="98.164062" id="tspan136" sodipodi:role="line">8888</tspan></text> + <g + transform="matrix(0.5,0,0,0.5,90.110264,225.71623)" + id="g208" + inkscape:label="HMI:Input@/PUMP0/STRIN" + style="stroke-width:2"> + <text + inkscape:label="value" + id="text164" + y="218.24219" + x="136.32812" + style="font-style:normal;font-weight:normal;font-size:160px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="stroke-width:2px" + y="218.24219" + x="136.32812" + id="tspan162" + sodipodi:role="line">8888</tspan></text> + <rect + style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ff00ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + id="rect166" + width="407.7037" + height="128" + x="139.85185" + y="95.40741" + onclick="" + inkscape:label="edit" /> + <g + transform="translate(-416.52022,170.47452)" + inkscape:label="+"dhu"" + id="g174" + style="stroke-width:2"> + <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;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + inkscape:transform-center-y="-14.956361" + d="m 797.19546,145.18619 -80.62929,0.60214 -0.60215,-80.629288 80.6293,-0.60214 z" + id="path168" + inkscape:connector-curvature="0" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="733.58197" + y="111.05016" + id="text172"><tspan + sodipodi:role="line" + id="tspan170" + x="733.58197" + y="111.05016" + style="stroke-width:1px">dhu</tspan></text> + </g> + <g + transform="translate(-416.52022,170.47452)" + inkscape:label="="plop"" + id="g182" + style="stroke-width:2"> + <path + transform="matrix(0,-2.0000001,1.9999999,0,1034.195,1298.6541)" + sodipodi:type="star" + 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;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + id="path176" + sodipodi:sides="3" + sodipodi:cx="596.74072" + sodipodi:cy="-184.98808" + sodipodi:r1="29.912722" + sodipodi:r2="14.956361" + sodipodi:arg1="0.52359878" + sodipodi:arg2="1.5707963" + inkscape:flatsided="true" + inkscape:rounded="0" + inkscape:randomized="0" + d="m 622.6459,-170.03172 -51.81035,0 25.90517,-44.86908 z" + inkscape:transform-center-y="-3.6154501e-05" + inkscape:transform-center-x="14.956371" /> + <text + id="text180" + y="111.05016" + x="633.09552" + style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="stroke-width:1px" + y="111.05016" + x="633.09552" + id="tspan178" + sodipodi:role="line">plop</tspan></text> + </g> + <g + transform="translate(-416.52022,170.47452)" + inkscape:label="="mhoo"" + id="g190" + style="stroke-width:2"> + <path + inkscape:transform-center-y="-5.9989963e-06" + d="m 648.55108,-186.34718 -103.62071,0 51.81035,-89.73817 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="1.5707963" + sodipodi:arg1="0.52359878" + sodipodi:r2="29.912722" + sodipodi:r1="59.825443" + sodipodi:cy="-216.2599" + sodipodi:cx="596.74072" + sodipodi:sides="3" + id="path184" + 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;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + sodipodi:type="star" + transform="rotate(-90,746.45698,-44.543641)" + inkscape:transform-center-x="14.956364" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="537.25018" + y="111.05016" + id="text188"><tspan + sodipodi:role="line" + id="tspan186" + x="537.25018" + y="111.05016" + style="stroke-width:1px">mhoo</tspan></text> + </g> + <g + transform="translate(-416.52022,170.47452)" + inkscape:label="="yodl"" + id="g198" + style="stroke-width:2"> + <path + sodipodi:type="star" + 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;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + id="path192" + sodipodi:sides="3" + sodipodi:cx="596.74072" + sodipodi:cy="105.17262" + sodipodi:r1="59.825443" + sodipodi:r2="29.912722" + sodipodi:arg1="0.52359878" + sodipodi:arg2="1.5707963" + inkscape:flatsided="true" + inkscape:rounded="0" + inkscape:randomized="0" + d="m 648.55108,135.08534 -103.62071,0 51.81035,-89.738161 z" + inkscape:transform-center-y="-5.5023185e-06" + transform="matrix(0,-1,-1,0,1043.9134,701.91334)" + inkscape:transform-center-x="-14.956365" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="925.82605" + y="111.05016" + id="text196"><tspan + sodipodi:role="line" + id="tspan194" + x="925.82605" + y="111.05016" + style="stroke-width:1px">yodl</tspan></text> + </g> + <g + transform="translate(-416.52022,170.47452)" + inkscape:label="="mhe"" + id="g206" + style="stroke-width:2"> + <path + inkscape:transform-center-y="-3.3040441e-05" + d="m 622.6459,151.4008 -51.81035,0 25.90517,-44.86908 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="1.5707963" + sodipodi:arg1="0.52359878" + sodipodi:r2="14.956361" + sodipodi:r1="29.912722" + sodipodi:cy="136.44444" + sodipodi:cx="596.74072" + sodipodi:sides="3" + id="path200" + 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;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + sodipodi:type="star" + transform="matrix(0,-2.0000001,-1.9999999,0,1122.1514,1298.6541)" + inkscape:transform-center-x="-14.956349" /> + <text + id="text204" + y="111.05016" + x="842.71497" + style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="stroke-width:1px" + y="111.05016" + x="842.71497" + id="tspan202" + sodipodi:role="line">mhe</tspan></text> + </g> + </g> </svg>