diff options
author | Tobias Jahnke <tobias.jahnke@microchip.com> | 2019-08-16 17:28:24 +0200 |
---|---|---|
committer | Tobias Jahnke <tobias.jahnke@microchip.com> | 2019-08-16 17:28:24 +0200 |
commit | 6854f72cb81b10e1add164e754aba1952df5b269 (patch) | |
tree | 4e7c7ecfed64acf38ab9d9201274ed3ad0fb34d7 | |
parent | cc1756d5e7e32e108f8baf4787ba9a811370aefd (diff) |
Add htdocs to test service widget
Bug-AGL: SPEC-2738
Introduce html web-ui to demo and test
the provided api.
Signed-off-by: Tobias Jahnke <tobias.jahnke@microchip.com>
Change-Id: Ia5866e954c4b0fffb0adf0ab551beaf48ec7bf0f
-rw-r--r-- | htdocs/AFB.js | 216 | ||||
-rw-r--r-- | htdocs/CMakeLists.txt | 40 | ||||
-rw-r--r-- | htdocs/index.html | 27 | ||||
-rw-r--r-- | htdocs/ucs-controller.css | 61 | ||||
-rw-r--r-- | htdocs/ucs-controller.html | 122 | ||||
-rw-r--r-- | htdocs/ucs-controller.js | 109 |
6 files changed, 575 insertions, 0 deletions
diff --git a/htdocs/AFB.js b/htdocs/AFB.js new file mode 100644 index 0000000..4c500b9 --- /dev/null +++ b/htdocs/AFB.js @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2017-2019 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +AFB = function(base, initialtoken){ + +if (typeof base != "object") + base = { base: base, token: initialtoken }; + +var initial = { + base: base.base || "api", + token: initialtoken || base.token || URLSearchParams(window.location.search).get('token') || "HELLO", + host: base.host || window.location.host, + url: base.url || undefined +}; + +var urlws = initial.url || "ws://"+initial.host+"/"+initial.base; + +/*********************************************/ +/**** ****/ +/**** AFB_context ****/ +/**** ****/ +/*********************************************/ +var AFB_context; +{ + var UUID = undefined; + var TOKEN = initial.token; + + var context = function(token, uuid) { + this.token = token; + this.uuid = uuid; + } + + context.prototype = { + get token() {return TOKEN;}, + set token(tok) {if(tok) TOKEN=tok;}, + get uuid() {return UUID;}, + set uuid(id) {if(id) UUID=id;} + }; + + AFB_context = new context(); +} +/*********************************************/ +/**** ****/ +/**** AFB_websocket ****/ +/**** ****/ +/*********************************************/ +var AFB_websocket; +{ + var CALL = 2; + var RETOK = 3; + var RETERR = 4; + var EVENT = 5; + + var PROTO1 = "x-afb-ws-json1"; + + AFB_websocket = function(on_open, on_abort) { + var u = urlws, p = '?'; + if (AFB_context.token) { + u = u + '?x-afb-token=' + AFB_context.token; + p = '&'; + } + if (AFB_context.uuid) + u = u + p + 'x-afb-uuid=' + AFB_context.uuid; + this.ws = new WebSocket(u, [ PROTO1 ]); + this.url = u; + this.pendings = {}; + this.awaitens = {}; + this.counter = 0; + this.ws.onopen = onopen.bind(this); + this.ws.onerror = onerror.bind(this); + this.ws.onclose = onclose.bind(this); + this.ws.onmessage = onmessage.bind(this); + this.onopen = on_open; + this.onabort = on_abort; + } + + function onerror(event) { + var f = this.onabort; + if (f) { + delete this.onopen; + delete this.onabort; + f(this); + } + this.onerror && this.onerror(this); + } + + function onopen(event) { + var f = this.onopen; + delete this.onopen; + delete this.onabort; + f && f(this); + } + + function onclose(event) { + var err = { + jtype: 'afb-reply', + request: { + status: 'disconnected', + info: 'server hung up' + } + }; + for (var id in this.pendings) { + try { this.pendings[id][1](err); } catch (x) {/*NOTHING*/} + } + this.pendings = {}; + this.onclose && this.onclose(); + } + + function fire(awaitens, name, data) { + var a = awaitens[name]; + if (a) + a.forEach(function(handler){handler(data);}); + var i = name.indexOf("/"); + if (i >= 0) { + a = awaitens[name.substring(0,i)]; + if (a) + a.forEach(function(handler){handler(data);}); + } + a = awaitens["*"]; + if (a) + a.forEach(function(handler){handler(data);}); + } + + function reply(pendings, id, ans, offset) { + if (id in pendings) { + var p = pendings[id]; + delete pendings[id]; + try { p[offset](ans); } catch (x) {/*TODO?*/} + } + } + + function onmessage(event) { + var obj = JSON.parse(event.data); + var code = obj[0]; + var id = obj[1]; + var ans = obj[2]; + AFB_context.token = obj[3]; + switch (code) { + case RETOK: + reply(this.pendings, id, ans, 0); + break; + case RETERR: + reply(this.pendings, id, ans, 1); + break; + case EVENT: + default: + fire(this.awaitens, id, ans); + break; + } + } + + function close() { + this.ws.close(); + this.ws.onopen = + this.ws.onerror = + this.ws.onclose = + this.ws.onmessage = + this.onopen = + this.onabort = function(){}; + } + + function call(method, request, callid) { + return new Promise((function(resolve, reject){ + var id, arr; + if (callid) { + id = String(callid); + if (id in this.pendings) + throw new Error("pending callid("+id+") exists"); + } else { + do { + id = String(this.counter = 4095 & (this.counter + 1)); + } while (id in this.pendings); + } + this.pendings[id] = [ resolve, reject ]; + arr = [CALL, id, method, request ]; + if (AFB_context.token) arr.push(AFB_context.token); + this.ws.send(JSON.stringify(arr)); + }).bind(this)); + } + + function onevent(name, handler) { + var id = name; + var list = this.awaitens[id] || (this.awaitens[id] = []); + list.push(handler); + } + + AFB_websocket.prototype = { + close: close, + call: call, + onevent: onevent + }; +} +/*********************************************/ +/**** ****/ +/**** ****/ +/**** ****/ +/*********************************************/ +return { + context: AFB_context, + ws: AFB_websocket +}; +}; + diff --git a/htdocs/CMakeLists.txt b/htdocs/CMakeLists.txt new file mode 100644 index 0000000..fa99594 --- /dev/null +++ b/htdocs/CMakeLists.txt @@ -0,0 +1,40 @@ +################################################################################ +# Copyright 2019 Microchip Technology Inc. and its subsidiaries +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################ + + +################################################## +# HTML Testing Files +################################################## +PROJECT_TARGET_ADD(www_test) + + file(GLOB SOURCE_FILES "*.html" "*.js" "*.jpg" "*.css") + + add_custom_target(${TARGET_NAME} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} + ) + + add_custom_command( + DEPENDS ${SOURCE_FILES} + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} + COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} + COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} + COMMAND cp -r ${SOURCE_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} + ) + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "HTDOCS" + OUTPUT_NAME ${TARGET_NAME} + ) diff --git a/htdocs/index.html b/htdocs/index.html new file mode 100644 index 0000000..c1a9137 --- /dev/null +++ b/htdocs/index.html @@ -0,0 +1,27 @@ +<!-- +Copyright 2019 Microchip Technology Inc. and its subsidiaries + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<html> + <head> + <title>UNICENS Tests</title> + </head> + <body> + <h1>UNICENS Bindings Test</h1> + <ol> + <li><a href="ucs-controller.html">UNICENS Controller</a></li> + </ol> + </body> +</html>
\ No newline at end of file diff --git a/htdocs/ucs-controller.css b/htdocs/ucs-controller.css new file mode 100644 index 0000000..8c90596 --- /dev/null +++ b/htdocs/ucs-controller.css @@ -0,0 +1,61 @@ +/* + * Copyright 2019 Microchip Technology Inc. and its subsidiaries + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; } +.string { color: green; } +.number { color: darkorange; } +.boolean { color: blue; } +.null { color: magenta; } +.key { color: red; } + +.slidecontainer { + width: 100%; /* Width of the outside container */ +} + +/* The slider itself */ +.slider { + -webkit-appearance: none; /* Override default CSS styles */ + appearance: none; + width: 100%; /* Full-width */ + height: 25px; /* Specified height */ + background: #d3d3d3; /* Grey background */ + outline: none; /* Remove outline */ + opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */ + -webkit-transition: .2s; /* 0.2 seconds transition on hover */ + transition: opacity .2s; +} + +/* Mouse-over effects */ + .slider:hover { + opacity: 1; /* Fully shown on mouse-over */ +} + +/* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */ +.slider::-webkit-slider-thumb { + -webkit-appearance: none; /* Override default look */ + appearance: none; + width: 25px; /* Set a specific slider handle width */ + height: 25px; /* Slider handle height */ + background: #4CAF50; /* Green background */ + cursor: pointer; /* Cursor on hover */ +} + +.slider::-moz-range-thumb { + width: 25px; /* Set a specific slider handle width */ + height: 25px; /* Slider handle height */ + background: #4CAF50; /* Green background */ + cursor: pointer; /* Cursor on hover */ +} diff --git a/htdocs/ucs-controller.html b/htdocs/ucs-controller.html new file mode 100644 index 0000000..f1b9ed8 --- /dev/null +++ b/htdocs/ucs-controller.html @@ -0,0 +1,122 @@ +<!-- +Copyright 2019 Microchip Technology Inc. and its subsidiaries + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<html> +<head> + <title>Unicens Controller Test</title> + + <link rel="stylesheet" href="ucs-controller.css"> + <script type="text/javascript" src="AFB.js"></script> + <script type="text/javascript" src="ucs-controller.js"></script> + <style> + .divTable{ + display: table; + } + .divTableRow { + display: table-row; + } + .divTableHeading { + background-color: #EEE; + display: table-header-group; + } + .divTableCell, .divTableHead { + border: 1px solid #999999; + display: table-cell; + padding: 3px 10px; + } + .divTableHeading { + background-color: #EEE; + display: table-header-group; + font-weight: bold; + } + .divTableFoot { + background-color: #EEE; + display: table-footer-group; + font-weight: bold; + } + .divTableBody { + display: table-row-group; + } + + .ucsCtrlButton { + border: none; + padding: 5px 15px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + width: 144px; + border: 2px solid #4CAF50; + } + </style> +</head> +<body onload="init('unused','unicens-controller', 'ping');"> + + <h1>Unicens Controller</h1> + + <button id="connected" onclick="init('ucs2_config','unicens', 'listconfig')">Binder WS Fail</button> + <br> + <h1>Slim-Amplifier</h1> + <h3>Master Volume</h3> + <div class="slidecontainer"> + <input type="range" min="0" max="100" value="50" class="slider" id="slimamp-master"> + </div> + + <h1>Fiberdyne-Amplifier</h1> + <h3>Master Volume</h3> + <div class="slidecontainer"> + <input type="range" min="0" max="100" value="50" class="slider" id="amplifier-master"> + </div> + + <h1>Microphone</h1> + <h3>Mode</h3> + <div> + <ol> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'none'})">None</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'doa'})">DOA</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'thinking'})">Thinking</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'speaking'})">Speaking</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'error'})">Error</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'waking'})">Waking</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'ending'})">Ending</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'cylon'})">Cylon</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'rainbow'})">Rainbow</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'wheel'})">Wheel</button></li> + <li><button onclick="callbinder('unicens-controller','microphone_mode_set', {'value': 'unknown'})">Unknown</button></li> + </ol> + </div> + + <h1>Events</h1> + <br> + <div id="main" style="visibility:hidden"> + <ol> + <li>Question <pre id="question"></pre> + <li>Response <pre id="output"></pre> + <li>Events: <pre id="outevt"></pre> + </ol> + </div> + + <div style="visibility:hidden"> + <ol> + <li><button onclick="callbinder('unicens-controller','slimamp_master_volume_set', {'value': 100})">Set Master-Volume: 100</button></li> + <li><button onclick="callbinder('unicens-controller','slimamp_master_volume_set', {'value': 75})">Set Master-Volume: 75</button></li> + <li><button onclick="callbinder('unicens-controller','slimamp_master_volume_set', {'value': 50})">Set Master-Volume: 50</button></li> + <li><button onclick="callbinder('unicens-controller','slimamp_master_volume_set', {'value': 25})">Set Master-Volume: 25</button></li> + <li><button onclick="callbinder('unicens-controller','slimamp_master_volume_set', {'value': 0})">Set Master-Volume: 0</button></li> + </ol> + </div> + +</body> diff --git a/htdocs/ucs-controller.js b/htdocs/ucs-controller.js new file mode 100644 index 0000000..195d41b --- /dev/null +++ b/htdocs/ucs-controller.js @@ -0,0 +1,109 @@ +/* + * Copyright 2019 Microchip Technology Inc. and its subsidiaries + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var afb = new AFB("api", "mysecret"); + var ws; + var evtidx=0; + var numid=0; + + function syntaxHighlight(json) { + if (typeof json !== 'string') { + json = JSON.stringify(json, undefined, 2); + } + json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { + var cls = 'number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'key'; + } else { + cls = 'string'; + } + } else if (/true|false/.test(match)) { + cls = 'boolean'; + } else if (/null/.test(match)) { + cls = 'null'; + } + return '<span class="' + cls + '">' + match + '</span>'; + }); + } + + function replyok(obj) { + console.log("replyok:" + JSON.stringify(obj)); + document.getElementById("output").innerHTML = "OK: "+ syntaxHighlight(obj); + } + + function replyerr(obj) { + console.log("replyerr:" + JSON.stringify(obj)); + document.getElementById("output").innerHTML = "ERROR: "+ syntaxHighlight(obj); + } + + function gotevent(obj) { + console.log("gotevent:" + JSON.stringify(obj)); + document.getElementById("outevt").innerHTML = (evtidx++) +": "+JSON.stringify(obj); + } + + function send(message) { + var api = document.getElementById("api").value; + var verb = document.getElementById("verb").value; + document.getElementById("question").innerHTML = "subscribe: "+api+"/"+verb + " (" + JSON.stringify(message) +")"; + ws.call(api+"/"+verb, {data:message}).then(replyok, replyerr); + } + + // On button click from HTML page + function callbinder(api, verb, query) { + console.log ("subscribe api="+api+" verb="+verb+" query=" +query); + var question = afb.urlws +"/" +api +"/" +verb + "?query=" + JSON.stringify(query); + document.getElementById("question").innerHTML = syntaxHighlight(question); + ws.call(api+"/"+verb, query).then(replyok, replyerr); + } + + function init(elemid, api, verb, query) { + + var slimMaster = document.getElementById("slimamp-master"); + var ampMaster = document.getElementById("amplifier-master"); + + // Update the current slider value (each time you drag the slider handle) + slimMaster.oninput = function() { + console.log ("slimamp-master: new value=%s", this.value); + var params = {value: parseInt(this.value, 10)}; + callbinder("unicens-controller","slimamp_master_volume_set", params); + } + + // Update the current slider value (each time you drag the slider handle) + ampMaster.oninput = function() { + console.log ("amplifier-master: new value=%s", this.value); + var params = {value: parseInt(this.value, 10)}; + callbinder("unicens-controller","amplifier_master_volume_set", params); + } + + function onopen() { + console.log("onopen triggered"); + document.getElementById("main").style.visibility = "visible"; + document.getElementById("connected").innerHTML = "Binder WS Active"; + document.getElementById("connected").style.background = "lightgreen"; + ws.onevent("*", gotevent); + } + + function onabort() { + console.log("onabort triggered"); + document.getElementById("main").style.visibility = "hidden"; + document.getElementById("connected").innerHTML = "Connected Closed"; + document.getElementById("connected").style.background = "red"; + } + + ws = new afb.ws(onopen, onabort); + } |