diff options
Diffstat (limited to 'python/gui')
| -rwxr-xr-x | python/gui/api.py | 47 | ||||
| -rw-r--r-- | python/gui/static/css/odr.css | 14 | ||||
| -rw-r--r-- | python/gui/static/js/odr-home.js | 240 | ||||
| -rw-r--r-- | python/gui/static/js/odr-predistortion.js | 129 | ||||
| -rw-r--r-- | python/gui/static/js/odr-rcvalues.js | 29 | ||||
| -rw-r--r-- | python/gui/templates/about.html | 42 | ||||
| -rw-r--r-- | python/gui/templates/home.html | 72 | ||||
| -rw-r--r-- | python/gui/templates/modulator.html | 40 | ||||
| -rw-r--r-- | python/gui/templates/predistortion.html | 129 | ||||
| -rw-r--r-- | python/gui/templates/rcvalues.html | 39 | 
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/>. +-->  | 
