# HG changeset patch # User Edouard Tisserant # Date 1636023650 -3600 # Node ID 3a0908b0319d6441d7cbcbc0b71a5f3851827248 # Parent 83ed4ea362db37c6ae8e3f4b48f503442644ede8 SVGHMI: add CURRENT_PAGE_{location} global variable to reflect currently visible page. If PLC wites some valid page reference in that variable, it triggers page switch. Additionally, fixed /HEARTBEAT being subscribed systematically by JS code even when wtchdog is not enabled. diff -r 83ed4ea362db -r 3a0908b0319d svghmi/detachable_pages.ysl2 --- a/svghmi/detachable_pages.ysl2 Fri Oct 29 11:49:22 2021 +0200 +++ b/svghmi/detachable_pages.ysl2 Thu Nov 04 12:00:50 2021 +0100 @@ -169,6 +169,7 @@ if "count($desc/path/@index)=0" warning > Page id="«$page/@id»" : No match for path "«$desc/path/@value»" in HMI tree | page_index: «$desc/path/@index», + | page_class: "«$indexed_hmitree/*[@hmipath = $desc/path/@value]/@class»", } | widgets: [ foreach "$page_managed_widgets" { diff -r 83ed4ea362db -r 3a0908b0319d svghmi/hmi_tree.py --- a/svghmi/hmi_tree.py Fri Oct 29 11:49:22 2021 +0200 +++ b/svghmi/hmi_tree.py Thu Nov 04 12:00:50 2021 +0100 @@ -160,5 +160,4 @@ SPECIAL_NODES = [("HMI_ROOT", "HMI_NODE"), ("heartbeat", "HMI_INT")] - # ("current_page", "HMI_STRING")]) diff -r 83ed4ea362db -r 3a0908b0319d svghmi/hmi_tree.ysl2 --- a/svghmi/hmi_tree.ysl2 Fri Oct 29 11:49:22 2021 +0200 +++ b/svghmi/hmi_tree.ysl2 Thu Nov 04 12:00:50 2021 +0100 @@ -1,5 +1,7 @@ // hmi_tree.ysl2 +// Location identifies uniquely SVGHMI instance +param "instance_name"; // HMI Tree computed from VARIABLES.CSV in svghmi.py const "hmitree", "ns:GetHMITree()"; @@ -19,20 +21,28 @@ | | var heartbeat_index = «$indexed_hmitree/*[@hmipath = '/HEARTBEAT']/@index»; | + | var current_page_var_index = «$indexed_hmitree/*[@hmipath = concat('/CURRENT_PAGE_', $instance_name)]/@index»; + | | var hmitree_types = [ foreach "$indexed_hmitree/*" - | /* «@index» */ "«substring(local-name(), 5)»"`if "position()!=last()" > ,` + | "«substring(local-name(), 5)»"`if "position()!=last()" > ,` | ]; | | var hmitree_paths = [ foreach "$indexed_hmitree/*" - | /* «@index» */ "«@hmipath»"`if "position()!=last()" > ,` + | "«@hmipath»"`if "position()!=last()" > ,` | ]; | + | var hmitree_nodes = { + + foreach "$indexed_hmitree/*[local-name() = 'HMI_NODE']" + | "«@hmipath»" : [«@index», "«@class»"]`if "position()!=last()" > ,` + | }; + | } template "*", mode="index" { diff -r 83ed4ea362db -r 3a0908b0319d svghmi/svghmi.js --- a/svghmi/svghmi.js Fri Oct 29 11:49:22 2021 +0200 +++ b/svghmi/svghmi.js Thu Nov 04 12:00:50 2021 +0100 @@ -30,12 +30,12 @@ }; // Open WebSocket to relative "/ws" address +var has_watchdog = window.location.hash == "#watchdog"; var ws_url = window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws') - + '?mode=' + (window.location.hash == "#watchdog" - ? "watchdog" - : "multiclient"); + + '?mode=' + (has_watchdog ? "watchdog" : "multiclient"); + var ws = new WebSocket(ws_url); ws.binaryType = 'arraybuffer'; @@ -195,15 +195,26 @@ } } -// 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({ - /* type: "Watchdog", */ +if(has_watchdog){ + // 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({ + /* type: "Watchdog", */ + frequency: 1, + indexes: [heartbeat_index], + new_hmi_value: function(index, value, oldval) { + apply_hmi_value(heartbeat_index, value+1); + } + }); +} + +// subscribe to per instance current page hmi variable +subscribers(current_page_var_index).add({ frequency: 1, - indexes: [heartbeat_index], + indexes: [current_page_var_index], new_hmi_value: function(index, value, oldval) { - apply_hmi_value(heartbeat_index, value+1); + switch_page(value); } }); @@ -401,7 +412,9 @@ if(page_name == undefined) page_name = current_subscribed_page; - + else if(page_index == undefined){ + [page_name, page_index] = page_name.split('@') + } let old_desc = page_desc[current_subscribed_page]; let new_desc = page_desc[page_name]; @@ -411,8 +424,19 @@ return false; } - if(page_index == undefined){ + if(page_index == undefined) page_index = new_desc.page_index; + else if(typeof(page_index) == "string") { + let hmitree_node = hmitree_nodes[page_index]; + if(hmitree_node !== undefined){ + let [int_index, hmiclass] = hmitree_node; + if(hmiclass == new_desc.page_class) + page_index = int_index; + else + page_index = new_desc.page_index; + } else { + page_index = new_desc.page_index; + } } if(old_desc){ @@ -443,6 +467,11 @@ if(jump_history.length > 42) jump_history.shift(); + apply_hmi_value(current_page_var_index, + page_index == undefined + ? page_name + : page_name + "@" + hmitree_paths[page_index]); + return true; }; diff -r 83ed4ea362db -r 3a0908b0319d svghmi/svghmi.py --- a/svghmi/svghmi.py Fri Oct 29 11:49:22 2021 +0200 +++ b/svghmi/svghmi.py Thu Nov 04 12:00:50 2021 +0100 @@ -130,6 +130,10 @@ # ignores variables starting with _TMP_ if path[-1].startswith("_TMP_"): continue + vartype = v["vartype"] + # ignores external variables + if vartype == "EXT": + continue derived = v["derived"] kwargs={} if derived == "HMI_NODE": @@ -138,7 +142,7 @@ kwargs['hmiclass'] = path[-1] else: name = path[-1] - new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], v["C_path"], **kwargs) + new_node = HMITreeNode(path, name, derived, v["type"], vartype, v["C_path"], **kwargs) placement_result = hmi_tree_root.place_node(new_node) if placement_result is not None: cause, problematic_node = placement_result @@ -148,10 +152,10 @@ ".".join(new_node.path)) last_FB = None - for v in varlist: - if v["vartype"] == "FB": - last_FB = v - if v["C_path"] == problematic_node: + for _v in varlist: + if _v["vartype"] == "FB": + last_FB = _v + if _v["C_path"] == problematic_node: break if last_FB is not None: failing_parent = last_FB["type"] @@ -572,7 +576,8 @@ # call xslt transform on Inkscape's SVG to generate XHTML try: self.ProgressStart("xslt", "XSLT transform") - result = transform.transform(svgdom) # , profile_run=True) + result = transform.transform( + svgdom, instance_name=location_str) # , profile_run=True) self.ProgressEnd("xslt") except XSLTApplyError as e: self.FatalError("SVGHMI " + svghmi_options["name"] + ": " + e.message) @@ -826,8 +831,11 @@ self.GetCTRoot().logger.write_error( _("Font file does not exist: %s\n") % fontfile) + def CTNGlobalInstances(self): + location_str = "_".join(map(str, self.GetCurrentLocation())) + return [("CURRENT_PAGE_"+location_str, "HMI_STRING", "")] + ## In case one day we support more than one heartbeat - # def CTNGlobalInstances(self): # view_name = self.BaseParams.getName() # return [(view_name + "_HEARTBEAT", "HMI_INT", "")] diff -r 83ed4ea362db -r 3a0908b0319d tests/svghmi/plc.xml --- a/tests/svghmi/plc.xml Fri Oct 29 11:49:22 2021 +0200 +++ b/tests/svghmi/plc.xml Thu Nov 04 12:00:50 2021 +0100 @@ -1,7 +1,7 @@ - + @@ -71,6 +71,25 @@ + + + + + + + + + + + + + + + + + + + @@ -287,6 +306,100 @@ 0 + + + + + + + + + + + + + CURRENT_PAGE_0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PAGESWITCH + + + + + + + 'RelativePageTest@/TRUMP2' + + + + + + + + + + + + + + + + + + + + + + +