aboutsummaryrefslogtreecommitdiffstats
path: root/python/lib
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2018-12-04 16:45:58 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2018-12-04 16:45:58 +0100
commit5cf52c74e9eb6bf8a82af4509ff3eb5106f928f9 (patch)
treea7edc1dfd2b2f4469f4dc4d760fdfa83a25fa710 /python/lib
parentd5cbe10c0e2298b0e40161607a3da158249bdb82 (diff)
downloaddabmod-5cf52c74e9eb6bf8a82af4509ff3eb5106f928f9.tar.gz
dabmod-5cf52c74e9eb6bf8a82af4509ff3eb5106f928f9.tar.bz2
dabmod-5cf52c74e9eb6bf8a82af4509ff3eb5106f928f9.zip
Rework GUI and DPDCE
Diffstat (limited to 'python/lib')
-rw-r--r--python/lib/__init__.py1
-rw-r--r--python/lib/yamlrpc.py93
-rw-r--r--python/lib/zmqrc.py84
3 files changed, 178 insertions, 0 deletions
diff --git a/python/lib/__init__.py b/python/lib/__init__.py
new file mode 100644
index 0000000..738b3a1
--- /dev/null
+++ b/python/lib/__init__.py
@@ -0,0 +1 @@
+# lib module
diff --git a/python/lib/yamlrpc.py b/python/lib/yamlrpc.py
new file mode 100644
index 0000000..bd61569
--- /dev/null
+++ b/python/lib/yamlrpc.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2018
+# 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/>.
+
+"""yamlrpc is json-rpc, except that it's yaml and not json."""
+
+# Same as jsonrpc version we're aiming to mirror in YAML
+YAMLRPC_VERSION = "2.0"
+
+import yaml
+import socket
+import struct
+
+def request(request_id: int, method: str, params) -> bytes:
+ r = {
+ 'yamlrpc': YAMLRPC_VERSION,
+ 'method': method,
+ 'params': params,
+ 'id': request_id}
+ return yaml.dump(r).encode()
+
+def response_success(request_id: int, result) -> bytes:
+ r = {
+ 'yamlrpc': YAMLRPC_VERSION,
+ 'result': result,
+ 'error': None,
+ 'id': request_id}
+ return yaml.dump(r).encode()
+
+def response_error(request_id: int, error) -> bytes:
+ r = {
+ 'yamlrpc': YAMLRPC_VERSION,
+ 'result': None,
+ 'error': error,
+ 'id': request_id}
+ return yaml.dump(r).encode()
+
+def notification(method: str, params) -> bytes:
+ r = {
+ 'yamlrpc': YAMLRPC_VERSION,
+ 'method': method,
+ 'params': params}
+ return yaml.dump(r).encode()
+
+class Socket:
+ def __init__(self, bind_port: int):
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ if bind_port > 0:
+ self.socket.bind(('127.0.0.1', bind_port))
+
+ def receive_request(self):
+ data, addr = self.socket.recvfrom(512)
+ y = yaml.load(data.decode())
+
+ if 'yamlrpc' not in y:
+ raise ValueError("Message is not yamlrpc")
+ if y['yamlrpc'] != YAMLRPC_VERSION:
+ raise ValueError("Invalid yamlrpc version")
+
+ # expect a request
+ try:
+ method = y['method']
+ msg_id = y['id']
+ params = y['params']
+ except KeyError:
+ raise ValueError("Incomplete message")
+ return addr, msg_id, method, params
+
+ def send_success_response(self, addr, msg_id: int, result):
+ self.socket.sendto(response_success(msg_id, result), addr)
+
+ def send_error_response(self, addr, msg_id: int, error):
+ self.socket.sendto(response_error(msg_id, error), addr)
+
diff --git a/python/lib/zmqrc.py b/python/lib/zmqrc.py
new file mode 100644
index 0000000..3897d7a
--- /dev/null
+++ b/python/lib/zmqrc.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2018
+# 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/>.
+import zmq
+import json
+
+class ModRemoteControl(object):
+ """Interact with ODR-DabMod using the ZMQ RC"""
+ def __init__(self, mod_host, mod_port=9400):
+ self._host = mod_host
+ self._port = mod_port
+ self._ctx = zmq.Context()
+
+ def _read(self, message_parts):
+ sock = zmq.Socket(self._ctx, zmq.REQ)
+ sock.setsockopt(zmq.LINGER, 0)
+ sock.connect("tcp://{}:{}".format(self._host, self._port))
+
+ for i, part in enumerate(message_parts):
+ if i == len(message_parts) - 1:
+ f = 0
+ else:
+ f = zmq.SNDMORE
+ sock.send(part.encode(), flags=f)
+
+ # use poll for timeouts:
+ poller = zmq.Poller()
+ poller.register(sock, zmq.POLLIN)
+ if poller.poll(5*1000): # 5s timeout in milliseconds
+ recv = sock.recv_multipart()
+ sock.close()
+ return [r.decode() for r in recv]
+ else:
+ raise IOError("Timeout processing ZMQ request")
+
+ def get_modules(self):
+ modules = {}
+
+ for mod in [json.loads(j) for j in self._read(['list'])]:
+ params = {}
+ pv_list = self._read(['show', mod['name']])
+
+ for pv in pv_list:
+ p, _, v = pv.partition(": ")
+ params[p] = {"value": v.strip()}
+
+ for p in mod['params']:
+ if p in params:
+ params[p]["help"] = mod['params'][p]
+ modules[mod['name']] = params
+
+ return modules
+
+ def get_param_value(self, module, param):
+ value = self._read(['get', module, param])
+ if value[0] == 'fail':
+ raise ValueError("Error getting param: {}".format(value[1]))
+ else:
+ return value[0]
+
+ def set_param_value(self, module, param, value):
+ ret = self._read(['set', module, param, value])
+ if ret[0] == 'fail':
+ raise ValueError("Error setting param: {}".format(ret[1]))
+