diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-11-28 15:04:41 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-11-28 15:04:41 +0100 |
commit | 8b42d3115db2ecec9031c5d1421463b0191e055c (patch) | |
tree | 66c1a9d5864c478ca5026a681963e81db6142e0f | |
parent | cfa9461f269e616d6d54658d583b37d215f35a7b (diff) | |
download | dabmod-8b42d3115db2ecec9031c5d1421463b0191e055c.tar.gz dabmod-8b42d3115db2ecec9031c5d1421463b0191e055c.tar.bz2 dabmod-8b42d3115db2ecec9031c5d1421463b0191e055c.zip |
Use multiprocessing for DPD functionality
-rwxr-xr-x | gui/api/__init__.py | 55 | ||||
-rw-r--r-- | gui/dpd/Capture.py | 2 | ||||
-rw-r--r-- | gui/dpd/__init__.py | 5 | ||||
-rwxr-xr-x | gui/run.py | 92 | ||||
-rw-r--r-- | gui/static/js/odr-predistortion.js | 2 |
5 files changed, 87 insertions, 69 deletions
diff --git a/gui/api/__init__.py b/gui/api/__init__.py index 56062c3..c1d73a0 100755 --- a/gui/api/__init__.py +++ b/gui/api/__init__.py @@ -21,7 +21,6 @@ # along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>. import cherrypy -from cherrypy.process import wspbus, plugins from cherrypy.lib.httputil import parse_query_string import urllib @@ -29,6 +28,7 @@ import os import io import datetime +import threading def send_ok(data=None): if data is not None: @@ -42,26 +42,36 @@ def send_error(reason=""): else: return {'status' : 'error'} -class API(plugins.SimplePlugin): - def __init__(self, mod_rc, bus): - plugins.SimplePlugin.__init__(self, bus) +class RXThread(threading.Thread): + def __init__(self, api): + super(RXThread, self).__init__() + self.api = api + self.running = False + self.daemon = True + + def cancel(self): + self.running = False + + def run(self): + self.running = True + while self.running: + if self.api.dpd_pipe.poll(1): + rx = self.api.dpd_pipe.recv() + if rx['cmd'] == "quit": + break + elif rx['cmd'] == "dpd-state": + self.api.dpd_state = rx['data'] + elif rx['cmd'] == "dpd-calibration-result": + self.api.calibration_result = rx['data'] + +class API: + def __init__(self, mod_rc, dpd_pipe): self.mod_rc = mod_rc + self.dpd_pipe = dpd_pipe self.dpd_state = None self.calibration_result = None - - def start(self): - self.bus.subscribe("dpd-state", self.dpd_state) - self.bus.subscribe("dpd-calibration-result", self.calibration_result) - - def stop(self): - self.bus.unsubscribe("dpd-state", self.dpd_state) - self.bus.unsubscribe("dpd-calibration-result", self.calibration_result) - - def calibration_result(self, new_result): - self.calibration_result = new_result - - def dpd_state(self, new_state): - self.dpd_state = new_state + self.receive_thread = RXThread(self) + self.receive_thread.start() @cherrypy.expose def index(self): @@ -93,7 +103,7 @@ class API(plugins.SimplePlugin): @cherrypy.tools.json_out() def trigger_capture(self, **kwargs): if cherrypy.request.method == 'POST': - cherrypy.engine.publish('dpd-capture', None) + self.dpd_pipe.send({'cmd': "dpd-capture"}) return send_ok() else: cherrypy.response.status = 400 @@ -109,12 +119,13 @@ class API(plugins.SimplePlugin): @cherrypy.expose @cherrypy.tools.json_out() - def dpd_calibrate(self, **kwargs): + def calibrate(self, **kwargs): if cherrypy.request.method == 'POST': - cherrypy.engine.publish('dpd-calibrate', None) + self.dpd_pipe.send({'cmd': "dpd-calibrate"}) return send_ok() else: - if self.dpd_state is not None: + if self.calibration_result is not None: + print("cal result", repr(self.calibration_result)) return send_ok(self.calibration_result) else: return send_error("DPD calibration result unknown") diff --git a/gui/dpd/Capture.py b/gui/dpd/Capture.py index 4c0e99c..3b2988b 100644 --- a/gui/dpd/Capture.py +++ b/gui/dpd/Capture.py @@ -172,7 +172,7 @@ class Capture: rxframe = rxframe * self.rx_normalisation txframe_aligned, rxframe_aligned, coarse_offset = align_samples(txframe, rxframe) - return tx_ts, tx_median, rx_ts, rx_median, coarse_offset, correlation_coefficient(txframe_aligned, rxframe_aligned) + return tx_ts, tx_median, rx_ts, rx_median, np.abs(coarse_offset), correlation_coefficient(txframe_aligned, rxframe_aligned) def get_samples(self): """Connect to ODR-DabMod, retrieve TX and RX samples, load diff --git a/gui/dpd/__init__.py b/gui/dpd/__init__.py index 716b8c2..85abe86 100644 --- a/gui/dpd/__init__.py +++ b/gui/dpd/__init__.py @@ -57,12 +57,13 @@ class DPD: def capture_calibration(self): tx_ts, tx_median, rx_ts, rx_median, coarse_offset, correlation_coefficient = self.capture.calibrate() result = {'status': "ok"} - result['length'] = len(txframe_aligned) result['tx_median'] = "{:.2}dB".format(20*np.log10(tx_median)) result['rx_median'] = "{:.2}dB".format(20*np.log10(rx_median)) result['tx_ts'] = tx_ts result['rx_ts'] = rx_ts - result['correlation'] = correlation_coefficient + result['coarse_offset'] = int(coarse_offset) + result['correlation'] = float(correlation_coefficient) + return result def capture_samples(self): """Captures samples and store them in the accumulated samples, @@ -22,9 +22,9 @@ # along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>. import configuration +from multiprocessing import Process, Pipe import os.path import cherrypy -from cherrypy.process import wspbus, plugins import argparse from jinja2 import Environment, FileSystemLoader from api import API @@ -36,12 +36,11 @@ env = Environment(loader=FileSystemLoader('templates')) base_js = ["js/odr.js"] class Root: - def __init__(self, config_file): + def __init__(self, config_file, dpd_pipe): self.config_file = config_file self.conf = configuration.Configuration(self.config_file) self.mod_rc = zmqrc.ModRemoteControl("localhost") - self.api = API(self.mod_rc, cherrypy.engine) - self.api.subscribe() + self.api = API(self.mod_rc, dpd_pipe) @cherrypy.expose def index(self): @@ -75,24 +74,32 @@ class Root: js = base_js + ["js/odr-predistortion.js"] return tmpl.render(tab='predistortion', js=js, is_login=False) -class DPDPlugin(plugins.SimplePlugin): - def __init__(self, bus): - plugins.SimplePlugin.__init__(self, bus) +class DPDRunner: + def __init__(self): + self.web_end, self.dpd_end = Pipe() self.dpd = dpd.DPD() - def start(self): - self.bus.subscribe("dpd-capture", self.trigger_capture) - self.bus.subscribe("dpd-calibrate", self.trigger_calibrate) + def __enter__(self): + self.p = Process(target=self._handle_messages) + self.p.start() + return self.web_end - def stop(self): - self.bus.unsubscribe("dpd-capture", self.trigger_capture) - self.bus.unsubscribe("dpd-calibrate", self.trigger_calibrate) + def _handle_messages(self): + while True: + rx = self.dpd_end.recv() + if rx['cmd'] == "quit": + break + elif rx['cmd'] == "dpd-capture": + self.dpd.capture_samples() + elif rx['cmd'] == "dpd-calibrate": + self.dpd_end.send({'cmd': "dpd-calibration-result", + 'data': self.dpd.capture_calibration()}) - def trigger_capture(self, param): - print("trigger_capture({})".format(param)) - def trigger_calibrate(self, param): - cherrypy.engine.publish('dpd-calibration-result', self.dpd.capture_calibration()) + def __exit__(self, exc_type, exc_value, traceback): + self.web_end.send({'cmd': "quit"}) + self.p.join() + return False if __name__ == '__main__': parser = argparse.ArgumentParser(description='ODR-DabMod Web GUI') @@ -127,30 +134,29 @@ if __name__ == '__main__': staticdir = os.path.realpath(config.config['global']['static_directory']) - DPDPlugin(cherrypy.engine).subscribe() - - cherrypy.tree.mount( - Root(cli_args.config), config={ - '/': { }, - '/css': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': os.path.join(staticdir, u"css/") - }, - '/js': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': os.path.join(staticdir, u"js/") - }, - '/fonts': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': os.path.join(staticdir, u"fonts/") - }, - '/favicon.ico': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': os.path.join(staticdir, u"fonts/favicon.ico") - }, - } - ) - - cherrypy.engine.start() - cherrypy.engine.block() + with DPDRunner() as dpd_pipe: + cherrypy.tree.mount( + Root(cli_args.config, dpd_pipe), config={ + '/': { }, + '/css': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': os.path.join(staticdir, u"css/") + }, + '/js': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': os.path.join(staticdir, u"js/") + }, + '/fonts': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': os.path.join(staticdir, u"fonts/") + }, + '/favicon.ico': { + 'tools.staticfile.on': True, + 'tools.staticfile.filename': os.path.join(staticdir, u"fonts/favicon.ico") + }, + } + ) + + cherrypy.engine.start() + cherrypy.engine.block() diff --git a/gui/static/js/odr-predistortion.js b/gui/static/js/odr-predistortion.js index 01992d7..e13fb88 100644 --- a/gui/static/js/odr-predistortion.js +++ b/gui/static/js/odr-predistortion.js @@ -19,7 +19,7 @@ // along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>. $(function(){ - $('#calibrate').click(function() { + $('#calibratebtn').click(function() { doApiRequestPOST("/api/calibrate", {}, function(data) { console.log("calibrate succeeded: " + JSON.stringify(data)); |