# HG changeset patch # User Edouard Tisserant # Date 1572445025 -3600 # Node ID 4a81cec5f78617aae2da8b85de9defd6bdbc02aa # Parent 63b9a37b73c707d5a254d30816a11437bef496a7 SVGHMI - prepare page with cached data when switching. This prevents values that do not change and that was already subscribed in previous page from keeping undefined. diff -r 63b9a37b73c7 -r 4a81cec5f786 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Tue Oct 29 11:18:58 2019 +0100 +++ b/svghmi/gen_index_xhtml.xslt Wed Oct 30 15:17:05 2019 +0100 @@ -344,6 +344,38 @@ + function dispatch_value_to_widget(widget, index, value, oldval) { + + let idxidx = widget.indexes.indexOf(index); + + if(idxidx == -1){ + + throw new Error("Dispatching to widget not interested, should not happen."); + + } + + let d = widget.dispatch; + + if(typeof(d) == "function" && idxidx == 0){ + + return d.call(widget, value, oldval); + + }else if(typeof(d) == "object" && d.length >= idxidx){ + + return d[idxidx].call(widget, value, oldval); + + }/* else dispatch_0, ..., dispatch_n ? */ + + /*else { + + throw new Error("Dunno how to dispatch to widget at index = " + index); + + }*/ + + } + + + function dispatch_value(index, value) { let widgets = subscribers[index]; @@ -360,378 +392,364 @@ for(let widget of widgets){ - let idxidx = widget.indexes.indexOf(index); - - if(idxidx == -1){ - - throw new Error("Dispatching to widget not interested, should not happen."); + dispatch_value_to_widget(widget, index, value, oldval); + + } + + } + + }; + + + + function init_widgets() { + + Object.keys(hmi_widgets).forEach(function(id) { + + let widget = hmi_widgets[id]; + + let init = widget.init; + + if(typeof(init) == "function"){ + + return init.call(widget); + + } + + }); + + }; + + + + // Open WebSocket to relative "/ws" address + + var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); + + ws.binaryType = 'arraybuffer'; + + + + const dvgetters = { + + INT: [DataView.prototype.getInt16, 2], + + BOOL: [DataView.prototype.getInt8, 1] + + /* TODO */ + + }; + + + + // Register message reception handler + + ws.onmessage = function (evt) { + + + + let data = evt.data; + + let dv = new DataView(data); + + let i = 0; + + try { + + for(let hash_int of hmi_hash) { + + if(hash_int != dv.getUint8(i)){ + + throw new Error("Hash doesn't match"); + + }; + + i++; + + }; + + + + while(i < data.byteLength){ + + let index = dv.getUint32(i, true); + + i += 4; + + let iectype = hmitree_types[index]; + + if(iectype != undefined){ + + let [dvgetter, bytesize] = dvgetters[iectype]; + + let value = dvgetter.call(dv,i,true); + + dispatch_value(index, value); + + i += bytesize; + + } else { + + throw new Error("Unknown index "+index) } - let d = widget.dispatch; - - if(typeof(d) == "function" && idxidx == 0){ - - return d.call(widget, value, oldval); - - }else if(typeof(d) == "object" && d.length >= idxidx){ - - return d[idxidx].call(widget, value, oldval); - - }/* else dispatch_0, ..., dispatch_n ? */ - - /*else { - - throw new Error("Dunno how to dispatch to widget at index = " + index); - - }*/ + }; + + } catch(err) { + + // 1003 is for "Unsupported Data" + + // ws.close(1003, err.message); + + + + // TODO : remove debug alert ? + + alert("Error : "+err.message+"\nHMI will be reloaded."); + + + + // force reload ignoring cache + + location.reload(true); + + } + + }; + + + + + + function send_blob(data) { + + if(data.length > 0) { + + ws.send(new Blob([new Uint8Array(hmi_hash)].concat(data))); + + }; + + }; + + + + const typedarray_types = { + + INT: Int16Array, + + BOOL: Uint8Array + + /* TODO */ + + }; + + + + function send_reset() { + + 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()); + + + + function update_subscriptions() { + + let delta = []; + + for(let index = 0; index < subscribers.length; index++){ + + let widgets = subscribers[index]; + + + + // periods are in ms + + let previous_period = subscriptions[index]; + + + + let new_period = 0; + + if(widgets.size > 0) { + + let maxfreq = 0; + + for(let widget of widgets) + + if(maxfreq < widget.frequency) + + maxfreq = widget.frequency; + + + + if(maxfreq != 0) + + new_period = 1000/maxfreq; } + + + if(previous_period != new_period) { + + subscriptions[index] = new_period; + + delta.push( + + new Uint8Array([2]), /* subscribe = 2 */ + + new Uint32Array([index]), + + new Uint16Array([new_period])); + + } + } - }; - - - - function init_widgets() { - - Object.keys(hmi_widgets).forEach(function(id) { - - let widget = hmi_widgets[id]; - - let init = widget.init; - - if(typeof(init) == "function"){ - - return init.call(widget); + send_blob(delta); + + }; + + + + function send_hmi_value(index, value) { + + let iectype = hmitree_types[index]; + + let jstype = typedarray_types[iectype]; + + send_blob([ + + new Uint8Array([0]), /* setval = 0 */ + + new Uint32Array([index]), + + new jstype([value])]); + + + + cache[index] = value; + + }; + + + + function change_hmi_value(index, opstr) { + + let op = opstr[0]; + + let given_val = opstr.slice(1); + + let old_val = cache[index] + + let new_val; + + switch(op){ + + case "=": + + eval("new_val"+opstr); + + break; + + case "+": + + case "-": + + case "*": + + case "/": + + if(old_val != undefined) + + new_val = eval("old_val"+opstr); + + break; + + } + + if(new_val != undefined && old_val != new_val) + + send_hmi_value(index, new_val); + + return new_val; + + } + + + + var current_page; + + + + function switch_page(page_name) { + + let old_desc = page_desc[current_page]; + + let new_desc = page_desc[page_name]; + + /* TODO hide / show widgets */ + + + + /* remove subsribers of previous page if any */ + + if(old_desc) for(let widget of old_desc.widgets){ + + for(let index of widget.indexes){ + + subscribers[index].delete(widget); } - }); - - }; - - - - // Open WebSocket to relative "/ws" address - - var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); - - ws.binaryType = 'arraybuffer'; - - - - const dvgetters = { - - INT: [DataView.prototype.getInt16, 2], - - BOOL: [DataView.prototype.getInt8, 1] - - /* TODO */ - - }; - - - - // Register message reception handler - - ws.onmessage = function (evt) { - - - - let data = evt.data; - - let dv = new DataView(data); - - let i = 0; - - try { - - for(let hash_int of hmi_hash) { - - if(hash_int != dv.getUint8(i)){ - - throw new Error("Hash doesn't match"); - - }; - - i++; - - }; - - - - while(i < data.byteLength){ - - let index = dv.getUint32(i, true); - - i += 4; - - let iectype = hmitree_types[index]; - - if(iectype != undefined){ - - let [dvgetter, bytesize] = dvgetters[iectype]; - - let value = dvgetter.call(dv,i,true); - - dispatch_value(index, value); - - i += bytesize; - - } else { - - throw new Error("Unknown index "+index) + } + + + + if(new_desc) { + + /* add new subsribers if any */ + + for(let widget of new_desc.widgets){ + + for(let index of widget.indexes){ + + subscribers[index].add(widget); + + let cached_val = cache[index]; + + if(cached_val != undefined) + + dispatch_value_to_widget(widget, index, cached_val, cached_val); + + } - }; - - } catch(err) { - - // 1003 is for "Unsupported Data" - - // ws.close(1003, err.message); - - - - // TODO : remove debug alert ? - - alert("Error : "+err.message+"\nHMI will be reloaded."); - - - - // force reload ignoring cache - - location.reload(true); - - } - - }; - - - - - - function send_blob(data) { - - if(data.length > 0) { - - ws.send(new Blob([new Uint8Array(hmi_hash)].concat(data))); - - }; - - }; - - - - const typedarray_types = { - - INT: Int16Array, - - BOOL: Uint8Array - - /* TODO */ - - }; - - - - function send_reset() { - - 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()); - - - - function update_subscriptions() { - - let delta = []; - - for(let index = 0; index < subscribers.length; index++){ - - let widgets = subscribers[index]; - - - - // periods are in ms - - let previous_period = subscriptions[index]; - - - - let new_period = 0; - - if(widgets.size > 0) { - - let maxfreq = 0; - - for(let widget of widgets) - - if(maxfreq < widget.frequency) - - maxfreq = widget.frequency; - - - - if(maxfreq != 0) - - new_period = 1000/maxfreq; - } - - - if(previous_period != new_period) { - - subscriptions[index] = new_period; - - delta.push( - - new Uint8Array([2]), /* subscribe = 2 */ - - new Uint32Array([index]), - - new Uint16Array([new_period])); - - } - - } - - send_blob(delta); - - }; - - - - function send_hmi_value(index, value) { - - let iectype = hmitree_types[index]; - - let jstype = typedarray_types[iectype]; - - send_blob([ - - new Uint8Array([0]), /* setval = 0 */ - - new Uint32Array([index]), - - new jstype([value])]); - - - - cache[index] = value; - - }; - - - - function change_hmi_value(index, opstr) { - - let op = opstr[0]; - - let given_val = opstr.slice(1); - - let old_val = cache[index] - - let new_val; - - switch(op){ - - case "=": - - eval("new_val"+opstr); - - break; - - case "+": - - case "-": - - case "*": - - case "/": - - if(old_val != undefined) - - new_val = eval("old_val"+opstr); - - break; - - } - - if(new_val != undefined && old_val != new_val) - - send_hmi_value(index, new_val); - - return new_val; - - } - - - - var current_page; - - - - function switch_page(page_name) { - - let old_desc = page_desc[current_page]; - - let new_desc = page_desc[page_name]; - - /* TODO hide / show widgets */ - - - - /* remove subsribers of previous page if any */ - - if(old_desc) for(let widget of old_desc.widgets){ - - for(let index of widget.indexes){ - - subscribers[index].delete(widget); - - } - - } - - - - if(new_desc) { - - /* add new subsribers if any */ - - for(let widget of new_desc.widgets){ - - for(let index of widget.indexes){ - - subscribers[index].add(widget); - - } - - } - svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); + // TODO dispatch current cache in newly opened page + } current_page = page_name; diff -r 63b9a37b73c7 -r 4a81cec5f786 svghmi/svghmi.js --- a/svghmi/svghmi.js Tue Oct 29 11:18:58 2019 +0100 +++ b/svghmi/svghmi.js Wed Oct 30 15:17:05 2019 +0100 @@ -2,6 +2,22 @@ var cache = hmitree_types.map(_ignored => undefined); +function dispatch_value_to_widget(widget, index, value, oldval) { + let idxidx = widget.indexes.indexOf(index); + if(idxidx == -1){ + throw new Error("Dispatching to widget not interested, should not happen."); + } + let d = widget.dispatch; + if(typeof(d) == "function" && idxidx == 0){ + return d.call(widget, value, oldval); + }else if(typeof(d) == "object" && d.length >= idxidx){ + return d[idxidx].call(widget, value, oldval); + }/* else dispatch_0, ..., dispatch_n ? */ + /*else { + throw new Error("Dunno how to dispatch to widget at index = " + index); + }*/ +} + function dispatch_value(index, value) { let widgets = subscribers[index]; @@ -10,19 +26,7 @@ if(widgets.size > 0) { for(let widget of widgets){ - let idxidx = widget.indexes.indexOf(index); - if(idxidx == -1){ - throw new Error("Dispatching to widget not interested, should not happen."); - } - let d = widget.dispatch; - if(typeof(d) == "function" && idxidx == 0){ - return d.call(widget, value, oldval); - }else if(typeof(d) == "object" && d.length >= idxidx){ - return d[idxidx].call(widget, value, oldval); - }/* else dispatch_0, ..., dispatch_n ? */ - /*else { - throw new Error("Dunno how to dispatch to widget at index = " + index); - }*/ + dispatch_value_to_widget(widget, index, value, oldval); } } }; @@ -193,6 +197,10 @@ for(let widget of new_desc.widgets){ for(let index of widget.indexes){ subscribers[index].add(widget); + 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(" "));