From e572cfe8022b2d2fd0d591bf90324c18c30090dc Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 16 Mar 2018 16:38:26 -0400 Subject: [PATCH] configuration additions --- .../www/www-static/index.html | 190 +++++++- op25/gr-op25_repeater/www/www-static/main.css | 91 ++++ op25/gr-op25_repeater/www/www-static/main.js | 410 +++++++++++++++++- 3 files changed, 671 insertions(+), 20 deletions(-) diff --git a/op25/gr-op25_repeater/www/www-static/index.html b/op25/gr-op25_repeater/www/www-static/index.html index b6c00bd..d1b882f 100644 --- a/op25/gr-op25_repeater/www/www-static/index.html +++ b/op25/gr-op25_repeater/www/www-static/index.html @@ -19,8 +19,10 @@
@@ -104,6 +106,190 @@
+ +
+ diff --git a/op25/gr-op25_repeater/www/www-static/main.css b/op25/gr-op25_repeater/www/www-static/main.css index aee67a5..9aa3e5e 100644 --- a/op25/gr-op25_repeater/www/www-static/main.css +++ b/op25/gr-op25_repeater/www/www-static/main.css @@ -153,6 +153,11 @@ div.adjacent { font-size: 24px; } +.boxtitle { + font-weight: bold; + text-align: left; +} + /* the whole NAC string... NAC, freq tsbks, etc. */ .nac { @@ -251,3 +256,89 @@ div.adjacent { background-color: #699; background: linear-gradient(#588, #699); } + +#div_settings table { + border-color: black; +} + +#div_settings tr { + border-top: none; + border-bottom: solid; +} + +#div_settings th.boxtitle-th { + text-align: left; +} + +.div_settings th { + max-width: 75px; + border-style: none; + padding: 3px; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + color: #000; + background: #eee; + text-align: right; + font-weight: normal; +} + +#div_settings td { + max-width: 75px; + border-style: none; + font-weight: bold; + text-align: right; +} + +#div_settings input[type=text] { + max-width: 75px; + border-top: none; + border-bottom-width: 1; + border-bottom: dotted; + border-right: none; + border-left: none; + text-align: right; +} + +#div_settings input[type=button] { + max-width: 75px; + padding: 10px; + color: blue; + border: 0; +} + +#div_settings select { + max-width: 100px; + padding: 0; + border: 0; +} + +#div_settings option { + max-width: 100px; + padding: 0; + border: 0; +} + +.boxtitle { + text-align: left; +} + +div#cfg_list_area select { + width: 250px; + max-width: 250px; +} + +#div_rx_opts td { + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + border-style: none; +} + +#div_rx_opts input[type=text] { + max-width: 75px; + border-top: none; + border-bottom-width: 1; + border-bottom: dotted; + border-right: none; + border-left: none; + text-align: right; +} diff --git a/op25/gr-op25_repeater/www/www-static/main.js b/op25/gr-op25_repeater/www/www-static/main.js index bf7d2ab..3319b2d 100644 --- a/op25/gr-op25_repeater/www/www-static/main.js +++ b/op25/gr-op25_repeater/www/www-static/main.js @@ -47,32 +47,155 @@ function find_parent(ele, tagname) { function f_command(ele, command) { var myrow = find_parent(ele, "TR"); + var mytbl = find_parent(ele, "TABLE"); + amend_d(myrow, mytbl, command); +} + +function edit_freq(freq, to_ui) { + var MHZ = 1000000.0; + if (to_ui) { + var f = (freq / MHZ) + ""; + if (f.indexOf(".") == -1) + f += ".0"; + return f; + } else { + var f = parseFloat(freq); + if (freq.indexOf(".")) + f *= MHZ; + return Math.round(f); + } +} + +function edit_d(d, to_ui) { + var new_d = {}; + var hexints = {"nac":1}; + var ints = {"if_rate":1, "ppm":1, "rate":1, "offset":1, "nac":1, "logfile-workers":1, "decim-amt":1, "seek":1, "hamlib-model":1 }; + var bools = {"active":1, "trunked":1, "rate":1, "offset":1, "phase2_tdma": 1, "phase2-tdma":1, "wireshark":1, "udp-player":1, "audio-if":1, "tone-detect":1, "vocoder":1, "audio":1, "pause":1 }; + var floats = {"costas-alpha":1, "gain-mu":1, "calibration":1, "fine-tune":1, "gain":1, "excess-bw":1, "offset":1} + var lists = {"blacklist":1, "whitelist":1, "cclist":1}; + var freqs = {"frequency":1, "cclist":1}; + + + for (var k in d) { + if (!to_ui) { + if (d[k] == "None") + new_d[k] = null; + else + new_d[k] = d[k]; + if (k == "plot" && !d[k].length) + new_d[k] = null; + if (k in ints) { + new_d[k] = parseInt(new_d[k]); + } else if (k in floats) { + new_d[k] = parseFloat(new_d[k]); + } else if (k in lists) { + var l = new_d[k].split(","); + if (k in freqs) { + var new_l = []; + for (var i in l) + new_l.push(edit_freq(l[i], to_ui)); + new_d[k] = new_l; + } else { + new_d[k] = l; + } + } else if (k in freqs) { + new_d[k] = edit_freq(new_d[k], to_ui); + } + } else { + if (k in hexints) { + new_d[k] = "0x" + d[k].toString(16); + } else if (k in ints) { + if (d[k] == null) + new_d[k] = ""; + else + new_d[k] = d[k].toString(10); + } else if (k in lists) { + if (k in freqs) { + var new_l = []; + for (var i in d[k]) { + new_l.push(edit_freq(d[k][i], to_ui)); + } + new_d[k] = new_l.join(","); + } else { + new_d[k] = d[k].join(","); + } + } else if (k in freqs) { + new_d[k] = edit_freq(d[k], to_ui); + } else { + new_d[k] = d[k]; + } + } + } + return new_d; +} + +function edit_l(cfg, to_ui) { + var new_d = {"devices": [], "channels": []}; + for (var device in cfg['devices']) + new_d["devices"].push(edit_d(cfg['devices'][device], to_ui)); + for (var channel in cfg['channels']) + new_d["channels"].push(edit_d(cfg['channels'][channel], to_ui)); + new_d["backend-rx"] = edit_d(cfg['backend-rx'], to_ui); + return new_d; +} + +function amend_d(myrow, mytbl, command) { + var trunk_row = null; + if (mytbl.id == "chtable") + trunk_row = find_next(myrow, "TR"); if (command == "delete") { var ok = confirm ("Confirm delete"); - if (ok) + if (ok) { myrow.parentNode.removeChild(myrow); + if (mytbl.id == "chtable") + trunk_row.parentNode.removeChild(trunk_row); + } } else if (command == "clone") { var newrow = myrow.cloneNode(true); - if (myrow.nextSibling) - myrow.parentNode.insertBefore(newrow, myrow.nextSibling); - else - myrow.parentNode.appendChild(newrow); + newrow.id = find_free_id("id_"); + if (mytbl.id == "chtable") { + var newrow2 = trunk_row.cloneNode(true); + newrow2.id = "tr_" + newrow.id.substring(3); + if (trunk_row.nextSibling) { + myrow.parentNode.insertBefore(newrow2, trunk_row.nextSibling); + myrow.parentNode.insertBefore(newrow, trunk_row.nextSibling); + } else { + myrow.parentNode.appendChild(newrow); + myrow.parentNode.appendChild(newrow2); + } + } else { + if (myrow.nextSibling) + myrow.parentNode.insertBefore(newrow, myrow.nextSibling); + else + myrow.parentNode.appendChild(newrow); + } } else if (command == "new") { - var mytbl = find_parent(ele, "TABLE"); var newrow = null; - if (mytbl.id == "chtable") + var parent = null; + if (mytbl.id == "chtable") { newrow = document.getElementById("chrow").cloneNode(true); - else if (mytbl.id == "devtable") + parent = document.getElementById("chrow").parentNode; + } else if (mytbl.id == "devtable") { newrow = document.getElementById("devrow").cloneNode(true); - else - return; - mytbl.appendChild(newrow); + parent = document.getElementById("devrow").parentNode; + } else { + return null; + } + newrow.style['display'] = ''; + newrow.id = find_free_id("id_"); + parent.appendChild(newrow); + if (mytbl.id == "chtable") { + var newrow2 = document.getElementById("trrow").cloneNode(true); + newrow2.id = "tr_" + newrow.id.substring(3); + parent.appendChild(newrow2); + } + return newrow.id; } } function nav_update(command) { - var names = ["b1", "b2", "b3"]; - var bmap = { "status": "b1", "plot": "b2", "about": "b3" }; + var names = ["b1", "b2", "b3", "b4", "b5"]; + var bmap = { "status": "b1", "plot": "b2", "settings": "b3", "rx": "b4", "about": "b5" }; var id = bmap[command]; for (var id1 in names) { b = document.getElementById(names[id1]); @@ -85,7 +208,7 @@ function nav_update(command) { } function f_select(command) { - var div_list = ["status", "plot", "about"]; + var div_list = ["status", "plot", "settings", "rx", "about"]; for (var i=0; i"; html += ""; html += ""; - html += ""; + html += ""; var ct = 0; for (var freq in d) { var color = "#d0d0d0"; if ((ct & 1) == 0) color = "#c0c0c0"; ct += 1; - html += ""; + html += ""; } html += "
Adjacent Sites
FrequencyRFSSSiteUplink
FrequencySys IDRFSSSiteUplink
" + freq / 1000000.0 + "" + d[freq]["rfid"] + "" + d[freq]["stid"] + "" + (d[freq]["uplink"] / 1000000.0) + "
" + freq / 1000000.0 + "" + d[freq]['sysid'].toString(16) + "" + d[freq]["rfid"] + "" + d[freq]["stid"] + "" + (d[freq]["uplink"] / 1000000.0) + "


"; @@ -174,6 +299,8 @@ function trunk_update(d) { var do_hex = {"syid":0, "sysid":0, "wacn": 0}; var do_float = {"rxchan":0, "txchan":0}; var html = ""; + var msg = JSON.stringify(d); + document.getElementById("answer_area").innerHTML = msg;msg; for (var nac in d) { if (!is_digit(nac.charAt(0))) continue; @@ -228,6 +355,58 @@ function trunk_update(d) { div_s1.innerHTML = html; } +function config_list(d) { + var html = ""; + html += ""; + document.getElementById("cfg_list_area").innerHTML = html; +} + +function config_data(d) { + var cfg = edit_l(d['data'], true); + open_editor(); + var chtable = document.getElementById("chtable"); + var devtable = document.getElementById("devtable"); + var chrow = document.getElementById("chrow"); + var devrow = document.getElementById("devrow"); + for (var device in cfg['devices']) + rollup_row("dev", document.getElementById(amend_d(devrow, devtable, "new")), cfg['devices'][device]); + for (var channel in cfg['channels']) + rollup_row("ch", document.getElementById(amend_d(chrow, chtable, "new")), cfg['channels'][channel]); + rollup_rx_rows(cfg['backend-rx']); +} + +function open_editor() { + document.getElementById("edit_settings").style["display"] = ""; + var rows = document.querySelectorAll(".dynrow"); + var ct = 0; + for (var r in rows) { + var row = rows[r]; + ct += 1; + if (row.id && (row.id.substring(0,3) == "id_" || row.id.substring(0,3) == "tr_")) { + row.parentNode.removeChild(row); + } + } + var oldtbl = document.getElementById("rt_1"); + if (oldtbl) + oldtbl.parentNode.removeChild(oldtbl); + var tbl = document.getElementById("rxopt-table"); + var newtbl = tbl.cloneNode(true); + newtbl.id = "rt_1"; + newtbl.style["display"] = ""; + var rxrow = newtbl.querySelector(".rxrow"); + var advrow = newtbl.querySelector(".advrow"); + rxrow.id = "rx_1"; + advrow.id = "rx_2"; + if (tbl.nextSibling) + tbl.parentNode.insertBefore(newtbl, tbl.nextSibling); + else + tbl.parentNode.appendChild(newtbl); +} function http_req_cb() { req_cb_count += 1; @@ -242,7 +421,7 @@ function http_req_cb() { } r200_count += 1; var dl = JSON.parse(http_req.responseText); - var dispatch = {'trunk_update': trunk_update, 'change_freq': change_freq, 'rx_update': rx_update} + var dispatch = {'trunk_update': trunk_update, 'change_freq': change_freq, 'rx_update': rx_update, 'config_data': config_data, 'config_list': config_list} for (var i=0; i= SEND_QLIMIT) { send_qfull += 1; send_queue.unshift(); } - send_queue.push( {"command": command, "data": data} ); + send_queue.push( d ); send_process(); } @@ -312,3 +496,193 @@ function f_debug() { var div_debug = document.getElementById("div_debug"); div_debug.innerHTML = html; } + +function find_next(e, tag) { + var n = e.nextSibling; + for (var i=0; i<25; i++) { + if (n == null) + return null; + if (n.nodeName == tag) + return n; + n = n.nextSibling; + } + return null; +} + +function find_free_id(pfx) { + for (var seq = 1; seq < 5000; seq++) { + var test_id = pfx + seq; + var ele = document.getElementById(test_id); + if (!ele) + return test_id; + } + return null; +} + +function f_trunked(e) { + var row = find_parent(e, "TR"); + var trrow = document.getElementById("tr_" + row.id.substring(3)); + trrow['style']["display"] = (e.checked) ? "" : "none"; +} + +function read_write_sel(sel_node, def) { + var result = []; + var elist = sel_node.querySelectorAll("option"); + for (var e in elist) { + var ele = elist[e]; + if (def) { + var options = def[sel_node.name].split(","); + var opts = {}; + for (var o in options) + opts[options[o]] = 1; + if (ele.value in opts) + ele.selected = true; + else + ele.selected = false; + } else { + if (ele.selected) + result.push(ele.value); + } + } + if (!def) + return result.join(); +} + +function read_write(elist, def) { + var result = {}; + var s = "len: " + elist.length + "; "; + for (var e in elist) { + s += elist[e].tagName + "; "; + } + for (var e in elist) { + var ele = elist[e]; + if (ele.nodeName == 'INPUT') { + if (ele.type == 'text') + if (def) { + ele.value = def[ele.name]; + s += ele.name + "=" + ele.value + "; "; + } else + result[ele.name] = ele.value; + else if (ele.type == 'checkbox') + if (def) { + ele.checked = def[ele.name]; + s += "checkbox " + ele.name + "; "; + } + else + result[ele.name] = ele.checked; + } else if (ele.nodeName == 'SELECT') { + if (def) { + read_write_sel(ele, def); + s += "select " + ele.name + "; "; + } + else + result[ele.name] = read_write_sel(ele, def); + } + + } + if (!def) + return result; +} + +function rollup_row(which, row, def) { + var elements = Array.from(row.querySelectorAll("input,select")); + if (which == "ch") { + var trrow = document.getElementById("tr_" + row.id.substring(3)); + elements = elements.concat(Array.from(trrow.querySelectorAll("input,select"))); + } + else if (which == "rx") { + var advrow = document.getElementById("rx_2"); + elements = elements.concat(Array.from(advrow.querySelectorAll("input,select"))); + } + if (def && which == "ch") + trrow.style["display"] = (def["trunked"]) ? "" : "none"; + var result = read_write(elements, def); + if (!def) + return result; +} + +function rollup(which, def) { + var result = []; + var mytbl = document.getElementById(which + "table"); + var elements = mytbl.querySelectorAll(".dynrow"); + for (var e in elements) { + var row = elements[e]; + if (row.id != null && row.id.substring(0,3) == "id_") + result.push(rollup_row(which, row)); + } + if (!def) + return result; +} + +function rollup_rx_rows(def) { + return rollup_row("rx", document.getElementById("rx_1"), def); +} + +function f_save() { + var name = document.getElementById("config_name"); + if (!name.value) { + alert("Name is required"); + name.focus(); + return; + } + if (name.value == "New Configuration") { + alert ("'" + name.value + "' is a reserved name, please retry"); + name.value = ""; + name.focus(); + return; + } + var cfg = { "devices": rollup("dev", null), "channels": rollup("ch", null), "backend-rx": rollup_rx_rows(null) }; + cfg = edit_l(cfg, false); + var request = {"name": name.value, "value": cfg}; + send_command("config-save", request); + f_list(); +} + +function f_list() { + var inp = document.getElementById("include_tsv"); + send_command("config-list", (inp.checked) ? "tsv" : ""); +} + +function f_start() { + var sel = document.getElementById("config_select"); + if (!sel) return; + var val = read_write_sel(sel, null); + if ((!val) || val == "New Configuration") { + alert ("You must select a valid configuration to start"); + return; + } + if (val.indexOf("[TSV]") >= 0) { + alert ("TSV files not supported. First, invoke \"Edit\"; inspect the resulting configuration; then click \"Save\"."); + return; + } + send_command("rx-start", val); +} + +function f_load() { + var sel = document.getElementById("config_select"); + if (!sel) return; + var val = read_write_sel(sel, null); + if (!val) { + alert ("You must select a configuration to edit"); + return; + } + if (val == "New Configuration") { + open_editor(); + } else { + send_command('config-load', val); + var ele = document.getElementById("config_name"); + ele.value = val; + } +} + +function show_advanced(o) { + var tbl = find_parent(o, "TABLE"); + var row = tbl.querySelector(".advrow"); + if (o.value == "Show") { + o.value = "Hide"; + row.style["display"] = ""; + } else { + o.value = "Show"; + row.style["display"] = "none"; + } +}