aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--python/dpd/ExtractStatistic.py4
-rwxr-xr-xpython/dpdce.py10
-rwxr-xr-xpython/gui.py4
-rwxr-xr-xpython/gui/api.py20
-rw-r--r--python/gui/static/css/odr.css14
-rw-r--r--python/gui/static/js/odr-home.js132
-rw-r--r--python/gui/templates/home.html38
-rw-r--r--python/lib/yamlrpc.py2
8 files changed, 203 insertions, 21 deletions
diff --git a/python/dpd/ExtractStatistic.py b/python/dpd/ExtractStatistic.py
index 25647a6..86580d8 100644
--- a/python/dpd/ExtractStatistic.py
+++ b/python/dpd/ExtractStatistic.py
@@ -76,7 +76,7 @@ class ExtractStatistic:
i_sub += 1
ax = plt.subplot(sub_rows, sub_cols, i_sub)
ax.plot(tx_values, rx_values,
- label="Estimated Values",
+ label="Averaged measurements",
color="red")
for i, tx_value in enumerate(tx_values):
rx_values_list = self.rx_values_lists[i]
@@ -94,7 +94,7 @@ class ExtractStatistic:
i_sub += 1
ax = plt.subplot(sub_rows, sub_cols, i_sub)
ax.plot(tx_values, np.rad2deg(phase_diffs_values),
- label="Estimated Values",
+ label="Averaged measurements",
color="red")
for i, tx_value in enumerate(tx_values):
phase_diff = phase_diffs_values_lists[i]
diff --git a/python/dpdce.py b/python/dpdce.py
index 27c5253..5b308c4 100755
--- a/python/dpdce.py
+++ b/python/dpdce.py
@@ -409,7 +409,7 @@ try:
try:
addr, msg_id, method, params = cmd_socket.receive_request()
except ValueError as e:
- logging.warning('YAML-RPC request error: {}'.format(e))
+ logging.warning('RPC request error: {}'.format(e))
continue
except TimeoutError:
continue
@@ -417,22 +417,22 @@ try:
logging.info('Caught KeyboardInterrupt')
break
except:
- logging.error('YAML-RPC unknown error')
+ logging.error('RPC unknown error')
break
if any(method == m for m in ['trigger_run', 'reset', 'adapt']):
- logging.info('YAML-RPC request : {}'.format(method))
+ logging.info('Received RPC request : {}'.format(method))
command_queue.put(method)
cmd_socket.send_success_response(addr, msg_id, None)
elif method == 'restore_dump':
- logging.info('YAML-RPC restore dump {}'.format(params['dump_id']))
+ logging.info('Received RPC request : restore_dump({})'.format(params['dump_id']))
command_queue.put(f"restore_dump-{params['dump_id']}")
cmd_socket.send_success_response(addr, msg_id, None)
elif method == 'get_results':
with lock:
cmd_socket.send_success_response(addr, msg_id, results)
elif method == 'calibrate':
- logging.info('YAML-RPC request : {}'.format(method))
+ logging.info('Received RPC request : {}'.format(method))
command_queue.put('calibrate')
cmd_socket.send_success_response(addr, msg_id, None)
else:
diff --git a/python/gui.py b/python/gui.py
index 0090a3a..a9328ee 100755
--- a/python/gui.py
+++ b/python/gui.py
@@ -33,6 +33,7 @@ from lib import zmqrc
env = Environment(loader=FileSystemLoader('gui/templates'))
base_js = ["js/odr.js"]
+base_css = ["css/odr.css"]
class Root:
def __init__(self, dpd_port):
@@ -51,7 +52,8 @@ class Root:
@cherrypy.expose
def home(self):
tmpl = env.get_template("home.html")
- return tmpl.render(tab='home', js=base_js, is_login=False)
+ js = base_js + ["js/odr-home.js"]
+ return tmpl.render(tab='home', js=js, css=base_css, is_login=False)
@cherrypy.expose
def rcvalues(self):
diff --git a/python/gui/api.py b/python/gui/api.py
index c0effde..f9e0ad0 100755
--- a/python/gui/api.py
+++ b/python/gui/api.py
@@ -80,8 +80,18 @@ class API:
return send_error(str(e))
return send_ok()
else:
- cherrypy.response.status = 400
- return send_error("POST only")
+ if all(p in kwargs for p in ('controllable', 'param')):
+ try:
+ return send_ok(self.mod_rc.get_param_value(kwargs['controllable'], kwargs['param']))
+ except IOError as e:
+ cherrypy.response.status = 503
+ return send_error(str(e))
+ except ValueError as e:
+ cherrypy.response.status = 503
+ return send_error(str(e))
+ else:
+ cherrypy.response.status = 400
+ return send_error("missing 'controllable' or 'param' GET parameters")
def _wrap_dpd(self, method, data=None):
try:
@@ -89,12 +99,12 @@ class API:
return send_ok(reply)
except ValueError as e:
cherrypy.response.status = 503
- return send_error("YAML-RPC call error: {}".format(e))
+ return send_error("DPDCE remote procedure call error: {}".format(e))
except TimeoutError as e:
cherrypy.response.status = 503
- return send_error("YAML-RPC timeout: {}".format(e))
+ return send_error("DPDCE remote procedure call timed out")
cherrypy.response.status = 500
- return send_error("YAML-RPC unknown error")
+ return send_error("Unknown DPDCE remote procedure error error")
@cherrypy.expose
@cherrypy.tools.json_out()
diff --git a/python/gui/static/css/odr.css b/python/gui/static/css/odr.css
new file mode 100644
index 0000000..1710464
--- /dev/null
+++ b/python/gui/static/css/odr.css
@@ -0,0 +1,14 @@
+.glyphicon-refresh-animate {
+ -animation: spin 1.8s infinite linear;
+ -webkit-animation: spin2 1.8s infinite linear;
+}
+
+@-webkit-keyframes spin2 {
+ from { -webkit-transform: rotate(0deg);}
+ to { -webkit-transform: rotate(360deg);}
+}
+
+@keyframes spin {
+ from { transform: scale(1) rotate(0deg);}
+ to { transform: scale(1) rotate(360deg);}
+}
diff --git a/python/gui/static/js/odr-home.js b/python/gui/static/js/odr-home.js
new file mode 100644
index 0000000..11aed8e
--- /dev/null
+++ b/python/gui/static/js/odr-home.js
@@ -0,0 +1,132 @@
+// Copyright (C) 2019
+// Matthias P. Braendli, matthias.braendli@mpb.li
+//
+// http://www.opendigitalradio.org
+//
+// This file is part of ODR-DabMod.
+//
+// ODR-DabMod is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// ODR-DabMod is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
+//
+
+function apiRequestChain(uri, get_data, success_callback, fail_callback) {
+ $.ajax({
+ type: "GET",
+ url: uri,
+ data: get_data,
+ contentType: 'application/json',
+ dataType: 'json',
+
+ error: function(data) {
+ console.log("GET " + JSON.stringify(get_data) + " error: " + data.responseText);
+ fail_callback(data.responseText);
+ },
+ success: function(data) {
+ console.log("GET " + JSON.stringify(get_data) + " success: " + JSON.stringify(data));
+ if (data.status == 'ok') {
+ success_callback(data.data);
+ }
+ else {
+ fail_callback(data.data);
+ }
+ },
+ });
+}
+
+function mark_pending(id) {
+ document.getElementById(id).className = "glyphicon glyphicon-refresh glyphicon-refresh-animate";
+}
+
+function mark_ok(id, comment) {
+ document.getElementById(id).className = "glyphicon glyphicon-ok";
+
+ if (comment) {
+ document.getElementById(id + "_comment").innerHTML = comment;
+ }
+}
+
+function mark_fail(id, reason) {
+ var el = document.getElementById(id);
+ el.className = "glyphicon glyphicon-remove";
+ el.style.color = "#FF3333";
+
+ document.getElementById(id + "_comment").innerHTML = reason;
+
+ var overall = document.getElementById("overall_state");
+ overall.style.color = "#FF8833";
+ overall.className = "glyphicon glyphicon-alert";
+}
+
+function check_rc() {
+ mark_pending('is_rc_ok');
+ apiRequestChain("/api/parameter",
+ {controllable: 'sdr', param: 'freq'},
+ function(data) {
+ mark_ok('is_rc_ok');
+ check_modulating(0);
+ },
+ function(data) {
+ mark_fail('is_rc_ok', JSON.parse(data)['reason']);
+ });
+}
+
+function check_modulating(last_num_frames) {
+ mark_pending('is_modulating');
+ apiRequestChain("/api/parameter",
+ {controllable: 'sdr', param: 'frames'},
+ function(data) {
+ if (data > 0) {
+ if (last_num_frames == 0) {
+ setTimeout(function() { check_modulating(data); }, 200);
+ }
+ else {
+ if (data == last_num_frames) {
+ mark_fail('is_modulating', "Frame counter not incrementing: " + data);
+ }
+ else {
+ mark_ok('is_modulating', "Number of frames modulated: " + data);
+ check_dpdce_running();
+ }
+ }
+ }
+ else {
+ mark_fail('is_modulating', 'number of frames is 0');
+ }
+ },
+ function(data) {
+ mark_fail('is_modulating', data);
+ });
+}
+
+function check_dpdce_running() {
+ mark_pending('is_dpdce_running');
+ apiRequestChain("/api/dpd_results",
+ {controllable: 'sdr', param: 'frames'},
+ function(data) {
+ mark_ok('is_dpdce_running', "State: " + data['state']);
+ mark_ok('overall_state');
+ },
+ function(data) {
+ mark_fail('is_dpdce_running', JSON.parse(data)['reason']);
+ });
+}
+
+$(function(){
+ setTimeout(check_rc, 20);
+});
+
+
+// ToolTip init
+$(function(){
+ $('[data-toggle="tooltip"]').tooltip();
+});
diff --git a/python/gui/templates/home.html b/python/gui/templates/home.html
index cc8fbf0..bf802d6 100644
--- a/python/gui/templates/home.html
+++ b/python/gui/templates/home.html
@@ -4,13 +4,37 @@
{% include 'head.html' %}
<body>
- {% include 'body-nav.html' %}
-
- <div class="container-fluid">
- <div class="jumbotron">
- <h1>Opendigitalradio</h1><h2>ODR-DabMod Interface</h2>
- </div>
- </div>
+ {% include 'body-nav.html' %}
+
+ <div class="container-fluid">
+ <div class="jumbotron">
+ <h1>Opendigitalradio</h1><h2>ODR-DabMod Status Check
+ <span id="overall_state" class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span>
+ </h2>
+ <div class="well well-sm">
+ <p>ODR-DabMod
+ </p>
+ <ul>
+ <li>Answering to RC:
+ <span id="is_rc_ok" class="glyphicon glyphicon-question-sign"></span>
+ <span id="is_rc_ok_comment"><span>
+ </li>
+ <li>Frame generation:
+ <span id="is_modulating" class="glyphicon glyphicon-question-sign"></span>
+ <span id="is_modulating_comment"><span>
+ </li>
+ </ul>
+
+ <p>Checking predistortion
+ <ul>
+ <li>DPDCE running:
+ <span id="is_dpdce_running" class="glyphicon glyphicon-question-sign"></span>
+ <span id="is_dpdce_running_comment"><span>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
</body>
</html>
diff --git a/python/lib/yamlrpc.py b/python/lib/yamlrpc.py
index d4e744a..67c65ff 100644
--- a/python/lib/yamlrpc.py
+++ b/python/lib/yamlrpc.py
@@ -85,7 +85,7 @@ class Socket:
try:
data, addr = self.socket.recvfrom(UDP_PACKETSIZE)
except socket.timeout as to:
- raise TimeoutError("Timeout: " + str(to))
+ raise TimeoutError()
y = yaml.load(data.decode())