--- 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);});
--- 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 */
}
--- 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)
{
--- 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(" "));
--- 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>