summaryrefslogtreecommitdiffstats
path: root/python/gui
diff options
context:
space:
mode:
Diffstat (limited to 'python/gui')
-rwxr-xr-xpython/gui/api.py47
-rw-r--r--python/gui/static/css/odr.css14
-rw-r--r--python/gui/static/js/odr-home.js240
-rw-r--r--python/gui/static/js/odr-predistortion.js129
-rw-r--r--python/gui/static/js/odr-rcvalues.js29
-rw-r--r--python/gui/templates/about.html42
-rw-r--r--python/gui/templates/home.html72
-rw-r--r--python/gui/templates/modulator.html40
-rw-r--r--python/gui/templates/predistortion.html129
-rw-r--r--python/gui/templates/rcvalues.html39
10 files changed, 586 insertions, 195 deletions
diff --git a/python/gui/api.py b/python/gui/api.py
index bff224e..f9e0ad0 100755
--- a/python/gui/api.py
+++ b/python/gui/api.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2018
+# Copyright (C) 2019
# Matthias P. Braendli, matthias.braendli@mpb.li
#
# http://www.opendigitalradio.org
@@ -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()
@@ -107,6 +117,15 @@ class API:
@cherrypy.expose
@cherrypy.tools.json_out()
+ def dpd_adapt(self, **kwargs):
+ if cherrypy.request.method == 'POST':
+ return self._wrap_dpd("adapt")
+ else:
+ cherrypy.response.status = 400
+ return send_error("POST only")
+
+ @cherrypy.expose
+ @cherrypy.tools.json_out()
def dpd_reset(self, **kwargs):
if cherrypy.request.method == 'POST':
return self._wrap_dpd("reset")
@@ -116,12 +135,20 @@ class API:
@cherrypy.expose
@cherrypy.tools.json_out()
- def dpd_settings(self, setting: str, value: str, **kwargs):
+ def dpd_restore_dump(self, **kwargs):
if cherrypy.request.method == 'POST':
- data = {'setting': setting, 'value': value}
- return self._wrap_dpd("set_setting", data)
+ cl = cherrypy.request.headers['Content-Length']
+ rawbody = cherrypy.request.body.read(int(cl))
+ params = json.loads(rawbody.decode())
+ if 'dump_id' in params:
+ data = {'dump_id': params['dump_id']}
+ return self._wrap_dpd("restore_dump", data)
+ else:
+ cherrypy.response.status = 400
+ return send_error("Missing dump_id")
else:
- return self._wrap_dpd("get_settings")
+ cherrypy.response.status = 400
+ return send_error("POST only")
@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..b74c4c8
--- /dev/null
+++ b/python/gui/static/js/odr-home.js
@@ -0,0 +1,240 @@
+// 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) {
+ if (data.status == 'ok') {
+ success_callback(data.data);
+ }
+ else {
+ fail_callback(data.data);
+ }
+ },
+ });
+}
+
+function mark_pending(id, comment) {
+ document.getElementById(id).className = "glyphicon glyphicon-refresh glyphicon-refresh-animate";
+
+ if (comment) {
+ document.getElementById(id + "_comment").innerHTML = comment;
+ }
+}
+
+var failure_encountered = false;
+
+function mark_overall_ok() {
+ if (!failure_encountered) {
+ document.getElementById("overall_state").className = "glyphicon glyphicon-ok";
+ }
+}
+
+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) {
+ failure_encountered = true;
+
+ 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_gpsdo_ok();
+ }
+ }
+ else {
+ mark_fail('is_modulating', 'number of frames is 0');
+ }
+ },
+ function(data) {
+ mark_fail('is_modulating', data);
+ });
+}
+
+function check_gpsdo_ok() {
+ mark_pending('is_gpsdo_ok');
+ apiRequestChain("/api/parameter",
+ {controllable: 'sdr', param: 'gpsdo_num_sv'},
+ function(data) {
+ if (data > 3) {
+ mark_ok('is_gpsdo_ok', "Number of SVs used: " + data);
+ }
+ else {
+ mark_fail('is_gpsdo_ok', "Number of SVs (" + data + ") is too low");
+ }
+ check_underrunning(0, 0);
+ check_late(0, 0);
+ },
+ function(data) {
+ mark_fail('is_gpsdo_ok', json.parse(data)['reason']);
+ });
+}
+
+
+function check_underrunning(iteration, first_underruns) {
+ var n_checks = 3;
+
+ apiRequestChain("/api/parameter",
+ {controllable: 'sdr', param: 'underruns'},
+ function(data) {
+ if (iteration == 0) {
+ mark_pending('is_underrunning', "Checking for underruns");
+ setTimeout(function() { check_underrunning(iteration+1, data); }, 2000);
+ }
+ else if (iteration < n_checks) {
+ mark_pending('is_underrunning', "Check " + iteration + "/" + n_checks + "...");
+ setTimeout(function() { check_underrunning(iteration+1, first_underruns); }, 2000);
+ }
+ else {
+ if (data == first_underruns) {
+ mark_ok('is_underrunning', "Number of underruns is not increasing: " + data);
+ }
+ else {
+ mark_fail('is_underrunning', "Underruns observed in last " + n_checks + " seconds: " + data);
+ }
+ check_rate_4x();
+ }
+ },
+ function(data) {
+ mark_fail('is_underrunning', data);
+ });
+}
+
+function check_late(iteration, first_late) {
+ var n_checks = 3;
+
+ apiRequestChain("/api/parameter",
+ {controllable: 'sdr', param: 'latepackets'},
+ function(data) {
+ if (iteration == 0) {
+ mark_pending('is_late', "Checking for late packets");
+ setTimeout(function() { check_late(iteration+1, data); }, 2000);
+ }
+ else if (iteration < n_checks) {
+ mark_pending('is_late', "Check " + iteration + "/" + n_checks + "...");
+ setTimeout(function() { check_late(iteration+1, first_late); }, 2000);
+ }
+ else {
+ if (data == first_late) {
+ mark_ok('is_late', "Number of late packets is not increasing: " + data);
+ }
+ else {
+ mark_fail('is_late', "Late packets observed in last " + n_checks + " seconds: " + data);
+ }
+ }
+ },
+ function(data) {
+ mark_fail('is_late', data);
+ });
+}
+
+function check_rate_4x() {
+ mark_pending('is_rate_4x');
+ apiRequestChain("/api/parameter",
+ {controllable: 'modulator', param: 'rate'},
+ function(data) {
+ if (data == 8192000) {
+ mark_ok('is_rate_4x', "Samplerate: " + data);
+ }
+ else {
+ mark_fail('is_rate_4x', "Samplerate is not 8192ksps: " + data);
+ }
+ check_dpdce_running();
+ },
+ function(data) {
+ mark_fail('is_rate_4x', JSON.parse(data)['reason']);
+ });
+}
+
+function check_dpdce_running() {
+ mark_pending('is_dpdce_running');
+ apiRequestChain("/api/dpd_results",
+ {},
+ function(data) {
+ mark_ok('is_dpdce_running', "State: " + data['state']);
+ mark_overall_ok();
+ },
+ 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/static/js/odr-predistortion.js b/python/gui/static/js/odr-predistortion.js
index 04d2773..4dae068 100644
--- a/python/gui/static/js/odr-predistortion.js
+++ b/python/gui/static/js/odr-predistortion.js
@@ -1,4 +1,4 @@
-// Copyright (C) 2018
+// Copyright (C) 2019
// Matthias P. Braendli, matthias.braendli@mpb.li
//
// http://www.opendigitalradio.org
@@ -18,6 +18,8 @@
// You should have received a copy of the GNU General Public License
// along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
+var adapt_dumps = [];
+
function resultrefresh() {
var jqxhr = doApiRequestGET("/api/dpd_results", function(data) {
var summary = "";
@@ -29,6 +31,30 @@ function resultrefresh() {
$('#dpdresults').html(summary);
$('#dpdstatus').text(data['state']);
+ var percentage = data['stateprogress'];
+ if (percentage > 100) {
+ percentage = 100;
+ }
+ $('#dpdprogress').css('width', percentage + '%');
+ $('#dpdprogresstext').text(percentage + '%');
+
+ if (data['statplot']) {
+ $('#dpdcapturestats').attr('src', data['statplot']);
+ }
+ else {
+ $('#dpdcapturestats').attr('src', "");
+ }
+
+ $('#dpdmodeldata').html(data['modeldata']);
+
+ if (data['modelplot']) {
+ $('#dpdmodelplot').attr('src', data['modelplot']);
+ }
+ else {
+ $('#dpdmodelplot').attr('src', "");
+ }
+
+ adapt_dumps = data['adapt_dumps'];
});
jqxhr.always(function() {
@@ -36,8 +62,32 @@ function resultrefresh() {
});
}
+function adaptdumpsrefresh() {
+ $('#dpdadaptdumps').html("");
+
+ $.each(adapt_dumps, function(i, item) {
+ console.log(item);
+
+ if (isNaN(+item)) {
+ $('#dpdadaptdumps').append($('<option>', {
+ value: item,
+ text : "DPD settings from " + item,
+ }));
+ }
+ else {
+ var d = new Date(0);
+ d.setUTCSeconds(item);
+
+ $('#dpdadaptdumps').append($('<option>', {
+ value: item,
+ text : "DPD settings from " + d.toISOString(),
+ }));
+ }
+ });
+}
+
$(function(){
- setTimeout(resultrefresh, 2000);
+ setTimeout(resultrefresh, 20);
$('#calibratebtn').click(function() {
doApiRequestPOST("/api/dpd_calibrate", {}, function(data) {
@@ -45,72 +95,39 @@ $(function(){
});
});
-});
-
-/*
-function calibraterefresh() {
- doApiRequestGET("/api/calibrate", function(data) {
- var text = "Captured TX signal and feedback." +
- " TX median: " + data['tx_median'] +
- " RX median: " + data['rx_median'] +
- " with relative timestamp offset " +
- (data['tx_ts'] - data['rx_ts']) +
- " and measured offset " + data['coarse_offset'] +
- ". Correlation: " + data['correlation'];
- $('#calibrationresults').text(text);
+ $('#triggerbtn').click(function() {
+ doApiRequestPOST("/api/dpd_trigger_run", {}, function(data) {
+ console.log("run succeeded: " + JSON.stringify(data));
+ });
});
-}
-$(function(){
- $('#refreshframesbtn').click(function() {
- var d = new Date();
- var n = d.getTime();
- $('#txframeimg').src = "dpd/txframe.png?cachebreak=" + n;
- $('#rxframeimg').src = "dpd/rxframe.png?cachebreak=" + n;
+ $('#adaptbtn').click(function() {
+ doApiRequestPOST("/api/dpd_adapt", {}, function(data) {
+ console.log("adapt succeeded: " + JSON.stringify(data));
+ });
});
- $('#capturebutton').click(function() {
- doApiRequestPOST("/api/trigger_capture", {}, function(data) {
- console.log("trigger_capture succeeded: " + JSON.stringify(data));
+
+ $('#resetbtn').click(function() {
+ doApiRequestPOST("/api/dpd_reset", {}, function(data) {
+ console.log("reset succeeded: " + JSON.stringify(data));
});
});
- $('#dpdstatusbutton').click(function() {
- doApiRequestGET("/api/dpd_status", function(data) {
- console.log("dpd_status succeeded: " + JSON.stringify(data));
- $('#histogram').text(data.histogram);
- $('#capturestatus').text(data.capture.status);
- $('#capturelength').text(data.capture.length);
- $('#tx_median').text(data.capture.tx_median);
- $('#rx_median').text(data.capture.rx_median);
- });
+ $('#adaptdumpsrefreshbtn').click(adaptdumpsrefresh);
+
+ $('#adaptdumpsload').click(function() {
+ var elt = document.getElementById("dpdadaptdumps");
- $.ajax({
- type: "GET",
- url: "/api/dpd_capture_pointcloud",
-
- error: function(data) {
- if (data.status == 500) {
- var errorWindow = window.open("", "_self");
- errorWindow.document.write(data.responseText);
- }
- else {
- $.gritter.add({ title: 'API',
- text: "AJAX failed: " + data.statusText,
- image: '/fonts/warning.png',
- sticky: true,
- });
- }
- },
- success: function(data) {
- $('#dpd_pointcloud').value(data)
+ if (elt.selectedIndex != -1) {
+ var selectedoption = elt.options[elt.selectedIndex].value;
+ doApiRequestPOST("/api/dpd_restore_dump", {dump_id: selectedoption}, function(data) {
+ console.log("reset succeeded: " + JSON.stringify(data));
+ });
}
- })
});
});
-*/
-
// ToolTip init
$(function(){
diff --git a/python/gui/static/js/odr-rcvalues.js b/python/gui/static/js/odr-rcvalues.js
index f49674c..486a8a7 100644
--- a/python/gui/static/js/odr-rcvalues.js
+++ b/python/gui/static/js/odr-rcvalues.js
@@ -31,22 +31,28 @@ function requestStatus() {
doApiRequestGET("/api/rc_parameters", function(data) {
console.log(data);
- let keys = Object.keys(data);
- keys.sort();
+ let controllable_names = Object.keys(data);
+ controllable_names.sort();
var key1;
- for (key1 in keys) {
- let keys2 = Object.keys(data[keys[key1]]);
- keys2.sort();
+ for (key1 in controllable_names) {
+ let param_names = Object.keys(data[controllable_names[key1]]);
+ param_names.sort();
var key2;
- for (key2 in keys2) {
- var param = data[keys[key1]][keys2[key2]];
- var key = keys[key1] + "_" + keys2[key2];
+ for (key2 in param_names) {
+ var name_controllable = controllable_names[key1];
+ var name_param = param_names[key2];
+ var key = name_controllable + "_" + name_param;
+
+ var param = data[name_controllable][name_param];
var valueentry = '<input type="text" id="input'+key+'" ' +
'value="' + param['value'] + '">' +
'<button type="button" class="btn btn-xs btn-warning"' +
- 'id="button'+key+'" >upd</button>';
+ 'id="button'+key+'" ' +
+ 'data-controllable="'+name_controllable+'" ' +
+ 'data-param="'+name_param+'" ' +
+ '>upd</button>';
$('#rctable > tbody:last').append(
'<tr><td>'+key+'</td>'+
@@ -54,7 +60,10 @@ function requestStatus() {
'<td>'+param['help']+'</td></tr>');
$('#button'+key).click(function() {
- buttonSetRc("input"+key, key1, key2);
+ var attr_c = this.getAttribute('data-controllable');
+ var attr_p = this.getAttribute('data-param');
+ var k = attr_c + "_" + attr_p;
+ buttonSetRc("input"+k, attr_c, attr_p);
});
}
}
diff --git a/python/gui/templates/about.html b/python/gui/templates/about.html
index 3a05230..b781d54 100644
--- a/python/gui/templates/about.html
+++ b/python/gui/templates/about.html
@@ -1,24 +1,3 @@
-<!--
- Copyright (C) 2018
- Matthias P. Braendli, matthias.braendli@mpb.li
-
-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/>.
--->
-
-
<!DOCTYPE html>
<html lang="en">
@@ -63,3 +42,24 @@ along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
</html>
+<!--
+ Copyright (C) 2018
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+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/>.
+-->
+
+
diff --git a/python/gui/templates/home.html b/python/gui/templates/home.html
index 5cb29f8..398df37 100644
--- a/python/gui/templates/home.html
+++ b/python/gui/templates/home.html
@@ -1,3 +1,59 @@
+<!DOCTYPE html>
+<html lang="en">
+
+{% include 'head.html' %}
+
+<body>
+ {% 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>
+ <li>GPSDO status:
+ <span id="is_gpsdo_ok" class="glyphicon glyphicon-question-sign"></span>
+ <span id="is_gpsdo_ok_comment"><span>
+ </li>
+ <li>Underruns:
+ <span id="is_underrunning" class="glyphicon glyphicon-question-sign"></span>
+ <span id="is_underrunning_comment"><span>
+ </li>
+ <li>Late packets:
+ <span id="is_late" class="glyphicon glyphicon-question-sign"></span>
+ <span id="is_late_comment"><span>
+ </li>
+ </ul>
+
+ <p>Checking predistortion
+ <ul>
+ <li>Sample rate at 4x native rate:
+ <span id="is_rate_4x" class="glyphicon glyphicon-question-sign"></span>
+ <span id="is_rate_4x_comment"><span>
+ </li>
+ <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>
+
<!--
Copyright (C) 2018
Matthias P. Braendli, matthias.braendli@mpb.li
@@ -17,19 +73,3 @@ 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/>.
-->
-
-<!DOCTYPE html>
-<html lang="en">
-
-{% 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>
-</body>
-</html>
diff --git a/python/gui/templates/modulator.html b/python/gui/templates/modulator.html
index 6deffb1..016344a 100644
--- a/python/gui/templates/modulator.html
+++ b/python/gui/templates/modulator.html
@@ -1,23 +1,3 @@
-<!--
- Copyright (C) 2018
- Matthias P. Braendli, matthias.braendli@mpb.li
-
-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/>.
--->
-
<!DOCTYPE html>
<html lang="en">
@@ -71,3 +51,23 @@ along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
</div>
</body>
</html>
+
+<!--
+ Copyright (C) 2018
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+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/>.
+-->
diff --git a/python/gui/templates/predistortion.html b/python/gui/templates/predistortion.html
index cc5ecb0..62e8503 100644
--- a/python/gui/templates/predistortion.html
+++ b/python/gui/templates/predistortion.html
@@ -1,23 +1,3 @@
-<!--
- Copyright (C) 2018
- Matthias P. Braendli, matthias.braendli@mpb.li
-
-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/>.
--->
-
<!DOCTYPE html>
<html lang="en">
@@ -31,42 +11,87 @@ along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
<div class="panel panel-default">
<div class="panel-heading">Status and calibration</div>
<div class="panel-body">
- <div>Current DPDCE status: <span id="dpdstatus" style="font-weight:bold;">N/A</span>
- <div class="well well-sm" id="dpdresults">N/A</div>
+
+ <div class="container-fluid">
+ <div class="row">
+ <div class="col-sm-4">
+ <h2>Current DPDCE status</h2>
+ <div>
+ <div id="dpdstatus" style="font-weight:bold;">N/A</div>
+ <div class="progress">
+ <div id="dpdprogress" class="progress-bar" role="progressbar" style="width:0%">
+ <span id="dpdprogresstext"></span>
+ </div>
+ </div>
+ </div>
+ <div class="well well-sm" id="dpdresults">N/A</div>
+ </div>
+ <div class="col-sm-4">
+ <h2>List of saved DPD settings</h2>
+ <!--TODO: 'erase' and 'clear' buttons. Show DPD settings in tooltip?-->
+ <p>This list contains previously used predistortion settings that you
+ can recall.</p>
+ <p>
+ <select id="dpdadaptdumps" size="8" style="width:70%" multiple></select>
+ </p>
+ <p>
+ <button type="button" class="btn btn-sm btn-info" id="adaptdumpsrefreshbtn">Refresh
+ </button>
+ <button type="button" class="btn btn-sm btn-warning" id="adaptdumpsload">Load and Apply
+ </button>
+ </p>
+ </div>
+ <div class="col-sm-4">
+ <h2>Summary</h2>
+ <p>Calibration needs to be done once before the PA model
+ can be trained. Every time calibration is changed, the predistortion
+ parameters are invalidated!</p>
+ <p>Once calibration succeeded and correct RX gain is set, you
+ can trigger a capture and model the PA. Usually, several capture
+ runs are needed before the model can be trained.</p>
+ <p>The capture and model analysis will calculate a new set of
+ DPD model data, that you can apply using the Update Predistorter button.</p>
+ <p>The reset button allows you to reset the computation engine. It does not
+ modify the currently active predistorter.</p>
+ </div>
+ </div>
</div>
- <div>Calibration needs to be done once before the PA model
- can be trained. Every time calibration is changed, the predistortion
- parameters are invalidated!</div>
<button type="button" class="btn btn-sm btn-warning" id="calibratebtn">
Calibrate</button>
+ <button type="button" class="btn btn-sm btn-warning" id="triggerbtn">
+ Trigger Capture and PA Modeling</button>
+ <button type="button" class="btn btn-sm btn-warning" id="adaptbtn">
+ Update Predistorter</button>
+ <button type="button" class="btn btn-sm btn-info" id="resetbtn">
+ Reset Capture and Model</button>
</div>
</div>
- <!--
+
<div class="panel panel-default">
- <div class="panel-heading">Capture TX and RX frames</div>
+ <div class="panel-heading">Capture Statistics</div>
<div class="panel-body">
- <div>
- <img id="txframeimg" src="dpd/txframe.png" width="320" height="240" />
- <img id="rxframeimg" src="dpd/rxframe.png" width="320" height="240" />
- </div>
- <div>
- <button type="button" class="btn btn-sm btn-info" id="refreshframesbtn">
- Refresh</button>
- </div>
+ <img id="dpdcapturestats" />
</div>
</div>
-
<div class="panel panel-default">
- <div class="panel-heading">Capture</div>
+ <div class="panel-heading">AM/AM and AM/PM Model</div>
<div class="panel-body">
- <div>On pressing this button,
- the DPDCE will trigger a capture and a quick data
- analysis, without updating any DPD models.</div>
- <button type="button" class="btn btn-sm btn-info" id="capturebutton">
- Capture</button>
+ <div class="container-fluid">
+ <div class="row">
+ <div class="col-sm-2">
+ <p>Model data:</p>
+ </div>
+ <div class="col-sm-10">
+ <pre id="dpdmodeldata"></pre>
+ </div>
+ </div>
+ </div>
+ <img id="dpdmodelplot" />
</div>
</div>
+
+ <!--
<div class="panel panel-default">
<div class="panel-heading">Status</div>
<div class="panel-body">
@@ -87,3 +112,23 @@ along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
</div>
</body>
</html>
+
+<!--
+ Copyright (C) 2019
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+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/>.
+-->
diff --git a/python/gui/templates/rcvalues.html b/python/gui/templates/rcvalues.html
index c1786bc..9e607bc 100644
--- a/python/gui/templates/rcvalues.html
+++ b/python/gui/templates/rcvalues.html
@@ -1,23 +1,3 @@
-<!--
- Copyright (C) 2018
- Matthias P. Braendli, matthias.braendli@mpb.li
-
-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/>.
--->
-
<!DOCTYPE html>
<html lang="en">
@@ -46,3 +26,22 @@ along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
</div>
</body>
</html>
+<!--
+ Copyright (C) 2018
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+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/>.
+-->