From 30012258948049da894e260d78551d1de44c2f50 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Sat, 4 Dec 2021 16:46:23 +0100 Subject: Update net.py to decode UDP data stream --- src/gui/gui.py | 7 ++-- src/gui/net.py | 67 +++++++++++++++++++----------- tests/sockets/Socket_test.grc | 24 +++++------ tests/sockets/Test_Bit_Errorrate.py | 83 ++++++------------------------------- 4 files changed, 71 insertions(+), 110 deletions(-) diff --git a/src/gui/gui.py b/src/gui/gui.py index b2cbebb..d817f63 100755 --- a/src/gui/gui.py +++ b/src/gui/gui.py @@ -98,7 +98,8 @@ with window(label="RX DSP Flow Graph", width=800, height=400, pos=(25,25), tag=" #================================================ # Network plots Window -recv_plot = net.network_plot(url="udp://localhost:31415", nsamples=100, label="Test", height=300, width=800) +recv_plot = net.network_plot(url="udp://localhost:31415", dtype=float, nsamples=100, \ + label="Test", height=300, width=800) plots = { recv_plot: "plt_ampl" @@ -107,9 +108,9 @@ plots = { with window(label="Time domain plots", width=800, height=400, pos=(850,25)): with recv_plot: add_plot_axis(mvXAxis, label="Time") - add_plot_axis(mvYAxis, label="Amplitude", tag="plt_ampl") + add_plot_axis(mvYAxis, label="Amplitude", tag="axis") - add_line_series(recv_plot.x_data, recv_plot.y_data, parent="plt_ampl") + add_line_series(recv_plot.xdata, recv_plot.ydata, parent="axis", tag="plt_ampl") #================================================ # Start GUI and main loop diff --git a/src/gui/net.py b/src/gui/net.py index 2c91bb8..c7008cd 100644 --- a/src/gui/net.py +++ b/src/gui/net.py @@ -1,6 +1,7 @@ import select import socket from urllib.parse import urlparse +import re import numpy as np from numpy_ringbuffer import RingBuffer @@ -11,9 +12,10 @@ class udpsource: """ Creates an UDP listening socket """ - def __init__(self, url): + def __init__(self, url, dtype): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.url = urlparse(url) + self.dtype = dtype def __del__(self): self.sock.close() @@ -23,32 +25,46 @@ class udpsource: self.sock.bind((self.url.hostname, self.url.port)) # self.sock.listen() - def read(self, nbytes): - ready_to_read, ready_to_write, in_err = \ - select.select([self.sock], [], [], 1) - - if ready_to_read: - data = sock.recv(nbytes) - print(data) - else: + def read(self, nblocks): + ready, _, _ = select.select([self.sock], [], []) + if not ready: return None + # read from socket + blocksize = 1024 * 4 + string = ready[0].recv(nblocks * blocksize).decode("ascii") + + # decode string, remove empty values + chunks = filter(None, re.split(r"\[(.+?)\]", string)) + + def chunk_to_samples(chunk): + samples = chunk.split(",") + if samples: + return list(map(self.dtype, samples)) + + # convert each chunk into a list of samples + chunk_values = map(chunk_to_samples, chunks) + + # flatten list of lists into a single list + values = sum(chunk_values, []) + + return values class network_plot(udpsource): - def __init__(self, url, nsamples, **kwargs): - udpsource.__init__(self, url) + def __init__(self, url, dtype, nsamples, **kwargs): + udpsource.__init__(self, url, dtype) + # create buffers for x and y values self.nsamples = nsamples - self.plot = dpg.plot(**kwargs) - - # create buffer and fill with zeroes - self.buffer = RingBuffer(capacity=nsamples, dtype=(float, 2)) - for i in range(nsamples): - # TODO: remove random data used for testing - self.buffer.append(np.array([i, 1 + np.random.rand() / 5])) + self.xvalues = np.arange(0, self.nsamples) + self.yvalues = RingBuffer(capacity=self.nsamples, dtype=np.dtype(dtype)) + self.yvalues.extend(np.zeros(self.nsamples)) + # create a plot + self.plot = dpg.plot(**kwargs) self.bind() + # Map `with' expressions to the underlying plot def __enter__(self): return self.plot.__enter__() @@ -56,13 +72,16 @@ class network_plot(udpsource): self.plot.__exit__(t, val, tb) @property - def x_data(self): - return np.array(self.buffer[:,0]) + def xdata(self): + return self.xvalues @property - def y_data(self): - return np.array(self.buffer[:,1]) + def ydata(self): + return np.array(self.yvalues) def refresh_series(self, tag): - dpg.set_value(tag, [self.x_data, self.y_data]) - pass + new_values = self.read(1) + + if new_values: + self.yvalues.extendleft(new_values) + dpg.set_value(tag, [self.xdata, self.ydata]) diff --git a/tests/sockets/Socket_test.grc b/tests/sockets/Socket_test.grc index 41c7f0a..fbc3cdf 100644 --- a/tests/sockets/Socket_test.grc +++ b/tests/sockets/Socket_test.grc @@ -8,7 +8,7 @@ options: description: '' gen_cmake: 'On' gen_linking: dynamic - generate_options: qt_gui + generate_options: no_gui hier_block_src_path: '.:' id: Test_Bit_Errorrate max_nouts: '0' @@ -18,7 +18,7 @@ options: realtime_scheduling: '' run: 'True' run_command: '{python} -u {filename}' - run_options: prompt + run_options: run sizing_mode: fixed thread_safe_setters: '' title: 'Bit Error Rate test ' @@ -41,7 +41,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [184, 12] + coordinate: [216, 20.0] rotation: 0 state: enabled - name: analog_noise_source_x_0 @@ -60,9 +60,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [528, 108.0] + coordinate: [32, 148.0] rotation: 0 - state: disabled + state: enabled - name: blocks_null_source_0 id: blocks_null_source parameters: @@ -73,15 +73,15 @@ blocks: maxoutbuf: '0' minoutbuf: '0' num_outputs: '1' - type: byte + type: complex vlen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [552, 224.0] + coordinate: [64, 264.0] rotation: 0 - state: true + state: disabled - name: blocks_throttle_1 id: blocks_throttle parameters: @@ -92,13 +92,13 @@ blocks: maxoutbuf: '0' minoutbuf: '0' samples_per_second: samp_rate - type: byte + type: float vlen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [800, 156.0] + coordinate: [280, 164.0] rotation: 0 state: true - name: fadingui_netsink_0 @@ -108,13 +108,13 @@ blocks: affinity: '' alias: '' comment: '' - type: byte + type: float veclen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [1016, 156.0] + coordinate: [504, 164.0] rotation: 0 state: true - name: import_0 diff --git a/tests/sockets/Test_Bit_Errorrate.py b/tests/sockets/Test_Bit_Errorrate.py index b545104..6a989df 100755 --- a/tests/sockets/Test_Bit_Errorrate.py +++ b/tests/sockets/Test_Bit_Errorrate.py @@ -9,64 +9,23 @@ # Author: Sara Halter # GNU Radio version: 3.8.2.0 -from distutils.version import StrictVersion - -if __name__ == '__main__': - import ctypes - import sys - if sys.platform.startswith('linux'): - try: - x11 = ctypes.cdll.LoadLibrary('libX11.so') - x11.XInitThreads() - except: - print("Warning: failed to XInitThreads()") - +from gnuradio import analog from gnuradio import blocks from gnuradio import gr from gnuradio.filter import firdes import sys import signal -from PyQt5 import Qt from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation import fadingui import numpy as np -from gnuradio import qtgui -class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): +class Test_Bit_Errorrate(gr.top_block): def __init__(self): gr.top_block.__init__(self, "Bit Error Rate test ") - Qt.QWidget.__init__(self) - self.setWindowTitle("Bit Error Rate test ") - qtgui.util.check_set_qss() - try: - self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) - except: - pass - self.top_scroll_layout = Qt.QVBoxLayout() - self.setLayout(self.top_scroll_layout) - self.top_scroll = Qt.QScrollArea() - self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) - self.top_scroll_layout.addWidget(self.top_scroll) - self.top_scroll.setWidgetResizable(True) - self.top_widget = Qt.QWidget() - self.top_scroll.setWidget(self.top_widget) - self.top_layout = Qt.QVBoxLayout(self.top_widget) - self.top_grid_layout = Qt.QGridLayout() - self.top_layout.addLayout(self.top_grid_layout) - - self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") - - try: - if StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): - self.restoreGeometry(self.settings.value("geometry").toByteArray()) - else: - self.restoreGeometry(self.settings.value("geometry")) - except: - pass ################################################## # Variables @@ -76,24 +35,19 @@ class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): ################################################## # Blocks ################################################## - self.fadingui_netsink_0 = fadingui.netsink(address='udp://localhost:31415', dtype="byte", vlen=1) - self.blocks_throttle_1 = blocks.throttle(gr.sizeof_char*1, samp_rate,True) - self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1) + self.fadingui_netsink_0 = fadingui.netsink(address='udp://localhost:31415', dtype="float", vlen=1) + self.blocks_throttle_1 = blocks.throttle(gr.sizeof_float*1, samp_rate,True) + self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 1, 0) ################################################## # Connections ################################################## - self.connect((self.blocks_null_source_0, 0), (self.blocks_throttle_1, 0)) + self.connect((self.analog_noise_source_x_0, 0), (self.blocks_throttle_1, 0)) self.connect((self.blocks_throttle_1, 0), (self.fadingui_netsink_0, 0)) - def closeEvent(self, event): - self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") - self.settings.setValue("geometry", self.saveGeometry()) - event.accept() - def get_samp_rate(self): return self.samp_rate @@ -106,34 +60,21 @@ class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): def main(top_block_cls=Test_Bit_Errorrate, options=None): - - if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): - style = gr.prefs().get_string('qtgui', 'style', 'raster') - Qt.QApplication.setGraphicsSystem(style) - qapp = Qt.QApplication(sys.argv) - tb = top_block_cls() - tb.start() - - tb.show() - def sig_handler(sig=None, frame=None): - Qt.QApplication.quit() + tb.stop() + tb.wait() + + sys.exit(0) signal.signal(signal.SIGINT, sig_handler) signal.signal(signal.SIGTERM, sig_handler) - timer = Qt.QTimer() - timer.start(500) - timer.timeout.connect(lambda: None) + tb.start() - def quitting(): - tb.stop() - tb.wait() + tb.wait() - qapp.aboutToQuit.connect(quitting) - qapp.exec_() if __name__ == '__main__': main() -- cgit v1.2.1