# HG changeset patch # User Edouard Tisserant # Date 1597149453 -7200 # Node ID f6fe42b7ce60258e308532cae7eca4addf9444f8 # Parent 15e2df3e5610e5c73245ae4c8f78530ffd4fc80c SVGHMI: finished initial implementation of PAGE_LOCAL and HMI_LOCAL variables. diff -r 15e2df3e5610 -r f6fe42b7ce60 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Sat Aug 08 15:53:28 2020 +0200 +++ b/svghmi/gen_index_xhtml.xslt Tue Aug 11 14:37:33 2020 +0200 @@ -1,6 +1,6 @@ - - + + @@ -875,7 +875,7 @@ " - + " , @@ -959,36 +959,54 @@ + var cache = hmitree_types.map(_ignored => undefined); + + + function page_local_index(varname, pagename){ let pagevars = hmi_locals[pagename]; + let new_index; + if(pagevars == undefined){ - let new_index = next_available_index++; - - hmi_locals[pagename] = {varname:new_index} - - return new_index; + new_index = next_available_index++; + + hmi_locals[pagename] = {[varname]:new_index} + + console.log("pagelocalindex insert",varname, pagename, new_index); } else { + + + console.log("pagevars",pagevars); + let result = pagevars[varname]; - if(result==undefined){ - - let new_index = next_available_index++; - - pagevars[varname] = new_index; - - return new_index; + if(result != undefined) { + + console.log("pagelocalindex reuse",varname, pagename, result); + + return result; } - return result; + + + new_index = next_available_index++; + + pagevars[varname] = new_index; + + console.log("pagelocalindex addwidget",varname, pagename, new_index); } + cache[new_index] = ""; + + return new_index; + } @@ -1050,7 +1068,7 @@ index += this.offset; - subscribers[index].delete(this); + subscribers(index).delete(this); } @@ -1078,9 +1096,7 @@ let index = this.get_variable_index(i); - if(index > last_remote_index) return; - - subscribers[index].add(this); + subscribers(index).add(this); } @@ -1116,8 +1132,6 @@ if(typeof(index) == "string"){ - let page = this.relativeness[varnum]; - index = page_local_index(index, this.container_id); } else { @@ -1152,7 +1166,7 @@ new_hmi_value(index, value, oldval) { - try { + /* try {*/ // TODO avoid searching, store index at sub() @@ -1192,11 +1206,11 @@ } - } catch(err) { + /* } catch(err) { console.log(err); - } + }*/ } @@ -1557,7 +1571,22 @@ " is not a svg::text element - fields: [], + + + + + "" + + 0 + + + , + + + + fields: [ + + ], @@ -2955,14 +2984,6 @@ " is not valid. - console.log(" - - ", " - - ", - - ); - id(" ").setAttribute("xlink:href", @@ -2976,14 +2997,6 @@ - console.log(" - - ", " - - ", - - ); - id(" ").textContent = String( @@ -3034,8 +3047,6 @@ spread_json_data: function(jdata) { - console.log(jdata); - @@ -3704,7 +3715,7 @@ - + @@ -3745,8 +3756,6 @@ - var cache = hmitree_types.map(_ignored => undefined); - var updates = {}; var need_cache_apply = []; @@ -3757,7 +3766,7 @@ function dispatch_value(index, value) { - let widgets = subscribers[index]; + let widgets = subscribers(index); @@ -3857,6 +3866,8 @@ // -> pass Number(index) instead + console.log("apply updated local variable ",index, updates[index]); + dispatch_value(Number(index), updates[index]); delete updates[index]; @@ -4057,19 +4068,65 @@ - // subscription state, as it should be in hmi server - - // hmitree indexed array of integers - - var subscriptions = hmitree_types.map(_ignored => 0); - - - - // subscription state as needed by widget now - - // hmitree indexed array of Sets of widgets objects - - var subscribers = hmitree_types.map(_ignored => new Set()); + var subscriptions = []; + + + + function subscribers(index) { + + let entry = subscriptions[index]; + + let res; + + if(entry == undefined){ + + res = new Set(); + + subscriptions[index] = [res,0]; + + }else{ + + [res, _ign] = entry; + + } + + return res + + } + + + + function get_subscription_period(index) { + + let entry = subscriptions[index]; + + if(entry == undefined) + + return 0; + + let [_ign, period] = entry; + + return period; + + } + + + + function set_subscription_period(index, period) { + + let entry = subscriptions[index]; + + if(entry == undefined){ + + subscriptions[index] = [new Set(), period]; + + } else { + + entry[1] = period; + + } + + } @@ -4079,7 +4136,7 @@ // PLC will periodically send variable at given frequency - subscribers[heartbeat_index].add({ + subscribers(heartbeat_index).add({ /* type: "Watchdog", */ @@ -4097,19 +4154,21 @@ + + function update_subscriptions() { let delta = []; - for(let index = 0; index < subscribers.length; index++){ - - let widgets = subscribers[index]; + for(let index in subscriptions){ + + let widgets = subscribers(index); // periods are in ms - let previous_period = subscriptions[index]; + let previous_period = get_subscription_period(index); @@ -4143,15 +4202,19 @@ if(previous_period != new_period) { - subscriptions[index] = new_period; - - delta.push( - - new Uint8Array([2]), /* subscribe = 2 */ - - new Uint32Array([index]), - - new Uint16Array([new_period])); + set_subscription_period(index, new_period); + + if(index <= last_remote_index){ + + delta.push( + + new Uint8Array([2]), /* subscribe = 2 */ + + new Uint32Array([index]), + + new Uint16Array([new_period])); + + } } @@ -4167,11 +4230,11 @@ if(index > last_remote_index){ - cache[index] = value; - console.log("updated local variable ",index,value); - /* TODO : dispatch value ASAP */ + updates[index] = value; + + requestHMIAnimation(); return; @@ -4375,7 +4438,7 @@ - container_id = String([page_name, page_index]); + container_id = page_name + (page_index != undefined ? page_index : ""); diff -r 15e2df3e5610 -r f6fe42b7ce60 svghmi/svghmi.js --- a/svghmi/svghmi.js Sat Aug 08 15:53:28 2020 +0200 +++ b/svghmi/svghmi.js Tue Aug 11 14:37:33 2020 +0200 @@ -1,12 +1,11 @@ // svghmi.js -var cache = hmitree_types.map(_ignored => undefined); var updates = {}; var need_cache_apply = []; function dispatch_value(index, value) { - let widgets = subscribers[index]; + let widgets = subscribers(index); let oldval = cache[index]; cache[index] = value; @@ -156,18 +155,41 @@ send_blob(new Uint8Array([1])); /* reset = 1 */ }; -// subscription state, as it should be in hmi server -// hmitree indexed array of integers -var subscriptions = hmitree_types.map(_ignored => 0); - -// subscription state as needed by widget now -// hmitree indexed array of Sets of widgets objects -var subscribers = hmitree_types.map(_ignored => new Set()); +var subscriptions = []; + +function subscribers(index) { + let entry = subscriptions[index]; + let res; + if(entry == undefined){ + res = new Set(); + subscriptions[index] = [res,0]; + }else{ + [res, _ign] = entry; + } + return res +} + +function get_subscription_period(index) { + let entry = subscriptions[index]; + if(entry == undefined) + return 0; + let [_ign, period] = entry; + return period; +} + +function set_subscription_period(index, period) { + let entry = subscriptions[index]; + if(entry == undefined){ + subscriptions[index] = [new Set(), period]; + } else { + entry[1] = period; + } +} // artificially subscribe the watchdog widget to "/heartbeat" hmi variable // Since dispatch directly calls change_hmi_value, // PLC will periodically send variable at given frequency -subscribers[heartbeat_index].add({ +subscribers(heartbeat_index).add({ /* type: "Watchdog", */ frequency: 1, indexes: [heartbeat_index], @@ -176,13 +198,14 @@ } }); + function update_subscriptions() { let delta = []; - for(let index = 0; index < subscribers.length; index++){ - let widgets = subscribers[index]; + for(let index in subscriptions){ + let widgets = subscribers(index); // periods are in ms - let previous_period = subscriptions[index]; + let previous_period = get_subscription_period(index); // subscribing with a zero period is unsubscribing let new_period = 0; @@ -199,11 +222,13 @@ } if(previous_period != new_period) { - subscriptions[index] = new_period; - delta.push( - new Uint8Array([2]), /* subscribe = 2 */ - new Uint32Array([index]), - new Uint16Array([new_period])); + set_subscription_period(index, new_period); + if(index <= last_remote_index){ + delta.push( + new Uint8Array([2]), /* subscribe = 2 */ + new Uint32Array([index]), + new Uint16Array([new_period])); + } } } send_blob(delta); @@ -211,9 +236,9 @@ function send_hmi_value(index, value) { if(index > last_remote_index){ - cache[index] = value; console.log("updated local variable ",index,value); - /* TODO : dispatch value ASAP */ + updates[index] = value; + requestHMIAnimation(); return; } @@ -315,7 +340,7 @@ } var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; - container_id = String([page_name, page_index]); + container_id = page_name + (page_index != undefined ? page_index : ""); new_desc.widgets.map(([widget,relativeness])=>widget.sub(new_offset,relativeness,container_id)); diff -r 15e2df3e5610 -r f6fe42b7ce60 svghmi/widget_display.ysl2 --- a/svghmi/widget_display.ysl2 Sat Aug 08 15:53:28 2020 +0200 +++ b/svghmi/widget_display.ysl2 Tue Aug 11 14:37:33 2020 +0200 @@ -18,7 +18,14 @@ if "$hmi_element[not(self::svg:text)]" error > Display Widget id="«$hmi_element/@id»" is not a svg::text element - | fields: [], + const "field_initializer" foreach "path" { + choose{ + when "@type='HMI_STRING'" > "" + otherwise 0 + } + if "position()!=last()" > , + } + | fields: [«$field_initializer»], } emit "preamble:display" diff -r 15e2df3e5610 -r f6fe42b7ce60 svghmi/widgets_common.ysl2 --- a/svghmi/widgets_common.ysl2 Sat Aug 08 15:53:28 2020 +0200 +++ b/svghmi/widgets_common.ysl2 Tue Aug 11 14:37:33 2020 +0200 @@ -32,7 +32,7 @@ when "not(@type)" error > Widget «$widget/@type» id="«$eltid»" : No match for path "«@value»" in HMI tree when "@type = 'PAGE_LOCAL'" - > "«substring(1,@value)»"`if "position()!=last()" > ,` + > "«substring(@value, 1)»"`if "position()!=last()" > ,` when "@type = 'HMI_LOCAL'" > hmi_local_index("«@value»")`if "position()!=last()" > ,` } @@ -75,21 +75,25 @@ var last_remote_index = hmitree_types.length - 1; var next_available_index = hmitree_types.length; + var cache = hmitree_types.map(_ignored => undefined); + function page_local_index(varname, pagename){ let pagevars = hmi_locals[pagename]; + let new_index; if(pagevars == undefined){ - let new_index = next_available_index++; - hmi_locals[pagename] = {varname:new_index} - return new_index; + new_index = next_available_index++; + hmi_locals[pagename] = {[varname]:new_index} } else { let result = pagevars[varname]; - if(result==undefined){ - let new_index = next_available_index++; - pagevars[varname] = new_index; - return new_index; - } - return result; - } + if(result != undefined) { + return result; + } + + new_index = next_available_index++; + pagevars[varname] = new_index; + } + cache[new_index] = ""; + return new_index; } function hmi_local_index(varname){ @@ -119,7 +123,7 @@ let index = this.indexes[i]; if(this.relativeness[i]) index += this.offset; - subscribers[index].delete(this); + subscribers(index).delete(this); } this.offset = 0; this.relativeness = undefined; @@ -133,8 +137,7 @@ if(!this.unsubscribable) for(let i = 0; i < this.indexes.length; i++) { let index = this.get_variable_index(i); - if(index > last_remote_index) return; - subscribers[index].add(this); + subscribers(index).add(this); } need_cache_apply.push(this); } @@ -152,7 +155,6 @@ get_variable_index(varnum) { let index = this.indexes[varnum]; if(typeof(index) == "string"){ - let page = this.relativeness[varnum]; index = page_local_index(index, this.container_id); } else { if(this.relativeness[varnum]){