diff options
author | Josh Morman <jmorman@gnuradio.org> | 2022-11-10 11:44:53 -0500 |
---|---|---|
committer | Josh Morman <jmorman@gnuradio.org> | 2022-11-10 11:44:55 -0500 |
commit | b5b05f7c2a5e708db525fa8c3ef7ff2f1f7816d3 (patch) | |
tree | 5e202f5275b199dee99d37221c0690c63e748935 | |
parent | filter: pfb_arb_resampler updated to new block api and use optfir (diff) | |
download | gnuradio-dev-4.0-minimal.tar.xz gnuradio-dev-4.0-minimal.zip |
global: strip down to minimal filesetdev-4.0-minimal
As a separate branch to start incorporating broader refactoring changes
Signed-off-by: Josh Morman <jmorman@gnuradio.org>
335 files changed, 45 insertions, 30387 deletions
diff --git a/bench/bm_nop.cc b/bench/bm_nop.cc deleted file mode 100644 index 8ed44379d..000000000 --- a/bench/bm_nop.cc +++ /dev/null @@ -1,123 +0,0 @@ -#include <chrono> -#include <iostream> -#include <thread> - -#include <gnuradio/blocks/nop_source.h> -#include <gnuradio/blocks/null_sink.h> -#include <gnuradio/buffer_cpu_simple.h> -#include <gnuradio/buffer_cpu_vmcirc.h> -#include <gnuradio/flowgraph.h> -#include <gnuradio/realtime.h> -#include <gnuradio/runtime.h> -#include <gnuradio/schedulers/nbt/scheduler_nbt.h> -#include <gnuradio/streamops/nop.h> -#include <gnuradio/streamops/nop_head.h> - -#include <iostream> - -#include "CLI/App.hpp" -#include "CLI/Config.hpp" -#include "CLI/Formatter.hpp" - -using namespace gr; - -int main(int argc, char* argv[]) -{ - uint64_t samples = 15000000; - int nblocks = 1; - int nthreads = 0; - int veclen = 1; - int buffer_type = 0; - bool rt_prio = false; - - CLI::App app{ "App description" }; - - app.add_option("--samples", samples, "Number of Samples"); - app.add_option("--veclen", veclen, "Vector Length"); - app.add_option("--nblocks", nblocks, "Number of copy blocks"); - app.add_option("--nthreads", nthreads, "Number of threads (0:tpb)"); - app.add_option("--buffer_type", - buffer_type, - "Buffer Type (0:simple, 1:vmcirc, 2:cuda, 3:cuda_pinned"); - app.add_flag("--rt_prio", rt_prio, "Enable Real-time priority"); - - if (rt_prio && gr::enable_realtime_scheduling() != rt_status_t::OK) { - std::cout << "Error: failed to enable real-time scheduling." << std::endl; - } - - { - auto src = blocks::nop_source::make({ 1, sizeof(gr_complex) * veclen }); - auto head = - streamops::nop_head::make({ samples / veclen, sizeof(gr_complex) * veclen }); - auto snk = blocks::null_sink::make({ 1, sizeof(gr_complex) * veclen }); - std::vector<streamops::nop::sptr> blks(nblocks); - for (int i = 0; i < nblocks; i++) { - blks[i] = streamops::nop::make({ sizeof(gr_complex) * veclen }); - } - flowgraph_sptr fg(new flowgraph()); - - if (buffer_type == 0) { - fg->connect(src, 0, head, 0); - fg->connect(head, 0, blks[0], 0); - for (int i = 0; i < nblocks - 1; i++) { - fg->connect(blks[i], 0, blks[i + 1], 0); - } - fg->connect(blks[nblocks - 1], 0, snk, 0); - } - else { - fg->connect(src, 0, head, 0)->set_custom_buffer(BUFFER_CPU_VMCIRC_ARGS); - fg->connect(head, 0, blks[0], 0)->set_custom_buffer(BUFFER_CPU_VMCIRC_ARGS); - for (int i = 0; i < nblocks - 1; i++) { - fg->connect(blks[i], 0, blks[i + 1], 0) - ->set_custom_buffer(BUFFER_CPU_VMCIRC_ARGS); - } - fg->connect(blks[nblocks - 1], 0, snk, 0) - ->set_custom_buffer(BUFFER_CPU_VMCIRC_ARGS); - } - - auto sched = schedulers::scheduler_nbt::make(); - if (buffer_type == 1) { - sched->set_default_buffer_factory(BUFFER_CPU_VMCIRC_ARGS); - } - - if (nthreads > 0) { - int blks_per_thread = nblocks / nthreads; - - for (int i = 0; i < nthreads; i++) { - std::vector<block_sptr> block_group; - if (i == 0) { - block_group.push_back(src); - block_group.push_back(head); - } - - for (int j = 0; j < blks_per_thread; j++) { - block_group.push_back(blks[i * blks_per_thread + j]); - } - - if (i == nthreads - 1) { - for (int j = 0; j < (nblocks - nthreads * blks_per_thread); j++) { - block_group.push_back(blks[(i + 1) * blks_per_thread + j]); - } - block_group.push_back(snk); - } - sched->add_block_group(block_group); - } - } - - fg->validate(); - - auto rt = runtime::make(); - rt->add_scheduler(sched); - rt->initialize(fg); - auto t1 = std::chrono::steady_clock::now(); - rt->start(); - rt->wait(); - - - auto t2 = std::chrono::steady_clock::now(); - auto time = - std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count() / 1e9; - - std::cout << "[PROFILE_TIME]" << time << "[PROFILE_TIME]" << std::endl; - } -} diff --git a/bench/meson.build b/bench/meson.build index 581596a94..1619841fa 100644 --- a/bench/meson.build +++ b/bench/meson.build @@ -25,18 +25,6 @@ executable('bm_nbt_fanout', CLI11_dep], install : true) -srcs = ['bm_nop.cc'] -executable('bm_nbt_nop', - srcs, - # include_directories : incdir, - link_language : 'cpp', - dependencies: [gnuradio_gr_dep, - gnuradio_blocklib_blocks_dep, - gnuradio_blocklib_streamops_dep, - gnuradio_scheduler_nbt_dep, - CLI11_dep], - install : true) - srcs = ['bm_msg_forward.cc'] executable('bm_msg_forward', srcs, diff --git a/blocklib/analog/.gitignore b/blocklib/analog/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/analog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/analog/agc/agc.yml b/blocklib/analog/agc/agc.yml deleted file mode 100644 index fb40998ea..000000000 --- a/blocklib/analog/agc/agc.yml +++ /dev/null @@ -1,43 +0,0 @@ -module: analog -block: agc -label: AGC -blocktype: sync_block -category: '[Core]/Level Controllers' - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - -# float rate = 1e-4, float reference = 1.0, float gain = 1.0) -parameters: -- id: rate - label: Rate - dtype: rf32 - default: 1e-4 -- id: reference - label: Reference - dtype: rf32 - default: 1.0 -- id: gain - label: Gain - dtype: rf32 - default: 1.0 - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - -- domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/analog/agc/agc_cpu.cc b/blocklib/analog/agc/agc_cpu.cc deleted file mode 100644 index 4cbf20cab..000000000 --- a/blocklib/analog/agc/agc_cpu.cc +++ /dev/null @@ -1,27 +0,0 @@ -#include "agc_cpu.h" -#include "agc_cpu_gen.h" - -namespace gr { -namespace analog { - -template <class T> -agc_cpu<T>::agc_cpu(const typename agc<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), - kernel::analog::agc<T>(args.rate, args.reference, args.gain, 65536) -{ -} - -template <class T> -work_return_t agc_cpu<T>::work(work_io& wio) -{ - auto in = wio.inputs()[0].items<T>(); - auto out = wio.outputs()[0].items<T>(); - auto noutput_items = wio.outputs()[0].n_items; - kernel::analog::agc<T>::scaleN(out, in, noutput_items); - - wio.outputs()[0].n_produced = noutput_items; - return work_return_t::OK; -} - -} // namespace analog -} // namespace gr diff --git a/blocklib/analog/agc/agc_cpu.h b/blocklib/analog/agc/agc_cpu.h deleted file mode 100644 index 0ea29190d..000000000 --- a/blocklib/analog/agc/agc_cpu.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include <gnuradio/analog/agc.h> -#include <gnuradio/kernel/analog/agc.h> - -namespace gr { -namespace analog { - -template <class T> -class agc_cpu : public agc<T>, kernel::analog::agc<T> -{ -public: - agc_cpu(const typename agc<T>::block_args& args); - work_return_t work(work_io&) override; - -protected: -}; - -} // namespace analog -} // namespace gr diff --git a/blocklib/analog/enums.yml b/blocklib/analog/enums.yml deleted file mode 100644 index 64bd5b2d0..000000000 --- a/blocklib/analog/enums.yml +++ /dev/null @@ -1,24 +0,0 @@ -waveform_t: - # type: uint32_t # Only specify if necessary - enumerators: - - id: constant - value: 100 # unnecessary - label: Constant - - id: sin - label: Sine - - id: cos - label: Cosine - - id: square - label: Square - - id: triangle - label: Triangle - - id: sawtooth - label: Saw Tooth - -noise_t: - enumerators: - - id: uniform - value: 200 # unnecessary - - id: gaussian - - id: laplacian - - id: impulse diff --git a/blocklib/analog/examples/fm_rx.grc b/blocklib/analog/examples/fm_rx.grc deleted file mode 100644 index c9920cda0..000000000 --- a/blocklib/analog/examples/fm_rx.grc +++ /dev/null @@ -1,207 +0,0 @@ -options: - parameters: - author: josh - catch_exceptions: 'True' - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: qt_gui - hier_block_src_path: '.:' - id: fm_rx - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: Not titled yet - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: fm_deviation_hz - id: variable - parameters: - comment: '' - value: 75e3 - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [400, 20.0] - rotation: 0 - state: true -- name: freq - id: variable - parameters: - comment: '' - value: '90500000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [288, 20.0] - rotation: 0 - state: enabled -- name: in_rate - id: variable - parameters: - comment: '' - value: samp_rate - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [192, 84.0] - rotation: 0 - state: enabled -- name: samp_rate - id: variable - parameters: - comment: '' - value: '4000000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [184, 12] - rotation: 0 - state: enabled -- name: analog_fm_deemph_0 - id: analog_fm_deemph - parameters: - affinity: '' - alias: '' - comment: '' - fs: '400000' - impl: cpu - maxoutbuf: '0' - minoutbuf: '0' - showports: 'False' - tau: 75e-6 - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [688, 220.0] - rotation: 0 - state: true -- name: analog_quadrature_demod_0 - id: analog_quadrature_demod - parameters: - affinity: '' - alias: '' - comment: '' - gain: in_rate/(2*math.pi*fm_deviation_hz) - impl: cpu - maxoutbuf: '0' - minoutbuf: '0' - showports: 'False' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [368, 276.0] - rotation: 0 - state: true -- name: blocks_null_source_0 - id: blocks_null_source - parameters: - affinity: '' - alias: '' - comment: '' - impl: cpu - itemsize: '0' - maxoutbuf: '0' - minoutbuf: '0' - nports: '1' - showports: 'False' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [96, 460.0] - rotation: 0 - state: true -- name: import_0 - id: import - parameters: - alias: '' - comment: '' - imports: import math - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [528, 28.0] - rotation: 0 - state: true -- name: qtgui_time_sink_0 - id: qtgui_time_sink - parameters: - T: float - affinity: '' - alias: '' - comment: '' - gui_hint: '' - impl: cpu - name: '"hello"' - nconnections: '1' - samp_rate: samp_rate - showports: 'False' - size: '10240' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1016, 188.0] - rotation: 0 - state: true -- name: soapy_hackrf_source_0 - id: soapy_hackrf_source - parameters: - T: complex - affinity: '' - alias: '' - amp: 'False' - bandwidth: '0' - center_freq: freq - comment: '' - dev_args: '' - device: '' - gain: '16' - impl: cpu - maxoutbuf: '0' - minoutbuf: '0' - samp_rate: samp_rate - showports: 'False' - vga: '16' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [112, 284.0] - rotation: 0 - state: disabled - -connections: -- [analog_fm_deemph_0, '0', qtgui_time_sink_0, '0'] -- [analog_quadrature_demod_0, '0', analog_fm_deemph_0, '0'] -- [blocks_null_source_0, '0', analog_quadrature_demod_0, '0'] -- [soapy_hackrf_source_0, '0', analog_quadrature_demod_0, '0'] - -metadata: - file_format: 1 diff --git a/blocklib/analog/examples/fm_rx.py b/blocklib/analog/examples/fm_rx.py deleted file mode 100755 index 630a3a183..000000000 --- a/blocklib/analog/examples/fm_rx.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# -# SPDX-License-Identifier: GPL-3.0 -# -# GNU Radio Python Flow Graph -# Title: Not titled yet -# Author: josh -# GNU Radio version: 0.2.0 - -from packaging.version import Version as 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 PyQt5 import Qt -from gnuradio import qtgui -from gnuradio.kernel.filter import firdes -import sip -from gnuradio import analog -from gnuradio import blocks -from gnuradio import gr -#from gnuradio.filter import firdes -#from gnuradio.fft import window -import sys -import signal -from argparse import ArgumentParser -#from gnuradio.eng_arg import eng_float, intx -#from gnuradio import eng_notation -import math - - - -from gnuradio import qtgui - -class fm_rx(Qt.QWidget): - def start(self): - self.fg.start() - - def stop(self): - self.fg.stop() - - def wait(self): - self.fg.wait() - - def connect(self,*args): - return self.fg.connect(*args) - - def msg_connect(self,*args): - return self.fg.connect(*args) - - def __init__(self): - self.fg = gr.flowgraph("Not titled yet") - Qt.QWidget.__init__(self) - self.setWindowTitle("Not titled yet") - 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", "fm_rx") - - 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 - ################################################## - self.samp_rate = samp_rate = 4000000 - self.in_rate = in_rate = samp_rate - self.freq = freq = 90500000 - self.fm_deviation_hz = fm_deviation_hz = 75e3 - - ################################################## - # Blocks - ################################################## - self.qtgui_time_sink_0 = qtgui.time_sink_f(10240,samp_rate,"hello",1) - self._qtgui_time_sink_0_win = sip.wrapinstance(self.qtgui_time_sink_0.qwidget(), Qt.QWidget) - self.top_layout.addWidget(self._qtgui_time_sink_0_win) - self.blocks_null_source_0 = blocks.null_source( 1,0, impl=blocks.null_source.cpu) - self.analog_quadrature_demod_0 = analog.quadrature_demod( in_rate/(2*math.pi*fm_deviation_hz), impl=analog.quadrature_demod.cpu) - self.analog_fm_deemph_0 = analog.fm_deemph( 400000,75e-6, impl=analog.fm_deemph.cpu) - - - - ################################################## - # Connections - ################################################## - self.connect((self.analog_fm_deemph_0, 0), (self.qtgui_time_sink_0, 0)) - self.connect((self.analog_quadrature_demod_0, 0), (self.analog_fm_deemph_0, 0)) - self.connect((self.blocks_null_source_0, 0), (self.analog_quadrature_demod_0, 0)) - - - def closeEvent(self, event): - self.settings = Qt.QSettings("GNU Radio", "fm_rx") - self.settings.setValue("geometry", self.saveGeometry()) - self.stop() - self.wait() - - event.accept() - - def get_samp_rate(self): - return self.samp_rate - - def set_samp_rate(self, samp_rate): - self.samp_rate = samp_rate - self.set_in_rate(self.samp_rate) - - def get_in_rate(self): - return self.in_rate - - def set_in_rate(self, in_rate): - self.in_rate = in_rate - - def get_freq(self): - return self.freq - - def set_freq(self, freq): - self.freq = freq - - def get_fm_deviation_hz(self): - return self.fm_deviation_hz - - def set_fm_deviation_hz(self, fm_deviation_hz): - self.fm_deviation_hz = fm_deviation_hz - - - - -def main(flowgraph_cls=fm_rx, 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) - - fg = flowgraph_cls() - rt = gr.runtime() - - rt.initialize(fg.fg) - rt.start() - - fg.show() - - def sig_handler(sig=None, frame=None): - rt.stop() - rt.wait() - - Qt.QApplication.quit() - - signal.signal(signal.SIGINT, sig_handler) - signal.signal(signal.SIGTERM, sig_handler) - - timer = Qt.QTimer() - timer.start(500) - timer.timeout.connect(lambda: None) - - qapp.exec_() - -if __name__ == '__main__': - main() diff --git a/blocklib/analog/fm_deemph/fm_deemph.yml b/blocklib/analog/fm_deemph/fm_deemph.yml deleted file mode 100644 index 598d91382..000000000 --- a/blocklib/analog/fm_deemph/fm_deemph.yml +++ /dev/null @@ -1,116 +0,0 @@ -module: analog -block: fm_deemph -label: FM Deemphasis IIR Filter -blocktype: hier_block -category: '[Core]/Modulators' - -# Example Parameters -parameters: -- id: fs - label: Sampling Rate - dtype: int - grc: - default: 400000 -- id: tau - label: Tau - dtype: rf64 - default: 75e-6 - - -# Example Ports -ports: -- domain: stream - id: in - direction: input - type: rf32 - -- domain: stream - id: out - direction: output - type: rf32 - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 - -doc: - brief: FM Deemphasis IIR filter - detail: |- - - - Args: - fs: sampling frequency in Hz (float) - tau: Time constant in seconds (75us in US and South Korea, 50us everywhere else) (float) - - An analog deemphasis filter: - - R - o------/\/\/\/---+----o - | - = C - | - --- - - Has this transfer function: - - 1 1 - ---- --- - RC tau - H(s) = ---------- = ---------- - 1 1 - s + ---- s + --- - RC tau - - And has its -3 dB response, due to the pole, at - - |H(j w_c)|^2 = 1/2 => s = j w_c = j (1/(RC)) - - Historically, this corner frequency of analog audio deemphasis filters - been specified by the RC time constant used, called tau. - So w_c = 1/tau. - - FWIW, for standard tau values, some standard analog components would be: - tau = 75 us = (50K)(1.5 nF) = (50 ohms)(1.5 uF) - tau = 50 us = (50K)(1.0 nF) = (50 ohms)(1.0 uF) - - In specifying tau for this digital deemphasis filter, tau specifies - the *digital* corner frequency, w_c, desired. - - The digital deemphasis filter design below, uses the - "bilinear transformation" method of designing digital filters: - - 1. Convert digital specifications into the analog domain, by prewarping - digital frequency specifications into analog frequencies. - - w_a = (2/T)tan(wT/2) - - 2. Use an analog filter design technique to design the filter. - - 3. Use the bilinear transformation to convert the analog filter design to a - digital filter design. - - H(z) = H(s)| - s = (2/T)(1-z^-1)/(1+z^-1) - - - w_ca 1 1 - (-1) z^-1 - H(z) = ---- * ----------- * ----------------------- - 2 fs -w_ca -w_ca - 1 - ----- 1 + ----- - 2 fs 2 fs - 1 - ----------- z^-1 - -w_ca - 1 - ----- - 2 fs - - We use this design technique, because it is an easy way to obtain a filter - design with the -6 dB/octave roll-off required of the deemphasis filter. - - Jackson, Leland B., _Digital_Filters_and_Signal_Processing_Second_Edition_, - Kluwer Academic Publishers, 1989, pp 201-212 - - Orfanidis, Sophocles J., _Introduction_to_Signal_Processing_, Prentice Hall, - 1996, pp 573-583 - """
\ No newline at end of file diff --git a/blocklib/analog/fm_deemph/fm_deemph_cpu.cc b/blocklib/analog/fm_deemph/fm_deemph_cpu.cc deleted file mode 100644 index b7691333a..000000000 --- a/blocklib/analog/fm_deemph/fm_deemph_cpu.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 FIXME - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "fm_deemph_cpu.h" -#include "fm_deemph_cpu_gen.h" - -#include <gnuradio/filter/iir_filter.h> - -namespace gr { -namespace analog { - -fm_deemph_cpu::fm_deemph_cpu(block_args args) : INHERITED_CONSTRUCTORS -{ - // Digital corner frequency - auto w_c = 1.0 / args.tau; - - // Prewarped analog corner frequency - auto w_ca = 2.0 * args.fs * tanf(w_c / (2.0 * args.fs)); - - // Resulting digital pole, zero, and gain term from the bilinear - // transformation of H(s) = w_ca / (s + w_ca) to - // H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) - auto k = -w_ca / (2.0 * args.fs); - auto z1 = -1.0; - auto p1 = (1.0 + k) / (1.0 - k); - auto b0 = -k / (1.0 - k); - - std::vector<double> btaps{ b0 * 1.0, b0 * -z1 }; - std::vector<double> ataps{ 1.0, -p1 }; - - // Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC - - deemph = filter::iir_filter_ffd::make({ btaps, ataps, false }); - hier_block::connect(self(), 0, deemph, 0); - hier_block::connect(deemph, 0, self(), 0); -} - - -} // namespace analog -} // namespace gr
\ No newline at end of file diff --git a/blocklib/analog/fm_deemph/fm_deemph_cpu.h b/blocklib/analog/fm_deemph/fm_deemph_cpu.h deleted file mode 100644 index c7a14c59a..000000000 --- a/blocklib/analog/fm_deemph/fm_deemph_cpu.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 FIXME - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/analog/fm_deemph.h> -#include <gnuradio/filter/iir_filter.h> - -namespace gr { -namespace analog { - -class fm_deemph_cpu : public virtual fm_deemph -{ -public: - fm_deemph_cpu(block_args args); - -private: - filter::iir_filter_ffd::sptr deemph; -}; - -} // namespace analog -} // namespace gr
\ No newline at end of file diff --git a/blocklib/analog/include/gnuradio/analog/.gitignore b/blocklib/analog/include/gnuradio/analog/.gitignore deleted file mode 100644 index d53050d7d..000000000 --- a/blocklib/analog/include/gnuradio/analog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build diff --git a/blocklib/analog/include/gnuradio/analog/meson.build b/blocklib/analog/include/gnuradio/analog/meson.build deleted file mode 100644 index e69de29bb..000000000 --- a/blocklib/analog/include/gnuradio/analog/meson.build +++ /dev/null diff --git a/blocklib/analog/lib/.gitignore b/blocklib/analog/lib/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/analog/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/analog/lib/meson.build b/blocklib/analog/lib/meson.build deleted file mode 100644 index bbe0f9769..000000000 --- a/blocklib/analog/lib/meson.build +++ /dev/null @@ -1,54 +0,0 @@ -analog_deps += [gnuradio_gr_dep, gr_kernel_math_lib_dep, gr_kernel_analog_lib_dep, gnuradio_blocklib_filter_dep, - volk_dep, fmt_dep, pmtf_dep] - -# analog_sources += 'kernel/agc.cc' -block_cpp_args = ['-DHAVE_CPU', '-DHAVE_HIER'] -# if IMPLEMENT_CUDA -# block_cpp_args += '-DHAVE_CUDA' - -# gnuradio_blocklib_analog_cu = library('gnuradio-blocklib-analog-cu', -# analog_cu_sources, -# include_directories : incdir, -# install : true, -# dependencies : [cuda_dep]) - -# gnuradio_blocklib_analog_cu_dep = declare_dependency(include_directories : incdir, -# link_with : gnuradio_blocklib_analog_cu, -# dependencies : cuda_dep) - -# analog_deps += [gnuradio_blocklib_analog_cu_dep, cuda_dep] - -# endif - -incdir = include_directories(['../include/gnuradio/analog','../include']) -gnuradio_blocklib_analog_lib = library('gnuradio-blocklib-analog', - analog_sources, - include_directories : incdir, - install : true, - link_language: 'cpp', - dependencies : analog_deps, - cpp_args : block_cpp_args) - -gnuradio_blocklib_analog_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_analog_lib, - dependencies : analog_deps) - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'analog') -cmake.configure_package_config_file( - name : 'gnuradio-analog', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_analog_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-analog', - filebase : 'gnuradio-analog', - description : 'GNU Radio Analog Module') diff --git a/blocklib/analog/noise_source/noise_source.yml b/blocklib/analog/noise_source/noise_source.yml deleted file mode 100644 index fabee1abe..000000000 --- a/blocklib/analog/noise_source/noise_source.yml +++ /dev/null @@ -1,45 +0,0 @@ -module: analog -block: noise_source -label: Noise Source -blocktype: sync_block -category: '[Core]/Waveform Generators' -includes: - - gnuradio/analog/enums.h - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - - ri32 - - ri16 - -parameters: -- id: type - label: Type - dtype: enums/noise_t - settable: true - is_enum: true # this should be handled better -- id: amplitude - label: Amplitude - dtype: rf32 - settable: true -- id: seed - label: Seed - dtype: ru64 - settable: false - default: 0 - -# Example Ports -ports: -- domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu -# - id: cuda - -file_format: 1
\ No newline at end of file diff --git a/blocklib/analog/noise_source/noise_source_cpu.cc b/blocklib/analog/noise_source/noise_source_cpu.cc deleted file mode 100644 index 1fecb3b29..000000000 --- a/blocklib/analog/noise_source/noise_source_cpu.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,2012,2018 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "noise_source_cpu.h" -#include "noise_source_cpu_gen.h" - -namespace gr { -namespace analog { - -template <class T> -noise_source_cpu<T>::noise_source_cpu(const typename noise_source<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), d_rng(args.seed) -{ -} - -template <> -noise_source_cpu<gr_complex>::noise_source_cpu( - const typename noise_source<gr_complex>::block_args& args) - : INHERITED_CONSTRUCTORS(gr_complex), d_rng(args.seed) -{ - // param_amplitude gets set in the INHERITED_CONSTRUCTORS from the noise_source - // autogen class but for complex, needs the 1/sqrt(2) factor - *param_amplitude = args.amplitude / sqrtf(2.0f); -} - -template <class T> -work_return_t noise_source_cpu<T>::work(work_io& wio) - -{ - auto out = wio.outputs()[0].items<T>(); - auto noutput_items = wio.outputs()[0].n_items; - - auto type = pmtf::get_as<int>(*this->param_type); - auto ampl = pmtf::get_as<float>(*this->param_amplitude); - - switch (static_cast<noise_t>(type)) { - case noise_t::UNIFORM: - for (size_t i = 0; i < noutput_items; i++) { - out[i] = static_cast<T>(ampl * ((d_rng.ran1() * 2.0) - 1.0)); - } - break; - - case noise_t::GAUSSIAN: - for (size_t i = 0; i < noutput_items; i++) { - out[i] = static_cast<T>(ampl * d_rng.gasdev()); - } - break; - - case noise_t::LAPLACIAN: - for (size_t i = 0; i < noutput_items; i++) { - out[i] = static_cast<T>(ampl * d_rng.laplacian()); - } - break; - - case noise_t::IMPULSE: // FIXME changeable impulse settings - for (size_t i = 0; i < noutput_items; i++) { - out[i] = static_cast<T>(ampl * d_rng.impulse(9)); - } - break; - default: - throw std::runtime_error("invalid type"); - } - - wio.produce_each(noutput_items); - return work_return_t::OK; -} - -} /* namespace analog */ -} /* namespace gr */ diff --git a/blocklib/analog/noise_source/noise_source_cpu.h b/blocklib/analog/noise_source/noise_source_cpu.h deleted file mode 100644 index acff4ff74..000000000 --- a/blocklib/analog/noise_source/noise_source_cpu.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/analog/noise_source.h> -#include <gnuradio/kernel/math/random.h> - -namespace gr { -namespace analog { - -template <class T> -class noise_source_cpu : public noise_source<T> -{ -public: - noise_source_cpu(const typename noise_source<T>::block_args& args); - - work_return_t work(work_io&) override; - -private: - kernel::math::random d_rng; -}; - - -} // namespace analog -} // namespace gr diff --git a/blocklib/analog/python/gnuradio/analog/.gitignore b/blocklib/analog/python/gnuradio/analog/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/analog/python/gnuradio/analog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/analog/python/gnuradio/analog/__init__.py b/blocklib/analog/python/gnuradio/analog/__init__.py deleted file mode 100644 index 3c278fc3a..000000000 --- a/blocklib/analog/python/gnuradio/analog/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ - -import os - -try: - from .analog_python import * -except ImportError: - dirname, filename = os.path.split(os.path.abspath(__file__)) - __path__.append(os.path.join(dirname, "bindings")) - from .analog_python import * - - -# from .fm_deemph_hier import *
\ No newline at end of file diff --git a/blocklib/analog/python/gnuradio/analog/fm_deemph_hier.py b/blocklib/analog/python/gnuradio/analog/fm_deemph_hier.py deleted file mode 100644 index 093110110..000000000 --- a/blocklib/analog/python/gnuradio/analog/fm_deemph_hier.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright 2005,2007,2012 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, filter -import math - - -def fm_deemph_hier(self, fs, tau): - # Digital corner frequency - w_c = 1.0 / tau - - # Prewarped analog corner frequency - w_ca = 2.0 * fs * math.tan(w_c / (2.0 * fs)) - - # Resulting digital pole, zero, and gain term from the bilinear - # transformation of H(s) = w_ca / (s + w_ca) to - # H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) - k = -w_ca / (2.0 * fs) - z1 = -1.0 - p1 = (1.0 + k) / (1.0 - k) - b0 = -k / (1.0 - k) - - btaps = [b0 * 1.0, b0 * -z1] - ataps = [1.0, -p1] - - # Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC - - deemph = filter.iir_filter_ffd(btaps, ataps, False) - self.connect((self, deemph, self)) diff --git a/blocklib/analog/quadrature_demod/quadrature_demod.yml b/blocklib/analog/quadrature_demod/quadrature_demod.yml deleted file mode 100644 index 0b28aa965..000000000 --- a/blocklib/analog/quadrature_demod/quadrature_demod.yml +++ /dev/null @@ -1,57 +0,0 @@ -module: analog -block: quadrature_demod -label: Quadrature Demod -blocktype: block -category: '[Core]/Modulators' - -doc: - brief: "quadrature demodulator: complex in, float out" - detail: |- - This can be used to demod FM, FSK, GMSK, etc. The input is complex - baseband, output is the signal frequency in relation to the sample - rate, multiplied with the gain. - - Mathematically, this block calculates the product of the one-sample - delayed input and the conjugate undelayed signal, and then calculates - the argument of the resulting complex number: - - y[n] = \mathrm{arg}\left(x[n] \, \bar x [n-1]\right). - - Let x be a complex sinusoid with amplitude A>0, (absolute) - frequency f\in\mathbb R and phase \phi_0\in[0;2\pi] sampled at - f_s>0 so, without loss of generality, - - x[n]= A e^{j2\pi( \frac f{f_s} n + \phi_0)}\f - - then - - y[n] = \mathrm{arg}\left(A e^{j2\pi\left( \frac f{f_s} n + \phi_0\right)} \overline{A e^{j2\pi( \frac f{f_s} (n-1) + \phi_0)}}\right)\ = \mathrm{arg}\left(A^2 e^{j2\pi\left( \frac f{f_s} n + \phi_0\right)} e^{-j2\pi( \frac f{f_s} (n-1) + \phi_0)}\right)\ = \mathrm{arg}\left( A^2 e^{j2\pi\left( \frac f{f_s} n + \phi_0 - \frac f{f_s} (n-1) - \phi_0\right)}\right)\ = \mathrm{arg}\left( A^2 e^{j2\pi\left( \frac f{f_s} n - \frac f{f_s} (n-1)\right)}\right)\ = \mathrm{arg}\left( A^2 e^{j2\pi\left( \frac f{f_s} \left(n-(n-1)\right)\right)}\right)\ = \mathrm{arg}\left( A^2 e^{j2\pi \frac f{f_s}}\right) \intertext{$A$ is real, so is $A^2$ and hence only \textit{scales}, therefore $\mathrm{arg}(\cdot)$ is invariant:} = \mathrm{arg}\left(e^{j2\pi \frac f{f_s}}\right)\= \frac f{f_s}\\ - - -# Example Parameters -parameters: -- id: gain - label: Gain - dtype: rf32 - settable: true - grc: - hide: part - default: samp_rate/(2*math.pi*fsk_deviation_hz) - -ports: -- domain: stream - id: in - direction: input - type: cf32 - -- domain: stream - id: out - direction: output - type: rf32 - - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/analog/quadrature_demod/quadrature_demod_cpu.cc b/blocklib/analog/quadrature_demod/quadrature_demod_cpu.cc deleted file mode 100644 index 30f7614b9..000000000 --- a/blocklib/analog/quadrature_demod/quadrature_demod_cpu.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2005,2010,2012 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "quadrature_demod_cpu.h" -#include "quadrature_demod_cpu_gen.h" - -#include <gnuradio/kernel/math/math.h> -#include <volk/volk.h> - -namespace gr { -namespace analog { - -quadrature_demod_cpu::quadrature_demod_cpu(block_args args) : INHERITED_CONSTRUCTORS -{ - // FIXME: do volk alignment -} - -work_return_t quadrature_demod_cpu::work(work_io& wio) -{ - auto in = wio.inputs()[0].items<gr_complex>(); - auto out = wio.outputs()[0].items<float>(); - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - - // because of the history requirement, input needs to be 1 more than what we produce - auto to_produce = std::min(ninput_items - (d_history - 1), noutput_items); - auto gain = pmtf::get_as<float>(*this->param_gain); - - std::vector<gr_complex> tmp(to_produce); - volk_32fc_x2_multiply_conjugate_32fc(&tmp[0], &in[1], &in[0], to_produce); - for (size_t i = 0; i < to_produce; i++) { - out[i] = gain * gr::kernel::math::fast_atan2f(imag(tmp[i]), real(tmp[i])); - } - - wio.produce_each(to_produce); - wio.consume_each(to_produce); - return work_return_t::OK; -} - - -} // namespace analog -} // namespace gr diff --git a/blocklib/analog/quadrature_demod/quadrature_demod_cpu.h b/blocklib/analog/quadrature_demod/quadrature_demod_cpu.h deleted file mode 100644 index ce6c058e2..000000000 --- a/blocklib/analog/quadrature_demod/quadrature_demod_cpu.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2012 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/analog/quadrature_demod.h> - -namespace gr { -namespace analog { - -class quadrature_demod_cpu : public virtual quadrature_demod -{ -public: - quadrature_demod_cpu(block_args args); - work_return_t work(work_io&) override; - -private: - size_t d_history = 2; -}; - -} // namespace analog -} // namespace gr
\ No newline at end of file diff --git a/blocklib/analog/random_source/random_source.yml b/blocklib/analog/random_source/random_source.yml deleted file mode 100644 index 6e592a389..000000000 --- a/blocklib/analog/random_source/random_source.yml +++ /dev/null @@ -1,59 +0,0 @@ -module: analog -block: random_source -label: Random Source -blocktype: grc - -category: '[Core]/Waveform Generators' - -typekeys: - - id: T - type: class - options: - - ri32 - - ri16 - - ri8 - -grc: - flags: [python] - templates: - imports: |- - from gnuradio import blocks - import numpy - make: |- - blocks.vector_source_${T.fcn}(list(map(int, numpy.random.randint(${min}, ${max}, - ${num_samps}))), ${repeat}) - -# Example Parameters -parameters: -- id: min - label: Minimum - dtype: typekeys/T - grc: - default: 0 -- id: max - label: Maximum - dtype: typekeys/T - grc: - default: 2 -- id: num_samps - label: Num Samples - dtype: size - grc: - default: 1000 -- id: repeat - label: Repeat - dtype: bool - grc: - default: true - -# Example Ports -ports: -- domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/analog/sig_source/.gitignore b/blocklib/analog/sig_source/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/analog/sig_source/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/analog/sig_source/sig_source.yml b/blocklib/analog/sig_source/sig_source.yml deleted file mode 100644 index 48252319e..000000000 --- a/blocklib/analog/sig_source/sig_source.yml +++ /dev/null @@ -1,67 +0,0 @@ -module: analog -block: sig_source -label: Signal Source -blocktype: sync_block -category: '[Core]/Waveform Generators' -includes: - - gnuradio/analog/enums.h - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - - ri32 - - ri16 - - ri8 - -parameters: -- id: sampling_freq - label: Sampling Freq - dtype: rf64 - settable: true - grc: - default: samp_rate -- id: waveform - label: Waveform - dtype: enums/waveform_t - is_enum: true - settable: true - grc: - default: analog.waveform.sin -- id: frequency - label: Wave Freq - dtype: rf64 - settable: true - grc: - default: 1000 -- id: ampl - label: Amplitude - dtype: rf64 - settable: true - grc: - default: 1.0 -- id: offset - label: Offset - dtype: T - settable: true - default: 0 -- id: phase - label: Phase - dtype: rf64 - settable: true - default: 0 - -# Example Ports -ports: -- domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu -# - id: cuda - -file_format: 1
\ No newline at end of file diff --git a/blocklib/analog/sig_source/sig_source_cpu.cc b/blocklib/analog/sig_source/sig_source_cpu.cc deleted file mode 100644 index 3510ba021..000000000 --- a/blocklib/analog/sig_source/sig_source_cpu.cc +++ /dev/null @@ -1,215 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "sig_source_cpu.h" -#include "sig_source_cpu_gen.h" - -#include <gnuradio/kernel/math/math.h> -#include <algorithm> - -namespace gr { -namespace analog { - -template <class T> -sig_source_cpu<T>::sig_source_cpu(const typename sig_source<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T) -{ - this->set_frequency(args.frequency); - this->set_phase(args.phase); -} - -template <typename T> -work_return_t sig_source_cpu<T>::work(work_io& wio) -{ - auto optr = wio.outputs()[0].items<T>(); - auto noutput_items = wio.outputs()[0].n_items; - - T t; - std::scoped_lock l(d_mutex); - - auto offset = pmtf::get_as<T>(*this->param_offset); - auto ampl = pmtf::get_as<float>(*this->param_ampl); - auto waveform = static_cast<waveform_t>(pmtf::get_as<int>(*this->param_waveform)); - - switch (waveform) { - case waveform_t::CONSTANT: - t = (T)ampl + offset; - std::fill_n(optr, noutput_items, t); - break; - - case waveform_t::SIN: - d_nco.sin(optr, noutput_items, ampl); - if (offset == 0) - break; - - for (size_t i = 0; i < noutput_items; i++) { - optr[i] += offset; - } - break; - case waveform_t::COS: - d_nco.cos(optr, noutput_items, ampl); - if (offset == 0) - break; - - for (size_t i = 0; i < noutput_items; i++) { - optr[i] += offset; - } - break; - - /* The square wave is high from -PI to 0. */ - case waveform_t::SQUARE: - t = (T)ampl + offset; - for (size_t i = 0; i < noutput_items; i++) { - if (d_nco.get_phase() < 0) - optr[i] = t; - else - optr[i] = offset; - d_nco.step(); - } - break; - - /* The triangle wave rises from -PI to 0 and falls from 0 to PI. */ - case waveform_t::TRIANGLE: - for (size_t i = 0; i < noutput_items; i++) { - double t = ampl * d_nco.get_phase() / GR_M_PI; - if (d_nco.get_phase() < 0) - optr[i] = static_cast<T>(t + ampl + offset); - else - optr[i] = static_cast<T>(-1 * t + ampl + offset); - d_nco.step(); - } - break; - - /* The saw tooth wave rises from -PI to PI. */ - case waveform_t::SAWTOOTH: - for (size_t i = 0; i < noutput_items; i++) { - t = static_cast<T>(ampl * d_nco.get_phase() / (2 * GR_M_PI) + ampl / 2 + - offset); - optr[i] = t; - d_nco.step(); - } - break; - default: - throw std::runtime_error("analog::sig_source: invalid waveform"); - } - - wio.produce_each(noutput_items); - return work_return_t::OK; -} - -template <> -work_return_t sig_source_cpu<gr_complex>::work(work_io& wio) - -{ - auto optr = wio.outputs()[0].items<gr_complex>(); - auto noutput_items = wio.outputs()[0].n_items; - - gr_complex t; - std::scoped_lock l(d_mutex); - - auto offset = pmtf::get_as<gr_complex>(*this->param_offset); - auto ampl = pmtf::get_as<float>(*this->param_ampl); - auto waveform = static_cast<waveform_t>(pmtf::get_as<int>(*this->param_waveform)); - - switch (waveform) { - case waveform_t::CONSTANT: - t = (gr_complex)ampl + offset; - std::fill_n(optr, noutput_items, t); - break; - - case waveform_t::SIN: - case waveform_t::COS: - d_nco.sincos(optr, noutput_items, ampl); - if (offset == gr_complex(0, 0)) - break; - - for (size_t i = 0; i < noutput_items; i++) { - optr[i] += offset; - } - break; - - /* Implements a real square wave high from -PI to 0. - * The imaginary square wave leads by 90 deg. - */ - case waveform_t::SQUARE: - for (size_t i = 0; i < noutput_items; i++) { - if (d_nco.get_phase() < -1 * GR_M_PI / 2) - optr[i] = gr_complex(ampl, 0) + offset; - else if (d_nco.get_phase() < 0) - optr[i] = gr_complex(ampl, ampl) + offset; - else if (d_nco.get_phase() < GR_M_PI / 2) - optr[i] = gr_complex(0, ampl) + offset; - else - optr[i] = offset; - d_nco.step(); - } - break; - - /* Implements a real triangle wave rising from -PI to 0 and - * falling from 0 to PI. The imaginary triangle wave leads by - * 90 deg. - */ - case waveform_t::TRIANGLE: - for (size_t i = 0; i < noutput_items; i++) { - if (d_nco.get_phase() < -1 * GR_M_PI / 2) { - optr[i] = gr_complex(ampl * d_nco.get_phase() / GR_M_PI + ampl, - -1 * ampl * d_nco.get_phase() / GR_M_PI - ampl / 2) + - offset; - } - else if (d_nco.get_phase() < 0) { - optr[i] = gr_complex(ampl * d_nco.get_phase() / GR_M_PI + ampl, - ampl * d_nco.get_phase() / GR_M_PI + ampl / 2) + - offset; - } - else if (d_nco.get_phase() < GR_M_PI / 2) { - optr[i] = gr_complex(-1 * ampl * d_nco.get_phase() / GR_M_PI + ampl, - ampl * d_nco.get_phase() / GR_M_PI + ampl / 2) + - offset; - } - else { - optr[i] = - gr_complex(-1 * ampl * d_nco.get_phase() / GR_M_PI + ampl, - -1 * ampl * d_nco.get_phase() / GR_M_PI + 3 * ampl / 2) + - offset; - } - d_nco.step(); - } - break; - - /* Implements a real saw tooth wave rising from -PI to PI. - * The imaginary saw tooth wave leads by 90 deg. - */ - case waveform_t::SAWTOOTH: - for (size_t i = 0; i < noutput_items; i++) { - if (d_nco.get_phase() < -1 * GR_M_PI / 2) { - optr[i] = - gr_complex(ampl * d_nco.get_phase() / (2 * GR_M_PI) + ampl / 2, - ampl * d_nco.get_phase() / (2 * GR_M_PI) + 5 * ampl / 4) + - offset; - } - else { - optr[i] = - gr_complex(ampl * d_nco.get_phase() / (2 * GR_M_PI) + ampl / 2, - ampl * d_nco.get_phase() / (2 * GR_M_PI) + ampl / 4) + - offset; - } - d_nco.step(); - } - break; - default: - throw std::runtime_error("analog::sig_source: invalid waveform"); - } - - wio.produce_each(noutput_items); - return work_return_t::OK; -} - -} /* namespace analog */ -} /* namespace gr */ diff --git a/blocklib/analog/sig_source/sig_source_cpu.h b/blocklib/analog/sig_source/sig_source_cpu.h deleted file mode 100644 index a950c6094..000000000 --- a/blocklib/analog/sig_source/sig_source_cpu.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/analog/sig_source.h> -#include <gnuradio/kernel/math/fxpt_nco.h> -#include <gnuradio/kernel/math/math.h> -#include <mutex> - -namespace gr { -namespace analog { - -template <class T> -class sig_source_cpu : public sig_source<T> -{ -public: - sig_source_cpu(const typename sig_source<T>::block_args& args); - - work_return_t work(work_io&) override; - - - void on_parameter_change(param_action_sptr action) override - { - // This will set the underlying PMT - block::on_parameter_change(action); - - // Do more updating for certain parameters - if (action->id() == sig_source<T>::id_phase) { - auto phase = pmtf::get_as<double>(*this->param_phase); - d_nco.set_phase(phase); - } - else if (action->id() == sig_source<T>::id_frequency) { - auto freq = pmtf::get_as<double>(*this->param_frequency); - auto samp_freq = pmtf::get_as<double>(*this->param_sampling_freq); - d_nco.set_freq(2 * GR_M_PI * freq / samp_freq); - } - } - - -private: - // Declare private variables here - gr::kernel::math::fxpt_nco d_nco; - - // sig_source has some non thread safe accessors (for now) - std::mutex d_mutex; -}; - - -} // namespace analog -} // namespace gr diff --git a/blocklib/analog/test/.gitignore b/blocklib/analog/test/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/analog/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/analog/test/meson.build b/blocklib/analog/test/meson.build deleted file mode 100644 index 8c3ed151a..000000000 --- a/blocklib/analog/test/meson.build +++ /dev/null @@ -1,9 +0,0 @@ -################################################### -# QA -################################################### - -if GR_ENABLE_PYTHON - test('qa_sig_source', find_program('qa_sig_source.py'), env: TEST_ENV) - test('qa_noise', find_program('qa_noise.py'), env: TEST_ENV) - test('qa_quadrature_demod', find_program('qa_quadrature_demod.py'), env: TEST_ENV) -endif diff --git a/blocklib/analog/test/qa_agc.py b/blocklib/analog/test/qa_agc.py deleted file mode 100644 index 7e3a08286..000000000 --- a/blocklib/analog/test/qa_agc.py +++ /dev/null @@ -1,497 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2004,2007,2010,2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, analog, blocks - - -class test_agc(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.flowgraph() - - def tearDown(self): - self.tb = None - - def test_001_sets(self): - agc = analog.agc_cc(1e-3, 1, 1) - - agc.set_rate(1) - agc.set_reference(1.1) - agc.set_gain(1.1) - agc.set_max_gain(100) - - self.assertAlmostEqual(agc.rate(), 1) - self.assertAlmostEqual(agc.reference(), 1.1) - self.assertAlmostEqual(agc.gain(), 1.1) - self.assertAlmostEqual(agc.max_gain(), 100) - - def test_001(self): - ''' Test the complex AGC loop (single rate input) ''' - tb = self.tb - - expected_result = ( - (100 + 0j), - (72.89209747314453 + 52.9592170715332j), - (25.089027404785156 + 77.2160873413086j), - (-22.611034393310547 + 69.58960723876953j), - (-53.35764694213867 + 38.766597747802734j), - (-59.4586067199707 - 2.7399494229030097e-06j), - (-43.3734245300293 - 31.51263999938965j), - (-14.941386222839355 - 45.984867095947266j), - (13.478157997131348 - 41.48149490356445j), - (31.838510513305664 - 23.13202476501465j), - (35.51927947998047 + 3.3255341804760974e-06j), - (25.94291114807129 + 18.848634719848633j), - (8.949296951293945 + 27.543113708496094j), - (-8.085277557373047 + 24.883914947509766j), - (-19.13165283203125 + 13.899954795837402j), - (-21.383323669433594 - 2.987417019539862e-06j), - (-15.65035343170166 - 11.370650291442871j), - (-5.4110236167907715 - 16.653427124023438j), - (4.900828838348389 - 15.083191871643066j), - (11.62836742401123 - 8.448498725891113j), - (13.036169052124023 + 2.4410530841123546e-06j), - (9.572690963745117 + 6.954970359802246j), - (3.3217051029205322 + 10.223164558410645j), - (-3.0204410552978516 + 9.295955657958984j), - (-7.197745323181152 + 5.229465007781982j), - (-8.107251167297363 - 1.8916969111160142e-06j), - (-5.983887195587158 - 4.347550392150879j), - (-2.087981939315796 - 6.426152229309082j), - (1.9100888967514038 - 5.87864351272583j), - (4.581503391265869 - 3.3286550045013428j), - (5.196768760681152 + 1.4596606661143596e-06j), - (3.864729881286621 + 2.807892322540283j), - (1.359479308128357 + 4.184051513671875j), - (-1.2544355392456055 + 3.8607518672943115j), - (-3.036635398864746 + 2.2062432765960693j), - (-3.4781548976898193 - 1.137218077928992e-06j), - (-2.613386869430542 - 1.8987380266189575j), - (-0.9293051958084106 - 2.8601105213165283j), - (0.8672783374786377 - 2.6692051887512207j), - (2.1244049072265625 - 1.5434693098068237j), - (2.463329315185547 + 9.225283861269418e-07j), - (1.8744803667068481 + 1.3618910312652588j), - (0.6752913594245911 + 2.078335762023926j), - (-0.6386655569076538 + 1.9656078815460205j), - (-1.5857415199279785 + 1.1521075963974j), - (-1.864084243774414 - 7.840082503207668e-07j), - (-1.438162922859192 - 1.0448874235153198j), - (-0.5252984762191772 - 1.6167048215866089j), - (0.5036717653274536 - 1.5501397848129272j), - (1.2676655054092407 - 0.9210119843482971j)) - - sampling_freq = 100 - src1 = analog.sig_source_c(sampling_freq, analog.GR_SIN_WAVE, - sampling_freq * 0.10, 100.0) - dst1 = blocks.vector_sink_c() - head = streamops.head(gr.sizeof_gr_complex, int(5 * sampling_freq * 0.10)) - - agc = analog.agc_cc(1e-3, 1, 1) - - tb.connect(src1, head) - tb.connect(head, agc) - tb.connect(agc, dst1) - - tb.run() - dst_data = dst1.data() - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_002_sets(self): - agc = analog.agc_ff(1e-3, 1, 1) - - agc.set_rate(1) - agc.set_reference(1.1) - agc.set_gain(1.1) - agc.set_max_gain(100) - - self.assertAlmostEqual(agc.rate(), 1) - self.assertAlmostEqual(agc.reference(), 1.1) - self.assertAlmostEqual(agc.gain(), 1.1) - self.assertAlmostEqual(agc.max_gain(), 100) - - def test_002(self): - ''' Test the floating point AGC loop (single rate input) ''' - tb = self.tb - - expected_result = ( - 0.0, - 58.83704376220703, - 89.69985961914062, - 81.26403045654297, - 45.50606918334961, - -3.3625440210016677e-06, - -42.9488639831543, - -65.50326538085938, - -59.368656158447266, - -33.26097869873047, - 4.995997642254224e-06, - 31.423521041870117, - 47.950958251953125, - 43.48566436767578, - 24.37834358215332, - -5.4677821026416495e-06, - -23.06298828125, - -35.21844482421875, - -31.964082717895508, - -17.93484115600586, - 5.396469077822985e-06, - 16.998228073120117, - 25.982229232788086, - 23.60628318786621, - 13.260700225830078, - -4.97806149724056e-06, - -12.598825454711914, - -19.282241821289062, - -17.543500900268555, - -9.870061874389648, - 4.467380676942412e-06, - 9.407480239868164, - 14.422045707702637, - 13.14553451538086, - 7.410478591918945, - -3.91256025977782e-06, - -7.092466354370117, - -10.896439552307129, - -9.955231666564941, - -5.62628698348999, - 3.411524403418298e-06, - 5.413146018981934, - 8.338950157165527, - 7.640974521636963, - 4.332027435302734, - -2.95963241114805e-06, - -4.19495964050293, - -6.483736991882324, - -5.962202072143555, - -3.3931667804718018) - - sampling_freq = 100 - src1 = analog.sig_source_f(sampling_freq, analog.GR_SIN_WAVE, - sampling_freq * 0.10, 100.0) - dst1 = blocks.vector_sink_f() - head = streamops.head(gr.sizeof_float, int(5 * sampling_freq * 0.10)) - - agc = analog.agc_ff(1e-3, 1, 1) - - tb.connect(src1, head) - tb.connect(head, agc) - tb.connect(agc, dst1) - - tb.run() - dst_data = dst1.data() - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_003_sets(self): - agc = analog.agc2_cc(1e-3, 1e-1, 1, 1) - - agc.set_attack_rate(1) - agc.set_decay_rate(2) - agc.set_reference(1.1) - agc.set_gain(1.1) - agc.set_max_gain(100) - - self.assertAlmostEqual(agc.attack_rate(), 1) - self.assertAlmostEqual(agc.decay_rate(), 2) - self.assertAlmostEqual(agc.reference(), 1.1) - self.assertAlmostEqual(agc.gain(), 1.1) - self.assertAlmostEqual(agc.max_gain(), 100) - - def test_003(self): - ''' Test the complex AGC loop (attack and decay rate inputs) ''' - tb = self.tb - - expected_result = \ - ((100 + 0j), - (0.8090173602104187 + 0.5877856016159058j), - (0.3090175688266754 + 0.9510582685470581j), - (-0.309017539024353 + 0.9510582089424133j), - (-0.8090170621871948 + 0.5877852439880371j), - (-1.000004529953003 - 4.608183701293456e-08j), - (-0.8090165853500366 - 0.587785005569458j), - (-0.3090173006057739 - 0.9510576725006104j), - (0.3090173900127411 - 0.951057493686676j), - (0.8090166449546814 - 0.5877848863601685j), - (1.0000040531158447 + 9.362654651567937e-08j), - (0.809016227722168 + 0.5877848267555237j), - (0.3090171217918396 + 0.9510573148727417j), - (-0.3090173006057739 + 0.9510571360588074j), - (-0.8090163469314575 + 0.5877846479415894j), - (-1.000003695487976 - 1.39708305368913e-07j), - (-0.8090159296989441 - 0.5877846479415894j), - (-0.30901697278022766 - 0.951056957244873j), - (0.30901727080345154 - 0.9510568976402283j), - (0.809016227722168 - 0.5877844095230103j), - (1.000003457069397 + 1.87252979344521e-07j), - (0.809015691280365 + 0.5877845287322998j), - (0.3090168535709381 + 0.9510567784309387j), - (-0.30901727080345154 + 0.951056718826294j), - (-0.8090161085128784 + 0.5877842903137207j), - (-1.0000033378601074 - 2.3333473109232727e-07j), - (-0.8090156316757202 - 0.5877845287322998j), - (-0.3090168237686157 - 0.9510566592216492j), - (0.3090173006057739 - 0.9510565400123596j), - (0.8090160489082336 - 0.5877842307090759j), - (1.0000032186508179 + 2.8087941927879e-07j), - (0.8090155124664307 + 0.5877845287322998j), - (0.30901676416397095 + 0.9510567784309387j), - (-0.3090173006057739 + 0.9510565400123596j), - (-0.8090160489082336 + 0.5877841711044312j), - (-1.0000033378601074 - 3.2696124208086985e-07j), - (-0.8090155124664307 - 0.5877845883369446j), - (-0.30901673436164856 - 0.9510567784309387j), - (0.3090173602104187 - 0.9510565400123596j), - (0.8090160489082336 - 0.5877841114997864j), - (1.0000033378601074 + 3.745059302673326e-07j), - (0.8090154528617859 + 0.5877846479415894j), - (0.3090166747570038 + 0.9510567784309387j), - (-0.3090174198150635 + 0.9510565400123596j), - (-0.8090161681175232 + 0.5877841114997864j), - (-1.0000032186508179 - 4.2058766780428414e-07j), - (-0.8090154528617859 - 0.5877846479415894j), - (-0.309016615152359 - 0.9510567784309387j), - (0.30901747941970825 - 0.9510564804077148j), - (0.8090161681175232 - 0.5877840518951416j)) - - sampling_freq = 100 - src1 = analog.sig_source_c(sampling_freq, analog.GR_SIN_WAVE, - sampling_freq * 0.10, 100) - dst1 = blocks.vector_sink_c() - head = streamops.head(gr.sizeof_gr_complex, int(5 * sampling_freq * 0.10)) - - agc = analog.agc2_cc(1e-2, 1e-3, 1, 1) - - tb.connect(src1, head) - tb.connect(head, agc) - tb.connect(agc, dst1) - - tb.run() - dst_data = dst1.data() - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_004_sets(self): - agc = analog.agc2_ff(1e-3, 1e-1, 1, 1) - - agc.set_attack_rate(1) - agc.set_decay_rate(2) - agc.set_reference(1.1) - agc.set_gain(1.1) - agc.set_max_gain(100) - - self.assertAlmostEqual(agc.attack_rate(), 1) - self.assertAlmostEqual(agc.decay_rate(), 2) - self.assertAlmostEqual(agc.reference(), 1.1) - self.assertAlmostEqual(agc.gain(), 1.1) - self.assertAlmostEqual(agc.max_gain(), 100) - - def test_004(self): - ''' Test the floating point AGC loop (attack and decay rate inputs) ''' - tb = self.tb - - expected_result = \ - (0.0, - 58.83704376220703, - 40.194339752197266, - 2.9184224605560303, - 0.6760660409927368, - -6.79303795436681e-08, - -1.4542515277862549, - -1.9210143089294434, - -1.0450801849365234, - -0.6193966865539551, - 1.3429632872430375e-07, - 1.4308913946151733, - 1.9054334163665771, - 1.044317603111267, - 0.619373619556427, - -2.003930177352231e-07, - -1.4308818578720093, - -1.905427098274231, - -1.0443172454833984, - -0.6193735599517822, - 2.6858961632569844e-07, - 1.4308820962905884, - 1.9054267406463623, - 1.0443172454833984, - 0.6193734407424927, - -3.3468785431978176e-07, - -1.4308820962905884, - -1.9054267406463623, - -1.0443171262741089, - -0.6193735599517822, - 4.0288449554282124e-07, - 1.430882215499878, - 1.905427098274231, - 1.0443170070648193, - 0.6193734407424927, - -4.689827903803234e-07, - -1.430882453918457, - -1.9054268598556519, - -1.0443170070648193, - -0.6193733811378479, - 5.371793463382346e-07, - 1.4308825731277466, - 1.9054265022277832, - 1.0443170070648193, - 0.6193733811378479, - -6.032776127540274e-07, - -1.4308825731277466, - -1.9054265022277832, - -1.0443168878555298, - -0.6193733811378479) - - sampling_freq = 100 - src1 = analog.sig_source_f(sampling_freq, analog.GR_SIN_WAVE, - sampling_freq * 0.10, 100) - dst1 = blocks.vector_sink_f() - head = streamops.head(gr.sizeof_float, int(5 * sampling_freq * 0.10)) - - agc = analog.agc2_ff(1e-2, 1e-3, 1, 1) - - tb.connect(src1, head) - tb.connect(head, agc) - tb.connect(agc, dst1) - - tb.run() - dst_data = dst1.data() - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_005(self): - ''' Test the complex AGC loop (attack and decay rate inputs) ''' - tb = self.tb - - expected_result = \ - ((100+0j), - (0.8090173602104187 + 0.5877856016159058j), - (0.3090175688266754 + 0.9510582685470581j), - (-0.309017539024353 + 0.9510582089424133j), - (-0.8090170621871948 + 0.5877852439880371j), - (-1.000004529953003 - 4.608183701293456e-08j), - (-0.8090165853500366 - 0.587785005569458j), - (-0.3090173006057739 - 0.9510576725006104j), - (0.3090173900127411 - 0.951057493686676j), - (0.8090166449546814 - 0.5877848863601685j), - (1.0000040531158447 + 9.362654651567937e-08j), - (0.809016227722168 + 0.5877848267555237j), - (0.3090171217918396 + 0.9510573148727417j), - (-0.3090173006057739 + 0.9510571360588074j), - (-0.8090163469314575 + 0.5877846479415894j), - (-1.000003695487976 - 1.39708305368913e-07j), - (-0.8090159296989441 - 0.5877846479415894j), - (-0.30901697278022766 - 0.951056957244873j), - (0.30901727080345154 - 0.9510568976402283j), - (0.809016227722168 - 0.5877844095230103j), - (1.000003457069397 + 1.87252979344521e-07j), - (0.809015691280365 + 0.5877845287322998j), - (0.3090168535709381 + 0.9510567784309387j), - (-0.30901727080345154 + 0.951056718826294j), - (-0.8090161085128784 + 0.5877842903137207j), - (-1.0000033378601074 - 2.3333473109232727e-07j), - (-0.8090156316757202 - 0.5877845287322998j), - (-0.3090168237686157 - 0.9510566592216492j), - (0.3090173006057739 - 0.9510565400123596j), - (0.8090160489082336 - 0.5877842307090759j), - (1.0000032186508179 + 2.8087941927879e-07j), - (0.8090155124664307 + 0.5877845287322998j), - (0.30901676416397095 + 0.9510567784309387j), - (-0.3090173006057739 + 0.9510565400123596j), - (-0.8090160489082336 + 0.5877841711044312j), - (-1.0000033378601074 - 3.2696124208086985e-07j), - (-0.8090155124664307 - 0.5877845883369446j), - (-0.30901673436164856 - 0.9510567784309387j), - (0.3090173602104187 - 0.9510565400123596j), - (0.8090160489082336 - 0.5877841114997864j), - (1.0000033378601074 + 3.745059302673326e-07j), - (0.8090154528617859 + 0.5877846479415894j), - (0.3090166747570038 + 0.9510567784309387j), - (-0.3090174198150635 + 0.9510565400123596j), - (-0.8090161681175232 + 0.5877841114997864j), - (-1.0000032186508179 - 4.2058766780428414e-07j), - (-0.8090154528617859 - 0.5877846479415894j), - (-0.309016615152359 - 0.9510567784309387j), - (0.30901747941970825 - 0.9510564804077148j), - (0.8090161681175232 - 0.5877840518951416j)) - - sampling_freq = 100 - src1 = analog.sig_source_c(sampling_freq, analog.GR_SIN_WAVE, - sampling_freq * 0.10, 100) - dst1 = blocks.vector_sink_c() - head = streamops.head(gr.sizeof_gr_complex, int(5 * sampling_freq * 0.10)) - - agc = analog.agc2_cc(1e-2, 1e-3, 1, 1) - - tb.connect(src1, head) - tb.connect(head, agc) - tb.connect(agc, dst1) - - tb.run() - dst_data = dst1.data() - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_006_sets(self): - agc = analog.agc3_cc(1e-3, 1e-1, 1) - - agc.set_attack_rate(1) - agc.set_decay_rate(2) - agc.set_reference(1.1) - agc.set_gain(1.1) - - self.assertAlmostEqual(agc.attack_rate(), 1) - self.assertAlmostEqual(agc.decay_rate(), 2) - self.assertAlmostEqual(agc.reference(), 1.1) - self.assertAlmostEqual(agc.gain(), 1.1) - - def test_006(self): - ''' Test the complex AGC loop (attack and decay rate inputs) ''' - tb = self.tb - - sampling_freq = 100 - N = int(5 * sampling_freq) - src1 = analog.sig_source_c(sampling_freq, analog.GR_SIN_WAVE, - sampling_freq * 0.10, 100) - dst1 = blocks.vector_sink_c() - head = streamops.head(gr.sizeof_gr_complex, N) - - ref = 1 - agc = analog.agc3_cc(1e-2, 1e-3, ref) - - tb.connect(src1, head) - tb.connect(head, agc) - tb.connect(agc, dst1) - - tb.run() - dst_data = dst1.data() - M = 100 - result = [abs(x) for x in dst_data[N - M:]] - self.assertFloatTuplesAlmostEqual(result, M * [ref, ], 4) - - def test_100(self): - ''' Test complex feedforward agc with constant input ''' - - length = 8 - gain = 2 - - input_data = 8 * (0.0,) + 24 * (1.0,) + 24 * (0.0,) - expected_result = (8 + length - 1) * (0.0,) + 24 * (gain * 1.0,) + (0,) - - src = blocks.vector_source_c(input_data) - agc = analog.feedforward_agc_cc(8, 2.0) - dst = blocks.vector_sink_c() - self.tb.connect(src, agc, dst) - - self.tb.run() - dst_data = dst.data()[0:len(expected_result)] - - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 4) - - -if __name__ == '__main__': - gr_unittest.run(test_agc) diff --git a/blocklib/analog/test/qa_noise.py b/blocklib/analog/test/qa_noise.py deleted file mode 100644 index 282656a99..000000000 --- a/blocklib/analog/test/qa_noise.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2007,2010,2012 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, analog - - -class test_noise_source(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_001(self): - # Just confirm that we can instantiate a noise source - op = analog.noise_source_f(analog.noise_t.GAUSSIAN, 10, 10) - - def test_002(self): - # Test get methods - set_type = analog.noise_t.GAUSSIAN - set_ampl = 10 - op = analog.noise_source_f(set_type, set_ampl, 10) - get_type = op.type() - get_ampl = op.amplitude() - - self.assertEqual(get_type, set_type) - self.assertEqual(get_ampl, set_ampl) - - -if __name__ == '__main__': - gr_unittest.run(test_noise_source) diff --git a/blocklib/analog/test/qa_quadrature_demod.py b/blocklib/analog/test/qa_quadrature_demod.py deleted file mode 100644 index f8b955014..000000000 --- a/blocklib/analog/test/qa_quadrature_demod.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -import cmath - -from gnuradio import gr, gr_unittest, analog, blocks - - -class test_quadrature_demod(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_quad_demod_001(self): - f = 1000.0 - fs = 8000.0 - - src_data = [] - for i in range(200): - ti = i / fs - src_data.append(cmath.exp(2j * cmath.pi * f * ti)) - - src_data = [0, ] + src_data # to account for history - - # f/fs is a quarter turn per sample. - # Set the gain based on this to get 1 out. - gain = 1.0 / (cmath.pi / 4) - - expected_result = [0, ] + 199 * [1.0] - - src = blocks.vector_source_c(src_data) - op = analog.quadrature_demod(gain) - dst = blocks.vector_sink_f() - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_result, result_data, 5) - - -if __name__ == '__main__': - gr_unittest.run(test_quadrature_demod) diff --git a/blocklib/analog/test/qa_sig_source.py b/blocklib/analog/test/qa_sig_source.py deleted file mode 100644 index 45e479889..000000000 --- a/blocklib/analog/test/qa_sig_source.py +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2004, 2007, 2010, 2012, 2013, 2020 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -import math -# import pmt -from gnuradio import gr, gr_unittest, analog, blocks, streamops - - -class test_sig_source(gr_unittest.TestCase): - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_const_f(self): - tb = self.tb - expected_result = [1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5] - src1 = analog.sig_source_f(1e6, analog.waveform_t.CONSTANT, 0, 1.5) - op = streamops.head(10) - dst1 = blocks.vector_sink_f() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertEqual(expected_result, dst_data) - - def test_const_i(self): - tb = self.tb - expected_result = [1, 1, 1, 1] - src1 = analog.sig_source_i(1e6, analog.waveform_t.CONSTANT, 0, 1) - op = streamops.head(4) - dst1 = blocks.vector_sink_i() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertEqual(expected_result, dst_data) - - def test_const_b(self): - tb = self.tb - expected_result = [1, 1, 1, 1] - src1 = analog.sig_source_b(1e6, analog.waveform_t.CONSTANT, 0, 1) - op = streamops.head(4) - dst1 = blocks.vector_sink_b() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertEqual(expected_result, dst_data) - - def test_sine_f(self): - tb = self.tb - sqrt2 = math.sqrt(2) / 2 - expected_result = [0, sqrt2, 1, sqrt2, 0, -sqrt2, -1, -sqrt2, 0] - src1 = analog.sig_source_f(8, analog.waveform_t.SIN, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_f() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 5) - - def test_sine_b(self): - tb = self.tb - sqrt2 = math.sqrt(2) / 2 - temp_result = [0, sqrt2, 1, sqrt2, 0, -sqrt2, -1, -sqrt2, 0] - amp = 8 - expected_result = tuple([int(z * amp) for z in temp_result]) - src1 = analog.sig_source_b(8, analog.waveform_t.SIN, 1.0, amp) - op = streamops.head(9) - dst1 = blocks.vector_sink_b() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - # Let the python know we are dealing with signed int behind scenes - dst_data_signed = [b if b < 127 else (256 - b) * -1 for b in dst_data] - self.assertFloatTuplesAlmostEqual(expected_result, dst_data_signed) - - def test_cosine_f(self): - tb = self.tb - sqrt2 = math.sqrt(2) / 2 - expected_result = [1, sqrt2, 0, -sqrt2, -1, -sqrt2, 0, sqrt2, 1] - src1 = analog.sig_source_f(8, analog.waveform_t.COS, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_f() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 5) - - def test_cosine_c(self): - tb = self.tb - sqrt2 = math.sqrt(2) / 2 - sqrt2j = 1j * math.sqrt(2) / 2 - expected_result = [ - 1, sqrt2 + sqrt2j, 1j, -sqrt2 + sqrt2j, -1, -sqrt2 - sqrt2j, -1j, - sqrt2 - sqrt2j, 1 - ] - src1 = analog.sig_source_c(8, analog.waveform_t.COS, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_c() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 5) - - def test_sqr_c(self): - tb = self.tb # arg6 is a bit before -PI/2 - expected_result = [1j, 1j, 0, 0, 1, 1, 1 + 0j, 1 + 1j, 1j] - src1 = analog.sig_source_c(8, analog.waveform_t.SQUARE, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_c() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertEqual(expected_result, dst_data) - - def test_tri_c(self): - tb = self.tb - expected_result = [ - 1 + .5j, .75 + .75j, .5 + 1j, .25 + .75j, 0 + .5j, .25 + .25j, - .5 + 0j, .75 + .25j, 1 + .5j - ] - src1 = analog.sig_source_c(8, analog.waveform_t.TRIANGLE, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_c() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 5) - - def test_saw_c(self): - tb = self.tb - expected_result = [ - .5 + .25j, .625 + .375j, .75 + .5j, .875 + .625j, 0 + .75j, - .125 + .875j, .25 + 1j, .375 + .125j, .5 + .25j - ] - src1 = analog.sig_source_c(8, analog.waveform_t.SAWTOOTH, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_c() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 5) - - def test_sqr_f(self): - tb = self.tb - expected_result = [0, 0, 0, 0, 1, 1, 1, 1, 0] - src1 = analog.sig_source_f(8, analog.waveform_t.SQUARE, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_f() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertEqual(expected_result, dst_data) - - def test_tri_f(self): - tb = self.tb - expected_result = [1, .75, .5, .25, 0, .25, .5, .75, 1] - src1 = analog.sig_source_f(8, analog.waveform_t.TRIANGLE, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_f() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 5) - - def test_saw_f(self): - tb = self.tb - expected_result = [.5, .625, .75, .875, 0, .125, .25, .375, .5] - src1 = analog.sig_source_f(8, analog.waveform_t.SAWTOOTH, 1.0, 1.0) - op = streamops.head(9) - dst1 = blocks.vector_sink_f() - tb.connect(src1, op) - tb.connect(op, dst1) - tb.run() - dst_data = dst1.data() - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 5) - - # def test_cmd_msg(self): - # src = analog.sig_source_c(8, analog.GR_SIN_WAVE, 1.0, 1.0) - # op = streamops.head(gr.sizeof_gr_complex, 9) - # snk = blocks.vector_sink_c() - # self.tb.connect(src, op, snk) - # self.assertAlmostEqual(src.frequency(), 1.0) - - # frequency = 3.0 - # amplitude = 10 - # offset = -1.0 - - # src._post( - # pmt.to_pmt('cmd'), - # pmt.to_pmt({ - # "freq": frequency, - # "ampl": amplitude, - # "offset": offset - # })) - # self.tb.run() - - # self.assertAlmostEqual(src.frequency(), frequency) - # self.assertAlmostEqual(src.amplitude(), amplitude) - # self.assertAlmostEqual(src.offset(), offset) - - -if __name__ == '__main__': - gr_unittest.run(test_sig_source) diff --git a/blocklib/audio/.gitignore b/blocklib/audio/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/audio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/audio/alsa_sink/alsa_sink.yml b/blocklib/audio/alsa_sink/alsa_sink.yml deleted file mode 100644 index 009b0c9b1..000000000 --- a/blocklib/audio/alsa_sink/alsa_sink.yml +++ /dev/null @@ -1,49 +0,0 @@ -module: audio -block: alsa_sink -label: ALSA Sink -blocktype: sync_block -category: '[Core]/Audio' - -# Example Parameters -parameters: -- id: sampling_rate - label: Sampling Rate - dtype: ru32 - settable: false - default: 0 - grc: - hide: part -- id: device_name - label: Device Name - dtype: string - settable: false - grc: - hide: part -- id: num_inputs - label: Num Inputs - dtype: size - settable: false - default: 1 - grc: - hide: part -- id: ok_to_block - label: OK to Block - dtype: bool - settable: false - default: 'true' - grc: - hide: part - -# Example Ports -ports: -- domain: stream - id: in - direction: input - type: rf32 - multiplicity: parameters/num_inputs - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/audio/alsa_sink/alsa_sink_cpu.cc b/blocklib/audio/alsa_sink/alsa_sink_cpu.cc deleted file mode 100644 index e396c4e0e..000000000 --- a/blocklib/audio/alsa_sink/alsa_sink_cpu.cc +++ /dev/null @@ -1,521 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "alsa_sink_cpu.h" -#include "alsa_sink_cpu_gen.h" - -#include <chrono> -#include <future> -#include <thread> - -#include <gnuradio/prefs.h> - -namespace gr { -namespace audio { - - -static bool CHATTY_DEBUG = true; - -static snd_pcm_format_t acceptable_formats[] = { - // these are in our preferred order... - SND_PCM_FORMAT_S32, - SND_PCM_FORMAT_S16 -}; - -#define NELEMS(x) (sizeof(x) / sizeof(x[0])) - -static std::string default_device_name() -{ - return prefs::get_string("audio_alsa", "default_output_device", "default"); -} - -static double default_period_time() -{ - return std::max(0.001, prefs::get_double("audio_alsa", "period_time", 0.010)); -} - -static int default_nperiods() -{ - return std::max(2L, prefs::get_long("audio_alsa", "nperiods", 32)); -} - - -alsa_sink_cpu::alsa_sink_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - d_sampling_rate(args.sampling_rate), - d_device_name(args.device_name.empty() ? default_device_name() : args.device_name), - d_nperiods(default_nperiods()), - d_period_time_us((size_t)(default_period_time() * 1e6)), - d_special_case_mono_to_stereo(false), - d_ok_to_block(args.ok_to_block), - d_num_inputs(args.num_inputs) -{ - CHATTY_DEBUG = prefs::get_bool("audio_alsa", "verbose", false); - - int error = -1; - int dir; - - // open the device for playback - int attempts = 10; - while ((error != 0) && (attempts-- > 0)) { - snd_pcm_t* t = nullptr; - error = snd_pcm_open(&t, d_device_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0); - d_pcm_handle.set(t); - if (error < 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - } - if (args.ok_to_block == false) - snd_pcm_nonblock(d_pcm_handle.get(), 1); - if (error < 0) { - d_logger->error("[{:s}]: {:s}", d_device_name, snd_strerror(error)); - throw std::runtime_error("audio_alsa_sink"); - } - - // Fill params with a full configuration space for a PCM. - error = snd_pcm_hw_params_any(d_pcm_handle.get(), d_hw_params.get()); - if (error < 0) - bail("broken configuration for playback", error); - - if (CHATTY_DEBUG) - gri_alsa_dump_hw_params(d_pcm_handle.get(), d_hw_params.get(), stdout); - - // now that we know how many channels the h/w can handle, set input signature - unsigned int umin_chan, umax_chan; - snd_pcm_hw_params_get_channels_min(d_hw_params.get(), &umin_chan); - snd_pcm_hw_params_get_channels_max(d_hw_params.get(), &umax_chan); - unsigned int min_chan = std::min(umin_chan, 1000U); - unsigned int max_chan = std::min(umax_chan, 1000U); - - // As a special case, if the hw's min_chan is two, we'll accept - // a single input and handle the duplication ourselves. - if (min_chan == 2) { - min_chan = 1; - d_special_case_mono_to_stereo = true; - } - - if (args.num_inputs < min_chan) { - throw std::runtime_error(fmt::format( - "Detected hardware requires at least {} input channels", min_chan)); - } - if (args.num_inputs > max_chan) { - throw std::runtime_error(fmt::format( - "Detected hardware supports no more than {} input channels", max_chan)); - } - // fill in portions of the d_hw_params that we know now... - - // Specify the access methods we implement - // For now, we only handle RW_INTERLEAVED... - snd_pcm_access_mask_t* access_mask; - snd_pcm_access_mask_t** access_mask_ptr = - &access_mask; // FIXME: workaround for compiler warning - snd_pcm_access_mask_alloca(access_mask_ptr); - snd_pcm_access_mask_none(access_mask); - snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED); - // snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); - - if ((error = snd_pcm_hw_params_set_access_mask( - d_pcm_handle.get(), d_hw_params.get(), access_mask)) < 0) - bail("failed to set access mask", error); - - // set sample format - if (!gri_alsa_pick_acceptable_format(d_pcm_handle.get(), - d_hw_params.get(), - acceptable_formats, - NELEMS(acceptable_formats), - &d_format, - "audio_alsa_sink", - CHATTY_DEBUG)) - throw std::runtime_error("audio_alsa_sink"); - - // sampling rate - unsigned int orig_sampling_rate = d_sampling_rate; - if ((error = snd_pcm_hw_params_set_rate_near( - d_pcm_handle.get(), d_hw_params.get(), &d_sampling_rate, 0)) < 0) - bail("failed to set rate near", error); - - if (orig_sampling_rate != d_sampling_rate) { - d_logger->info("[{:s}]: unable to support sampling rate {:d}\n\tCard " - "requested {:d} instead.", - snd_pcm_name(d_pcm_handle.get()), - orig_sampling_rate, - d_sampling_rate); - } - - /* - * ALSA transfers data in units of "periods". - * We indirectly determine the underlying buffersize by specifying - * the number of periods we want (typically 4) and the length of each - * period in units of time (typically 1ms). - */ - unsigned int min_nperiods, max_nperiods; - snd_pcm_hw_params_get_periods_min(d_hw_params.get(), &min_nperiods, &dir); - snd_pcm_hw_params_get_periods_max(d_hw_params.get(), &max_nperiods, &dir); - - unsigned int orig_nperiods = d_nperiods; - d_nperiods = std::min(std::max(min_nperiods, d_nperiods), max_nperiods); - - // adjust period time so that total buffering remains more-or-less constant - d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods; - - error = snd_pcm_hw_params_set_periods( - d_pcm_handle.get(), d_hw_params.get(), d_nperiods, 0); - if (error < 0) - bail("set_periods failed", error); - - dir = 0; - error = snd_pcm_hw_params_set_period_time_near( - d_pcm_handle.get(), d_hw_params.get(), &d_period_time_us, &dir); - if (error < 0) - bail("set_period_time_near failed", error); - - dir = 0; - error = snd_pcm_hw_params_get_period_size(d_hw_params.get(), &d_period_size, &dir); - if (error < 0) - bail("get_period_size failed", error); - - set_output_multiple(d_period_size); -} - -bool alsa_sink_cpu::start() -{ - int nchan = d_num_inputs; - int err; - - // Check the state of the stream - // Ensure that the pcm is in a state where we can still mess with the hw_params - snd_pcm_state_t state; - state = snd_pcm_state(d_pcm_handle.get()); - if (state == SND_PCM_STATE_RUNNING) - return true; // If stream is running, don't change any parameters - else if (state == SND_PCM_STATE_XRUN) - snd_pcm_prepare( - d_pcm_handle.get()); // Prepare stream on underrun, and we can set parameters; - - bool special_case = nchan == 1 && d_special_case_mono_to_stereo; - if (special_case) - nchan = 2; - - err = snd_pcm_hw_params_set_channels(d_pcm_handle.get(), d_hw_params.get(), nchan); - - if (err < 0) { - output_error_msg("set_channels failed", err); - return false; - } - - // set the parameters into the driver... - err = snd_pcm_hw_params(d_pcm_handle.get(), d_hw_params.get()); - if (err < 0) { - output_error_msg("snd_pcm_hw_params failed", err); - return false; - } - - // get current s/w params - err = snd_pcm_sw_params_current(d_pcm_handle.get(), d_sw_params.get()); - if (err < 0) - bail("snd_pcm_sw_params_current", err); - - // Tell the PCM device to wait to start until we've filled - // it's buffers half way full. This helps avoid audio underruns. - - err = snd_pcm_sw_params_set_start_threshold( - d_pcm_handle.get(), d_sw_params.get(), d_nperiods * d_period_size / 2); - if (err < 0) - bail("snd_pcm_sw_params_set_start_threshold", err); - - // store the s/w params - err = snd_pcm_sw_params(d_pcm_handle.get(), d_sw_params.get()); - if (err < 0) - bail("snd_pcm_sw_params", err); - - d_buffer.resize(d_period_size * nchan * snd_pcm_format_size(d_format, 1)); - - if (CHATTY_DEBUG) { - d_debug_logger->debug("[{:s}]: sample resolution = {:d} bits", - snd_pcm_name(d_pcm_handle.get()), - snd_pcm_hw_params_get_sbits(d_hw_params.get())); - } - - switch (d_format) { - case SND_PCM_FORMAT_S16: - if (special_case) { - d_worker = [this](work_io& wio) { return this->work_s16_1x2(wio); }; - } - else { - d_worker = [this](work_io& wio) { return this->work_s16(wio); }; - } - break; - - case SND_PCM_FORMAT_S32: - if (special_case) { - d_worker = [this](work_io& wio) { return this->work_s32_1x2(wio); }; - } - else { - d_worker = [this](work_io& wio) { return this->work_s32(wio); }; - } - break; - - default: - throw std::runtime_error("Unsupported PCM format returned from ALSA"); - } - - return true; -} - -work_return_t alsa_sink_cpu::work(work_io& wio) - -{ - // assert((noutput_items % d_period_size) == 0); - - // this is a call through std::function - return d_worker(wio); -} - - -/* - * Work function that deals with float to S16 conversion - */ -work_return_t alsa_sink_cpu::work_s16(work_io& wio) -{ - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 16 - 1) - 1; - - size_t nchan = wio.inputs().size(); - auto noutput_items = wio.min_ninput_items(); - std::vector<const float*> in_ptrs(nchan); - for (size_t i = 0; i < wio.inputs().size(); i++) { - in_ptrs[i] = wio.inputs()[i].items<float>(); - } - auto in = in_ptrs.data(); - sample_t* buf = reinterpret_cast<sample_t*>(d_buffer.data()); - int bi; - size_t n; - - size_t sizeof_frame = nchan * sizeof(sample_t); - assert(d_buffer.size() == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size) { - // process one period of data - bi = 0; - for (size_t i = 0; i < d_period_size; i++) { - for (size_t chan = 0; chan < nchan; chan++) { - buf[bi++] = (sample_t)(in[chan][i] * scale_factor); - } - } - - // update src pointers - for (size_t chan = 0; chan < nchan; chan++) - in[chan] += d_period_size; - - if (!write_buffer(buf, d_period_size, sizeof_frame)) - return work_return_t::DONE; // No fixing this problem. Say - // we're done. - } - - wio.consume_each(n); - return work_return_t::OK; -} - -/* - * Work function that deals with float to S32 conversion - */ -work_return_t alsa_sink_cpu::work_s32(work_io& wio) -{ - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 32 - 1) - 1; - - size_t nchan = wio.inputs().size(); - auto noutput_items = wio.min_ninput_items(); - std::vector<const float*> in_ptrs(nchan); - for (size_t i = 0; i < wio.inputs().size(); i++) { - in_ptrs[i] = wio.inputs()[i].items<float>(); - } - auto in = in_ptrs.data(); - sample_t* buf = reinterpret_cast<sample_t*>(d_buffer.data()); - int bi; - size_t n; - - size_t sizeof_frame = nchan * sizeof(sample_t); - assert(d_buffer.size() == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size) { - // process one period of data - bi = 0; - for (size_t i = 0; i < d_period_size; i++) { - for (size_t chan = 0; chan < nchan; chan++) { - buf[bi++] = (sample_t)(in[chan][i] * scale_factor); - } - } - - // update src pointers - for (size_t chan = 0; chan < nchan; chan++) - in[chan] += d_period_size; - - if (!write_buffer(buf, d_period_size, sizeof_frame)) - return work_return_t::DONE; // No fixing this problem. Say - // we're done. - } - - wio.consume_each(n); - return work_return_t::OK; -} - -/* - * Work function that deals with float to S16 conversion and - * mono to stereo kludge. - */ -work_return_t alsa_sink_cpu::work_s16_1x2(work_io& wio) -{ - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 16 - 1) - 1; - - assert(wio.inputs().size() == 1); - static const size_t nchan = 2; - auto noutput_items = wio.min_ninput_items(); - std::vector<const float*> in_ptrs(nchan); - for (size_t i = 0; i < wio.inputs().size(); i++) { - in_ptrs[i] = wio.inputs()[i].items<float>(); - } - auto in = in_ptrs.data(); - sample_t* buf = reinterpret_cast<sample_t*>(d_buffer.data()); - int bi; - size_t n; - - size_t sizeof_frame = nchan * sizeof(sample_t); - assert(d_buffer.size() == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size) { - // process one period of data - bi = 0; - for (size_t i = 0; i < d_period_size; i++) { - sample_t t = (sample_t)(in[0][i] * scale_factor); - buf[bi++] = t; - buf[bi++] = t; - } - - // update src pointers - in[0] += d_period_size; - - if (!write_buffer(buf, d_period_size, sizeof_frame)) - return work_return_t::DONE; // No fixing this problem. Say - // we're done. - } - - wio.consume_each(n); - return work_return_t::OK; -} - -/* - * Work function that deals with float to S32 conversion and - * mono to stereo kludge. - */ -work_return_t alsa_sink_cpu::work_s32_1x2(work_io& wio) -{ - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 32 - 1) - 1; - - static size_t nchan = 2; - auto noutput_items = wio.min_ninput_items(); - std::vector<const float*> in_ptrs(nchan); - for (size_t i = 0; i < wio.inputs().size(); i++) { - in_ptrs[i] = wio.inputs()[i].items<float>(); - } - auto in = in_ptrs.data(); - sample_t* buf = reinterpret_cast<sample_t*>(d_buffer.data()); - int bi; - size_t n; - - size_t sizeof_frame = nchan * sizeof(sample_t); - assert(d_buffer.size() == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size) { - // process one period of data - bi = 0; - for (size_t i = 0; i < d_period_size; i++) { - sample_t t = (sample_t)(in[0][i] * scale_factor); - buf[bi++] = t; - buf[bi++] = t; - } - - // update src pointers - in[0] += d_period_size; - - if (!write_buffer(buf, d_period_size, sizeof_frame)) - return work_return_t::DONE; // No fixing this problem. Say - // we're done. - } - - wio.consume_each(n); - return work_return_t::OK; -} - -bool alsa_sink_cpu::write_buffer(const void* vbuffer, - unsigned nframes, - unsigned sizeof_frame) -{ - const unsigned char* buffer = (const unsigned char*)vbuffer; - - while (nframes > 0) { - int r = snd_pcm_writei(d_pcm_handle.get(), buffer, nframes); - if (r == -EAGAIN) { - if (d_ok_to_block == true) - continue; // try again - break; - } - else if (r == -EPIPE) { // underrun - d_nunderuns++; - // we need to have an lvalue, async pitfall! - auto future_local = std::async(::fputs, "aU", stderr); - - if ((r = snd_pcm_prepare(d_pcm_handle.get())) < 0) { - output_error_msg("snd_pcm_prepare failed. Can't recover from underrun", - r); - return false; - } - continue; // try again - } -#ifdef ESTRPIPE - else if (r == -ESTRPIPE) { // h/w is suspended (whatever that means) - // This is apparently related to power management - d_nsuspends++; - if ((r = snd_pcm_resume(d_pcm_handle.get())) < 0) { - output_error_msg("failed to resume from suspend", r); - return false; - } - continue; // try again - } -#endif - else if (r < 0) { - output_error_msg("snd_pcm_writei failed", r); - return false; - } - - nframes -= r; - buffer += r * sizeof_frame; - } - - return true; -} - -void alsa_sink_cpu::output_error_msg(const char* msg, int err) -{ - d_logger->error( - "[{:s}]: {:s}: {:s}", snd_pcm_name(d_pcm_handle.get()), msg, snd_strerror(err)); -} - -void alsa_sink_cpu::bail(const char* msg, int err) -{ - output_error_msg(msg, err); - throw std::runtime_error("audio_alsa_sink"); -} - - -} // namespace audio -} // namespace gr
\ No newline at end of file diff --git a/blocklib/audio/alsa_sink/alsa_sink_cpu.h b/blocklib/audio/alsa_sink/alsa_sink_cpu.h deleted file mode 100644 index fdbd13325..000000000 --- a/blocklib/audio/alsa_sink/alsa_sink_cpu.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include "../lib/alsa_internal.h" -#include <gnuradio/audio/alsa_sink.h> - -#include <functional> - -namespace gr { -namespace audio { - -class alsa_sink_cpu : public virtual alsa_sink -{ -public: - alsa_sink_cpu(block_args args); - work_return_t work(work_io&) override; - -private: - // TODO: change to std::function - - - unsigned int d_sampling_rate; - std::string d_device_name; - alsa_internal::sndpcm_wrap d_pcm_handle; - alsa_internal::hwparam_wrap d_hw_params; - alsa_internal::swparam_wrap d_sw_params; - snd_pcm_format_t d_format; - unsigned int d_nperiods; - unsigned int d_period_time_us; // microseconds - snd_pcm_uframes_t d_period_size = 0; // in frames - std::vector<char> d_buffer; - work_t d_worker = nullptr; // the work method to use - bool d_special_case_mono_to_stereo; - - // random stats - int d_nunderuns = 0; // count of underruns - int d_nsuspends = 0; // count of suspends - bool d_ok_to_block; // defaults to "true", controls blocking/non-block I/O - size_t d_num_inputs; - - void output_error_msg(const char* msg, int err); - void bail(const char* msg, int err); - - bool start() override; - -protected: - bool write_buffer(const void* buffer, unsigned nframes, unsigned sizeof_frame); - - work_return_t work_s16(work_io& wio); - - work_return_t work_s16_1x2(work_io& wio); - - work_return_t work_s32(work_io& wio); - - work_return_t work_s32_1x2(work_io& wio); -}; - -} // namespace audio -} // namespace gr
\ No newline at end of file diff --git a/blocklib/audio/examples/.gitignore b/blocklib/audio/examples/.gitignore deleted file mode 100644 index f104652b6..000000000 --- a/blocklib/audio/examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.py diff --git a/blocklib/audio/examples/alsa_tones.grc b/blocklib/audio/examples/alsa_tones.grc deleted file mode 100644 index 6d319df9e..000000000 --- a/blocklib/audio/examples/alsa_tones.grc +++ /dev/null @@ -1,154 +0,0 @@ -options: - parameters: - author: josh - catch_exceptions: 'True' - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: qt_gui - hier_block_src_path: '.:' - id: alsa_tones - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: Not titled yet - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: samp_rate - id: variable - parameters: - comment: '' - value: '32000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [184, 12] - rotation: 0 - state: enabled -- name: analog_sig_source_0 - id: analog_sig_source - parameters: - T: float - affinity: '' - alias: '' - ampl: '0.25' - comment: '' - domain: cpu - frequency: '440' - maxoutbuf: '0' - minoutbuf: '0' - offset: '0' - phase: '0' - sampling_freq: samp_rate - showports: 'False' - waveform: analog.waveform_t.COS - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [344, 324.0] - rotation: 0 - state: enabled -- name: analog_sig_source_0_0 - id: analog_sig_source - parameters: - T: float - affinity: '' - alias: '' - ampl: '0.25' - comment: '' - domain: cpu - frequency: '554.4' - maxoutbuf: '0' - minoutbuf: '0' - offset: '0' - phase: '0' - sampling_freq: samp_rate - showports: 'False' - waveform: analog.waveform_t.COS - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [336, 132.0] - rotation: 0 - state: true -- name: audio_alsa_sink_0 - id: audio_alsa_sink - parameters: - affinity: '' - alias: '' - comment: '' - device_name: '"pulse"' - domain: cpu - num_inputs: '1' - ok_to_block: 'True' - sampling_rate: samp_rate - showports: 'False' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [872, 292.0] - rotation: 0 - state: true -- name: import_0 - id: import - parameters: - alias: '' - comment: '' - imports: from gnuradio import analog - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [296, 12.0] - rotation: 0 - state: true -- name: math_add_0 - id: math_add - parameters: - T: float - affinity: '' - alias: '' - comment: '' - domain: cpu - maxoutbuf: '0' - minoutbuf: '0' - nports: '2' - showports: 'False' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [664, 304.0] - rotation: 0 - state: enabled - -connections: -- [analog_sig_source_0, '0', math_add_0, '1'] -- [analog_sig_source_0_0, '0', math_add_0, '0'] -- [math_add_0, '0', audio_alsa_sink_0, '0'] - -metadata: - file_format: 1 diff --git a/blocklib/audio/include/gnuradio/audio/.gitignore b/blocklib/audio/include/gnuradio/audio/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/audio/include/gnuradio/audio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/audio/include/gnuradio/audio/meson.build b/blocklib/audio/include/gnuradio/audio/meson.build deleted file mode 100644 index 80941fc75..000000000 --- a/blocklib/audio/include/gnuradio/audio/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -headers = [] - -install_headers(headers, subdir : 'gnuradio/audio')
\ No newline at end of file diff --git a/blocklib/audio/lib/.gitignore b/blocklib/audio/lib/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/audio/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/audio/lib/alsa_internal.cc b/blocklib/audio/lib/alsa_internal.cc deleted file mode 100644 index 793d0d0fe..000000000 --- a/blocklib/audio/lib/alsa_internal.cc +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifdef HAVE_CONFIG_H -#warning "ALSA CONFIG H" -#include "config.h" -#endif - -#include <gnuradio/logger.h> - -#include "alsa_internal.h" - -#include <algorithm> - -static snd_pcm_access_t access_types[] = { SND_PCM_ACCESS_MMAP_INTERLEAVED, - SND_PCM_ACCESS_MMAP_NONINTERLEAVED, - SND_PCM_ACCESS_MMAP_COMPLEX, - SND_PCM_ACCESS_RW_INTERLEAVED, - SND_PCM_ACCESS_RW_NONINTERLEAVED }; - -static snd_pcm_format_t format_types[] = { - // SND_PCM_FORMAT_UNKNOWN, - SND_PCM_FORMAT_S8, - SND_PCM_FORMAT_U8, - SND_PCM_FORMAT_S16_LE, - SND_PCM_FORMAT_S16_BE, - SND_PCM_FORMAT_U16_LE, - SND_PCM_FORMAT_U16_BE, - SND_PCM_FORMAT_S24_LE, - SND_PCM_FORMAT_S24_BE, - SND_PCM_FORMAT_U24_LE, - SND_PCM_FORMAT_U24_BE, - SND_PCM_FORMAT_S32_LE, - SND_PCM_FORMAT_S32_BE, - SND_PCM_FORMAT_U32_LE, - SND_PCM_FORMAT_U32_BE, - SND_PCM_FORMAT_FLOAT_LE, - SND_PCM_FORMAT_FLOAT_BE, - SND_PCM_FORMAT_FLOAT64_LE, - SND_PCM_FORMAT_FLOAT64_BE, - SND_PCM_FORMAT_IEC958_SUBFRAME_LE, - SND_PCM_FORMAT_IEC958_SUBFRAME_BE, - SND_PCM_FORMAT_MU_LAW, - SND_PCM_FORMAT_A_LAW, - SND_PCM_FORMAT_IMA_ADPCM, - SND_PCM_FORMAT_MPEG, - SND_PCM_FORMAT_GSM, - SND_PCM_FORMAT_SPECIAL, - SND_PCM_FORMAT_S24_3LE, - SND_PCM_FORMAT_S24_3BE, - SND_PCM_FORMAT_U24_3LE, - SND_PCM_FORMAT_U24_3BE, - SND_PCM_FORMAT_S20_3LE, - SND_PCM_FORMAT_S20_3BE, - SND_PCM_FORMAT_U20_3LE, - SND_PCM_FORMAT_U20_3BE, - SND_PCM_FORMAT_S18_3LE, - SND_PCM_FORMAT_S18_3BE, - SND_PCM_FORMAT_U18_3LE, - SND_PCM_FORMAT_U18_3BE -}; - -static unsigned int test_rates[] = { 8000, 16000, 22050, 32000, - 44100, 48000, 96000, 192000 }; - -#define NELEMS(x) (sizeof(x) / sizeof(x[0])) - -void gri_alsa_dump_hw_params(snd_pcm_t* pcm, snd_pcm_hw_params_t* hwparams, FILE* fp) -{ - fprintf(fp, "PCM name: %s\n", snd_pcm_name(pcm)); - - fprintf(fp, "Access types:\n"); - for (unsigned i = 0; i < NELEMS(access_types); i++) { - snd_pcm_access_t at = access_types[i]; - fprintf(fp, - " %-20s %s\n", - snd_pcm_access_name(at), - snd_pcm_hw_params_test_access(pcm, hwparams, at) == 0 ? "YES" : "NO"); - } - - fprintf(fp, "Formats:\n"); - for (unsigned i = 0; i < NELEMS(format_types); i++) { - snd_pcm_format_t ft = format_types[i]; - if (0) - fprintf(fp, - " %-20s %s\n", - snd_pcm_format_name(ft), - snd_pcm_hw_params_test_format(pcm, hwparams, ft) == 0 ? "YES" : "NO"); - else { - if (snd_pcm_hw_params_test_format(pcm, hwparams, ft) == 0) - fprintf(fp, " %-20s YES\n", snd_pcm_format_name(ft)); - } - } - - fprintf(fp, "Number of channels\n"); - unsigned int min_chan, max_chan; - snd_pcm_hw_params_get_channels_min(hwparams, &min_chan); - snd_pcm_hw_params_get_channels_max(hwparams, &max_chan); - fprintf(fp, " min channels: %d\n", min_chan); - fprintf(fp, " max channels: %d\n", max_chan); - unsigned int chan; - max_chan = std::min(max_chan, 16U); // truncate display... - for (chan = min_chan; chan <= max_chan; chan++) { - fprintf(fp, - " %d channels\t%s\n", - chan, - snd_pcm_hw_params_test_channels(pcm, hwparams, chan) == 0 ? "YES" : "NO"); - } - - fprintf(fp, "Sample Rates:\n"); - unsigned int min_rate, max_rate; - int min_dir, max_dir; - - snd_pcm_hw_params_get_rate_min(hwparams, &min_rate, &min_dir); - snd_pcm_hw_params_get_rate_max(hwparams, &max_rate, &max_dir); - fprintf(fp, " min rate: %7d (dir = %d)\n", min_rate, min_dir); - fprintf(fp, " max rate: %7d (dir = %d)\n", max_rate, max_dir); - for (unsigned i = 0; i < NELEMS(test_rates); i++) { - unsigned int rate = test_rates[i]; - fprintf(fp, - " %6u %s\n", - rate, - snd_pcm_hw_params_test_rate(pcm, hwparams, rate, 0) == 0 ? "YES" : "NO"); - } - - fflush(fp); -} - -bool gri_alsa_pick_acceptable_format(snd_pcm_t* pcm, - snd_pcm_hw_params_t* hwparams, - snd_pcm_format_t acceptable_formats[], - unsigned nacceptable_formats, - snd_pcm_format_t* selected_format, - const char* error_msg_tag, - bool verbose) -{ - int err; - gr::logger_ptr logger, debug_logger; - gr::configure_default_loggers( - logger, debug_logger, "gri_alsa_pick_acceptable_format"); - - // pick a format that we like... - for (unsigned i = 0; i < nacceptable_formats; i++) { - if (snd_pcm_hw_params_test_format(pcm, hwparams, acceptable_formats[i]) == 0) { - err = snd_pcm_hw_params_set_format(pcm, hwparams, acceptable_formats[i]); - if (err < 0) { - logger->error("{:s}[{:s}]: failed to set format: {:s}", - error_msg_tag, - snd_pcm_name(pcm), - snd_strerror(err)); - return false; - } - debug_logger->info("{:s}[{:s}]: using {:s}", - error_msg_tag, - snd_pcm_name(pcm), - snd_pcm_format_name(acceptable_formats[i])); - *selected_format = acceptable_formats[i]; - return true; - } - } - - logger->error( - "{:s}[{:s}]: failed to find acceptable format", error_msg_tag, snd_pcm_name(pcm)); - return false; -} diff --git a/blocklib/audio/lib/alsa_internal.h b/blocklib/audio/lib/alsa_internal.h deleted file mode 100644 index 0147cb1b6..000000000 --- a/blocklib/audio/lib/alsa_internal.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <alsa/asoundlib.h> -#include <cstdio> -#include <stdexcept> - -void gri_alsa_dump_hw_params(snd_pcm_t* pcm, snd_pcm_hw_params_t* hwparams, FILE* fp); - -bool gri_alsa_pick_acceptable_format(snd_pcm_t* pcm, - snd_pcm_hw_params_t* hwparams, - snd_pcm_format_t acceptable_formats[], - unsigned nacceptable_formats, - snd_pcm_format_t* selected_format, - const char* error_msg_tag, - bool verbose); - -namespace gr { -namespace audio { -namespace alsa_internal { -// hw/sw params RAII wrapper. -template <typename T, int Alloc(T**), void Free(T*)> -class param_wrap -{ -public: - param_wrap() - { - const int err = Alloc(&d_param); - if (err) { - throw std::runtime_error("failed to allocate ALSA params. Error code " + - std::to_string(err)); - } - } - param_wrap(const param_wrap&) = delete; - param_wrap& operator=(const param_wrap&) = delete; - T* get() { return d_param; } - ~param_wrap() { Free(d_param); } - -private: - T* d_param = nullptr; -}; -typedef param_wrap<snd_pcm_hw_params_t, snd_pcm_hw_params_malloc, snd_pcm_hw_params_free> - hwparam_wrap; -typedef param_wrap<snd_pcm_sw_params_t, snd_pcm_sw_params_malloc, snd_pcm_sw_params_free> - swparam_wrap; - -class sndpcm_wrap -{ -public: - sndpcm_wrap(snd_pcm_t* in = nullptr) : d_pcm_handle(in) {} - sndpcm_wrap(const sndpcm_wrap&) = delete; - sndpcm_wrap(sndpcm_wrap&&) = delete; - sndpcm_wrap& operator=(const sndpcm_wrap&) = delete; - sndpcm_wrap& operator=(sndpcm_wrap&&) = delete; - ~sndpcm_wrap() { close(); } - void close() - { - if (d_pcm_handle == nullptr) { - return; - } - if (snd_pcm_state(d_pcm_handle) == SND_PCM_STATE_RUNNING) { - snd_pcm_drop(d_pcm_handle); - } - snd_pcm_close(d_pcm_handle); - d_pcm_handle = nullptr; - } - void set(snd_pcm_t* ptr) - { - close(); - d_pcm_handle = ptr; - } - snd_pcm_t* get() noexcept { return d_pcm_handle; } - -private: - snd_pcm_t* d_pcm_handle; -}; - -} // namespace alsa_internal -} // namespace audio -} // namespace gr diff --git a/blocklib/audio/lib/meson.build b/blocklib/audio/lib/meson.build deleted file mode 100644 index d0530e463..000000000 --- a/blocklib/audio/lib/meson.build +++ /dev/null @@ -1,42 +0,0 @@ -audio_sources += [ - 'alsa_internal.cc' -] - -alsa_dep = dependency('alsa', required: true) - -audio_deps += [gnuradio_gr_dep, volk_dep, fmt_dep, pmtf_dep, alsa_dep] - -block_cpp_args = ['-DHAVE_CPU'] - -incdir = include_directories(['../include/gnuradio/audio','../include']) -gnuradio_blocklib_audio_lib = library('gnuradio-blocklib-audio', - audio_sources, - include_directories : incdir, - install : true, - link_language: 'cpp', - dependencies : audio_deps, - cpp_args : block_cpp_args) - -gnuradio_blocklib_audio_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_audio_lib, - dependencies : audio_deps) - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'audio') -cmake.configure_package_config_file( - name : 'gnuradio-audio', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_audio_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-audio', - filebase : 'gnuradio-audio', - description : 'GNU Radio Audio Module') diff --git a/blocklib/audio/python/gnuradio/audio/.gitignore b/blocklib/audio/python/gnuradio/audio/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/audio/python/gnuradio/audio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/audio/python/gnuradio/audio/__init__.py b/blocklib/audio/python/gnuradio/audio/__init__.py deleted file mode 100644 index e87741f28..000000000 --- a/blocklib/audio/python/gnuradio/audio/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ - -import os - -try: - from .audio_python import * -except ImportError: - dirname, filename = os.path.split(os.path.abspath(__file__)) - __path__.append(os.path.join(dirname, "bindings")) - from .audio_python import * diff --git a/blocklib/audio/test/.gitignore b/blocklib/audio/test/.gitignore deleted file mode 100644 index d53050d7d..000000000 --- a/blocklib/audio/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build diff --git a/blocklib/audio/test/meson.build b/blocklib/audio/test/meson.build deleted file mode 100644 index a3efa7246..000000000 --- a/blocklib/audio/test/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -################################################### -# QA -################################################### diff --git a/blocklib/blocks/nop_source/nop_source.yml b/blocklib/blocks/nop_source/nop_source.yml deleted file mode 100644 index a3b3a04de..000000000 --- a/blocklib/blocks/nop_source/nop_source.yml +++ /dev/null @@ -1,33 +0,0 @@ -module: blocks -block: nop_source -label: Nop Source -blocktype: sync_block -category: '[Core]/Debug Tools' - -parameters: -- id: nports - label: Num. Ports - dtype: size - default: 1 - settable: false -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part - -ports: -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - multiplicity: parameters/nports - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/blocks/nop_source/nop_source_cpu.cc b/blocklib/blocks/nop_source/nop_source_cpu.cc deleted file mode 100644 index 3dd30fe6f..000000000 --- a/blocklib/blocks/nop_source/nop_source_cpu.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- c++ -*- */ -/* - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "nop_source_cpu.h" -#include "nop_source_cpu_gen.h" - -namespace gr { -namespace blocks { - -nop_source_cpu::nop_source_cpu(block_args args) : INHERITED_CONSTRUCTORS {} - -work_return_t nop_source_cpu::work(work_io& wio) -{ - for (auto& out : wio.outputs()) { - auto noutput_items = out.n_items; - out.n_produced = noutput_items; - } - - return work_return_t::OK; -} - - -} // namespace blocks -} // namespace gr
\ No newline at end of file diff --git a/blocklib/blocks/nop_source/nop_source_cpu.h b/blocklib/blocks/nop_source/nop_source_cpu.h deleted file mode 100644 index 9daef2d64..000000000 --- a/blocklib/blocks/nop_source/nop_source_cpu.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- c++ -*- */ -/* - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/blocks/nop_source.h> - -namespace gr { -namespace blocks { - -class nop_source_cpu : public nop_source -{ -public: - nop_source_cpu(block_args args); - work_return_t work(work_io&) override; - -protected: - size_t d_nports; -}; - -} // namespace blocks -} // namespace gr diff --git a/blocklib/fec/include/gnuradio/fec/.gitignore b/blocklib/fec/include/gnuradio/fec/.gitignore deleted file mode 100644 index d53050d7d..000000000 --- a/blocklib/fec/include/gnuradio/fec/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build diff --git a/blocklib/fec/include/gnuradio/fec/api.h b/blocklib/fec/include/gnuradio/fec/api.h deleted file mode 100644 index f0a0de2d4..000000000 --- a/blocklib/fec/include/gnuradio/fec/api.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/attributes.h> - -#ifdef gnuradio_fec_EXPORTS -#define FEC_API __GR_ATTR_EXPORT -#else -#define FEC_API __GR_ATTR_IMPORT -#endif diff --git a/blocklib/fec/include/gnuradio/fec/meson.build b/blocklib/fec/include/gnuradio/fec/meson.build deleted file mode 100644 index b95e69612..000000000 --- a/blocklib/fec/include/gnuradio/fec/meson.build +++ /dev/null @@ -1,6 +0,0 @@ -headers = [ - 'api.h', - 'rs.h' -] - -install_headers(headers, subdir : 'gnuradio/fec') diff --git a/blocklib/fec/include/gnuradio/fec/rs.h b/blocklib/fec/include/gnuradio/fec/rs.h deleted file mode 100644 index ae05c79eb..000000000 --- a/blocklib/fec/include/gnuradio/fec/rs.h +++ /dev/null @@ -1,41 +0,0 @@ -#include <gnuradio/fec/api.h> -/* User include file for the Reed-Solomon codec - * Copyright 2002, Phil Karn KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -/* General purpose RS codec, 8-bit symbols */ -FEC_API void encode_rs_char(void* rs, unsigned char* data, unsigned char* parity); -FEC_API int decode_rs_char(void* rs, unsigned char* data, int* eras_pos, int no_eras); -FEC_API void* init_rs_char(unsigned int symsize, - unsigned int gfpoly, - unsigned int fcr, - unsigned int prim, - unsigned int nroots); -FEC_API void free_rs_char(void* rs); - -/* General purpose RS codec, integer symbols */ -FEC_API void encode_rs_int(void* rs, int* data, int* parity); -FEC_API int decode_rs_int(void* rs, int* data, int* eras_pos, int no_eras); -FEC_API void* init_rs_int(unsigned int symsize, - unsigned int gfpoly, - unsigned int fcr, - unsigned int prim, - unsigned int nroots); -FEC_API void free_rs_int(void* rs); - -/* CCSDS standard (255,223) RS codec with conventional (*not* dual-basis) - * symbol representation - */ -FEC_API void encode_rs_8(unsigned char* data, unsigned char* parity); -FEC_API int decode_rs_8(unsigned char* data, int* eras_pos, int no_eras); - -/* CCSDS standard (255,223) RS codec with dual-basis symbol representation - */ -FEC_API void encode_rs_ccsds(unsigned char* data, unsigned char* parity); -FEC_API int decode_rs_ccsds(unsigned char* data, int* eras_pos, int no_eras); - -/* Tables to map from conventional->dual (Taltab) and - * dual->conventional (Tal1tab) bases - */ -extern unsigned char Taltab[], Tal1tab[]; diff --git a/blocklib/fec/lib/.gitignore b/blocklib/fec/lib/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/fec/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/fec/lib/meson.build b/blocklib/fec/lib/meson.build deleted file mode 100644 index ecf8cef44..000000000 --- a/blocklib/fec/lib/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -subdir('reed-solomon') - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'fec') -cmake.configure_package_config_file( - name : 'gnuradio-fec', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_fec_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-fec', - filebase : 'gnuradio-fec', - description : 'GNU Radio FEC Module') diff --git a/blocklib/fec/lib/reed-solomon/Makefile.in.karn b/blocklib/fec/lib/reed-solomon/Makefile.in.karn deleted file mode 100644 index 8550b4158..000000000 --- a/blocklib/fec/lib/reed-solomon/Makefile.in.karn +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2002 Phil Karn, KA9Q -# May be used under the terms of the GNU General Public License (GPL) -# @configure_input@ -srcdir = @srcdir@ -prefix = @prefix@ -exec_prefix=@exec_prefix@ -VPATH = @srcdir@ -CC=@CC@ - -CFLAGS=@CFLAGS@ @ARCH_OPTION@ -Wall - -LIB= encode_rs_char.o encode_rs_int.o encode_rs_8.o \ - decode_rs_char.o decode_rs_int.o decode_rs_8.o \ - init_rs_char.o init_rs_int.o ccsds_tab.o \ - encode_rs_ccsds.o decode_rs_ccsds.o ccsds_tal.o - -all: librs.a librs.so.@SO_VERSION@ - -test: rstest - ./rstest - -rstest: rstest.o exercise_int.o exercise_char.o exercise_8.o exercise_ccsds.o \ - librs.a - gcc -g -o $@ $^ - -install: all - install -D -m 644 -p librs.a librs.so.@SO_VERSION@ @libdir@ - (cd @libdir@;ln -f -s librs.so.@SO_VERSION@ librs.so) - ldconfig - install -m 644 -p rs.h @includedir@ - install -m 644 rs.3 @mandir@/man3 - -librs.a: $(LIB) - ar rv $@ $^ - -librs.so.@SO_VERSION@: librs.a - gcc -shared -Xlinker -soname=librs.so.@SO_NAME@ -o $@ -Wl,-whole-archive $^ -Wl,-no-whole-archive -lc - -encode_rs_char.o: encode_rs.c - gcc $(CFLAGS) -c -o $@ $^ - -encode_rs_int.o: encode_rs.c - gcc -DBIGSYM=1 $(CFLAGS) -c -o $@ $^ - -encode_rs_8.o: encode_rs.c - gcc -DFIXED=1 $(CFLAGS) -c -o $@ $^ - -decode_rs_char.o: decode_rs.c - gcc $(CFLAGS) -c -o $@ $^ - -decode_rs_int.o: decode_rs.c - gcc -DBIGSYM=1 $(CFLAGS) -c -o $@ $^ - -decode_rs_8.o: decode_rs.c - gcc -DFIXED=1 $(CFLAGS) -c -o $@ $^ - -init_rs_char.o: init_rs.c - gcc $(CFLAGS) -c -o $@ $^ - -init_rs_int.o: init_rs.c - gcc -DBIGSYM=1 $(CFLAGS) -c -o $@ $^ - -ccsds_tab.o: ccsds_tab.c - -ccsds_tab.c: gen_ccsds - ./gen_ccsds > ccsds_tab.c - -gen_ccsds: gen_ccsds.o init_rs_char.o - gcc -o $@ $^ - -gen_ccsds.o: gen_ccsds.c - gcc $(CFLAGS) -c -o $@ $^ - -ccsds_tal.o: ccsds_tal.c - -ccsds_tal.c: gen_ccsds_tal - ./gen_ccsds_tal > ccsds_tal.c - -exercise_char.o: exercise.c - gcc $(CFLAGS) -c -o $@ $^ - -exercise_int.o: exercise.c - gcc -DBIGSYM=1 $(CFLAGS) -c -o $@ $^ - -exercise_8.o: exercise.c - gcc -DFIXED=1 $(CFLAGS) -c -o $@ $^ - -exercise_ccsds.o: exercise.c - gcc -DCCSDS=1 $(CFLAGS) -c -o $@ $^ - - -clean: - rm -f *.o *.a ccsds_tab.c ccsds_tal.c gen_ccsds gen_ccsds_tal \ - rstest librs.so.@SO_VERSION@ - -distclean: clean - rm -f config.log config.cache config.status config.h makefile - - diff --git a/blocklib/fec/lib/reed-solomon/README b/blocklib/fec/lib/reed-solomon/README deleted file mode 100644 index 5c867638e..000000000 --- a/blocklib/fec/lib/reed-solomon/README +++ /dev/null @@ -1,2 +0,0 @@ -This code is from http://people.qualcomm.com/karn/code/fec -It is based on reed-soloman-3.1.1 (1 Jan 2002). diff --git a/blocklib/fec/lib/reed-solomon/README.karn b/blocklib/fec/lib/reed-solomon/README.karn deleted file mode 100644 index f30644ffe..000000000 --- a/blocklib/fec/lib/reed-solomon/README.karn +++ /dev/null @@ -1,22 +0,0 @@ -This package implements a general purpose Reed-Solomon encoding and decoding -facility. See the rs.3 man page for details. - -To install, simply do the following after extracting this tarball into -an empty directory: - -./configure -make -make install - -The command "make test" runs a battery of encode/decode tests using a -variety of RS codes using random data and random errors. Each test -should pass with an "OK"; if any fail, please let me know so I can -track down the problem. - -Phil Karn (karn@ka9q.net) 1 Jan 2002 - -Copyright 2002, Phil Karn, KA9Q -This software may be used under the terms of the GNU General Public License (GPL). - - - diff --git a/blocklib/fec/lib/reed-solomon/ccsds.c b/blocklib/fec/lib/reed-solomon/ccsds.c deleted file mode 100644 index 6bdadff10..000000000 --- a/blocklib/fec/lib/reed-solomon/ccsds.c +++ /dev/null @@ -1,10 +0,0 @@ -/* Reed-Solomon decoder - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -#define FIXED -#include "fixed.h" - -#include "decode_rs.h" -#include "encode_rs.h" diff --git a/blocklib/fec/lib/reed-solomon/ccsds.h b/blocklib/fec/lib/reed-solomon/ccsds.h deleted file mode 100644 index 52746f583..000000000 --- a/blocklib/fec/lib/reed-solomon/ccsds.h +++ /dev/null @@ -1 +0,0 @@ -extern unsigned char Taltab[], Tal1tab[]; diff --git a/blocklib/fec/lib/reed-solomon/ccsds_tab.c b/blocklib/fec/lib/reed-solomon/ccsds_tab.c deleted file mode 100644 index 63a3f366e..000000000 --- a/blocklib/fec/lib/reed-solomon/ccsds_tab.c +++ /dev/null @@ -1,45 +0,0 @@ -/* This has been generated with gen_ccsds */ - -char CCSDS_alpha_to[] = { -0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, -0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, -0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, -0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, -0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, -0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, -0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, -0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, -0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, -0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, -0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, -0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, -0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, -0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, -0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, -0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, -}; - -char CCSDS_index_of[] = { -255, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, - 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, - 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, -103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, - 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, -202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, -104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, -110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, - 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, -209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, -203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, -192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, -105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, -130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, -111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, - 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, -}; - -char CCSDS_poly[] = { - 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, - 24, 5,170, 66, 50,213, 3, 30, 97,251,126, 43, 4, 66, 59,249, - 0, -}; diff --git a/blocklib/fec/lib/reed-solomon/ccsds_tal.c b/blocklib/fec/lib/reed-solomon/ccsds_tal.c deleted file mode 100644 index e579eef4d..000000000 --- a/blocklib/fec/lib/reed-solomon/ccsds_tal.c +++ /dev/null @@ -1,40 +0,0 @@ -/* This has been generated with gen_ccsds_tal */ - -unsigned char Taltab[] = { - -0x00,0x7b,0xaf,0xd4,0x99,0xe2,0x36,0x4d,0xfa,0x81,0x55,0x2e,0x63,0x18,0xcc,0xb7, -0x86,0xfd,0x29,0x52,0x1f,0x64,0xb0,0xcb,0x7c,0x07,0xd3,0xa8,0xe5,0x9e,0x4a,0x31, -0xec,0x97,0x43,0x38,0x75,0x0e,0xda,0xa1,0x16,0x6d,0xb9,0xc2,0x8f,0xf4,0x20,0x5b, -0x6a,0x11,0xc5,0xbe,0xf3,0x88,0x5c,0x27,0x90,0xeb,0x3f,0x44,0x09,0x72,0xa6,0xdd, -0xef,0x94,0x40,0x3b,0x76,0x0d,0xd9,0xa2,0x15,0x6e,0xba,0xc1,0x8c,0xf7,0x23,0x58, -0x69,0x12,0xc6,0xbd,0xf0,0x8b,0x5f,0x24,0x93,0xe8,0x3c,0x47,0x0a,0x71,0xa5,0xde, -0x03,0x78,0xac,0xd7,0x9a,0xe1,0x35,0x4e,0xf9,0x82,0x56,0x2d,0x60,0x1b,0xcf,0xb4, -0x85,0xfe,0x2a,0x51,0x1c,0x67,0xb3,0xc8,0x7f,0x04,0xd0,0xab,0xe6,0x9d,0x49,0x32, -0x8d,0xf6,0x22,0x59,0x14,0x6f,0xbb,0xc0,0x77,0x0c,0xd8,0xa3,0xee,0x95,0x41,0x3a, -0x0b,0x70,0xa4,0xdf,0x92,0xe9,0x3d,0x46,0xf1,0x8a,0x5e,0x25,0x68,0x13,0xc7,0xbc, -0x61,0x1a,0xce,0xb5,0xf8,0x83,0x57,0x2c,0x9b,0xe0,0x34,0x4f,0x02,0x79,0xad,0xd6, -0xe7,0x9c,0x48,0x33,0x7e,0x05,0xd1,0xaa,0x1d,0x66,0xb2,0xc9,0x84,0xff,0x2b,0x50, -0x62,0x19,0xcd,0xb6,0xfb,0x80,0x54,0x2f,0x98,0xe3,0x37,0x4c,0x01,0x7a,0xae,0xd5, -0xe4,0x9f,0x4b,0x30,0x7d,0x06,0xd2,0xa9,0x1e,0x65,0xb1,0xca,0x87,0xfc,0x28,0x53, -0x8e,0xf5,0x21,0x5a,0x17,0x6c,0xb8,0xc3,0x74,0x0f,0xdb,0xa0,0xed,0x96,0x42,0x39, -0x08,0x73,0xa7,0xdc,0x91,0xea,0x3e,0x45,0xf2,0x89,0x5d,0x26,0x6b,0x10,0xc4,0xbf, -}; - -unsigned char Tal1tab[] = { -0x00,0xcc,0xac,0x60,0x79,0xb5,0xd5,0x19,0xf0,0x3c,0x5c,0x90,0x89,0x45,0x25,0xe9, -0xfd,0x31,0x51,0x9d,0x84,0x48,0x28,0xe4,0x0d,0xc1,0xa1,0x6d,0x74,0xb8,0xd8,0x14, -0x2e,0xe2,0x82,0x4e,0x57,0x9b,0xfb,0x37,0xde,0x12,0x72,0xbe,0xa7,0x6b,0x0b,0xc7, -0xd3,0x1f,0x7f,0xb3,0xaa,0x66,0x06,0xca,0x23,0xef,0x8f,0x43,0x5a,0x96,0xf6,0x3a, -0x42,0x8e,0xee,0x22,0x3b,0xf7,0x97,0x5b,0xb2,0x7e,0x1e,0xd2,0xcb,0x07,0x67,0xab, -0xbf,0x73,0x13,0xdf,0xc6,0x0a,0x6a,0xa6,0x4f,0x83,0xe3,0x2f,0x36,0xfa,0x9a,0x56, -0x6c,0xa0,0xc0,0x0c,0x15,0xd9,0xb9,0x75,0x9c,0x50,0x30,0xfc,0xe5,0x29,0x49,0x85, -0x91,0x5d,0x3d,0xf1,0xe8,0x24,0x44,0x88,0x61,0xad,0xcd,0x01,0x18,0xd4,0xb4,0x78, -0xc5,0x09,0x69,0xa5,0xbc,0x70,0x10,0xdc,0x35,0xf9,0x99,0x55,0x4c,0x80,0xe0,0x2c, -0x38,0xf4,0x94,0x58,0x41,0x8d,0xed,0x21,0xc8,0x04,0x64,0xa8,0xb1,0x7d,0x1d,0xd1, -0xeb,0x27,0x47,0x8b,0x92,0x5e,0x3e,0xf2,0x1b,0xd7,0xb7,0x7b,0x62,0xae,0xce,0x02, -0x16,0xda,0xba,0x76,0x6f,0xa3,0xc3,0x0f,0xe6,0x2a,0x4a,0x86,0x9f,0x53,0x33,0xff, -0x87,0x4b,0x2b,0xe7,0xfe,0x32,0x52,0x9e,0x77,0xbb,0xdb,0x17,0x0e,0xc2,0xa2,0x6e, -0x7a,0xb6,0xd6,0x1a,0x03,0xcf,0xaf,0x63,0x8a,0x46,0x26,0xea,0xf3,0x3f,0x5f,0x93, -0xa9,0x65,0x05,0xc9,0xd0,0x1c,0x7c,0xb0,0x59,0x95,0xf5,0x39,0x20,0xec,0x8c,0x40, -0x54,0x98,0xf8,0x34,0x2d,0xe1,0x81,0x4d,0xa4,0x68,0x08,0xc4,0xdd,0x11,0x71,0xbd, -}; diff --git a/blocklib/fec/lib/reed-solomon/char.c b/blocklib/fec/lib/reed-solomon/char.c deleted file mode 100644 index 1aea39c75..000000000 --- a/blocklib/fec/lib/reed-solomon/char.c +++ /dev/null @@ -1,9 +0,0 @@ -/* Reed-Solomon decoder - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -#include "char.h" - -#include "decode_rs.h" -#include "encode_rs.h" diff --git a/blocklib/fec/lib/reed-solomon/char.h b/blocklib/fec/lib/reed-solomon/char.h deleted file mode 100644 index 80435b633..000000000 --- a/blocklib/fec/lib/reed-solomon/char.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Include file to configure the RS codec for character symbols - * - * Copyright 2002, Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -#define DTYPE unsigned char - -#include <gnuradio/fec/api.h> - -/* Reed-Solomon codec control block */ -struct rs { - unsigned int mm; /* Bits per symbol */ - unsigned int nn; /* Symbols per block (= (1<<mm)-1) */ - unsigned char* alpha_to; /* log lookup table */ - unsigned char* index_of; /* Antilog lookup table */ - unsigned char* genpoly; /* Generator polynomial */ - unsigned int nroots; /* Number of generator roots = number of parity symbols */ - unsigned char fcr; /* First consecutive root, index form */ - unsigned char prim; /* Primitive element, index form */ - unsigned char iprim; /* prim-th root of 1, index form */ - int* modnn_table; /* modnn lookup table, 512 entries */ -}; - -static inline unsigned int modnn(struct rs* rs, unsigned int x) -{ - while (x >= rs->nn) { - x -= rs->nn; - x = (x >> rs->mm) + (x & rs->nn); - } - return x; -} -#define MODNN(x) modnn(rs, x) - -#define MM (rs->mm) -#define NN (rs->nn) -#define ALPHA_TO (rs->alpha_to) -#define INDEX_OF (rs->index_of) -#define GENPOLY (rs->genpoly) -#define NROOTS (rs->nroots) -#define FCR (rs->fcr) -#define PRIM (rs->prim) -#define IPRIM (rs->iprim) -#define A0 (NN) - -#define ENCODE_RS encode_rs_char -#define DECODE_RS decode_rs_char -#define INIT_RS init_rs_char -#define FREE_RS free_rs_char - -FEC_API void ENCODE_RS(void* p, DTYPE* data, DTYPE* parity); -FEC_API int DECODE_RS(void* p, DTYPE* data, int* eras_pos, int no_eras); -FEC_API void* INIT_RS(unsigned int symsize, - unsigned int gfpoly, - unsigned int fcr, - unsigned int prim, - unsigned int nroots); -FEC_API void FREE_RS(void* p); diff --git a/blocklib/fec/lib/reed-solomon/decode_rs.h b/blocklib/fec/lib/reed-solomon/decode_rs.h deleted file mode 100644 index 0b0799bf9..000000000 --- a/blocklib/fec/lib/reed-solomon/decode_rs.h +++ /dev/null @@ -1,273 +0,0 @@ -/* Reed-Solomon decoder - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -#ifdef DEBUG -#include <stdio.h> -#endif - -#include <string.h> - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#define min(a, b) ((a) < (b) ? (a) : (b)) - -int DECODE_RS( -#ifndef FIXED - void* p, -#endif - DTYPE* data, - int* eras_pos, - int no_eras) -{ - -#ifndef FIXED - struct rs* rs = (struct rs*)p; -#endif - int deg_lambda, el, deg_omega; - int i, j, r, k; -#ifdef MAX_ARRAY - DTYPE u, q, tmp, num1, num2, den, discr_r; - DTYPE lambda[MAX_ARRAY], s[MAX_ARRAY]; /* Err+Eras Locator poly - * and syndrome poly */ - DTYPE b[MAX_ARRAY], t[MAX_ARRAY], omega[MAX_ARRAY]; - DTYPE root[MAX_ARRAY], reg[MAX_ARRAY], loc[MAX_ARRAY]; -#else - DTYPE u, q, tmp, num1, num2, den, discr_r; - DTYPE lambda[NROOTS + 1], s[NROOTS]; /* Err+Eras Locator poly - * and syndrome poly */ - DTYPE b[NROOTS + 1], t[NROOTS + 1], omega[NROOTS + 1]; - DTYPE root[NROOTS], reg[NROOTS + 1], loc[NROOTS]; -#endif - int syn_error, count; - - /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ - for (i = 0; (unsigned int)i < NROOTS; i++) - s[i] = data[0]; - - for (j = 1; (unsigned int)j < NN; j++) { - for (i = 0; (unsigned int)i < NROOTS; i++) { - if (s[i] == 0) { - s[i] = data[j]; - } - else { - s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR + i) * PRIM)]; - } - } - } - - /* Convert syndromes to index form, checking for nonzero condition */ - syn_error = 0; - for (i = 0; (unsigned int)i < NROOTS; i++) { - syn_error |= s[i]; - s[i] = INDEX_OF[s[i]]; - } - - if (!syn_error) { - /* if syndrome is zero, data[] is a codeword and there are no - * errors to correct. So return data[] unmodified - */ - count = 0; - goto finish; - } - memset(&lambda[1], 0, NROOTS * sizeof(lambda[0])); - lambda[0] = 1; - - if (no_eras > 0) { - /* Init lambda to be the erasure locator polynomial */ - lambda[1] = ALPHA_TO[MODNN(PRIM * (NN - 1 - eras_pos[0]))]; - for (i = 1; i < no_eras; i++) { - u = MODNN(PRIM * (NN - 1 - eras_pos[i])); - for (j = i + 1; j > 0; j--) { - tmp = INDEX_OF[lambda[j - 1]]; - if (tmp != A0) - lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; - } - } - -#if DEBUG >= 1 - /* Test code that verifies the erasure locator polynomial just constructed - Needed only for decoder debugging. */ - - /* find roots of the erasure location polynomial */ - for (i = 1; i <= no_eras; i++) - reg[i] = INDEX_OF[lambda[i]]; - - count = 0; - for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) { - q = 1; - for (j = 1; j <= no_eras; j++) - if (reg[j] != A0) { - reg[j] = MODNN(reg[j] + j); - q ^= ALPHA_TO[reg[j]]; - } - if (q != 0) - continue; - /* store root and error location number indices */ - root[count] = i; - loc[count] = k; - count++; - } - if (count != no_eras) { - printf("count = %d no_eras = %d\n lambda(x) is WRONG\n", count, no_eras); - count = -1; - goto finish; - } -#if DEBUG >= 2 - printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); - for (i = 0; i < count; i++) - printf("%d ", loc[i]); - printf("\n"); -#endif -#endif - } - for (i = 0; (unsigned int)i < NROOTS + 1; i++) - b[i] = INDEX_OF[lambda[i]]; - - /* - * Begin Berlekamp-Massey algorithm to determine error+erasure - * locator polynomial - */ - r = no_eras; - el = no_eras; - while ((unsigned int)(++r) <= NROOTS) { /* r is the step number */ - /* Compute discrepancy at the r-th step in poly-form */ - discr_r = 0; - for (i = 0; i < r; i++) { - if ((lambda[i] != 0) && (s[r - i - 1] != A0)) { - discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r - i - 1])]; - } - } - discr_r = INDEX_OF[discr_r]; /* Index form */ - if (discr_r == A0) { - /* 2 lines below: B(x) <-- x*B(x) */ - memmove(&b[1], b, NROOTS * sizeof(b[0])); - b[0] = A0; - } - else { - /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */ - t[0] = lambda[0]; - for (i = 0; (unsigned int)i < NROOTS; i++) { - if (b[i] != A0) - t[i + 1] = lambda[i + 1] ^ ALPHA_TO[MODNN(discr_r + b[i])]; - else - t[i + 1] = lambda[i + 1]; - } - if (2 * el <= r + no_eras - 1) { - el = r + no_eras - el; - /* - * 2 lines below: B(x) <-- inv(discr_r) * - * lambda(x) - */ - for (i = 0; (unsigned int)i <= NROOTS; i++) - b[i] = - (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN); - } - else { - /* 2 lines below: B(x) <-- x*B(x) */ - memmove(&b[1], b, NROOTS * sizeof(b[0])); - b[0] = A0; - } - memcpy(lambda, t, (NROOTS + 1) * sizeof(t[0])); - } - } - - /* Convert lambda to index form and compute deg(lambda(x)) */ - deg_lambda = 0; - for (i = 0; (unsigned int)i < NROOTS + 1; i++) { - lambda[i] = INDEX_OF[lambda[i]]; - if (lambda[i] != A0) - deg_lambda = i; - } - /* Find roots of the error+erasure locator polynomial by Chien search */ - memcpy(®[1], &lambda[1], NROOTS * sizeof(reg[0])); - count = 0; /* Number of roots of lambda(x) */ - for (i = 1, k = IPRIM - 1; (unsigned int)i <= NN; i++, k = MODNN(k + IPRIM)) { - q = 1; /* lambda[0] is always 0 */ - for (j = deg_lambda; j > 0; j--) { - if (reg[j] != A0) { - reg[j] = MODNN(reg[j] + j); - q ^= ALPHA_TO[reg[j]]; - } - } - if (q != 0) - continue; /* Not a root */ - /* store root (index-form) and error location number */ -#if DEBUG >= 2 - printf("count %d root %d loc %d\n", count, i, k); -#endif - root[count] = i; - loc[count] = k; - /* If we've already found max possible roots, - * abort the search to save time - */ - if (++count == deg_lambda) - break; - } - if (deg_lambda != count) { - /* - * deg(lambda) unequal to number of roots => uncorrectable - * error detected - */ - count = -1; - goto finish; - } - /* - * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo - * x**NROOTS). in index form. Also find deg(omega). - */ - deg_omega = 0; - for (i = 0; (unsigned int)i < NROOTS; i++) { - tmp = 0; - j = (deg_lambda < i) ? deg_lambda : i; - for (; j >= 0; j--) { - if ((s[i - j] != A0) && (lambda[j] != A0)) - tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; - } - if (tmp != 0) - deg_omega = i; - omega[i] = INDEX_OF[tmp]; - } - omega[NROOTS] = A0; - - /* - * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = - * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form - */ - for (j = count - 1; j >= 0; j--) { - num1 = 0; - for (i = deg_omega; i >= 0; i--) { - if (omega[i] != A0) - num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; - } - num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; - den = 0; - - /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ - for (i = (int)min((unsigned int)deg_lambda, NROOTS - 1) & ~1; i >= 0; i -= 2) { - if (lambda[i + 1] != A0) - den ^= ALPHA_TO[MODNN(lambda[i + 1] + i * root[j])]; - } - if (den == 0) { -#if DEBUG >= 1 - printf("\n ERROR: denominator = 0\n"); -#endif - count = -1; - goto finish; - } - /* Apply error to data */ - if (num1 != 0) { - data[loc[j]] ^= - ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; - } - } -finish: - if (eras_pos != NULL) { - for (i = 0; i < count; i++) - eras_pos[i] = loc[i]; - } - return count; -} diff --git a/blocklib/fec/lib/reed-solomon/decode_rs_ccsds.c b/blocklib/fec/lib/reed-solomon/decode_rs_ccsds.c deleted file mode 100644 index be6e2018e..000000000 --- a/blocklib/fec/lib/reed-solomon/decode_rs_ccsds.c +++ /dev/null @@ -1,28 +0,0 @@ -/* This function wraps around the fixed 8-bit decoder, performing the - * basis transformations necessary to meet the CCSDS standard - * - * Copyright 2002, Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#define FIXED 1 -#include "ccsds.h" -#include "fixed.h" - -int decode_rs_ccsds(unsigned char* data, int* eras_pos, int no_eras) -{ - int i, r; - unsigned char cdata[NN]; - - /* Convert data from dual basis to conventional */ - for (i = 0; i < NN; i++) - cdata[i] = Tal1tab[data[i]]; - - r = decode_rs_8(cdata, eras_pos, no_eras); - - if (r > 0) { - /* Convert from conventional to dual basis */ - for (i = 0; i < NN; i++) - data[i] = Taltab[cdata[i]]; - } - return r; -} diff --git a/blocklib/fec/lib/reed-solomon/encode_rs.h b/blocklib/fec/lib/reed-solomon/encode_rs.h deleted file mode 100644 index 45e1ab720..000000000 --- a/blocklib/fec/lib/reed-solomon/encode_rs.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Reed-Solomon encoder - * Copyright 2002, Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -#include <string.h> - -void ENCODE_RS( -#ifndef FIXED - void* p, -#endif - DTYPE* data, - DTYPE* bb) -{ -#ifndef FIXED - struct rs* rs = (struct rs*)p; -#endif - unsigned int i, j; - DTYPE feedback; - - memset(bb, 0, NROOTS * sizeof(DTYPE)); - - for (i = 0; i < NN - NROOTS; i++) { - feedback = INDEX_OF[data[i] ^ bb[0]]; - if (feedback != A0) { /* feedback term is non-zero */ -#ifdef UNNORMALIZED - /* This line is unnecessary when GENPOLY[NROOTS] is unity, as it must - * always be for the polynomials constructed by init_rs() - */ - feedback = MODNN(NN - GENPOLY[NROOTS] + feedback); -#endif - for (j = 1; j < NROOTS; j++) -#ifdef FIXED - bb[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS - j])]; -#elif defined(BIGSYM) - // Same as above; keeping as a separate line in case these change. - bb[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS - j])]; -#else - bb[j] ^= ALPHA_TO[rs->modnn_table[feedback + GENPOLY[NROOTS - j]]]; -#endif - } - /* Shift */ - memmove(&bb[0], &bb[1], sizeof(DTYPE) * (NROOTS - 1)); - if (feedback != A0) -#ifdef FIXED - bb[NROOTS - 1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])]; -#elif defined(BIGSYM) - // Same as above; keeping as a separate line in case these change. - bb[NROOTS - 1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])]; -#else - bb[NROOTS - 1] = ALPHA_TO[rs->modnn_table[feedback + GENPOLY[0]]]; -#endif - else - bb[NROOTS - 1] = 0; - } -} diff --git a/blocklib/fec/lib/reed-solomon/encode_rs_ccsds.c b/blocklib/fec/lib/reed-solomon/encode_rs_ccsds.c deleted file mode 100644 index 7080b3f41..000000000 --- a/blocklib/fec/lib/reed-solomon/encode_rs_ccsds.c +++ /dev/null @@ -1,25 +0,0 @@ -/* This function wraps around the fixed 8-bit encoder, performing the - * basis transformations necessary to meet the CCSDS standard - * - * Copyright 2002, Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#define FIXED -#include "ccsds.h" -#include "fixed.h" - -void encode_rs_ccsds(unsigned char* data, unsigned char* parity) -{ - int i; - unsigned char cdata[NN - NROOTS]; - - /* Convert data from dual basis to conventional */ - for (i = 0; i < NN - NROOTS; i++) - cdata[i] = Tal1tab[data[i]]; - - encode_rs_8(cdata, parity); - - /* Convert parity from conventional to dual basis */ - for (i = 0; i < NN - NROOTS; i++) - parity[i] = Taltab[parity[i]]; -} diff --git a/blocklib/fec/lib/reed-solomon/exercise.c b/blocklib/fec/lib/reed-solomon/exercise.c deleted file mode 100644 index 598f485fe..000000000 --- a/blocklib/fec/lib/reed-solomon/exercise.c +++ /dev/null @@ -1,136 +0,0 @@ -/* Exercise an RS codec a specified number of times using random - * data and error patterns - * - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#define FLAG_ERASURE 1 /* Randomly flag 50% of errors as erasures */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef FIXED -#include "fixed.h" -#define EXERCISE exercise_8 -#elif defined(CCSDS) -#include "ccsds.h" -#include "fixed.h" -#define EXERCISE exercise_ccsds -#elif defined(BIGSYM) -#include "int.h" -#define EXERCISE exercise_int -#else -#include "char.h" -#define EXERCISE exercise_char -#endif - -#ifdef FIXED -#define PRINTPARM printf("(255,223):"); -#elif defined(CCSDS) -#define PRINTPARM printf("CCSDS (255,223):"); -#else -#define PRINTPARM printf("(%d,%d):", rs->nn, rs->nn - rs->nroots); -#endif - -/* Exercise the RS codec passed as an argument */ -int EXERCISE( -#if !defined(CCSDS) && !defined(FIXED) - void* p, -#endif - int trials) -{ -#if !defined(CCSDS) && !defined(FIXED) - struct rs* rs = (struct rs*)p; -#endif -#if MAX_ARRAY - DTYPE block[MAX_ARRAY], tblock[MAX_ARRAY]; - unsigned int i; - int errors; - int errlocs[MAX_ARRAY]; - int derrlocs[MAX_ARRAY]; -#else - DTYPE block[NN], tblock[NN]; - unsigned int i; - int errors; - int errlocs[NN]; - int derrlocs[NROOTS]; -#endif - int derrors; - int errval, errloc; - int erasures; - int decoder_errors = 0; - - while (trials-- != 0) { - /* Test up to the error correction capacity of the code */ - for (errors = 0; (unsigned int)errors <= NROOTS / 2; errors++) { - - /* Load block with random data and encode */ - for (i = 0; i < NN - NROOTS; i++) - block[i] = rand() & NN; - -#if defined(CCSDS) || defined(FIXED) - ENCODE_RS(&block[0], &block[NN - NROOTS]); -#else - ENCODE_RS(rs, &block[0], &block[NN - NROOTS]); -#endif - - /* Make temp copy, seed with errors */ - memcpy(tblock, block, sizeof(tblock)); - memset(errlocs, 0, sizeof(errlocs)); - memset(derrlocs, 0, sizeof(derrlocs)); - erasures = 0; - for (i = 0; i < (unsigned int)errors; i++) { - do { - errval = rand() & NN; - } while (errval == 0); /* Error value must be nonzero */ - - do { - errloc = rand() % NN; - } while (errlocs[errloc] != - 0); /* Must not choose the same location twice */ - - errlocs[errloc] = 1; - -#if FLAG_ERASURE - if (rand() & 1) /* 50-50 chance */ - derrlocs[erasures++] = errloc; -#endif - tblock[errloc] ^= errval; - } - - /* Decode the errored block */ -#if defined(CCSDS) || defined(FIXED) - derrors = DECODE_RS(tblock, derrlocs, erasures); -#else - derrors = DECODE_RS(rs, tblock, derrlocs, erasures); -#endif - - if (derrors != errors) { - PRINTPARM - printf(" decoder says %d errors, true number is %d\n", derrors, errors); - decoder_errors++; - } - for (i = 0; i < (unsigned int)derrors; i++) { - if (errlocs[derrlocs[i]] == 0) { - PRINTPARM - printf(" decoder indicates error in location %d without error\n", i); - decoder_errors++; - } - } - if (memcmp(tblock, block, sizeof(tblock)) != 0) { - PRINTPARM - printf(" uncorrected errors! output ^ input:"); - decoder_errors++; - for (i = 0; i < NN; i++) - printf(" %02x", tblock[i] ^ block[i]); - printf("\n"); - } - } - } - return decoder_errors; -} diff --git a/blocklib/fec/lib/reed-solomon/fixed.h b/blocklib/fec/lib/reed-solomon/fixed.h deleted file mode 100644 index feb3105b0..000000000 --- a/blocklib/fec/lib/reed-solomon/fixed.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Configure the RS codec with fixed parameters for CCSDS standard - * (255,223) code over GF(256). Note: the conventional basis is still - * used; the dual-basis mappings are performed in [en|de]code_rs_ccsds.c - * - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#define DTYPE unsigned char - -#include <gnuradio/fec/api.h> - -static inline int mod255(int x) -{ - while (x >= 255) { - x -= 255; - x = (x >> 8) + (x & 255); - } - return x; -} -#define MODNN(x) mod255(x) - -extern unsigned char CCSDS_alpha_to[]; -extern unsigned char CCSDS_index_of[]; -extern unsigned char CCSDS_poly[]; - -#define MM 8 -#define NN 255 -#define ALPHA_TO CCSDS_alpha_to -#define INDEX_OF CCSDS_index_of -#define GENPOLY CCSDS_poly -#define NROOTS 32 -#define FCR 112 -#define PRIM 11 -#define IPRIM 116 -#define A0 (NN) - -#define ENCODE_RS encode_rs_8 -#define DECODE_RS decode_rs_8 - -FEC_API void ENCODE_RS(DTYPE* data, DTYPE* parity); -FEC_API int DECODE_RS(DTYPE* data, int* eras_pos, int no_eras);
\ No newline at end of file diff --git a/blocklib/fec/lib/reed-solomon/gen_ccsds.c b/blocklib/fec/lib/reed-solomon/gen_ccsds.c deleted file mode 100644 index 8073278d8..000000000 --- a/blocklib/fec/lib/reed-solomon/gen_ccsds.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Generate tables for CCSDS code - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#include "char.h" -#include <stdio.h> - -int main() -{ - struct rs* rs; - int i; - - rs = init_rs_char(8, 0x187, 112, 11, 32); /* CCSDS standard */ - printf("unsigned char CCSDS_alpha_to[] = {"); - for (i = 0; i < 256; i++) { - if ((i % 16) == 0) - printf("\n"); - printf("0x%02x,", rs->alpha_to[i]); - } - printf("\n};\n\nunsigned char CCSDS_index_of[] = {"); - for (i = 0; i < 256; i++) { - if ((i % 16) == 0) - printf("\n"); - printf("%3d,", rs->index_of[i]); - } - printf("\n};\n\nunsigned char CCSDS_poly[] = {"); - for (i = 0; i < 33; i++) { - if ((i % 16) == 0) - printf("\n"); - - printf("%3d,", rs->genpoly[i]); - } - printf("\n};\n"); - exit(0); -} diff --git a/blocklib/fec/lib/reed-solomon/gen_ccsds_tal.c b/blocklib/fec/lib/reed-solomon/gen_ccsds_tal.c deleted file mode 100644 index 9db195d79..000000000 --- a/blocklib/fec/lib/reed-solomon/gen_ccsds_tal.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Conversion lookup tables from conventional alpha to Berlekamp's - * dual-basis representation. Used in the CCSDS version only. - * taltab[] -- convert conventional to dual basis - * tal1tab[] -- convert dual basis to conventional - - * Note: the actual RS encoder/decoder works with the conventional basis. - * So data is converted from dual to conventional basis before either - * encoding or decoding and then converted back. - * - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#include <stdio.h> -unsigned char Taltab[256], Tal1tab[256]; - -static unsigned char tal[] = { 0x8d, 0xef, 0xec, 0x86, 0xfa, 0x99, 0xaf, 0x7b }; - -/* Generate conversion lookup tables between conventional alpha representation - * (@**7, @**6, ...@**0) - * and Berlekamp's dual basis representation - * (l0, l1, ...l7) - */ -int main() -{ - int i, j, k; - - for (i = 0; i < 256; i++) { /* For each value of input */ - Taltab[i] = 0; - for (j = 0; j < 8; j++) /* for each column of matrix */ - for (k = 0; k < 8; k++) { /* for each row of matrix */ - if (i & (1 << k)) - Taltab[i] ^= tal[7 - k] & (1 << j); - } - Tal1tab[Taltab[i]] = i; - } - printf("unsigned char Taltab[] = {\n"); - for (i = 0; i < 256; i++) { - if ((i % 16) == 0) - printf("\n"); - printf("0x%02x,", Taltab[i]); - } - printf("\n};\n\nunsigned char Tal1tab[] = {"); - for (i = 0; i < 256; i++) { - if ((i % 16) == 0) - printf("\n"); - printf("0x%02x,", Tal1tab[i]); - } - printf("\n};\n"); - exit(0); -} diff --git a/blocklib/fec/lib/reed-solomon/init_rs.c b/blocklib/fec/lib/reed-solomon/init_rs.c deleted file mode 100644 index 11a89d1be..000000000 --- a/blocklib/fec/lib/reed-solomon/init_rs.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Initialize a RS codec - * - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#include <stdlib.h> - -#ifdef CCSDS -#include "ccsds.h" -#elif defined(BIGSYM) -#include "int.h" -#else -#include "char.h" -#endif - -#ifndef NULL -#define NULL ((void*)0) -#endif - -void FREE_RS(void* p) -{ - struct rs* rs = (struct rs*)p; - - free(rs->alpha_to); - free(rs->index_of); - free(rs->genpoly); -#ifdef FIXED -#elif defined(BIGSYM) -#else - free(rs->modnn_table); -#endif - free(rs); -} - -/* Initialize a Reed-Solomon codec - * symsize = symbol size, bits (1-8) - * gfpoly = Field generator polynomial coefficients - * fcr = first root of RS code generator polynomial, index form - * prim = primitive element to generate polynomial roots - * nroots = RS code generator polynomial degree (number of roots) - */ -void* INIT_RS(unsigned int symsize, - unsigned int gfpoly, - unsigned fcr, - unsigned prim, - unsigned int nroots) -{ - struct rs* rs; - int sr, root, iprim; - unsigned int i, j; - - if (symsize > 8 * sizeof(DTYPE)) - return NULL; /* Need version with ints rather than chars */ - - if (fcr >= (1u << symsize)) - return NULL; - if (prim == 0 || prim >= (1u << symsize)) - return NULL; - if (nroots >= (1u << symsize)) - return NULL; /* Can't have more roots than symbol values! */ - - rs = (struct rs*)calloc(1, sizeof(struct rs)); - if (rs == NULL) - return NULL; - rs->mm = symsize; - rs->nn = (1 << symsize) - 1; - - rs->alpha_to = (DTYPE*)malloc(sizeof(DTYPE) * (rs->nn + 1)); - if (rs->alpha_to == NULL) { - free(rs); - return NULL; - } - rs->index_of = (DTYPE*)malloc(sizeof(DTYPE) * (rs->nn + 1)); - if (rs->index_of == NULL) { - free(rs->alpha_to); - free(rs); - return NULL; - } - - /* Generate Galois field lookup tables */ - rs->index_of[0] = A0; /* log(zero) = -inf */ - rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ - sr = 1; - for (i = 0; i < rs->nn; i++) { - rs->index_of[sr] = i; - rs->alpha_to[i] = sr; - sr <<= 1; - if (sr & (1 << symsize)) - sr ^= gfpoly; - sr &= rs->nn; - } - if (sr != 1) { - /* field generator polynomial is not primitive! */ - free(rs->alpha_to); - free(rs->index_of); - free(rs); - return NULL; - } - - /* Form RS code generator polynomial from its roots */ - rs->genpoly = (DTYPE*)malloc(sizeof(DTYPE) * (nroots + 1)); - if (rs->genpoly == NULL) { - free(rs->alpha_to); - free(rs->index_of); - free(rs); - return NULL; - } - rs->fcr = fcr; - rs->prim = prim; - rs->nroots = nroots; - - /* Find prim-th root of 1, used in decoding */ - for (iprim = 1; (iprim % prim) != 0; iprim += rs->nn) - ; - rs->iprim = iprim / prim; - - rs->genpoly[0] = 1; - for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) { - rs->genpoly[i + 1] = 1; - - /* Multiply rs->genpoly[] by @**(root + x) */ - for (j = i; j > 0; j--) { - if (rs->genpoly[j] != 0) - rs->genpoly[j] = - rs->genpoly[j - 1] ^ - rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[j]] + root)]; - else - rs->genpoly[j] = rs->genpoly[j - 1]; - } - /* rs->genpoly[0] can never be zero */ - rs->genpoly[0] = rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[0]] + root)]; - } - /* convert rs->genpoly[] to index form for quicker encoding */ - for (i = 0; i <= nroots; i++) - rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; - -#ifdef FIXED -#elif defined(BIGSYM) -#else - /* Form modnn lookup table */ - rs->modnn_table = (int*)malloc(sizeof(int) * (2 << ((sizeof(unsigned char)) * 8))); - if (rs->modnn_table == NULL) { - free(rs->genpoly); - free(rs->alpha_to); - free(rs->index_of); - free(rs); - return NULL; - } - for (i = 0; i < (2 << ((sizeof(unsigned char)) * 8)); i++) { - j = i; - rs->modnn_table[i] = modnn(rs, j); - } -#endif - -#if 0 - printf ("genpoly:\n"); - for (i = nroots; i >= 0; i--){ - printf (" %3d*X^%d\n", rs->alpha_to[rs->genpoly[i]], i); - } -#endif - - return rs; -} diff --git a/blocklib/fec/lib/reed-solomon/int.h b/blocklib/fec/lib/reed-solomon/int.h deleted file mode 100644 index 80dd50d3f..000000000 --- a/blocklib/fec/lib/reed-solomon/int.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Include file to configure the RS codec for integer symbols - * - * Copyright 2002, Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#define DTYPE int - -#include <gnuradio/fec/api.h> - -/* Reed-Solomon codec control block */ -struct FEC_API rs { - unsigned int mm; /* Bits per symbol */ - unsigned int nn; /* Symbols per block (= (1<<mm)-1) */ - int* alpha_to; /* log lookup table */ - int* index_of; /* Antilog lookup table */ - int* genpoly; /* Generator polynomial */ - unsigned int nroots; /* Number of generator roots = number of parity symbols */ - unsigned int fcr; /* First consecutive root, index form */ - unsigned int prim; /* Primitive element, index form */ - unsigned int iprim; /* prim-th root of 1, index form */ -}; - -static inline int modnn(struct rs* rs, int x) -{ - while (x >= rs->nn) { - x -= rs->nn; - x = (x >> rs->mm) + (x & rs->nn); - } - return x; -} -#define MODNN(x) modnn(rs, x) - -#define MM (rs->mm) -#define NN (rs->nn) -#define ALPHA_TO (rs->alpha_to) -#define INDEX_OF (rs->index_of) -#define GENPOLY (rs->genpoly) -#define NROOTS (rs->nroots) -#define FCR (rs->fcr) -#define PRIM (rs->prim) -#define IPRIM (rs->iprim) -#define A0 (NN) - -#define ENCODE_RS encode_rs_int -#define DECODE_RS decode_rs_int -#define INIT_RS init_rs_int -#define FREE_RS free_rs_int - -FEC_API void ENCODE_RS(void* p, DTYPE* data, DTYPE* parity); -FEC_API int DECODE_RS(void* p, DTYPE* data, int* eras_pos, int no_eras); -void* INIT_RS(unsigned int symsize, - unsigned int gfpoly, - unsigned int fcr, - unsigned int prim, - unsigned int nroots); -FEC_API void FREE_RS(void* p); diff --git a/blocklib/fec/lib/reed-solomon/meson.build b/blocklib/fec/lib/reed-solomon/meson.build deleted file mode 100644 index c5d99a910..000000000 --- a/blocklib/fec/lib/reed-solomon/meson.build +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2010-2012 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -# ######################################################################## -# # This file included, use CMake directory variables -# ######################################################################## -# #MSVC workaround: we can't have dynamically sized arrays. -# #So ifdef a max array bounds that is larger than NN and NROOTS -# #Its a bit of a hack, but if you look at the code, its so full of ifdefs, -# #and lacks optimization where it should be pre-allocating these arrays. -# if(MSVC) -# set_source_files_properties( -# ${CMAKE_CURRENT_SOURCE_DIR}/exercise.c -# ${CMAKE_CURRENT_SOURCE_DIR}/char.c -# PROPERTIES COMPILE_DEFINITIONS "MAX_ARRAY=256;" -# ) -# endif(MSVC) - -# add_library(gr_fec_rs OBJECT -# ${CMAKE_CURRENT_SOURCE_DIR}/ccsds.c -# ${CMAKE_CURRENT_SOURCE_DIR}/ccsds_tab.c -# ${CMAKE_CURRENT_SOURCE_DIR}/ccsds_tal.c -# ${CMAKE_CURRENT_SOURCE_DIR}/char.c -# ${CMAKE_CURRENT_SOURCE_DIR}/decode_rs_ccsds.c -# ${CMAKE_CURRENT_SOURCE_DIR}/encode_rs_ccsds.c -# ${CMAKE_CURRENT_SOURCE_DIR}/init_rs.c -# ) -# target_include_directories(gr_fec_rs -# PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include> -# PRIVATE $<TARGET_PROPERTY:gnuradio-runtime,INCLUDE_DIRECTORIES> -# ) -# set_target_properties(gr_fec_rs PROPERTIES POSITION_INDEPENDENT_CODE ON) - -sources = [ - 'ccsds.c','ccsds_tab.c','ccsds_tal.c','char.c','decode_rs_ccsds.c','encode_rs_ccsds.c','init_rs.c' -] - -incdir = include_directories(['../../include/gnuradio/fec','../../include']) - -gnuradio_blocklib_fec_lib = library('gnuradio-blocklib-fec', - sources, - include_directories : incdir, - install : true, - dependencies : [gnuradio_gr_dep], - pic : true) - -gnuradio_blocklib_fec_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_fec_lib) - - -# target_sources(gnuradio-fec PRIVATE $<TARGET_OBJECTS:gr_fec_rs>) - -# ######################################################################## -# # Register unit tests -# ######################################################################## -# if(ENABLE_TESTING) -# add_executable(gr_fec_rstest -# ${CMAKE_CURRENT_SOURCE_DIR}/exercise.c -# ${CMAKE_CURRENT_SOURCE_DIR}/rstest.c -# $<TARGET_OBJECTS:gr_fec_rs> -# ) -# target_link_libraries(gr_fec_rstest gnuradio-runtime) -# target_include_directories(gr_fec_rstest -# PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include -# ) -# add_test(test_rs gr_fec_rstest) -# endif(ENABLE_TESTING) diff --git a/blocklib/fec/lib/reed-solomon/rs.3 b/blocklib/fec/lib/reed-solomon/rs.3 deleted file mode 100644 index c3953ce57..000000000 --- a/blocklib/fec/lib/reed-solomon/rs.3 +++ /dev/null @@ -1,170 +0,0 @@ -.TH REED-SOLOMON 3 -.SH NAME -init_rs_int, encode_rs_int, decode_rs_int, free_rs_int, -init_rs_char, encode_rs_char, decode_rs_char, free_rs_char, -encode_rs_8, decode_rs_8, encode_rs_ccsds, decode_rs_ccsds -.SH SYNOPSIS -.nf -.ft B -#include "rs.h" - -void *init_rs_int(unsigned int symsize,unsigned int gfpoly,unsigned fcr, -unsigned prim,unsigned int nroots); -void encode_rs_int(void *rs,int *data,int *parity); -int decode_rs_int(void *rs,int *data,int *eras_pos,int no_eras); -void free_rs_int(void *rs); - -void *init_rs_char(unsigned int symsize,unsigned int gfpoly,unsigned fcr, -unsigned prim,unsigned int nroots); -void encode_rs_char(void *rs,unsigned char *data,unsigned char *parity); -int decode_rs_char(void *rs,unsigned char *data,int *eras_pos,int no_eras); -void free_rs_char(void *rs); - -void encode_rs_8(unsigned char *data,unsigned char *parity); -int decode_rs_8(unsigned char *data,int *eras_pos,int no_eras); - -void encode_rs_ccsds(unsigned char *data,unsigned char *parity); -int decode_rs_ccsds(unsigned char *data,int *eras_pos,int no_eras); - -unsigned char Taltab[256]; -unsigned char Tal1tab[256]; - -.fi - -.SH DESCRIPTION -These functions implement Reed-Solomon error control encoding and -decoding. For optimal performance in a variety of applications, three -sets of functions are supplied. To access these functions, add "-lrs" -to your linker command line. - -The functions with names ending in "_int" handle data in integer arrays, -permitting arbitrarily large codewords limited only by machine -resources. - -The functions with names ending in "_char" take unsigned char arrays and can -handle codes with symbols of 8 bits or less (i.e., with codewords of -255 symbols or less). - -\fBencode_rs_8\fR and \fBdecode_rs_8\fR implement a specific -(255,223) code with 8-bit symbols specified by the CCSDS: -a field generator of 1 + X + X^2 + X^7 + X^8 and a code -generator with first consecutive root = 112 and a primitive element of -11. These functions use the conventional -polynomial form, \fBnot\fR the dual-basis specified in -the CCSDS standard, to represent symbols. - -For full CCSDS compatibility, \fBencode_rs_ccsds\fR and -\fBdecode_rs_ccsds\fR are provided. These functions use two lookup -tables, \fBTaltab\fR to convert from conventional to dual-basis, and -\fBTal1tab\fR to perform the inverse mapping from dual-basis to -conventional form, before and after calls to \fBencode_rs_8\fR -and \fBdecode_rs_8\fR. - -The _8 and _ccsds functions do not require initialization. -To use the general purpose RS encoder or decoder (i.e., -the _char or _int versions), the user must first -call \fBinit_rs_int\fR or \fBinit_rs_char\fR as appropriate. The -arguments are as follows: - -\fBsymsize\fR gives the symbol size in bits, up to 8 for \fBinit_rs_char\fR -or 32 for \fBinit_rs_int\fR on a machine with 32-bit ints (though such a -huge code would exhaust memory limits on a 32-bit machine). The resulting -Reed-Solomon code word will have 2^\fBsymsize\fR - 1 symbols, -each containing \fBsymsize\fR bits. - -\fBgfpoly\fR gives the extended Galois field generator polynomial coefficients, -with the 0th coefficient in the low order bit. The polynomial -\fImust\fR be primitive; if not, the call will fail and NULL will be -returned. - -\fBfcr\fR gives, in index form, the first consecutive root of the -Reed Solomon code generator polynomial. - -\fBprim\fR gives, in index form, the primitive element in the Galois field -used to generate the Reed Solomon code generator polynomial. - -\fBnroots\fR gives the number of roots in the Reed Solomon code -generator polynomial. This equals the number of parity symbols -per code block. - -The resulting Reed-Solomon code has parameters (N,K), where -N = 2^\fBsymsize\fR-1 and K = N-\fBnroots\fR. - -The \fBencode_rs_char\fR and \fBencode_rs_int\fR functions accept -the pointer returned by \fBinit_rs_char\fR or -\fBinit_rs_int\fR, respectively, to -encode a block of data using the specified code. -The input data array is expected to -contain K symbols (of \fBsymsize\fR bits each, right justified -in each char or int) and \fBnroots\fR parity symbols will be placed -into the \fBparity\fR array, right justified. - -The \fBdecode_rs_char\fR and \fBdecode_rs_int\fR functions correct -the errors in a Reed-Solomon codeword up to the capability of the code. -An optional list of "erased" symbol indices may be given in the \fBeras_pos\fR -array to assist the decoder; this parameter may be NULL if no erasures -are given. The number of erased symbols must be given in the \fBno_eras\fR -parameter. - -To maximize performance, the encode and decode functions perform no -"sanity checking" of their inputs. Decoder failure may result if -\fBeras_pos\fR contains duplicate entries, and both encoder and -decoder will fail if an input symbol exceeds its allowable range. -(Symbol range overflow cannot occur with the _8 or _ccsds functions, -or with the _char functions when 8-bit symbols are specified.) - -The decoder corrects the symbols "in place", returning the number -of symbols in error. If the codeword is uncorrectable, -1 is returned -and the data block is unchanged. If \fBeras_pos\fR is non-null, it is -used to return a list of corrected symbol positions, in no particular -order. This means that the -array passed through this parameter \fImust\fR have at least \fBnroots\fR -elements to prevent a possible buffer overflow. - -The \fBfree_rs_int\fR and \fBfree_rs_char\fR functions free the internal -space allocated by the \fBinit_rs_int\fR and \fBinit_rs_char\fR functions, -respecitively. - -The functions \fBencode_rs_8\fR and \fBdecode_rs_8\fR do not have -corresponding \fBinit\fR and \fBfree\fR, nor do they take the -\fBrs\fR argument accepted by the other functions as their parameters -are statically compiled. These functions implement a code -equivalent to calling - -\fBinit_rs_char\fR(8,0x187,112,11,32); - -and using the resulting pointer with \fBencode_rs_char\fR and -\fBdecode_rs_char\fR. - -.SH RETURN VALUES -\fBinit_rs_int\fR and \fBinit_rs_char\fR return a pointer to an internal -control structure that must be passed to the corresponding encode, decode -and free functions. These functions return NULL on error. - -The decode functions return a count of corrected -symbols, or -1 if the block was uncorrectible. - -.SH AUTHOR -Phil Karn, KA9Q (karn@ka9q.net), based heavily on earlier work by Robert -Morelos-Zaragoza (rober@spectra.eng.hawaii.edu) and Hari Thirumoorthy -(harit@spectra.eng.hawaii.edu). - -.SH COPYRIGHT -Copyright 2002, Phil Karn, KA9Q. May be used under the terms of the -GNU General Public License (GPL). - -.SH SEE ALSO -CCSDS 101.0-B-5: Telemetry Channel Coding. -http://www.ccsds.org/documents/pdf/CCSDS-101.0-B-5.pdf - -.SH NOTE -CCSDS chose the "dual basis" symbol representation because it -simplified the implementation of a Reed-Solomon encoder in dedicated -hardware. However, this approach holds no advantages for a software -implementation on a general purpose computer, so use of the dual basis -is recommended only if compatibility with the CCSDS standard is needed, -e.g., to decode data from an existing spacecraft using the CCSDS -standard. If you just want a fast (255,223) RS codec without needing -to interoperate with a CCSDS standard code, use \fBencode_rs_8\fR -and \fBdecode_rs_8\fR. - diff --git a/blocklib/fec/lib/reed-solomon/rstest.c b/blocklib/fec/lib/reed-solomon/rstest.c deleted file mode 100644 index cfc2d62bc..000000000 --- a/blocklib/fec/lib/reed-solomon/rstest.c +++ /dev/null @@ -1,123 +0,0 @@ -/* Test the Reed-Solomon codecs - * for various block sizes and with random data and random error patterns - * - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gnuradio/fec/rs.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -int exercise_char(void*, int); - -#ifdef ALL_VERSIONS -int exercise_int(void*, int); -int exercise_8(int); -int exercise_ccsds(int); -#endif - -struct { - int symsize; - int genpoly; - int fcs; - int prim; - int nroots; - int ntrials; -} Tab[] = { - { 2, 0x7, 1, 1, 1, 10 }, - { 3, 0xb, 1, 1, 2, 10 }, - { 4, 0x13, 1, 1, 4, 10 }, - { 5, 0x25, 1, 1, 6, 10 }, - { 6, 0x43, 1, 1, 8, 10 }, - { 7, 0x89, 1, 1, 10, 10 }, - { 8, 0x11d, 1, 1, 32, 10 }, - { 8, 0x187, 112, 11, 32, 10 }, /* Duplicates CCSDS codec */ -#ifdef ALL_VESIONS - { 9, 0x211, 1, 1, 32, 10 }, - { 10, 0x409, 1, 1, 32, 10 }, - { 11, 0x805, 1, 1, 32, 10 }, - { 12, 0x1053, 1, 1, 32, 5 }, - { 13, 0x201b, 1, 1, 32, 2 }, - { 14, 0x4443, 1, 1, 32, 1 }, - { 15, 0x8003, 1, 1, 32, 1 }, - { 16, 0x1100b, 1, 1, 32, 1 }, -#endif - { 0, 0, 0, 0, 0 }, -}; - -int main() -{ - void* handle; - int errs, terrs; - int i; - - terrs = 0; - srand(time(NULL)); - -#ifdef ALL_VERSIONS - printf("Testing fixed (255,223) RS codec..."); - fflush(stdout); - errs = exercise_8(10); - terrs += errs; - if (errs == 0) { - printf("OK\n"); - } - printf("Testing CCSDS standard (255,223) RS codec..."); - fflush(stdout); - errs = exercise_ccsds(10); - terrs += errs; - if (errs == 0) { - printf("OK\n"); - } -#endif - - for (i = 0; Tab[i].symsize != 0; i++) { - int nn, kk; - - nn = (1 << Tab[i].symsize) - 1; - kk = nn - Tab[i].nroots; - printf("Testing (%d,%d) RS codec...", nn, kk); - fflush(stdout); - if (Tab[i].symsize <= 8) { - if ((handle = init_rs_char(Tab[i].symsize, - Tab[i].genpoly, - Tab[i].fcs, - Tab[i].prim, - Tab[i].nroots)) == NULL) { - printf("init_rs_char failed!\n"); - continue; - } - errs = exercise_char(handle, Tab[i].ntrials); - } else { -#ifdef ALL_VERSIONS - if ((handle = init_rs_int(Tab[i].symsize, - Tab[i].genpoly, - Tab[i].fcs, - Tab[i].prim, - Tab[i].nroots)) == NULL) { - printf("init_rs_int failed!\n"); - continue; - } - errs = exercise_int(handle, Tab[i].ntrials); -#else - printf("init_rs_init support is not enabled\n"); - exit(1); -#endif - } - terrs += errs; - if (errs == 0) { - printf("OK\n"); - } - free_rs_char(handle); - } - if (terrs == 0) - printf("All codec tests passed!\n"); - - exit(0); -} diff --git a/blocklib/fec/meson.build b/blocklib/fec/meson.build deleted file mode 100644 index 0aa86b5b9..000000000 --- a/blocklib/fec/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -subdir('include/gnuradio/fec') - -fec_sources = [] -fec_cu_sources = [] -fec_pybind_sources = [] -fec_pybind_names = [] -fec_deps = [] - -# Individual block subdirectories - - -subdir('lib') -# if (get_option('enable_python')) -# subdir('python/fec') -# endif - -# if (get_option('enable_testing')) -# subdir('test') -# endif
\ No newline at end of file diff --git a/blocklib/fec/python/gnuradio/fec/meson.build b/blocklib/fec/python/gnuradio/fec/meson.build deleted file mode 100644 index e69de29bb..000000000 --- a/blocklib/fec/python/gnuradio/fec/meson.build +++ /dev/null diff --git a/blocklib/fft/.gitignore b/blocklib/fft/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/fft/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/fft/bench/bm_fft.py b/blocklib/fft/bench/bm_fft.py deleted file mode 100644 index a6c13659c..000000000 --- a/blocklib/fft/bench/bm_fft.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# -# SPDX-License-Identifier: GPL-3.0 -# -# GNU Radio Python Flow Graph -# Title: Not titled yet -# GNU Radio version: 3.9.0.0-git - -from gnuradio import gr, blocks, streamops, fft -from gnuradio.kernel.filter import firdes -from gnuradio.schedulers import nbt -import sys -import signal -from argparse import ArgumentParser -from gnuradio.fft import window -import time -from gnuradio import filter - - -class benchmark_cuda_fft(gr.flowgraph): - - def __init__(self, args): - gr.flowgraph.__init__(self) - - ################################################## - # Variables - ################################################## - nsamples = args.samples - nblocks = args.nblocks - fftsize = args.fft_size - bufsize = args.buffer_size - - ################################################## - # Blocks - ################################################## - self.nsrc = blocks.null_source(gr.sizeof_gr_complex*fftsize) - self.nsnk = blocks.null_sink(gr.sizeof_gr_complex*fftsize) - self.hd = streamops.head(gr.sizeof_gr_complex * - fftsize, int(nsamples) // fftsize) - - blks = [] - if not args.cuda: - for ii in range(nblocks): - if ii % 2 == 0: - blks.append(fft.fft_cc_fwd(fftsize, [], False)) - else: - blks.append(fft.fft_cc_rev(fftsize, [], False)) - if (ii > 0): - self.connect(blks[ii-1], 0, blks[ii], 0) - - self.connect(self.hd, 0, blks[0], 0) - self.connect(self.nsrc, 0, self.hd, 0) - self.connect(blks[nblocks-1], 0, self.nsnk, 0) - else: - for ii in range(nblocks): - if ii % 2 == 0: - blks.append(fft.fft_cc_fwd(fftsize, [], False)) - else: - blks.append(fft.fft_cc_rev(fftsize, [], False)) - if (ii > 0): - self.connect(blks[ii-1], 0, blks[ii], 0).set_custom_buffer( - gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2D).set_buffer_size(bufsize)) - - self.connect(self.hd, 0, self.blks[0], 0) .set_custom_buffer( - gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H).set_buffer_size(bufsize)) - self.connect(self.nsrc, 0, self.hd, 0).set_custom_buffer( - gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D).set_buffer_size(bufsize)) - self.connect(blks[nblocks-1], 0, self.nsnk).set_custom_buffer( - gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D).set_buffer_size(bufsize)) - - # sched = nbt.scheduler_nbt("nbtsched") - # self.add_scheduler(sched) - # sched.add_block_group([x.base() for x in nsnks]) - - # self.validate() - - -def main(top_block_cls=benchmark_cuda_fft, options=None): - - parser = ArgumentParser( - description='Run a flowgraph iterating over parameters for benchmarking') - parser.add_argument( - '--rt_prio', help='enable realtime scheduling', action='store_true') - parser.add_argument('--samples', type=int, default=1e8) - parser.add_argument('--nblocks', type=int, default=4) - parser.add_argument('--fft_size', type=int, default=1024) - parser.add_argument('--buffer_size', type=int, default=8192) - parser.add_argument('--cuda', action='store_true') - - args = parser.parse_args() - print(args) - - if args.rt_prio and gr.enable_realtime_scheduling() != gr.RT_OK: - print("Error: failed to enable real-time scheduling.") - - tb = top_block_cls(args) - - def sig_handler(sig=None, frame=None): - tb.stop() - tb.wait() - sys.exit(0) - - signal.signal(signal.SIGINT, sig_handler) - signal.signal(signal.SIGTERM, sig_handler) - - print("starting ...") - startt = time.time() - tb.start() - - tb.wait() - endt = time.time() - print(f'[PROFILE_TIME]{endt-startt}[PROFILE_TIME]') - - -if __name__ == '__main__': - main() diff --git a/blocklib/fft/fft/fft.yml b/blocklib/fft/fft/fft.yml deleted file mode 100644 index 03aac8424..000000000 --- a/blocklib/fft/fft/fft.yml +++ /dev/null @@ -1,54 +0,0 @@ -module: fft -block: fft -label: FFT -blocktype: sync_block -category: '[Core]/Fourier Analysis' - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - - id: direction - type: bool - label: Direction - options: - - ['true','_fwd'] - - ['false','_rev'] - - -parameters: -- id: fft_size - label: FFT Size - dtype: size - settable: false -- id: window - label: Window - dtype: rf32 - container: vector - settable: false -- id: shift - label: Shift - dtype: bool - default: 'false' - settable: false - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - shape: parameters/fft_size - -- domain: stream - id: out - direction: output - type: typekeys/T - shape: parameters/fft_size - -implementations: -- id: cpu -- id: cuda - -file_format: 1 diff --git a/blocklib/fft/fft/fft_cpu.cc b/blocklib/fft/fft/fft_cpu.cc deleted file mode 100644 index 9f51276bf..000000000 --- a/blocklib/fft/fft/fft_cpu.cc +++ /dev/null @@ -1,198 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2007,2008,2010,2012,2020 Free Software Foundation, Inc. - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "fft_cpu.h" -#include "fft_cpu_gen.h" - -namespace gr { -namespace fft { - -template <class T, bool forward> -fft_cpu<T, forward>::fft_cpu(const typename fft<T, forward>::block_args& args) - : INHERITED_CONSTRUCTORS(T, forward), - d_fft_size(args.fft_size), - d_shift(args.shift), - d_fft(args.fft_size) -{ - if (args.window.empty() || args.window.size() == d_fft_size) { - d_window = args.window; - } - else { - throw std::runtime_error("fft: window not the same length as fft_size"); - } -} - -template <class T, bool forward> -void fft_cpu<T, forward>::set_nthreads(int n) -{ - d_fft.set_nthreads(n); -} - -template <class T, bool forward> -int fft_cpu<T, forward>::nthreads() const -{ - return d_fft.nthreads(); -} - -template <> -void fft_cpu<gr_complex, true>::fft_and_shift(const gr_complex* in, gr_complex* out) -{ - if (!d_window.empty()) { - gr_complex* dst = d_fft.get_inbuf(); - volk_32fc_32f_multiply_32fc(&dst[0], in, &d_window[0], d_fft_size); - } - else { - memcpy(d_fft.get_inbuf(), in, sizeof(gr_complex) * d_fft_size); - } - d_fft.execute(); - if (d_shift) { - unsigned int len = (unsigned int)(ceil(d_fft_size / 2.0)); - memcpy( - &out[0], &d_fft.get_outbuf()[len], sizeof(gr_complex) * (d_fft_size - len)); - memcpy(&out[d_fft_size - len], &d_fft.get_outbuf()[0], sizeof(gr_complex) * len); - } - else { - - memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size); - } -} - -template <> -void fft_cpu<gr_complex, false>::fft_and_shift(const gr_complex* in, gr_complex* out) -{ - if (!d_window.empty()) { - gr_complex* dst = d_fft.get_inbuf(); - if (d_shift) { - unsigned int offset = d_fft_size / 2; - int fft_m_offset = d_fft_size - offset; - volk_32fc_32f_multiply_32fc(&dst[fft_m_offset], &in[0], &d_window[0], offset); - volk_32fc_32f_multiply_32fc( - &dst[0], &in[offset], &d_window[offset], d_fft_size - offset); - } - else { - volk_32fc_32f_multiply_32fc(&dst[0], in, &d_window[0], d_fft_size); - } - } - else { - if (d_shift) { // apply an ifft shift on the data - gr_complex* dst = d_fft.get_inbuf(); - unsigned int len = - (unsigned int)(floor(d_fft_size / 2.0)); // half length of complex array - memcpy(&dst[0], &in[len], sizeof(gr_complex) * (d_fft_size - len)); - memcpy(&dst[d_fft_size - len], &in[0], sizeof(gr_complex) * len); - } - else { - memcpy(d_fft.get_inbuf(), in, sizeof(gr_complex) * d_fft_size); - } - } - d_fft.execute(); - memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size); -} - -template <> -void fft_cpu<float, true>::fft_and_shift(const float* in, gr_complex* out) -{ - // copy input into optimally aligned buffer - if (!d_window.empty()) { - gr_complex* dst = d_fft.get_inbuf(); - for (unsigned int i = 0; i < d_fft_size; i++) // apply window - dst[i] = in[i] * d_window[i]; - } - else { - gr_complex* dst = d_fft.get_inbuf(); - for (unsigned int i = 0; i < d_fft_size; i++) // float to complex conversion - dst[i] = in[i]; - } - - d_fft.execute(); - if (d_shift) { - unsigned int len = (unsigned int)(ceil(d_fft_size / 2.0)); - memcpy( - &out[0], &d_fft.get_outbuf()[len], sizeof(gr_complex) * (d_fft_size - len)); - memcpy(&out[d_fft_size - len], &d_fft.get_outbuf()[0], sizeof(gr_complex) * len); - } - else { - - memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size); - } -} - -template <> -void fft_cpu<float, false>::fft_and_shift(const float* in, gr_complex* out) -{ - // copy input into optimally aligned buffer - if (!d_window.empty()) { - gr_complex* dst = d_fft.get_inbuf(); - if (d_shift) { - unsigned int len = - (unsigned int)(floor(d_fft_size / 2.0)); // half length of complex array - for (unsigned int i = 0; i < len; i++) { - dst[i] = in[len + i] * d_window[len + i]; - } - for (unsigned int i = len; i < d_fft_size; i++) { - dst[i] = in[i - len] * d_window[i - len]; - } - } - else { - for (unsigned int i = 0; i < d_fft_size; i++) // apply window - dst[i] = in[i] * d_window[i]; - } - } - else { - gr_complex* dst = d_fft.get_inbuf(); - if (d_shift) { - unsigned int len = - (unsigned int)(floor(d_fft_size / 2.0)); // half length of complex array - for (unsigned int i = 0; i < len; i++) { - dst[i] = in[len + i]; - } - for (unsigned int i = len; i < d_fft_size; i++) { - dst[i] = in[i - len]; - } - } - else { - for (unsigned int i = 0; i < d_fft_size; i++) // float to complex conversion - dst[i] = in[i]; - } - } - - // compute the fft - d_fft.execute(); - - // copy result to output stream - memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size); -} - -template <class T, bool forward> -work_return_t fft_cpu<T, forward>::work(work_io& wio) -{ - auto in = wio.inputs()[0].items<T>(); - auto out = wio.outputs()[0].items<gr_complex>(); - auto noutput_items = wio.outputs()[0].n_items; - - size_t count = 0; - - while (count++ < noutput_items) { - - fft_and_shift(in, out); - - in += d_fft_size; - out += d_fft_size; - } - - - wio.produce_each(noutput_items); - return work_return_t::OK; -} - - -} // namespace fft -} // namespace gr
\ No newline at end of file diff --git a/blocklib/fft/fft/fft_cpu.h b/blocklib/fft/fft/fft_cpu.h deleted file mode 100644 index 186eb33ee..000000000 --- a/blocklib/fft/fft/fft_cpu.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2007,2008,2012,2020 Free Software Foundation, Inc. - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/fft/fft.h> -#include <gnuradio/kernel/fft/fftw_fft.h> - -namespace gr { -namespace fft { - -template <class T, bool forward> -class fft_cpu : public fft<T, forward> -{ -public: - fft_cpu(const typename fft<T, forward>::block_args& args); - work_return_t work(work_io&) override; - - void set_nthreads(int n); - int nthreads() const; - -protected: - size_t d_fft_size; - std::vector<float> d_window; - bool d_shift; - - kernel::fft::fftw_fft<gr_complex, forward> d_fft; - - void fft_and_shift(const T* in, gr_complex* out); -}; - -} // namespace fft -} // namespace gr
\ No newline at end of file diff --git a/blocklib/fft/fft/fft_cuda.cc b/blocklib/fft/fft/fft_cuda.cc deleted file mode 100644 index 5b4eeebad..000000000 --- a/blocklib/fft/fft/fft_cuda.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "fft_cuda.h" -#include "fft_cuda_gen.h" - - -extern void exec_fft_shift(const cuFloatComplex* in, - cuFloatComplex* out, - int n, - int grid_size, - int block_size, - cudaStream_t stream); - -namespace gr { -namespace fft { - -template <class T, bool forward> -fft_cuda<T, forward>::fft_cuda(const typename fft<T, forward>::block_args& args) - : INHERITED_CONSTRUCTORS(T, forward), - d_fft_size(args.fft_size), - d_shift(args.shift), - d_fft(args.fft_size) -{ - if (args.window.empty() || args.window.size() == d_fft_size) { - d_window = args.window; - } - else { - throw std::runtime_error("fft: window not the same length as fft_size"); - } - - cudaStreamCreate(&d_stream); -} - - -template <> -void fft_cuda<gr_complex, true>::fft_and_shift(const gr_complex* in, - gr_complex* out, - int batch) -{ - int blockSize = 1024; - int gridSize = (batch * d_fft_size + blockSize - 1) / blockSize; - if (d_shift) - exec_fft_shift((cuFloatComplex*)in, - (cuFloatComplex*)in, - batch * d_fft_size, - gridSize, - blockSize, - d_stream); - d_fft.launch(in, out, batch, d_stream); -} - -template <> -void fft_cuda<gr_complex, false>::fft_and_shift(const gr_complex* in, - gr_complex* out, - int batch) -{ - int blockSize = 1024; - int gridSize = (batch * d_fft_size + blockSize - 1) / blockSize; - if (d_shift) - exec_fft_shift((cuFloatComplex*)in, - (cuFloatComplex*)in, - batch * d_fft_size, - gridSize, - blockSize, - d_stream); - d_fft.launch(in, out, batch, d_stream); -} - -template <> -void fft_cuda<float, true>::fft_and_shift(const float* in, gr_complex* out, int batch) -{ -} - -template <> -void fft_cuda<float, false>::fft_and_shift(const float* in, gr_complex* out, int batch) -{ -} - -template <class T, bool forward> -work_return_t fft_cuda<T, forward>::work(work_io& wio) -{ - - auto in = wio.inputs()[0].items<T>(); - auto out = wio.outputs()[0].items<gr_complex>(); - auto noutput_items = wio.outputs()[0].n_items; - - fft_and_shift(in, out, noutput_items); - cudaStreamSynchronize(d_stream); - wio.produce_each(noutput_items); - return work_return_t::OK; -} - -} // namespace fft -} // namespace gr diff --git a/blocklib/fft/fft/fft_cuda.h b/blocklib/fft/fft/fft_cuda.h deleted file mode 100644 index afeea0138..000000000 --- a/blocklib/fft/fft/fft_cuda.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/fft/fft.h> -#include <cusp/fft.cuh> - -namespace gr { -namespace fft { - -template <class T, bool forward> -class fft_cuda : public fft<T, forward> -{ -public: - fft_cuda(const typename fft<T, forward>::block_args& args); - work_return_t work(work_io&) override; - -protected: - size_t d_fft_size; - std::vector<float> d_window; - bool d_shift; - cudaStream_t d_stream; - - // std::shared_ptr<cusp::fft<T,forward>> d_fft; - cusp::fft<T, forward> d_fft; - - void fft_and_shift(const T* in, gr_complex* out, int batch); -}; - -} // namespace fft -} // namespace gr
\ No newline at end of file diff --git a/blocklib/fft/fft/fft_shift.cu b/blocklib/fft/fft/fft_shift.cu deleted file mode 100644 index 235f7005c..000000000 --- a/blocklib/fft/fft/fft_shift.cu +++ /dev/null @@ -1,39 +0,0 @@ -#include <cuComplex.h> - -template <typename T> -__global__ void kernel_fft_shift(const T* in, T* out, int n); - -template <> -__global__ void kernel_fft_shift(const cuFloatComplex* in, cuFloatComplex* out, int n) -{ - int i = blockIdx.x * blockDim.x + threadIdx.x; - - if (i < n) { - float a = 1 - 2 * (i & 1); - out[i].x = in[i].x * a; - out[i].y = in[i].y * a; - } -} - -template <> -__global__ void kernel_fft_shift(const cuDoubleComplex* in, cuDoubleComplex* out, int n) -{ - int i = blockIdx.x * blockDim.x + threadIdx.x; - - if (i < n) { - double a = 1 - 2 * (i & 1); - out[i].x = in[i].x * a; - out[i].y = in[i].y * a; - } -} - - -void exec_fft_shift(const cuFloatComplex* in, - cuFloatComplex* out, - int n, - int grid_size, - int block_size, - cudaStream_t stream) -{ - kernel_fft_shift<<<grid_size, block_size, 0, stream>>>(in, out, n); -} diff --git a/blocklib/fft/include/gnuradio/fft/.gitignore b/blocklib/fft/include/gnuradio/fft/.gitignore deleted file mode 100644 index d53050d7d..000000000 --- a/blocklib/fft/include/gnuradio/fft/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build diff --git a/blocklib/fft/include/gnuradio/fft/api.h b/blocklib/fft/include/gnuradio/fft/api.h deleted file mode 100644 index 492d3e899..000000000 --- a/blocklib/fft/include/gnuradio/fft/api.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/attributes.h> - -#ifdef gnuradio_fft_EXPORTS -#define FFT_API __GR_ATTR_EXPORT -#else -#define FFT_API __GR_ATTR_IMPORT -#endif diff --git a/blocklib/fft/include/gnuradio/fft/meson.build b/blocklib/fft/include/gnuradio/fft/meson.build deleted file mode 100644 index b7dfa1e07..000000000 --- a/blocklib/fft/include/gnuradio/fft/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -headers = [ - 'api.h', - # 'fftw_fft.h', - # 'window.h' -] - -install_headers(headers, subdir : 'gnuradio/fft') diff --git a/blocklib/fft/lib/.gitignore b/blocklib/fft/lib/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/fft/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/fft/lib/meson.build b/blocklib/fft/lib/meson.build deleted file mode 100644 index b79654039..000000000 --- a/blocklib/fft/lib/meson.build +++ /dev/null @@ -1,60 +0,0 @@ -fft_deps += [gnuradio_gr_dep, volk_dep, fmt_dep, pmtf_dep, gr_kernel_fft_lib_dep] - -# fft_sources += ['fftw_fft.cc','window.cc'] - -if IMPLEMENT_CUDA - fft_deps += cuda_dep - fft_deps += cusp_dep -endif - -block_cpp_args = ['-DHAVE_CPU'] -if IMPLEMENT_CUDA - block_cpp_args += '-DHAVE_CUDA' - - gnuradio_blocklib_fft_cu = library('gnuradio-blocklib-fft-cu', - fft_cu_sources, - include_directories : incdir, - install : true, - dependencies : [cuda_dep]) - - gnuradio_blocklib_fft_cu_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_fft_cu, - dependencies : cuda_dep) - - fft_deps += [gnuradio_blocklib_fft_cu_dep, cuda_dep] - # fft_deps += [cuda_dep] - -endif - -incdir = include_directories(['../include/gnuradio/fft','../include']) -gnuradio_blocklib_fft_lib = library('gnuradio-blocklib-fft', - fft_sources, - include_directories : incdir, - install : true, - link_language: 'cpp', - dependencies : fft_deps, - cpp_args : block_cpp_args) - -gnuradio_blocklib_fft_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_fft_lib, - dependencies : fft_deps) - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'fft') -cmake.configure_package_config_file( - name : 'gnuradio-fft', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_fft_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-fft', - filebase : 'gnuradio-fft', - description : 'GNU Radio FFT Module') diff --git a/blocklib/fft/python/gnuradio/fft/.gitignore b/blocklib/fft/python/gnuradio/fft/.gitignore deleted file mode 100644 index 87a129428..000000000 --- a/blocklib/fft/python/gnuradio/fft/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -./meson.build -!bindings/meson.build
\ No newline at end of file diff --git a/blocklib/fft/python/gnuradio/fft/__init__.py b/blocklib/fft/python/gnuradio/fft/__init__.py deleted file mode 100644 index 22e856a99..000000000 --- a/blocklib/fft/python/gnuradio/fft/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ - -import os - -try: - from .fft_python import * -except ImportError: - dirname, filename = os.path.split(os.path.abspath(__file__)) - __path__.append(os.path.join(dirname, "bindings")) - from .fft_python import * diff --git a/blocklib/fft/python/gnuradio/fft/bindings/meson.build b/blocklib/fft/python/gnuradio/fft/bindings/meson.build deleted file mode 100644 index 82b25a1f2..000000000 --- a/blocklib/fft/python/gnuradio/fft/bindings/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -# fft_pybind_sources = [files('window_pybind.cc')] + fft_pybind_sources -# fft_pybind_names = ['window'] + fft_pybind_names
\ No newline at end of file diff --git a/blocklib/fft/python/gnuradio/fft/bindings/window_pybind.cc b/blocklib/fft/python/gnuradio/fft/bindings/window_pybind.cc deleted file mode 100644 index f60e55669..000000000 --- a/blocklib/fft/python/gnuradio/fft/bindings/window_pybind.cc +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2020,2021 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -/***********************************************************************************/ -/* This file is automatically generated using bindtool and can be manually edited */ -/* The following lines can be configured to regenerate this file during cmake */ -/* If manual edits are made, the following tags should be modified accordingly. */ -/* BINDTOOL_GEN_AUTOMATIC(0) */ -/* BINDTOOL_USE_PYGCCXML(0) */ -/* BINDTOOL_HEADER_FILE(window.h) */ -/* BINDTOOL_HEADER_FILE_HASH(872e1911444c9a5982f4d00af81a2def) */ -/***********************************************************************************/ - -#include <pybind11/complex.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/kernel/fft/window.h> - -void bind_window(py::module& m) -{ - using window = gr::kernel::fft::window; - - py::class_<window, std::shared_ptr<window>> window_class(m, "window"); - - py::enum_<gr::kernel::fft::window::window_t>(window_class, "window_t") - .value("HAMMING", gr::kernel::fft::window::HAMMING) // 0 - .value("HANN", gr::kernel::fft::window::HANN) // 1 - .value("HANNING", gr::kernel::fft::window::HANNING) // 1 - .value("BLACKMAN", gr::kernel::fft::window::BLACKMAN) // 2 - .value("RECTANGULAR", gr::kernel::fft::window::RECTANGULAR) // 3 - .value("KAISER", gr::kernel::fft::window::KAISER) // 4 - .value("BLACKMAN_hARRIS", gr::kernel::fft::window::BLACKMAN_hARRIS) // 5 - .value("BLACKMAN_HARRIS", gr::kernel::fft::window::BLACKMAN_HARRIS) // 5 - .value("BARTLETT", gr::kernel::fft::window::BARTLETT) // 6 - .value("FLATTOP", gr::kernel::fft::window::FLATTOP) // 7 - .value("NUTTALL", gr::kernel::fft::window::NUTTALL) // 8 - .value("BLACKMAN_NUTTALL", gr::kernel::fft::window::BLACKMAN_NUTTALL) // 8 - .value("NUTTALL_CFD", gr::kernel::fft::window::NUTTALL_CFD) // 9 - .value("WELCH", gr::kernel::fft::window::WELCH) // 10 - .value("PARZEN", gr::kernel::fft::window::PARZEN) // 11 - .value("EXPONENTIAL", gr::kernel::fft::window::EXPONENTIAL) // 12 - .value("RIEMANN", gr::kernel::fft::window::RIEMANN) // 13 - .value("GAUSSIAN", gr::kernel::fft::window::GAUSSIAN) // 14 - .value("TUKEY", gr::kernel::fft::window::TUKEY) // 15 - .export_values(); - - py::implicitly_convertible<int, gr::kernel::fft::window::window_t>(); - - window_class - .def_static("max_attenuation", - &window::max_attenuation, - py::arg("type"), - py::arg("param") = 6.7599999999999998) - - - .def_static("coswindow", - (std::vector<float>(*)(int, float, float, float)) & window::coswindow, - py::arg("ntaps"), - py::arg("c0"), - py::arg("c1"), - py::arg("c2")) - - - .def_static("coswindow", - (std::vector<float>(*)(int, float, float, float, float)) & - window::coswindow, - py::arg("ntaps"), - py::arg("c0"), - py::arg("c1"), - py::arg("c2"), - py::arg("c3")) - - - .def_static("coswindow", - (std::vector<float>(*)(int, float, float, float, float, float)) & - window::coswindow, - py::arg("ntaps"), - py::arg("c0"), - py::arg("c1"), - py::arg("c2"), - py::arg("c3"), - py::arg("c4")) - - - .def_static("rectangular", &window::rectangular, py::arg("ntaps")) - - - .def_static("hamming", &window::hamming, py::arg("ntaps")) - - - .def_static("hann", &window::hann, py::arg("ntaps")) - - - .def_static("hanning", &window::hanning, py::arg("ntaps")) - - - .def_static("blackman", &window::blackman, py::arg("ntaps")) - - - .def_static("blackman2", &window::blackman2, py::arg("ntaps")) - - - .def_static("blackman3", &window::blackman3, py::arg("ntaps")) - - - .def_static("blackman4", &window::blackman4, py::arg("ntaps")) - - - .def_static("blackman_harris", - &window::blackman_harris, - py::arg("ntaps"), - py::arg("atten") = 92) - - - .def_static("blackmanharris", - &window::blackmanharris, - py::arg("ntaps"), - py::arg("atten") = 92) - - - .def_static("nuttall", &window::nuttall, py::arg("ntaps")) - - - .def_static("blackman_nuttall", &window::blackman_nuttall, py::arg("ntaps")) - - - .def_static("nuttall_cfd", &window::nuttall_cfd, py::arg("ntaps")) - - - .def_static("flattop", &window::flattop, py::arg("ntaps")) - - - .def_static("kaiser", &window::kaiser, py::arg("ntaps"), py::arg("beta")) - - - .def_static("bartlett", &window::bartlett, py::arg("ntaps")) - - - .def_static("welch", &window::welch, py::arg("ntaps")) - - - .def_static("parzen", &window::parzen, py::arg("ntaps")) - - - .def_static("exponential", &window::exponential, py::arg("ntaps"), py::arg("d")) - - - .def_static("riemann", &window::riemann, py::arg("ntaps")) - - - .def_static("tukey", &window::tukey, py::arg("ntaps"), py::arg("alpha")) - - - .def_static("gaussian", &window::gaussian, py::arg("ntaps"), py::arg("sigma")) - - - .def_static("build", - &window::build, - py::arg("type"), - py::arg("ntaps"), - py::arg("param") = 6.76, - py::arg("normalize") = false) - - ; -} diff --git a/blocklib/fft/test/.gitignore b/blocklib/fft/test/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/fft/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/fft/test/meson.build b/blocklib/fft/test/meson.build deleted file mode 100644 index 6f6fcb4f3..000000000 --- a/blocklib/fft/test/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -################################################### -# QA -################################################### - -if GR_ENABLE_PYTHON - test('qa_fft', py3, args : files('qa_fft.py'), env: TEST_ENV) - if (IMPLEMENT_CUDA) - test('qa_cufft', py3, args : files('qa_cufft.py'), env: TEST_ENV) - endif - -endif diff --git a/blocklib/fft/test/qa_cufft.py b/blocklib/fft/test/qa_cufft.py deleted file mode 100644 index d5e670c12..000000000 --- a/blocklib/fft/test/qa_cufft.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2008,2010,2012 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, fft, blocks - -# Note: Octave code to verify these results: -# primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, -# 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311] -# src_data = primes(1:2:end) + primes(2:2:end)*i -# forward = fft(src_data(:)) -# reverse = ifft(forward(:)) -# windowed = fft(src_data(:).*hamming(32)) -# reverse_window_shift = ifft(fftshift(forward.*hamming(32))) - -primes = ( - 2, - 3, - 5, - 7, - 11, - 13, - 17, - 19, - 23, - 29, - 31, - 37, - 41, - 43, - 47, - 53, - 59, - 61, - 67, - 71, - 73, - 79, - 83, - 89, - 97, - 101, - 103, - 107, - 109, - 113, - 127, - 131, - 137, - 139, - 149, - 151, - 157, - 163, - 167, - 173, - 179, - 181, - 191, - 193, - 197, - 199, - 211, - 223, - 227, - 229, - 233, - 239, - 241, - 251, - 257, - 263, - 269, - 271, - 277, - 281, - 283, - 293, - 307, - 311) - -primes_transformed = ((4377 + 4516j), - (-1706.1268310546875 + 1638.4256591796875j), - (-915.2083740234375 + 660.69427490234375j), - (-660.370361328125 + 381.59600830078125j), - (-499.96044921875 + 238.41630554199219j), - (-462.26748657226562 + 152.88948059082031j), - (-377.98440551757812 + 77.5928955078125j), - (-346.85821533203125 + 47.152004241943359j), - (-295 + 20j), - (-286.33609008789062 - 22.257017135620117j), - (-271.52999877929688 - 33.081821441650391j), - (-224.6358642578125 - 67.019538879394531j), - (-244.24473571777344 - 91.524826049804688j), - (-203.09068298339844 - 108.54627227783203j), - (-198.45195007324219 - 115.90768432617188j), - (-182.97744750976562 - 128.12318420410156j), - (-167 - 180j), - (-130.33688354492188 - 173.83778381347656j), - (-141.19784545898438 - 190.28807067871094j), - (-111.09677124023438 - 214.48896789550781j), - (-70.039543151855469 - 242.41630554199219j), - (-68.960540771484375 - 228.30015563964844j), - (-53.049201965332031 - 291.47097778320312j), - (-28.695289611816406 - 317.64553833007812j), - (57 - 300j), - (45.301143646240234 - 335.69509887695312j), - (91.936195373535156 - 373.32437133789062j), - (172.09465026855469 - 439.275146484375j), - (242.24473571777344 - 504.47515869140625j), - (387.81732177734375 - 666.6788330078125j), - (689.48553466796875 - 918.2142333984375j), - (1646.539306640625 - 1694.1956787109375j)) - - -class test_fft(gr_unittest.TestCase): - def setUp(self): - self.tb = gr.flowgraph() - self.rt = gr.runtime() - self.fft_size = 32 - - def tearDown(self): - pass - - def assert_fft_ok2(self, expected_result, result_data): - expected_result = expected_result[:len(result_data)] - self.assertComplexTuplesAlmostEqual2(expected_result, result_data, - abs_eps=1e-9, rel_eps=4e-4) - - def test_forward(self): - src_data = tuple([complex(primes[2 * i], primes[2 * i + 1]) - for i in range(self.fft_size)]) - expected_result = primes_transformed - - src = blocks.vector_source_c(src_data, False, self.fft_size) - op = fft.fft_cc_fwd(self.fft_size, [], False, fft.fft_cc_fwd.cuda) - dst = blocks.vector_sink_c(self.fft_size) - self.tb.connect(src, 0, op, 0).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D)) - self.tb.connect(op, 0, dst, 0).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H)) - self.rt.initialize(self.tb) - self.rt.run() - result_data = dst.data() - self.assert_fft_ok2(expected_result, result_data) - - def test_reverse(self): - src_data = tuple([x / self.fft_size for x in primes_transformed]) - expected_result = tuple( - [complex(primes[2 * i], primes[2 * i + 1]) for i in range(self.fft_size)]) - - src = blocks.vector_source_c(src_data, False, self.fft_size) - op = fft.fft_cc_rev(self.fft_size, [], False, fft.fft_cc_rev.cuda) - dst = blocks.vector_sink_c(self.fft_size) - self.tb.connect(src, 0, op, 0).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D)) - self.tb.connect(op, 0, dst, 0).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H)) - self.rt.initialize(self.tb) - self.rt.run() - result_data = dst.data() - self.assert_fft_ok2(expected_result, result_data) - - # def test_multithreaded(self): - # # Same test as above, only use 2 threads - # src_data = tuple([x / self.fft_size for x in primes_transformed]) - # expected_result = tuple( - # [complex(primes[2 * i], primes[2 * i + 1]) for i in range(self.fft_size)]) - # nthreads = 2 - - # src = blocks.vector_source_c(src_data) - # s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) - # op = fft.fft_vcc(self.fft_size, False, [], False, nthreads) - # v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, self.fft_size) - # dst = blocks.vector_sink_c() - # self.tb.connect(src, s2v, op, v2s, dst) - # self.tb.run() - # result_data = dst.data() - # self.assert_fft_ok2(expected_result, result_data) - - # def test_window(self): - # src_data = tuple([complex(primes[2 * i], primes[2 * i + 1]) - # for i in range(self.fft_size)]) - # expected_result = ((2238.9174 + 2310.4750j), - # (-1603.7416 - 466.7420j), - # (116.7449 - 70.8553j), - # (-13.9157 + 19.0855j), - # (-4.8283 + 16.7025j), - # (-43.7425 + 16.9871j), - # (-16.1904 + 1.7494j), - # (-32.3797 + 6.9964j), - # (-13.5283 + 7.7721j), - # (-24.3276 - 7.5378j), - # (-29.2711 + 4.5709j), - # (-2.7124 - 6.6307j), - # (-33.5486 - 8.3485j), - # (-8.3016 - 9.9534j), - # (-18.8590 - 8.3501j), - # (-13.9092 - 1.1396j), - # (-17.7626 - 26.9281j), - # (0.0182 - 8.9000j), - # (-19.9143 - 14.1320j), - # (-10.3073 - 15.5759j), - # (3.5800 - 29.1835j), - # (-7.5263 - 1.5900j), - # (-3.0392 - 31.7445j), - # (-15.1355 - 33.6158j), - # (28.2345 - 11.4373j), - # (-6.0055 - 27.0418j), - # (5.2074 - 21.2431j), - # (23.1617 - 31.8610j), - # (13.6494 - 11.1982j), - # (14.7145 - 14.4113j), - # (-60.0053 + 114.7418j), - # (-440.1561 - 1632.9807j)) - # window = fft.window.hamming(ntaps=self.fft_size) - - # src = blocks.vector_source_c(src_data) - # s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) - # op = fft.fft_vcc(self.fft_size, True, window, False) - # v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, self.fft_size) - # dst = blocks.vector_sink_c() - # self.tb.connect(src, s2v, op, v2s, dst) - # self.tb.run() - # result_data = dst.data() - # self.assert_fft_ok2(expected_result, result_data) - - # def test_reverse_window_shift(self): - # src_data = tuple([x / self.fft_size for x in primes_transformed]) - # expected_result = ((-74.8629 - 63.2502j), - # (-3.5446 - 2.0365j), - # (2.9231 + 1.6827j), - # (-2.7852 - 0.8613j), - # (2.4763 + 2.7881j), - # (-2.7457 - 3.2602j), - # (4.7748 + 2.4145j), - # (-2.8807 - 4.5313j), - # (5.9949 + 4.1976j), - # (-6.1095 - 6.0681j), - # (5.2248 + 5.7743j), - # (-6.0436 - 6.3773j), - # (9.7184 + 9.2482j), - # (-8.2791 - 8.6507j), - # (6.3273 + 6.1560j), - # (-12.2841 - 12.4692j), - # (10.5816 + 10.0241j), - # (-13.0312 - 11.9451j), - # (12.2983 + 13.3644j), - # (-13.0372 - 14.0795j), - # (14.4682 + 13.3079j), - # (-16.7673 - 16.7287j), - # (14.3946 + 11.5916j), - # (-16.8368 - 21.3156j), - # (20.4528 + 16.8499j), - # (-18.4075 - 18.2446j), - # (17.7507 + 19.2109j), - # (-21.5207 - 20.7159j), - # (22.2183 + 19.8012j), - # (-22.2144 - 20.0343j), - # (17.0359 + 17.6910j), - # (-91.8955 - 103.1093j)) - # window = fft.window.hamming(ntaps=self.fft_size) - - # src = blocks.vector_source_c(src_data) - # s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) - # op = fft.fft_vcc(self.fft_size, False, window, True) - # v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, self.fft_size) - # dst = blocks.vector_sink_c() - # self.tb.connect(src, s2v, op, v2s, dst) - # self.tb.run() - # result_data = dst.data() - # self.assert_fft_ok2(expected_result, result_data) - - -if __name__ == '__main__': - gr_unittest.run(test_fft) - diff --git a/blocklib/fft/test/qa_fft.py b/blocklib/fft/test/qa_fft.py deleted file mode 100644 index c38e5840a..000000000 --- a/blocklib/fft/test/qa_fft.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2008,2010,2012 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, fft, blocks - -# Note: Octave code to verify these results: -# primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, -# 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311] -# src_data = primes(1:2:end) + primes(2:2:end)*i -# forward = fft(src_data(:)) -# reverse = ifft(forward(:)) -# windowed = fft(src_data(:).*hamming(32)) -# reverse_window_shift = ifft(fftshift(forward.*hamming(32))) - -primes = ( - 2, - 3, - 5, - 7, - 11, - 13, - 17, - 19, - 23, - 29, - 31, - 37, - 41, - 43, - 47, - 53, - 59, - 61, - 67, - 71, - 73, - 79, - 83, - 89, - 97, - 101, - 103, - 107, - 109, - 113, - 127, - 131, - 137, - 139, - 149, - 151, - 157, - 163, - 167, - 173, - 179, - 181, - 191, - 193, - 197, - 199, - 211, - 223, - 227, - 229, - 233, - 239, - 241, - 251, - 257, - 263, - 269, - 271, - 277, - 281, - 283, - 293, - 307, - 311) - -primes_transformed = ((4377 + 4516j), - (-1706.1268310546875 + 1638.4256591796875j), - (-915.2083740234375 + 660.69427490234375j), - (-660.370361328125 + 381.59600830078125j), - (-499.96044921875 + 238.41630554199219j), - (-462.26748657226562 + 152.88948059082031j), - (-377.98440551757812 + 77.5928955078125j), - (-346.85821533203125 + 47.152004241943359j), - (-295 + 20j), - (-286.33609008789062 - 22.257017135620117j), - (-271.52999877929688 - 33.081821441650391j), - (-224.6358642578125 - 67.019538879394531j), - (-244.24473571777344 - 91.524826049804688j), - (-203.09068298339844 - 108.54627227783203j), - (-198.45195007324219 - 115.90768432617188j), - (-182.97744750976562 - 128.12318420410156j), - (-167 - 180j), - (-130.33688354492188 - 173.83778381347656j), - (-141.19784545898438 - 190.28807067871094j), - (-111.09677124023438 - 214.48896789550781j), - (-70.039543151855469 - 242.41630554199219j), - (-68.960540771484375 - 228.30015563964844j), - (-53.049201965332031 - 291.47097778320312j), - (-28.695289611816406 - 317.64553833007812j), - (57 - 300j), - (45.301143646240234 - 335.69509887695312j), - (91.936195373535156 - 373.32437133789062j), - (172.09465026855469 - 439.275146484375j), - (242.24473571777344 - 504.47515869140625j), - (387.81732177734375 - 666.6788330078125j), - (689.48553466796875 - 918.2142333984375j), - (1646.539306640625 - 1694.1956787109375j)) - - -class test_fft(gr_unittest.TestCase): - def setUp(self): - self.tb = gr.flowgraph() - self.rt = gr.runtime() - self.fft_size = 32 - - def tearDown(self): - pass - - def assert_fft_ok2(self, expected_result, result_data): - expected_result = expected_result[:len(result_data)] - self.assertComplexTuplesAlmostEqual2(expected_result, result_data, - abs_eps=1e-9, rel_eps=4e-4) - - def test_forward(self): - src_data = tuple([complex(primes[2 * i], primes[2 * i + 1]) - for i in range(self.fft_size)]) - expected_result = primes_transformed - - src = blocks.vector_source_c(src_data, False, self.fft_size) - op = fft.fft_cc_fwd(self.fft_size, [], False) - dst = blocks.vector_sink_c(self.fft_size) - self.tb.connect(src, 0, op, 0) - self.tb.connect(op, 0, dst, 0) - self.rt.initialize(self.tb) - self.rt.run() - result_data = dst.data() - self.assert_fft_ok2(expected_result, result_data) - - def test_reverse(self): - src_data = tuple([x / self.fft_size for x in primes_transformed]) - expected_result = tuple( - [complex(primes[2 * i], primes[2 * i + 1]) for i in range(self.fft_size)]) - - src = blocks.vector_source_c(src_data, False, self.fft_size) - op = fft.fft_cc_rev(self.fft_size, [], False) - dst = blocks.vector_sink_c(self.fft_size) - self.tb.connect(src, 0, op, 0) - self.tb.connect(op, 0, dst, 0) - self.rt.initialize(self.tb) - self.rt.run() - result_data = dst.data() - self.assert_fft_ok2(expected_result, result_data) - - # def test_multithreaded(self): - # # Same test as above, only use 2 threads - # src_data = tuple([x / self.fft_size for x in primes_transformed]) - # expected_result = tuple( - # [complex(primes[2 * i], primes[2 * i + 1]) for i in range(self.fft_size)]) - # nthreads = 2 - - # src = blocks.vector_source_c(src_data) - # s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) - # op = fft.fft_vcc(self.fft_size, False, [], False, nthreads) - # v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, self.fft_size) - # dst = blocks.vector_sink_c() - # self.tb.connect(src, s2v, op, v2s, dst) - # self.tb.run() - # result_data = dst.data() - # self.assert_fft_ok2(expected_result, result_data) - - # def test_window(self): - # src_data = tuple([complex(primes[2 * i], primes[2 * i + 1]) - # for i in range(self.fft_size)]) - # expected_result = ((2238.9174 + 2310.4750j), - # (-1603.7416 - 466.7420j), - # (116.7449 - 70.8553j), - # (-13.9157 + 19.0855j), - # (-4.8283 + 16.7025j), - # (-43.7425 + 16.9871j), - # (-16.1904 + 1.7494j), - # (-32.3797 + 6.9964j), - # (-13.5283 + 7.7721j), - # (-24.3276 - 7.5378j), - # (-29.2711 + 4.5709j), - # (-2.7124 - 6.6307j), - # (-33.5486 - 8.3485j), - # (-8.3016 - 9.9534j), - # (-18.8590 - 8.3501j), - # (-13.9092 - 1.1396j), - # (-17.7626 - 26.9281j), - # (0.0182 - 8.9000j), - # (-19.9143 - 14.1320j), - # (-10.3073 - 15.5759j), - # (3.5800 - 29.1835j), - # (-7.5263 - 1.5900j), - # (-3.0392 - 31.7445j), - # (-15.1355 - 33.6158j), - # (28.2345 - 11.4373j), - # (-6.0055 - 27.0418j), - # (5.2074 - 21.2431j), - # (23.1617 - 31.8610j), - # (13.6494 - 11.1982j), - # (14.7145 - 14.4113j), - # (-60.0053 + 114.7418j), - # (-440.1561 - 1632.9807j)) - # window = fft.window.hamming(ntaps=self.fft_size) - - # src = blocks.vector_source_c(src_data) - # s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) - # op = fft.fft_vcc(self.fft_size, True, window, False) - # v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, self.fft_size) - # dst = blocks.vector_sink_c() - # self.tb.connect(src, s2v, op, v2s, dst) - # self.tb.run() - # result_data = dst.data() - # self.assert_fft_ok2(expected_result, result_data) - - # def test_reverse_window_shift(self): - # src_data = tuple([x / self.fft_size for x in primes_transformed]) - # expected_result = ((-74.8629 - 63.2502j), - # (-3.5446 - 2.0365j), - # (2.9231 + 1.6827j), - # (-2.7852 - 0.8613j), - # (2.4763 + 2.7881j), - # (-2.7457 - 3.2602j), - # (4.7748 + 2.4145j), - # (-2.8807 - 4.5313j), - # (5.9949 + 4.1976j), - # (-6.1095 - 6.0681j), - # (5.2248 + 5.7743j), - # (-6.0436 - 6.3773j), - # (9.7184 + 9.2482j), - # (-8.2791 - 8.6507j), - # (6.3273 + 6.1560j), - # (-12.2841 - 12.4692j), - # (10.5816 + 10.0241j), - # (-13.0312 - 11.9451j), - # (12.2983 + 13.3644j), - # (-13.0372 - 14.0795j), - # (14.4682 + 13.3079j), - # (-16.7673 - 16.7287j), - # (14.3946 + 11.5916j), - # (-16.8368 - 21.3156j), - # (20.4528 + 16.8499j), - # (-18.4075 - 18.2446j), - # (17.7507 + 19.2109j), - # (-21.5207 - 20.7159j), - # (22.2183 + 19.8012j), - # (-22.2144 - 20.0343j), - # (17.0359 + 17.6910j), - # (-91.8955 - 103.1093j)) - # window = fft.window.hamming(ntaps=self.fft_size) - - # src = blocks.vector_source_c(src_data) - # s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) - # op = fft.fft_vcc(self.fft_size, False, window, True) - # v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, self.fft_size) - # dst = blocks.vector_sink_c() - # self.tb.connect(src, s2v, op, v2s, dst) - # self.tb.run() - # result_data = dst.data() - # self.assert_fft_ok2(expected_result, result_data) - - -if __name__ == '__main__': - gr_unittest.run(test_fft) - diff --git a/blocklib/fileio/.gitignore b/blocklib/fileio/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/fileio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/fileio/file_sink/file_sink.yml b/blocklib/fileio/file_sink/file_sink.yml deleted file mode 100644 index f3058e5d2..000000000 --- a/blocklib/fileio/file_sink/file_sink.yml +++ /dev/null @@ -1,40 +0,0 @@ -module: fileio -block: file_sink -label: File Sink -blocktype: sync_block -category: '[Core]/File Operators' - -parameters: -- id: filename - label: Filename - dtype: string - settable: false -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 -- id: append - label: Append - dtype: bool - settable: false - default: 'false' - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -callbacks: -- id: set_unbuffered - return: void - args: - - id: unbuffered - dtype: bool - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/fileio/file_sink/file_sink_cpu.cc b/blocklib/fileio/file_sink/file_sink_cpu.cc deleted file mode 100644 index 5412a9097..000000000 --- a/blocklib/fileio/file_sink/file_sink_cpu.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2006,2007,2010,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "file_sink_cpu.h" -#include "file_sink_cpu_gen.h" - -namespace gr { -namespace fileio { - -file_sink_cpu::file_sink_cpu(const block_args& args) - : INHERITED_CONSTRUCTORS, - file_sink_base(args.filename, true, args.append), - d_itemsize(args.itemsize) - -{ -} - -file_sink_cpu::~file_sink_cpu() {} - -work_return_t file_sink_cpu::work(work_io& wio) -{ - auto inbuf = wio.inputs()[0].items<uint8_t>(); - auto noutput_items = wio.inputs()[0].n_items; - - if (d_itemsize == 0) { - d_itemsize = wio.inputs()[0].buf().item_size(); - } - - size_t nwritten = 0; - - do_update(); // update d_fp is reqd - - if (!d_fp) { - wio.inputs()[0].n_consumed = noutput_items; // drop output on the floor - return work_return_t::OK; - } - - while (nwritten < noutput_items) { - const int count = fwrite(inbuf, d_itemsize, noutput_items - nwritten, d_fp); - if (count == 0) { - if (ferror(d_fp)) { - std::stringstream s; - s << "file_sink write failed with error " << fileno(d_fp) << std::endl; - throw std::runtime_error(s.str()); - } - else { // is EOF - break; - } - } - nwritten += count; - inbuf += count * d_itemsize; - } - - if (d_unbuffered) - fflush(d_fp); - - wio.consume_each(nwritten); - return work_return_t::OK; -} - -bool file_sink_cpu::stop() -{ - do_update(); - fflush(d_fp); - return true; -} - -} // namespace fileio -} // namespace gr
\ No newline at end of file diff --git a/blocklib/fileio/file_sink/file_sink_cpu.h b/blocklib/fileio/file_sink/file_sink_cpu.h deleted file mode 100644 index e2e84f805..000000000 --- a/blocklib/fileio/file_sink/file_sink_cpu.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2007,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/fileio/file_sink.h> -#include <gnuradio/fileio/file_sink_base.h> - -namespace gr { -namespace fileio { - -class file_sink_cpu : public file_sink, public file_sink_base -{ -public: - file_sink_cpu(const block_args& args); - ~file_sink_cpu() override; - - bool stop() override; - - work_return_t work(work_io&) override; - - void set_unbuffered(bool unbuffered) override - { - file_sink_base::set_unbuffered(unbuffered); - } - - -private: - size_t d_itemsize; -}; - -} // namespace fileio -} // namespace gr
\ No newline at end of file diff --git a/blocklib/fileio/file_source/file_source.yml b/blocklib/fileio/file_source/file_source.yml deleted file mode 100644 index 0845c0343..000000000 --- a/blocklib/fileio/file_source/file_source.yml +++ /dev/null @@ -1,52 +0,0 @@ -module: fileio -block: file_source -label: File Source -blocktype: sync_block -category: '[Core]/File Operators' - -parameters: -- id: filename - label: File Name - dtype: string - settable: false -- id: repeat - label: Repeat - dtype: bool - settable: false - default: 'false' -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 -- id: offset - label: Offset - dtype: ru64 - settable: false - default: 0 -- id: len - label: Length - dtype: ru64 - settable: false - default: 0 - -ports: -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - -callbacks: -- id: seek - return: bool - args: - - id: seek_point - dtype: ri64 - - id: whence - dtype: int - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/fileio/file_source/file_source_cpu.cc b/blocklib/fileio/file_source/file_source_cpu.cc deleted file mode 100644 index 0a01efdd8..000000000 --- a/blocklib/fileio/file_source/file_source_cpu.cc +++ /dev/null @@ -1,335 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012, 2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "file_source_cpu.h" -#include "file_source_cpu_gen.h" - -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <cstdio> -#include <filesystem> -#include <stdexcept> - -#include <pmtf/scalar.hpp> -#include <pmtf/string.hpp> - -#ifdef _MSC_VER -#define GR_FSEEK _fseeki64 -#define GR_FTELL _ftelli64 -#define GR_FSTAT _fstati64 -#define GR_FILENO _fileno -#define GR_STAT _stati64 -#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) -#else -#define GR_FSEEK fseeko -#define GR_FTELL ftello -#define GR_FSTAT fstat -#define GR_FILENO fileno -#define GR_STAT stat -#endif - -namespace fs = std::filesystem; - -namespace gr { -namespace fileio { - -file_source_cpu::file_source_cpu(const file_source::block_args& args) - : INHERITED_CONSTRUCTORS, - - d_start_offset_items(args.offset), - d_length_items(args.len), - d_repeat(args.repeat), - d_itemsize(args.itemsize), - d_filename(args.filename), - d_offset(args.offset) -{ - - if (args.itemsize > 0) { - open(d_filename, d_repeat, d_offset, d_length_items); - do_update(); - } - else { - fs::path f{ d_filename }; - if (!fs::exists(f)) { - throw new std::runtime_error( - fmt::format("file_source: the file {} does not exist", d_filename)); - } - } - - std::stringstream str; - str << name() << id(); - _id = pmtf::string(str.str()); -} - - -file_source_cpu::~file_source_cpu() -{ - if (d_fp) - fclose((FILE*)d_fp); - if (d_new_fp) - fclose((FILE*)d_new_fp); -} - -bool file_source_cpu::seek(int64_t seek_point, int whence) -{ - if (d_seekable) { - seek_point += d_start_offset_items; - - switch (whence) { - case SEEK_SET: - break; - case SEEK_CUR: - seek_point += (d_length_items - d_items_remaining); - break; - case SEEK_END: - seek_point = d_length_items - seek_point; - break; - default: - d_logger->warn("bad seek mode"); - return 0; - } - - if ((seek_point < (int64_t)d_start_offset_items) || - (seek_point > (int64_t)(d_start_offset_items + d_length_items - 1))) { - d_logger->warn("bad seek point"); - return 0; - } - return GR_FSEEK((FILE*)d_fp, seek_point * d_itemsize, SEEK_SET) == 0; - } - else { - d_logger->warn("file not seekable"); - return 0; - } -} - - -void file_source_cpu::open(const std::string& filename, - bool repeat, - uint64_t start_offset_items, - uint64_t length_items) -{ - // obtain exclusive access for duration of this function - std::scoped_lock lock(fp_mutex); - - if (d_new_fp) { - fclose(d_new_fp); - d_new_fp = 0; - } - - if ((d_new_fp = fopen(filename.c_str(), "rb")) == NULL) { - d_logger->error("{}:{}", filename, strerror(errno)); - throw std::runtime_error("can't open file"); - } - - struct GR_STAT st; - - if (GR_FSTAT(GR_FILENO(d_new_fp), &st)) { - d_logger->error("{}:{}", filename, strerror(errno)); - throw std::runtime_error("can't fstat file"); - } - if (S_ISREG(st.st_mode)) { - d_seekable = true; - } - else { - d_seekable = false; - } - - uint64_t file_size; - - if (d_seekable) { - // Check to ensure the file will be consumed according to item size - if (GR_FSEEK(d_new_fp, 0, SEEK_END) == -1) { - throw std::runtime_error("can't fseek()"); - } - file_size = GR_FTELL(d_new_fp); - - // Make sure there will be at least one item available - if ((file_size / d_itemsize) < (start_offset_items + 1)) { - if (start_offset_items) { - d_logger->warn("file is too small for start offset"); - } - else { - d_logger->warn("file is too small"); - } - fclose(d_new_fp); - throw std::runtime_error("file is too small"); - } - } - else { - file_size = INT64_MAX; - } - - uint64_t items_available = (file_size / d_itemsize - start_offset_items); - - // If length is not specified, use the remainder of the file. Check alignment at end. - if (length_items == 0) { - length_items = items_available; - if (file_size % d_itemsize) { - d_logger->warn("file size is not a multiple of item size"); - } - } - - // Check specified length. Warn and use available items instead of throwing an - // exception. - if (length_items > items_available) { - length_items = items_available; - d_logger->warn("file too short, will read fewer than requested items"); - } - - // Rewind to start offset - if (d_seekable) { - auto start_offset = start_offset_items * d_itemsize; -#ifdef _POSIX_C_SOURCE -#if _POSIX_C_SOURCE >= 200112L - // If supported, tell the OS that we'll be accessing the file sequentially - // and that it would be a good idea to start prefetching it - auto fd = fileno(d_new_fp); - static const std::map<int, const std::string> fadv_errstrings = { - { EBADF, "bad file descriptor" }, - { EINVAL, "invalid advise" }, - { ESPIPE, "tried to act as if a pipe or similar was a file" } - }; - if (file_size && file_size != INT64_MAX) { - if (auto ret = posix_fadvise( - fd, start_offset, file_size - start_offset, POSIX_FADV_SEQUENTIAL)) { - d_logger->warn("failed to advise to read sequentially, {}", - fadv_errstrings.at(ret)); - } - if (auto ret = posix_fadvise( - fd, start_offset, file_size - start_offset, POSIX_FADV_WILLNEED)) { - d_logger->warn("failed to advise we'll need file contents soon, {}", - fadv_errstrings.at(ret)); - } - } -#endif -#endif - if (GR_FSEEK(d_new_fp, start_offset, SEEK_SET) == -1) { - throw std::runtime_error("can't fseek()"); - } - } - - d_updated = true; - d_repeat = repeat; - d_start_offset_items = start_offset_items; - d_length_items = length_items; - d_items_remaining = length_items; -} - -void file_source_cpu::close() -{ - // obtain exclusive access for duration of this function - std::scoped_lock lock(fp_mutex); - - if (d_new_fp != NULL) { - fclose(d_new_fp); - d_new_fp = NULL; - } - d_updated = true; -} - -void file_source_cpu::do_update() -{ - if (d_updated) { - std::scoped_lock lock(fp_mutex); // hold while in scope - - if (d_fp) - fclose(d_fp); - - d_fp = d_new_fp; // install new file pointer - d_new_fp = 0; - d_updated = false; - d_file_begin = true; - } -} - -void file_source_cpu::set_begin_tag(const std::string& val) { d_add_begin_tag = val; } - -work_return_t file_source_cpu::work(work_io& wio) -{ - auto out = wio.outputs()[0].items<uint8_t>(); - auto noutput_items = wio.outputs()[0].n_items; - uint64_t size = noutput_items; - - if (d_itemsize == 0) { - d_itemsize = wio.outputs()[0].buf().item_size(); - open(d_filename, d_repeat, d_offset, d_length_items); - } - - do_update(); // update d_fp is reqd - if (d_fp == NULL) - throw std::runtime_error("work with file not open"); - - std::scoped_lock lock(fp_mutex); // hold for the rest of this function - - // No items remaining - all done - if (d_items_remaining == 0) { - wio.outputs()[0].n_produced = 0; - return work_return_t::DONE; - } - - while (size) { - - // Add stream tag whenever the file starts again - if (d_file_begin && !d_add_begin_tag.empty()) { - wio.outputs()[0].buf().add_tag( - wio.outputs()[0].buf().total_written() + noutput_items - size, - pmtf::map{ { d_add_begin_tag, pmtf::scalar<int64_t>(d_repeat_cnt) }, - { "srcid", _id } }); - - d_file_begin = false; - } - - uint64_t nitems_to_read = std::min(size, d_items_remaining); - - size_t nitems_read = fread(out, d_itemsize, nitems_to_read, (FILE*)d_fp); - if (nitems_to_read != nitems_read) { - // Size of non-seekable files is unknown. EOF is normal. - if (!d_seekable && feof((FILE*)d_fp)) { - size -= nitems_read; - d_items_remaining = 0; - break; - } - - throw std::runtime_error("fread error"); - } - - size -= nitems_read; - d_items_remaining -= nitems_read; - out += nitems_read * d_itemsize; - - // Ran out of items ("EOF") - if (d_items_remaining == 0) { - // Repeat: rewind and request tag - if (d_repeat && d_seekable) { - if (GR_FSEEK(d_fp, d_start_offset_items * d_itemsize, SEEK_SET) == -1) { - throw std::runtime_error("can't fseek()"); - } - d_items_remaining = d_length_items; - if (!d_add_begin_tag.empty()) { - d_file_begin = true; - d_repeat_cnt++; - } - } - - // No repeat: return - else { - break; - } - } - } - - wio.produce_each(noutput_items - size); - return work_return_t::OK; -} - - -} // namespace fileio -} // namespace gr diff --git a/blocklib/fileio/file_source/file_source_cpu.h b/blocklib/fileio/file_source/file_source_cpu.h deleted file mode 100644 index 52930fe35..000000000 --- a/blocklib/fileio/file_source/file_source_cpu.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012, 2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/fileio/file_source.h> - -namespace gr { -namespace fileio { - -class file_source_cpu : public file_source -{ -public: - file_source_cpu(const block_args& args); - ~file_source_cpu() override; - work_return_t work(work_io&) override; - - /*! - * \brief seek file to \p seek_point relative to \p whence - * - * \param seek_point sample offset in file - * \param whence one of SEEK_SET, SEEK_CUR, SEEK_END (man fseek) - */ - bool seek(int64_t seek_point, int whence) override; - - /*! - * \brief Opens a new file. - * - * \param filename name of the file to source from - * \param repeat repeat file from start - * \param offset begin this many items into file - * \param len produce only items [offset, offset+len) - */ - void - open(const std::string& filename, bool repeat, uint64_t offset = 0, uint64_t len = 0); - - /*! - * \brief Close the file handle. - */ - void close(); - - /*! - * \brief Add a stream tag to the first sample of the file if true - */ - void set_begin_tag(const std::string& val); - -private: - uint64_t d_start_offset_items; - uint64_t d_length_items; - uint64_t d_items_remaining; - FILE* d_fp = nullptr; - FILE* d_new_fp = nullptr; - bool d_repeat; - size_t d_itemsize; - std::string d_filename; - size_t d_offset; - bool d_updated = false; - bool d_file_begin = true; - bool d_seekable; - long d_repeat_cnt = 0; - std::string d_add_begin_tag; - - std::mutex fp_mutex; - pmtf::pmt _id; - - void do_update(); -}; - -} // namespace fileio -} // namespace gr diff --git a/blocklib/fileio/include/gnuradio/fileio/.gitignore b/blocklib/fileio/include/gnuradio/fileio/.gitignore deleted file mode 100644 index d53050d7d..000000000 --- a/blocklib/fileio/include/gnuradio/fileio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build diff --git a/blocklib/fileio/include/gnuradio/fileio/file_sink_base.h b/blocklib/fileio/include/gnuradio/fileio/file_sink_base.h deleted file mode 100644 index 8c9a21c3c..000000000 --- a/blocklib/fileio/include/gnuradio/fileio/file_sink_base.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2007,2008,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/logger.h> -#include <cstdio> -#include <mutex> - -namespace gr { -namespace fileio { - -/*! - * \brief Common base class for file sinks - */ -class file_sink_base -{ -protected: - FILE* d_fp; // current FILE pointer - FILE* d_new_fp; // new FILE pointer - bool d_updated; // is there a new FILE pointer? - bool d_is_binary; - std::mutex d_mutex; - bool d_unbuffered; - bool d_append; - gr::logger_ptr d_logger, d_debug_logger; - -protected: - file_sink_base(const std::string& filename, bool is_binary, bool append); - -public: - file_sink_base() {} - ~file_sink_base(); - - /*! - * \brief Open filename and begin output to it. - */ - bool open(const char* filename); - - /*! - * \brief Close current output file. - * - * Closes current output file and ignores any output until - * open is called to connect to another file. - */ - void close(); - - /*! - * \brief if we've had an update, do it now. - */ - void do_update(); - - /*! - * \brief turn on unbuffered writes for slower outputs - */ - void set_unbuffered(bool unbuffered); -}; - -} // namespace fileio -} // namespace gr diff --git a/blocklib/fileio/include/gnuradio/fileio/meson.build b/blocklib/fileio/include/gnuradio/fileio/meson.build deleted file mode 100644 index e69de29bb..000000000 --- a/blocklib/fileio/include/gnuradio/fileio/meson.build +++ /dev/null diff --git a/blocklib/fileio/lib/.gitignore b/blocklib/fileio/lib/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/fileio/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/fileio/lib/file_sink_base.cc b/blocklib/fileio/lib/file_sink_base.cc deleted file mode 100644 index 0328b0729..000000000 --- a/blocklib/fileio/lib/file_sink_base.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2006,2007,2009,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gnuradio/fileio/file_sink_base.h> - -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <cstdio> -#include <stdexcept> - -// win32 (mingw/msvc) specific -#ifdef HAVE_IO_H -#include <io.h> -#endif -#ifdef O_BINARY -#define OUR_O_BINARY O_BINARY -#else -#define OUR_O_BINARY 0 -#endif - -// should be handled via configure -#ifdef O_LARGEFILE -#define OUR_O_LARGEFILE O_LARGEFILE -#else -#define OUR_O_LARGEFILE 0 -#endif - -namespace gr { -namespace fileio { - -file_sink_base::file_sink_base(const std::string& filename, bool is_binary, bool append) - : d_fp(0), d_new_fp(0), d_updated(false), d_is_binary(is_binary), d_append(append) -{ - if (!open(filename.c_str())) - throw std::runtime_error("can't open file"); - - gr::configure_default_loggers(d_logger, d_debug_logger, "file_sink_base"); -} - -file_sink_base::~file_sink_base() -{ - close(); - if (d_fp) { - fclose(d_fp); - d_fp = 0; - } -} - -bool file_sink_base::open(const char* filename) -{ - std::scoped_lock guard(d_mutex); // hold mutex for duration of this function - - // we use the open system call to get access to the O_LARGEFILE flag. - int fd; - int flags; - - if (d_append) { - flags = O_WRONLY | O_CREAT | O_APPEND | OUR_O_LARGEFILE | OUR_O_BINARY; - } - else { - flags = O_WRONLY | O_CREAT | O_TRUNC | OUR_O_LARGEFILE | OUR_O_BINARY; - } - if ((fd = ::open(filename, flags, 0664)) < 0) { - d_logger->error("{}: {}", filename, strerror(errno)); - return false; - } - if (d_new_fp) { // if we've already got a new one open, close it - fclose(d_new_fp); - d_new_fp = 0; - } - - if ((d_new_fp = fdopen(fd, d_is_binary ? "wb" : "w")) == NULL) { - d_logger->error("{}: {}", filename, strerror(errno)); - ::close(fd); // don't leak file descriptor if fdopen fails. - } - - d_updated = true; - return d_new_fp != 0; -} - -void file_sink_base::close() -{ - std::scoped_lock guard(d_mutex); // hold mutex for duration of this function - - if (d_new_fp) { - fclose(d_new_fp); - d_new_fp = 0; - } - d_updated = true; -} - -void file_sink_base::do_update() -{ - if (d_updated) { - std::scoped_lock guard(d_mutex); // hold mutex for duration of this block - if (d_fp) - fclose(d_fp); - d_fp = d_new_fp; // install new file pointer - d_new_fp = 0; - d_updated = false; - } -} - -void file_sink_base::set_unbuffered(bool unbuffered) { d_unbuffered = unbuffered; } - -} // namespace fileio -} /* namespace gr */ diff --git a/blocklib/fileio/lib/meson.build b/blocklib/fileio/lib/meson.build deleted file mode 100644 index ff7f2b12e..000000000 --- a/blocklib/fileio/lib/meson.build +++ /dev/null @@ -1,52 +0,0 @@ -fileio_deps += [gnuradio_gr_dep, volk_dep, fmt_dep, pmtf_dep] -fileio_sources += 'file_sink_base.cc' -block_cpp_args = ['-DHAVE_CPU'] -# if IMPLEMENT_CUDA -# block_cpp_args += '-DHAVE_CUDA' - -# gnuradio_blocklib_fileio_cu = library('gnuradio-blocklib-fileio-cu', -# fileio_cu_sources, -# include_directories : incdir, -# install : true, -# dependencies : [cuda_dep]) - -# gnuradio_blocklib_fileio_cu_dep = declare_dependency(include_directories : incdir, -# link_with : gnuradio_blocklib_fileio_cu, -# dependencies : cuda_dep) - -# fileio_deps += [gnuradio_blocklib_fileio_cu_dep, cuda_dep] - -# endif - -incdir = include_directories(['../include/gnuradio/fileio','../include']) -gnuradio_blocklib_fileio_lib = library('gnuradio-blocklib-fileio', - fileio_sources, - include_directories : incdir, - install : true, - link_language: 'cpp', - dependencies : fileio_deps, - cpp_args : block_cpp_args) - -gnuradio_blocklib_fileio_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_fileio_lib, - dependencies : fileio_deps) - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'fileio') -cmake.configure_package_config_file( - name : 'gnuradio-fileio', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_fileio_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-fileio', - filebase : 'gnuradio-fileio', - description : 'GNU Radio FileIO Module') diff --git a/blocklib/fileio/python/gnuradio/fileio/.gitignore b/blocklib/fileio/python/gnuradio/fileio/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/fileio/python/gnuradio/fileio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/fileio/python/gnuradio/fileio/__init__.py b/blocklib/fileio/python/gnuradio/fileio/__init__.py deleted file mode 100644 index 4d381cca2..000000000 --- a/blocklib/fileio/python/gnuradio/fileio/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ - -import os - -try: - from .fileio_python import * -except ImportError: - dirname, filename = os.path.split(os.path.abspath(__file__)) - __path__.append(os.path.join(dirname, "bindings")) - from .fileio_python import * diff --git a/blocklib/fileio/python/gnuradio/fileio/bindings/file_sink_base_pybind.cc b/blocklib/fileio/python/gnuradio/fileio/bindings/file_sink_base_pybind.cc deleted file mode 100644 index 71720e966..000000000 --- a/blocklib/fileio/python/gnuradio/fileio/bindings/file_sink_base_pybind.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2020 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include <pybind11/complex.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/fileio/file_sink_base.h> -// pydoc.h is automatically generated in the build directory -// #include <block_pydoc.h> - -void bind_file_sink_base(py::module& m) -{ - using file_sink_base = ::gr::fileio::file_sink_base; - - py::class_<file_sink_base, std::shared_ptr<file_sink_base>>(m, "file_sink_base") - .def("set_unbuffered", &file_sink_base::set_unbuffered, py::arg("unbuffered")); -} diff --git a/blocklib/fileio/test/.gitignore b/blocklib/fileio/test/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/fileio/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/fileio/test/meson.build b/blocklib/fileio/test/meson.build deleted file mode 100644 index c7dae54cd..000000000 --- a/blocklib/fileio/test/meson.build +++ /dev/null @@ -1,9 +0,0 @@ -################################################### -# QA -################################################### - -if GR_ENABLE_PYTHON - test('qa_file_source', py3, args : files('qa_file_source.py'), env: TEST_ENV) - test('qa_file_sink', py3, args : files('qa_file_sink.py'), env: TEST_ENV) - -endif diff --git a/blocklib/fileio/test/qa_file_sink.py b/blocklib/fileio/test/qa_file_sink.py deleted file mode 100644 index 01128c756..000000000 --- a/blocklib/fileio/test/qa_file_sink.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - -import os -import tempfile -import array -from gnuradio import gr, gr_unittest, blocks, fileio - - -class test_file_sink(gr_unittest.TestCase): - - def setUp(self): - os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' - self.tb = gr.flowgraph() - self.rt = gr.runtime() - - def tearDown(self): - self.tb = None - self.rt = None - - def test_file_sink(self): - data = range(1000) - expected_result = data - - with tempfile.NamedTemporaryFile() as temp: - src = blocks.vector_source_f(data) - snk = fileio.file_sink(temp.name) - snk.set_unbuffered(True) # FIXME: comes from base class no pybind yet - self.tb.connect(src, snk) - self.rt.initialize(self.tb) - self.rt.run() - - # Check file length (float: 4 * nsamples) - file_size = os.stat(temp.name).st_size - self.assertEqual(file_size, 4 * len(data)) - - # Check file contents - with open(temp.name, 'rb') as datafile: - result_data = array.array('f') - result_data.fromfile(datafile, len(data)) - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - -if __name__ == '__main__': - gr_unittest.run(test_file_sink) diff --git a/blocklib/fileio/test/qa_file_source.py b/blocklib/fileio/test/qa_file_source.py deleted file mode 100644 index a2fa53524..000000000 --- a/blocklib/fileio/test/qa_file_source.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - -import os -import tempfile -import array -# import pmt -from gnuradio import gr, gr_unittest, blocks, fileio - - -class test_file_source(gr_unittest.TestCase): - - @classmethod - def setUpClass(cls): - os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' - cls._datafile = tempfile.NamedTemporaryFile() - cls._datafilename = cls._datafile.name - cls._vector = [x for x in range(1000)] - with open(cls._datafilename, 'wb') as f: - array.array('f', cls._vector).tofile(f) - - @classmethod - def tearDownClass(cls): - del cls._vector - del cls._datafilename - del cls._datafile - - def setUp(self): - self.tb = gr.flowgraph() - self.rt = gr.runtime() - - def tearDown(self): - self.tb = None - self.rt = None - - def test_file_source(self): - src = fileio.file_source(self._datafilename) - snk = blocks.vector_sink_f() - self.tb.connect(src, snk) - self.rt.initialize(self.tb) - self.rt.run() - - result_data = snk.data() - self.assertFloatTuplesAlmostEqual(self._vector, result_data) - # self.assertEqual(len(snk.tags()), 0) - - def test_file_source_no_such_file(self): - """ - Try to open a non-existent file and verify exception is thrown. - """ - try: - _ = fileio.file_source("___no_such_file___") - self.assertTrue(False) - except RuntimeError: - self.assertTrue(True) - - def test_file_source_with_offset(self): - expected_result = self._vector[100:] - - src = fileio.file_source( - self._datafilename, - offset=100) - snk = blocks.vector_sink_f() - - self.tb.connect(src, snk) - self.rt.initialize(self.tb) - self.rt.run() - - result_data = snk.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - # self.assertEqual(len(snk.tags()), 0) - - def test_source_with_offset_and_len(self): - expected_result = self._vector[100:100 + 600] - - src = fileio.file_source( - self._datafilename, - offset=100, - len=600) - snk = blocks.vector_sink_f() - self.tb.connect(src, snk) - self.rt.initialize(self.tb) - self.rt.run() - - result_data = snk.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - # self.assertEqual(len(snk.tags()), 0) - - def test_file_source_can_seek_after_open(self): - - src = fileio.file_source(self._datafilename, itemsize=gr.sizeof_float) - self.assertTrue(src.seek(0, os.SEEK_SET)) - self.assertTrue(src.seek(len(self._vector) - 1, os.SEEK_SET)) - # Seek past end of file - this will also log a warning - self.assertFalse(src.seek(len(self._vector), os.SEEK_SET)) - # Negative seek - this will also log a warning - self.assertFalse(src.seek(-1, os.SEEK_SET)) - - self.assertTrue(src.seek(1, os.SEEK_END)) - self.assertTrue(src.seek(len(self._vector), os.SEEK_END)) - # Seek past end of file - this will also log a warning - self.assertFalse(src.seek(0, os.SEEK_END)) - - self.assertTrue(src.seek(0, os.SEEK_SET)) - self.assertTrue(src.seek(1, os.SEEK_CUR)) - # Seek past end of file - this will also log a warning - self.assertFalse(src.seek(len(self._vector), os.SEEK_CUR)) - - # def test_begin_tag(self): - # expected_result = self._vector - - # src = blocks.file_source(gr.sizeof_float, self._datafilename) - # src.set_begin_tag(pmt.string_to_symbol("file_begin")) - # snk = blocks.vector_sink_f() - # self.tb.connect(src, snk) - # self.tb.run() - - # result_data = snk.data() - # self.assertFloatTuplesAlmostEqual(expected_result, result_data) - # self.assertEqual(len(snk.tags()), 1) - - # def test_begin_tag_repeat(self): - # expected_result = self._vector + self._vector - - # src = blocks.file_source(gr.sizeof_float, self._datafilename, True) - # src.set_begin_tag(pmt.string_to_symbol("file_begin")) - # head = streamops.head(gr.sizeof_float, 2 * len(self._vector)) - # snk = blocks.vector_sink_f() - # self.tb.connect(src, head, snk) - # self.tb.run() - - # result_data = snk.data() - # self.assertFloatTuplesAlmostEqual(expected_result, result_data) - # tags = snk.tags() - # self.assertEqual(len(tags), 2) - # self.assertEqual(str(tags[0].key), "file_begin") - # self.assertEqual(str(tags[0].value), "0") - # self.assertEqual(tags[0].offset, 0) - # self.assertEqual(str(tags[1].key), "file_begin") - # self.assertEqual(str(tags[1].value), "1") - # self.assertEqual(tags[1].offset, 1000) - - -if __name__ == '__main__': - gr_unittest.run(test_file_source) diff --git a/blocklib/filter/.gitignore b/blocklib/filter/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/filter/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/filter/bench/bm_pfb_channelizer.py b/blocklib/filter/bench/bm_pfb_channelizer.py deleted file mode 100644 index c223118c1..000000000 --- a/blocklib/filter/bench/bm_pfb_channelizer.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# -# SPDX-License-Identifier: GPL-3.0 -# -# GNU Radio Python Flow Graph -# Title: Not titled yet -# GNU Radio version: 3.9.0.0-git - -from gnuradio import gr, blocks, streamops, fft -from gnuradio.kernel.filter import firdes -from gnuradio.kernel.fft import window -from gnuradio.schedulers import nbt -import sys -import signal -from argparse import ArgumentParser -import time -from gnuradio import filter - -class benchmark_pfb_channelizer(gr.flowgraph): - - def __init__(self, args): - gr.flowgraph.__init__(self) - - ################################################## - # Variables - ################################################## - nsamples = args.samples - nchans = args.nchans - attn = args.attenuation - bufsize = args.buffer_size - - taps = firdes.low_pass_2(1, nchans, 1 / 2, 1 / 10, attenuation_dB=attn,window=window.BLACKMAN_hARRIS) - - ################################################## - # Blocks - ################################################## - self.nsrc = blocks.null_source() - self.nsnk = blocks.null_sink(nports=nchans) - self.hd = streamops.head(int(nsamples)) - - if not args.cuda: - self.channelizer = filter.pfb_channelizer_cc( - nchans, - taps, - 1.0) - # self.s2ss = streamops.stream_to_streams(gr.sizeof_gr_complex, nchans) - - ################################################## - # Connections - ################################################## - # nsnks = [] - for ii in range(nchans): - # nsnks.append(blocks.null_sink(gr.sizeof_gr_complex*1)) - self.connect(self.channelizer, ii, self.nsnk, ii) - # self.connect(self.s2ss, ii, self.channelizer, ii) - # self.connect(self.channelizer, self.nsnk) - # self.connect(self.hd, 0, self.s2ss, 0) - self.connect([self.nsrc, self.hd, self.channelizer]) - # self.connect(self.nsrc, 0, self.hd, 0) - else: - self.channelizer = filter.pfb_channelizer_cc( - nchans, - taps, - 1.0, - impl=filter.pfb_channelizer_cc.cuda) - # self.s2ss = streamops.stream_to_streams(gr.sizeof_gr_complex, nchans, impl=streamops.stream_to_streams.cuda) - - ################################################## - # Connections - ################################################## - # nsnks = [] - for ii in range(nchans): - # blk = blocks.null_sink(gr.sizeof_gr_complex*1) - # nsnks.append(blk) - self.connect(self.channelizer, ii, self.nsnk, ii).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H).set_buffer_size(bufsize)) - # self.connect(self.s2ss, ii, self.channelizer, ii).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2D).set_buffer_size(bufsize)) - # self.connect(self.channelizer, ii, nsnks[ii], 0).set_custom_buffer(gr.buffer_cuda_pinned_properties.make().set_buffer_size(bufsize)) - # self.connect(self.s2ss, ii, self.channelizer, ii).set_custom_buffer(gr.buffer_cuda_pinned_properties.make().set_buffer_size(bufsize)) - - # self.connect(self.channelizer, self.nsnk) - # self.connect(self.hd, 0, self.s2ss, 0).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D).set_buffer_size(bufsize)) - self.connect(self.hd, 0, self.channelizer, 0).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D).set_buffer_size(bufsize)) - # self.connect(self.hd, 0, self.s2ss, 0).set_custom_buffer(gr.buffer_cuda_pinned_properties.make().set_buffer_size(bufsize)) - self.connect(self.nsrc, 0, self.hd, 0).set_custom_buffer(gr.buffer_cpu_vmcirc_properties.make(gr.buffer_cpu_vmcirc_type.AUTO).set_buffer_size(bufsize)) - - # sched = nbt.scheduler_nbt("nbtsched") - # self.add_scheduler(sched) - # sched.add_block_group([x.base() for x in nsnks]) - - # self.validate() - - -def main(top_block_cls=benchmark_pfb_channelizer, options=None): - - parser = ArgumentParser(description='Run a flowgraph iterating over parameters for benchmarking') - parser.add_argument('--rt_prio', help='enable realtime scheduling', action='store_true') - parser.add_argument('--samples', type=int, default=1e8) - parser.add_argument('--nchans', type=int, default=4) - parser.add_argument('--attenuation', type=float, default=70) - parser.add_argument('--buffer_size', type=int, default=8192) - parser.add_argument('--cuda', action='store_true') - - args = parser.parse_args() - print(args) - - if args.rt_prio and gr.enable_realtime_scheduling() != gr.RT_OK: - print("Error: failed to enable real-time scheduling.") - - tb = top_block_cls(args) - - def sig_handler(sig=None, frame=None): - tb.stop() - tb.wait() - sys.exit(0) - - signal.signal(signal.SIGINT, sig_handler) - signal.signal(signal.SIGTERM, sig_handler) - - print("starting ...") - startt = time.time() - tb.start() - - tb.wait() - endt = time.time() - print(f'[PROFILE_TIME]{endt-startt}[PROFILE_TIME]') - -if __name__ == '__main__': - main() diff --git a/blocklib/filter/dc_blocker/dc_blocker.yml b/blocklib/filter/dc_blocker/dc_blocker.yml deleted file mode 100644 index 038a77b40..000000000 --- a/blocklib/filter/dc_blocker/dc_blocker.yml +++ /dev/null @@ -1,40 +0,0 @@ -module: filter -block: dc_blocker -label: DC Blocker -blocktype: sync_block -category: '[Core]/Filters' - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - -parameters: -- id: D - label: Delay Line Length - dtype: int - settable: true -- id: long_form - label: Long Form - dtype: bool - settable: false - default: 'true' - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - -- domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/filter/dc_blocker/dc_blocker_cpu.cc b/blocklib/filter/dc_blocker/dc_blocker_cpu.cc deleted file mode 100644 index 32c97f6e3..000000000 --- a/blocklib/filter/dc_blocker/dc_blocker_cpu.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011,2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "dc_blocker_cpu.h" -#include "dc_blocker_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace filter { - -template <class T> -dc_blocker_cpu<T>::dc_blocker_cpu(const typename dc_blocker<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), - d_length(args.D), - d_long_form(args.long_form), - d_ma_0(args.D), - d_ma_1(args.D) -{ - if (d_long_form) { - d_ma_2 = std::make_unique<kernel::filter::moving_averager<T>>(d_length); - d_ma_3 = std::make_unique<kernel::filter::moving_averager<T>>(d_length); - d_delay_line = std::deque<T>(d_length - 1, 0); - } -} - -template <class T> -int dc_blocker_cpu<T>::group_delay() -{ - if (d_long_form) - return (2 * d_length - 2); - else - return d_length - 1; -} - -template <class T> -work_return_t dc_blocker_cpu<T>::work(work_io& wio) -{ - - auto in = wio.inputs()[0].items<T>(); - auto out = wio.outputs()[0].items<T>(); - auto noutput_items = wio.outputs()[0].n_items; - - if (d_long_form) { - T y1, y2, y3, y4, d; - for (size_t i = 0; i < noutput_items; i++) { - y1 = d_ma_0.filter(in[i]); - y2 = d_ma_1.filter(y1); - y3 = d_ma_2->filter(y2); - y4 = d_ma_3->filter(y3); - - d_delay_line.push_back(d_ma_0.delayed_sig()); - d = d_delay_line[0]; - d_delay_line.pop_front(); - - out[i] = d - y4; - } - } - else { - T y1, y2; - for (size_t i = 0; i < noutput_items; i++) { - y1 = d_ma_0.filter(in[i]); - y2 = d_ma_1.filter(y1); - out[i] = d_ma_0.delayed_sig() - y2; - } - } - - wio.outputs()[0].n_produced = noutput_items; - return work_return_t::OK; -} - -} /* namespace filter */ -} /* namespace gr */ diff --git a/blocklib/filter/dc_blocker/dc_blocker_cpu.h b/blocklib/filter/dc_blocker/dc_blocker_cpu.h deleted file mode 100644 index 76da348b2..000000000 --- a/blocklib/filter/dc_blocker/dc_blocker_cpu.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011,2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/dc_blocker.h> -#include <gnuradio/kernel/filter/moving_averager.h> - -namespace gr { -namespace filter { - -template <class T> -class dc_blocker_cpu : public dc_blocker<T> -{ -public: - dc_blocker_cpu(const typename dc_blocker<T>::block_args& args); - - work_return_t work(work_io&) override; - - int group_delay(); - -protected: - int d_length; - bool d_long_form; - kernel::filter::moving_averager<T> d_ma_0; - kernel::filter::moving_averager<T> d_ma_1; - std::unique_ptr<kernel::filter::moving_averager<T>> d_ma_2; - std::unique_ptr<kernel::filter::moving_averager<T>> d_ma_3; - std::deque<T> d_delay_line; -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/examples/.gitignore b/blocklib/filter/examples/.gitignore deleted file mode 100644 index f104652b6..000000000 --- a/blocklib/filter/examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.py diff --git a/blocklib/filter/examples/pfb_channelizer_example.grc b/blocklib/filter/examples/pfb_channelizer_example.grc deleted file mode 100644 index 4cc5d9792..000000000 --- a/blocklib/filter/examples/pfb_channelizer_example.grc +++ /dev/null @@ -1,263 +0,0 @@ -options: - parameters: - author: josh - catch_exceptions: 'True' - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: qt_gui - hier_block_src_path: '.:' - id: pfb_channelizer_example - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: Not titled yet - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: samp_rate - id: variable - parameters: - comment: '' - value: '32000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [184, 12] - rotation: 0 - state: enabled -- name: analog_noise_source_0 - id: analog_noise_source - parameters: - T: complex - affinity: '' - alias: '' - amplitude: '0.1' - comment: '' - domain: cpu - maxoutbuf: '0' - minoutbuf: '0' - seed: '0' - showports: 'False' - type: analog.noise_t.GAUSSIAN - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [248, 604.0] - rotation: 0 - state: true -- name: analog_sig_source_0 - id: analog_sig_source - parameters: - T: complex - affinity: '' - alias: '' - ampl: '1.0' - comment: '' - domain: cpu - frequency: '10000' - maxoutbuf: '0' - minoutbuf: '0' - offset: '0' - phase: '0' - sampling_freq: samp_rate - showports: 'False' - waveform: analog.waveform_t.COS - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [160, 428.0] - rotation: 0 - state: true -- name: analog_sig_source_0_0 - id: analog_sig_source - parameters: - T: complex - affinity: '' - alias: '' - ampl: '1.0' - comment: '' - domain: cpu - frequency: '1000' - maxoutbuf: '0' - minoutbuf: '0' - offset: '0' - phase: '0' - sampling_freq: samp_rate - showports: 'False' - waveform: analog.waveform_t.COS - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [160, 252.0] - rotation: 0 - state: true -- name: filter_pfb_channelizer_0 - id: filter_pfb_channelizer - parameters: - T: complex - affinity: '' - alias: '' - comment: '' - domain: cpu - maxoutbuf: '0' - minoutbuf: '0' - numchans: '2' - oversample_rate: '1' - showports: 'False' - taps: filterk.firdes.low_pass(1.0, 2.0, 0.45, 0.01) - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [736, 204.0] - rotation: 0 - state: true -- name: import_0 - id: import - parameters: - alias: '' - comment: '' - imports: from gnuradio.kernel import fft as fftk - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [352, 28.0] - rotation: 0 - state: true -- name: import_0_0 - id: import - parameters: - alias: '' - comment: '' - imports: from gnuradio.kernel import filter as filterk - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [456, 28.0] - rotation: 0 - state: true -- name: math_add_0 - id: math_add - parameters: - T: complex - affinity: '' - alias: '' - comment: '' - domain: cpu - maxoutbuf: '0' - minoutbuf: '0' - nports: '3' - showports: 'False' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [416, 388.0] - rotation: 0 - state: true -- name: qtgui_freq_sink_0_0 - id: qtgui_freq_sink - parameters: - T: complex - affinity: '' - alias: '' - bw: samp_rate / 2 - comment: '' - domain: cpu - fc: '0' - fftsize: '1024' - gui_hint: '' - name: '"1"' - nconnections: '1' - showports: 'False' - wintype: '5' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1168, 180.0] - rotation: 0 - state: enabled -- name: qtgui_freq_sink_0_0_0 - id: qtgui_freq_sink - parameters: - T: complex - affinity: '' - alias: '' - bw: samp_rate / 2 - comment: '' - domain: cpu - fc: '0' - fftsize: '1024' - gui_hint: '' - name: '"2"' - nconnections: '1' - showports: 'False' - wintype: '5' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1096, 372.0] - rotation: 0 - state: enabled -- name: qtgui_freq_sink_0_1 - id: qtgui_freq_sink - parameters: - T: complex - affinity: '' - alias: '' - bw: samp_rate - comment: '' - domain: cpu - fc: '0' - fftsize: '1024' - gui_hint: '' - name: '"ALL"' - nconnections: '1' - showports: 'False' - wintype: '5' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [720, 404.0] - rotation: 0 - state: enabled - -connections: -- [analog_noise_source_0, '0', math_add_0, '2'] -- [analog_sig_source_0, '0', math_add_0, '1'] -- [analog_sig_source_0_0, '0', math_add_0, '0'] -- [filter_pfb_channelizer_0, '0', qtgui_freq_sink_0_0, '0'] -- [filter_pfb_channelizer_0, '1', qtgui_freq_sink_0_0_0, '0'] -- [math_add_0, '0', filter_pfb_channelizer_0, '0'] -- [math_add_0, '0', qtgui_freq_sink_0_1, '0'] - -metadata: - file_format: 1 diff --git a/blocklib/filter/fir_filter/fir_filter.yml b/blocklib/filter/fir_filter/fir_filter.yml deleted file mode 100644 index 27c495987..000000000 --- a/blocklib/filter/fir_filter/fir_filter.yml +++ /dev/null @@ -1,70 +0,0 @@ -module: filter -block: fir_filter -label: FIR Filter -blocktype: block -category: '[Core]/Filters' - -typekeys: - - id: IN_T - type: class - options: - - cf32 - - rf32 - - ri16 - - - id: OUT_T - type: class - options: - - cf32 - - rf32 - - ri16 - - - id: TAP_T - type: class - options: - - cf32 - - rf32 - -type_inst: - - value: [cf32, cf32, cf32] - label: Complex->Complex (Complex Taps) - - value: [cf32, cf32, rf32] - label: Complex->Complex (Real Taps) - - value: [rf32, cf32, cf32] - label: Float->Complex (Complex Taps) - - value: [rf32, rf32, rf32] - label: Float->Float (Real Taps) - - value: [rf32, ri16, rf32] - label: Float->Short (Real Taps) - - value: [ri16, cf32, cf32] - label: Short->Complex (Complex Taps) - -parameters: -- id: decimation - label: Decimation - dtype: size - settable: false - grc: - default: 1 -- id: taps - label: Taps - dtype: TAP_T - container: vector - settable: true - -ports: -- domain: stream - id: in - direction: input - type: typekeys/IN_T - -- domain: stream - id: out - direction: output - type: typekeys/OUT_T - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/filter/fir_filter/fir_filter_cpu.cc b/blocklib/filter/fir_filter/fir_filter_cpu.cc deleted file mode 100644 index bce57909a..000000000 --- a/blocklib/filter/fir_filter/fir_filter_cpu.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "fir_filter_cpu.h" -#include "fir_filter_cpu_gen.h" - -namespace gr { -namespace filter { - -template <class IN_T, class OUT_T, class TAP_T> -fir_filter_cpu<IN_T, OUT_T, TAP_T>::fir_filter_cpu( - const typename fir_filter<IN_T, OUT_T, TAP_T>::block_args& args) - : INHERITED_CONSTRUCTORS(IN_T, OUT_T, TAP_T), d_fir(args.taps) -{ - this->set_relative_rate(1.0 / args.decimation); - this->declare_noconsume(d_fir.ntaps() - 1); - // const int alignment_multiple = volk_get_alignment() / sizeof(float); - // this->set_alignment(std::max(1, alignment_multiple)); -} - -template <class IN_T, class OUT_T, class TAP_T> -void fir_filter_cpu<IN_T, OUT_T, TAP_T>::on_parameter_change(param_action_sptr action) -{ - // This will set the underlying PMT - block::on_parameter_change(action); - - // Do more updating for certain parameters - if (action->id() == fir_filter<IN_T, OUT_T, TAP_T>::id_taps) { - auto taps = pmtf::get_as<std::vector<TAP_T>>(*this->param_taps); - d_fir.set_taps(taps); - this->declare_noconsume(d_fir.ntaps() - 1); - } -} - -template <class IN_T, class OUT_T, class TAP_T> -work_return_t fir_filter_cpu<IN_T, OUT_T, TAP_T>::enforce_constraints(work_io& wio) -{ - // Do forecasting - size_t ninput = wio.inputs()[0].n_items; - size_t noutput = wio.outputs()[0].n_items; - - auto decim = pmtf::get_as<size_t>(*this->param_decimation); - - auto min_ninput = - std::min(noutput * decim + this->noconsume(), ninput - this->noconsume()); - auto noutput_items = std::min(min_ninput / decim, noutput); - - if (noutput_items <= 0) { - return work_return_t::INSUFFICIENT_INPUT_ITEMS; - } - - wio.outputs()[0].n_items = noutput_items; - wio.inputs()[0].n_items = noutput_items * decim; - - return work_return_t::OK; -} - -template <class IN_T, class OUT_T, class TAP_T> -work_return_t fir_filter_cpu<IN_T, OUT_T, TAP_T>::work(work_io& wio) -{ - size_t ninput = wio.inputs()[0].n_items; - size_t noutput = wio.outputs()[0].n_items; - - auto in = wio.inputs()[0].items<IN_T>(); - auto out = wio.outputs()[0].items<OUT_T>(); - - auto decim = pmtf::get_as<size_t>(*this->param_decimation); - - if (decim == 1) { - d_fir.filterN(out, in, noutput); - } - else { - d_fir.filterNdec(out, in, noutput, decim); - } - - wio.consume_each(ninput); - wio.produce_each(noutput); - - return work_return_t::OK; -} - -} /* namespace filter */ -} /* namespace gr */ diff --git a/blocklib/filter/fir_filter/fir_filter_cpu.h b/blocklib/filter/fir_filter/fir_filter_cpu.h deleted file mode 100644 index 6ca61bb87..000000000 --- a/blocklib/filter/fir_filter/fir_filter_cpu.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/fir_filter.h> -#include <gnuradio/kernel/filter/fir_filter.h> - -namespace gr { -namespace filter { - -template <class IN_T, class OUT_T, class TAP_T> -class fir_filter_cpu : public fir_filter<IN_T, OUT_T, TAP_T> -{ -public: - fir_filter_cpu(const typename fir_filter<IN_T, OUT_T, TAP_T>::block_args& args); - - work_return_t work(work_io&) override; - - void on_parameter_change(param_action_sptr action) override; - - -private: - work_return_t enforce_constraints(work_io& wio) override; - - gr::kernel::filter::fir_filter<IN_T, OUT_T, TAP_T> d_fir; -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/fir_filter/qa_fir_filter.py b/blocklib/filter/fir_filter/qa_fir_filter.py deleted file mode 100644 index 9e3663f69..000000000 --- a/blocklib/filter/fir_filter/qa_fir_filter.py +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2008,2010,2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, filter, blocks -from gnuradio.kernel.filter import firdes -import math - -def fir_filter(x, taps, decim=1): - y = [] - m = decim *((len(x)-len(taps)+1) // decim) - - for i in range(0, m, decim): - yi = 0 - for j in range(len(taps)): - yi += taps[len(taps) - 1 - j] * x[i + j] - y.append(yi) - return y - - -class test_filter(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_fir_filter_fff_001(self): - decim = 1 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fff(decim, taps) - dst = blocks.vector_sink_f() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_fff_002(self): - decim = 4 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fff(decim, taps) - dst = blocks.vector_sink_f() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccf_001(self): - decim = 1 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccf(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccf_002(self): - decim = 4 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccf(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccc_001(self): - decim = 1 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccc_002(self): - decim = 1 - taps = firdes.low_pass(1, 1, 0.1, 0.01) - src_data = [0]*len(taps) + 10 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccc_003(self): - decim = 4 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_scc_001(self): - decim = 1 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_s(src_data) - op = filter.fir_filter_scc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_scc_002(self): - decim = 4 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_s(src_data) - op = filter.fir_filter_scc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_fsf_001(self): - decim = 1 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - expected_data = [int(e) for e in expected_data] - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fsf(decim, taps) - dst = blocks.vector_sink_s() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_fsf_002(self): - decim = 4 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - expected_data = [int(e) for e in expected_data] - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fsf(decim, taps) - dst = blocks.vector_sink_s() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - -if __name__ == '__main__': - gr_unittest.run(test_filter) diff --git a/blocklib/filter/iir_filter/iir_filter.yml b/blocklib/filter/iir_filter/iir_filter.yml deleted file mode 100644 index 39b2c246f..000000000 --- a/blocklib/filter/iir_filter/iir_filter.yml +++ /dev/null @@ -1,69 +0,0 @@ -module: filter -block: iir_filter -label: IIR Filter -blocktype: sync_block -category: '[Core]/Filters' - -typekeys: - - id: T_IN - type: class - options: - - cf32 - - rf32 - - id: T_OUT - type: class - options: - - cf32 - - rf32 - - id: TAP_T - type: class - options: - - cf64 - - cf32 - - rf64 - - rf32 -type_inst: - - value: [rf32, rf32, rf64] - label: Float->Float (Double Taps) - - value: [cf32, cf32, rf32] - label: Complex->Complex (Float Taps) - - value: [cf32, cf32, rf64] - label: Complex->Complex (Double Taps) - - value: [cf32, cf32, cf32] - label: Complex->Complex (Complex Taps) - - value: [cf32, cf32, cf64] - label: Complex->Complex (Complex Double Taps) - -parameters: -- id: fftaps - label: Feed Forward Taps - dtype: TAP_T - container: vector - settable: true -- id: fbtaps - label: Feed Back Taps - dtype: TAP_T - container: vector - settable: true -- id: oldstyle - label: Old Style Taps - dtype: bool - default: 'true' - settable: false - -ports: - - domain: stream - id: in - direction: input - type: typekeys/T_IN - - - domain: stream - id: out - direction: output - type: typekeys/T_OUT - -implementations: - - id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/filter/iir_filter/iir_filter_cpu.cc b/blocklib/filter/iir_filter/iir_filter_cpu.cc deleted file mode 100644 index ace7ab312..000000000 --- a/blocklib/filter/iir_filter/iir_filter_cpu.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "iir_filter_cpu.h" -#include "iir_filter_cpu_gen.h" - -namespace gr { -namespace filter { - -template <class T_IN, class T_OUT, class TAP_T> -iir_filter_cpu<T_IN, T_OUT, TAP_T>::iir_filter_cpu( - const typename iir_filter<T_IN, T_OUT, TAP_T>::block_args& args) - : INHERITED_CONSTRUCTORS(T_IN, T_OUT, TAP_T), - d_iir(args.fftaps, args.fbtaps, args.oldstyle) -{ -} - -template <class T_IN, class T_OUT, class TAP_T> -work_return_t iir_filter_cpu<T_IN, T_OUT, TAP_T>::work(work_io& wio) -{ - auto in = wio.inputs()[0].items<T_IN>(); - auto out = wio.outputs()[0].items<T_OUT>(); - auto noutput_items = wio.outputs()[0].n_items; - - d_iir.filter_n(out, in, noutput_items); - wio.produce_each(noutput_items); - return work_return_t::OK; -} - -} /* namespace filter */ -} /* namespace gr */ diff --git a/blocklib/filter/iir_filter/iir_filter_cpu.h b/blocklib/filter/iir_filter/iir_filter_cpu.h deleted file mode 100644 index 556c926e4..000000000 --- a/blocklib/filter/iir_filter/iir_filter_cpu.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/iir_filter.h> - -#include <gnuradio/kernel/filter/iir_filter.h> - -namespace gr { -namespace filter { - -template <class T_IN, class T_OUT, class TAP_T> -class iir_filter_cpu : public iir_filter<T_IN, T_OUT, TAP_T> -{ -public: - iir_filter_cpu(const typename iir_filter<T_IN, T_OUT, TAP_T>::block_args& args); - - work_return_t work(work_io&) override; - -private: - bool d_updated; - kernel::filter::iir_filter<T_IN, T_OUT, TAP_T> d_iir; - - void on_parameter_change(param_action_sptr action) override - { - // This will set the underlying PMT - block::on_parameter_change(action); - auto fftaps = pmtf::get_as<std::vector<TAP_T>>(*this->param_fftaps); - auto fbtaps = pmtf::get_as<std::vector<TAP_T>>(*this->param_fbtaps); - - // Do more updating for certain parameters - if (action->id() == iir_filter<T_IN, T_OUT, TAP_T>::id_fftaps || - action->id() == iir_filter<T_IN, T_OUT, TAP_T>::id_fbtaps) { - d_iir.set_taps(fftaps, fbtaps); - } - } -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/include/gnuradio/filter/.gitignore b/blocklib/filter/include/gnuradio/filter/.gitignore deleted file mode 100644 index d53050d7d..000000000 --- a/blocklib/filter/include/gnuradio/filter/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build diff --git a/blocklib/filter/include/gnuradio/filter/api.h b/blocklib/filter/include/gnuradio/filter/api.h deleted file mode 100644 index 0e90bde23..000000000 --- a/blocklib/filter/include/gnuradio/filter/api.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/attributes.h> - -#ifdef gnuradio_filter_EXPORTS -#define FILTER_API __GR_ATTR_EXPORT -#else -#define FILTER_API __GR_ATTR_IMPORT -#endif diff --git a/blocklib/filter/include/gnuradio/filter/meson.build b/blocklib/filter/include/gnuradio/filter/meson.build deleted file mode 100644 index 2a4f9f1af..000000000 --- a/blocklib/filter/include/gnuradio/filter/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -headers = [ - 'api.h', - # 'single_pole_iir.h', - # 'polyphase_filterbank.h', - # 'firdes.h', - # 'fir_filter.h', - # 'interpolator_taps.h', - # 'mmse_fir_interpolator_ff.h' -] - -install_headers(headers, subdir : 'gnuradio/filter') diff --git a/blocklib/filter/lib/.gitignore b/blocklib/filter/lib/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/filter/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/filter/lib/meson.build b/blocklib/filter/lib/meson.build deleted file mode 100644 index 85d029726..000000000 --- a/blocklib/filter/lib/meson.build +++ /dev/null @@ -1,60 +0,0 @@ -sources = [ - # 'moving_averager.cc', - # 'fir_filter.cc', - # 'mmse_fir_interpolator_ff.cc', - # 'polyphase_filterbank.cc', - # 'firdes.cc' -] - -filter_sources += sources -filter_deps += [gnuradio_gr_dep, gnuradio_blocklib_fft_dep, volk_dep, fmt_dep, pmtf_dep, gr_kernel_filter_lib_dep] -block_cpp_args = ['-DHAVE_CPU'] -if IMPLEMENT_CUDA - block_cpp_args += '-DHAVE_CUDA' - -# gnuradio_blocklib_filter_cu = library('gnuradio-blocklib-filter-cu', -# filter_cu_sources, -# include_directories : incdir, -# install : true, -# dependencies : [cuda_dep]) - -# gnuradio_blocklib_filter_cu_dep = declare_dependency(include_directories : incdir, -# link_with : gnuradio_blocklib_filter_cu, -# dependencies : cuda_dep) - - filter_deps += [cuda_dep, cusp_dep] -endif - - -incdir = include_directories(['../include/gnuradio/filter','../include']) -gnuradio_blocklib_filter_lib = library('gnuradio-blocklib-filter', - filter_sources, - include_directories : incdir, - install : true, - link_language: 'cpp', - dependencies : filter_deps, - cpp_args : block_cpp_args) - -gnuradio_blocklib_filter_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_filter_lib, - dependencies : filter_deps) - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'filter') -cmake.configure_package_config_file( - name : 'gnuradio-filter', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_filter_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-filter', - filebase : 'gnuradio-filter', - description : 'GNU Radio Filter Module') diff --git a/blocklib/filter/moving_average/moving_average.yml b/blocklib/filter/moving_average/moving_average.yml deleted file mode 100644 index 4110014c6..000000000 --- a/blocklib/filter/moving_average/moving_average.yml +++ /dev/null @@ -1,50 +0,0 @@ -module: filter -block: moving_average -label: Moving Average -blocktype: block -category: '[Core]/Filters' - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - -parameters: -- id: length - label: Length - dtype: size - settable: true -- id: scale - label: Scale - dtype: T - settable: true -- id: max_iter - label: Max Iter - dtype: size - settable: false - default: 4096 -- id: vlen - label: Vector Length - dtype: size - settable: false - default: 1 - - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - -- domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu -- id: cuda - -file_format: 1 diff --git a/blocklib/filter/moving_average/moving_average_cpu.cc b/blocklib/filter/moving_average/moving_average_cpu.cc deleted file mode 100644 index 14cdcff73..000000000 --- a/blocklib/filter/moving_average/moving_average_cpu.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2010,2013,2017,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "moving_average_cpu.h" -#include "moving_average_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace filter { - -template <class T> -moving_average_cpu<T>::moving_average_cpu( - const typename moving_average<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), - d_length(args.length), - d_scale(args.scale), - d_max_iter(args.max_iter), - d_vlen(args.vlen), - d_new_length(args.length), - d_new_scale(args.scale) -{ - d_sum = std::vector<T>(d_vlen); - d_history = std::vector<T>(d_vlen * (d_length - 1)); -} - -template <class T> -work_return_t moving_average_cpu<T>::work(work_io& wio) -{ - if (wio.inputs()[0].n_items < d_length) { - wio.outputs()[0].n_produced = 0; - wio.inputs()[0].n_consumed = 0; - return work_return_t::INSUFFICIENT_INPUT_ITEMS; - } - - if (d_updated) { - d_length = d_new_length; - d_scale = d_new_scale; - d_updated = false; - wio.outputs()[0].n_produced = 0; - wio.inputs()[0].n_consumed = 0; - return work_return_t::OK; - } - - auto in = wio.inputs()[0].items<T>(); - auto out = wio.outputs()[0].items<T>(); - - size_t noutput_items = - std::min((wio.inputs()[0].n_items - d_length), wio.outputs()[0].n_items); - - auto num_iter = (noutput_items > d_max_iter) ? d_max_iter : noutput_items; - auto tr = wio.inputs()[0].buf().total_read(); - - if (tr == 0) { // for the first no history case - for (size_t i = 0; i < num_iter; i++) { - for (size_t elem = 0; elem < d_vlen; elem++) { - d_sum[elem] += in[i * d_vlen + elem]; - out[i * d_vlen + elem] = d_sum[elem] * d_scale; - if (i >= (d_length - 1)) { - d_sum[elem] -= in[(i - (d_length - 1)) * d_vlen + elem]; - } - } - } - } - else { - for (size_t i = 0; i < num_iter; i++) { - for (size_t elem = 0; elem < d_vlen; elem++) { - - d_sum[elem] += in[(i + d_length - 1) * d_vlen + elem]; - out[i * d_vlen + elem] = d_sum[elem] * d_scale; - d_sum[elem] -= in[i * d_vlen + elem]; - } - } - } - - // don't consume the last d_length-1 samples - wio.outputs()[0].n_produced = num_iter; - wio.inputs()[0].n_consumed = tr == 0 ? num_iter - (d_length - 1) : num_iter; - return work_return_t::OK; -} // namespace filter - -} // namespace filter -} /* namespace gr */ diff --git a/blocklib/filter/moving_average/moving_average_cpu.h b/blocklib/filter/moving_average/moving_average_cpu.h deleted file mode 100644 index c9ef0290d..000000000 --- a/blocklib/filter/moving_average/moving_average_cpu.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2010,2013,2017,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/moving_average.h> - -#include <vector> - -namespace gr { -namespace filter { - -template <class T> -class moving_average_cpu : public moving_average<T> -{ -public: - moving_average_cpu(const typename moving_average<T>::block_args& args); - - work_return_t work(work_io&) override; - - int group_delay(); - -protected: - size_t d_length; - T d_scale; - size_t d_max_iter; - size_t d_vlen; - T d_scalar_sum; - std::vector<T> d_sum; - - std::vector<T> d_history; - - size_t d_new_length; - T d_new_scale; - bool d_updated = false; -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/moving_average/moving_average_cuda.cc b/blocklib/filter/moving_average/moving_average_cuda.cc deleted file mode 100644 index 68c677d88..000000000 --- a/blocklib/filter/moving_average/moving_average_cuda.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "moving_average_cuda.h" -#include "moving_average_cuda_gen.h" - -namespace gr { -namespace filter { - -template <class T> -moving_average_cuda<T>::moving_average_cuda( - const typename moving_average<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), - d_length(args.length), - d_scale(args.scale), - d_max_iter(args.max_iter), - d_vlen(args.vlen), - d_new_length(args.length), - d_new_scale(args.scale) -{ - std::vector<T> taps(d_length); - for (size_t i = 0; i < d_length; i++) { - taps[i] = (float)1.0 * d_scale; - } - - p_kernel_full = - std::make_shared<cusp::convolve<T, T>>(taps, cusp::convolve_mode_t::FULL_TRUNC); - p_kernel_valid = - std::make_shared<cusp::convolve<T, T>>(taps, cusp::convolve_mode_t::VALID); -} - -template <class T> -work_return_t moving_average_cuda<T>::work(work_io& wio) -{ - if (wio.inputs()[0].n_items < d_length) { - wio.outputs()[0].n_produced = 0; - wio.inputs()[0].n_consumed = 0; - return work_return_t::INSUFFICIENT_INPUT_ITEMS; - } - - auto in = wio.inputs()[0].items<T>(); - auto out = wio.outputs()[0].items<T>(); - - size_t noutput_items = std::min((wio.inputs()[0].n_items), wio.outputs()[0].n_items); - - // auto num_iter = (noutput_items > d_max_iter) ? d_max_iter : noutput_items; - auto num_iter = noutput_items; - auto tr = wio.inputs()[0].buf().total_read(); - - if (tr == 0) { - p_kernel_full->launch_default_occupancy({ in }, { out }, num_iter); - } - else { - p_kernel_valid->launch_default_occupancy({ in }, { out }, num_iter); - } - - // don't consume the last d_length-1 samples - wio.outputs()[0].n_produced = tr == 0 ? num_iter : num_iter - (d_length - 1); - wio.inputs()[0].n_consumed = - tr == 0 ? num_iter - (d_length - 1) : num_iter - (d_length - 1); - return work_return_t::OK; -} // namespace filter - -} // namespace filter -} /* namespace gr */ diff --git a/blocklib/filter/moving_average/moving_average_cuda.h b/blocklib/filter/moving_average/moving_average_cuda.h deleted file mode 100644 index dbaf0dacd..000000000 --- a/blocklib/filter/moving_average/moving_average_cuda.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/moving_average.h> - -#include <vector> - -#include <cusp/convolve.cuh> - -namespace gr { -namespace filter { - -template <class T> -class moving_average_cuda : public moving_average<T> -{ -public: - moving_average_cuda(const typename moving_average<T>::block_args& args); - - work_return_t work(work_io&) override; - - int group_delay(); - -protected: - size_t d_length; - T d_scale; - size_t d_max_iter; - size_t d_vlen; - - size_t d_new_length; - T d_new_scale; - bool d_updated = false; - - std::shared_ptr<cusp::convolve<T, T>> p_kernel_full; - std::shared_ptr<cusp::convolve<T, T>> p_kernel_valid; -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler.yml b/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler.yml deleted file mode 100644 index a95e28a87..000000000 --- a/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler.yml +++ /dev/null @@ -1,79 +0,0 @@ -module: filter -block: pfb_arb_resampler -label: PFB Arbitrary Resampler -blocktype: block -category: '[Core]/Resamplers' - -typekeys: - - id: IN_T - type: class - options: - - cf32 - - rf32 - - id: OUT_T - type: class - options: - - cf32 - - rf32 - - id: TAP_T - type: class - options: - - cf32 - - rf32 - -type_inst: - - value: [cf32, cf32, cf32] - label: Complex->Complex (Complex Taps) - - value: [cf32, cf32, rf32] - label: Complex->Complex (Real Taps) - - value: [rf32, rf32, rf32] - label: Float->Float (Real Taps) - -parameters: -- id: rate - label: Rate - dtype: rf32 - settable: true -- id: taps - label: Taps - dtype: TAP_T - container: vector - settable: true -- id: filter_size - label: Filter Size - dtype: rf32 - settable: false - default: 32 - - -# Example Ports -ports: -- domain: stream - id: in - direction: input - type: typekeys/IN_T - -- domain: stream - id: out - direction: output - type: typekeys/OUT_T - -callbacks: -- id: group_delay - return: size_t - const: true -- id: phase_offset - return: rf32 - args: - - id: freq - dtype: rf32 - - id: fs - dtype: rf32 - const: true - - -implementations: -- id: cpu -# - id: cuda - -file_format: 1
\ No newline at end of file diff --git a/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler_cpu.cc b/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler_cpu.cc deleted file mode 100644 index 8d7a1eceb..000000000 --- a/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler_cpu.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "pfb_arb_resampler_cpu.h" -#include "pfb_arb_resampler_cpu_gen.h" - -namespace gr { -namespace filter { - -template <> -std::vector<gr_complex> -pfb_arb_resampler_cpu<gr_complex, gr_complex, gr_complex>::create_taps(float rate, - size_t flt_size, - float atten) -{ - auto ftaps = create_taps_float(rate, flt_size, atten); - std::vector<gr_complex> ctaps; - for (auto& f : ftaps) { - ctaps.push_back(gr_complex(f, 0.0)); - } - return ctaps; -} - -template <class IN_T, class OUT_T, class TAP_T> -std::vector<TAP_T> pfb_arb_resampler_cpu<IN_T, OUT_T, TAP_T>::create_taps(float rate, - size_t flt_size, - float atten) -{ - return create_taps_float(rate, flt_size, atten); -} - - -template <class IN_T, class OUT_T, class TAP_T> -pfb_arb_resampler_cpu<IN_T, OUT_T, TAP_T>::pfb_arb_resampler_cpu( - const typename pfb_arb_resampler<IN_T, OUT_T, TAP_T>::block_args& args) - : INHERITED_CONSTRUCTORS(IN_T, OUT_T, TAP_T) -{ - - std::vector<TAP_T> taps = args.taps; - if (taps.empty()) { - taps = create_taps(args.rate, args.filter_size, 100.0); - } - - d_resamp = std::make_unique<kernel::filter::pfb_arb_resampler<IN_T, OUT_T, TAP_T>>( - args.rate, taps, args.filter_size); - this->declare_noconsume(d_resamp->taps_per_filter() - 1); - - this->set_relative_rate(args.rate); - if (args.rate >= 1.0f) { - size_t output_multiple = std::max<size_t>(args.rate, args.filter_size); - this->set_output_multiple(output_multiple); - } - - d_padding_samps = this->noconsume(); - d_padding_vec.resize(d_padding_samps * 2 + 1); -} - - -template <class IN_T, class OUT_T, class TAP_T> -work_return_t pfb_arb_resampler_cpu<IN_T, OUT_T, TAP_T>::enforce_constraints(work_io& wio) -{ - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - - // Constrain inputs based on outputs - size_t nin = 0; - size_t nout = (noutput_items / this->output_multiple()) * this->output_multiple(); - - if (nout / this->relative_rate() < 1) { - nin = this->relative_rate() + this->noconsume(); - } - else { - nin = nout / this->relative_rate() + this->noconsume(); - } - - if (ninput_items < nin) { - nin = ninput_items; - // Then we have to constrain from input to output - nout = (((ninput_items - this->noconsume()) * this->relative_rate()) / - this->output_multiple()) * - this->output_multiple(); - } - - if (nout < this->output_multiple()) { - return work_return_t::INSUFFICIENT_INPUT_ITEMS; - } - - - wio.inputs()[0].n_items = nin - this->noconsume(); - wio.outputs()[0].n_items = nout; - - return work_return_t::OK; -} - -template <class IN_T, class OUT_T, class TAP_T> -work_return_t pfb_arb_resampler_cpu<IN_T, OUT_T, TAP_T>::work(work_io& wio) -{ - - auto in = wio.inputs()[0].items<IN_T>(); - auto out = wio.outputs()[0].items<OUT_T>(); - - auto nitems = wio.inputs()[0].n_items; - - - if (!d_init_padding) { - d_padding_samps = this->noconsume(); - d_init_padding = true; - } - - int nitems_read; - int processed; - if (d_padding_samps) { - // size_t nfilt = std::min(nfilt, ninput_items); - size_t npad = std::min(nitems, d_padding_samps); - - std::copy(in, in + npad, d_padding_vec.data() + npad); - processed = d_resamp->filter(out, d_padding_vec.data(), npad, nitems_read); - d_padding_samps -= npad; - nitems_read -= npad; - } - else { - processed = d_resamp->filter(out, in, nitems, nitems_read); - } - - wio.consume_each(nitems_read); - wio.produce_each(processed); - return work_return_t::OK; -} - -} /* namespace filter */ -} /* namespace gr */ diff --git a/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler_cpu.h b/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler_cpu.h deleted file mode 100644 index a19a43ad3..000000000 --- a/blocklib/filter/pfb_arb_resampler/pfb_arb_resampler_cpu.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/pfb_arb_resampler.h> -#include <gnuradio/kernel/fft/window.h> -#include <gnuradio/kernel/filter/firdes.h> -#include <gnuradio/kernel/filter/optfir.h> -#include <gnuradio/kernel/filter/pfb_arb_resampler.h> - -using namespace gr::kernel::filter; - -namespace gr { -namespace filter { - -template <class IN_T, class OUT_T, class TAP_T> -class pfb_arb_resampler_cpu : public pfb_arb_resampler<IN_T, OUT_T, TAP_T> -{ -public: - pfb_arb_resampler_cpu( - const typename pfb_arb_resampler<IN_T, OUT_T, TAP_T>::block_args& args); - - work_return_t work(work_io&) override; - virtual size_t group_delay() const override { return d_resamp->group_delay(); } - virtual float phase_offset(float freq, float fs) const override - { - return d_resamp->phase_offset(freq, fs); - }; - -private: - std::unique_ptr<kernel::filter::pfb_arb_resampler<IN_T, OUT_T, TAP_T>> d_resamp; - size_t d_history; - - bool d_init_padding = false; - size_t d_padding_samps = 0; - std::vector<IN_T> d_padding_vec; - - work_return_t enforce_constraints(work_io&) override; - - std::vector<TAP_T> create_taps(float rate, size_t flt_size = 32, float atten = 100); - - std::vector<float> - create_taps_float(float rate, size_t flt_size = 32, float atten = 100) - { - // # Create a filter that covers the full bandwidth of the output signal - - // # If rate >= 1, we need to prevent images in the output, - // # so we have to filter it to less than half the channel - // # width of 0.5. If rate < 1, we need to filter to less - // # than half the output signal's bw to avoid aliasing, so - // # the half-band here is 0.5*rate. - - float percent = 0.80; - if (rate < 1) { - float halfband = 0.5 * rate; - float bw = percent * halfband; - float tb = (percent / 2.0) * halfband; - // float ripple = 0.1; - - - // # As we drop the bw factor, the optfir filter has a harder time converging; - // # using the firdes method here for better results. - return firdes::low_pass_2(flt_size, - flt_size, - bw, - tb, - atten, - gr::kernel::fft::window::window_t::BLACKMAN_HARRIS); - } - else { - float halfband = 0.5; - float bw = percent * halfband; - float tb = (percent / 2.0) * halfband; - float ripple = 0.1; - std::vector<double> dtaps; - - while (true) { - try { - dtaps = gr::kernel::filter::optfir::low_pass( - flt_size, flt_size, bw, bw + tb, ripple, atten); - break; - } catch (std::exception& e) { - ripple += 0.01; - this->d_logger->warn( - "Warning: set ripple to {:4f} dB. If this is a problem, adjust " - "the attenuation or create your own filter taps.", - ripple); - - // # Build in an exit strategy; if we've come this far, it ain't - // working. - if (ripple >= 1.0) { - throw std::runtime_error( - "optfir could not generate an appropriate filter."); - } - } - } - - return std::vector<float>(dtaps.begin(), dtaps.end()); - } - } - - - void on_parameter_change(param_action_sptr action) override - { - // This will set the underlying PMT - block::on_parameter_change(action); - - // Do more updating for certain parameters - if (action->id() == pfb_arb_resampler<IN_T, OUT_T, TAP_T>::id_taps) { - d_resamp->set_taps(pmtf::get_as<std::vector<TAP_T>>(*this->param_taps)); - d_history = d_resamp->taps_per_filter(); - } - else if (action->id() == pfb_arb_resampler<IN_T, OUT_T, TAP_T>::id_rate) { - d_resamp->set_rate(pmtf::get_as<float>(*this->param_rate)); - this->set_relative_rate(pmtf::get_as<float>(*this->param_rate)); - } - } -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/pfb_arb_resampler/qa_pfb_arb_resampler.py b/blocklib/filter/pfb_arb_resampler/qa_pfb_arb_resampler.py deleted file mode 100644 index 5e7fab5cf..000000000 --- a/blocklib/filter/pfb_arb_resampler/qa_pfb_arb_resampler.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, fft, filter, blocks -from gnuradio.kernel.filter import firdes -from gnuradio.kernel.fft import window -import math - - -def sig_source_c(samp_rate, freq, amp, N): - t = [float(x) / samp_rate for x in range(N)] - y = [math.cos(2. * math.pi * freq * x) + - 1j * math.sin(2. * math.pi * freq * x) for x in t] - return y - - -def sig_source_f(samp_rate, freq, amp, N): - t = [float(x) / samp_rate for x in range(N)] - y = [math.sin(2. * math.pi * freq * x) for x in t] - return y - - -class test_pfb_arb_resampler(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_fff_000(self): - N = 500 # number of samples to use - fs = 5000.0 # baseband sampling rate - rrate = 2.3421 # resampling rate - - nfilts = 32 - taps = firdes.low_pass_2( - nfilts, - nfilts * fs, - fs / 2, - fs / 10, - attenuation_dB=80, - window=window.BLACKMAN_hARRIS) - - freq = 121.213 - data = sig_source_f(fs, freq, 1, N) - signal = blocks.vector_source_f(data) - pfb = filter.pfb_arb_resampler_fff(rrate, taps, nfilts) - snk = blocks.vector_sink_f() - - self.tb.connect((signal, pfb, snk)) - self.tb.run() - - Ntest = 50 - L = len(snk.data()) - - # Get group delay and estimate of phase offset from the filter itself. - delay = pfb.group_delay() - phase = pfb.phase_offset(freq, fs) - - # Create a timeline offset by the filter's group delay - t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # Data of the sinusoid at frequency freq with the delay and phase - # offset. - expected_data = [math.sin(2. * math.pi * freq * x + phase) for x in t] - - dst_data = snk.data() - - self.assertFloatTuplesAlmostEqual( - expected_data[-Ntest:], dst_data[-Ntest:], 2) - - def test_ccf_000(self): - N = 5000 # number of samples to use - fs = 5000.0 # baseband sampling rate - rrate = 2.4321 # resampling rate - - nfilts = 32 - taps = firdes.low_pass_2( - nfilts, - nfilts * fs, - fs / 2, - fs / 10, - attenuation_dB=80, - window=window.BLACKMAN_hARRIS) - - freq = 211.123 - data = sig_source_c(fs, freq, 1, N) - signal = blocks.vector_source_c(data) - pfb = filter.pfb_arb_resampler_ccf(rrate, taps, nfilts) - snk = blocks.vector_sink_c() - - self.tb.connect((signal, pfb, snk)) - self.tb.run() - - Ntest = 50 - L = len(snk.data()) - - # Get group delay and estimate of phase offset from the filter itself. - delay = pfb.group_delay() - phase = pfb.phase_offset(freq, fs) - - # Create a timeline offset by the filter's group delay - t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # Data of the sinusoid at frequency freq with the delay and phase - # offset. - expected_data = [ - math.cos( - 2. * - math.pi * - freq * - x + - phase) + - 1j * - math.sin( - 2. * - math.pi * - freq * - x + - phase) for x in t] - - dst_data = snk.data() - - self.assertComplexTuplesAlmostEqual( - expected_data[-Ntest:], dst_data[-Ntest:], 2) - - def test_ccf_001(self): - N = 50000 # number of samples to use - fs = 5000.0 # baseband sampling rate - rrate = 0.75 # resampling rate - - nfilts = 32 - taps = firdes.low_pass_2( - nfilts, - nfilts * fs, - fs / 4, - fs / 10, - attenuation_dB=80, - window=window.BLACKMAN_hARRIS) - - freq = 211.123 - data = sig_source_c(fs, freq, 1, N) - signal = blocks.vector_source_c(data) - pfb = filter.pfb_arb_resampler_ccf(rrate, taps, nfilts) - snk = blocks.vector_sink_c() - - self.tb.connect((signal, pfb, snk)) - self.tb.run() - - Ntest = 50 - L = len(snk.data()) - - # Get group delay and estimate of phase offset from the filter itself. - delay = pfb.group_delay() - phase = pfb.phase_offset(freq, fs) - - # Create a timeline offset by the filter's group delay - t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # Data of the sinusoid at frequency freq with the delay and phase - # offset. - expected_data = [ - math.cos( - 2. * - math.pi * - freq * - x + - phase) + - 1j * - math.sin( - 2. * - math.pi * - freq * - x + - phase) for x in t] - - dst_data = snk.data() - - self.assertComplexTuplesAlmostEqual( - expected_data[-Ntest:], dst_data[-Ntest:], 2) - - def test_ccc_000(self): - N = 5000 # number of samples to use - fs = 5000.0 # baseband sampling rate - rrate = 3.4321 # resampling rate - - nfilts = 32 - taps = firdes.complex_band_pass_2( - nfilts, - nfilts * fs, - 50, - 400, - fs / 10, - attenuation_dB=80, - window=window.BLACKMAN_hARRIS) - - freq = 211.123 - data = sig_source_c(fs, freq, 1, N) - signal = blocks.vector_source_c(data) - pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts) - snk = blocks.vector_sink_c() - - self.tb.connect((signal, pfb, snk)) - self.tb.run() - - Ntest = 50 - L = len(snk.data()) - - # Get group delay and estimate of phase offset from the filter itself. - delay = pfb.group_delay() - phase = pfb.phase_offset(freq, fs) - - # Create a timeline offset by the filter's group delay - t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # Data of the sinusoid at frequency freq with the delay and phase - # offset. - expected_data = [ - math.cos( - 2. * - math.pi * - freq * - x + - phase) + - 1j * - math.sin( - 2. * - math.pi * - freq * - x + - phase) for x in t] - - dst_data = snk.data() - - self.assertComplexTuplesAlmostEqual( - expected_data[-Ntest:], dst_data[-Ntest:], 2) - - def test_ccc_001(self): - N = 50000 # number of samples to use - fs = 5000.0 # baseband sampling rate - rrate = 0.715 # resampling rate - - nfilts = 32 - taps = firdes.complex_band_pass_2( - nfilts, - nfilts * fs, - 50, - 400, - fs / 10, - attenuation_dB=80, - window=window.BLACKMAN_hARRIS) - - freq = 211.123 - data = sig_source_c(fs, freq, 1, N) - signal = blocks.vector_source_c(data) - pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts) - snk = blocks.vector_sink_c() - - self.tb.connect((signal, pfb, snk)) - self.tb.run() - - Ntest = 50 - L = len(snk.data()) - - # Get group delay and estimate of phase offset from the filter itself. - delay = pfb.group_delay() - phase = pfb.phase_offset(freq, fs) - - # Create a timeline offset by the filter's group delay - t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # Data of the sinusoid at frequency freq with the delay and phase - # offset. - expected_data = [ - math.cos( - 2. * - math.pi * - freq * - x + - phase) + - 1j * - math.sin( - 2. * - math.pi * - freq * - x + - phase) for x in t] - - dst_data = snk.data() - - self.assertComplexTuplesAlmostEqual( - expected_data[-Ntest:], dst_data[-Ntest:], 2) - - -if __name__ == '__main__': - gr_unittest.run(test_pfb_arb_resampler) diff --git a/blocklib/filter/pfb_channelizer/pfb_channelizer.yml b/blocklib/filter/pfb_channelizer/pfb_channelizer.yml deleted file mode 100644 index 7a78cdf44..000000000 --- a/blocklib/filter/pfb_channelizer/pfb_channelizer.yml +++ /dev/null @@ -1,47 +0,0 @@ -module: filter -block: pfb_channelizer -label: PFB Channelizer -blocktype: block -category: '[Core]/Channelizers' - -typekeys: - - id: T - type: class - options: - - cf32 - # - rf32 - - -parameters: -- id: numchans - label: Number of Channels - dtype: size - settable: false -- id: taps - label: Filter Taps - dtype: rf32 - container: vector - settable: false -- id: oversample_rate - label: Oversample Rate - dtype: rf32 - settable: false - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - # multiplicity: parameters/numchans - -- domain: stream - id: out - direction: output - type: typekeys/T - multiplicity: parameters/numchans - -implementations: -- id: cpu -- id: cuda - -file_format: 1 diff --git a/blocklib/filter/pfb_channelizer/pfb_channelizer_cpu.cc b/blocklib/filter/pfb_channelizer/pfb_channelizer_cpu.cc deleted file mode 100644 index 5f500a6f4..000000000 --- a/blocklib/filter/pfb_channelizer/pfb_channelizer_cpu.cc +++ /dev/null @@ -1,180 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009,2010,2012,2014 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "pfb_channelizer_cpu.h" -#include "pfb_channelizer_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace filter { - -template <class T> -pfb_channelizer_cpu<T>::pfb_channelizer_cpu( - const typename pfb_channelizer<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), - polyphase_filterbank(args.numchans, args.taps), - d_oversample_rate(args.oversample_rate), - d_nchans(args.numchans) -{ - - // The over sampling rate must be rationally related to the number of channels - // in that it must be N/i for i in [1,N], which gives an outputsample rate - // of [fs/N, fs] where fs is the input sample rate. - // This tests the specified input sample rate to see if it conforms to this - // requirement within a few significant figures. - const double srate = d_nfilts / d_oversample_rate; - const double rsrate = round(srate); - if (fabs(srate - rsrate) > 0.00001) - throw std::invalid_argument( - "pfb_channelizer: oversample rate must be N/i for i in [1, N]"); - - this->set_relative_rate(d_oversample_rate / d_nchans); - - // Default channel map. The channel map specifies which input - // goes to which output channel; so out[0] comes from - // channel_map[0]. - d_channel_map.resize(d_nfilts); - for (unsigned int i = 0; i < d_nfilts; i++) { - d_channel_map[i] = i; - } - - // We use a look up table to set the index of the FFT input - // buffer, which equivalently performs the FFT shift operation - // on every other turn when the rate_ratio>1. Also, this - // performs the index 'flip' where the first input goes into the - // last filter. In the pfb_decimator_ccf, we directly index the - // input_items buffers starting with this last; here we start - // with the first and put it into the fft object properly for - // the same effect. - d_rate_ratio = (int)rintf(d_nfilts / d_oversample_rate); - d_idxlut.resize(d_nfilts); - for (unsigned int i = 0; i < d_nfilts; i++) { - d_idxlut[i] = d_nfilts - ((i + d_rate_ratio) % d_nfilts) - 1; - } - - // Calculate the number of filtering rounds to do to evenly - // align the input vectors with the output channels - d_output_multiple = 1; - while ((d_output_multiple * d_rate_ratio) % d_nfilts != 0) - d_output_multiple++; - this->set_output_multiple(d_output_multiple); - - // Use set_taps to also set the history requirement - set_taps(args.taps); - - // because we need a stream_to_streams block for the input, - // only send tags from in[i] -> out[i]. - this->set_tag_propagation_policy(tag_propagation_policy_t::TPP_ONE_TO_ONE); - - d_deinterleaved.resize(d_nchans); -} - -template <class T> -void pfb_channelizer_cpu<T>::set_taps(const std::vector<float>& taps) -{ - // std::scoped_lock guard(d_mutex); - - polyphase_filterbank::set_taps(taps); - // set_history(d_taps_per_filter + 1); - d_history = d_nchans * (d_taps_per_filter + 1); - d_updated = true; -} - - -template <class T> -work_return_t pfb_channelizer_cpu<T>::work(work_io& wio) -{ - // std::scoped_lock guard(d_mutex); - - auto in = wio.inputs()[0].items<T>(); - auto out = wio.outputs()[0].items<T>(); - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - - if ((size_t)ninput_items < d_history * d_nchans) { // if we can produce 1 output item - return work_return_t::INSUFFICIENT_INPUT_ITEMS; - } - - if (d_updated) { - d_updated = false; - return work_return_t::OK; // history requirements may have changed. - } - - // includes history - auto total_items = - std::min(ninput_items / d_nchans, noutput_items + (d_history / d_nchans)); - - for (size_t j = 0; j < d_nchans; j++) { - if (d_deinterleaved[j].size() < total_items) { - d_deinterleaved[j].resize(total_items); - } - for (size_t i = 0; i < total_items; i++) { - d_deinterleaved[j][i] = in[i * d_nchans + j]; - } - } - - size_t noutputs = wio.outputs().size(); - noutput_items = total_items - d_history + 1; - - // The following algorithm looks more complex in order to handle - // the cases where we want more that 1 sps for each - // channel. Otherwise, this would boil down into a single loop - // that operates from input_items[0] to [d_nfilts]. - - // When dealing with osps>1, we start not at the last filter, - // but nfilts/osps and then wrap around to the next symbol into - // the other set of filters. - // For details of this operation, see: - // fred harris, Multirate Signal Processing For Communication - // Systems. Upper Saddle River, NJ: Prentice Hall, 2004. - - int n = 1, i = -1, j = 0, oo = 0, last; - int toconsume = (int)rintf(noutput_items / d_oversample_rate); - while (n <= toconsume) { - j = 0; - i = (i + d_rate_ratio) % d_nfilts; - last = i; - while (i >= 0) { - // in = wio.inputs()[j].items<gr_complex>(); - in = d_deinterleaved[j].data(); - d_fft.get_inbuf()[d_idxlut[j]] = d_fir_filters[i].filter(&in[n]); - j++; - i--; - } - - i = d_nfilts - 1; - while (i > last) { - // in = wio.inputs()[j].items<gr_complex>(); - in = d_deinterleaved[j].data(); - d_fft.get_inbuf()[d_idxlut[j]] = d_fir_filters[i].filter(&in[n - 1]); - j++; - i--; - } - - n += (i + d_rate_ratio) >= (int)d_nfilts; - - // despin through FFT - d_fft.execute(); - - // Send to output channels - for (unsigned int nn = 0; nn < noutputs; nn++) { - out = wio.outputs()[nn].items<gr_complex>(); - out[oo] = d_fft.get_outbuf()[d_channel_map[nn]]; - } - oo++; - } - wio.consume_each(toconsume * d_nchans); - // this->produce_each(noutput_items - (d_history / d_nchans - 1), work_output); - wio.produce_each(noutput_items); - return work_return_t::OK; -} - -} /* namespace filter */ -} /* namespace gr */ diff --git a/blocklib/filter/pfb_channelizer/pfb_channelizer_cpu.h b/blocklib/filter/pfb_channelizer/pfb_channelizer_cpu.h deleted file mode 100644 index 9bd442577..000000000 --- a/blocklib/filter/pfb_channelizer/pfb_channelizer_cpu.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009,2010,2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/pfb_channelizer.h> -#include <gnuradio/kernel/filter/polyphase_filterbank.h> - -#include <mutex> - -namespace gr { -namespace filter { - -template <class T> -class pfb_channelizer_cpu : public pfb_channelizer<T>, - kernel::filter::polyphase_filterbank -{ -public: - pfb_channelizer_cpu(const typename pfb_channelizer<T>::block_args& args); - - work_return_t work(work_io&) override; - - int group_delay(); - void set_taps(const std::vector<float>& taps) override; - -private: - bool d_updated = false; - float d_oversample_rate; - std::vector<int> d_idxlut; - int d_rate_ratio; - int d_output_multiple; - std::vector<int> d_channel_map; - std::mutex d_mutex; // mutex to protect set/work access - - size_t d_history = 1; - - size_t d_nchans; - - std::vector<std::vector<T>> d_deinterleaved; -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/pfb_channelizer/pfb_channelizer_cuda.cc b/blocklib/filter/pfb_channelizer/pfb_channelizer_cuda.cc deleted file mode 100644 index 9caadb73b..000000000 --- a/blocklib/filter/pfb_channelizer/pfb_channelizer_cuda.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "pfb_channelizer_cuda.h" -#include "pfb_channelizer_cuda_gen.h" - -#include <gnuradio/helper_cuda.h> - -namespace gr { -namespace filter { - -template <class T> -pfb_channelizer_cuda<T>::pfb_channelizer_cuda( - const typename pfb_channelizer<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), d_nchans(args.numchans) -{ - d_in_items.resize(1); - d_out_items.resize(d_nchans); - - auto new_taps = std::vector<gr_complex>(args.taps.size()); - for (size_t i = 0; i < args.taps.size(); i++) { - new_taps[i] = gr_complex(args.taps[i], 0); - } - - // quantize the overlap to the nchans - d_overlap = d_nchans * ((args.taps.size() + d_nchans - 1) / d_nchans); - checkCudaErrors(cudaMalloc(&d_dev_tail, d_overlap * sizeof(gr_complex))); - checkCudaErrors(cudaMemset(d_dev_tail, 0, d_overlap * sizeof(gr_complex))); - - checkCudaErrors( - cudaMalloc(&d_dev_buf, 16 * 1024 * 1024 * sizeof(gr_complex))); // 4M items max ?? - - p_channelizer = std::make_shared<cusp::channelizer<gr_complex>>(new_taps, d_nchans); - cudaStreamCreate(&d_stream); - p_channelizer->set_stream(d_stream); - - p_deinterleaver = - std::make_shared<cusp::deinterleave>(d_nchans, 1, sizeof(gr_complex)); - - p_deinterleaver->set_stream(d_stream); - // set_output_multiple(nchans); - // set_min_noutput_items(d_overlap+1024); -} - -template <class T> -work_return_t pfb_channelizer_cuda<T>::work(work_io& wio) -{ - // std::scoped_lock guard(d_mutex); - - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - - if ((size_t)ninput_items < noutput_items * d_nchans + d_overlap) { - return work_return_t::INSUFFICIENT_INPUT_ITEMS; - } - - d_in_items = wio.all_input_ptrs(); - d_out_items = wio.all_output_ptrs(); - - checkCudaErrors(p_channelizer->launch_default_occupancy( - d_in_items, { d_dev_buf }, (noutput_items + d_overlap / d_nchans))); - - checkCudaErrors(p_deinterleaver->launch_default_occupancy( - { (gr_complex*)d_dev_buf + d_overlap }, d_out_items, noutput_items * d_nchans)); - - cudaStreamSynchronize(d_stream); - - wio.consume_each(noutput_items * d_nchans); - wio.produce_each(noutput_items); - return work_return_t::OK; -} - -} /* namespace filter */ -} /* namespace gr */ diff --git a/blocklib/filter/pfb_channelizer/pfb_channelizer_cuda.h b/blocklib/filter/pfb_channelizer/pfb_channelizer_cuda.h deleted file mode 100644 index 67b2afe4a..000000000 --- a/blocklib/filter/pfb_channelizer/pfb_channelizer_cuda.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/filter/pfb_channelizer.h> -#include <cusp/channelizer.cuh> -#include <cusp/deinterleave.cuh> - -namespace gr { -namespace filter { - -template <class T> -class pfb_channelizer_cuda : public pfb_channelizer<T> -{ -public: - pfb_channelizer_cuda(const typename pfb_channelizer<T>::block_args& args); - - work_return_t work(work_io&) override; - - -private: - size_t d_nchans; - size_t d_taps; - size_t d_overlap; - - void* d_dev_buf; - void* d_dev_tail; - cudaStream_t d_stream; - - std::shared_ptr<cusp::channelizer<gr_complex>> p_channelizer; - std::shared_ptr<cusp::deinterleave> p_deinterleaver; - - std::vector<const void*> d_in_items; - std::vector<void*> d_out_items; -}; - - -} // namespace filter -} // namespace gr diff --git a/blocklib/filter/python/gnuradio/filter/.gitignore b/blocklib/filter/python/gnuradio/filter/.gitignore deleted file mode 100644 index 2926fbdb7..000000000 --- a/blocklib/filter/python/gnuradio/filter/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -!meson.build -!bindings/meson.build
\ No newline at end of file diff --git a/blocklib/filter/python/gnuradio/filter/__init__.py b/blocklib/filter/python/gnuradio/filter/__init__.py deleted file mode 100644 index 335c503ca..000000000 --- a/blocklib/filter/python/gnuradio/filter/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ - -import os - -try: - from .filter_python import * -except ImportError: - dirname, filename = os.path.split(os.path.abspath(__file__)) - __path__.append(os.path.join(dirname, "bindings")) - from .filter_python import * diff --git a/blocklib/filter/python/gnuradio/filter/bindings/firdes_pybind.cc b/blocklib/filter/python/gnuradio/filter/bindings/firdes_pybind.cc deleted file mode 100644 index 5c7e51ae5..000000000 --- a/blocklib/filter/python/gnuradio/filter/bindings/firdes_pybind.cc +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2020 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -/***********************************************************************************/ -/* This file is automatically generated using bindtool and can be manually edited */ -/* The following lines can be configured to regenerate this file during cmake */ -/* If manual edits are made, the following tags should be modified accordingly. */ -/* BINDTOOL_GEN_AUTOMATIC(0) */ -/* BINDTOOL_USE_PYGCCXML(0) */ -/* BINDTOOL_HEADER_FILE(firdes.h) */ -/* BINDTOOL_HEADER_FILE_HASH(10cf0c4b9664ba7e2931c2375c13c68c) */ -/***********************************************************************************/ - -#include <pybind11/complex.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/kernel/filter/firdes.h> -// pydoc.h is automatically generated in the build directory -// #include <firdes_pydoc.h> - -void bind_firdes(py::module& m) -{ - using firdes = gr::filter::firdes; - - py::class_<firdes, std::shared_ptr<firdes>> firdes_class(m, "firdes"); - - firdes_class - .def_static("window", - &firdes::window, - py::arg("type"), - py::arg("ntaps"), - py::arg("param")) - - - .def_static("low_pass", - &firdes::low_pass, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("cutoff_freq"), - py::arg("transition_width"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("low_pass_2", - &firdes::low_pass_2, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("cutoff_freq"), - py::arg("transition_width"), - py::arg("attenuation_dB"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("high_pass", - &firdes::high_pass, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("cutoff_freq"), - py::arg("transition_width"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("high_pass_2", - &firdes::high_pass_2, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("cutoff_freq"), - py::arg("transition_width"), - py::arg("attenuation_dB"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("band_pass", - &firdes::band_pass, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("band_pass_2", - &firdes::band_pass_2, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("attenuation_dB"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("complex_band_pass", - &firdes::complex_band_pass, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("complex_band_pass_2", - &firdes::complex_band_pass_2, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("attenuation_dB"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("band_reject", - &firdes::band_reject, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("band_reject_2", - &firdes::band_reject_2, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("attenuation_dB"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("complex_band_reject", - &firdes::complex_band_reject, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("complex_band_reject_2", - &firdes::complex_band_reject_2, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("low_cutoff_freq"), - py::arg("high_cutoff_freq"), - py::arg("transition_width"), - py::arg("attenuation_dB"), - py::arg("window") = ::gr::kernel::fft::window::window_t::HAMMING, - py::arg("param") = 6.7599999999999998) - - - .def_static("hilbert", - &firdes::hilbert, - py::arg("ntaps") = 19, - py::arg("windowtype") = - ::gr::kernel::fft::window::window_t::RECTANGULAR, - py::arg("param") = 6.7599999999999998) - - - .def_static("root_raised_cosine", - &firdes::root_raised_cosine, - py::arg("gain"), - py::arg("sampling_freq"), - py::arg("symbol_rate"), - py::arg("alpha"), - py::arg("ntaps")) - - - .def_static("gaussian", - &firdes::gaussian, - py::arg("gain"), - py::arg("spb"), - py::arg("bt"), - py::arg("ntaps")) - - ; -} diff --git a/blocklib/filter/python/gnuradio/filter/bindings/meson.build b/blocklib/filter/python/gnuradio/filter/bindings/meson.build deleted file mode 100644 index 6097165d2..000000000 --- a/blocklib/filter/python/gnuradio/filter/bindings/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -# filter_pybind_sources = [files('firdes_pybind.cc')] + filter_pybind_sources -# filter_pybind_names = ['firdes'] + filter_pybind_names
\ No newline at end of file diff --git a/blocklib/filter/python/gnuradio/filter/meson.build b/blocklib/filter/python/gnuradio/filter/meson.build deleted file mode 100644 index 2e0b56032..000000000 --- a/blocklib/filter/python/gnuradio/filter/meson.build +++ /dev/null @@ -1,54 +0,0 @@ -# not autogenerated -# can be autogenerated when there is a way to figure out the top level imports -###################### -# Python Bindings ### -###################### - -# Generate _python.cc for each block -fs = import('fs') -if fs.exists('bindings/meson.build') -subdir('bindings') -endif -srcs = ['__init__.py'] - -foreach s: srcs -configure_file(copy: true, - input: s, - output: s -) -endforeach - -d = { - 'blocks' : filter_pybind_names, - 'module' : 'filter', - 'imports' : ['gnuradio.gr','gnuradio.fft'] -} - -gen_filter_pybind = custom_target('gen_filter_pybind', - output : ['filter_pybind.cc'], - command : ['python3', join_paths(SCRIPTS_DIR,'process_module_pybind.py'), - '--blocks', d['blocks'], - '--imports', d['imports'], - '--module', d['module'], - '--output_file', '@OUTPUT@', - '--build_dir', join_paths(meson.build_root())], - install : false) - -filter_pybind_sources += gen_filter_pybind - -gnuradio_blocklib_filter_pybind = py3.extension_module('filter_python', - filter_pybind_sources, - include_directories: ['../../../lib', incdir_numpy], - dependencies : [gnuradio_blocklib_filter_dep, python3_dep, pybind11_dep], - link_language : 'cpp', - install : true, - install_dir : join_paths(py3_install_dir,'gnuradio','filter') -) - -gnuradio_blocklib_filter_pybind_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_filter_pybind, - dependencies : filter_deps) - - -# Target for pure python -install_data(srcs, install_dir : join_paths(py3_install_dir,'gnuradio','filter')) diff --git a/blocklib/filter/test/.gitignore b/blocklib/filter/test/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/filter/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/filter/test/cuda/qa_moving_average_cuda.py b/blocklib/filter/test/cuda/qa_moving_average_cuda.py deleted file mode 100644 index 6bdbf4a7c..000000000 --- a/blocklib/filter/test/cuda/qa_moving_average_cuda.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2013,2017 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio 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, or (at your option) -# any later version. -# -# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - - -from gnuradio import gr, gr_unittest, blocks, filter -import numpy as np - -import math, random - -def make_random_complex_tuple(L, scale=1): - result = [] - for x in range(L): - result.append(scale*complex(2*random.random()-1, - 2*random.random()-1)) - return tuple(result) - -def make_random_float_tuple(L, scale=1): - result = [] - for x in range(L): - result.append(scale*(2*random.random()-1)) - return tuple(result) - -class test_moving_average(gr_unittest.TestCase): - - def setUp(self): - random.seed(0) - self.tb = gr.flowgraph() - - def tearDown(self): - self.tb = None - - # These tests will always pass and are therefore useless. 100 random numbers [-1,1) are - # getting summed up and scaled with 0.001. Then, an assertion verifies a result near 0, - # which is the case even if the block is malfunctioning. - - def test_01(self): - tb = self.tb - - N = 10000 - data = make_random_float_tuple(N, 1) - expected_result = N*[0,] - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(100, 0.001, impl=filter.moving_average_ff.cuda) - dst = blocks.vector_sink_f() - - tb.connect(src, op).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D)) - tb.connect(op, dst).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H)) - tb.run() - - dst_data = dst.data() - - # make sure result is close to zero - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 1) - - def test_02(self): - tb = self.tb - - N = 10000 - data = make_random_complex_tuple(N, 1) - expected_result = N*[0,] - - src = blocks.vector_source_c(data, False) - op = filter.moving_average_cc(100, 0.001, impl=filter.moving_average_cc.cuda) - dst = blocks.vector_sink_c() - - tb.connect(src, op).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D)) - tb.connect(op, dst).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H)) - tb.run() - - dst_data = dst.data() - - # make sure result is close to zero - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1) - - def test_moving_sum(self): - tb = self.tb - - N = 10000 - filt_len = 14 - data = [1.0] * N - expected_result = N*[filt_len,] - expected_result[0:filt_len-1] = list(range(1, filt_len)) - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(filt_len, 1.0, impl=filter.moving_average_ff.cuda) - dst = blocks.vector_sink_f() - - tb.connect(src, op).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D)) - tb.connect(op, dst).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H)) - tb.run() - - dst_data = dst.data() - - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_moving_sum2(self): - tb = self.tb - - - filt_len = 3 - data = list(range(1,11)) - expected_result = [] - for ii in range(10): - sum = 0.0 - for jj in range(filt_len): - if (ii - jj ) >= 0: - sum += data[ii-jj] - expected_result.append(sum) - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(filt_len, 1.0, 4, impl=filter.moving_average_ff.cuda) - dst = blocks.vector_sink_f() - - tb.connect(src, op).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D)) - tb.connect(op, dst).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H)) - tb.run() - - dst_data = dst.data() - - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_moving_avg3(self): - tb = self.tb - - N = 100000 - filt_len = 64 - data = list(make_random_float_tuple(N, scale=1)) - expected_result = [] - for ii in range(N): - sum = 0.0 - for jj in range(filt_len): - if (ii - jj ) >= 0: - sum += data[ii-jj] - expected_result.append(float(sum / N)) - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(filt_len, 1.0 / N, 4000, impl=filter.moving_average_ff.cuda) - dst = blocks.vector_sink_f() - - tb.connect(src, op).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.H2D)) - tb.connect(op, dst).set_custom_buffer(gr.buffer_cuda_properties.make(gr.buffer_cuda_type.D2H)) - tb.run() - - dst_data = dst.data() - - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 7) - - # This tests implement own moving average to verify correct behaviour of the block - - # def test_03(self): - # tb = self.tb - - # vlen = 5 - # N = 10*vlen - # data = make_random_float_tuple(N, 2**10) - # data = [int(d*1000) for d in data] - # src = blocks.vector_source_i(data, False) - # one_to_many = blocks.stream_to_streams(gr.sizeof_int, vlen) - # one_to_vector = blocks.stream_to_vector(gr.sizeof_int, vlen) - # many_to_vector = blocks.streams_to_vector(gr.sizeof_int, vlen) - # isolated = [ filter.moving_average_ii(100, 1) for i in range(vlen)] - # dut = filter.moving_average_ii(100, 1, vlen=vlen) - # dut_dst = blocks.vector_sink_i(vlen=vlen) - # ref_dst = blocks.vector_sink_i(vlen=vlen) - - # tb.connect(src, one_to_many) - # tb.connect(src, one_to_vector) #, dut, dut_dst) - # tb.connect(one_to_vector, dut) - # tb.connect(dut, dut_dst) - # tb.connect(many_to_vector, ref_dst) - # for idx, single in enumerate(isolated): - # tb.connect((one_to_many,idx), single, (many_to_vector,idx)) - - # tb.run() - - # dut_data = dut_dst.data() - # ref_data = ref_dst.data() - - # # make sure result is close to zero - # self.assertTupleEqual(dut_data, ref_data) - - # def test_04(self): - # tb = self.tb - - # N = 10000 # number of samples - # history = 100 # num of samples to average - # data = make_random_complex_tuple(N, 1) # generate random data - - # # pythonic MA filter - # data_padded = (history-1)*[0.0+1j*0.0]+list(data) # history - # expected_result = [] - # moving_sum = sum(data_padded[:history-1]) - # for i in range(N): - # moving_sum += data_padded[i+history-1] - # expected_result.append(moving_sum) - # moving_sum -= data_padded[i] - - # src = blocks.vector_source_c(data, False) - # op = filter.moving_average_cc(history, 1) - # dst = blocks.vector_sink_c() - - # tb.connect(src, op) - # tb.connect(op, dst) - # tb.run() - - # dst_data = dst.data() - - # # make sure result is close to zero - # self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 4) - -if __name__ == '__main__': - gr_unittest.run(test_moving_average) diff --git a/blocklib/filter/test/meson.build b/blocklib/filter/test/meson.build deleted file mode 100644 index ea9e53dcb..000000000 --- a/blocklib/filter/test/meson.build +++ /dev/null @@ -1,10 +0,0 @@ -################################################### -# QA -################################################### - -if GR_ENABLE_PYTHON - test('qa_fir_filter', find_program('qa_fir_filter.py'), env: TEST_ENV) - test('qa_iir_filter', find_program('qa_iir_filter.py'), env: TEST_ENV) - test('qa_pfb_channelizer', find_program('qa_pfb_channelizer.py'), env: TEST_ENV) - # test('qa_moving_average', find_program('qa_moving_average.py'), env: TEST_ENV) -endif diff --git a/blocklib/filter/test/qa_fir_filter.py b/blocklib/filter/test/qa_fir_filter.py deleted file mode 100644 index e19040a2c..000000000 --- a/blocklib/filter/test/qa_fir_filter.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2008,2010,2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, filter, blocks -from gnuradio.kernel.filter import firdes -import math - -def fir_filter(x, taps, decim=1): - y = [] - # x2 = (len(taps) - 1) * [0, ] + x - x2 = x - m = decim *((len(x)-len(taps)+1) // decim) - - for i in range(0, m, decim): - yi = 0 - for j in range(len(taps)): - yi += taps[len(taps) - 1 - j] * x2[i + j] - y.append(yi) - return y - - -class test_filter(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_fir_filter_fff_001(self): - decim = 1 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fff(decim, taps) - dst = blocks.vector_sink_f() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_fff_002(self): - decim = 4 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fff(decim, taps) - dst = blocks.vector_sink_f() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccf_001(self): - decim = 1 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccf(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccf_002(self): - decim = 4 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccf(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccc_001(self): - decim = 1 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccc_002(self): - decim = 1 - taps = firdes.low_pass(1, 1, 0.1, 0.01) - src_data = [0]*len(taps) + 10 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_ccc_003(self): - decim = 4 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_c(src_data) - op = filter.fir_filter_ccc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_scc_001(self): - decim = 1 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_s(src_data) - op = filter.fir_filter_scc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_scc_002(self): - decim = 4 - taps = 20 * [0.5 + 1j, 0.5 + 1j] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - - src = blocks.vector_source_s(src_data) - op = filter.fir_filter_scc(decim, taps) - dst = blocks.vector_sink_c() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_fsf_001(self): - decim = 1 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - expected_data = [int(e) for e in expected_data] - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fsf(decim, taps) - dst = blocks.vector_sink_s() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - def test_fir_filter_fsf_002(self): - decim = 4 - taps = 20 * [0.5, 0.5] - src_data = 40 * [1, 2, 3, 4] - expected_data = fir_filter(src_data, taps, decim) - expected_data = [int(e) for e in expected_data] - - src = blocks.vector_source_f(src_data) - op = filter.fir_filter_fsf(decim, taps) - dst = blocks.vector_sink_s() - self.tb.connect((src, op, dst)) - self.tb.run() - result_data = dst.data() - self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5) - - -if __name__ == '__main__': - gr_unittest.run(test_filter) diff --git a/blocklib/filter/test/qa_iir_filter.py b/blocklib/filter/test/qa_iir_filter.py deleted file mode 100644 index 305f7cbd5..000000000 --- a/blocklib/filter/test/qa_iir_filter.py +++ /dev/null @@ -1,403 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2004,2007,2010,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, filter, blocks - - -class test_iir_filter(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_iir_direct_001(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - fftaps = () - fbtaps = () - expected_result = (0, 0, 0, 0, 0, 0, 0, 0) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_direct_002(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - fftaps = (2,) - fbtaps = (0,) - expected_result = (2, 4, 6, 8, 10, 12, 14, 16) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_direct_003(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - fftaps = (2, 11) - fbtaps = (0, 0) - expected_result = (2, 15, 28, 41, 54, 67, 80, 93) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_direct_004(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - fftaps = (2, 11) - fbtaps = (0, -1) - expected_result = (2, 13, 15, 26, 28, 39, 41, 52) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_direct_005(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - fftaps = (2, 11, 0) - fbtaps = (0, -1, 3) - expected_result = (2, 13, 21, 59, 58, 186, 68, 583) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_direct_006(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - expected_result = (2, 13, 21, 59, 58, 186, 68, 583) - fftaps = (2, 1) - fbtaps = (0, -1) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - fftaps = (2, 11, 0) - fbtaps = (0, -1, 3) - # FIXME: implement set_taps as generalized callback - # op.set_taps(fftaps, fbtaps) - op.set_fftaps(fftaps) - op.set_fbtaps(fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_direct_007(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - expected_result = (2, 2, 5, 5, 8, 8, 11, 11) - fftaps = (2, 1) - fbtaps = (0, -1) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - fftaps = (2, 0, 1) - fbtaps = (0, -1) - # FIXME: implement set_taps as generalized callback - # op.set_taps(fftaps, fbtaps) - op.set_fftaps(fftaps) - op.set_fbtaps(fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_direct_008(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8) - expected_result = (2, 4, 4, 10, 18, 14, 26, 56) - fftaps = (2,) - fbtaps = (0, 1) - src = blocks.vector_source_f(src_data) - op = filter.iir_filter_ffd(fftaps, fbtaps) - fftaps_data = (1) - fbtaps = (0, 0, -1, 3) - # FIXME: implement set_taps as generalized callback - # op.set_taps(fftaps, fbtaps) - op.set_fftaps(fftaps) - op.set_fbtaps(fbtaps) - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccf_001(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = ( - 2 + 2j, - (6 + 6j), - (12 + 12j), - (20 + 20j), - (30 + 30j), - (42 + 42j), - (56 + 56j), - (72 + 72j)) - fftaps = (2,) - fbtaps = (0, 1) - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccf(fftaps, fbtaps) - dst = blocks.vector_sink_c() - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccf_002(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = ( - 2 + 2j, - (6 + 6j), - (12 + 12j), - (20 + 20j), - (30 + 30j), - (42 + 42j), - (56 + 56j), - (72 + 72j)) - - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccf([1], [1]) - dst = blocks.vector_sink_c() - - fftaps = (2,) - fbtaps = (0, 1) - # FIXME: implement set_taps as generalized callback - # op.set_taps(fftaps, fbtaps) - op.set_fftaps(fftaps) - op.set_fbtaps(fbtaps) - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccd_001(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = ( - 2 + 2j, - (6 + 6j), - (12 + 12j), - (20 + 20j), - (30 + 30j), - (42 + 42j), - (56 + 56j), - (72 + 72j)) - fftaps = (2,) - fbtaps = (0, 1) - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccd(fftaps, fbtaps) - dst = blocks.vector_sink_c() - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccd_002(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = ( - 2 + 2j, - (6 + 6j), - (12 + 12j), - (20 + 20j), - (30 + 30j), - (42 + 42j), - (56 + 56j), - (72 + 72j)) - - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccd([1], [1]) - dst = blocks.vector_sink_c() - - fftaps = (2,) - fbtaps = (0, 1) - # FIXME: implement set_taps as generalized callback - # op.set_taps(fftaps, fbtaps) - op.set_fftaps(fftaps) - op.set_fbtaps(fbtaps) - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccc_001(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = (4j, 12j, 24j, 40j, 60j, 84j, 112j, 144j) - fftaps = (2 + 2j,) - fbtaps = (0, 1) - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccc(fftaps, fbtaps) - dst = blocks.vector_sink_c() - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccc_002(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = (4j, 12j, 24j, 40j, 60j, 84j, 112j, 144j) - - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccc([1], [1]) - dst = blocks.vector_sink_c() - - fftaps = (2 + 2j,) - fbtaps = (0, 1) - # FIXME: implement set_taps as generalized callback - # op.set_taps(fftaps, fbtaps) - op.set_fftaps(fftaps) - op.set_fbtaps(fbtaps) - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccz_001(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = (4j, 12j, 24j, 40j, 60j, 84j, 112j, 144j) - fftaps = (2 + 2j,) - fbtaps = (0, 1) - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccz(fftaps, fbtaps) - dst = blocks.vector_sink_c() - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_iir_ccz_002(self): - src_data = ( - 1 + 1j, - 2 + 2j, - 3 + 3j, - 4 + 4j, - 5 + 5j, - 6 + 6j, - 7 + 7j, - 8 + 8j) - expected_result = (4j, 12j, 24j, 40j, 60j, 84j, 112j, 144j) - - src = blocks.vector_source_c(src_data) - op = filter.iir_filter_ccz([1], [1]) - dst = blocks.vector_sink_c() - - fftaps = (2 + 2j,) - fbtaps = (0, 1) - # FIXME: implement set_taps as generalized callback - # op.set_taps(fftaps, fbtaps) - op.set_fftaps(fftaps) - op.set_fbtaps(fbtaps) - - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.tb.run() - - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - -if __name__ == '__main__': - gr_unittest.run(test_iir_filter) diff --git a/blocklib/filter/test/qa_moving_average.py b/blocklib/filter/test/qa_moving_average.py deleted file mode 100644 index 47fac453a..000000000 --- a/blocklib/filter/test/qa_moving_average.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2013,2017 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio 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, or (at your option) -# any later version. -# -# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - - -from gnuradio import gr, gr_unittest, blocks, filter -import numpy as np - -import math, random - -def make_random_complex_tuple(L, scale=1): - result = [] - for x in range(L): - result.append(scale*complex(2*random.random()-1, - 2*random.random()-1)) - return tuple(result) - -def make_random_float_tuple(L, scale=1): - result = [] - for x in range(L): - result.append(scale*(2*random.random()-1)) - return tuple(result) - -class test_moving_average(gr_unittest.TestCase): - - def setUp(self): - random.seed(0) - self.tb = gr.flowgraph() - - def tearDown(self): - self.tb = None - - # These tests will always pass and are therefore useless. 100 random numbers [-1,1) are - # getting summed up and scaled with 0.001. Then, an assertion verifies a result near 0, - # which is the case even if the block is malfunctioning. - - def test_01(self): - tb = self.tb - - N = 10000 - data = make_random_float_tuple(N, 1) - expected_result = N*[0,] - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(100, 0.001) - dst = blocks.vector_sink_f() - - tb.connect(src, op) - tb.connect(op, dst) - tb.run() - - dst_data = dst.data() - - # make sure result is close to zero - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 1) - - def test_02(self): - tb = self.tb - - N = 10000 - data = make_random_complex_tuple(N, 1) - expected_result = N*[0,] - - src = blocks.vector_source_c(data, False) - op = filter.moving_average_cc(100, 0.001) - dst = blocks.vector_sink_c() - - tb.connect(src, op) - tb.connect(op, dst) - tb.run() - - dst_data = dst.data() - - # make sure result is close to zero - self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1) - - def test_moving_sum(self): - tb = self.tb - - N = 10000 - filt_len = 14 - data = [1.0] * N - expected_result = N*[filt_len,] - expected_result[0:filt_len-1] = list(range(1, filt_len)) - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(filt_len, 1.0) - dst = blocks.vector_sink_f() - - tb.connect(src, op) - tb.connect(op, dst) - tb.run() - - dst_data = dst.data() - - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_moving_sum2(self): - tb = self.tb - - - filt_len = 3 - data = list(range(1,11)) - expected_result = [] - for ii in range(10): - sum = 0.0 - for jj in range(filt_len): - if (ii - jj ) >= 0: - sum += data[ii-jj] - expected_result.append(sum) - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(filt_len, 1.0, 4) - dst = blocks.vector_sink_f() - - tb.connect(src, op) - tb.connect(op, dst) - tb.run() - - dst_data = dst.data() - - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) - - def test_moving_avg3(self): - tb = self.tb - - N = 100000 - filt_len = 64 - data = list(make_random_float_tuple(N, scale=1)) - expected_result = [] - for ii in range(N): - sum = 0.0 - for jj in range(filt_len): - if (ii - jj ) >= 0: - sum += data[ii-jj] - expected_result.append(float(sum / N)) - - src = blocks.vector_source_f(data, False) - op = filter.moving_average_ff(filt_len, 1.0 / N, 4000) - dst = blocks.vector_sink_f() - - tb.connect(src, op) - tb.connect(op, dst) - tb.run() - - dst_data = dst.data() - - self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 7) - - # This tests implement own moving average to verify correct behaviour of the block - - # def test_03(self): - # tb = self.tb - - # vlen = 5 - # N = 10*vlen - # data = make_random_float_tuple(N, 2**10) - # data = [int(d*1000) for d in data] - # src = blocks.vector_source_i(data, False) - # one_to_many = blocks.stream_to_streams(gr.sizeof_int, vlen) - # one_to_vector = blocks.stream_to_vector(gr.sizeof_int, vlen) - # many_to_vector = blocks.streams_to_vector(gr.sizeof_int, vlen) - # isolated = [ filter.moving_average_ii(100, 1) for i in range(vlen)] - # dut = filter.moving_average_ii(100, 1, vlen=vlen) - # dut_dst = blocks.vector_sink_i(vlen=vlen) - # ref_dst = blocks.vector_sink_i(vlen=vlen) - - # tb.connect(src, one_to_many) - # tb.connect(src, one_to_vector) #, dut, dut_dst) - # tb.connect(one_to_vector, dut) - # tb.connect(dut, dut_dst) - # tb.connect(many_to_vector, ref_dst) - # for idx, single in enumerate(isolated): - # tb.connect((one_to_many,idx), single, (many_to_vector,idx)) - - # tb.run() - - # dut_data = dut_dst.data() - # ref_data = ref_dst.data() - - # # make sure result is close to zero - # self.assertTupleEqual(dut_data, ref_data) - - # def test_04(self): - # tb = self.tb - - # N = 10000 # number of samples - # history = 100 # num of samples to average - # data = make_random_complex_tuple(N, 1) # generate random data - - # # pythonic MA filter - # data_padded = (history-1)*[0.0+1j*0.0]+list(data) # history - # expected_result = [] - # moving_sum = sum(data_padded[:history-1]) - # for i in range(N): - # moving_sum += data_padded[i+history-1] - # expected_result.append(moving_sum) - # moving_sum -= data_padded[i] - - # src = blocks.vector_source_c(data, False) - # op = filter.moving_average_cc(history, 1) - # dst = blocks.vector_sink_c() - - # tb.connect(src, op) - # tb.connect(op, dst) - # tb.run() - - # dst_data = dst.data() - - # # make sure result is close to zero - # self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 4) - -if __name__ == '__main__': - gr_unittest.run(test_moving_average) diff --git a/blocklib/filter/test/qa_pfb_arb_resampler.py b/blocklib/filter/test/qa_pfb_arb_resampler.py deleted file mode 100644 index 993dea934..000000000 --- a/blocklib/filter/test/qa_pfb_arb_resampler.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, fft, filter, blocks -from gnuradio.kernel.filter import firdes -from gnuradio.kernel.fft import window -import math - - -def sig_source_c(samp_rate, freq, amp, N): - t = [float(x) / samp_rate for x in range(N)] - y = [math.cos(2. * math.pi * freq * x) + - 1j * math.sin(2. * math.pi * freq * x) for x in t] - return y - - -def sig_source_f(samp_rate, freq, amp, N): - t = [float(x) / samp_rate for x in range(N)] - y = [math.sin(2. * math.pi * freq * x) for x in t] - return y - - -class test_pfb_arb_resampler(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_fff_000(self): - N = 500 # number of samples to use - fs = 5000.0 # baseband sampling rate - rrate = 2.3421 # resampling rate - - nfilts = 32 - taps = firdes.low_pass_2( - nfilts, - nfilts * fs, - fs / 2, - fs / 10, - attenuation_dB=80, - window=window.BLACKMAN_hARRIS) - - freq = 121.213 - data = sig_source_f(fs, freq, 1, N) - signal = blocks.vector_source_f(data) - pfb = filter.pfb_arb_resampler_fff(rrate, taps, nfilts) - snk = blocks.vector_sink_f() - - self.tb.connect((signal, pfb, snk)) - self.tb.run() - - Ntest = 50 - L = len(snk.data()) - - # Get group delay and estimate of phase offset from the filter itself. - delay = pfb.group_delay() - phase = pfb.phase_offset(freq, fs) - - # Create a timeline offset by the filter's group delay - t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # Data of the sinusoid at frequency freq with the delay and phase - # offset. - expected_data = [math.sin(2. * math.pi * freq * x + phase) for x in t] - - dst_data = snk.data() - - self.assertFloatTuplesAlmostEqual( - expected_data[-Ntest:], dst_data[-Ntest:], 2) - - # def test_ccf_000(self): - # N = 5000 # number of samples to use - # fs = 5000.0 # baseband sampling rate - # rrate = 2.4321 # resampling rate - - # nfilts = 32 - # taps = firdes.low_pass_2( - # nfilts, - # nfilts * fs, - # fs / 2, - # fs / 10, - # attenuation_dB=80, - # window=window.BLACKMAN_hARRIS) - - # freq = 211.123 - # data = sig_source_c(fs, freq, 1, N) - # signal = blocks.vector_source_c(data) - # pfb = filter.pfb_arb_resampler_ccf(rrate, taps, nfilts) - # snk = blocks.vector_sink_c() - - # self.tb.connect((signal, pfb, snk)) - # self.tb.run() - - # Ntest = 50 - # L = len(snk.data()) - - # # Get group delay and estimate of phase offset from the filter itself. - # delay = pfb.group_delay() - # phase = pfb.phase_offset(freq, fs) - - # # Create a timeline offset by the filter's group delay - # t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # # Data of the sinusoid at frequency freq with the delay and phase - # # offset. - # expected_data = [ - # math.cos( - # 2. * - # math.pi * - # freq * - # x + - # phase) + - # 1j * - # math.sin( - # 2. * - # math.pi * - # freq * - # x + - # phase) for x in t] - - # dst_data = snk.data() - - # self.assertComplexTuplesAlmostEqual( - # expected_data[-Ntest:], dst_data[-Ntest:], 2) - - # def test_ccf_001(self): - # N = 50000 # number of samples to use - # fs = 5000.0 # baseband sampling rate - # rrate = 0.75 # resampling rate - - # nfilts = 32 - # taps = firdes.low_pass_2( - # nfilts, - # nfilts * fs, - # fs / 4, - # fs / 10, - # attenuation_dB=80, - # window=window.BLACKMAN_hARRIS) - - # freq = 211.123 - # data = sig_source_c(fs, freq, 1, N) - # signal = blocks.vector_source_c(data) - # pfb = filter.pfb_arb_resampler_ccf(rrate, taps, nfilts) - # snk = blocks.vector_sink_c() - - # self.tb.connect((signal, pfb, snk)) - # self.tb.run() - - # Ntest = 50 - # L = len(snk.data()) - - # # Get group delay and estimate of phase offset from the filter itself. - # delay = pfb.group_delay() - # phase = pfb.phase_offset(freq, fs) - - # # Create a timeline offset by the filter's group delay - # t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # # Data of the sinusoid at frequency freq with the delay and phase - # # offset. - # expected_data = [ - # math.cos( - # 2. * - # math.pi * - # freq * - # x + - # phase) + - # 1j * - # math.sin( - # 2. * - # math.pi * - # freq * - # x + - # phase) for x in t] - - # dst_data = snk.data() - - # self.assertComplexTuplesAlmostEqual( - # expected_data[-Ntest:], dst_data[-Ntest:], 2) - - # def test_ccc_000(self): - # N = 5000 # number of samples to use - # fs = 5000.0 # baseband sampling rate - # rrate = 3.4321 # resampling rate - - # nfilts = 32 - # taps = firdes.complex_band_pass_2( - # nfilts, - # nfilts * fs, - # 50, - # 400, - # fs / 10, - # attenuation_dB=80, - # window=window.BLACKMAN_hARRIS) - - # freq = 211.123 - # data = sig_source_c(fs, freq, 1, N) - # signal = blocks.vector_source_c(data) - # pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts) - # snk = blocks.vector_sink_c() - - # self.tb.connect((signal, pfb, snk)) - # self.tb.run() - - # Ntest = 50 - # L = len(snk.data()) - - # # Get group delay and estimate of phase offset from the filter itself. - # delay = pfb.group_delay() - # phase = pfb.phase_offset(freq, fs) - - # # Create a timeline offset by the filter's group delay - # t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # # Data of the sinusoid at frequency freq with the delay and phase - # # offset. - # expected_data = [ - # math.cos( - # 2. * - # math.pi * - # freq * - # x + - # phase) + - # 1j * - # math.sin( - # 2. * - # math.pi * - # freq * - # x + - # phase) for x in t] - - # dst_data = snk.data() - - # self.assertComplexTuplesAlmostEqual( - # expected_data[-Ntest:], dst_data[-Ntest:], 2) - - # def test_ccc_001(self): - # N = 50000 # number of samples to use - # fs = 5000.0 # baseband sampling rate - # rrate = 0.715 # resampling rate - - # nfilts = 32 - # taps = firdes.complex_band_pass_2( - # nfilts, - # nfilts * fs, - # 50, - # 400, - # fs / 10, - # attenuation_dB=80, - # window=window.BLACKMAN_hARRIS) - - # freq = 211.123 - # data = sig_source_c(fs, freq, 1, N) - # signal = blocks.vector_source_c(data) - # pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts) - # snk = blocks.vector_sink_c() - - # self.tb.connect((signal, pfb, snk)) - # self.tb.run() - - # Ntest = 50 - # L = len(snk.data()) - - # # Get group delay and estimate of phase offset from the filter itself. - # delay = pfb.group_delay() - # phase = pfb.phase_offset(freq, fs) - - # # Create a timeline offset by the filter's group delay - # t = [float(x) / (fs * rrate) for x in range(-delay, L - delay)] - - # # Data of the sinusoid at frequency freq with the delay and phase - # # offset. - # expected_data = [ - # math.cos( - # 2. * - # math.pi * - # freq * - # x + - # phase) + - # 1j * - # math.sin( - # 2. * - # math.pi * - # freq * - # x + - # phase) for x in t] - - # dst_data = snk.data() - - # self.assertComplexTuplesAlmostEqual( - # expected_data[-Ntest:], dst_data[-Ntest:], 2) - - -if __name__ == '__main__': - gr_unittest.run(test_pfb_arb_resampler) diff --git a/blocklib/filter/test/qa_pfb_channelizer.py b/blocklib/filter/test/qa_pfb_channelizer.py deleted file mode 100644 index b0d98c1b3..000000000 --- a/blocklib/filter/test/qa_pfb_channelizer.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2012-2014 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, fft, filter, blocks, streamops, math as grmath -from gnuradio.kernel.filter import firdes -from gnuradio.kernel.fft import window -import math -import cmath - - -def sig_source_c(samp_rate, freq, amp, N): - t = [float(x) / samp_rate for x in range(N)] - y = [math.cos(2. * math.pi * freq * x) + - 1j * math.sin(2. * math.pi * freq * x) for x in t] - return y - - -class test_pfb_channelizer(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.flowgraph() - self.freqs = [110., -513., 203., -230, 121] - # Number of channels to channelize. - self.M = len(self.freqs) - # Number of samples to use. - self.N = 1000 - # Baseband sampling rate. - self.fs = 5000 - # Input samp rate to channelizer. - self.ifs = self.M * self.fs - - self.taps = firdes.low_pass_2( - 1, self.ifs, self.fs / 2, self.fs / 10, - attenuation_dB=80, - window=window.BLACKMAN_hARRIS) - - self.Ntest = 50 - - def tearDown(self): - self.tb = None - - def test_0000(self): - self.check_channelizer(filter.pfb_channelizer_cc( - self.M, taps=self.taps, oversample_rate=1)) - - - # def test_0001(self): - # self.check_channelizer(filter.pfb.channelizer_hier_ccf( - # self.M, n_filterbanks=1, taps=self.taps)) - - # def test_0002(self): - # """Test roundig error handling for oversample rate (ok).""" - # channels, oversample = 36, 25. - # filter.pfb.channelizer_ccf(channels, taps=self.taps, - # oversample_rate=channels / oversample) - - def test_0003(self): - """Test roundig error handling for oversample rate, (bad).""" - # pybind11 raises ValueError instead of TypeError - self.assertRaises(ValueError, - filter.pfb_channelizer_cc, - 36, taps=self.taps, oversample_rate=10.1334) - - - def check_channelizer(self, channelizer_block): - signals = list() - add = grmath.add_cc(len(self.freqs)) - for i in range(len(self.freqs)): - f = self.freqs[i] + i * self.fs - data = sig_source_c(self.ifs, f, 1, self.N) - signals.append(blocks.vector_source_c(data)) - self.tb.connect(signals[i],0 , add, i) - - s2ss = streamops.deinterleave(self.M) - - # self.tb.connect(add, 0, s2ss, 0) - self.tb.connect(add, channelizer_block) - - snks = list() - for i in range(self.M): - snks.append(blocks.vector_sink_c()) - # self.tb.connect(s2ss,i, channelizer_block,i) - self.tb.connect(channelizer_block, i, snks[i],0) - - self.tb.run() - - L = len(snks[0].data()) - - expected_data = self.get_expected_data(L) - received_data = [snk.data() for snk in snks] - - for expected, received in zip(expected_data, received_data): - self.compare_data(expected, received) - - def compare_data(self, expected, received): - Ntest = 50 - expected = expected[-Ntest:] - received = received[-Ntest:] - expected = [x / expected[0] for x in expected] - received = [x / received[0] for x in received] - self.assertComplexTuplesAlmostEqual(expected, received, 3) - - def get_freq(self, data): - freqs = [] - for r1, r2 in zip(data[:-1], data[1:]): - diff = cmath.phase(r1) - cmath.phase(r2) - if diff > math.pi: - diff -= 2 * math.pi - if diff < -math.pi: - diff += 2 * math.pi - freqs.append(diff) - freq = float(sum(freqs)) / len(freqs) - freq /= 2 * math.pi - return freq - - def get_expected_data(self, L): - - # Filter delay is the normal delay of each arm - tpf = math.ceil(len(self.taps) / float(self.M)) - delay = -(tpf - 1.0) / 2.0 - delay = int(delay) - - # Create a time scale that's delayed to match the filter delay - t = [float(x) / self.fs for x in range(delay, L + delay)] - - # Create known data as complex sinusoids at the different baseband freqs - # the different channel numbering is due to channelizer output order. - expected_data = [[math.cos(2. * - math.pi * - f * - x) + - 1j * - math.sin(2. * - math.pi * - f * - x) for x in t] for f in self.freqs] - return expected_data - - -if __name__ == '__main__': - gr_unittest.run(test_pfb_channelizer) diff --git a/blocklib/math/complex_to_mag/complex_to_mag.yml b/blocklib/math/complex_to_mag/complex_to_mag.yml deleted file mode 100644 index e67842ddf..000000000 --- a/blocklib/math/complex_to_mag/complex_to_mag.yml +++ /dev/null @@ -1,31 +0,0 @@ -module: math -block: complex_to_mag -label: Complex to Magnitude -blocktype: sync_block -category: '[Core]/Math Operators' - -parameters: -- id: vlen - label: Vector Length - dtype: size - settable: false - default: 1 - -ports: -- domain: stream - id: in - direction: input - type: cf32 - shape: parameters/vlen - -- domain: stream - id: out - direction: output - type: rf32 - shape: parameters/vlen - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/math/complex_to_mag/complex_to_mag_cpu.cc b/blocklib/math/complex_to_mag/complex_to_mag_cpu.cc deleted file mode 100644 index 3d3d0eed4..000000000 --- a/blocklib/math/complex_to_mag/complex_to_mag_cpu.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "complex_to_mag_cpu.h" -#include "complex_to_mag_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace math { - -complex_to_mag_cpu::complex_to_mag_cpu(const block_args& args) - : INHERITED_CONSTRUCTORS, d_vlen(args.vlen) -{ - // const int alignment_multiple = volk_get_alignment() / sizeof(float); - // set_output_multiple(std::max(1, alignment_multiple)); -} - -work_return_t complex_to_mag_cpu::work(work_io& wio) -{ - auto noutput_items = wio.outputs()[0].n_items; - int noi = noutput_items * d_vlen; - - auto iptr = wio.inputs()[0].items<gr_complex>(); - auto optr = wio.outputs()[0].items<float>(); - - volk_32fc_magnitude_32f_u(optr, iptr, noi); - - wio.produce_each(noutput_items); - return work_return_t::OK; -} - - -} // namespace math -} // namespace gr diff --git a/blocklib/math/complex_to_mag/complex_to_mag_cpu.h b/blocklib/math/complex_to_mag/complex_to_mag_cpu.h deleted file mode 100644 index 4d6455fa2..000000000 --- a/blocklib/math/complex_to_mag/complex_to_mag_cpu.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/math/complex_to_mag.h> -#include <volk/volk.h> -namespace gr { -namespace math { - -class complex_to_mag_cpu : public complex_to_mag -{ -public: - complex_to_mag_cpu(const block_args& args); - work_return_t work(work_io&) override; - -private: - size_t d_vlen; -}; - -} // namespace math -} // namespace gr
\ No newline at end of file diff --git a/blocklib/math/complex_to_mag_squared/complex_to_mag_squared.yml b/blocklib/math/complex_to_mag_squared/complex_to_mag_squared.yml deleted file mode 100644 index 03ea8a448..000000000 --- a/blocklib/math/complex_to_mag_squared/complex_to_mag_squared.yml +++ /dev/null @@ -1,31 +0,0 @@ -module: math -block: complex_to_mag_squared -label: Complex to Magnitude Squared -blocktype: sync_block -category: '[Core]/Math Operators' - -parameters: -- id: vlen - label: Vector Length - dtype: size - settable: false - default: 1 - -ports: -- domain: stream - id: in - direction: input - type: cf32 - shape: parameters/vlen - -- domain: stream - id: out - direction: output - type: rf32 - shape: parameters/vlen - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/math/complex_to_mag_squared/complex_to_mag_squared_cpu.cc b/blocklib/math/complex_to_mag_squared/complex_to_mag_squared_cpu.cc deleted file mode 100644 index 826a53679..000000000 --- a/blocklib/math/complex_to_mag_squared/complex_to_mag_squared_cpu.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "complex_to_mag_squared_cpu.h" -#include "complex_to_mag_squared_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace math { -complex_to_mag_squared_cpu::complex_to_mag_squared_cpu(const block_args& args) - : INHERITED_CONSTRUCTORS, d_vlen(args.vlen) -{ - // const int alignment_multiple = volk_get_alignment() / sizeof(float); - // set_output_multiple(std::max(1, alignment_multiple)); -} - -work_return_t complex_to_mag_squared_cpu::work(work_io& wio) -{ - auto noutput_items = wio.outputs()[0].n_items; - int noi = noutput_items * d_vlen; - - auto iptr = wio.inputs()[0].items<gr_complex>(); - auto optr = wio.outputs()[0].items<float>(); - - volk_32fc_magnitude_squared_32f(optr, iptr, noi); - - wio.produce_each(noutput_items); - return work_return_t::OK; -} - - -} // namespace math -} // namespace gr diff --git a/blocklib/math/complex_to_mag_squared/complex_to_mag_squared_cpu.h b/blocklib/math/complex_to_mag_squared/complex_to_mag_squared_cpu.h deleted file mode 100644 index b50bbd544..000000000 --- a/blocklib/math/complex_to_mag_squared/complex_to_mag_squared_cpu.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/math/complex_to_mag_squared.h> -#include <volk/volk.h> - -namespace gr { -namespace math { - -class complex_to_mag_squared_cpu : public complex_to_mag_squared -{ -public: - complex_to_mag_squared_cpu(const block_args& args); - - work_return_t work(work_io&) override; - -private: - size_t d_vlen; -}; - -} // namespace math -} // namespace gr
\ No newline at end of file diff --git a/blocklib/math/divide/divide.yml b/blocklib/math/divide/divide.yml deleted file mode 100644 index 5939755ba..000000000 --- a/blocklib/math/divide/divide.yml +++ /dev/null @@ -1,46 +0,0 @@ -module: math -block: divide -label: Divide -blocktype: sync_block -category: '[Core]/Math Operators' - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - - ri32 - - ri16 - -parameters: -- id: num_inputs - label: Number of Inputs - dtype: size - settable: false - default: 2 -- id: vlen - label: Vec. Length - dtype: size - settable: false - default: 1 - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - shape: parameters/vlen - multiplicity: parameters/num_inputs - -- domain: stream - id: out - direction: output - type: typekeys/T - shape: parameters/vlen - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/math/divide/divide_cpu.cc b/blocklib/math/divide/divide_cpu.cc deleted file mode 100644 index e25cfeaa0..000000000 --- a/blocklib/math/divide/divide_cpu.cc +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2012,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "divide_cpu.h" -#include "divide_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace math { - -template <class T> -divide_cpu<T>::divide_cpu(const typename divide<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), d_num_inputs(args.num_inputs), d_vlen(args.vlen) -{ -} - -template <> -divide_cpu<float>::divide_cpu(const typename divide<float>::block_args& args) - : INHERITED_CONSTRUCTORS(float), d_num_inputs(args.num_inputs), d_vlen(args.vlen) -{ - // const int alignment_multiple = volk_get_alignment() / sizeof(float); - // set_output_multiple(std::max(1, alignment_multiple)); -} - -template <> -divide_cpu<gr_complex>::divide_cpu(const typename divide<gr_complex>::block_args& args) - : INHERITED_CONSTRUCTORS(gr_complex), d_num_inputs(args.num_inputs), d_vlen(args.vlen) -{ - const int alignment_multiple = volk_get_alignment() / sizeof(gr_complex); - set_output_multiple(std::max(1, alignment_multiple)); -} - - -template <> -work_return_t divide_cpu<float>::work(work_io& wio) -{ - auto optr = wio.outputs()[0].items<float>(); - auto noutput_items = wio.outputs()[0].n_items; - - auto numerator = wio.inputs()[0].items<float>(); - for (size_t inp = 1; inp < d_num_inputs; ++inp) { - volk_32f_x2_divide_32f( - optr, numerator, wio.inputs()[inp].items<float>(), noutput_items * d_vlen); - numerator = optr; - } - - wio.outputs()[0].n_produced = wio.outputs()[0].n_items; - return work_return_t::OK; -} - -template <> -work_return_t divide_cpu<gr_complex>::work(work_io& wio) - -{ - auto optr = wio.outputs()[0].items<gr_complex>(); - auto noutput_items = wio.outputs()[0].n_items; - - auto numerator = wio.inputs()[0].items<gr_complex>(); - for (size_t inp = 1; inp < d_num_inputs; ++inp) { - volk_32fc_x2_divide_32fc(optr, - numerator, - wio.inputs()[inp].items<gr_complex>(), - noutput_items * d_vlen); - numerator = optr; - } - - wio.outputs()[0].n_produced = wio.outputs()[0].n_items; - return work_return_t::OK; -} - -template <class T> -work_return_t divide_cpu<T>::work(work_io& wio) - -{ - auto optr = wio.outputs()[0].items<T>(); - auto noutput_items = wio.outputs()[0].n_items; - - for (size_t i = 0; i < noutput_items * d_vlen; i++) { - T acc = (wio.inputs()[0].items<T>())[i]; - for (size_t j = 1; j < d_num_inputs; j++) { - acc /= (wio.inputs()[j].items<T>())[i]; - } - *optr++ = static_cast<T>(acc); - } - - wio.outputs()[0].n_produced = wio.outputs()[0].n_items; - wio.inputs()[0].n_consumed = wio.inputs()[0].n_items; - return work_return_t::OK; -} - - -} /* namespace math */ -} /* namespace gr */ diff --git a/blocklib/math/divide/divide_cpu.h b/blocklib/math/divide/divide_cpu.h deleted file mode 100644 index bb5f667be..000000000 --- a/blocklib/math/divide/divide_cpu.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2012,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/math/divide.h> - -namespace gr { -namespace math { - -template <class T> -class divide_cpu : public divide<T> -{ -public: - divide_cpu(const typename divide<T>::block_args& args); - - work_return_t work(work_io&) override; - -protected: - size_t d_num_inputs; - size_t d_vlen; -}; - - -} // namespace math -} // namespace gr diff --git a/blocklib/math/multiply/multiply.yml b/blocklib/math/multiply/multiply.yml deleted file mode 100644 index f355a96d4..000000000 --- a/blocklib/math/multiply/multiply.yml +++ /dev/null @@ -1,46 +0,0 @@ -module: math -block: multiply -label: Multiply -blocktype: sync_block -category: '[Core]/Math Operators' - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - - ri32 - - ri16 - -parameters: -- id: num_inputs - label: Number of Inputs - dtype: size - settable: false - default: 2 -- id: vlen - label: Vec. Length - dtype: size - settable: false - default: 1 - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - shape: parameters/vlen - multiplicity: parameters/num_inputs - -- domain: stream - id: out - direction: output - type: typekeys/T - shape: parameters/vlen - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/math/multiply/multiply_cpu.cc b/blocklib/math/multiply/multiply_cpu.cc deleted file mode 100644 index f7178dc80..000000000 --- a/blocklib/math/multiply/multiply_cpu.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2012,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "multiply_cpu.h" -#include "multiply_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace math { - -template <class T> -multiply_cpu<T>::multiply_cpu(const typename multiply<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), d_num_inputs(args.num_inputs), d_vlen(args.vlen) -{ -} - -template <> -multiply_cpu<float>::multiply_cpu(const typename multiply<float>::block_args& args) - : INHERITED_CONSTRUCTORS(float), d_num_inputs(args.num_inputs), d_vlen(args.vlen) -{ - // const int alignment_multiple = volk_get_alignment() / sizeof(float); - // set_output_multiple(std::max(1, alignment_multiple)); -} - -template <> -multiply_cpu<gr_complex>::multiply_cpu( - const typename multiply<gr_complex>::block_args& args) - : INHERITED_CONSTRUCTORS(gr_complex), d_num_inputs(args.num_inputs), d_vlen(args.vlen) -{ - // const int alignment_multiple = volk_get_alignment() / sizeof(gr_complex); - // set_output_multiple(std::max(1, alignment_multiple)); -} - -template <> -work_return_t multiply_cpu<float>::work(work_io& wio) -{ - auto out = wio.outputs()[0].items<float>(); - auto noutput_items = wio.outputs()[0].n_items; - int noi = d_vlen * noutput_items; - - memcpy(out, wio.inputs()[0].items<float>(), noi * sizeof(float)); - for (size_t i = 1; i < d_num_inputs; i++) { - volk_32f_x2_multiply_32f(out, out, wio.inputs()[i].items<float>(), noi); - } - - wio.outputs()[0].n_produced = wio.outputs()[0].n_items; - return work_return_t::OK; -} - -template <> -work_return_t multiply_cpu<gr_complex>::work(work_io& wio) - -{ - auto out = wio.outputs()[0].items<gr_complex>(); - auto noutput_items = wio.outputs()[0].n_items; - int noi = d_vlen * noutput_items; - - memcpy(out, wio.inputs()[0].items<gr_complex>(), noi * sizeof(gr_complex)); - for (size_t i = 1; i < d_num_inputs; i++) { - volk_32fc_x2_multiply_32fc(out, out, wio.inputs()[i].items<gr_complex>(), noi); - } - - wio.outputs()[0].n_produced = wio.outputs()[0].n_items; - return work_return_t::OK; -} - -template <class T> -work_return_t multiply_cpu<T>::work(work_io& wio) - -{ - auto optr = wio.outputs()[0].items<T>(); - auto noutput_items = wio.outputs()[0].n_items; - - for (size_t i = 0; i < noutput_items * d_vlen; i++) { - T acc = (wio.inputs()[0].items<T>())[i]; - for (size_t j = 1; j < d_num_inputs; j++) { - acc *= (wio.inputs()[j].items<T>())[i]; - } - *optr++ = static_cast<T>(acc); - } - - wio.outputs()[0].n_produced = wio.outputs()[0].n_items; - wio.inputs()[0].n_consumed = wio.inputs()[0].n_items; - return work_return_t::OK; -} - -} /* namespace math */ -} /* namespace gr */ diff --git a/blocklib/math/multiply/multiply_cpu.h b/blocklib/math/multiply/multiply_cpu.h deleted file mode 100644 index 18dfa463a..000000000 --- a/blocklib/math/multiply/multiply_cpu.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2012,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/math/multiply.h> - -namespace gr { -namespace math { - -template <class T> -class multiply_cpu : public multiply<T> -{ -public: - multiply_cpu(const typename multiply<T>::block_args& args); - - work_return_t work(work_io&) override; - -protected: - size_t d_num_inputs; - size_t d_vlen; -}; - - -} // namespace math -} // namespace gr diff --git a/blocklib/math/test/meson.build b/blocklib/math/test/meson.build index 4a525e008..f21368bca 100644 --- a/blocklib/math/test/meson.build +++ b/blocklib/math/test/meson.build @@ -1,7 +1,6 @@ if GR_ENABLE_PYTHON test('qa_conjugate', py3, args : files('qa_conjugate.py'), env: TEST_ENV) - test('qa_type_conversions', py3, args : files('qa_type_conversions.py'), env: TEST_ENV) test('qa_add_mult_div_sub', py3, args : files('qa_add_mult_div_sub.py'), env: TEST_ENV) test('qa_add_numpy', py3, args : files('qa_add_numpy.py'), env: TEST_ENV) if (IMPLEMENT_CUDA) diff --git a/blocklib/math/test/qa_add_mult_div_sub.py b/blocklib/math/test/qa_add_mult_div_sub.py index 728be544f..4edbc6cb6 100644 --- a/blocklib/math/test/qa_add_mult_div_sub.py +++ b/blocklib/math/test/qa_add_mult_div_sub.py @@ -124,37 +124,37 @@ class test_add_mult_div_sub(gr_unittest.TestCase): # multiply_XX - def test_multiply_ss(self): - src1_data = [1, 2, 3, 4, 5] - src2_data = [8, -3, 4, 8, 2] - expected_result = [8, -6, 12, 32, 10] - op = math.multiply_ss(2) - self.help_ss((src1_data, src2_data), - expected_result, op) + # def test_multiply_ss(self): + # src1_data = [1, 2, 3, 4, 5] + # src2_data = [8, -3, 4, 8, 2] + # expected_result = [8, -6, 12, 32, 10] + # op = math.multiply_ss(2) + # self.help_ss((src1_data, src2_data), + # expected_result, op) - def test_multiply_ii(self): - src1_data = [1, 2, 3, 4, 5] - src2_data = [8, -3, 4, 8, 2] - expected_result = [8, -6, 12, 32, 10] - op = math.multiply_ii(2) - self.help_ii((src1_data, src2_data), - expected_result, op) + # def test_multiply_ii(self): + # src1_data = [1, 2, 3, 4, 5] + # src2_data = [8, -3, 4, 8, 2] + # expected_result = [8, -6, 12, 32, 10] + # op = math.multiply_ii(2) + # self.help_ii((src1_data, src2_data), + # expected_result, op) - def test_multiply_ff(self): - src1_data = [1, 2, 3, 4, 5] - src2_data = [8, -3, 4, 8, 2] - expected_result = [8, -6, 12, 32, 10] - op = math.multiply_ff(2) - self.help_ff((src1_data, src2_data), - expected_result, op) + # def test_multiply_ff(self): + # src1_data = [1, 2, 3, 4, 5] + # src2_data = [8, -3, 4, 8, 2] + # expected_result = [8, -6, 12, 32, 10] + # op = math.multiply_ff(2) + # self.help_ff((src1_data, src2_data), + # expected_result, op) - def test_multiply_cc(self): - src1_data = [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j, 5 + 5j] - src2_data = [8, -3, 4, 8, 2] - expected_result = [8 + 8j, -6 - 6j, 12 + 12j, 32 + 32j, 10 + 10j] - op = math.multiply_cc(2) - self.help_cc((src1_data, src2_data), - expected_result, op) + # def test_multiply_cc(self): + # src1_data = [1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j, 5 + 5j] + # src2_data = [8, -3, 4, 8, 2] + # expected_result = [8 + 8j, -6 - 6j, 12 + 12j, 32 + 32j, 10 + 10j] + # op = math.multiply_cc(2) + # self.help_cc((src1_data, src2_data), + # expected_result, op) # multiply_const_XX @@ -268,12 +268,12 @@ class test_add_mult_div_sub(gr_unittest.TestCase): # result_data = dst.data() # self.assertEqual(expected_result, result_data) - def test_div_ff(self): - src1_data = [5, 9, -15, 1024] - src2_data = [10, 3, -5, 64] - expected_result = [0.5, 3, 3, 16] - op = math.divide_ff() - self.help_ff((src1_data, src2_data), expected_result, op) + # def test_div_ff(self): + # src1_data = [5, 9, -15, 1024] + # src2_data = [10, 3, -5, 64] + # expected_result = [0.5, 3, 3, 16] + # op = math.divide_ff() + # self.help_ff((src1_data, src2_data), expected_result, op) if __name__ == '__main__': diff --git a/blocklib/math/test/qa_type_conversions.py b/blocklib/math/test/qa_type_conversions.py deleted file mode 100644 index 8ef973f53..000000000 --- a/blocklib/math/test/qa_type_conversions.py +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, blocks, math - -from math import sqrt, atan2 - - -class test_type_conversions(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.flowgraph() - self.rt = gr.runtime() - - def tearDown(self): - self.tb = None - self.rt = None - - # def test_char_to_float_identity(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_b(src_data) - # op = blocks.char_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_char_to_float_scale(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [0.5, 1.0, 1.5, 2.0, 2.5] - # src = blocks.vector_source_b(src_data) - # op = blocks.char_to_float(scale=2.0) - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_char_to_short(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [256, 512, 768, 1024, 1280] - # src = blocks.vector_source_b(src_data) - # op = blocks.char_to_short() - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_complex_to_interleaved_char(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_interleaved_char() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_complex_to_interleaved_short(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_interleaved_short() - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_complex_to_float_1(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1.0, 3.0, 5.0, 7.0, 9.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_complex_to_float_2(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data1 = [1.0, 3.0, 5.0, 7.0, 9.0] - # expected_data2 = [2.0, 4.0, 6.0, 8.0, 10.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_float() - # dst1 = blocks.vector_sink_f() - # dst2 = blocks.vector_sink_f() - # self.tb.connect(src, op) - # self.tb.connect((op, 0), dst1) - # self.tb.connect((op, 1), dst2) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data1, dst1.data()) - # self.assertFloatTuplesAlmostEqual(expected_data2, dst2.data()) - - # def test_complex_to_real(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1.0, 3.0, 5.0, 7.0, 9.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_real() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_complex_to_imag(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [2.0, 4.0, 6.0, 8.0, 10.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_imag() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - def test_complex_to_mag(self): - src_data = (1 + 2j, 3 - 4j, 5 + 6j, 7 - 8j, -9 + 10j) - expected_data = [sqrt(5), sqrt(25), sqrt(61), sqrt(113), sqrt(181)] - src = blocks.vector_source_c(src_data) - op = math.complex_to_mag() - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.rt.initialize(self.tb) - self.rt.run() - self.assertFloatTuplesAlmostEqual(expected_data, dst.data(), 5) - - def test_complex_to_mag_squared(self): - src_data = (1 + 2j, 3 - 4j, 5 + 6j, 7 - 8j, -9 + 10j) - expected_data = [5.0, 25.0, 61.0, 113.0, 181.0] - src = blocks.vector_source_c(src_data) - op = math.complex_to_mag_squared() - dst = blocks.vector_sink_f() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.rt.initialize(self.tb) - self.rt.run() - self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_complex_to_arg(self): - # src_data = (1 + 2j, 3 - 4j, 5 + 6j, 7 - 8j, -9 + 10j) - # expected_data = [atan2(2, 1), atan2(-4, 3), - # atan2(6, 5), atan2(-8, 7), atan2(10, -9)] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_arg() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data(), 2) - - # def test_float_to_char_identity(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_char() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_char_scale(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [5, 10, 15, 20, 25] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_char(1, 5) - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_complex_1(self): - # src_data = (1.0, 3.0, 5.0, 7.0, 9.0) - # expected_data = [1 + 0j, 3 + 0j, 5 + 0j, 7 + 0j, 9 + 0j] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_complex() - # dst = blocks.vector_sink_c() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_float_to_complex_2(self): - # src1_data = (1.0, 3.0, 5.0, 7.0, 9.0) - # src2_data = (2.0, 4.0, 6.0, 8.0, 10.0) - # expected_data = [1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j] - # src1 = blocks.vector_source_f(src1_data) - # src2 = blocks.vector_source_f(src2_data) - # op = blocks.float_to_complex() - # dst = blocks.vector_sink_c() - # self.tb.connect(src1, (op, 0)) - # self.tb.connect(src2, (op, 1)) - # self.tb.connect(op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_float_to_int_identity(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_int() - # dst = blocks.vector_sink_i() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_int_scale(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [5, 10, 15, 20, 25] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_int(1, 5) - # dst = blocks.vector_sink_i() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_short_identity(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_short() - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_short_scale(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [5, 10, 15, 20, 25] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_short(1, 5) - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_uchar(self): - # src_data = (1.0, -2.0, 3.0, -4.0, 256.0) - # expected_data = [1, 0, 3, 0, 255] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_uchar() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_int_to_float_identity(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_i(src_data) - # op = blocks.int_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_int_to_float_scale(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [0.2, 0.4, 0.6, 0.8, 1.0] - # src = blocks.vector_source_i(src_data) - # op = blocks.int_to_float(1, 5) - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_interleaved_short_to_complex(self): - # src_data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - # expected_data = [1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j] - # src = blocks.vector_source_s(src_data, vlen=2) - # op = streamops.interleaved_short_to_complex() - # dst = blocks.vector_sink_c() - # self.tb.connect(src, op) - # self.tb.connect(op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_short_to_char(self): - # src_data = (256, 512, 768, 1024, 1280) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_s(src_data) - # op = blocks.short_to_char() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_short_to_float_identity(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_s(src_data) - # op = blocks.short_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_short_to_float_scale(self): - # src_data = (5, 10, 15, 20, 25) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_s(src_data) - # op = blocks.short_to_float(1, 5) - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_uchar_to_float(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_b(src_data) - # op = blocks.uchar_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - -if __name__ == '__main__': - gr_unittest.run(test_type_conversions) diff --git a/blocklib/meson.build b/blocklib/meson.build index 0e30f3c60..c1655791d 100644 --- a/blocklib/meson.build +++ b/blocklib/meson.build @@ -17,31 +17,6 @@ endif if get_option('enable_gr_blocks') subdir('blocks') endif - -if get_option('enable_gr_fec') -subdir('fec') -endif -if get_option('enable_gr_fft') -subdir('fft') -endif -if get_option('enable_gr_filter') -subdir('filter') -endif -if get_option('enable_gr_analog') -subdir('analog') -endif if get_option('enable_gr_streamops') subdir('streamops') endif -if get_option('enable_gr_fileio') -subdir('fileio') -endif -if get_option('enable_gr_zeromq') -subdir('zeromq') -endif -if get_option('enable_gr_audio') -subdir('audio') -endif -if get_option('enable_gr_soapy') -subdir('soapy') -endif diff --git a/blocklib/soapy/.gitignore b/blocklib/soapy/.gitignore deleted file mode 100644 index 74cf878c2..000000000 --- a/blocklib/soapy/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -meson.build -!include/gnuradio/soapy/meson.build -!lib/meson.build -!python/gnuradio/soapy/bindings/meson.build -!test/meson.build diff --git a/blocklib/soapy/hackrf_sink/hackrf_sink.yml b/blocklib/soapy/hackrf_sink/hackrf_sink.yml deleted file mode 100644 index 661a44ed8..000000000 --- a/blocklib/soapy/hackrf_sink/hackrf_sink.yml +++ /dev/null @@ -1,92 +0,0 @@ -module: soapy -block: hackrf_sink -label: HackRF Sink -blocktype: grc -category: '[Core]/Soapy' - -typekeys: - - id: T - type: class - options: - - cf32 - # - rf32 - -grc: - flags: [python] - templates: - imports: from gnuradio import soapy - make: |- - dev = 'driver=hackrf' - stream_args = '' - tune_args = [''] - settings = [''] - - self.${id} = soapy.sink_${T.fcn}(dev, 1, ${dev_args}, - stream_args, tune_args, settings) - self.${id}.set_sample_rate(0, ${samp_rate}) - self.${id}.set_bandwidth(0, ${bandwidth}) - self.${id}.set_frequency(0, ${center_freq}) - self.${id}.set_gain(0, 'AMP', ${amp}) - self.${id}.set_gain(0, 'VGA', min(max(${vga}, 0.0), 47.0)) - callbacks: - - set_sample_rate(0, ${samp_rate}) - - set_bandwidth(0, ${bandwidth}) - - set_frequency(0, ${center_freq}) - - set_gain(0, 'AMP', ${amp}) - - set_gain(0, 'VGA', min(max(${vga}, 0.0), 47.0)) - - -parameters: - - id: dev_args - label: Device arguments - dtype: string - grc: - hide: ${'part' if not dev_args else 'none'} - - - id: samp_rate - label: Sample Rate - dtype: rf32 - grc: - default: 'samp_rate' - - - id: bandwidth - label: Bandwidth (0=auto) - dtype: rf32 - grc: - default: '0' - hide: part - category: RF Options - - - id: center_freq - label: 'Center Freq (Hz)' - dtype: rf64 - grc: - category: RF Options - default: 'freq' - - - id: amp - label: 'Amp On (+14 dB)' - dtype: bool - grc: - default: 'False' - hide: part - category: RF Options - - - id: vga - label: 'VGA Gain (0dB - 47dB)' - dtype: rf64 - grc: - default: '16' - hide: part - category: RF Options - -ports: - - domain: stream - id: in - direction: input - type: typekeys/T - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/soapy/hackrf_source/hackrf_source.yml b/blocklib/soapy/hackrf_source/hackrf_source.yml deleted file mode 100644 index c63bdff42..000000000 --- a/blocklib/soapy/hackrf_source/hackrf_source.yml +++ /dev/null @@ -1,104 +0,0 @@ -module: soapy -block: hackrf_source -label: HackRF Source -blocktype: grc -category: '[Core]/Soapy' - -typekeys: - - id: T - type: class - options: - - cf32 - # - rf32 - -grc: - flags: [python] - templates: - imports: |- - from gnuradio import soapy - make: |- - dev = 'driver=hackrf' - stream_args = '' - tune_args = [''] - settings = [''] - - self.${id} = soapy.source_${T.fcn}(dev, 1, ${dev_args}, - stream_args, tune_args, settings) - self.${id}.set_sample_rate(0, ${samp_rate}) - self.${id}.set_bandwidth(0, ${bandwidth}) - self.${id}.set_frequency(0, ${center_freq}) - self.${id}.set_gain(0, 'AMP', ${amp}) - self.${id}.set_gain(0, 'LNA', min(max(${gain}, 0.0), 40.0)) - self.${id}.set_gain(0, 'VGA', min(max(${vga}, 0.0), 62.0)) - callbacks: - - set_sample_rate(0, ${samp_rate}) - - set_bandwidth(0, ${bandwidth}) - - set_frequency(0, ${center_freq}) - - set_gain(0, 'AMP', ${amp}) - - set_gain(0, 'LNA', min(max(${gain}, 0.0), 40.0)) - - set_gain(0, 'VGA', min(max(${vga}, 0.0), 62.0)) - - -parameters: - - id: dev_args - label: Device arguments - dtype: string - grc: - hide: ${'part' if not dev_args else 'none'} - - - id: samp_rate - label: Sample Rate - dtype: rf32 - grc: - default: 'samp_rate' - - - id: bandwidth - label: Bandwidth (0=auto) - dtype: rf32 - grc: - category: RF Options - default: '0' - hide: part - - - id: center_freq - label: 'Center Freq (Hz)' - - dtype: rf32 - grc: - category: RF Options - default: 'freq' - - - id: amp - label: 'Amp On (+14 dB)' - dtype: bool - grc: - category: RF Options - default: 'False' - hide: part - - - id: gain - label: 'IF Gain (0dB - 40dB)' - dtype: rf32 - grc: - category: RF Options - default: '16' - hide: part - - - id: vga - label: 'VGA Gain (0dB - 62dB)' - dtype: rf32 - grc: - category: RF Options - default: '16' - hide: part - -ports: - - domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/soapy/include/gnuradio/soapy/api.h b/blocklib/soapy/include/gnuradio/soapy/api.h deleted file mode 100644 index be2073508..000000000 --- a/blocklib/soapy/include/gnuradio/soapy/api.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * gr-soapy: Soapy SDR Radio Module - * - * Copyright (C) 2018 - * Libre Space Foundation <http://librespacefoundation.org/> - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/attributes.h> - -#ifdef gnuradio_soapy_EXPORTS -#define SOAPY_API __GR_ATTR_EXPORT -#else -#define SOAPY_API __GR_ATTR_IMPORT -#endif diff --git a/blocklib/soapy/include/gnuradio/soapy/block.h b/blocklib/soapy/include/gnuradio/soapy/block.h deleted file mode 100644 index 49422881b..000000000 --- a/blocklib/soapy/include/gnuradio/soapy/block.h +++ /dev/null @@ -1,726 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Jeff Long - * Copyright 2018-2021 Libre Space Foundation <http://libre.space/> - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include <gnuradio/block.h> -#include <gnuradio/soapy/api.h> -#include <gnuradio/soapy/soapy_types.h> -#include <cstdint> -#include <string> -#include <vector> - -namespace gr { -namespace soapy { - -class SOAPY_API block : virtual public gr::block -{ -public: - /*! - * A key that uniquely identifies the device driver. - * This key identifies the underlying implementation. - * Several variants of a product may share a driver. - */ - virtual std::string get_driver_key() const = 0; - - /*! - * A key that uniquely identifies the hardware. - * This key should be meaningful to the user - * to optimize for the underlying hardware. - */ - virtual std::string get_hardware_key() const = 0; - - /*! - * Query a dictionary of available device information. - * This dictionary can any number of values like - * vendor name, product name, revisions, serials... - * This information can be displayed to the user - * to help identify the instantiated device. - */ - virtual kwargs_t get_hardware_info() const = 0; - - /*! - * Set the frontend mapping of available DSP units to RF frontends. - * This mapping controls channel mapping and channel availability. - * \param frontend_mapping a vendor-specific mapping string - */ - virtual void set_frontend_mapping(const std::string& frontend_mapping) = 0; - - /*! - * Get the frontend mapping of available DSP units to RF frontends. - * This mapping describes channel mapping and channel availability. - * \return a vendor-specific mapping string - */ - virtual std::string get_frontend_mapping() const = 0; - - /*! - * Query a dictionary of available channel information. - * This dictionary can any number of values like - * decoder type, version, available functions... - * This information can be displayed to the user - * to help identify the instantiated channel. - * \param channel an available channel on the device - * \return channel information - */ - virtual kwargs_t get_channel_info(size_t channel) const = 0; - - /*! - * Set sample rate - * \param channel an available channel - * \param sample_rate samples per second - */ - virtual void set_sample_rate(size_t channel, double sample_rate) = 0; - - /*! - * Get the baseband sample rate of the RX chain. - * \param channel an available channel on the device - * \return the sample rate in samples per second - */ - virtual double get_sample_rate(size_t channel) const = 0; - - /*! - * Get the range of possible baseband sample rates. - * \param channel an available channel on the device - * \return a list of sample rate ranges in samples per second - */ - virtual range_list_t get_sample_rate_range(size_t channel) const = 0; - - /*! - * Set device center frequency - * \param channel an available channel - * \param freq frequency in Hz - */ - virtual void set_frequency(size_t channel, double freq) = 0; - - /*! - * Set center frequency of a tunable element - * \param channel an available channel - * \param name an available element name - * \param freq frequency in Hz - */ - virtual void set_frequency(size_t channel, const std::string& name, double freq) = 0; - - /*! - * Get the down conversion frequency of the chain. - * \param channel an available channel on the device - * \return the center frequency in Hz - */ - virtual double get_frequency(size_t channel) const = 0; - - /*! - * Get the frequency of a tunable element in the chain. - * \param channel an available channel on the device - * \param name the name of a tunable element - * \return the tunable element's frequency in Hz - */ - virtual double get_frequency(size_t channel, const std::string& name) const = 0; - - /*! - * List available tunable elements in the chain. - * Elements should be in order RF to baseband. - * \param channel an available channel - * \return a list of tunable elements by name - */ - virtual std::vector<std::string> list_frequencies(size_t channel) const = 0; - - /*! - * Get the range of overall frequency values. - * \param channel an available channel on the device - * \return a list of frequency ranges in Hz - */ - virtual range_list_t get_frequency_range(size_t channel) const = 0; - - /*! - * Get the range of tunable values for the specified element. - * \param channel an available channel on the device - * \param name the name of a tunable element - * \return a list of frequency ranges in Hz - */ - virtual range_list_t get_frequency_range(size_t channel, - const std::string& name) const = 0; - - /*! - * Query the argument info description for stream args. - * \param channel an available channel on the device - * \return a list of argument info structures - */ - virtual arginfo_list_t get_frequency_args_info(size_t channel) const = 0; - - /*! - * Set filter bandwidth - * \param channel an available channel - * \param bandwidth filter width in Hz - */ - virtual void set_bandwidth(size_t channel, double bandwidth) = 0; - - /*! - * Get baseband filter width of the RX chain. - * \param channel an available channel on the device - * \return the baseband filter width in Hz - */ - virtual double get_bandwidth(size_t channel) const = 0; - - /*! - * Get the range of possible baseband filter widths. - * \param channel an available channel on the device - * \return a list of bandwidth ranges in Hz - */ - virtual range_list_t get_bandwidth_range(size_t channel) const = 0; - - /*! - * List available antennas for a channel - * @param channel channel index - * @return available antenna names - */ - virtual std::vector<std::string> list_antennas(int channel) const = 0; - - /*! - * Set antenna for channel - * \param channel an available channel - * \param name an available antenna string name - */ - virtual void set_antenna(size_t channel, const std::string& name) = 0; - - /*! - * Get the selected antenna on RX chain. - * \param channel an available channel on the device - * \return the name of the selected antenna - */ - virtual std::string get_antenna(size_t channel) const = 0; - - /*! - * Return whether automatic gain control (AGC) is supported - * \param channel an available channel - */ - virtual bool has_gain_mode(size_t channel) const = 0; - - /*! - * Set automatic gain control (AGC) - * \param channel an available channel - * \param enable true to enable AGC - */ - virtual void set_gain_mode(size_t channel, bool enable) = 0; - - /*! - * Get the automatic gain mode on the RX chain. - * \param channel an available channel on the device - * \return true for automatic gain setting - */ - virtual bool get_gain_mode(size_t channel) const = 0; - - /*! - * List available amplification elements. - * Elements should be in order RF to baseband. - * \param channel an available channel - * \return a list of gain string names - */ - virtual std::vector<std::string> list_gains(size_t channel) const = 0; - - /*! - * Set overall gain - * The gain will be distributed automatically across available - * elements according to Soapy API. - * \param channel an available channel - * \param gain overall gain value - */ - virtual void set_gain(size_t channel, double gain) = 0; - - /*! - * Set specific gain value - * \param channel an available channel - * \param name gain name to set - * \param gain gain value - */ - virtual void set_gain(size_t channel, const std::string& name, double gain) = 0; - - /*! - * Get the overall value of the gain elements in a chain - * \param channel an available channel on the device - * \return the value of the gain in dB - */ - virtual double get_gain(size_t channel) const = 0; - - /*! - * Get the value of an individual amplification element in a chain. - * \param channel an available channel on the device - * \param name the name of an amplification element - * \return the value of the gain in dB - */ - virtual double get_gain(size_t channel, const std::string& name) const = 0; - - /*! - * Get the overall range of possible gain values. - * \param channel an available channel on the device - * \return a list of gain ranges in dB - */ - virtual range_t get_gain_range(size_t channel) const = 0; - - /*! - * Get the range of possible gain values for a specific element. - * \param channel an available channel on the device - * \param name the name of an amplification element - * \return a list of gain ranges in dB - */ - virtual range_t get_gain_range(size_t channel, const std::string& name) const = 0; - - /*! - * Return whether frequency correction is supported - * \param channel an available channel - */ - virtual bool has_frequency_correction(size_t channel) const = 0; - - /*! - * Set frequency correction - * \param channel an available channel - * \param freq_correction in PPM - */ - virtual void set_frequency_correction(size_t channel, double freq_correction) = 0; - - /*! - * Get the frequency correction value. - * \param channel an available channel on the device - * \return the correction value in PPM - */ - virtual double get_frequency_correction(size_t channel) const = 0; - - /*! - * Return whether DC offset mode can be set - * \param channel an available channel - */ - virtual bool has_dc_offset_mode(size_t channel) const = 0; - - /*! - * Set DC offset mode - * \param channel an available channel - * \param automatic true to set automatic DC removal - */ - virtual void set_dc_offset_mode(size_t channel, bool automatic) = 0; - - /*! - * Get the automatic DC offset correction mode. - * \param channel an available channel on the device - * \return true for automatic offset correction - */ - virtual bool get_dc_offset_mode(size_t channel) const = 0; - - /*! - * Return whether manual dc offset correction is supported - * \param channel an available channel - */ - virtual bool has_dc_offset(size_t channel) const = 0; - - /*! - * Set dc offset correction - * \param channel an available channel - * \param dc_offset complex dc offset correction - */ - virtual void set_dc_offset(size_t channel, const gr_complexd& dc_offset) = 0; - - /*! - * Get the DC offset correction. - * \param channel an available channel on the device - * \return the relative correction (1.0 max) - */ - virtual gr_complexd get_dc_offset(size_t channel) const = 0; - - /*! - * Return whether manual IQ balance correction is supported - * \param channel an available channel - */ - virtual bool has_iq_balance(size_t channel) const = 0; - - /*! - * Set IQ balance correction - * \param channel an available channel - * \param iq_balance complex iq balance correction - */ - virtual void set_iq_balance(size_t channel, const gr_complexd& iq_balance) = 0; - - /*! - * Get the IQ balance correction. - * \param channel an available channel on the device - * \return the relative correction (1.0 max) - */ - virtual gr_complexd get_iq_balance(size_t channel) const = 0; - - /*! - * Does the device support automatic frontend IQ balance correction? - * \param channel an available channel on the device - * \return true if IQ balance corrections are supported - */ - virtual bool has_iq_balance_mode(size_t channel) const = 0; - - /*! - * Set the automatic frontend IQ balance correction. - * \param channel an available channel on the device - * \param automatic true for automatic correction - */ - virtual void set_iq_balance_mode(size_t channel, bool automatic) = 0; - - /*! - * Get the automatic IQ balance corrections mode. - * \param channel an available channel on the device - * \return true for automatic correction - */ - virtual bool get_iq_balance_mode(size_t channel) const = 0; - - /*! - * Set master clock rate - * \param clock_rate clock rate in Hz - */ - virtual void set_master_clock_rate(double clock_rate) = 0; - - /*! - * Get the master clock rate of the device. - * \return the clock rate in Hz - */ - virtual double get_master_clock_rate() const = 0; - - /*! - * Get the range of available master clock rates. - * \return a list of clock rate ranges in Hz - */ - virtual range_list_t get_master_clock_rates() const = 0; - - /*! - * Set the reference clock rate of the device. - * \param rate the clock rate in Hz - */ - virtual void set_reference_clock_rate(double rate) = 0; - - /*! - * Get the reference clock rate of the device. - * \return the clock rate in Hz - */ - virtual double get_reference_clock_rate() const = 0; - - /*! - * Get the range of available reference clock rates. - * \return a list of clock rate ranges in Hz - */ - virtual range_list_t get_reference_clock_rates() const = 0; - - /*! - * Get the list of available clock sources. - * \return a list of clock source names - */ - virtual std::vector<std::string> list_clock_sources() const = 0; - - /*! - * Set the clock source - * \param clock_source an available clock source - */ - virtual void set_clock_source(const std::string& clock_source) = 0; - - /*! - * Get the clock source of the device - * \return the name of the clock source - */ - virtual std::string get_clock_source() const = 0; - - /*! - * Get the list of available time sources. - * \return a list of time source names - */ - virtual std::vector<std::string> list_time_sources() const = 0; - - /*! - * Set the time source on the device - * \param source the name of a time source - */ - virtual void set_time_source(const std::string& source) = 0; - - /*! - * Get the time source of the device - * \return the name of a time source - */ - virtual std::string get_time_source() const = 0; - - /*! - * Does this device have a hardware clock? - * \param what optional argument - * \return true if the hardware clock exists - */ - virtual bool has_hardware_time(const std::string& what = "") const = 0; - - /*! - * Read the time from the hardware clock on the device. - * The what argument can refer to a specific time counter. - * \param what optional argument - * \return the time in nanoseconds - */ - virtual long long get_hardware_time(const std::string& what = "") const = 0; - - /*! - * Write the time to the hardware clock on the device. - * The what argument can refer to a specific time counter. - * \param timeNs time in nanoseconds - * \param what optional argument - */ - virtual void set_hardware_time(long long timeNs, const std::string& what = "") = 0; - - /*! - * List the available global readback sensors. - * A sensor can represent a reference lock, RSSI, temperature. - * \return a list of available sensor string names - */ - virtual std::vector<std::string> list_sensors() const = 0; - - /*! - * Get meta-information about a sensor. - * Example: displayable name, type, range. - * \param key the ID name of an available sensor - * \return meta-information about a sensor - */ - virtual arginfo_t get_sensor_info(const std::string& key) const = 0; - - /*! - * Readback a global sensor given the name. - * The value returned is a string which can represent - * a boolean ("true"/"false"), an integer, or float. - * \param key the ID name of an available sensor - * \return the current value of the sensor - */ - virtual std::string read_sensor(const std::string& key) const = 0; - - /*! - * List the available channel readback sensors. - * A sensor can represent a reference lock, RSSI, temperature. - * \param channel an available channel on the device - * \return a list of available sensor string names - */ - virtual std::vector<std::string> list_sensors(size_t channel) const = 0; - - /*! - * Get meta-information about a channel sensor. - * Example: displayable name, type, range. - * \param channel an available channel on the device - * \param key the ID name of an available sensor - * \return meta-information about a sensor - */ - virtual arginfo_t get_sensor_info(size_t channel, const std::string& key) const = 0; - - /*! - * Readback a channel sensor given the name. - * The value returned is a string which can represent - * a boolean ("true"/"false"), an integer, or float. - * \param channel an available channel on the device - * \param key the ID name of an available sensor - * \return the current value of the sensor - */ - virtual std::string read_sensor(size_t channel, const std::string& key) const = 0; - - /*! - * Get a list of available register interfaces by name. - * \return a list of available register interfaces - */ - virtual std::vector<std::string> list_register_interfaces() const = 0; - - /*! - * Write a register on the device given the interface name. - * This can represent a register on a soft CPU, FPGA, IC; - * the interpretation is up the implementation to decide. - * \param name the name of a available register interface - * \param addr the register address - * \param value the register value - */ - virtual void - write_register(const std::string& name, unsigned addr, unsigned value) = 0; - - /*! - * Read a register on the device given the interface name. - * \param name the name of a available register interface - * \param addr the register address - * \return the register value - */ - virtual unsigned read_register(const std::string& name, unsigned addr) const = 0; - - /*! - * Write a memory block on the device given the interface name. - * This can represent a memory block on a soft CPU, FPGA, IC; - * the interpretation is up the implementation to decide. - * \param name the name of a available memory block interface - * \param addr the memory block start address - * \param value the memory block content - */ - virtual void write_registers(const std::string& name, - unsigned addr, - const std::vector<unsigned>& value) = 0; - - /*! - * Read a memory block on the device given the interface name. - * \param name the name of a available memory block interface - * \param addr the memory block start address - * \param length number of words to be read from memory block - * \return the memory block content - */ - virtual std::vector<unsigned> - read_registers(const std::string& name, unsigned addr, size_t length) const = 0; - - /*! - * Describe the allowed keys and values used for settings. - * \return a list of argument info structures - */ - virtual arginfo_list_t get_setting_info() const = 0; - - /*! - * Write an arbitrary setting on the device. - * The interpretation is up the implementation. - * \param key the setting identifier - * \param value the setting value - */ - virtual void write_setting(const std::string& key, const std::string& value) = 0; - - /*! - * Read an arbitrary setting on the device. - * \param key the setting identifier - * \return the setting value - */ - virtual std::string read_setting(const std::string& key) const = 0; - - /*! - * Describe the allowed keys and values used for channel settings. - * \param channel an available channel on the device - * \return a list of argument info structures - */ - virtual arginfo_list_t get_setting_info(size_t channel) const = 0; - - /*! - * Write an arbitrary channel setting on the device. - * The interpretation is up the implementation. - * \param channel an available channel on the device - * \param key the setting identifier - * \param value the setting value - */ - virtual void - write_setting(size_t channel, const std::string& key, const std::string& value) = 0; - - /*! - * Read an arbitrary channel setting on the device. - * \param channel an available channel on the device - * \param key the setting identifier - * \return the setting value - */ - virtual std::string read_setting(size_t channel, const std::string& key) const = 0; - - /*! - * Get a list of available GPIO banks by name. - */ - virtual std::vector<std::string> list_gpio_banks() const = 0; - - /*! - * Write the value of a GPIO bank. - * \param bank the name of an available bank - * \param value an integer representing GPIO bits - */ - virtual void write_gpio(const std::string& bank, unsigned value) = 0; - - /*! - * Write the value of a GPIO bank with modification mask. - * \param bank the name of an available bank - * \param value an integer representing GPIO bits - * \param mask a modification mask where 1 = modify - */ - virtual void write_gpio(const std::string& bank, unsigned value, unsigned mask) = 0; - - /*! - * Readback the value of a GPIO bank. - * \param bank the name of an available bank - * \return an integer representing GPIO bits - */ - virtual unsigned read_gpio(const std::string& bank) const = 0; - - /*! - * Write the data direction of a GPIO bank. - * 1 bits represent outputs, 0 bits represent inputs. - * \param bank the name of an available bank - * \param dir an integer representing data direction bits - */ - virtual void write_gpio_dir(const std::string& bank, unsigned dir) = 0; - - /*! - * Write the data direction of a GPIO bank with modification mask. - * 1 bits represent outputs, 0 bits represent inputs. - * \param bank the name of an available bank - * \param dir an integer representing data direction bits - * \param mask a modification mask where 1 = modify - */ - virtual void write_gpio_dir(const std::string& bank, unsigned dir, unsigned mask) = 0; - - /*! - * Read the data direction of a GPIO bank. - * 1 bits represent outputs, 0 bits represent inputs. - * \param bank the name of an available bank - * \return an integer representing data direction bits - */ - virtual unsigned read_gpio_dir(const std::string& bank) const = 0; - - /*! - * Write to an available I2C slave. - * If the device contains multiple I2C masters, - * the address bits can encode which master. - * \param addr the address of the slave - * \param data an array of bytes write out - */ - virtual void write_i2c(int addr, const std::string& data) = 0; - - /*! - * Read from an available I2C slave. - * If the device contains multiple I2C masters, - * the address bits can encode which master. - * \param addr the address of the slave - * \param num_bytes the number of bytes to read - * \return an array of bytes read from the slave - */ - virtual std::string read_i2c(int addr, size_t num_bytes) = 0; - - /*! - * Perform a SPI transaction and return the result. - * Its up to the implementation to set the clock rate, - * and read edge, and the write edge of the SPI core. - * SPI slaves without a readback pin will return 0. - * - * If the device contains multiple SPI masters, - * the address bits can encode which master. - * - * \param addr an address of an available SPI slave - * \param data the SPI data, num_bits-1 is first out - * \param num_bits the number of bits to clock out - * \return the readback data, num_bits-1 is first in - */ - virtual unsigned transact_spi(int addr, unsigned data, size_t num_bits) = 0; - - /*! - * Enumerate the available UART devices. - * \return a list of names of available UARTs - */ - virtual std::vector<std::string> list_uarts() const = 0; - - /*! - * Write data to a UART device. - * Its up to the implementation to set the baud rate, - * carriage return settings, flushing on newline. - * \param which the name of an available UART - * \param data an array of bytes to write out - */ - virtual void write_uart(const std::string& which, const std::string& data) = 0; - - /*! - * Read bytes from a UART until timeout or newline. - * Its up to the implementation to set the baud rate, - * carriage return settings, flushing on newline. - * \param which the name of an available UART - * \param timeout_us a timeout in microseconds - * \return an array of bytes read from the UART - */ - virtual std::string read_uart(const std::string& which, - long timeout_us = 100000) const = 0; -}; - -} // namespace soapy -} // namespace gr diff --git a/blocklib/soapy/include/gnuradio/soapy/meson.build b/blocklib/soapy/include/gnuradio/soapy/meson.build deleted file mode 100644 index 415d5a6b1..000000000 --- a/blocklib/soapy/include/gnuradio/soapy/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -headers = [] - -install_headers(headers, subdir : 'gnuradio/soapy')
\ No newline at end of file diff --git a/blocklib/soapy/include/gnuradio/soapy/soapy_types.h b/blocklib/soapy/include/gnuradio/soapy/soapy_types.h deleted file mode 100644 index 1d276db22..000000000 --- a/blocklib/soapy/include/gnuradio/soapy/soapy_types.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -/* GR-style type aliases for Soapy types exposed in gr-soapy blocks */ - -#include <SoapySDR/Types.hpp> - -namespace gr { -namespace soapy { - -using arginfo_t = SoapySDR::ArgInfo; -using arginfo_list_t = SoapySDR::ArgInfoList; - -using argtype_t = SoapySDR::ArgInfo::Type; - -using kwargs_t = SoapySDR::Kwargs; -using kwargs_list_t = SoapySDR::KwargsList; - -using range_t = SoapySDR::Range; -using range_list_t = SoapySDR::RangeList; - -} // namespace soapy -} // namespace gr diff --git a/blocklib/soapy/lib/block_impl.cc b/blocklib/soapy/lib/block_impl.cc deleted file mode 100644 index 4b920526c..000000000 --- a/blocklib/soapy/lib/block_impl.cc +++ /dev/null @@ -1,1660 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Jeff Long - * Copyright 2018-2021 Libre Space Foundation <http://libre.space> - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - -#include "block_impl.h" -#include "setting_string_conversion.h" -#include <SoapySDR/Formats.h> -#include <SoapySDR/Version.hpp> -#include <fmt/core.h> -#include <pmtf/scalar.hpp> -#include <pmtf/string.hpp> -#include <cmath> -#include <numeric> - -namespace gr { -namespace soapy { - -static bool arg_info_has_key(const arginfo_list_t& info_list, const std::string& key) -{ - return std::any_of(info_list.begin(), info_list.end(), [key](const arginfo_t& info) { - return info.key == key; - }); -} - -template <typename T> -static inline bool vector_contains(const std::vector<T>& vec, const std::string& elem) -{ - return (std::find(vec.begin(), vec.end(), elem) != vec.end()); -} - -static inline bool value_in_range(const range_t& range, double value) -{ - return (value >= range.minimum()) && (value <= range.maximum()); -} - -static inline bool value_in_ranges(const range_list_t& ranges, double value) -{ - return std::any_of(ranges.begin(), ranges.end(), [value](const range_t& range) { - return value_in_range(range, value); - }); -} - -static std::string string_vector_to_string(const std::vector<std::string>& vec) -{ - if (vec.empty()) - return "[]"; - - std::string str = "["; - for (const auto& vecStr : vec) { - str += vecStr; - str += ", "; - } - str.erase(str.length() - 2, 2); - - str += "]"; - - return str; -} - -static std::string range_to_string(const range_t& range) -{ - const auto min = range.minimum(); - const auto max = range.maximum(); - - if (min == max) - return std::to_string(min); - else - return "[" + std::to_string(min) + ", " + std::to_string(max) + "]"; -} - -static std::string ranges_to_string(const range_list_t& ranges) -{ - if (ranges.empty()) - return "[]"; - - std::string str; - for (const auto& range : ranges) { - str += range_to_string(range); - str += ", "; - } - str.erase(str.length() - 2, 2); - - return str; -} - -static void check_abi(void) -{ - const std::string buildtime_abi = SOAPY_SDR_ABI_VERSION; - const std::string runtime_abi = SoapySDR::getABIVersion(); - - if (buildtime_abi != runtime_abi) { - throw std::runtime_error(fmt::format( - "\nGR-Soapy detected ABI compatibility mismatch with SoapySDR library.\n" - "GR-Soapy was built against ABI: {},\n" - "but the SoapySDR library reports ABI: {}\n" - "Suggestion: install an ABI compatible version of SoapySDR,\n" - "or rebuild GR-Soapy component against this ABI version.\n", - buildtime_abi, - runtime_abi)); - } -} - -const std::string CMD_CHAN_KEY = "chan"; -const std::string CMD_FREQ_KEY = "freq"; -const std::string CMD_GAIN_KEY = "gain"; -const std::string CMD_ANTENNA_KEY = "antenna"; -const std::string CMD_RATE_KEY = "rate"; -const std::string CMD_BW_KEY = "bandwidth"; -const std::string CMD_GAINMODE_KEY = "gain_mode"; -const std::string CMD_FREQCORR_KEY = "freq_corr"; -const std::string CMD_DCOFFSETMODE_KEY = "dc_offset_mode"; -const std::string CMD_DCOFFSET_KEY = "dc_offset"; -const std::string CMD_IQBAL_KEY = "iq_bal"; -const std::string CMD_IQBALMODE_KEY = "iq_bal_mode"; -const std::string CMD_MCR_KEY = "master_clock_rate"; -const std::string CMD_REFCLOCKRATE_KEY = "ref_clock_rate"; -const std::string CMD_CLOCKSRC_KEY = "clock_src"; -const std::string CMD_TIMESRC_KEY = "time_src"; -const std::string CMD_HWTIME_KEY = "hw_time"; -const std::string CMD_REG_KEY = "reg"; -const std::string CMD_REGS_KEY = "regs"; -const std::string CMD_SETTING_KEY = "setting"; -const std::string CMD_GPIO_KEY = "gpio"; -const std::string CMD_GPIODIR_KEY = "gpio_dir"; -const std::string CMD_I2C_KEY = "i2c"; -const std::string CMD_UART_KEY = "uart"; - -const std::string CMD_NAME_KEY = "name"; -const std::string CMD_KEY_KEY = "key"; -const std::string CMD_VALUE_KEY = "value"; -const std::string CMD_ADDR_KEY = "addr"; -const std::string CMD_MASK_KEY = "mask"; -const std::string CMD_TIME_KEY = "time"; -const std::string CMD_BANK_KEY = "bank"; -const std::string CMD_DATA_KEY = "data"; - -// Common default values for pmt::dict_ref -const pmtf::pmt PMT_EMPTYSTR = pmtf::string(""); -const pmtf::pmt PMT_ZERO = pmtf::scalar<int>(0); - -/* - * The private constructor - */ -block_impl::block_impl(int direction, - const std::string& device, - const std::string& type, - size_t nchan, - const std::string& dev_args, - const std::string& stream_args, - const std::vector<std::string>& tune_args, - const std::vector<std::string>& other_settings) - : gr::block("soapy_block"), - d_direction(direction), - d_nchan(nchan), - d_stream_args(stream_args), - d_channels(nchan) -{ - check_abi(); - - // Channel list - std::iota(std::begin(d_channels), std::end(d_channels), 0); - - // Must be 1 or nchan. - if (nchan != tune_args.size() && tune_args.size() != 1) { - throw std::invalid_argument(name() + - ": Wrong number of channels and tune arguments"); - } - - // Must be 1 or nchan. - if (nchan != other_settings.size() && other_settings.size() != 1) { - throw std::invalid_argument(name() + ": Wrong number of channels and settings"); - } - - // Convert type to Soapy type. - if (type == "fc32" || type == SOAPY_SDR_CF32) { - d_soapy_type = SOAPY_SDR_CF32; - } - else if (type == "sc16" || type == SOAPY_SDR_CS16) { - d_soapy_type = SOAPY_SDR_CS16; - } - else if (type == "sc8" || type == SOAPY_SDR_CS8) { - d_soapy_type = SOAPY_SDR_CS8; - } - else { - throw std::invalid_argument(name() + ": Invalid IO type"); - } - - kwargs_t dev_kwargs = SoapySDR::KwargsFromString(device + ", " + dev_args); - d_device = device_ptr_t(SoapySDR::Device::make(dev_kwargs)); - - /* Some of the arguments maybe device settings, so we need to re-apply them */ - arginfo_list_t supported_settings = d_device->getSettingInfo(); - for (const auto& arg : dev_kwargs) { - for (const auto& supported : supported_settings) { - if (supported.key == arg.first) { - d_device->writeSetting(arg.first, arg.second); - } - } - } - - if (d_nchan > d_device->getNumChannels(d_direction)) { - throw std::invalid_argument( - name() + ": Unsupported number of channels. Only " + - std::to_string(d_device->getNumChannels(d_direction)) + - " channels available."); - } - - /* - * Validate stream arguments for all channels - */ - for (const auto& channel : d_channels) { - arginfo_list_t supported_args = d_device->getStreamArgsInfo(d_direction, channel); - kwargs_t stream_kwargs = SoapySDR::KwargsFromString(stream_args); - - for (const auto& arg : stream_kwargs) { - if (!arg_info_has_key(supported_args, arg.first)) { - throw std::invalid_argument(name() + ": Unsupported stream argument " + - arg.first + " for channel " + - std::to_string(channel)); - } - } - } - - /* Validate tuning arguments for each channel */ - for (const auto& channel : d_channels) { - arginfo_list_t supported_args = - d_device->getFrequencyArgsInfo(d_direction, channel); - - /* If single set of args, apply to all channels */ - const size_t arg_idx = tune_args.size() == 1 ? 0 : channel; - kwargs_t tune_kwargs = SoapySDR::KwargsFromString(tune_args[arg_idx]); - - for (const auto& arg : tune_kwargs) { - if (!arg_info_has_key(supported_args, arg.first)) { - throw std::invalid_argument(name() + ": Unsupported tune argument " + - arg.first + " for channel " + - std::to_string(channel)); - } - } - d_tune_args.push_back(tune_kwargs); - } - - /* Validate and apply other settings to each channel */ - for (const auto& channel : d_channels) { - arginfo_list_t supported_settings = - d_device->getSettingInfo(d_direction, channel); - - /* If single set of args, apply to all channels */ - const size_t arg_idx = other_settings.size() == 1 ? 0 : channel; - kwargs_t settings_kwargs = SoapySDR::KwargsFromString(other_settings[arg_idx]); - - /* - * Before applying the setting, make a last check if the setting - * is a valid gain - */ - std::vector<std::string> gain_names = d_device->listGains(d_direction, channel); - for (const auto& gain_name : gain_names) { - SoapySDR::Kwargs::iterator iter = settings_kwargs.find(gain_name); - if (iter != settings_kwargs.end()) { - d_device->setGain( - d_direction, channel, gain_name, std::stod(iter->second)); - /* - * As only valid settings are applied, we remove it so it does not - * recognized as an invalid setting - */ - settings_kwargs.erase(iter); - } - } - - for (const auto& arg : settings_kwargs) { - if (!arg_info_has_key(supported_settings, arg.first)) { - throw std::invalid_argument(name() + ": Unsupported setting " + - arg.first + " for channel " + - std::to_string(channel)); - } - d_device->writeSetting(d_direction, channel, arg.first, arg.second); - } - } - - // message_port_register_in(pmtf::string("cmd")); - // set_msg_handler(pmtf::string("cmd"), - // [this](pmtf::pmt pmt) { this->msg_handler_cmd(pmt); }); - // register_msg_cmd_handler(CMD_FREQ_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_frequency(val, channel); - // }); - // register_msg_cmd_handler(CMD_GAIN_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_gain(val, channel); - // }); - - // register_msg_cmd_handler(CMD_RATE_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_samp_rate(val, channel); - // }); - // register_msg_cmd_handler(CMD_BW_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_bw(val, channel); - // }); - // register_msg_cmd_handler(CMD_ANTENNA_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_antenna(val, channel); - // }); - // register_msg_cmd_handler(CMD_GAINMODE_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_gain_mode(val, channel); - // }); - // register_msg_cmd_handler(CMD_FREQCORR_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_frequency_correction(val, channel); - // }); - // register_msg_cmd_handler(CMD_FREQCORR_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_frequency_correction(val, channel); - // }); - // register_msg_cmd_handler(CMD_DCOFFSETMODE_KEY, - // [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_dc_offset_mode(val, channel); - // }); - // register_msg_cmd_handler(CMD_DCOFFSET_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_dc_offset(val, channel); - // }); - // register_msg_cmd_handler(CMD_IQBAL_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_iq_balance(val, channel); - // }); - // register_msg_cmd_handler(CMD_IQBALMODE_KEY, [this](pmtf::pmt val, size_t channel) - // { - // this->cmd_handler_iq_balance_mode(val, channel); - // }); - // register_msg_cmd_handler(CMD_MCR_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_master_clock_rate(val, channel); - // }); - // register_msg_cmd_handler(CMD_REFCLOCKRATE_KEY, - // [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_reference_clock_rate(val, channel); - // }); - // register_msg_cmd_handler(CMD_CLOCKSRC_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_clock_source(val, channel); - // }); - // register_msg_cmd_handler(CMD_TIMESRC_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_time_source(val, channel); - // }); - // register_msg_cmd_handler(CMD_HWTIME_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_hardware_time(val, channel); - // }); - // register_msg_cmd_handler(CMD_REG_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_register(val, channel); - // }); - // register_msg_cmd_handler(CMD_REGS_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_registers(val, channel); - // }); - // register_msg_cmd_handler(CMD_SETTING_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_setting(val, channel); - // }); - // register_msg_cmd_handler(CMD_GPIO_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_gpio(val, channel); - // }); - // register_msg_cmd_handler(CMD_GPIODIR_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_gpio_dir(val, channel); - // }); - // register_msg_cmd_handler(CMD_I2C_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_i2c(val, channel); - // }); - // register_msg_cmd_handler(CMD_UART_KEY, [this](pmtf::pmt val, size_t channel) { - // this->cmd_handler_uart(val, channel); - // }); -} - -bool block_impl::start() -{ - std::lock_guard<std::mutex> l(d_device_mutex); - - d_stream = d_device->setupStream( - d_direction, d_soapy_type, d_channels, SoapySDR::KwargsFromString(d_stream_args)); - d_mtu = d_device->getStreamMTU(d_stream); - - // /* This limits each work invocation to MTU transfers */ - // if (d_mtu > 0) { - // set_max_noutput_items(d_mtu); - // } else { - // set_max_noutput_items(1024); - // } - - d_device->activateStream(d_stream); - - return true; -} - -bool block_impl::stop() -{ - if (d_stream) { - std::lock_guard<std::mutex> l(d_device_mutex); - d_device->closeStream(d_stream); - d_stream = nullptr; - } - - return true; -} - -block_impl::~block_impl() {} - -void block_impl::register_msg_cmd_handler(const pmtf::pmt& cmd, cmd_handler_t handler) -{ - // d_cmd_handlers[cmd] = handler; -} - -void block_impl::validate_channel(size_t channel) const -{ - if (channel >= d_nchan) { - throw std::invalid_argument(name() + ": Channel " + std::to_string(channel) + - " is not activated."); - } -} - -std::string block_impl::get_driver_key() const { return d_device->getDriverKey(); } - -std::string block_impl::get_hardware_key() const { return d_device->getHardwareKey(); } - -kwargs_t block_impl::get_hardware_info() const { return d_device->getHardwareInfo(); } - -void block_impl::set_frontend_mapping(const std::string& mapping) -{ - d_device->setFrontendMapping(d_direction, mapping); -} - -std::string block_impl::get_frontend_mapping() const -{ - return d_device->getFrontendMapping(d_direction); -} - -kwargs_t block_impl::get_channel_info(size_t channel) const -{ - validate_channel(channel); - return d_device->getChannelInfo(d_direction, channel); -} - -void block_impl::set_sample_rate(size_t channel, double sample_rate) -{ - validate_channel(channel); - - range_list_t sps_range = d_device->getSampleRateRange(d_direction, channel); - - if (!value_in_ranges(sps_range, sample_rate)) { - std::string msg = name() + ": Unsupported sample rate (" + - std::to_string(sample_rate) + "). Rate must be in the range "; - msg += ranges_to_string(sps_range); - - throw std::invalid_argument(msg); - } - - d_device->setSampleRate(d_direction, channel, sample_rate); -} - -double block_impl::get_sample_rate(size_t channel) const -{ - validate_channel(channel); - return d_device->getSampleRate(d_direction, channel); -} - -range_list_t block_impl::get_sample_rate_range(size_t channel) const -{ - validate_channel(channel); - return d_device->getSampleRateRange(d_direction, channel); -} - -void block_impl::set_frequency(size_t channel, double frequency) -{ - validate_channel(channel); - d_device->setFrequency(d_direction, channel, frequency, d_tune_args[channel]); -} - -void block_impl::set_frequency(size_t channel, const std::string& name, double frequency) -{ - validate_channel(channel); - std::vector<std::string> freqs = d_device->listFrequencies(d_direction, channel); - - // Set frequency for specified element, silently ignoring a non-existant - // element if frequency is zero. - if (vector_contains(freqs, name)) { - d_device->setFrequency(d_direction, channel, name, frequency); - } - else if (std::fpclassify(std::abs(frequency)) != FP_ZERO) { - throw std::invalid_argument( - this->name() + ": Channel " + std::to_string(channel) + - " does not support frequency " + name + - ". Consider setting this frequency to 0 to bypass this error"); - } -} - -double block_impl::get_frequency(size_t channel) const -{ - validate_channel(channel); - return d_device->getFrequency(d_direction, channel); -} - -double block_impl::get_frequency(size_t channel, const std::string& name) const -{ - validate_channel(channel); - return d_device->getFrequency(d_direction, channel, name); -} - -std::vector<std::string> block_impl::list_frequencies(size_t channel) const -{ - validate_channel(channel); - return d_device->listFrequencies(d_direction, channel); -} - -range_list_t block_impl::get_frequency_range(size_t channel) const -{ - validate_channel(channel); - return d_device->getFrequencyRange(d_direction, channel); -} - -range_list_t block_impl::get_frequency_range(size_t channel, - const std::string& name) const -{ - validate_channel(channel); - return d_device->getFrequencyRange(d_direction, channel, name); -} - -arginfo_list_t block_impl::get_frequency_args_info(size_t channel) const -{ - validate_channel(channel); - return d_device->getFrequencyArgsInfo(d_direction, channel); -} - -void block_impl::set_bandwidth(size_t channel, double bandwidth) -{ - validate_channel(channel); - d_device->setBandwidth(d_direction, channel, bandwidth); -} - -double block_impl::get_bandwidth(size_t channel) const -{ - validate_channel(channel); - return d_device->getBandwidth(d_direction, channel); -} - -range_list_t block_impl::get_bandwidth_range(size_t channel) const -{ - validate_channel(channel); - return d_device->getBandwidthRange(d_direction, channel); -} - -std::vector<std::string> block_impl::list_antennas(int channel) const -{ - validate_channel(channel); - return d_device->listAntennas(d_direction, channel); -} - -void block_impl::set_antenna(const size_t channel, const std::string& name) -{ - validate_channel(channel); - std::vector<std::string> antennas = d_device->listAntennas(d_direction, channel); - - // Ignore call if there are no antennas. - if (antennas.empty()) { - return; - } - - if (!vector_contains(antennas, name)) { - std::string msg = this->name() + ": Antenna " + name + " at channel " + - std::to_string(channel) + " is not supported. " + - "Available antennas are: "; - msg += string_vector_to_string(antennas); - - throw std::invalid_argument(msg); - } - - d_device->setAntenna(d_direction, channel, name); -} - -std::string block_impl::get_antenna(size_t channel) const -{ - validate_channel(channel); - return d_device->getAntenna(d_direction, channel); -} - -bool block_impl::has_gain_mode(size_t channel) const -{ - validate_channel(channel); - return d_device->hasGainMode(d_direction, channel); -} - -void block_impl::set_gain_mode(size_t channel, bool enable) -{ - validate_channel(channel); - // TODO: ignoring error if disabling AGC ... is this a good idea? - if (!has_gain_mode(channel) && enable) { - throw std::invalid_argument(name() + ": Channel " + std::to_string(channel) + - " does not support AGC"); - } - d_device->setGainMode(d_direction, channel, enable); -} - -bool block_impl::get_gain_mode(size_t channel) const -{ - validate_channel(channel); - return d_device->getGainMode(d_direction, channel); -} - -std::vector<std::string> block_impl::list_gains(size_t channel) const -{ - validate_channel(channel); - return d_device->listGains(d_direction, channel); -} - -void block_impl::set_gain(size_t channel, double gain) -{ - validate_channel(channel); - range_t rGain = d_device->getGainRange(d_direction, channel); - - if (!value_in_range(rGain, gain)) { - d_debug_logger->error( - "Gain out of range: {} <= gain <= {}", rGain.minimum(), rGain.maximum()); - return; - } - - d_device->setGain(d_direction, channel, gain); -} - -void block_impl::set_gain(size_t channel, const std::string& name, double gain) -{ - validate_channel(channel); - - /* Validate gain name */ - std::vector<std::string> gains = d_device->listGains(d_direction, channel); - if (!vector_contains(gains, name)) { - throw std::invalid_argument(this->name() + ": Unknown gain " + name + - " for channel " + std::to_string(channel)); - } - - /* Validate gain value */ - range_t rGain = d_device->getGainRange(d_direction, channel, name); - if (!value_in_range(rGain, gain)) { - d_debug_logger->error("Gain {} out of range: {} <= gain <= {}", - name, - rGain.minimum(), - rGain.maximum()); - } - - d_device->setGain(d_direction, channel, name, gain); -} - -double block_impl::get_gain(size_t channel) const -{ - validate_channel(channel); - return d_device->getGain(d_direction, channel); -} - -double block_impl::get_gain(size_t channel, const std::string& name) const -{ - validate_channel(channel); - return d_device->getGain(d_direction, channel, name); -} - -range_t block_impl::get_gain_range(size_t channel) const -{ - validate_channel(channel); - return d_device->getGainRange(d_direction, channel); -} - -range_t block_impl::get_gain_range(size_t channel, const std::string& name) const -{ - validate_channel(channel); - return d_device->getGainRange(d_direction, channel, name); -} - -bool block_impl::has_frequency_correction(size_t channel) const -{ - validate_channel(channel); - return d_device->hasFrequencyCorrection(d_direction, channel); -} - -void block_impl::set_frequency_correction(size_t channel, double freq_correction) -{ - validate_channel(channel); - - // Set frequency correction, ignoring missing functionality if correction - // is zero. - if (has_frequency_correction(channel)) { - d_device->setFrequencyCorrection(d_direction, channel, freq_correction); - } - else if (std::fpclassify(std::abs(freq_correction)) != FP_ZERO) { - throw std::invalid_argument(this->name() + ": Channel " + - std::to_string(channel) + - " does not support frequency correction setting"); - } -} - -double block_impl::get_frequency_correction(size_t channel) const -{ - validate_channel(channel); - return d_device->getFrequencyCorrection(d_direction, channel); -} - -bool block_impl::has_dc_offset_mode(size_t channel) const -{ - validate_channel(channel); - return d_device->hasDCOffsetMode(d_direction, channel); -} - -void block_impl::set_dc_offset_mode(size_t channel, bool automatic) -{ - validate_channel(channel); - - // TODO: ignoring error if disabling automatic ... is this a good idea? - if (!has_dc_offset_mode(channel) && automatic) { - throw std::invalid_argument(this->name() + ": Channel " + - std::to_string(channel) + - " does not support automatic DC removal setting"); - } - d_device->setDCOffsetMode(d_direction, channel, automatic); -} - -bool block_impl::get_dc_offset_mode(size_t channel) const -{ - validate_channel(channel); - return d_device->getDCOffsetMode(d_direction, channel); -} - -bool block_impl::has_dc_offset(size_t channel) const -{ - validate_channel(channel); - return d_device->hasDCOffset(d_direction, channel); -} - -void block_impl::set_dc_offset(size_t channel, const gr_complexd& dc_offset) -{ - validate_channel(channel); - - const bool supported = has_dc_offset(channel); - /* - * In case of 0 DC offset, the method exits to avoid failing in case of the - * device does not supports DC offset - */ - if (std::fpclassify(std::norm(dc_offset)) == FP_ZERO) { - if (supported && !d_device->getDCOffsetMode(d_direction, channel)) { - d_device->setDCOffset(d_direction, channel, dc_offset); - } - return; - } - - if (!supported) { - throw std::invalid_argument(this->name() + ": Channel " + - std::to_string(channel) + - " does not support DC offset setting"); - } - d_device->setDCOffset(d_direction, channel, dc_offset); -} - -gr_complexd block_impl::get_dc_offset(size_t channel) const -{ - validate_channel(channel); - return d_device->getDCOffset(d_direction, channel); -} - -bool block_impl::has_iq_balance(size_t channel) const -{ - validate_channel(channel); - return d_device->hasIQBalance(d_direction, channel); -} - -void block_impl::set_iq_balance(size_t channel, const gr_complexd& iq_balance) -{ - validate_channel(channel); - - const bool supported = has_iq_balance(channel); - /* - * In case of 0 frequency correction, the method exits to avoid failing - * in case of the device does not supports DC offset - */ - if (std::fpclassify(std::norm(iq_balance)) == FP_ZERO) { - if (supported) { - d_device->setIQBalance(d_direction, channel, iq_balance); - } - return; - } - - if (!supported) { - throw std::invalid_argument(this->name() + ": Channel " + - std::to_string(channel) + - " does not support IQ imbalance correction setting"); - } - d_device->setIQBalance(d_direction, channel, iq_balance); -} - -gr_complexd block_impl::get_iq_balance(size_t channel) const -{ - validate_channel(channel); - return d_device->getIQBalance(d_direction, channel); -} - -bool block_impl::has_iq_balance_mode(size_t channel) const -{ - validate_channel(channel); - -#ifdef SOAPY_SDR_API_HAS_IQ_BALANCE_MODE - return d_device->hasIQBalanceMode(d_direction, channel); -#else - (void)channel; - throw std::runtime_error( - "Automatic IQ imbalance correction API not implemented in this version"); -#endif -} - -void block_impl::set_iq_balance_mode(size_t channel, bool automatic) -{ - validate_channel(channel); - -#ifdef SOAPY_SDR_API_HAS_IQ_BALANCE_MODE - if (!has_iq_balance_mode(channel)) { - throw std::invalid_argument( - this->name() + ": Channel " + std::to_string(channel) + - " does not support automatic IQ imbalance correction"); - } - d_device->setIQBalanceMode(d_direction, channel, automatic); -#else - (void)channel; - (void)automatic; - throw std::runtime_error( - "Automatic IQ imbalance correction API not implemented in this version"); -#endif -} - -bool block_impl::get_iq_balance_mode(size_t channel) const -{ - validate_channel(channel); - -#ifdef SOAPY_SDR_API_HAS_IQ_BALANCE_MODE - if (!has_iq_balance_mode(channel)) { - throw std::invalid_argument( - this->name() + ": Channel " + std::to_string(channel) + - " does not support automatic IQ imbalance correction"); - } - return d_device->getIQBalanceMode(d_direction, channel); -#else - (void)channel; - throw std::runtime_error( - "Automatic IQ imbalance correction API not implemented in this version"); -#endif -} - -void block_impl::set_master_clock_rate(double clock_rate) -{ - const auto clock_rates = d_device->getMasterClockRates(); - - if (!value_in_ranges(clock_rates, clock_rate)) { - std::string msg = "Unsupported clock rate ("; - msg += std::to_string(clock_rate); - msg += "). Clock rate must be in the range "; - msg += ranges_to_string(clock_rates); - - throw std::invalid_argument(msg); - } - d_device->setMasterClockRate(clock_rate); -} - -double block_impl::get_master_clock_rate() const -{ - return d_device->getMasterClockRate(); -} - -range_list_t block_impl::get_master_clock_rates() const -{ - return d_device->getMasterClockRates(); -} - -void block_impl::set_reference_clock_rate(double clock_rate) -{ -#ifdef SOAPY_SDR_API_HAS_REF_CLOCK_RATE_API - const auto clock_rates = d_device->getReferenceClockRates(); - - if (!value_in_ranges(clock_rates, clock_rate)) { - std::string msg = "Unsupported clock rate ("; - msg += std::to_string(clock_rate); - msg += "). Clock rate must be in the range "; - msg += ranges_to_string(clock_rates); - - throw std::invalid_argument(msg); - } - d_device->setReferenceClockRate(clock_rate); -#else - (void)clock_rate; - throw std::runtime_error("Reference clock API not implemented in this version"); -#endif -} - -double block_impl::get_reference_clock_rate() const -{ -#ifdef SOAPY_SDR_API_HAS_REF_CLOCK_RATE_API - return d_device->getReferenceClockRate(); -#else - throw std::runtime_error("Reference clock API not implemented in this version"); -#endif -} - -range_list_t block_impl::get_reference_clock_rates() const -{ -#ifdef SOAPY_SDR_API_HAS_REF_CLOCK_RATE_API - return d_device->getReferenceClockRates(); -#else - throw std::runtime_error("Reference clock API not implemented in this version"); -#endif -} - -std::vector<std::string> block_impl::list_time_sources() const -{ - return d_device->listTimeSources(); -} - -void block_impl::set_time_source(const std::string& time_source) -{ - const auto time_sources = d_device->listTimeSources(); - - if (!vector_contains(time_sources, time_source)) { - std::string msg = "Invalid time source (" + time_source + ")."; - msg += "Valid time sources: "; - msg += string_vector_to_string(time_sources); - - throw std::invalid_argument(msg); - } - - d_device->setTimeSource(time_source); -} - -std::string block_impl::get_time_source() const { return d_device->getTimeSource(); } - -std::vector<std::string> block_impl::list_clock_sources() const -{ - return d_device->listClockSources(); -} - -void block_impl::set_clock_source(const std::string& clock_source) -{ - const auto clock_sources = d_device->listClockSources(); - - if (!vector_contains(clock_sources, clock_source)) { - std::string msg = "Invalid clock source (" + clock_source + ")."; - msg += "Valid clock sources: "; - msg += string_vector_to_string(clock_sources); - - throw std::invalid_argument(msg); - } - - d_device->setClockSource(clock_source); -} - -std::string block_impl::get_clock_source() const { return d_device->getClockSource(); } - -bool block_impl::has_hardware_time(const std::string& what) const -{ - return d_device->hasHardwareTime(what); -} - -long long block_impl::get_hardware_time(const std::string& what) const -{ - if (!has_hardware_time(what)) { - std::string msg = - this->name() + ": device does not support querying hardware time"; - if (!what.empty()) { - msg += " ("; - msg += what; - msg += ")"; - } - - throw std::invalid_argument(msg); - } - return d_device->getHardwareTime(what); -} - -void block_impl::set_hardware_time(long long timeNs, const std::string& what) -{ - if (!has_hardware_time(what)) { - std::string msg = - this->name() + ": device does not support querying hardware time"; - if (!what.empty()) { - msg += " (" + what + ")"; - } - - throw std::invalid_argument(msg); - } - d_device->setHardwareTime(timeNs, what); -} - -std::vector<std::string> block_impl::list_sensors() const -{ - return d_device->listSensors(); -} - -arginfo_t block_impl::get_sensor_info(const std::string& key) const -{ - const auto sensors = d_device->listSensors(); - - if (vector_contains(sensors, key)) { - return d_device->getSensorInfo(key); - } - else { - throw std::invalid_argument("Invalid sensor: " + key); - } -} - -std::string block_impl::read_sensor(const std::string& key) const -{ - const auto sensors = d_device->listSensors(); - - if (vector_contains(sensors, key)) { - return d_device->readSensor(key); - } - else { - throw std::invalid_argument("Invalid sensor: " + key); - } -} - -std::vector<std::string> block_impl::list_sensors(size_t channel) const -{ - validate_channel(channel); - return d_device->listSensors(d_direction, channel); -} - -arginfo_t block_impl::get_sensor_info(size_t channel, const std::string& key) const -{ - validate_channel(channel); - const auto sensors = d_device->listSensors(d_direction, channel); - - if (vector_contains(sensors, key)) { - return d_device->getSensorInfo(d_direction, channel, key); - } - else { - throw std::invalid_argument("Invalid sensor: " + key); - } -} - -std::string block_impl::read_sensor(size_t channel, const std::string& key) const -{ - validate_channel(channel); - const auto sensors = d_device->listSensors(d_direction, channel); - - if (vector_contains(sensors, key)) { - return d_device->readSensor(d_direction, channel, key); - } - else { - throw std::invalid_argument("Invalid sensor: " + key); - } -} - -std::vector<std::string> block_impl::list_register_interfaces() const -{ - return d_device->listRegisterInterfaces(); -} - -void block_impl::write_register(const std::string& name, unsigned addr, unsigned value) -{ - const auto register_interfaces = list_register_interfaces(); - if (!vector_contains(register_interfaces, name)) { - throw std::invalid_argument(this->name() + ": invalid register interface (" + - name + ")"); - } - d_device->writeRegister(name, addr, value); -} - -unsigned block_impl::read_register(const std::string& name, unsigned addr) const -{ - const auto register_interfaces = list_register_interfaces(); - if (!vector_contains(register_interfaces, name)) { - throw std::invalid_argument(this->name() + ": invalid register interface (" + - name + ")"); - } - return d_device->readRegister(name, addr); -} - -void block_impl::write_registers(const std::string& name, - unsigned addr, - const std::vector<unsigned>& value) -{ - const auto register_interfaces = list_register_interfaces(); - if (!vector_contains(register_interfaces, name)) { - throw std::invalid_argument(this->name() + ": invalid register interface (" + - name + ")"); - } - d_device->writeRegisters(name, addr, value); -} - -std::vector<unsigned> -block_impl::read_registers(const std::string& name, unsigned addr, size_t length) const -{ - const auto register_interfaces = list_register_interfaces(); - if (!vector_contains(register_interfaces, name)) { - throw std::invalid_argument(this->name() + ": invalid register interface (" + - name + ")"); - } - return d_device->readRegisters(name, addr, length); -} - -arginfo_list_t block_impl::get_setting_info() const { return d_device->getSettingInfo(); } - -void block_impl::write_setting(const std::string& key, const std::string& value) -{ - const auto setting_info = d_device->getSettingInfo(); - - if (arg_info_has_key(setting_info, key)) { - d_device->writeSetting(key, value); - } - else { - throw std::invalid_argument("Invalid setting: " + key); - } -} - -std::string block_impl::read_setting(const std::string& key) const -{ - const auto setting_info = d_device->getSettingInfo(); - - if (arg_info_has_key(setting_info, key)) { - return d_device->readSetting(key); - } - else { - throw std::invalid_argument("Invalid setting: " + key); - } -} - -arginfo_list_t block_impl::get_setting_info(size_t channel) const -{ - validate_channel(channel); - return d_device->getSettingInfo(d_direction, channel); -} - -void block_impl::write_setting(size_t channel, - const std::string& key, - const std::string& value) -{ - validate_channel(channel); - const auto setting_info = d_device->getSettingInfo(d_direction, channel); - - if (arg_info_has_key(setting_info, key)) { - d_device->writeSetting(d_direction, channel, key, value); - } - else { - throw std::invalid_argument("Invalid setting: " + key); - } -} - -std::string block_impl::read_setting(size_t channel, const std::string& key) const -{ - validate_channel(channel); - const auto setting_info = d_device->getSettingInfo(d_direction, channel); - - if (arg_info_has_key(setting_info, key)) { - return d_device->readSetting(d_direction, channel, key); - } - else { - throw std::invalid_argument("Invalid setting: " + key); - } -} - -std::vector<std::string> block_impl::list_gpio_banks() const -{ - return d_device->listGPIOBanks(); -} - -void block_impl::write_gpio(const std::string& bank, unsigned value) -{ - const auto gpio_banks = list_gpio_banks(); - if (!vector_contains(gpio_banks, bank)) { - throw std::invalid_argument(this->name() + ": invalid GPIO bank (" + bank + ")"); - } - d_device->writeGPIO(bank, value); -} - -void block_impl::write_gpio(const std::string& bank, unsigned value, unsigned mask) -{ - const auto gpio_banks = list_gpio_banks(); - if (!vector_contains(gpio_banks, bank)) { - throw std::invalid_argument(this->name() + ": invalid GPIO bank (" + bank + ")"); - } - d_device->writeGPIO(bank, value, mask); -} - -unsigned block_impl::read_gpio(const std::string& bank) const -{ - const auto gpio_banks = list_gpio_banks(); - - if (!vector_contains(gpio_banks, bank)) { - throw std::invalid_argument(this->name() + ": invalid GPIO bank (" + bank + ")"); - } - return d_device->readGPIO(bank); -} - -void block_impl::write_gpio_dir(const std::string& bank, unsigned dir) -{ - const auto gpio_banks = list_gpio_banks(); - if (!vector_contains(gpio_banks, bank)) { - throw std::invalid_argument(this->name() + ": invalid GPIO bank (" + bank + ")"); - } - d_device->writeGPIODir(bank, dir); -} - -void block_impl::write_gpio_dir(const std::string& bank, unsigned dir, unsigned mask) -{ - const auto gpio_banks = list_gpio_banks(); - if (!vector_contains(gpio_banks, bank)) { - throw std::invalid_argument(this->name() + ": invalid GPIO bank (" + bank + ")"); - } - d_device->writeGPIODir(bank, dir, mask); -} - -unsigned block_impl::read_gpio_dir(const std::string& bank) const -{ - const auto gpio_banks = list_gpio_banks(); - - if (!vector_contains(gpio_banks, bank)) { - throw std::invalid_argument(this->name() + ": invalid GPIO bank (" + bank + ")"); - } - return d_device->readGPIODir(bank); -} - -void block_impl::write_i2c(int addr, const std::string& data) -{ - d_device->writeI2C(addr, data); -} - -std::string block_impl::read_i2c(int addr, size_t num_bytes) -{ - return d_device->readI2C(addr, num_bytes); -} - -unsigned block_impl::transact_spi(int addr, unsigned data, size_t num_bits) -{ - return d_device->transactSPI(addr, data, num_bits); -} - -std::vector<std::string> block_impl::list_uarts() const { return d_device->listUARTs(); } - -void block_impl::write_uart(const std::string& which, const std::string& data) -{ - const auto uarts = list_uarts(); - - if (!vector_contains(uarts, which)) { - std::string msg = "Invalid UART (" + which + ")."; - msg += "Valid UARTs: "; - msg += string_vector_to_string(uarts); - - throw std::invalid_argument(msg); - } - d_device->writeUART(which, data); -} - -std::string block_impl::read_uart(const std::string& which, long timeout_us) const -{ - const auto uarts = list_uarts(); - - if (!vector_contains(uarts, which)) { - std::string msg = "Invalid UART (" + which + ")."; - msg += "Valid UARTs: "; - msg += string_vector_to_string(uarts); - - throw std::invalid_argument(msg); - } - return d_device->readUART(which, timeout_us); -} - -/* End public API implementation */ - -// void block_impl::cmd_handler_frequency(pmtf::pmt val, size_t channel) -// { -// if (!(val->is_number() && !val->is_complex())) { -// GR_LOG_ERROR(d_debug_logger, "soapy: freq must be float/int"); -// return; -// } -// set_frequency(channel, pmtf::scalar<double>(val)); -// } - -// void block_impl::cmd_handler_gain(pmtf::pmt val, size_t channel) -// { -// // For compatibility, accept either a numeric value for setting the -// // overall gain or a dict with a gain element and element-specific -// // value. -// if (!(val->is_number() && !val->is_complex()) && !val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: gain must be float/int or a dict"); -// return; -// } - -// if (val->is_dict()) { -// if (!pmt::dict_has_key(val, CMD_GAIN_KEY)) { -// GR_LOG_ERROR(d_debug_logger, "soapy: gain dict must contain key \"gain\""); -// return; -// } - -// // Accept no name, falls back to default argument "" -// const auto name = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_NAME_KEY, PMT_EMPTYSTR)); -// const auto gain = pmtf::scalar<double>(pmt::dict_ref(val, CMD_GAIN_KEY, -// PMT_ZERO)); - -// set_gain(channel, name, gain); -// } else { -// set_gain(channel, pmtf::scalar<double>(val)); -// } -// } - -// void block_impl::cmd_handler_samp_rate(pmtf::pmt val, size_t channel) -// { -// if (!(val->is_number() && !val->is_complex())) { -// GR_LOG_ERROR(d_debug_logger, "soapy: rate must be float/int"); -// return; -// } -// set_sample_rate(channel, pmtf::scalar<double>(val)); -// } - -// void block_impl::cmd_handler_bw(pmtf::pmt val, size_t channel) -// { -// if (!(val->is_number() && !val->is_complex())) { -// GR_LOG_ERROR(d_debug_logger, "soapy: bw must be float/int"); -// return; -// } -// set_bandwidth(channel, pmtf::scalar<double>(val)); -// } - -// void block_impl::cmd_handler_antenna(pmtf::pmt val, size_t channel) -// { -// if (!val->is_symbol()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: ant must be string"); -// return; -// } -// set_antenna(channel, pmt::symbol_to_string(val)); -// } - -// void block_impl::cmd_handler_gain_mode(pmtf::pmt val, size_t channel) -// { -// if (!val->is_bool()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: gain mode must be bool"); -// return; -// } -// set_gain_mode(channel, pmt::to_bool(val)); -// } - -// void block_impl::cmd_handler_frequency_correction(pmtf::pmt val, size_t channel) -// { -// if (!(val->is_number() && !val->is_complex())) { -// GR_LOG_ERROR(d_debug_logger, "soapy: frequency correction must be float/int"); -// return; -// } -// set_frequency_correction(channel, pmtf::scalar<double>(val)); -// } - -// void block_impl::cmd_handler_dc_offset_mode(pmtf::pmt val, size_t channel) -// { -// if (!val->is_bool()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: DC offset mode must be bool"); -// return; -// } -// set_dc_offset_mode(channel, pmt::to_bool(val)); -// } - -// void block_impl::cmd_handler_dc_offset(pmtf::pmt val, size_t channel) -// { -// if (!val->is_number()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: DC offset must be numeric"); -// return; -// } -// set_dc_offset(channel, pmt::to_complex(val)); -// } - -// void block_impl::cmd_handler_iq_balance(pmtf::pmt val, size_t channel) -// { -// if (!val->is_number()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: IQ balance must be numeric"); -// return; -// } -// set_iq_balance(channel, pmt::to_complex(val)); -// } - -// void block_impl::cmd_handler_iq_balance_mode(pmtf::pmt val, size_t channel) -// { -// if (!val->is_bool()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: IQ balance mode must be bool"); -// return; -// } -// set_iq_balance_mode(channel, pmt::to_bool(val)); -// } - -// void block_impl::cmd_handler_master_clock_rate(pmtf::pmt val, size_t) -// { -// if (!(val->is_number() && !val->is_complex())) { -// GR_LOG_ERROR(d_debug_logger, "soapy: master clock rate must be float/int"); -// return; -// } -// set_master_clock_rate(pmtf::scalar<double>(val)); -// } - -// void block_impl::cmd_handler_reference_clock_rate(pmtf::pmt val, size_t) -// { -// if (!(val->is_number() && !val->is_complex())) { -// GR_LOG_ERROR(d_debug_logger, "soapy: reference clock rate must be float/int"); -// return; -// } -// set_reference_clock_rate(pmtf::scalar<double>(val)); -// } - -// void block_impl::cmd_handler_clock_source(pmtf::pmt val, size_t) -// { -// if (!val->is_symbol()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: clock source must be string"); -// return; -// } -// set_clock_source(pmt::symbol_to_string(val)); -// } - -// void block_impl::cmd_handler_time_source(pmtf::pmt val, size_t) -// { -// if (!val->is_symbol()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: time source must be string"); -// return; -// } -// set_time_source(pmt::symbol_to_string(val)); -// } - -// void block_impl::cmd_handler_hardware_time(pmtf::pmt val, size_t) -// { -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: hardware time must be a dict"); -// return; -// } - -// if (!pmt::dict_has_key(val, CMD_TIME_KEY)) { -// GR_LOG_ERROR(d_debug_logger, -// "soapy: hardware time dict must contain key \"time\""); -// return; -// } - -// // Accept no name, falls back to default argument "" -// const auto name = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_NAME_KEY, PMT_EMPTYSTR)); -// const auto time = pmt::to_long(pmt::dict_ref(val, CMD_TIME_KEY, PMT_ZERO)); - -// set_hardware_time(static_cast<long long>(time), name); -// } - -// void block_impl::cmd_handler_register(pmtf::pmt val, size_t) -// { -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: register write param must be a dict"); -// return; -// } - -// if (!pmt::dict_has_key(val, CMD_NAME_KEY) || !pmt::dict_has_key(val, CMD_ADDR_KEY) -// || -// !pmt::dict_has_key(val, CMD_VALUE_KEY)) { -// GR_LOG_ERROR( -// d_debug_logger, -// "soapy: register write dict must contain keys \"name\", \"addr\", -// \"value\""); -// return; -// } - -// const auto name = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_NAME_KEY, PMT_EMPTYSTR)); -// const auto addr = pmt::to_uint64(pmt::dict_ref(val, CMD_ADDR_KEY, PMT_ZERO)); -// const auto value = pmt::to_uint64(pmt::dict_ref(val, CMD_VALUE_KEY, PMT_ZERO)); - -// write_register(name, static_cast<unsigned>(addr), static_cast<unsigned>(value)); -// } - -// void block_impl::cmd_handler_registers(pmtf::pmt val, size_t) -// { -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: multi-register write param must be a -// dict"); return; -// } - -// if (!pmt::dict_has_key(val, CMD_NAME_KEY) || !pmt::dict_has_key(val, CMD_ADDR_KEY) -// || -// !pmt::dict_has_key(val, CMD_VALUE_KEY)) { -// GR_LOG_ERROR(d_debug_logger, -// "soapy: multi-register write dict must contain keys \"name\", " -// "\"addr\", \"value\""); -// return; -// } - -// const auto name = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_NAME_KEY, PMT_EMPTYSTR)); -// const auto addr = pmt::to_uint64(pmt::dict_ref(val, CMD_ADDR_KEY, PMT_ZERO)); -// const auto value = pmt::u32vector_elements( -// pmt::dict_ref(val, CMD_VALUE_KEY, pmt::make_u32vector(0, 0))); - -// write_registers(name, static_cast<unsigned>(addr), value); -// } - -// // TODO: any way to call channel-less version? -// void block_impl::cmd_handler_setting(pmtf::pmt val, size_t channel) -// { -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: GPIO must be a dict"); -// return; -// } - -// if (!pmt::dict_has_key(val, CMD_KEY_KEY) || !pmt::dict_has_key(val, CMD_VALUE_KEY)) -// { -// GR_LOG_ERROR(d_debug_logger, "soapy: GPIO must contain keys \"key\", -// \"value\""); return; -// } - -// const auto key = pmt::symbol_to_string(pmt::dict_ref(val, CMD_KEY_KEY, -// PMT_EMPTYSTR)); const auto value_pmt = pmt::dict_ref(val, CMD_VALUE_KEY, -// PMT_EMPTYSTR); - -// std::string value; -// if (pmt::is_bool(val)) { -// write_setting(channel, key, setting_to_string(pmt::to_bool(value_pmt))); -// } else if (pmt::is_number(val)) { -// write_setting(channel, key, -// setting_to_string(pmtf::scalar<double>(value_pmt))); -// } else { -// write_setting(channel, key, pmt::symbol_to_string(value_pmt)); -// } -// } - -// void block_impl::cmd_handler_gpio(pmtf::pmt val, size_t) -// { -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: setting must be a dict"); -// return; -// } - -// if (!pmt::dict_has_key(val, CMD_BANK_KEY) || !pmt::dict_has_key(val, -// CMD_VALUE_KEY)) { -// GR_LOG_ERROR(d_debug_logger, "soapy: GPIO must contain keys \"bank\", -// \"value\""); return; -// } - -// const auto bank = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_BANK_KEY, PMT_EMPTYSTR)); -// const auto value = pmt::to_uint64(pmt::dict_ref(val, CMD_VALUE_KEY, PMT_ZERO)); - -// if (pmt::dict_has_key(val, CMD_MASK_KEY)) { -// const auto mask = pmt::to_uint64(pmt::dict_ref(val, CMD_MASK_KEY, PMT_ZERO)); - -// write_gpio(bank, static_cast<unsigned>(value), static_cast<unsigned>(mask)); -// } else { -// write_gpio(bank, static_cast<unsigned>(value)); -// } -// } - -// void block_impl::cmd_handler_gpio_dir(pmtf::pmt val, size_t) -// { -// static const pmtf::pmt CMD_DIR_KEY = pmtf::string("dir"); - -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: GPIO dir must be a dict"); -// return; -// } - -// if (!pmt::dict_has_key(val, CMD_BANK_KEY) || !pmt::dict_has_key(val, CMD_DIR_KEY)) -// { -// GR_LOG_ERROR(d_debug_logger, -// "soapy: GPIO dir must contain keys \"bank\", \"dir\""); -// return; -// } - -// const auto bank = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_BANK_KEY, PMT_EMPTYSTR)); -// const auto dir = pmt::to_uint64(pmt::dict_ref(val, CMD_DIR_KEY, PMT_ZERO)); - -// if (pmt::dict_has_key(val, CMD_MASK_KEY)) { -// const auto mask = pmt::to_uint64(pmt::dict_ref(val, CMD_MASK_KEY, PMT_ZERO)); - -// write_gpio_dir(bank, static_cast<unsigned>(dir), static_cast<unsigned>(mask)); -// } else { -// write_gpio_dir(bank, static_cast<unsigned>(dir)); -// } -// } - -// void block_impl::cmd_handler_i2c(pmtf::pmt val, size_t) -// { -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: I2C must be a dict"); -// return; -// } - -// if (!pmt::dict_has_key(val, CMD_ADDR_KEY) || !pmt::dict_has_key(val, CMD_DATA_KEY)) -// { -// GR_LOG_ERROR(d_debug_logger, "soapy: I2C must contain keys \"addr\", -// \"data\""); return; -// } - -// const auto addr = pmt::to_long(pmt::dict_ref(val, CMD_ADDR_KEY, PMT_ZERO)); -// const auto data = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_DATA_KEY, PMT_EMPTYSTR)); - -// write_i2c(static_cast<int>(addr), data); -// } - -// void block_impl::cmd_handler_uart(pmtf::pmt val, size_t) -// { -// if (!val->is_dict()) { -// GR_LOG_ERROR(d_debug_logger, "soapy: UART must be a dict"); -// return; -// } - -// if (!pmt::dict_has_key(val, CMD_NAME_KEY) || !pmt::dict_has_key(val, CMD_DATA_KEY)) -// { -// GR_LOG_ERROR(d_debug_logger, "soapy: UART must contain keys \"name\", -// \"data\""); return; -// } - -// const auto name = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_NAME_KEY, PMT_EMPTYSTR)); -// const auto data = -// pmt::symbol_to_string(pmt::dict_ref(val, CMD_DATA_KEY, PMT_EMPTYSTR)); - -// write_uart(name, data); -// } - -// void block_impl::msg_handler_cmd(pmtf::pmt msg) -// { -// const long CHANNEL_ALL = 0x12345678; // arbitrary - -// if (!pmt::is_dict(msg)) { -// GR_LOG_ERROR(d_debug_logger, "soapy: commands must be pmt::dict"); -// return; -// } - -// // Channel not specified means apply to all -// const pmtf::pmt channel_all_pmt = pmt::from_long(CHANNEL_ALL); -// size_t channel = pmt::to_long(pmt::dict_ref(msg, CMD_CHAN_KEY, channel_all_pmt)); - -// if (channel != CHANNEL_ALL && channel >= d_nchan) { -// GR_LOG_ERROR(d_debug_logger, -// "soapy: ignoring command for invalid channel {}", -// channel); -// return; -// } - -// for (size_t i = 0; i < pmt::length(msg); i++) { -// const pmtf::pmt item = pmt::nth(i, msg); -// const pmtf::pmt key = pmt::car(item); -// const pmtf::pmt val = pmt::cdr(item); -// if (key == CMD_CHAN_KEY) { -// continue; -// } - -// // Find command handler -// auto it = d_cmd_handlers.find(key); -// if (it == d_cmd_handlers.end()) { -// GR_LOG_ERROR(d_debug_logger, -// "soapy: ignoring unknown command key '{}'", -// pmt::symbol_to_string(key)); -// continue; -// } -// cmd_handler_t handler = it->second; - -// if (channel != CHANNEL_ALL) { -// std::lock_guard<std::mutex> l(d_device_mutex); -// handler(val, channel); -// } else { -// for (size_t c = 0; c < d_nchan; c++) { -// std::lock_guard<std::mutex> l(d_device_mutex); -// handler(val, c); -// } -// } -// } -// } -} /* namespace soapy */ -} /* namespace gr */ diff --git a/blocklib/soapy/lib/block_impl.h b/blocklib/soapy/lib/block_impl.h deleted file mode 100644 index 8ccd878ad..000000000 --- a/blocklib/soapy/lib/block_impl.h +++ /dev/null @@ -1,294 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Jeff Long - * Copyright 2018-2021 Libre Space Foundation <http://libre.space> - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include <mutex> - -#include <gnuradio/soapy/block.h> - -#include <SoapySDR/Device.hpp> -#include <SoapySDR/Modules.hpp> -#include <SoapySDR/Registry.hpp> -#include <SoapySDR/Version.hpp> - -namespace gr { -namespace soapy { - -using cmd_handler_t = std::function<void(pmtf::pmt, size_t)>; -struct device_deleter { - void operator()(SoapySDR::Device* d) { SoapySDR::Device::unmake(d); } -}; -using device_ptr_t = std::unique_ptr<SoapySDR::Device, device_deleter>; - -/*! - * \brief Base block implementation for SDR devices. - */ - -class block_impl : virtual public block -{ -private: - const int d_direction; - const std::string d_dev_str; - const std::string d_args; - - size_t d_nchan; - std::string d_stream_args; - std::vector<size_t> d_channels; - std::string d_soapy_type; - std::map<pmtf::pmt, cmd_handler_t> d_cmd_handlers; - kwargs_list_t d_tune_args; - - void register_msg_cmd_handler(const pmtf::pmt& cmd, cmd_handler_t handler); - - /*! - * \brief Raise std::invalid_argument if channel is invalid - */ - void validate_channel(size_t channel) const; - -protected: - size_t d_mtu = 0; - - block_impl(int direction, - const std::string& device, - const std::string& type, - size_t nchan, - const std::string& dev_args, - const std::string& stream_args, - const std::vector<std::string>& tune_args, - const std::vector<std::string>& other_settings); - block_impl(const block_impl&) = delete; - block_impl(block_impl&&) = delete; - block_impl& operator=(const block_impl&) = delete; - block_impl& operator=(block_impl&&) = delete; - ~block_impl() override; - - std::mutex d_device_mutex; - device_ptr_t d_device; - SoapySDR::Stream* d_stream = nullptr; - - // static io_signature::sptr args_to_io_sig(const std::string& type, size_t nchan) - // { - // size_t size = 0; - // if (type == "fc32") { - // size = 8; - // } else if (type == "sc16") { - // size = 4; - // } else if (type == "sc8") { - // size = 2; - // } else { - // size = 1; /* TODO: this is an error */ - // } - // return io_signature::make(nchan, nchan, size); - // } - -public: - bool start() override; - bool stop() override; - - /*** Begin public API implementation ***/ - - std::string get_driver_key() const override; - std::string get_hardware_key() const override; - kwargs_t get_hardware_info() const override; - - void set_frontend_mapping(const std::string& frontend_mapping) override; - std::string get_frontend_mapping() const override; - - kwargs_t get_channel_info(size_t channel) const override; - - void set_sample_rate(size_t channel, double sample_rate) override; - double get_sample_rate(size_t channel) const override; - range_list_t get_sample_rate_range(size_t channel) const override; - - void set_frequency(size_t channel, double frequency) override; - void - set_frequency(size_t channel, const std::string& name, double frequency) override; - double get_frequency(size_t channel) const override; - double get_frequency(size_t channel, const std::string& name) const override; - std::vector<std::string> list_frequencies(size_t channel) const override; - range_list_t get_frequency_range(size_t channel) const override; - range_list_t get_frequency_range(size_t channel, - const std::string& name) const override; - arginfo_list_t get_frequency_args_info(size_t channel) const override; - - void set_bandwidth(size_t channel, double bandwidth) override; - double get_bandwidth(size_t channel) const override; - range_list_t get_bandwidth_range(size_t channel) const override; - - std::vector<std::string> list_antennas(int channel) const override; - void set_antenna(size_t channel, const std::string& name) override; - std::string get_antenna(size_t channel) const override; - - bool has_gain_mode(size_t channel) const override; - void set_gain_mode(size_t channel, bool enable) override; - bool get_gain_mode(size_t channel) const override; - - std::vector<std::string> list_gains(size_t channel) const override; - void set_gain(size_t channel, double gain) override; - void set_gain(size_t channel, const std::string& name, double gain) override; - double get_gain(size_t channel) const override; - double get_gain(size_t channel, const std::string& name) const override; - range_t get_gain_range(size_t channel) const override; - range_t get_gain_range(size_t channel, const std::string& name) const override; - - bool has_frequency_correction(size_t channel) const override; - void set_frequency_correction(size_t channel, double freq_correction) override; - double get_frequency_correction(size_t channel) const override; - - bool has_dc_offset_mode(size_t channel) const override; - void set_dc_offset_mode(size_t channel, bool automatic) override; - bool get_dc_offset_mode(size_t channel) const override; - - bool has_dc_offset(size_t channel) const override; - void set_dc_offset(size_t channel, const gr_complexd& dc_offset) override; - gr_complexd get_dc_offset(size_t channel) const override; - - bool has_iq_balance(size_t channel) const override; - void set_iq_balance(size_t channel, const gr_complexd& iq_balance) override; - gr_complexd get_iq_balance(size_t channel) const override; - - bool has_iq_balance_mode(size_t channel) const override; - void set_iq_balance_mode(size_t channel, bool automatic) override; - bool get_iq_balance_mode(size_t channel) const override; - - void set_master_clock_rate(double clock_rate) override; - double get_master_clock_rate() const override; - range_list_t get_master_clock_rates() const override; - - void set_reference_clock_rate(double rate) override; - double get_reference_clock_rate() const override; - range_list_t get_reference_clock_rates() const override; - - std::vector<std::string> list_clock_sources() const override; - void set_clock_source(const std::string& clock_source) override; - std::string get_clock_source() const override; - - std::vector<std::string> list_time_sources() const override; - void set_time_source(const std::string& source) override; - std::string get_time_source() const override; - bool has_hardware_time(const std::string& what) const override; - long long get_hardware_time(const std::string& what) const override; - void set_hardware_time(long long timeNs, const std::string& what) override; - - std::vector<std::string> list_sensors() const override; - arginfo_t get_sensor_info(const std::string& key) const override; - std::string read_sensor(const std::string& key) const override; - std::vector<std::string> list_sensors(size_t channel) const override; - arginfo_t get_sensor_info(size_t channel, const std::string& key) const override; - std::string read_sensor(size_t channel, const std::string& key) const override; - - std::vector<std::string> list_register_interfaces() const override; - void write_register(const std::string& name, unsigned addr, unsigned value) override; - unsigned read_register(const std::string& name, unsigned addr) const override; - void write_registers(const std::string& name, - unsigned addr, - const std::vector<unsigned>& value) override; - std::vector<unsigned> - read_registers(const std::string& name, unsigned addr, size_t length) const override; - - arginfo_list_t get_setting_info() const override; - void write_setting(const std::string& key, const std::string& value) override; - std::string read_setting(const std::string& key) const override; - arginfo_list_t get_setting_info(size_t channel) const override; - void write_setting(size_t channel, - const std::string& key, - const std::string& value) override; - std::string read_setting(size_t channel, const std::string& key) const override; - - std::vector<std::string> list_gpio_banks() const override; - void write_gpio(const std::string& bank, unsigned value) override; - void write_gpio(const std::string& bank, unsigned value, unsigned mask) override; - unsigned read_gpio(const std::string& bank) const override; - void write_gpio_dir(const std::string& bank, unsigned dir) override; - void write_gpio_dir(const std::string& bank, unsigned dir, unsigned mask) override; - unsigned read_gpio_dir(const std::string& bank) const override; - - void write_i2c(int addr, const std::string& data) override; - std::string read_i2c(int addr, size_t num_bytes) override; - - unsigned transact_spi(int addr, unsigned data, size_t num_bits) override; - - std::vector<std::string> list_uarts() const override; - void write_uart(const std::string& which, const std::string& data) override; - std::string read_uart(const std::string& which, long timeout_us) const override; - - /*** End public API implementation ***/ - -protected: - /*** Begin message handlers ***/ - - // /*! - // * Calls the correct message handler according to the received message symbol. - // * A dictionary with key the handler name is used in order to call the - // * corresponding handler. - // * \param msg a PMT dictionary - // */ - // void msg_handler_cmd(pmtf::pmt msg); - - // /*! - // * Set the center frequency of the RX chain. - // * @param val center frequency in Hz - // * @param channel an available channel on the device - // */ - // void cmd_handler_frequency(pmtf::pmt val, size_t channel); - - // /*! - // * Set the overall gain for the specified chain. - // * The gain will be distributed automatically across available - // * elements according to Soapy API. - // * @param val the new amplification value in dB - // * @param channel an avalaible channel on the device - // */ - // void cmd_handler_gain(pmtf::pmt val, size_t channel); - - // /*! - // * Set the baseband sample rate for the RX chain. - // * @param val the sample rate samples per second - // * @param channel an available channel on the device - // */ - // void cmd_handler_samp_rate(pmtf::pmt val, size_t channel); - - // /*! - // * Set the baseband filter width for the RX chain. - // * @param val baseband filter width in Hz - // * @param channel an available channel on the device - // */ - // void cmd_handler_bw(pmtf::pmt val, size_t channel); - - // /*! - // * Set the anntena element for the RX chain. - // * @param val name of the anntena - // * @param channel an available channel on the device - // */ - // void cmd_handler_antenna(pmtf::pmt val, size_t channel); - - // void cmd_handler_gain_mode(pmtf::pmt val, size_t channel); - // void cmd_handler_frequency_correction(pmtf::pmt val, size_t channel); - // void cmd_handler_dc_offset_mode(pmtf::pmt val, size_t channel); - // void cmd_handler_dc_offset(pmtf::pmt val, size_t channel); - // void cmd_handler_iq_balance(pmtf::pmt val, size_t channel); - // void cmd_handler_iq_balance_mode(pmtf::pmt val, size_t channel); - // void cmd_handler_master_clock_rate(pmtf::pmt val, size_t); - // void cmd_handler_reference_clock_rate(pmtf::pmt val, size_t); - // void cmd_handler_clock_source(pmtf::pmt val, size_t); - // void cmd_handler_time_source(pmtf::pmt val, size_t); - // void cmd_handler_hardware_time(pmtf::pmt val, size_t); - // void cmd_handler_register(pmtf::pmt val, size_t); - // void cmd_handler_registers(pmtf::pmt val, size_t); - // void cmd_handler_setting(pmtf::pmt val, size_t channel); - // void cmd_handler_gpio(pmtf::pmt val, size_t); - // void cmd_handler_gpio_dir(pmtf::pmt val, size_t); - // void cmd_handler_i2c(pmtf::pmt val, size_t); - // void cmd_handler_uart(pmtf::pmt val, size_t); - - /*** End message handlers ***/ -}; - -} // namespace soapy -} // namespace gr diff --git a/blocklib/soapy/lib/meson.build b/blocklib/soapy/lib/meson.build deleted file mode 100644 index 1888e6cb0..000000000 --- a/blocklib/soapy/lib/meson.build +++ /dev/null @@ -1,40 +0,0 @@ -soapy_sources += ['block_impl.cc'] - -soapysdr_dep = dependency('SoapySDR', version : '>=0.7', required : true) - -soapy_deps += [gnuradio_gr_dep, soapysdr_dep, volk_dep, fmt_dep, pmtf_dep] - -block_cpp_args = ['-DHAVE_CPU'] - -incdir = include_directories(['../include/gnuradio/soapy','../include']) -gnuradio_blocklib_soapy_lib = library('gnuradio-blocklib-soapy', - soapy_sources, - include_directories : incdir, - install : true, - link_language: 'cpp', - dependencies : soapy_deps, - cpp_args : block_cpp_args) - -gnuradio_blocklib_soapy_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_soapy_lib, - dependencies : soapy_deps) - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'soapy') -cmake.configure_package_config_file( - name : 'gnuradio-soapy', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_soapy_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-soapy', - filebase : 'gnuradio-soapy', - description : 'GNU Radio Soapy Module') diff --git a/blocklib/soapy/lib/setting_string_conversion.h b/blocklib/soapy/lib/setting_string_conversion.h deleted file mode 100644 index 8b000aa11..000000000 --- a/blocklib/soapy/lib/setting_string_conversion.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2021 Nicholas Corgan - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include <SoapySDR/Types.hpp> -#include <SoapySDR/Version.h> - -#include <sstream> - -namespace gr { -namespace soapy { - -// SoapySDR doesn't have an API define for SettingToString, so we need -// to check the version. 0.8 is the first tagged version to have this -// functionality. -#if SOAPY_SDR_API_VERSION >= 0x080000 - -template <typename T> -static inline T string_to_setting(const std::string& str) -{ - return SoapySDR::StringToSetting<T>(str); -} - -template <typename T> -static inline std::string setting_to_string(const T& setting) -{ - return SoapySDR::SettingToString<T>(setting); -} - -#else - -// Copied from SoapySDR 0.8 -#define SOAPY_SDR_TRUE "true" -#define SOAPY_SDR_FALSE "false" - -template <typename T> -static inline T string_to_setting(const std::string& str) -{ - std::stringstream sstream(str); - T setting; - - sstream >> setting; - - return setting; -} - -// Copied from SoapySDR 0.8 -//! convert empty and "false" strings to false, integers to their truthness -template <> -inline bool string_to_setting<bool>(const std::string& str) -{ - if (str.empty() || str == SOAPY_SDR_FALSE) { - return false; - } - if (str == SOAPY_SDR_TRUE) { - return true; - } - try { - return static_cast<bool>(std::stod(str)); - } catch (std::invalid_argument& e) { - } - // other values are true - return true; -} - -template <typename T> -static inline std::string setting_to_string(const T& setting) -{ - return std::to_string(setting); -} - -template <> -inline std::string setting_to_string<bool>(const bool& setting) -{ - return setting ? SOAPY_SDR_TRUE : SOAPY_SDR_FALSE; -} - -#endif - -} // namespace soapy -} // namespace gr diff --git a/blocklib/soapy/limesdr_source/limesdr_source.yml b/blocklib/soapy/limesdr_source/limesdr_source.yml deleted file mode 100644 index 3e96a4089..000000000 --- a/blocklib/soapy/limesdr_source/limesdr_source.yml +++ /dev/null @@ -1,92 +0,0 @@ -module: soapy -block: limesdr_source -label: LimeSDR Source -blocktype: grc -category: '[Core]/Soapy' - -typekeys: - - id: T - type: class - options: - - cf32 - # - rf32 - -grc: - flags: [python] - templates: - imports: from gnuradio import soapy - make: | - dev = 'driver=lime' - stream_args = '' - tune_args = [''] - settings = [''] - - self.${id} = soapy.source_${T.fcn}(dev, 1, ${dev_args}, - stream_args, tune_args, settings) - self.${id}.set_sample_rate(0, ${samp_rate}) - self.${id}.set_bandwidth(0, ${bandwidth}) - self.${id}.set_frequency(0, ${center_freq}) - self.${id}.set_frequency_correction(0, ${freq_correction}) - self.${id}.set_gain(0, min(max(${gain}, -12.0), 61.0)) - callbacks: - - set_sample_rate(0, ${samp_rate}) - - set_bandwidth(0, ${bandwidth}) - - set_frequency(0, ${center_freq}) - - set_frequency_correction(0, ${freq_correction}) - - set_gain(0, min(max(${gain}, -12.0), 61.0)) - - -parameters: - - id: dev_args - label: Device arguments - dtype: string - grc: - hide: ${'part' if not dev_args else 'none'} - - - id: samp_rate - label: Sample Rate - dtype: rf32 - grc: - default: 'samp_rate' - - - id: bandwidth - label: Bandwidth - dtype: rf32 - grc: - category: RF Options - default: '0.0' - hide: part - - - id: center_freq - label: 'Center Freq (Hz)' - dtype: rf32 - grc: - category: RF Options - default: 'freq' - - - id: freq_correction - label: 'Frequency Correction (PPM)' - dtype: rf32 - grc: - category: RF Options - default: '0' - hide: 'part' - - - id: gain - label: 'RF Gain (-12dB - 61dB)' - dtype: rf32 - grc: - category: RF Options - default: '20.0' - hide: 'part' - -ports: - - domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/soapy/python/gnuradio/soapy/__init__.py b/blocklib/soapy/python/gnuradio/soapy/__init__.py deleted file mode 100644 index b155fe72b..000000000 --- a/blocklib/soapy/python/gnuradio/soapy/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ - -import os - -try: - from .soapy_python import * -except ImportError: - dirname, filename = os.path.split(os.path.abspath(__file__)) - __path__.append(os.path.join(dirname, "bindings")) - from .soapy_python import * diff --git a/blocklib/soapy/python/gnuradio/soapy/bindings/block_pybind.cc b/blocklib/soapy/python/gnuradio/soapy/bindings/block_pybind.cc deleted file mode 100644 index da6b1c82e..000000000 --- a/blocklib/soapy/python/gnuradio/soapy/bindings/block_pybind.cc +++ /dev/null @@ -1,657 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2020-2021 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -/***********************************************************************************/ -/* This file is automatically generated using bindtool and can be manually edited */ -/* The following lines can be configured to regenerate this file during cmake */ -/* If manual edits are made, the following tags should be modified accordingly. */ -/* BINDTOOL_GEN_AUTOMATIC(0) */ -/* BINDTOOL_USE_PYGCCXML(0) */ -/* BINDTOOL_HEADER_FILE(block.h) */ -/* BINDTOOL_HEADER_FILE_HASH(6326cce2f22e30ab332ef966343f4a50) */ -/***********************************************************************************/ - -#include "soapy_common.h" - -#include <pybind11/complex.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/soapy/block.h> -// pydoc.h is automatically generated in the build directory -// #include <block_pydoc.h> - -#include <algorithm> -#include <cassert> - -#define __EXPAND(x) x -#define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT -#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1)) -#define __CAT1(a, b) a##b -#define __CAT2(a, b) __CAT1(a, b) -#define __DOC1(n1) "" -#define __DOC2(n1, n2) "" -#define __DOC3(n1, n2, n3) "" -#define __DOC4(n1, n2, n3, n4) "" -#define __DOC5(n1, n2, n3, n4, n5) "" -#define __DOC6(n1, n2, n3, n4, n5, n6) "" -#define __DOC7(n1, n2, n3, n4, n5, n6, n7) "" -#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) -#define D(...) DOC(gr, soapy, __VA_ARGS__) - -// Assumption: we've validated that this key exists, -// probably through get_setting_info. -static gr::soapy::arginfo_t -get_specific_arginfo(const gr::soapy::arginfo_list_t& arginfo_list, - const std::string& key) -{ - auto iter = std::find_if( - arginfo_list.begin(), - arginfo_list.end(), - [&key](const gr::soapy::arginfo_t& arginfo) { return (arginfo.key == key); }); - assert(iter != arginfo_list.end()); - - return (*iter); -} - -void bind_block(py::module& m) -{ - - using block = ::gr::soapy::block; - - - py::class_<block, gr::block, gr::node, std::shared_ptr<block>>(m, "block", D(block)) - - - .def("set_frontend_mapping", - &block::set_frontend_mapping, - py::arg("frontend_mapping"), - D(block, set_frontend_mapping)) - - - .def("get_frontend_mapping", - &block::get_frontend_mapping, - D(block, get_frontend_mapping)) - - - .def("get_channel_info", - &block::get_channel_info, - py::arg("channel"), - D(block, get_channel_info)) - - - .def("set_sample_rate", - &block::set_sample_rate, - py::arg("channel"), - py::arg("sample_rate"), - D(block, set_sample_rate)) - - - .def("get_sample_rate", - &block::get_sample_rate, - py::arg("channel"), - D(block, get_sample_rate)) - - - .def("get_sample_rate_range", - &block::get_sample_rate_range, - py::arg("channel"), - D(block, get_sample_rate_range)) - - - .def("set_frequency", - (void(block::*)(size_t, double)) & block::set_frequency, - py::arg("channel"), - py::arg("freq"), - D(block, set_frequency, 0)) - - - .def("set_frequency", - (void(block::*)(size_t, const std::string&, double)) & block::set_frequency, - py::arg("channel"), - py::arg("name"), - py::arg("freq"), - D(block, set_frequency, 1)) - - - .def("get_frequency", - (double(block::*)(size_t) const) & block::get_frequency, - py::arg("channel"), - D(block, get_frequency, 0)) - - - .def("get_frequency", - (double(block::*)(size_t, const std::string&) const) & block::get_frequency, - py::arg("channel"), - py::arg("name"), - D(block, get_frequency, 1)) - - - .def("list_frequencies", - &block::list_frequencies, - py::arg("channel"), - D(block, list_frequencies)) - - - .def("get_frequency_range", - (gr::soapy::range_list_t(block::*)(size_t) const) & - block::get_frequency_range, - py::arg("channel"), - D(block, get_frequency_range, 0)) - - - .def("get_frequency_range", - (gr::soapy::range_list_t(block::*)(size_t, const std::string&) const) & - block::get_frequency_range, - py::arg("channel"), - py::arg("name"), - D(block, get_frequency_range, 1)) - - - .def("get_frequency_args_info", - &block::get_frequency_args_info, - py::arg("channel"), - D(block, get_frequency_args_info)) - - - .def("set_bandwidth", - &block::set_bandwidth, - py::arg("channel"), - py::arg("bandwidth"), - D(block, set_bandwidth)) - - - .def("get_bandwidth", - &block::get_bandwidth, - py::arg("channel"), - D(block, get_bandwidth)) - - - .def("get_bandwidth_range", - &block::get_bandwidth_range, - py::arg("channel"), - D(block, get_bandwidth_range)) - - - .def("list_antennas", - &block::list_antennas, - py::arg("channel"), - D(block, list_antennas)) - - - .def("set_antenna", - &block::set_antenna, - py::arg("channel"), - py::arg("name"), - D(block, set_antenna)) - - - .def( - "get_antenna", &block::get_antenna, py::arg("channel"), D(block, get_antenna)) - - - .def("has_gain_mode", - &block::has_gain_mode, - py::arg("channel"), - D(block, has_gain_mode)) - - - .def("set_gain_mode", - &block::set_gain_mode, - py::arg("channel"), - py::arg("automatic"), - D(block, set_gain_mode)) - - - .def("get_gain_mode", - &block::get_gain_mode, - py::arg("channel"), - D(block, get_gain_mode)) - - - .def("list_gains", &block::list_gains, py::arg("channel"), D(block, list_gains)) - - - .def("set_gain", - (void(block::*)(size_t, double)) & block::set_gain, - py::arg("channel"), - py::arg("gain"), - D(block, set_gain, 0)) - - - .def("set_gain", - (void(block::*)(size_t, const std::string&, double)) & block::set_gain, - py::arg("channel"), - py::arg("name"), - py::arg("gain"), - D(block, set_gain, 1)) - - - .def("get_gain", - (double(block::*)(size_t) const) & block::get_gain, - py::arg("channel"), - D(block, get_gain, 0)) - - - .def("get_gain", - (double(block::*)(size_t, const std::string&) const) & block::get_gain, - py::arg("channel"), - py::arg("name"), - D(block, get_gain, 1)) - - - .def("get_gain_range", - (gr::soapy::range_t(block::*)(size_t) const) & block::get_gain_range, - py::arg("channel"), - D(block, get_gain_range, 0)) - - - .def("get_gain_range", - (gr::soapy::range_t(block::*)(size_t, const std::string&) const) & - block::get_gain_range, - py::arg("channel"), - py::arg("name"), - D(block, get_gain_range, 1)) - - - .def("has_frequency_correction", - &block::has_frequency_correction, - py::arg("channel"), - D(block, has_frequency_correction)) - - - .def("set_frequency_correction", - &block::set_frequency_correction, - py::arg("channel"), - py::arg("freq_correction"), - D(block, set_frequency_correction)) - - - .def("get_frequency_correction", - &block::get_frequency_correction, - py::arg("channel"), - D(block, get_frequency_correction)) - - - .def("has_dc_offset_mode", - &block::has_dc_offset_mode, - py::arg("channel"), - D(block, has_dc_offset_mode)) - - - .def("set_dc_offset_mode", - &block::set_dc_offset_mode, - py::arg("channel"), - py::arg("automatic"), - D(block, set_dc_offset_mode)) - - - .def("get_dc_offset_mode", - &block::get_dc_offset_mode, - py::arg("channel"), - D(block, get_dc_offset_mode)) - - - .def("has_dc_offset", - &block::has_dc_offset, - py::arg("channel"), - D(block, has_dc_offset)) - - - .def("set_dc_offset", - &block::set_dc_offset, - py::arg("channel"), - py::arg("dc_offset"), - D(block, set_dc_offset)) - - - .def("get_dc_offset", - &block::get_dc_offset, - py::arg("channel"), - D(block, get_dc_offset)) - - - .def("has_iq_balance", - &block::has_iq_balance, - py::arg("channel"), - D(block, has_iq_balance)) - - - .def("set_iq_balance", - &block::set_iq_balance, - py::arg("channel"), - py::arg("iq_balance"), - D(block, set_iq_balance)) - - - .def("get_iq_balance", - &block::get_iq_balance, - py::arg("channel"), - D(block, get_iq_balance)) - - - .def("has_iq_balance_mode", - &block::has_iq_balance_mode, - py::arg("channel"), - D(block, has_iq_balance_mode)) - - - .def("set_iq_balance_mode", - &block::set_iq_balance_mode, - py::arg("channel"), - py::arg("automatic"), - D(block, set_iq_balance_mode)) - - - .def("get_iq_balance_mode", - &block::get_iq_balance_mode, - py::arg("channel"), - D(block, get_iq_balance_mode)) - - - .def("set_master_clock_rate", - &block::set_master_clock_rate, - py::arg("clock_rate"), - D(block, set_master_clock_rate)) - - - .def("get_master_clock_rate", - &block::get_master_clock_rate, - D(block, get_master_clock_rate)) - - - .def("get_master_clock_rates", - &block::get_master_clock_rates, - D(block, get_master_clock_rate)) - - - .def("set_reference_clock_rate", - &block::set_reference_clock_rate, - py::arg("clock_rate"), - D(block, set_reference_clock_rate)) - - - .def("get_reference_clock_rate", - &block::get_reference_clock_rate, - D(block, get_reference_clock_rate)) - - - .def("get_reference_clock_rates", - &block::get_reference_clock_rates, - D(block, get_reference_clock_rate)) - - - .def("list_clock_sources", - &block::list_clock_sources, - D(block, list_clock_sources)) - - - .def("set_clock_source", - &block::set_clock_source, - py::arg("clock_source"), - D(block, set_clock_source)) - - - .def("get_clock_source", &block::get_clock_source, D(block, get_clock_source)) - - - .def("list_time_sources", &block::list_time_sources, D(block, list_time_sources)) - - - .def("set_time_source", - &block::set_time_source, - py::arg("time_source"), - D(block, set_time_source)) - - - .def("get_time_source", &block::get_time_source, D(block, get_time_source)) - - - .def("has_hardware_time", - &block::has_hardware_time, - py::arg("what") = "", - D(block, has_hardware_time)) - - - .def("set_hardware_time", - &block::set_hardware_time, - py::arg("what") = "", - py::arg("time_ns"), - D(block, set_hardware_time)) - - - .def("get_hardware_time", - &block::get_hardware_time, - py::arg("what") = "", - D(block, get_hardware_time)) - - - .def("list_sensors", - (std::vector<std::string>(block::*)() const) & block::list_sensors, - D(block, list_sensors, 0)) - - .def("get_sensor_info", - (gr::soapy::arginfo_t(block::*)(const std::string&) const) & - block::get_sensor_info, - py::arg("key"), - D(block, get_sensor_info, 0)) - - .def( - "read_sensor", - [](const block& self, const std::string& key) -> py::object { - const auto arginfo = self.get_sensor_info(key); - - return cast_string_to_arginfo_type(arginfo.type, arginfo.value); - }, - py::arg("key"), - D(block, read_sensor, 0)) - - .def("list_sensors", - (std::vector<std::string>(block::*)(size_t) const) & block::list_sensors, - py::arg("channel"), - D(block, list_sensors, 1)) - - .def("get_sensor_info", - (gr::soapy::arginfo_t(block::*)(size_t, const std::string&) const) & - block::get_sensor_info, - py::arg("channel"), - py::arg("key"), - D(block, get_sensor_info, 1)) - - .def( - "read_sensor", - [](const block& self, size_t channel, const std::string& key) -> py::object { - const auto arginfo = self.get_sensor_info(channel, key); - - return cast_string_to_arginfo_type(arginfo.type, arginfo.value); - }, - py::arg("channel"), - py::arg("key"), - D(block, read_sensor, 1)) - - - .def("list_register_interfaces", - &block::list_register_interfaces, - D(block, list_register_interfaces)) - - - .def("write_register", - &block::write_register, - py::arg("name"), - py::arg("addr"), - py::arg("value"), - D(block, write_register)) - - - .def("read_register", - &block::read_register, - py::arg("name"), - py::arg("addr"), - D(block, read_register)) - - - .def("write_registers", - &block::write_registers, - py::arg("name"), - py::arg("addr"), - py::arg("value"), - D(block, write_registers)) - - - .def("read_registers", - &block::read_registers, - py::arg("name"), - py::arg("addr"), - py::arg("length"), - D(block, read_registers)) - - .def("get_setting_info", - (gr::soapy::arginfo_list_t(block::*)() const) & block::get_setting_info, - D(block, get_setting_info, 0)) - - .def( - "write_setting", - [](block& self, const std::string& key, py::object value) -> void { - auto setting_info = cast_pyobject_to_arginfo_string(value); - - self.write_setting(key, setting_info.value); - }, - py::arg("key"), - py::arg("value"), - D(block, write_setting, 0)) - - .def( - "read_setting", - [](const block& self, const std::string& key) -> py::object { - const auto setting_info = - get_specific_arginfo(self.get_setting_info(), key); - - return cast_string_to_arginfo_type(setting_info.type, setting_info.value); - }, - py::arg("key"), - D(block, read_setting, 0)) - - .def("get_setting_info", - (gr::soapy::arginfo_list_t(block::*)(size_t) const) & - block::get_setting_info, - py::arg("channel"), - D(block, get_setting_info, 0)) - - .def( - "write_setting", - [](block& self, size_t channel, const std::string& key, py::object value) - -> void { - auto setting_info = cast_pyobject_to_arginfo_string(value); - - self.write_setting(channel, key, setting_info.value); - }, - py::arg("channel"), - py::arg("key"), - py::arg("value"), - D(block, write_setting, 0)) - - .def( - "read_setting", - [](const block& self, size_t channel, const std::string& key) -> py::object { - const auto setting_info = - get_specific_arginfo(self.get_setting_info(channel), key); - - return cast_string_to_arginfo_type(setting_info.type, setting_info.value); - }, - py::arg("channel"), - py::arg("key"), - D(block, read_setting, 0)) - - - .def("list_gpio_banks", &block::list_gpio_banks, D(block, list_gpio_banks)) - - - .def("write_gpio", - (void(block::*)(const std::string&, unsigned)) & block::write_gpio, - py::arg("bank"), - py::arg("value"), - D(block, write_gpio, 0)) - - - .def("write_gpio", - (void(block::*)(const std::string&, unsigned, unsigned)) & block::write_gpio, - py::arg("bank"), - py::arg("value"), - py::arg("mask"), - D(block, write_gpio, 1)) - - - .def("read_gpio", &block::read_gpio, py::arg("bank"), D(block, read_gpio)) - - - .def("write_gpio_dir", - (void(block::*)(const std::string&, unsigned)) & block::write_gpio_dir, - py::arg("bank"), - py::arg("value"), - D(block, write_gpio_dir, 0)) - - - .def("write_gpio_dir", - (void(block::*)(const std::string&, unsigned, unsigned)) & - block::write_gpio_dir, - py::arg("bank"), - py::arg("value"), - py::arg("mask"), - D(block, write_gpio_dir, 1)) - - - .def("read_gpio_dir", - &block::read_gpio_dir, - py::arg("bank"), - D(block, read_gpio_dir)) - - - .def("write_i2c", - &block::write_i2c, - py::arg("addr"), - py::arg("data"), - D(block, write_i2c)) - - - .def("read_i2c", - &block::read_i2c, - py::arg("addr"), - py::arg("length"), - D(block, read_i2c)) - - - .def("transact_spi", - &block::transact_spi, - py::arg("addr"), - py::arg("data"), - py::arg("num_bits"), - D(block, transact_spi)) - - - .def("list_uarts", &block::list_uarts, D(block, list_uarts)) - - - .def("write_uart", - &block::write_uart, - py::arg("which"), - py::arg("data"), - D(block, write_uart)) - - - .def("read_uart", - &block::read_uart, - py::arg("which"), - py::arg("timeout_us") = 100000, - D(block, read_uart)) - - ; -} diff --git a/blocklib/soapy/python/gnuradio/soapy/bindings/meson.build b/blocklib/soapy/python/gnuradio/soapy/bindings/meson.build deleted file mode 100644 index 9bd9af38b..000000000 --- a/blocklib/soapy/python/gnuradio/soapy/bindings/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -soapy_pybind_sources = [files('soapy_types_pybind.cc', 'soapy_common.cc', 'block_pybind.cc')] + soapy_pybind_sources -soapy_pybind_names = ['soapy_types', 'block'] + soapy_pybind_names
\ No newline at end of file diff --git a/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_common.cc b/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_common.cc deleted file mode 100644 index 5f1fc70ab..000000000 --- a/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_common.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2021 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "setting_string_conversion.h" -#include "soapy_common.h" - -#include <SoapySDR/Types.hpp> -#include <SoapySDR/Version.h> -#include <string> - -py::object cast_string_to_arginfo_type(gr::soapy::argtype_t argtype, - const std::string& str) -{ - py::object ret; - switch (argtype) { - case SoapySDR::ArgInfo::BOOL: - ret = py::bool_(gr::soapy::string_to_setting<bool>(str)); - break; - - case SoapySDR::ArgInfo::INT: - ret = py::int_(gr::soapy::string_to_setting<int>(str)); - break; - - case SoapySDR::ArgInfo::FLOAT: - ret = py::float_(gr::soapy::string_to_setting<double>(str)); - break; - - default: - ret = py::str(str); - break; - } - - return ret; -} - -setting_info cast_pyobject_to_arginfo_string(py::object obj) -{ - setting_info info; - - if (py::isinstance<py::bool_>(obj)) { - info.value = gr::soapy::setting_to_string(bool(py::cast<py::bool_>(obj))); - info.type = SoapySDR::ArgInfo::BOOL; - } - else if (py::isinstance<py::int_>(obj)) { - info.value = gr::soapy::setting_to_string(int(py::cast<py::int_>(obj))); - info.type = SoapySDR::ArgInfo::INT; - } - else if (py::isinstance<py::float_>(obj)) { - info.value = gr::soapy::setting_to_string(double(py::cast<py::float_>(obj))); - info.type = SoapySDR::ArgInfo::FLOAT; - } - else { - info.value = py::str(obj); - info.type = SoapySDR::ArgInfo::STRING; - } - - return info; -} diff --git a/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_common.h b/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_common.h deleted file mode 100644 index 90d5b9035..000000000 --- a/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_common.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2021 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <pybind11/complex.h> -#include <pybind11/operators.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/soapy/soapy_types.h> - -py::object cast_string_to_arginfo_type(gr::soapy::argtype_t argtype, - const std::string& str); - -struct setting_info { - std::string value; - gr::soapy::argtype_t type; -}; - -setting_info cast_pyobject_to_arginfo_string(py::object obj); diff --git a/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_types_pybind.cc b/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_types_pybind.cc deleted file mode 100644 index f91e03f61..000000000 --- a/blocklib/soapy/python/gnuradio/soapy/bindings/soapy_types_pybind.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2021 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "soapy_common.h" - -#include <pybind11/complex.h> -#include <pybind11/operators.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/soapy/soapy_types.h> - -void bind_soapy_types(py::module& m) -{ - py::class_<gr::soapy::range_t>(m, "range_t") - // Constructors - .def(py::init<>()) - .def(py::init<double, double>()) - .def(py::init<double, double, double>()) - - // Methods - .def("minimum", &gr::soapy::range_t::minimum) - .def("maximum", &gr::soapy::range_t::maximum) - .def("step", &gr::soapy::range_t::step) - - .def("__str__", [](const gr::soapy::range_t& range) -> std::string { - std::string ret = "(minimum: "; - ret += std::to_string(range.minimum()); - ret += ", maximum: "; - ret += std::to_string(range.maximum()); - ret += ", step: "; - ret += std::to_string(range.step()); - ret += ")"; - - return ret; - }); - - py::enum_<gr::soapy::argtype_t>(m, "argtype_t") - .value("BOOL", gr::soapy::arginfo_t::BOOL) - .value("INT", gr::soapy::arginfo_t::INT) - .value("FLOAT", gr::soapy::arginfo_t::FLOAT) - .value("STRING", gr::soapy::arginfo_t::STRING) - .export_values(); - - py::class_<gr::soapy::arginfo_t>(m, "arginfo_t") - // Constructors - .def(py::init<>()) - - // Properties - .def_readwrite("key", &gr::soapy::arginfo_t::key) - .def_property( - "value", - [](const gr::soapy::arginfo_t& arginfo) -> py::object { - return cast_string_to_arginfo_type(arginfo.type, arginfo.value); - }, - // So we can implicitly convert to Soapy's convention - [](gr::soapy::arginfo_t& arginfo, py::object obj) -> void { - const auto info = cast_pyobject_to_arginfo_string(obj); - - arginfo.value = info.value; - arginfo.type = info.type; - }) - - .def_readwrite("name", &gr::soapy::arginfo_t::name) - .def_readwrite("description", &gr::soapy::arginfo_t::description) - .def_readwrite("units", &gr::soapy::arginfo_t::units) - .def_readwrite("type", &gr::soapy::arginfo_t::type) - .def_readwrite("range", &gr::soapy::arginfo_t::range) - .def_readwrite("options", &gr::soapy::arginfo_t::options) - .def_readwrite("option_names", &gr::soapy::arginfo_t::optionNames) - - .def("__str__", [](const gr::soapy::arginfo_t& arginfo) -> std::string { - return (arginfo.key + "=" + arginfo.value); - }); -} diff --git a/blocklib/soapy/rtlsdr_source/rtlsdr_source.yml b/blocklib/soapy/rtlsdr_source/rtlsdr_source.yml deleted file mode 100644 index 0a6f42597..000000000 --- a/blocklib/soapy/rtlsdr_source/rtlsdr_source.yml +++ /dev/null @@ -1,92 +0,0 @@ -module: soapy -block: rtlsdr_source -label: RTL SDR Source -blocktype: grc -category: '[Core]/Soapy' - -typekeys: - - id: T - type: class - options: - - cf32 - # - rf32 - -grc: - flags: [python] - templates: - imports: |- - from gnuradio import soapy - make: |- - dev = 'driver=rtlsdr' - stream_args = '' - tune_args = [''] - settings = [''] - - self.${id} = soapy.source_${T.fcn}(dev, 1, ${dev_args}, - stream_args, tune_args, settings) - self.${id}.set_sample_rate(0, ${samp_rate}) - self.${id}.set_gain_mode(0, ${agc}) - self.${id}.set_frequency(0, ${center_freq}) - self.${id}.set_frequency_correction(0, ${freq_correction}) - self.${id}.set_gain(0, 'TUNER', ${gain}) - - callbacks: - - set_sample_rate(0, ${samp_rate}) - - set_gain_mode(0, ${agc}) - - set_frequency(0, ${center_freq}) - - set_frequency_correction(0, ${freq_correction}) - - set_gain(0, 'TUNER', ${gain}) - - -parameters: - - id: dev_args - label: Device arguments - dtype: string - grc: - hide: ${'part' if not dev_args else 'none'} - - id: samp_rate - label: Sample Rate - dtype: rf32 - grc: - default: "samp_rate" - settable: true - - id: center_freq - label: "Center Freq (Hz)" - dtype: rf32 - grc: - category: RF Options - default: "freq" - settable: true - - id: gain - label: "RF Gain" - dtype: rf32 - grc: - category: RF Options - default: "20" - hide: ${'all' if agc else 'part'} - settable: true - - id: freq_correction - label: "Frequency Correction (PPM)" - dtype: rf32 - default: 0 - grc: - category: RF Options - hide: "part" - - id: agc - label: "AGC" - dtype: bool - default: 'false' - grc: - category: RF Options - hide: "part" - -ports: - - domain: stream - id: out - direction: output - type: typekeys/T - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/soapy/sink/sink.yml b/blocklib/soapy/sink/sink.yml deleted file mode 100644 index d91a9f45a..000000000 --- a/blocklib/soapy/sink/sink.yml +++ /dev/null @@ -1,84 +0,0 @@ -module: soapy -block: sink -label: Sink -blocktype: gr::soapy::block -# inherits: gr::soapy::block -category: '[Core]/Soapy' - -typekeys: - - id: T - type: class - options: - - cf32 - # - rf32 - -includes: - - gnuradio/soapy/block.h - -parameters: -- id: device - label: Device - dtype: string - settable: false - grc: - hide: 'all' -- id: nchan - label: Number of Channels - dtype: size_t - settable: false - grc: - hide: 'all' -- id: dev_args - label: Device Args - dtype: string - settable: false - default: '""' -- id: stream_args - label: Stream Args - dtype: string - settable: false - default: '""' - grc: - hide: 'all' -- id: tune_args - label: Tune Args - dtype: string - container: vector - settable: false - serializable: false # pmtf library doesn't support vectors of strings yet - default: std::vector<std::string>{""} - grc: - default: '[]' - hide: 'all' -- id: other_settings - label: Other Settings - dtype: string - container: vector - settable: false - serializable: false # pmtf library doesn't support vectors of strings yet - default: std::vector<std::string>{""} - grc: - default: '[]' - hide: 'all' - -- id: length_tag_name - label: Length Tag Name - dtype: string - cotr: false - settable: true - default: '""' - grc: - hide: 'part' - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - multiplicity: parameters/nchan - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/soapy/sink/sink_cpu.cc b/blocklib/soapy/sink/sink_cpu.cc deleted file mode 100644 index cf6299fb7..000000000 --- a/blocklib/soapy/sink/sink_cpu.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2012,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "sink_cpu.h" -#include "sink_cpu_gen.h" -#include <SoapySDR/Errors.hpp> -#include <SoapySDR/Formats.h> -#include <volk/volk.h> - -namespace gr { -namespace soapy { - -template <> -sink_cpu<gr_complex>::sink_cpu(const typename sink<gr_complex>::block_args& args) - : gr::block("soapy_sink"), - sink<gr_complex>(args), - block_impl(SOAPY_SDR_TX, - args.device, - SOAPY_SDR_CF32, - args.nchan, - args.dev_args, - args.stream_args, - args.tune_args, - args.other_settings) -{ -} - -template <class T> -work_return_t sink_cpu<T>::work(work_io& wio) -{ - int nin = wio.inputs()[0].n_items; - long long int time_ns = 0; - int nconsumed = 0; - - int nwrite = nin; - int flags = 0; - - // TODO: optimization: add loop to handle portions of more than one burst - // per call. - - // FIXME: Add back burst tag handling. Requires some changes to tag/pmt - - int result = 0; - if (nwrite != 0) { - // No command handlers while writing - std::lock_guard<std::mutex> l(d_device_mutex); - result = d_device->writeStream( - d_stream, wio.all_input_ptrs().data(), nwrite, flags, time_ns); - } - - if (result >= 0) { - nconsumed += result; - // if (d_burst_remaining > 0) { - // d_burst_remaining -= result; - // } - } - else if (result == SOAPY_SDR_UNDERFLOW) { - std::cerr << "sU" << std::flush; - } - else { - d_logger->warn("Soapy sink error: {:s}", SoapySDR::errToStr(result)); - } - - wio.consume_each(nconsumed); - return work_return_t::OK; -} - - -} /* namespace soapy */ -} /* namespace gr */ diff --git a/blocklib/soapy/sink/sink_cpu.h b/blocklib/soapy/sink/sink_cpu.h deleted file mode 100644 index 0d8be80ab..000000000 --- a/blocklib/soapy/sink/sink_cpu.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "block_impl.h" -#include <gnuradio/soapy/sink.h> -namespace gr { -namespace soapy { - -template <class T> -class sink_cpu : public sink<T>, public block_impl -{ -public: - sink_cpu(const typename sink<T>::block_args& args); - - work_return_t work(work_io&) override; - -private: - size_t d_burst_remaining = 0; -}; - - -} // namespace soapy -} // namespace gr diff --git a/blocklib/soapy/source/source.yml b/blocklib/soapy/source/source.yml deleted file mode 100644 index 07624cb28..000000000 --- a/blocklib/soapy/source/source.yml +++ /dev/null @@ -1,75 +0,0 @@ -module: soapy -block: source -label: Source -blocktype: gr::soapy::block -# inherits: gr::soapy::block -category: '[Core]/Soapy' - -typekeys: - - id: T - type: class - options: - - cf32 - # - rf32 - -includes: - - gnuradio/soapy/block.h - -parameters: -- id: device - label: Device - dtype: string - settable: false - grc: - hide: 'all' -- id: nchan - label: Number of Channels - dtype: size_t - settable: false - grc: - hide: 'all' -- id: dev_args - label: Device Args - dtype: string - settable: false - default: '""' -- id: stream_args - label: Stream Args - dtype: string - settable: false - default: '""' - grc: - hide: 'all' -- id: tune_args - label: Tune Args - dtype: string - container: vector - settable: false - serializable: false # pmtf library doesn't support vectors of strings yet - default: std::vector<std::string>{""} - grc: - default: '[]' - hide: 'all' -- id: other_settings - label: Other Settings - dtype: std::string - container: vector - settable: false - serializable: false # pmtf library doesn't support vectors of strings yet - default: std::vector<std::string>{""} - grc: - default: '[]' - hide: 'all' - -ports: -- domain: stream - id: out - direction: output - type: typekeys/T - multiplicity: parameters/nchan - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/soapy/source/source_cpu.cc b/blocklib/soapy/source/source_cpu.cc deleted file mode 100644 index de838506f..000000000 --- a/blocklib/soapy/source/source_cpu.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2012,2018 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "source_cpu.h" -#include "source_cpu_gen.h" -#include <SoapySDR/Errors.hpp> -#include <SoapySDR/Formats.h> -#include <volk/volk.h> - -namespace gr { -namespace soapy { - -template <> -source_cpu<gr_complex>::source_cpu(const typename source<gr_complex>::block_args& args) - : gr::block("soapy_source"), - source<gr_complex>(args), - block_impl(SOAPY_SDR_RX, - args.device, - SOAPY_SDR_CF32, - args.nchan, - args.dev_args, - args.stream_args, - args.tune_args, - args.other_settings) -{ -} - -template <class T> -work_return_t source_cpu<T>::work(work_io& wio) -{ - auto noutput_items = wio.outputs()[0].n_items; - /* This limits each work invocation to MTU transfers */ - if (d_mtu > 0) { - noutput_items = std::min(noutput_items, d_mtu); - } - else { - noutput_items = std::min(noutput_items, size_t{ 1024 }); - } - - long long int time_ns = 0; - int flags = 0; - const long timeout_us = 500000; // 0.5 sec - int nout = 0; - - auto output_items = wio.all_output_ptrs(); - for (;;) { - - // No command handlers while reading - int result; - { - std::lock_guard<std::mutex> l(d_device_mutex); - result = d_device->readStream( - d_stream, output_items.data(), noutput_items, flags, time_ns, timeout_us); - } - - if (result >= 0) { - nout = result; - break; - } - - switch (result) { - - // Retry on overflow. Data has been lost. - case SOAPY_SDR_OVERFLOW: - std::cerr << "sO" << std::flush; - continue; - - // Yield back to scheduler on timeout. - case SOAPY_SDR_TIMEOUT: - break; - - // Report and yield back to scheduler on other errors. - default: - logger()->warn("Soapy source error: {}", SoapySDR::errToStr(result)); - break; - } - - break; - }; - - wio.produce_each(nout); - - // if we didn't produce anything, need to kick the scheduler - // This emulates GR 3.x scheduler behavior but also allows for - // a non-blocking implementation above - if (!nout) { - this->come_back_later(100); - } - - return work_return_t::OK; -} - - -} /* namespace soapy */ -} /* namespace gr */ diff --git a/blocklib/soapy/source/source_cpu.h b/blocklib/soapy/source/source_cpu.h deleted file mode 100644 index 2cfe37022..000000000 --- a/blocklib/soapy/source/source_cpu.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "block_impl.h" -#include <gnuradio/soapy/source.h> -namespace gr { -namespace soapy { - -template <class T> -class source_cpu : public source<T>, public block_impl -{ -public: - source_cpu(const typename source<T>::block_args& args); - - work_return_t work(work_io&) override; - -private: -}; - - -} // namespace soapy -} // namespace gr diff --git a/blocklib/soapy/test/meson.build b/blocklib/soapy/test/meson.build deleted file mode 100644 index e69de29bb..000000000 --- a/blocklib/soapy/test/meson.build +++ /dev/null diff --git a/blocklib/soapy/test/test_soapy.py b/blocklib/soapy/test/test_soapy.py deleted file mode 100644 index 15b9d8404..000000000 --- a/blocklib/soapy/test/test_soapy.py +++ /dev/null @@ -1,27 +0,0 @@ -from gnuradio import gr, soapy, blocks, streamops - -samp_rate = 250000 - -src = soapy.source_c('driver=rtlsdr',1) -src.set_sample_rate(0, samp_rate) -src.set_gain_mode(0, False) -src.set_frequency(0, 90500000) -src.set_frequency_correction(0, 0) -src.set_gain(0, 'TUNER', 40) - -hd = streamops.head(100000) -snk = blocks.vector_sink_c() - -fg = gr.flowgraph() - -fg.connect(src,0,hd,0) -fg.connect(hd,0,snk,0) - -fg.start() -fg.wait() - -from matplotlib import pyplot as plt -import numpy as np -plt.plot(np.real(snk.data())) -plt.plot(np.imag(snk.data())) -plt.show()
\ No newline at end of file diff --git a/blocklib/streamops/annotator/annotator.yml b/blocklib/streamops/annotator/annotator.yml deleted file mode 100644 index 2b9802f89..000000000 --- a/blocklib/streamops/annotator/annotator.yml +++ /dev/null @@ -1,61 +0,0 @@ -# This YAML is currently not used because ports need to support multiplicity -## As it is currently implemented, the ports are added in the _cpu constructor -## which we need to be in the top level constructor, but requires extra logic - -module: streamops -block: annotator -label: Annotator -blocktype: sync_block -category: '[Core]/Debug Tools' - -parameters: -- id: when - label: When - dtype: ru64 - settable: false -- id: num_inputs - label: Num Inputs - dtype: size - settable: false -- id: num_outputs - label: Num Outputs - dtype: size - settable: false -- id: tpp - label: Tag Propagation Policy - dtype: gr::tag_propagation_policy_t - settable: false - serializable: false -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - multiplicity: parameters/num_inputs - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - multiplicity: parameters/num_outputs - -callbacks: -- id: data - return: std::vector<tag_t> - const: true - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/streamops/annotator/annotator_cpu.cc b/blocklib/streamops/annotator/annotator_cpu.cc deleted file mode 100644 index 01923b4ca..000000000 --- a/blocklib/streamops/annotator/annotator_cpu.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2010,2013 Free Software Foundation, Inc. - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "annotator_cpu.h" -#include "annotator_cpu_gen.h" -#include <pmtf/scalar.hpp> -#include <pmtf/string.hpp> -#include <cstring> -#include <iomanip> -#include <iostream> - -namespace gr { -namespace streamops { - -annotator_cpu::annotator_cpu(const block_args& args) - : INHERITED_CONSTRUCTORS, - d_when(args.when), - d_num_inputs(args.num_inputs), - d_num_outputs(args.num_outputs), - d_tpp(args.tpp) -{ - - set_tag_propagation_policy(args.tpp); - - d_tag_counter = 0; - // set_relative_rate(1, 1); -} - -work_return_t annotator_cpu::work(work_io& wio) - -{ - auto noutput_items = wio.outputs()[0].n_items; - - uint64_t abs_N = 0; - - for (unsigned i = 0; i < d_num_inputs; i++) { - abs_N = wio.inputs()[i].nitems_read(); - - auto tags = wio.inputs()[i].tags_in_window(0, noutput_items); - d_stored_tags.insert(d_stored_tags.end(), tags.begin(), tags.end()); - } - - // Storing the current noutput_items as the value to the "noutput_items" key - auto srcid = pmtf::string(alias()); - auto key = "seq"; - - // Work does nothing to the data stream; just copy all inputs to outputs - // Adds a new tag when the number of items read is a multiple of d_when - abs_N = wio.outputs()[0].buf().total_written(); - - for (size_t j = 0; j < noutput_items; j++) { - // the min() is a hack to make sure this doesn't segfault if - // there are a different number of ins and outs. This is - // specifically designed to test the 1-to-1 propagation policy. - // for (unsigned i = 0; i < std::min(d_num_outputs, d_num_inputs); i++) { - for (unsigned i = 0; i < d_num_outputs; i++) { - if (abs_N % d_when == 0) { - auto value = pmtf::scalar<uint64_t>(d_tag_counter++); - // tag_map tm = {{key, value}, {"srcid",srcid}}; - wio.outputs()[i].buf().add_tag( - abs_N, pmtf::map{ { key, value }, { "srcid", srcid } }); - } - } - abs_N++; - } - for (unsigned i = 0; i < d_num_outputs; i++) { - wio.outputs()[i].n_produced = noutput_items; - } - - return work_return_t::OK; -} - -} /* namespace streamops */ -} /* namespace gr */ diff --git a/blocklib/streamops/annotator/annotator_cpu.h b/blocklib/streamops/annotator/annotator_cpu.h deleted file mode 100644 index 61b3d2981..000000000 --- a/blocklib/streamops/annotator/annotator_cpu.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2010,2013 Free Software Foundation, Inc. - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/annotator.h> - -namespace gr { -namespace streamops { - -class annotator_cpu : public annotator -{ -public: - annotator_cpu(const block_args& args); - work_return_t work(work_io&) override; - - std::vector<tag_t> data() const override { return d_stored_tags; }; - -private: - const uint64_t d_when; - uint64_t d_tag_counter; - std::vector<tag_t> d_stored_tags; - size_t d_num_inputs, d_num_outputs; - tag_propagation_policy_t d_tpp; -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/deinterleave/deinterleave.yml b/blocklib/streamops/deinterleave/deinterleave.yml deleted file mode 100644 index 37599c5d8..000000000 --- a/blocklib/streamops/deinterleave/deinterleave.yml +++ /dev/null @@ -1,70 +0,0 @@ -module: streamops -block: deinterleave -label: deinterleave -blocktype: block -category: '[Core]/Stream Operators' - -doc: - brief: deinterleave an input block of samples into N outputs - detail: |- - This block deinterleaves blocks of samples. For each output - connection, the input stream will be deinterleaved successively - to the output connections. By default, the block deinterleaves - a single input to each output unless blocksize is given in the - constructor. - - \code - blocksize = 1 - connections = 2 - input = [a, b, c, d, e, f, g, h] - output[0] = [a, c, e, g] - output[1] = [b, d, f, h] - \endcode - - \code - blocksize = 2 - connections = 2 - input = [a, b, c, d, e, f, g, h] - output[0] = [a, b, e, f] - output[1] = [c, d, g, h] - \endcode - -parameters: -- id: nstreams - label: Num Streams - dtype: size - settable: false - grc: - default: 2 -- id: blocksize - label: Block Size - dtype: size - settable: false - default: 1 -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - multiplicity: parameters/nstreams - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/streamops/deinterleave/deinterleave_cpu.cc b/blocklib/streamops/deinterleave/deinterleave_cpu.cc deleted file mode 100644 index 811dd1921..000000000 --- a/blocklib/streamops/deinterleave/deinterleave_cpu.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "deinterleave_cpu.h" -#include "deinterleave_cpu_gen.h" - -#include <algorithm> - -namespace gr { -namespace streamops { - -deinterleave_cpu::deinterleave_cpu(block_args args) : INHERITED_CONSTRUCTORS -{ - if (args.itemsize > 0) { - d_size_bytes = args.itemsize * args.blocksize; - set_output_multiple(args.blocksize); - } - set_relative_rate(1.0 / args.nstreams); -} - -work_return_t deinterleave_cpu::work(work_io& wio) - -{ - auto blocksize = pmtf::get_as<size_t>(*this->param_blocksize); - auto itemsize = wio.inputs()[0].buf().item_size(); - - // Since itemsize can be set after construction - if (d_size_bytes == 0) { - d_size_bytes = itemsize * blocksize; - set_output_multiple(blocksize); - return work_return_t::OK; - } - - // Forecasting - auto nstreams = pmtf::get_as<size_t>(*this->param_nstreams); - auto noutput_items = wio.min_noutput_items(); - auto ninput_items = wio.inputs()[0].n_items; - auto min_output = blocksize * (ninput_items / (blocksize * nstreams)); - if (min_output < 1) { - return work_return_t::INSUFFICIENT_INPUT_ITEMS; - } - noutput_items = std::min(noutput_items, min_output); - ninput_items = noutput_items * nstreams; - - auto in = wio.inputs()[0].items<uint8_t>(); - int count = 0, totalcount = noutput_items * nstreams; - unsigned int skip = 0; - unsigned int acc = 0; - while (count < totalcount) { - auto out = wio.outputs()[d_current_output].items<uint8_t>(); - memcpy(out + skip * d_size_bytes, in, d_size_bytes); - in += d_size_bytes; - // produce(d_current_output, blocksize); - wio.outputs()[d_current_output].n_produced += blocksize; - d_current_output = (d_current_output + 1) % nstreams; - - // accumulate times through the loop; increment skip after a - // full pass over the output streams. - // This is separate than d_current_output since we could be in - // the middle of a loop when we exit. - acc++; - if (acc >= nstreams) { - skip++; - acc = 0; - } - - // Keep track of our loop counter - count += blocksize; - } - wio.consume_each(totalcount); - return work_return_t::OK; -} - - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/deinterleave/deinterleave_cpu.h b/blocklib/streamops/deinterleave/deinterleave_cpu.h deleted file mode 100644 index 61630ddf4..000000000 --- a/blocklib/streamops/deinterleave/deinterleave_cpu.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/deinterleave.h> - -namespace gr { -namespace streamops { - -class deinterleave_cpu : public virtual deinterleave -{ -public: - deinterleave_cpu(block_args args); - work_return_t work(work_io&) override; - -private: - size_t d_current_output = 0; - size_t d_size_bytes = 0; // block size in bytes -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/interleave/interleave.yml b/blocklib/streamops/interleave/interleave.yml deleted file mode 100644 index 0ece776a6..000000000 --- a/blocklib/streamops/interleave/interleave.yml +++ /dev/null @@ -1,72 +0,0 @@ -module: streamops -block: interleave -label: interleave -blocktype: block -category: '[Core]/Stream Operators' - -doc: - brief: interleave N inputs into a single output - detail: |- - This block interleaves blocks of samples. For each input - connection, the samples are interleaved successively to the - output connection. By default, the block interleaves a single - sample from each input to the output unless blocksize is given - in the constructor. - - \code - blocksize = 1 - connections = 2 - input[0] = [a, c, e, g] - input[1] = [b, d, f, h] - output = [a, b, c, d, e, f, g, h] - \endcode - - \code - blocksize = 2 - connections = 2 - input[0] = [a, b, e, f] - input[1] = [c, d, g, h] - output = [a, b, c, d, e, f, g, h] - \endcode - - -parameters: -- id: nstreams - label: Num Streams - dtype: size - settable: false - grc: - default: 2 -- id: blocksize - label: Block Size - dtype: size - settable: false - default: 1 -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - multiplicity: parameters/nstreams - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/streamops/interleave/interleave_cpu.cc b/blocklib/streamops/interleave/interleave_cpu.cc deleted file mode 100644 index f9d003e2c..000000000 --- a/blocklib/streamops/interleave/interleave_cpu.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "interleave_cpu.h" -#include "interleave_cpu_gen.h" - -namespace gr { -namespace streamops { - -interleave_cpu::interleave_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - d_ninputs(args.nstreams), - d_blocksize(args.blocksize), - d_itemsize(args.itemsize) - -{ - set_relative_rate(d_ninputs); - set_output_multiple(d_blocksize * d_ninputs); -} - -work_return_t interleave_cpu::work(work_io& wio) - -{ - - // Since itemsize can be set after construction - if (d_itemsize == 0) { - d_itemsize = wio.inputs()[0].buf().item_size(); - return work_return_t::OK; - } - - // Forecasting - auto ninput_items = wio.min_ninput_items(); - auto noutput_items = wio.outputs()[0].n_items; - auto noutput_blocks = - std::min(ninput_items / d_blocksize, noutput_items / (d_blocksize * d_ninputs)); - - if (noutput_blocks < 1) { - return work_return_t::INSUFFICIENT_OUTPUT_ITEMS; - } - - auto out = wio.outputs()[0].items<uint8_t>(); - - for (unsigned int i = 0; i < noutput_blocks; i++) { - for (auto& in : wio.inputs()) { - memcpy(out, - in.items<uint8_t>() + d_itemsize * d_blocksize * i, - d_itemsize * d_blocksize); - out += d_itemsize * d_blocksize; - } - } - wio.consume_each(noutput_blocks * d_blocksize); - wio.produce_each(noutput_blocks * d_blocksize * d_ninputs); - return work_return_t::OK; -} - - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/interleave/interleave_cpu.h b/blocklib/streamops/interleave/interleave_cpu.h deleted file mode 100644 index 20d39d84c..000000000 --- a/blocklib/streamops/interleave/interleave_cpu.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/interleave.h> - -namespace gr { -namespace streamops { - -class interleave_cpu : public virtual interleave -{ -public: - interleave_cpu(block_args args); - work_return_t work(work_io&) override; - -private: - const unsigned int d_ninputs; - const unsigned int d_blocksize; - size_t d_itemsize; -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex.yml b/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex.yml deleted file mode 100644 index d53f5cd7d..000000000 --- a/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex.yml +++ /dev/null @@ -1,35 +0,0 @@ -module: streamops -block: interleaved_short_to_complex -label: Interleaved Short to Complex -blocktype: sync_block -category: '[Core]/Stream Operators' - -parameters: -- id: swap - label: Swap I and Q - dtype: bool - settable: false - default: 'false' -- id: scale_factor - label: Scale Factor - dtype: rf32 - settable: true - default: 1.0 - -ports: -- domain: stream - id: in - direction: input - type: int16_t - shape: '2' - -- domain: stream - id: out - direction: output - type: cf32 - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex_cpu.cc b/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex_cpu.cc deleted file mode 100644 index 5020819b2..000000000 --- a/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex_cpu.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "interleaved_short_to_complex_cpu.h" -#include "interleaved_short_to_complex_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace streamops { - -interleaved_short_to_complex_cpu::interleaved_short_to_complex_cpu(const block_args& args) - : INHERITED_CONSTRUCTORS, d_scalar(args.scale_factor), d_swap(args.swap) -{ -} - -void interleaved_short_to_complex_cpu::set_swap(bool swap) { d_swap = swap; } -void interleaved_short_to_complex_cpu::set_scale_factor(float new_value) -{ - d_scalar = new_value; -} - -work_return_t interleaved_short_to_complex_cpu::work(work_io& wio) - -{ - auto in = wio.inputs()[0].items<short>(); - auto out = wio.outputs()[0].items<float>(); - - auto noutput_items = wio.outputs()[0].n_items; - - // This calculates in[] * 1.0 / d_scalar - volk_16i_s32f_convert_32f(out, in, d_scalar, 2 * noutput_items); - - if (d_swap) { - for (size_t i = 0; i < noutput_items; ++i) { - float f = out[2 * i + 1]; - out[2 * i + 1] = out[2 * i]; - out[2 * i] = f; - } - } - - wio.outputs()[0].n_produced = noutput_items; - return work_return_t::OK; -} - - -} /* namespace streamops */ -} /* namespace gr */ diff --git a/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex_cpu.h b/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex_cpu.h deleted file mode 100644 index b4ec50fe1..000000000 --- a/blocklib/streamops/interleaved_short_to_complex/interleaved_short_to_complex_cpu.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/interleaved_short_to_complex.h> - -namespace gr { -namespace streamops { - -class interleaved_short_to_complex_cpu : public interleaved_short_to_complex -{ -public: - interleaved_short_to_complex_cpu(const block_args& args); - - work_return_t work(work_io&) override; - - - void set_swap(bool swap); - void set_scale_factor(float new_value) override; - -private: - float d_scalar; - bool d_swap; -}; - - -} // namespace streamops -} // namespace gr diff --git a/blocklib/streamops/keep_m_in_n/keep_m_in_n.yml b/blocklib/streamops/keep_m_in_n/keep_m_in_n.yml deleted file mode 100644 index 913c8a55f..000000000 --- a/blocklib/streamops/keep_m_in_n/keep_m_in_n.yml +++ /dev/null @@ -1,52 +0,0 @@ -module: streamops -block: keep_m_in_n -label: Keep M in N -blocktype: block -category: '[Core]/Stream Operators' - -# Example Parameters -parameters: -- id: m - label: M - dtype: size - settable: true - grc: - default: 1 -- id: n - label: N - dtype: size - settable: true - grc: - default: 2 -- id: offset - label: offset - dtype: size - settable: true - grc: - default: 0 -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - -implementations: -- id: cpu -- id: cuda - -file_format: 1 diff --git a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cpu.cc b/blocklib/streamops/keep_m_in_n/keep_m_in_n_cpu.cc deleted file mode 100644 index 6b297546c..000000000 --- a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cpu.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012,2018,2022 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "keep_m_in_n_cpu.h" -#include "keep_m_in_n_cpu_gen.h" - -namespace gr { -namespace streamops { - -keep_m_in_n_cpu::keep_m_in_n_cpu(block_args args) : INHERITED_CONSTRUCTORS -{ - // sanity checking - if (args.m <= 0) { - throw std::runtime_error(fmt::format("m={:d} but must be > 0", args.m)); - } - if (args.n <= 0) { - throw std::runtime_error(fmt::format("n={:d} but must be > 0", args.n)); - } - if (args.m > args.n) { - throw std::runtime_error(fmt::format("m = {:d} ≤ {:d} = n", args.m, args.n)); - } - if (args.offset < 0) { - throw std::runtime_error( - fmt::format("offset {:d} but must be >= 0", args.offset)); - } - if (args.offset >= args.n) { - throw std::runtime_error( - fmt::format("offset = {:d} < {:d} = n", args.offset, args.n)); - } - - set_output_multiple(args.m); - - // TODO: integer ratio relative rate - // set_relative_rate(static_cast<uint64_t>(m), static_cast<uint64_t>(n)); - set_relative_rate((double)args.m / args.n); -} - -work_return_t keep_m_in_n_cpu::work(work_io& wio) - -{ - auto out = wio.outputs()[0].items<uint8_t>(); - auto in = wio.inputs()[0].items<uint8_t>(); - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - - // Grab our parameters - auto itemsize = wio.outputs()[0].buf().item_size(); - auto m = pmtf::get_as<size_t>(*this->param_m); - auto n = pmtf::get_as<size_t>(*this->param_n); - auto offset = pmtf::get_as<size_t>(*this->param_offset); - - // iterate over data blocks of size {n, input : m, output} - int blks = std::min(noutput_items / m, ninput_items / n); - int excess = (offset + m - n) * itemsize; - - for (int i = 0; i < blks; i++) { - // set up copy pointers - const uint8_t* iptr = &in[(i * n + offset) * itemsize]; - uint8_t* optr = &out[i * m * itemsize]; - // perform copy - if (excess <= 0) { - memcpy(optr, iptr, m * itemsize); - } - else { - memcpy(optr, &in[i * n * itemsize], excess); - memcpy(optr + excess, iptr, m * itemsize - excess); - } - } - - wio.consume_each(blks * n); - wio.produce_each(blks * m); - return work_return_t::OK; -} - -void keep_m_in_n_cpu::on_parameter_change(param_action_sptr action) -{ - // This will set the underlying PMT - block::on_parameter_change(action); - - auto m = pmtf::get_as<size_t>(*this->param_m); - auto n = pmtf::get_as<size_t>(*this->param_n); - - // Do more updating for certain parameters - if (action->id() == keep_m_in_n::id_m) { - - set_output_multiple(m); - set_relative_rate((double)m / n); - } - else if (action->id() == keep_m_in_n::id_n) { - set_relative_rate((double)m / n); - } -} -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cpu.h b/blocklib/streamops/keep_m_in_n/keep_m_in_n_cpu.h deleted file mode 100644 index 9f1ad5e76..000000000 --- a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cpu.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/keep_m_in_n.h> - -namespace gr { -namespace streamops { - -class keep_m_in_n_cpu : public virtual keep_m_in_n -{ -public: - keep_m_in_n_cpu(block_args args); - work_return_t work(work_io&) override; - -private: - void on_parameter_change(param_action_sptr action) override; -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cuda.cc b/blocklib/streamops/keep_m_in_n/keep_m_in_n_cuda.cc deleted file mode 100644 index 0765af585..000000000 --- a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cuda.cc +++ /dev/null @@ -1,111 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "keep_m_in_n_cuda.h" -#include "keep_m_in_n_cuda_gen.h" - -#include <gnuradio/helper_cuda.h> - -#include <cuComplex.h> -#include <cuda.h> -#include <cuda_runtime.h> - - -namespace gr { -namespace streamops { - -keep_m_in_n_cuda::keep_m_in_n_cuda(block_args args) : INHERITED_CONSTRUCTORS - -{ - // sanity checking - if (args.m <= 0) { - throw std::runtime_error(fmt::format("m={:d} but must be > 0", args.m)); - } - if (args.n <= 0) { - throw std::runtime_error(fmt::format("n={:d} but must be > 0", args.n)); - } - if (args.m > args.n) { - throw std::runtime_error(fmt::format("m = {:d} ≤ {:d} = n", args.m, args.n)); - } - if (args.offset >= args.n) { - throw std::runtime_error( - fmt::format("offset = {:d} < {:d} = n", args.offset, args.n)); - } - - - // can change this to uint64_t by restricting the output multiple - p_kernel = std::make_shared<cusp::keep_m_in_n<uint8_t>>(args.m, args.n, 4); - p_kernel->occupancy(&d_min_block, &d_min_grid); - - cudaStreamCreate(&d_stream); - p_kernel->set_stream(d_stream); - - set_output_multiple(args.m); - set_relative_rate((double)args.m / args.n); -} - -work_return_t keep_m_in_n_cuda::work(work_io& wio) - -{ - auto out = wio.outputs()[0].items<uint8_t>(); - auto in = wio.inputs()[0].items<uint8_t>(); - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - auto itemsize = wio.outputs()[0].buf().item_size(); - auto m = pmtf::get_as<size_t>(*this->param_m); - auto n = pmtf::get_as<size_t>(*this->param_n); - auto offset = pmtf::get_as<size_t>(*this->param_offset); - - // iterate over data blocks of size {n, input : m, output} - int blks = std::min(noutput_items / m, ninput_items / n); - - if (blks == 0) { - wio.consume_each(0); - wio.produce_each(0); - return work_return_t::OK; - } - - int gridSize = (blks * m * itemsize + d_min_block - 1) / d_min_block; - checkCudaErrors(p_kernel->launch(in, - out, - m, - n, - itemsize, - offset, - gridSize, - d_min_block, - blks * m * itemsize, - d_stream)); - - wio.consume_each(blks * n); - wio.produce_each(blks * m); - return work_return_t::OK; -} - -void keep_m_in_n_cuda::on_parameter_change(param_action_sptr action) -{ - // This will set the underlying PMT - block::on_parameter_change(action); - - auto m = pmtf::get_as<size_t>(*this->param_m); - auto n = pmtf::get_as<size_t>(*this->param_n); - - // Do more updating for certain parameters - if (action->id() == keep_m_in_n::id_m) { - - set_output_multiple(m); - set_relative_rate((double)m / n); - } - else if (action->id() == keep_m_in_n::id_n) { - set_relative_rate((double)m / n); - } -} -} // namespace streamops -} // namespace gr diff --git a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cuda.h b/blocklib/streamops/keep_m_in_n/keep_m_in_n_cuda.h deleted file mode 100644 index ed2fec555..000000000 --- a/blocklib/streamops/keep_m_in_n/keep_m_in_n_cuda.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/keep_m_in_n.h> - -#include <cusp/keep_m_in_n.cuh> - -namespace gr { -namespace streamops { - -class keep_m_in_n_cuda : public keep_m_in_n -{ -public: - keep_m_in_n_cuda(block_args args); - work_return_t work(work_io&) override; - -private: - int d_min_block; - int d_min_grid; - cudaStream_t d_stream; - std::shared_ptr<cusp::keep_m_in_n<uint8_t>> p_kernel; - void on_parameter_change(param_action_sptr action) override; -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/nop/nop.yml b/blocklib/streamops/nop/nop.yml deleted file mode 100644 index ef1379d15..000000000 --- a/blocklib/streamops/nop/nop.yml +++ /dev/null @@ -1,33 +0,0 @@ -module: streamops -block: nop -label: Nop -blocktype: sync_block -category: '[Core]/Debug Tools' - -parameters: -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/streamops/nop/nop_cpu.cc b/blocklib/streamops/nop/nop_cpu.cc deleted file mode 100644 index 7f4880744..000000000 --- a/blocklib/streamops/nop/nop_cpu.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* -*- c++ -*- */ -/* - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "nop_cpu.h" -#include "nop_cpu_gen.h" - -namespace gr { -namespace streamops { - -nop_cpu::nop_cpu(block_args args) : INHERITED_CONSTRUCTORS {} - -work_return_t nop_cpu::work(work_io& wio) - -{ - wio.produce_each(wio.outputs()[0].n_items); - return work_return_t::OK; -} - - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/nop/nop_cpu.h b/blocklib/streamops/nop/nop_cpu.h deleted file mode 100644 index 9e78ec776..000000000 --- a/blocklib/streamops/nop/nop_cpu.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- c++ -*- */ -/* - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/nop.h> - -namespace gr { -namespace streamops { - -class nop_cpu : public nop -{ -public: - nop_cpu(block_args args); - work_return_t work(work_io&) override; -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/nop_head/nop_head.yml b/blocklib/streamops/nop_head/nop_head.yml deleted file mode 100644 index 14a6c3387..000000000 --- a/blocklib/streamops/nop_head/nop_head.yml +++ /dev/null @@ -1,36 +0,0 @@ -module: streamops -block: nop_head -label: Nop Head -blocktype: sync_block -category: '[Core]/Debug Tools' - -parameters: -- id: nitems - label: Num. Items - dtype: size - settable: false -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/streamops/nop_head/nop_head_cpu.cc b/blocklib/streamops/nop_head/nop_head_cpu.cc deleted file mode 100644 index bc9571e3d..000000000 --- a/blocklib/streamops/nop_head/nop_head_cpu.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- c++ -*- */ -/* - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "nop_head_cpu.h" -#include "nop_head_cpu_gen.h" - -namespace gr { -namespace streamops { - -nop_head_cpu::nop_head_cpu(const block_args& args) - : INHERITED_CONSTRUCTORS, d_nitems(args.nitems) -{ -} - -work_return_t nop_head_cpu::work(work_io& wio) - -{ - - if (d_ncopied_items >= d_nitems) { - wio.outputs()[0].n_produced = 0; - return work_return_t::DONE; // Done! - } - - unsigned n = std::min(d_nitems - d_ncopied_items, (uint64_t)wio.outputs()[0].n_items); - - if (n == 0) { - wio.outputs()[0].n_produced = 0; - return work_return_t::OK; - } - - // Do Nothing - - d_ncopied_items += n; - wio.outputs()[0].n_produced = n; - - return work_return_t::OK; -} - -} /* namespace streamops */ -} /* namespace gr */ diff --git a/blocklib/streamops/nop_head/nop_head_cpu.h b/blocklib/streamops/nop_head/nop_head_cpu.h deleted file mode 100644 index 3b167c0bf..000000000 --- a/blocklib/streamops/nop_head/nop_head_cpu.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- c++ -*- */ -/* - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/nop_head.h> - -namespace gr { -namespace streamops { - -class nop_head_cpu : public nop_head -{ -public: - nop_head_cpu(const block_args& args); - work_return_t work(work_io&) override; - -private: - size_t d_nitems; - size_t d_ncopied_items = 0; -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/probe_signal/probe_signal.yml b/blocklib/streamops/probe_signal/probe_signal.yml deleted file mode 100644 index 909f5748b..000000000 --- a/blocklib/streamops/probe_signal/probe_signal.yml +++ /dev/null @@ -1,34 +0,0 @@ -module: streamops -block: probe_signal -label: Probe Signal -blocktype: sync_block -category: '[Core]/Measurement Tools' - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - - ri32 - - ri16 - - ri8 - -parameters: -- id: level - label: Probe Level - dtype: T - gettable: true - cotr: false - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - -implementations: -- id: cpu -# - id: cuda - -file_format: 1
\ No newline at end of file diff --git a/blocklib/streamops/probe_signal/probe_signal_cpu.cc b/blocklib/streamops/probe_signal/probe_signal_cpu.cc deleted file mode 100644 index 5514ca6b6..000000000 --- a/blocklib/streamops/probe_signal/probe_signal_cpu.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "probe_signal_cpu.h" -#include "probe_signal_cpu_gen.h" - -namespace gr { -namespace streamops { - -template <class T> -probe_signal_cpu<T>::probe_signal_cpu(const typename probe_signal<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T) -{ -} - -template <class T> -work_return_t probe_signal_cpu<T>::work(work_io& wio) - -{ - auto in = wio.inputs()[0].items<T>(); - auto ninput_items = wio.inputs()[0].n_items; - - if (ninput_items > 0) - *this->param_level = in[ninput_items - 1]; - - wio.consume_each(ninput_items); - return work_return_t::OK; -} - -} /* namespace streamops */ -} /* namespace gr */ diff --git a/blocklib/streamops/probe_signal/probe_signal_cpu.h b/blocklib/streamops/probe_signal/probe_signal_cpu.h deleted file mode 100644 index 7d1a9d68b..000000000 --- a/blocklib/streamops/probe_signal/probe_signal_cpu.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/probe_signal.h> - -namespace gr { -namespace streamops { - -template <class T> -class probe_signal_cpu : public probe_signal<T> -{ -public: - probe_signal_cpu(const typename probe_signal<T>::block_args& args); - - work_return_t work(work_io&) override; - -private: - // Declare private variables here -}; - - -} // namespace streamops -} // namespace gr diff --git a/blocklib/streamops/probe_signal_v/probe_signal_v.yml b/blocklib/streamops/probe_signal_v/probe_signal_v.yml deleted file mode 100644 index 0a42b5ebb..000000000 --- a/blocklib/streamops/probe_signal_v/probe_signal_v.yml +++ /dev/null @@ -1,45 +0,0 @@ -module: streamops -block: probe_signal_v -label: Probe Signal Vector -blocktype: sync_block -category: '[Core]/Measurement Tools' - -doc: - brief: Sink that allows a vector of samples to be grabbed from Python. - -typekeys: - - id: T - type: class - options: - - cf32 - - rf32 - - ri32 - - ri16 - - ri8 - -parameters: -- id: vlen - label: Vec. Length - dtype: size - settable: false -- id: level - label: Constant - dtype: T - gettable: true - container: vector - cotr: false - grc: - hide: all - -ports: -- domain: stream - id: in - direction: input - type: typekeys/T - shape: parameters/vlen - -implementations: -- id: cpu -# - id: cuda - -file_format: 1
\ No newline at end of file diff --git a/blocklib/streamops/probe_signal_v/probe_signal_v_cpu.cc b/blocklib/streamops/probe_signal_v/probe_signal_v_cpu.cc deleted file mode 100644 index b200ada10..000000000 --- a/blocklib/streamops/probe_signal_v/probe_signal_v_cpu.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005,2010,2012-2013,2018 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "probe_signal_v_cpu.h" -#include "probe_signal_v_cpu_gen.h" - -namespace gr { -namespace streamops { - -template <class T> -probe_signal_v_cpu<T>::probe_signal_v_cpu( - const typename probe_signal_v<T>::block_args& args) - : INHERITED_CONSTRUCTORS(T), d_vlen(args.vlen), d_level(args.vlen) -{ -} - -template <class T> -work_return_t probe_signal_v_cpu<T>::work(work_io& wio) - -{ - auto in = wio.inputs()[0].items<T>(); - auto ninput_items = wio.inputs()[0].n_items; - - memcpy(d_level.data(), &in[(ninput_items - 1) * d_vlen], d_vlen * sizeof(T)); - - wio.consume_each(ninput_items); - return work_return_t::OK; -} - -} /* namespace streamops */ -} /* namespace gr */ diff --git a/blocklib/streamops/probe_signal_v/probe_signal_v_cpu.h b/blocklib/streamops/probe_signal_v/probe_signal_v_cpu.h deleted file mode 100644 index 28f4beddc..000000000 --- a/blocklib/streamops/probe_signal_v/probe_signal_v_cpu.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/probe_signal_v.h> - -namespace gr { -namespace streamops { - -template <class T> -class probe_signal_v_cpu : public probe_signal_v<T> -{ -public: - probe_signal_v_cpu(const typename probe_signal_v<T>::block_args& args); - - work_return_t work(work_io&) override; - -private: - // Just work with the private member variable, and pass it out as pmt when queried - void on_parameter_query(param_action_sptr action) override - { - pmtf::pmt param = d_level; - action->set_pmt_value(param); - } - - size_t d_vlen; - std::vector<T> d_level; -}; - - -} // namespace streamops -} // namespace gr diff --git a/blocklib/streamops/selector/selector.yml b/blocklib/streamops/selector/selector.yml deleted file mode 100644 index a179afb3f..000000000 --- a/blocklib/streamops/selector/selector.yml +++ /dev/null @@ -1,67 +0,0 @@ -module: streamops -block: selector -label: Selector -blocktype: block -category: '[Core]/Misc' - -parameters: -- id: num_inputs - label: Num Inputs - dtype: size - settable: false - grc: - hide: part - default: 2 -- id: num_outputs - label: Num Outputs - dtype: size - settable: false - grc: - hide: part - default: 2 -- id: input_index - label: Input Index - dtype: size - settable: true - grc: - default: 0 -- id: output_index - label: Output Index - dtype: size - settable: true - grc: - default: 0 -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part -- id: enabled - label: Enabled - dtype: bool - cotr: false - settable: true - default: true - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - multiplicity: parameters/num_inputs - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - multiplicity: parameters/num_outputs - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/streamops/selector/selector_cpu.cc b/blocklib/streamops/selector/selector_cpu.cc deleted file mode 100644 index 3d4d3522c..000000000 --- a/blocklib/streamops/selector/selector_cpu.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "selector_cpu.h" -#include "selector_cpu_gen.h" - -namespace gr { -namespace streamops { - -selector_cpu::selector_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - d_itemsize(args.itemsize), - d_num_inputs(args.num_inputs), - d_num_outputs(args.num_outputs) -{ - set_tag_propagation_policy(gr::tag_propagation_policy_t::TPP_CUSTOM); -} - -work_return_t selector_cpu::work(work_io& wio) - -{ - auto input_index = pmtf::get_as<size_t>(*this->param_input_index); - auto output_index = pmtf::get_as<size_t>(*this->param_output_index); - auto enabled = pmtf::get_as<bool>(*this->param_enabled); - auto in = wio.inputs()[input_index].items<uint8_t>(); - auto out = wio.outputs()[output_index].items<uint8_t>(); - auto noutput_items = - std::min(wio.inputs()[input_index].n_items, wio.outputs()[output_index].n_items); - - if (d_itemsize == 0) { - d_itemsize = wio.outputs()[output_index].buf().item_size(); - } - - if (enabled) { - auto nread = wio.inputs()[input_index].nitems_read(); - auto nwritten = wio.outputs()[output_index].nitems_written(); - - auto tags = - wio.inputs()[input_index].tags_in_window(nread, nread + noutput_items); - - for (auto tag : tags) { - tag.set_offset(tag.offset() - (nread - nwritten)); - wio.outputs()[output_index].add_tag(tag); - } - - std::copy(in, in + noutput_items * d_itemsize, out); - wio.outputs()[output_index].n_produced = noutput_items; - } - - wio.consume_each(noutput_items); - return work_return_t::OK; -} - - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/selector/selector_cpu.h b/blocklib/streamops/selector/selector_cpu.h deleted file mode 100644 index 6065512a4..000000000 --- a/blocklib/streamops/selector/selector_cpu.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/selector.h> - -namespace gr { -namespace streamops { - -class selector_cpu : public virtual selector -{ -public: - selector_cpu(block_args args); - work_return_t work(work_io&) override; - -private: - size_t d_itemsize = 0; - size_t d_num_inputs, d_num_outputs; -}; - -} // namespace streamops -} // namespace gr
\ No newline at end of file diff --git a/blocklib/streamops/stream_to_streams/stream_to_streams.yml b/blocklib/streamops/stream_to_streams/stream_to_streams.yml deleted file mode 100644 index 496a8c762..000000000 --- a/blocklib/streamops/stream_to_streams/stream_to_streams.yml +++ /dev/null @@ -1,38 +0,0 @@ -module: streamops -block: stream_to_streams -label: Stream To Streams -blocktype: block -category: '[Core]/Stream Operators' - -parameters: -- id: nstreams - label: Number of Streams - dtype: size - settable: false -- id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - grc: - hide: part - -ports: -- domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -- domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - multiplicity: parameters/nstreams - -implementations: -- id: cpu -- id: cuda - -file_format: 1 diff --git a/blocklib/streamops/stream_to_streams/stream_to_streams_cpu.cc b/blocklib/streamops/stream_to_streams/stream_to_streams_cpu.cc deleted file mode 100644 index 591fb67dd..000000000 --- a/blocklib/streamops/stream_to_streams/stream_to_streams_cpu.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "stream_to_streams_cpu.h" -#include "stream_to_streams_cpu_gen.h" -#include <volk/volk.h> - -namespace gr { -namespace streamops { - -stream_to_streams_cpu::stream_to_streams_cpu(const block_args& args) - : INHERITED_CONSTRUCTORS -{ -} - -work_return_t stream_to_streams_cpu::work(work_io& wio) -{ - auto in = wio.inputs()[0].items<uint8_t>(); - - uint8_t* in_ptr = const_cast<uint8_t*>(in); - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - size_t nstreams = wio.outputs().size(); - - auto total_items = std::min(ninput_items / nstreams, (size_t)noutput_items); - auto itemsize = wio.outputs()[0].buf().item_size(); - - for (size_t i = 0; i < total_items; i++) { - for (size_t j = 0; j < nstreams; j++) { - memcpy(wio.outputs()[j].items<uint8_t>() + i * itemsize, in_ptr, itemsize); - in_ptr += itemsize; - } - } - - wio.produce_each(total_items); - wio.consume_each(total_items * nstreams); - return work_return_t::OK; -} - - -} /* namespace streamops */ -} /* namespace gr */ diff --git a/blocklib/streamops/stream_to_streams/stream_to_streams_cpu.h b/blocklib/streamops/stream_to_streams/stream_to_streams_cpu.h deleted file mode 100644 index bc601044d..000000000 --- a/blocklib/streamops/stream_to_streams/stream_to_streams_cpu.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/stream_to_streams.h> - -namespace gr { -namespace streamops { - -class stream_to_streams_cpu : public stream_to_streams -{ -public: - stream_to_streams_cpu(const block_args& args); - - work_return_t work(work_io&) override; -}; - - -} // namespace streamops -} // namespace gr diff --git a/blocklib/streamops/stream_to_streams/stream_to_streams_cuda.cc b/blocklib/streamops/stream_to_streams/stream_to_streams_cuda.cc deleted file mode 100644 index d5b7d418f..000000000 --- a/blocklib/streamops/stream_to_streams/stream_to_streams_cuda.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "stream_to_streams_cuda.h" -#include "stream_to_streams_cuda_gen.h" -#include <gnuradio/helper_cuda.h> -#include <volk/volk.h> - -namespace gr { -namespace streamops { - -stream_to_streams_cuda::stream_to_streams_cuda(const block_args& args) - : INHERITED_CONSTRUCTORS, d_nstreams(args.nstreams) -{ - d_out_items.resize(args.nstreams); - cudaStreamCreate(&d_stream); -} - -work_return_t stream_to_streams_cuda::work(work_io& wio) - -{ - auto noutput_items = wio.outputs()[0].n_items; - auto ninput_items = wio.inputs()[0].n_items; - size_t nstreams = wio.outputs().size(); - auto itemsize = wio.outputs()[0].buf().item_size(); - - if (!p_kernel) { - p_kernel = - std::make_shared<cusp::deinterleave>((int)d_nstreams, 1, (int)itemsize); - p_kernel->set_stream(d_stream); - } - - - auto total_items = std::min(ninput_items / nstreams, (size_t)noutput_items); - - d_out_items = wio.all_output_ptrs(); - - p_kernel->launch_default_occupancy({ wio.inputs()[0].items<uint8_t>() }, - d_out_items, - itemsize * total_items * nstreams); - cudaStreamSynchronize(d_stream); - - wio.produce_each(total_items); - wio.consume_each(total_items * nstreams); - return work_return_t::OK; -} - - -} /* namespace streamops */ -} /* namespace gr */ diff --git a/blocklib/streamops/stream_to_streams/stream_to_streams_cuda.h b/blocklib/streamops/stream_to_streams/stream_to_streams_cuda.h deleted file mode 100644 index 8d7608d05..000000000 --- a/blocklib/streamops/stream_to_streams/stream_to_streams_cuda.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/streamops/stream_to_streams.h> -#include <cusp/deinterleave.cuh> - -namespace gr { -namespace streamops { - -class stream_to_streams_cuda : public stream_to_streams -{ -public: - stream_to_streams_cuda(const block_args& args); - - work_return_t work(work_io&) override; - -private: - size_t d_nstreams; - - std::vector<void*> d_out_items; - - std::shared_ptr<cusp::deinterleave> p_kernel; - cudaStream_t d_stream; -}; - - -} // namespace streamops -} // namespace gr diff --git a/blocklib/streamops/test/meson.build b/blocklib/streamops/test/meson.build index a301e1ad7..71b2b5f3b 100644 --- a/blocklib/streamops/test/meson.build +++ b/blocklib/streamops/test/meson.build @@ -4,9 +4,4 @@ if GR_ENABLE_PYTHON test('qa_delay', py3, args : files('qa_delay.py'), env: TEST_ENV) - test('qa_type_conversions', py3, args : files('qa_type_conversions.py'), env: TEST_ENV) - test('qa_keep_m_in_n', py3, args : files('qa_keep_m_in_n.py'), env: TEST_ENV) - test('qa_probe_signal', py3, args : files('qa_probe_signal.py'), env: TEST_ENV) - test('qa_interleave', py3, args : files('qa_interleave.py'), env: TEST_ENV) - test('qa_selector', py3, args : files('qa_selector.py'), env: TEST_ENV) endif diff --git a/blocklib/streamops/test/qa_interleave.py b/blocklib/streamops/test/qa_interleave.py deleted file mode 100644 index 08eabdfcb..000000000 --- a/blocklib/streamops/test/qa_interleave.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2007,2010,2012-2014 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, blocks, streamops - - -class test_interleave (gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_int_001(self): - lenx = 64 - src0 = blocks.vector_source_f(list(range(0, lenx, 4))) - src1 = blocks.vector_source_f(list(range(1, lenx, 4))) - src2 = blocks.vector_source_f(list(range(2, lenx, 4))) - src3 = blocks.vector_source_f(list(range(3, lenx, 4))) - op = streamops.interleave(gr.sizeof_float) - dst = blocks.vector_sink_f() - - self.tb.connect((src0, 0), (op, 0)) - self.tb.connect((src1, 0), (op, 1)) - self.tb.connect((src2, 0), (op, 2)) - self.tb.connect((src3, 0), (op, 3)) - self.tb.connect(op, dst) - self.tb.run() - expected_result = tuple(range(lenx)) - result_data = dst.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_int_002(self): - blksize = 4 - lenx = 64 - def plusup_big(a): return a + (blksize * 4) - def plusup_little(a): return a + blksize - a_vec = list(range(0, blksize)) - for i in range(0, (lenx // (4 * blksize)) - 1): - a_vec += list(map(plusup_big, a_vec[len(a_vec) - blksize:])) - - b_vec = list(map(plusup_little, a_vec)) - c_vec = list(map(plusup_little, b_vec)) - d_vec = list(map(plusup_little, c_vec)) - - src0 = blocks.vector_source_f(a_vec) - src1 = blocks.vector_source_f(b_vec) - src2 = blocks.vector_source_f(c_vec) - src3 = blocks.vector_source_f(d_vec) - op = streamops.interleave(gr.sizeof_float, blksize) - dst = blocks.vector_sink_f() - - self.tb.connect((src0, 0), (op, 0)) - self.tb.connect((src1, 0), (op, 1)) - self.tb.connect((src2, 0), (op, 2)) - self.tb.connect((src3, 0), (op, 3)) - self.tb.connect(op, dst) - self.tb.run() - expected_result = tuple(range(lenx)) - result_data = dst.data() - - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - - def test_deint_001(self): - lenx = 64 - src = blocks.vector_source_f(list(range(lenx))) - op = streamops.deinterleave(gr.sizeof_float) - dst0 = blocks.vector_sink_f() - dst1 = blocks.vector_sink_f() - dst2 = blocks.vector_sink_f() - dst3 = blocks.vector_sink_f() - - self.tb.connect(src, op) - self.tb.connect((op, 0), (dst0, 0)) - self.tb.connect((op, 1), (dst1, 0)) - self.tb.connect((op, 2), (dst2, 0)) - self.tb.connect((op, 3), (dst3, 0)) - self.tb.run() - - expected_result0 = tuple(range(0, lenx, 4)) - expected_result1 = tuple(range(1, lenx, 4)) - expected_result2 = tuple(range(2, lenx, 4)) - expected_result3 = tuple(range(3, lenx, 4)) - - self.assertFloatTuplesAlmostEqual(expected_result0, dst0.data()) - self.assertFloatTuplesAlmostEqual(expected_result1, dst1.data()) - self.assertFloatTuplesAlmostEqual(expected_result2, dst2.data()) - self.assertFloatTuplesAlmostEqual(expected_result3, dst3.data()) - - def test_deint_002(self): - blksize = 4 - lenx = 64 - src = blocks.vector_source_f(list(range(lenx))) - op = streamops.deinterleave(gr.sizeof_float, blksize) - dst0 = blocks.vector_sink_f() - dst1 = blocks.vector_sink_f() - dst2 = blocks.vector_sink_f() - dst3 = blocks.vector_sink_f() - - self.tb.connect(src, op) - self.tb.connect((op, 0), (dst0, 0)) - self.tb.connect((op, 1), (dst1, 0)) - self.tb.connect((op, 2), (dst2, 0)) - self.tb.connect((op, 3), (dst3, 0)) - self.tb.run() - - def plusup_big(a): return a + (blksize * 4) - def plusup_little(a): return a + blksize - a_vec = list(range(0, blksize)) - for i in range(0, (lenx // (4 * blksize)) - 1): - a_vec += list(map(plusup_big, a_vec[len(a_vec) - blksize:])) - - b_vec = list(map(plusup_little, a_vec)) - c_vec = list(map(plusup_little, b_vec)) - d_vec = list(map(plusup_little, c_vec)) - - expected_result0 = tuple(a_vec) - expected_result1 = tuple(b_vec) - expected_result2 = tuple(c_vec) - expected_result3 = tuple(d_vec) - - self.assertFloatTuplesAlmostEqual(expected_result0, dst0.data()) - self.assertFloatTuplesAlmostEqual(expected_result1, dst1.data()) - self.assertFloatTuplesAlmostEqual(expected_result2, dst2.data()) - self.assertFloatTuplesAlmostEqual(expected_result3, dst3.data()) - - -if __name__ == '__main__': - gr_unittest.run(test_interleave) diff --git a/blocklib/streamops/test/qa_keep_m_in_n.py b/blocklib/streamops/test/qa_keep_m_in_n.py deleted file mode 100644 index a3f4fdc17..000000000 --- a/blocklib/streamops/test/qa_keep_m_in_n.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008,2010,2012,2013,2018,2022 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, blocks, streamops - -import sys -import random - - -class test_keep_m_in_n(gr_unittest.TestCase): - - def setUp(self): - random.seed(0) - - def tearDown(self): - pass - - def test_001(self): - self.maxDiff = None - tb = gr.top_block() - src = blocks.vector_source_c(list(range(0, 100))) - - # itemsize, M, N, offset - km2 = streamops.keep_m_in_n(1, 2, 0) - km3 = streamops.keep_m_in_n(1, 3, 1) - km7 = streamops.keep_m_in_n(1, 7, 2) - snk2 = blocks.vector_sink_c() - snk3 = blocks.vector_sink_c() - snk7 = blocks.vector_sink_c() - tb.connect((src, km2, snk2)) - tb.connect((src, km3, snk3)) - tb.connect((src, km7, snk7)) - tb.run() - - self.assertEqual(list(range(0, 100, 2)), list(snk2.data())) - self.assertEqual(list(range(1, 100, 3)), list(snk3.data())) - self.assertEqual(list(range(2, 100, 7)), list(snk7.data())) - - def test_002(self): - self.maxDiff = None - tb = gr.top_block() - src = blocks.vector_source_f(list(range(0, 100))) - - km = [] - snk = [] - for i in range(5): - km.append(streamops.keep_m_in_n(3, 5, i)) - snk.append(blocks.vector_sink_f()) - tb.connect((src, km[i], snk[i])) - tb.run() - - for i in range(5): - self.assertEqual( - sorted( - list(range(i, 100, 5)) + - list(range((i + 1) % 5, 100, 5)) + - list(range((i + 2) % 5, 100, 5)) - ), - list(snk[i].data()) - ) - - def test_003(self): - with self.assertRaises(RuntimeError) as cm: - streamops.keep_m_in_n(0, 5, 0) - self.assertEqual(str(cm.exception), 'm=0 but must be > 0') - - with self.assertRaises(RuntimeError) as cm: - streamops.keep_m_in_n(5, 0, 0) - self.assertEqual(str(cm.exception), 'n=0 but must be > 0') - - with self.assertRaises(RuntimeError) as cm: - streamops.keep_m_in_n(6, 5, 0) - self.assertEqual(str(cm.exception), 'm = 6 ≤ 5 = n') - - # with self.assertRaises(RuntimeError) as cm: - # streamops.keep_m_in_n(2, 5, -1) - # self.assertEqual(str(cm.exception), - # 'offset -1 but must be >= 0') - - with self.assertRaises(RuntimeError) as cm: - streamops.keep_m_in_n(2, 5, 5) - self.assertEqual(str(cm.exception), 'offset = 5 < 5 = n') - - -if __name__ == '__main__': - gr_unittest.run(test_keep_m_in_n) diff --git a/blocklib/streamops/test/qa_probe_signal.py b/blocklib/streamops/test/qa_probe_signal.py deleted file mode 100644 index 85293bf9b..000000000 --- a/blocklib/streamops/test/qa_probe_signal.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2012-2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, blocks, streamops - - -class test_probe_signal(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_001(self): - value = 12.3 - repeats = 100 - src_data = [value] * repeats - - src = blocks.vector_source_f(src_data) - dst = streamops.probe_signal_f() - - self.tb.connect(src, dst) - self.tb.run() - output = dst.level() - self.assertAlmostEqual(value, output, places=6) - - def test_002(self): - vector_length = 10 - repeats = 10 - value = [0.5 + i for i in range(0, vector_length)] - src_data = value * repeats - - src = blocks.vector_source_f(src_data, vlen=vector_length) - dst = streamops.probe_signal_v_f(vector_length) - - self.tb.connect(src, dst) - self.tb.run() - output = dst.level() - self.assertEqual(len(output), vector_length) - self.assertAlmostEqual(value[3], output[3], places=6) - - def test_003_race_condition_regression_test(self): - src = blocks.vector_source_c([1 + 2j, 3 + 4j], True) - dst = streamops.probe_signal_c() - - self.tb.connect(src, dst) - self.tb.start() - - while dst.level() == 0.0: - continue - - for _ in range(100000): - output = dst.level() - self.assertIn(output, [1 + 2j, 3 + 4j]) - - self.tb.stop() - self.tb.wait() - - def test_004_race_condition_regression_test_vector(self): - vector_length = 10 - src_data = [1.0] * vector_length + [2.0] * vector_length - - src = blocks.vector_source_f(src_data, True, vector_length) - dst = streamops.probe_signal_v_f(vector_length) - - self.tb.connect(src, dst) - self.tb.start() - - while dst.level()[0] == 0.0: - continue - - for _ in range(10000): - output = dst.level() - self.assertIn(output[0], [1.0, 2.0]) - for i in range(1, vector_length): - self.assertEqual(output[0], output[i]) - - self.tb.stop() - self.tb.wait() - - -if __name__ == '__main__': - gr_unittest.run(test_probe_signal) diff --git a/blocklib/streamops/test/qa_selector.py b/blocklib/streamops/test/qa_selector.py deleted file mode 100644 index 5a18655c2..000000000 --- a/blocklib/streamops/test/qa_selector.py +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2019 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, blocks, streamops - - -class test_selector(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_select_same(self): - src_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - expected_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - expected_drop = () - - num_inputs = 4 - num_outputs = 4 - input_index = 1 - output_index = 2 - - op = streamops.selector(num_inputs, num_outputs, input_index, output_index) - - src = [] - dst = [] - for ii in range(num_inputs): - src.append(blocks.vector_source_b(src_data)) - self.tb.connect((src[ii], 0), (op, ii)) - for jj in range(num_outputs): - dst.append(blocks.vector_sink_b()) - self.tb.connect((op, jj), (dst[jj], 0)) - - self.tb.run() - - dst_data = dst[output_index].data() - - self.assertEqual(expected_result, dst_data) - - def test_select_input(self): - - num_inputs = 4 - num_outputs = 4 - input_index = 1 - output_index = 2 - - op = streamops.selector(num_inputs, num_outputs, input_index, output_index) - - src = [] - dst = [] - for ii in range(num_inputs): - src_data = [ii + 1] * 10 - src.append(blocks.vector_source_b(src_data)) - self.tb.connect((src[ii], 0), (op, ii)) - for jj in range(num_outputs): - dst.append(blocks.vector_sink_b()) - self.tb.connect((op, jj), (dst[jj], 0)) - - self.tb.run() - - expected_result = [input_index + 1] * 10 - dst_data = list(dst[output_index].data()) - - self.assertEqual(expected_result, dst_data) - - def test_dump(self): - - num_inputs = 4 - num_outputs = 4 - input_index = 1 - output_index = 2 - output_not_selected = 3 - - op = streamops.selector(num_inputs, num_outputs, input_index, output_index) - - src = [] - dst = [] - for ii in range(num_inputs): - src_data = [ii + 1] * 10 - src.append(blocks.vector_source_b(src_data)) - self.tb.connect((src[ii], 0), (op, ii)) - for jj in range(num_outputs): - dst.append(blocks.vector_sink_b()) - self.tb.connect((op, jj), (dst[jj],0)) - - self.tb.run() - - expected_result = [] - dst_data = list(dst[output_not_selected].data()) - - self.assertEqual(expected_result, dst_data) - - def test_not_enabled(self): - src_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - expected_result = [] - - num_inputs = 4 - num_outputs = 4 - input_index = 1 - output_index = 2 - - op = streamops.selector(num_inputs, num_outputs, input_index, output_index) - op.set_enabled(False) - - src = [] - dst = [] - for ii in range(num_inputs): - src.append(blocks.vector_source_b(src_data)) - self.tb.connect((src[ii], 0), (op, ii)) - for jj in range(num_outputs): - dst.append(blocks.vector_sink_b()) - self.tb.connect((op, jj), (dst[jj], 0)) - - self.tb.run() - - dst_data = dst[output_index].data() - self.assertEqual(expected_result, dst_data) - - # These tests cannot be run as set_index can only be called after check_topology is called - def test_set_indices(self): - - num_inputs = 4; num_outputs = 4 - input_index = 1; output_index = 2 - - op = streamops.selector(num_inputs, num_outputs, 0, 0) - - src = [] - dst = [] - for ii in range(num_inputs): - src_data = [ii+1]*10 - src.append( blocks.vector_source_b(src_data)) - self.tb.connect((src[ii], 0), (op,ii)) - for jj in range(num_outputs): - dst.append(blocks.vector_sink_b()) - self.tb.connect((op,jj),(dst[jj], 0)) - - op.set_input_index(input_index) - op.set_output_index(output_index) - - self.tb.run() - - expected_result = [input_index+1]*10 - dst_data = list(dst[output_index].data()) - - self.assertEqual(expected_result, dst_data) - - def test_dont_set_indices(self): - - num_inputs = 4; num_outputs = 4 - input_index = 1; output_index = 2 - - op = streamops.selector(num_inputs, num_outputs, 0, 0) - #op.set_input_index(input_index) - #op.set_output_index(output_index) - - src = [] - dst = [] - for ii in range(num_inputs): - src_data = [ii+1]*10 - src.append( blocks.vector_source_b(src_data)) - self.tb.connect((src[ii], 0), (op,ii)) - for jj in range(num_outputs): - dst.append(blocks.vector_sink_b()) - self.tb.connect((op,jj),(dst[jj], 0)) - - self.tb.run() - - expected_result = [input_index+1]*10 - dst_data = list(dst[output_index].data()) - - self.assertNotEqual(expected_result, dst_data) - - def test_float_vector(self): - - num_inputs = 4 - num_outputs = 4 - input_index = 1 - output_index = 2 - - veclen = 3 - - op = streamops.selector( - num_inputs, - num_outputs, - input_index, - output_index) - - src = [] - dst = [] - for ii in range(num_inputs): - src_data = [float(ii) + 1] * 10 * veclen - src.append( - blocks.vector_source_f( - src_data, - repeat=False, - vlen=veclen)) - self.tb.connect((src[ii], 0), (op, ii)) - for jj in range(num_outputs): - dst.append(blocks.vector_sink_f(vlen=veclen)) - self.tb.connect((op, jj), (dst[jj], 0)) - - self.tb.run() - - expected_result = [float(input_index) + 1] * 10 * veclen - dst_data = list(dst[output_index].data()) - - self.assertEqual(expected_result, dst_data) - - -if __name__ == '__main__': - gr_unittest.run(test_selector) diff --git a/blocklib/streamops/test/qa_type_conversions.py b/blocklib/streamops/test/qa_type_conversions.py deleted file mode 100644 index ac50f870f..000000000 --- a/blocklib/streamops/test/qa_type_conversions.py +++ /dev/null @@ -1,321 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2012,2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, blocks, streamops - -# from math import sqrt, atan2 - - -class test_type_conversions(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.flowgraph() - self.rt = gr.runtime() - - def tearDown(self): - self.tb = None - self.rt = None - - # def test_char_to_float_identity(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_b(src_data) - # op = blocks.char_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_char_to_float_scale(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [0.5, 1.0, 1.5, 2.0, 2.5] - # src = blocks.vector_source_b(src_data) - # op = blocks.char_to_float(scale=2.0) - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_char_to_short(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [256, 512, 768, 1024, 1280] - # src = blocks.vector_source_b(src_data) - # op = blocks.char_to_short() - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_complex_to_interleaved_char(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_interleaved_char() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_complex_to_interleaved_short(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_interleaved_short() - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_complex_to_float_1(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1.0, 3.0, 5.0, 7.0, 9.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_complex_to_float_2(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data1 = [1.0, 3.0, 5.0, 7.0, 9.0] - # expected_data2 = [2.0, 4.0, 6.0, 8.0, 10.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_float() - # dst1 = blocks.vector_sink_f() - # dst2 = blocks.vector_sink_f() - # self.tb.connect(src, op) - # self.tb.connect((op, 0), dst1) - # self.tb.connect((op, 1), dst2) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data1, dst1.data()) - # self.assertFloatTuplesAlmostEqual(expected_data2, dst2.data()) - - # def test_complex_to_real(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [1.0, 3.0, 5.0, 7.0, 9.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_real() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_complex_to_imag(self): - # src_data = (1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j) - # expected_data = [2.0, 4.0, 6.0, 8.0, 10.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_imag() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_complex_to_mag(self): - # src_data = (1 + 2j, 3 - 4j, 5 + 6j, 7 - 8j, -9 + 10j) - # expected_data = [sqrt(5), sqrt(25), sqrt(61), sqrt(113), sqrt(181)] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_mag() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data(), 5) - - # def test_complex_to_mag_squared(self): - # src_data = (1 + 2j, 3 - 4j, 5 + 6j, 7 - 8j, -9 + 10j) - # expected_data = [5.0, 25.0, 61.0, 113.0, 181.0] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_mag_squared() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_complex_to_arg(self): - # src_data = (1 + 2j, 3 - 4j, 5 + 6j, 7 - 8j, -9 + 10j) - # expected_data = [atan2(2, 1), atan2(-4, 3), - # atan2(6, 5), atan2(-8, 7), atan2(10, -9)] - # src = blocks.vector_source_c(src_data) - # op = blocks.complex_to_arg() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data(), 2) - - # def test_float_to_char_identity(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_char() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_char_scale(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [5, 10, 15, 20, 25] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_char(1, 5) - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_complex_1(self): - # src_data = (1.0, 3.0, 5.0, 7.0, 9.0) - # expected_data = [1 + 0j, 3 + 0j, 5 + 0j, 7 + 0j, 9 + 0j] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_complex() - # dst = blocks.vector_sink_c() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_float_to_complex_2(self): - # src1_data = (1.0, 3.0, 5.0, 7.0, 9.0) - # src2_data = (2.0, 4.0, 6.0, 8.0, 10.0) - # expected_data = [1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j] - # src1 = blocks.vector_source_f(src1_data) - # src2 = blocks.vector_source_f(src2_data) - # op = blocks.float_to_complex() - # dst = blocks.vector_sink_c() - # self.tb.connect(src1, (op, 0)) - # self.tb.connect(src2, (op, 1)) - # self.tb.connect(op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_float_to_int_identity(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_int() - # dst = blocks.vector_sink_i() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_int_scale(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [5, 10, 15, 20, 25] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_int(1, 5) - # dst = blocks.vector_sink_i() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_short_identity(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_short() - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_short_scale(self): - # src_data = (1.0, 2.0, 3.0, 4.0, 5.0) - # expected_data = [5, 10, 15, 20, 25] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_short(1, 5) - # dst = blocks.vector_sink_s() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_float_to_uchar(self): - # src_data = (1.0, -2.0, 3.0, -4.0, 256.0) - # expected_data = [1, 0, 3, 0, 255] - # src = blocks.vector_source_f(src_data) - # op = blocks.float_to_uchar() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_int_to_float_identity(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_i(src_data) - # op = blocks.int_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - # def test_int_to_float_scale(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [0.2, 0.4, 0.6, 0.8, 1.0] - # src = blocks.vector_source_i(src_data) - # op = blocks.int_to_float(1, 5) - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertFloatTuplesAlmostEqual(expected_data, dst.data()) - - def test_interleaved_short_to_complex(self): - src_data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - expected_data = [1 + 2j, 3 + 4j, 5 + 6j, 7 + 8j, 9 + 10j] - src = blocks.vector_source_s(src_data, vlen=2) - op = streamops.interleaved_short_to_complex() - dst = blocks.vector_sink_c() - self.tb.connect(src, op) - self.tb.connect(op, dst) - self.rt.initialize(self.tb) - self.rt.run() - self.assertEqual(expected_data, dst.data()) - - # def test_short_to_char(self): - # src_data = (256, 512, 768, 1024, 1280) - # expected_data = [1, 2, 3, 4, 5] - # src = blocks.vector_source_s(src_data) - # op = blocks.short_to_char() - # dst = blocks.vector_sink_b() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_short_to_float_identity(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_s(src_data) - # op = blocks.short_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_short_to_float_scale(self): - # src_data = (5, 10, 15, 20, 25) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_s(src_data) - # op = blocks.short_to_float(1, 5) - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - # def test_uchar_to_float(self): - # src_data = (1, 2, 3, 4, 5) - # expected_data = [1.0, 2.0, 3.0, 4.0, 5.0] - # src = blocks.vector_source_b(src_data) - # op = blocks.uchar_to_float() - # dst = blocks.vector_sink_f() - # self.tb.connect(src, op, dst) - # self.tb.run() - # self.assertEqual(expected_data, dst.data()) - - -if __name__ == '__main__': - gr_unittest.run(test_type_conversions) diff --git a/blocklib/zeromq/.gitignore b/blocklib/zeromq/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/zeromq/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/zeromq/include/gnuradio/zeromq/.gitignore b/blocklib/zeromq/include/gnuradio/zeromq/.gitignore deleted file mode 100644 index d53050d7d..000000000 --- a/blocklib/zeromq/include/gnuradio/zeromq/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build diff --git a/blocklib/zeromq/include/gnuradio/zeromq/api.h b/blocklib/zeromq/include/gnuradio/zeromq/api.h deleted file mode 100644 index 29941d0f4..000000000 --- a/blocklib/zeromq/include/gnuradio/zeromq/api.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/attributes.h> - -#ifdef gnuradio_blocks_EXPORTS -#define ZEROMQ_API __GR_ATTR_EXPORT -#else -#define ZEROMQ_API __GR_ATTR_IMPORT -#endif diff --git a/blocklib/zeromq/include/gnuradio/zeromq/meson.build b/blocklib/zeromq/include/gnuradio/zeromq/meson.build deleted file mode 100644 index 9bb4be16a..000000000 --- a/blocklib/zeromq/include/gnuradio/zeromq/meson.build +++ /dev/null @@ -1,25 +0,0 @@ -zeromq_headers = [ - 'api.h' -] - -install_headers(zeromq_headers, subdir : 'gnuradio/zeromq') - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'zeromq') -cmake.configure_package_config_file( - name : 'gnuradio-zeromq', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-zeromq', - filebase : 'gnuradio-zeromq', - description : 'GNU Radio ZeroMQ Blocks') diff --git a/blocklib/zeromq/lib/.gitignore b/blocklib/zeromq/lib/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/zeromq/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/zeromq/lib/base.cc b/blocklib/zeromq/lib/base.cc deleted file mode 100644 index 10a07cfa3..000000000 --- a/blocklib/zeromq/lib/base.cc +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2016,2019 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "base.h" -#include "tag_headers.h" - -namespace { -constexpr int LINGER_DEFAULT = 1000; // 1 second. -} - -namespace gr { -namespace zeromq { - -base::base(int type, size_t itemsize, int timeout, bool pass_tags, const std::string& key) - : d_context(1), - d_socket(d_context, type), - d_vsize(itemsize), - d_timeout(timeout), - d_pass_tags(pass_tags), - d_key(key) -{ - /* "Fix" timeout value (ms for new API, us for old API) */ - int major, minor, patch; - zmq::version(&major, &minor, &patch); - - if (major < 3) { - d_timeout *= 1000; - } -} - -std::string base::last_endpoint() const -{ - return d_socket.get(zmq::sockopt::last_endpoint); -} - - -base_sink::base_sink(int type, - size_t itemsize, - const std::string& address, - int timeout, - bool pass_tags, - int hwm, - const std::string& key) - : base(type, itemsize, timeout, pass_tags, key) -{ - gr::configure_default_loggers(d_base_logger, d_base_debug_logger, "zmq_base_source"); - - /* Set high watermark */ - if (hwm >= 0) { - d_socket.set(zmq::sockopt::sndhwm, hwm); - } - - /* Set ZMQ_LINGER so socket won't infinitely block during teardown */ - d_socket.set(zmq::sockopt::linger, LINGER_DEFAULT); - - /* Bind */ - d_socket.bind(address); -} - -int base_sink::send_message(const void* in_buf, - const int in_nitems, - const uint64_t in_offset, - const std::vector<tag_t>& tags) -{ - /* Send key if it exists */ - if (!d_key.empty()) { - zmq::message_t key_message(d_key.size()); - memcpy(key_message.data(), d_key.data(), d_key.size()); - d_socket.send(key_message, zmq::send_flags::sndmore); - } - /* Meta-data header */ - std::string header(""); - if (d_pass_tags) { - // std::vector<gr::tag_t> tags; - // get_tags_in_range(tags, 0, in_offset, in_offset + in_nitems); - header = gen_tag_header(in_offset, tags); - } - - /* Create message */ - size_t payload_len = in_nitems * d_vsize; - size_t msg_len = d_pass_tags ? payload_len + header.length() : payload_len; - zmq::message_t msg(msg_len); - - if (d_pass_tags) { - memcpy(msg.data(), header.c_str(), header.length()); - memcpy((uint8_t*)msg.data() + header.length(), in_buf, payload_len); - } - else { - memcpy(msg.data(), in_buf, payload_len); - } - - /* Send */ - d_socket.send(msg, zmq::send_flags::none); - - /* Report back */ - return in_nitems; -} - -base_source::base_source(int type, - size_t itemsize, - const std::string& address, - int timeout, - bool pass_tags, - int hwm, - const std::string& key) - : base(type, itemsize, timeout, pass_tags, key), - d_consumed_bytes(0), - d_consumed_items(0) -{ - /* Set high watermark */ - if (hwm >= 0) { - d_socket.set(zmq::sockopt::rcvhwm, hwm); - } - - /* Set ZMQ_LINGER so socket won't infinitely block during teardown */ - d_socket.set(zmq::sockopt::linger, LINGER_DEFAULT); - - /* Connect */ - d_socket.connect(address); -} - -bool base_source::has_pending() { return d_msg.size() > d_consumed_bytes; } - -int base_source::flush_pending(block_work_output& work_output, - const int out_nitems, - const uint64_t out_offset) -{ - /* How much to copy in this call */ - int to_copy_items = - std::min(out_nitems, (int)((d_msg.size() - d_consumed_bytes) / d_vsize)); - int to_copy_bytes = d_vsize * to_copy_items; - auto nw = work_output.nitems_written(); - - /* Copy actual data */ - memcpy(work_output.items<uint8_t>() + out_offset * d_vsize, - (uint8_t*)d_msg.data() + d_consumed_bytes, - to_copy_bytes); - - /* Add tags matching this segment of samples */ - for (unsigned int i = 0; i < d_tags.size(); i++) { - if ((d_tags[i].offset() >= (uint64_t)d_consumed_items) && - (d_tags[i].offset() < (uint64_t)d_consumed_items + to_copy_items)) { - gr::tag_t nt = d_tags[i]; - nt.set_offset(nt.offset() + nw + out_offset - d_consumed_items); - work_output.add_tag(nt); - } - } - - /* Update pointer */ - d_consumed_items += to_copy_items; - d_consumed_bytes += to_copy_bytes; - - return to_copy_items; -} - -bool base_source::load_message(bool wait) -{ - /* Poll for input */ - zmq::pollitem_t items[] = { { static_cast<void*>(d_socket), 0, ZMQ_POLLIN, 0 } }; - zmq::poll(&items[0], 1, std::chrono::milliseconds{ wait ? d_timeout : 0 }); - - if (!(items[0].revents & ZMQ_POLLIN)) - return false; - - /* Is this the start or continuation of a multi-part message? */ - auto more = d_socket.get(zmq::sockopt::rcvmore); - - /* Reset */ - d_msg.rebuild(); - d_tags.clear(); - d_consumed_items = 0; - d_consumed_bytes = 0; - - /* Get the message */ - const bool ok = bool(d_socket.recv(d_msg)); - - if (!ok) { - // This shouldn't happen since we polled POLLIN, but ZMQ wants us to check - // the return value. - d_base_logger->warn("Failed to recv() message."); - return false; - } - - /* Throw away key and get the first message. Avoid blocking if a multi-part - * message is not sent */ - if (!d_key.empty() && !more) { - auto is_multipart = d_socket.get(zmq::sockopt::rcvmore); - - d_msg.rebuild(); - if (is_multipart) { - const bool multi_ok = bool(d_socket.recv(d_msg)); - - if (!multi_ok) { - d_base_logger->error("Failure to receive multi-part message."); - } - } - else { - return false; - } - } - /* Parse header from the first (or only) message of a multi-part message */ - if (d_pass_tags && !more) { - uint64_t rcv_offset; - - /* Parse header */ - d_consumed_bytes = parse_tag_header(d_msg, rcv_offset, d_tags); - - /* Fixup the tags offset to be relative to the start of this message */ - for (unsigned int i = 0; i < d_tags.size(); i++) { - d_tags[i].set_offset(d_tags[i].offset() - rcv_offset); - } - } - - /* Each message must contain an integer multiple of data vectors */ - if ((d_msg.size() - d_consumed_bytes) % d_vsize != 0) { - throw std::runtime_error("Incompatible vector sizes: need a multiple of " + - std::to_string(d_vsize) + " bytes per message"); - } - - /* We got one ! */ - return true; -} - -} /* namespace zeromq */ -} /* namespace gr */ diff --git a/blocklib/zeromq/lib/base.h b/blocklib/zeromq/lib/base.h deleted file mode 100644 index 7fb6d2ccb..000000000 --- a/blocklib/zeromq/lib/base.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2016,2019 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include "zmq_common_impl.h" -#include <gnuradio/block_work_io.h> -#include <gnuradio/logger.h> -#include <gnuradio/tag.h> - -namespace gr { -namespace zeromq { - -class base -{ -public: - base(int type, - size_t itemsize, - int timeout, - bool pass_tags, - const std::string& key = ""); - - void set_vsize(size_t vsize) { d_vsize = vsize; } - -protected: - std::string last_endpoint() const; - zmq::context_t d_context; - zmq::socket_t d_socket; - size_t d_vsize; - int d_timeout; - bool d_pass_tags; - const std::string d_key; - - logger_ptr d_base_logger; - logger_ptr d_base_debug_logger; -}; - -class base_sink : public base -{ -public: - base_sink(int type, - size_t itemsize, - const std::string& address, - int timeout, - bool pass_tags, - int hwm, - const std::string& key = ""); - -protected: - int send_message(const void* in_buf, - const int in_nitems, - const uint64_t in_offset, - const std::vector<tag_t>& tags); -}; - -class base_source : public base -{ -public: - base_source(int type, - size_t itemsize, - const std::string& address, - int timeout, - bool pass_tags, - int hwm, - const std::string& key = ""); - -protected: - zmq::message_t d_msg; - std::vector<gr::tag_t> d_tags; - size_t d_consumed_bytes; - int d_consumed_items; - - bool has_pending(); - int flush_pending(block_work_output& work_output, - const int out_nitems, - const uint64_t out_offset); - bool load_message(bool wait); -}; - -} // namespace zeromq -} // namespace gr diff --git a/blocklib/zeromq/lib/meson.build b/blocklib/zeromq/lib/meson.build deleted file mode 100644 index c3f036763..000000000 --- a/blocklib/zeromq/lib/meson.build +++ /dev/null @@ -1,36 +0,0 @@ -zeromq_deps += [gnuradio_gr_dep, volk_dep, fmt_dep, pmtf_dep, cppzmq_dep] -zeromq_sources += ['base.cc', 'tag_headers.cc'] -block_cpp_args = ['-DHAVE_CPU'] - -incdir = include_directories(['../include/gnuradio/zeromq','../include']) -gnuradio_blocklib_zeromq_lib = library('gnuradio-blocklib-zeromq', - zeromq_sources, - include_directories : incdir, - install : true, - link_language: 'cpp', - dependencies : zeromq_deps, - cpp_args : block_cpp_args) - -gnuradio_blocklib_zeromq_dep = declare_dependency(include_directories : incdir, - link_with : gnuradio_blocklib_zeromq_lib, - dependencies : zeromq_deps) - -cmake_conf = configuration_data() -cmake_conf.set('libdir', join_paths(prefix,get_option('libdir'))) -cmake_conf.set('module', 'zeromq') -cmake.configure_package_config_file( - name : 'gnuradio-zeromq', - input : join_paths(meson.source_root(),'cmake','Modules','gnuradioConfigModule.cmake.in'), - install_dir : get_option('prefix') / get_option('libdir') / 'cmake' / 'gnuradio', - configuration : cmake_conf -) - -pkg = import('pkgconfig') -libs = [gnuradio_blocklib_zeromq_lib] # the library/libraries users need to link against -h = ['.'] # subdirectories of ${prefix}/${includedir} to add to header path -pkg.generate(libraries : libs, - subdirs : h, - version : meson.project_version(), - name : 'libgnuradio-zeromq', - filebase : 'gnuradio-zeromq', - description : 'GNU Radio ZeroMQ Module') diff --git a/blocklib/zeromq/lib/tag_headers.cc b/blocklib/zeromq/lib/tag_headers.cc deleted file mode 100644 index fd814bead..000000000 --- a/blocklib/zeromq/lib/tag_headers.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2014 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "zmq_common_impl.h" -#include <gnuradio/tag.h> -#include <cstring> -#include <sstream> - -#define GR_HEADER_MAGIC 0x5FF0 -#define GR_HEADER_VERSION 0x02 - -namespace gr { -namespace zeromq { - -struct membuf : std::streambuf { - membuf(void* b, size_t len) - { - char* bc = static_cast<char*>(b); - this->setg(bc, bc, bc + len); - } -}; - -std::string gen_tag_header(uint64_t offset, const std::vector<gr::tag_t>& tags) -{ - std::stringbuf sb(""); - std::ostream ss(&sb); - - uint16_t header_magic = GR_HEADER_MAGIC; - uint8_t header_version = GR_HEADER_VERSION; - uint64_t ntags = (uint64_t)tags.size(); - - ss.write((const char*)&header_magic, sizeof(uint16_t)); - ss.write((const char*)&header_version, sizeof(uint8_t)); - ss.write((const char*)&offset, sizeof(uint64_t)); - ss.write((const char*)&ntags, sizeof(uint64_t)); - - for (auto& tag : tags) { - tag.serialize(sb); - } - - return sb.str(); -} - -size_t parse_tag_header(zmq::message_t& msg, - uint64_t& offset_out, - std::vector<gr::tag_t>& tags_out) -{ - membuf sb(msg.data(), msg.size()); - std::istream iss(&sb); - - size_t min_len = - sizeof(uint16_t) + sizeof(uint8_t) + sizeof(uint64_t) + sizeof(uint64_t); - if (msg.size() < min_len) - throw std::runtime_error("incoming zmq msg too small to hold gr tag header!"); - - uint16_t header_magic; - uint8_t header_version; - uint64_t rcv_ntags; - - iss.read((char*)&header_magic, sizeof(uint16_t)); - iss.read((char*)&header_version, sizeof(uint8_t)); - - if (header_magic != GR_HEADER_MAGIC) - throw std::runtime_error("gr header magic does not match!"); - - if (header_version != GR_HEADER_VERSION) - throw std::runtime_error("gr header version does not match!"); - - iss.read((char*)&offset_out, sizeof(uint64_t)); - iss.read((char*)&rcv_ntags, sizeof(uint64_t)); - - for (size_t i = 0; i < rcv_ntags; i++) { - gr::tag_t newtag = tag_t::deserialize(sb); - tags_out.push_back(newtag); - } - - return msg.size() - sb.in_avail(); -} -} /* namespace zeromq */ -} /* namespace gr */ - -// vim: ts=2 sw=2 expandtab diff --git a/blocklib/zeromq/lib/tag_headers.h b/blocklib/zeromq/lib/tag_headers.h deleted file mode 100644 index b8b7a09b1..000000000 --- a/blocklib/zeromq/lib/tag_headers.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2014 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef ZEROMQ_TAG_HEADERS_H -#define ZEROMQ_TAG_HEADERS_H - -#include "zmq_common_impl.h" -#include <gnuradio/tag.h> - -namespace gr { -namespace zeromq { - -std::string gen_tag_header(uint64_t offset, const std::vector<gr::tag_t>& tags); -size_t parse_tag_header(zmq::message_t& msg, - uint64_t& offset_out, - std::vector<gr::tag_t>& tags_out); - -} /* namespace zeromq */ -} /* namespace gr */ - -#endif /* ZEROMQ_TAG_HEADERS_H */ diff --git a/blocklib/zeromq/lib/zmq_common_impl.h b/blocklib/zeromq/lib/zmq_common_impl.h deleted file mode 100644 index fc08ef301..000000000 --- a/blocklib/zeromq/lib/zmq_common_impl.h +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2019 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ -#pragma once - -#include <zmq.hpp> diff --git a/blocklib/zeromq/pub_sink/pub_sink.yml b/blocklib/zeromq/pub_sink/pub_sink.yml deleted file mode 100644 index f65b4a70f..000000000 --- a/blocklib/zeromq/pub_sink/pub_sink.yml +++ /dev/null @@ -1,55 +0,0 @@ -module: zeromq -block: pub_sink -label: PUB Sink -blocktype: sync_block -category: '[Core]/ZeroMQ Interfaces' - -# Example Parameters -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: pass_tags - label: Pass Tags - dtype: bool - settable: false - default: "false" - - id: hwm - label: HWM - dtype: int - settable: false - default: -1 - - id: key - label: Key - dtype: string - settable: false - default: "\"\"" - - id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - -callbacks: -- id: last_endpoint - return: std::string - const: true - # inherited: true - -ports: - - domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -implementations: -- id: cpu - -file_format: 1 diff --git a/blocklib/zeromq/pub_sink/pub_sink_cpu.cc b/blocklib/zeromq/pub_sink/pub_sink_cpu.cc deleted file mode 100644 index 2a5d9d3f5..000000000 --- a/blocklib/zeromq/pub_sink/pub_sink_cpu.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include "pub_sink_cpu.h" -#include "pub_sink_cpu_gen.h" - -namespace gr { -namespace zeromq { - -pub_sink_cpu::pub_sink_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - base_sink(ZMQ_PUB, - args.itemsize, - args.address, - args.timeout, - args.pass_tags, - args.hwm, - args.key) -{ -} - -work_return_t pub_sink_cpu::work(work_io& wio) -{ - auto noutput_items = wio.inputs()[0].n_items; - auto nread = wio.inputs()[0].nitems_read(); - auto nsent = send_message(wio.inputs()[0].raw_items(), - noutput_items, - nread, - wio.inputs()[0].tags_in_window(0, noutput_items)); - wio.consume_each(nsent); - return work_return_t::OK; -} - - -} // namespace zeromq -} // namespace gr diff --git a/blocklib/zeromq/pub_sink/pub_sink_cpu.h b/blocklib/zeromq/pub_sink/pub_sink_cpu.h deleted file mode 100644 index e55d125e7..000000000 --- a/blocklib/zeromq/pub_sink/pub_sink_cpu.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "base.h" -#include <gnuradio/zeromq/pub_sink.h> - -namespace gr { -namespace zeromq { - -class pub_sink_cpu : public virtual pub_sink, public virtual base_sink -{ -public: - pub_sink_cpu(block_args args); - work_return_t work(work_io&) override; - std::string last_endpoint() const override { return base_sink::last_endpoint(); } - - // Since vsize can be set as 0, then inferred on flowgraph init, set it during start() - bool start() override - { - set_vsize(this->input_stream_ports()[0]->itemsize()); - return pub_sink::start(); - } - -private: - // private variables here -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/pull_msg_source/pull_msg_source.yml b/blocklib/zeromq/pull_msg_source/pull_msg_source.yml deleted file mode 100644 index 3cde228af..000000000 --- a/blocklib/zeromq/pull_msg_source/pull_msg_source.yml +++ /dev/null @@ -1,37 +0,0 @@ -module: zeromq -block: pull_msg_source -label: Pull Msg Source -blocktype: sync_block -category: '[Core]/ZeroMQ Interfaces' - -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: bind - label: Bind - dtype: bool - settable: false - default: "false" - -callbacks: -- id: last_endpoint - return: std::string - const: true - -ports: -- domain: message - id: out - direction: output - -implementations: -- id: cpu -# - id: cuda - -file_format: 1
\ No newline at end of file diff --git a/blocklib/zeromq/pull_msg_source/pull_msg_source_cpu.cc b/blocklib/zeromq/pull_msg_source/pull_msg_source_cpu.cc deleted file mode 100644 index 94c81afb6..000000000 --- a/blocklib/zeromq/pull_msg_source/pull_msg_source_cpu.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014,2019 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "pull_msg_source_cpu.h" -#include "pull_msg_source_cpu_gen.h" - -#include <chrono> - -namespace { -constexpr int LINGER_DEFAULT = 1000; // 1 second. -} - -namespace gr { -namespace zeromq { - -pull_msg_source_cpu::pull_msg_source_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - d_timeout(args.timeout), - d_context(1), - d_socket(d_context, ZMQ_PULL) -{ - - d_socket.set(zmq::sockopt::linger, LINGER_DEFAULT); - - if (args.bind) { - d_socket.bind(args.address); - } - else { - d_socket.connect(args.address); - } -} - -bool pull_msg_source_cpu::start() -{ - d_finished = false; - d_thread = std::thread([this] { readloop(); }); - return block::start(); -} - -bool pull_msg_source_cpu::stop() -{ - d_finished = true; - if (d_thread.joinable()) { - d_thread.join(); - } - return block::stop(); -} - -void pull_msg_source_cpu::readloop() -{ - using namespace std::chrono_literals; - while (!d_finished) { - - zmq::pollitem_t items[] = { { static_cast<void*>(d_socket), 0, ZMQ_POLLIN, 0 } }; - zmq::poll(&items[0], 1, std::chrono::milliseconds{ d_timeout }); - - // If we got a reply, process - if (items[0].revents & ZMQ_POLLIN) { - - // Receive data - zmq::message_t msg; - const bool ok = bool(d_socket.recv(msg)); - - if (!ok) { - // Should not happen, we've checked POLLIN. - d_logger->error("Failed to receive message."); - std::this_thread::sleep_for(100us); - continue; - } - - std::string buf(static_cast<char*>(msg.data()), msg.size()); - std::stringbuf sb(buf); - try { - auto m = pmtf::pmt::deserialize(sb); - d_msg_out->post(m); - } catch (...) { // Take out PMT specific exception for now - d_logger->error("Invalid PMT message"); - } - } - else { - std::this_thread::sleep_for(100us); - } - } -} - - -} // namespace zeromq -} // namespace gr diff --git a/blocklib/zeromq/pull_msg_source/pull_msg_source_cpu.h b/blocklib/zeromq/pull_msg_source/pull_msg_source_cpu.h deleted file mode 100644 index a31704ffd..000000000 --- a/blocklib/zeromq/pull_msg_source/pull_msg_source_cpu.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014,2019 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/zeromq/pull_msg_source.h> - -#include <zmq.hpp> -#include <thread> - -namespace gr { -namespace zeromq { - -class pull_msg_source_cpu : public virtual pull_msg_source -{ -public: - pull_msg_source_cpu(block_args args); - bool start() override; - bool stop() override; - std::string last_endpoint() const override - { - return d_socket.get(zmq::sockopt::last_endpoint); - } - -private: - bool d_finished; - int d_timeout; // microseconds, -1 is blocking - zmq::context_t d_context; - zmq::socket_t d_socket; - std::thread d_thread; - - - void readloop(); -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/pull_source/pull_source.yml b/blocklib/zeromq/pull_source/pull_source.yml deleted file mode 100644 index 491211407..000000000 --- a/blocklib/zeromq/pull_source/pull_source.yml +++ /dev/null @@ -1,43 +0,0 @@ -module: zeromq -block: pull_source -label: PULL Source -blocktype: sync_block -category: '[Core]/ZeroMQ Interfaces' -# inherits: base - -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: pass_tags - label: Pass Tags - dtype: bool - settable: false - default: "false" - - id: hwm - label: HWM - dtype: int - settable: false - default: -1 - - id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 -ports: - - domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - -implementations: - - id: cpu - -file_format: 1 diff --git a/blocklib/zeromq/pull_source/pull_source_cpu.cc b/blocklib/zeromq/pull_source/pull_source_cpu.cc deleted file mode 100644 index 6331db2cc..000000000 --- a/blocklib/zeromq/pull_source/pull_source_cpu.cc +++ /dev/null @@ -1,53 +0,0 @@ -#include "pull_source_cpu.h" -#include "pull_source_cpu_gen.h" - -#include <chrono> -#include <thread> - -namespace gr { -namespace zeromq { - -pull_source_cpu::pull_source_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - base_source( - ZMQ_PULL, args.itemsize, args.address, args.timeout, args.pass_tags, args.hwm) -{ -} - -work_return_t pull_source_cpu::work(work_io& wio) -{ - - auto noutput_items = wio.outputs()[0].n_items; - bool first = true; - size_t done = 0; - - /* Process as much as we can */ - while (1) { - if (has_pending()) { - /* Flush anything pending */ - done += flush_pending(wio.outputs()[0], noutput_items - done, done); - - /* No more space ? */ - if (done == noutput_items) - break; - } - else { - /* Try to get the next message */ - if (!load_message(first)) { - // Launch a thread to come back and try again some time later - come_back_later(100); - break; /* No message, we're done for now */ - } - - /* Not the first anymore */ - first = false; - } - } - - wio.outputs()[0].n_produced = done; - return work_return_t::OK; -} - - -} // namespace zeromq -} // namespace gr diff --git a/blocklib/zeromq/pull_source/pull_source_cpu.h b/blocklib/zeromq/pull_source/pull_source_cpu.h deleted file mode 100644 index 157a9ba45..000000000 --- a/blocklib/zeromq/pull_source/pull_source_cpu.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "base.h" -#include <gnuradio/zeromq/pull_source.h> - -namespace gr { -namespace zeromq { - -class pull_source_cpu : public virtual pull_source, public virtual base_source -{ -public: - pull_source_cpu(block_args args); - work_return_t work(work_io&) override; - - // Since vsize can be set as 0, then inferred on flowgraph init, set it during start() - bool start() override - { - set_vsize(this->output_stream_ports()[0]->itemsize()); - return pull_source::start(); - } -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/push_msg_sink/push_msg_sink.yml b/blocklib/zeromq/push_msg_sink/push_msg_sink.yml deleted file mode 100644 index 172631951..000000000 --- a/blocklib/zeromq/push_msg_sink/push_msg_sink.yml +++ /dev/null @@ -1,38 +0,0 @@ -module: zeromq -block: push_msg_sink -label: Push Msg Sink -blocktype: block -category: '[Core]/ZeroMQ Interfaces' - -# Example Parameters -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: bind - label: Bind - dtype: bool - settable: false - default: "true" - -callbacks: -- id: last_endpoint - return: std::string - const: true - -ports: -- domain: message - id: in - direction: input - -implementations: -- id: cpu -# - id: cuda - -file_format: 1 diff --git a/blocklib/zeromq/push_msg_sink/push_msg_sink_cpu.cc b/blocklib/zeromq/push_msg_sink/push_msg_sink_cpu.cc deleted file mode 100644 index dd044868d..000000000 --- a/blocklib/zeromq/push_msg_sink/push_msg_sink_cpu.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "push_msg_sink_cpu.h" -#include "push_msg_sink_cpu_gen.h" - -namespace { -constexpr int LINGER_DEFAULT = 1000; // 1 second. -} - -namespace gr { -namespace zeromq { - -push_msg_sink_cpu::push_msg_sink_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - d_timeout(args.timeout), - d_context(1), - d_socket(d_context, ZMQ_PUSH) -{ - - d_socket.set(zmq::sockopt::linger, LINGER_DEFAULT); - - if (args.bind) { - d_socket.bind(args.address); - } - else { - d_socket.connect(args.address); - } -} - -void push_msg_sink_cpu::handle_msg_in(pmtf::pmt msg) -{ - std::stringbuf sb(""); - msg.serialize(sb); - std::string s = sb.str(); - zmq::message_t zmsg(s.size()); - memcpy(zmsg.data(), s.c_str(), s.size()); - d_socket.send(zmsg, zmq::send_flags::none); -} - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/push_msg_sink/push_msg_sink_cpu.h b/blocklib/zeromq/push_msg_sink/push_msg_sink_cpu.h deleted file mode 100644 index ad8e01d4e..000000000 --- a/blocklib/zeromq/push_msg_sink/push_msg_sink_cpu.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014 Free Software Foundation, Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <gnuradio/zeromq/push_msg_sink.h> - -#include <zmq.hpp> - -namespace gr { -namespace zeromq { - -class push_msg_sink_cpu : public virtual push_msg_sink -{ -public: - push_msg_sink_cpu(block_args args); - - std::string last_endpoint() const override - { - return d_socket.get(zmq::sockopt::last_endpoint); - } - -private: - int d_timeout; // microseconds, -1 is blocking - zmq::context_t d_context; - zmq::socket_t d_socket; - - void handle_msg_in(pmtf::pmt msg) override; -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/push_sink/push_sink.yml b/blocklib/zeromq/push_sink/push_sink.yml deleted file mode 100644 index 9e45debb1..000000000 --- a/blocklib/zeromq/push_sink/push_sink.yml +++ /dev/null @@ -1,51 +0,0 @@ -module: zeromq -block: push_sink -label: PUSH Sink -blocktype: sync_block -category: '[Core]/ZeroMQ Interfaces' -# inherits: gr::zeromq::base -# includes: -# - gnuradio/zeromq/base.h - -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: pass_tags - label: Pass Tags - dtype: bool - settable: false - default: "false" - - id: hwm - label: HWM - dtype: int - settable: false - default: -1 - - id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 -callbacks: -- id: last_endpoint - return: std::string - const: true - # inherited: true - -ports: - - domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -implementations: - - id: cpu - -file_format: 1 diff --git a/blocklib/zeromq/push_sink/push_sink_cpu.cc b/blocklib/zeromq/push_sink/push_sink_cpu.cc deleted file mode 100644 index 85de05df0..000000000 --- a/blocklib/zeromq/push_sink/push_sink_cpu.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include "push_sink_cpu.h" -#include "push_sink_cpu_gen.h" - -namespace gr { -namespace zeromq { - -push_sink_cpu::push_sink_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - base_sink( - ZMQ_PUSH, args.itemsize, args.address, args.timeout, args.pass_tags, args.hwm) -{ -} -work_return_t push_sink_cpu::work(work_io& wio) - -{ - // Poll with a timeout (FIXME: scheduler can't wait for us) - zmq::pollitem_t itemsout[] = { { static_cast<void*>(d_socket), 0, ZMQ_POLLOUT, 0 } }; - zmq::poll(&itemsout[0], 1, std::chrono::milliseconds{ d_timeout }); - - // If we can send something, do it - if (itemsout[0].revents & ZMQ_POLLOUT) { - wio.inputs()[0].n_consumed = - send_message(wio.inputs()[0].raw_items(), - wio.inputs()[0].n_items, - wio.inputs()[0].nitems_read(), - wio.inputs()[0].tags_in_window(0, wio.inputs()[0].n_items)); - } - - return work_return_t::OK; -} - - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/push_sink/push_sink_cpu.h b/blocklib/zeromq/push_sink/push_sink_cpu.h deleted file mode 100644 index f58102cfa..000000000 --- a/blocklib/zeromq/push_sink/push_sink_cpu.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "base.h" -#include <gnuradio/zeromq/push_sink.h> - -namespace gr { -namespace zeromq { - -class push_sink_cpu : public virtual push_sink, public virtual base_sink -{ -public: - push_sink_cpu(block_args args); - work_return_t work(work_io&) override; - std::string last_endpoint() const override { return base_sink::last_endpoint(); } - - // Since vsize can be set as 0, then inferred on flowgraph init, set it during start() - bool start() override - { - set_vsize(this->input_stream_ports()[0]->itemsize()); - return push_sink::start(); - } -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/python/gnuradio/zeromq/.gitignore b/blocklib/zeromq/python/gnuradio/zeromq/.gitignore deleted file mode 100644 index 25d053a52..000000000 --- a/blocklib/zeromq/python/gnuradio/zeromq/.gitignore +++ /dev/null @@ -1 +0,0 @@ -meson.build
\ No newline at end of file diff --git a/blocklib/zeromq/python/gnuradio/zeromq/__init__.py b/blocklib/zeromq/python/gnuradio/zeromq/__init__.py deleted file mode 100644 index ee01dd5ab..000000000 --- a/blocklib/zeromq/python/gnuradio/zeromq/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ - -import os - -try: - from .zeromq_python import * -except ImportError: - dirname, filename = os.path.split(os.path.abspath(__file__)) - __path__.append(os.path.join(dirname, "bindings")) - from .zeromq_python import * diff --git a/blocklib/zeromq/python/gnuradio/zeromq/bindings/.gitignore b/blocklib/zeromq/python/gnuradio/zeromq/bindings/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/zeromq/python/gnuradio/zeromq/bindings/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/zeromq/python/gnuradio/zeromq/bindings/base_pybind.cc b/blocklib/zeromq/python/gnuradio/zeromq/bindings/base_pybind.cc deleted file mode 100644 index 59d6b86a8..000000000 --- a/blocklib/zeromq/python/gnuradio/zeromq/bindings/base_pybind.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2020 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -/***********************************************************************************/ -/* This file is automatically generated using bindtool and can be manually edited */ -/* The following lines can be configured to regenerate this file during cmake */ -/* If manual edits are made, the following tags should be modified accordingly. */ -/* BINDTOOL_GEN_AUTOMATIC(0) */ -/* BINDTOOL_USE_PYGCCXML(0) */ -/* BINDTOOL_HEADER_FILE(firdes.h) */ -/* BINDTOOL_HEADER_FILE_HASH(10cf0c4b9664ba7e2931c2375c13c68c) */ -/***********************************************************************************/ - -#include <pybind11/complex.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/zeromq/base.h> - -void bind_base(py::module& m) -{ - using base = gr::zeromq::base; - using base_source = gr::zeromq::base_source; - using base_sink = gr::zeromq::base_sink; - - py::class_<base, std::shared_ptr<base>> base_class(m, "base"); - py::class_<base_source, std::shared_ptr<base_source>> base_class(m, "base_source"); - py::class_<base_sink, std::shared_ptr<base_sink>> base_class(m, "base_sink"); - - base.def("last_endpoint", &base::last_endpoint) -} diff --git a/blocklib/zeromq/python/gnuradio/zeromq/bindings/meson.build b/blocklib/zeromq/python/gnuradio/zeromq/bindings/meson.build deleted file mode 100644 index 8a830aaec..000000000 --- a/blocklib/zeromq/python/gnuradio/zeromq/bindings/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -# zeromq_pybind_sources = [files('base_pybind.cc')] + zeromq_pybind_sources -# zeromq_pybind_names = ['base'] + zeromq_pybind_names
\ No newline at end of file diff --git a/blocklib/zeromq/rep_sink/rep_sink.yml b/blocklib/zeromq/rep_sink/rep_sink.yml deleted file mode 100644 index 2d6a7647e..000000000 --- a/blocklib/zeromq/rep_sink/rep_sink.yml +++ /dev/null @@ -1,51 +0,0 @@ -module: zeromq -block: rep_sink -label: REP Sink -blocktype: sync_block -category: '[Core]/ZeroMQ Interfaces' -# inherits: gr::zeromq::base -# includes: -# - gnuradio/zeromq/base.h - -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: pass_tags - label: Pass Tags - dtype: bool - settable: false - default: "false" - - id: hwm - label: HWM - dtype: int - settable: false - default: -1 - - id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 -callbacks: -- id: last_endpoint - return: std::string - const: true - # inherited: true - -ports: - - domain: stream - id: in - direction: input - type: untyped - size: parameters/itemsize - -implementations: - - id: cpu - -file_format: 1 diff --git a/blocklib/zeromq/rep_sink/rep_sink_cpu.cc b/blocklib/zeromq/rep_sink/rep_sink_cpu.cc deleted file mode 100644 index 7ad80d471..000000000 --- a/blocklib/zeromq/rep_sink/rep_sink_cpu.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014,2019 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "rep_sink_cpu.h" -#include "rep_sink_cpu_gen.h" - -namespace gr { -namespace zeromq { - -rep_sink_cpu::rep_sink_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - base_sink( - ZMQ_REP, args.itemsize, args.address, args.timeout, args.pass_tags, args.hwm) -{ -} -work_return_t rep_sink_cpu::work(work_io& wio) -{ - auto in = wio.inputs()[0].items<uint8_t>(); - auto noutput_items = wio.inputs()[0].n_items; - bool first = true; - int done = 0; - - /* Process as much as we can */ - while (1) { - /* Wait for a small time (FIXME: scheduler can't wait for us) */ - /* We only wait if its the first iteration, for the others we'll - * let the scheduler retry */ - zmq::pollitem_t items[] = { { static_cast<void*>(d_socket), 0, ZMQ_POLLIN, 0 } }; - zmq::poll(&items[0], 1, std::chrono::milliseconds{ (first ? d_timeout : 0) }); - - /* If we don't have anything, we're done */ - if (!(items[0].revents & ZMQ_POLLIN)) - break; - - /* Get and parse the request */ - zmq::message_t request; - bool ok = bool(d_socket.recv(request)); - - if (!ok) { - // Should not happen, we've checked POLLIN. - d_logger->error("Failed to receive message."); - break; - } - - int nitems_send = noutput_items - done; - if (request.size() >= sizeof(uint32_t)) { - int req = (int)*(static_cast<uint32_t*>(request.data())); - nitems_send = std::min(nitems_send, req); - } - - /* Delegate the actual send */ - done += send_message(in + (done * d_vsize), - nitems_send, - wio.inputs()[0].nitems_read() + done, - wio.inputs()[0].tags_in_window(0, noutput_items)); - - /* Not the first anymore */ - first = false; - } - - wio.inputs()[0].n_consumed = done; - return work_return_t::OK; -} - - -} // namespace zeromq -} // namespace gr diff --git a/blocklib/zeromq/rep_sink/rep_sink_cpu.h b/blocklib/zeromq/rep_sink/rep_sink_cpu.h deleted file mode 100644 index 98d106c4a..000000000 --- a/blocklib/zeromq/rep_sink/rep_sink_cpu.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014,2019 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include "base.h" -#include <gnuradio/zeromq/rep_sink.h> - -namespace gr { -namespace zeromq { - -class rep_sink_cpu : public virtual rep_sink, public virtual base_sink -{ -public: - rep_sink_cpu(block_args args); - work_return_t work(work_io&) override; - std::string last_endpoint() const override { return base_sink::last_endpoint(); } - - // Since vsize can be set as 0, then inferred on flowgraph init, set it during start() - bool start() override - { - set_vsize(this->input_stream_ports()[0]->itemsize()); - return rep_sink::start(); - } -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/req_source/req_source.yml b/blocklib/zeromq/req_source/req_source.yml deleted file mode 100644 index 8980ec8f3..000000000 --- a/blocklib/zeromq/req_source/req_source.yml +++ /dev/null @@ -1,43 +0,0 @@ -module: zeromq -block: req_source -label: REQ Source -blocktype: sync_block -category: '[Core]/ZeroMQ Interfaces' -# inherits: base - -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: pass_tags - label: Pass Tags - dtype: bool - settable: false - default: "false" - - id: hwm - label: HWM - dtype: int - settable: false - default: -1 - - id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 -ports: - - domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - -implementations: - - id: cpu - -file_format: 1 diff --git a/blocklib/zeromq/req_source/req_source_cpu.cc b/blocklib/zeromq/req_source/req_source_cpu.cc deleted file mode 100644 index 2fc6f86b1..000000000 --- a/blocklib/zeromq/req_source/req_source_cpu.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "req_source_cpu.h" -#include "req_source_cpu_gen.h" - -#include <chrono> -#include <thread> - -namespace gr { -namespace zeromq { - -req_source_cpu::req_source_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - base_source( - ZMQ_REQ, args.itemsize, args.address, args.timeout, args.pass_tags, args.hwm) -{ -} - -work_return_t req_source_cpu::work(work_io& wio) -{ - - auto noutput_items = wio.outputs()[0].n_items; - bool first = true; - size_t done = 0; - - /* Process as much as we can */ - while (1) { - if (has_pending()) { - /* Flush anything pending */ - done += flush_pending(wio.outputs()[0], noutput_items - done, done); - - /* No more space ? */ - if (done == noutput_items) - break; - } - else { - - /* Send request if needed */ - if (!d_req_pending) { - /* The REP/REQ pattern state machine guarantees we can send at this point - */ - uint32_t req_len = noutput_items - done; - zmq::message_t request(sizeof(uint32_t)); - memcpy((void*)request.data(), &req_len, sizeof(uint32_t)); - d_socket.send(request, zmq::send_flags::none); - d_req_pending = true; - } - - /* Try to get the next message */ - if (!load_message(first)) { - // Launch a thread to come back and try again some time later - come_back_later(100); - break; /* No message, we're done for now */ - } - - /* Got response */ - d_req_pending = false; - - /* Not the first anymore */ - first = false; - } - } - - wio.outputs()[0].n_produced = done; - return work_return_t::OK; -} - - -} // namespace zeromq -} // namespace gr diff --git a/blocklib/zeromq/req_source/req_source_cpu.h b/blocklib/zeromq/req_source/req_source_cpu.h deleted file mode 100644 index 05cd2b6b8..000000000 --- a/blocklib/zeromq/req_source/req_source_cpu.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013,2014 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include "base.h" -#include <gnuradio/zeromq/req_source.h> - -namespace gr { -namespace zeromq { - -class req_source_cpu : public virtual req_source, public virtual base_source -{ -public: - req_source_cpu(block_args args); - work_return_t work(work_io&) override; - - // Since vsize can be set as 0, then inferred on flowgraph init, set it during start() - bool start() override - { - set_vsize(this->output_stream_ports()[0]->itemsize()); - return req_source::start(); - } - -private: - bool d_req_pending = false; -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/sub_source/sub_source.yml b/blocklib/zeromq/sub_source/sub_source.yml deleted file mode 100644 index b461962c6..000000000 --- a/blocklib/zeromq/sub_source/sub_source.yml +++ /dev/null @@ -1,49 +0,0 @@ -module: zeromq -block: sub_source -label: SUB Source -blocktype: sync_block -category: '[Core]/ZeroMQ Interfaces' - -# Example Parameters -parameters: - - id: address - label: IP Address - dtype: string - settable: false - - id: timeout - label: Timeout - dtype: int - settable: false - default: 100 - - id: pass_tags - label: Pass Tags - dtype: bool - settable: false - default: "false" - - id: hwm - label: HWM - dtype: int - settable: false - default: -1 - - id: key - label: Key - dtype: string - settable: false - default: "\"\"" - - id: itemsize - label: Item Size - dtype: size - settable: false - default: 0 - -ports: - - domain: stream - id: out - direction: output - type: untyped - size: parameters/itemsize - -implementations: - - id: cpu - -file_format: 1
\ No newline at end of file diff --git a/blocklib/zeromq/sub_source/sub_source_cpu.cc b/blocklib/zeromq/sub_source/sub_source_cpu.cc deleted file mode 100644 index 47e8a05b4..000000000 --- a/blocklib/zeromq/sub_source/sub_source_cpu.cc +++ /dev/null @@ -1,60 +0,0 @@ -#include "sub_source_cpu.h" -#include "sub_source_cpu_gen.h" - -#include <chrono> -#include <thread> - -namespace gr { -namespace zeromq { - -sub_source_cpu::sub_source_cpu(block_args args) - : INHERITED_CONSTRUCTORS, - base_source(ZMQ_SUB, - args.itemsize, - args.address, - args.timeout, - args.pass_tags, - args.hwm, - args.key) -{ - - /* Subscribe */ - d_socket.set(zmq::sockopt::subscribe, args.key); -} - -work_return_t sub_source_cpu::work(work_io& wio) -{ - auto noutput_items = wio.outputs()[0].n_items; - bool first = true; - size_t done = 0; - - /* Process as much as we can */ - while (1) { - if (has_pending()) { - /* Flush anything pending */ - done += flush_pending(wio.outputs()[0], noutput_items - done, done); - - /* No more space ? */ - if (done == noutput_items) - break; - } - else { - /* Try to get the next message */ - if (!load_message(first)) { - // Launch a thread to come back and try again some time later - come_back_later(100); - break; /* No message, we're done for now */ - } - - /* Not the first anymore */ - first = false; - } - } - - wio.produce_each(done); - return work_return_t::OK; -} - - -} // namespace zeromq -} // namespace gr diff --git a/blocklib/zeromq/sub_source/sub_source_cpu.h b/blocklib/zeromq/sub_source/sub_source_cpu.h deleted file mode 100644 index 85ec087ac..000000000 --- a/blocklib/zeromq/sub_source/sub_source_cpu.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "base.h" -#include <gnuradio/zeromq/sub_source.h> - -namespace gr { -namespace zeromq { - -class sub_source_cpu : public virtual sub_source, public virtual base_source -{ -public: - sub_source_cpu(block_args args); - work_return_t work(work_io&) override; - - // Since vsize can be set as 0, then inferred on flowgraph init, set it during start() - bool start() override - { - set_vsize(this->output_stream_ports()[0]->itemsize()); - return sub_source::start(); - } - -private: - // private variables here -}; - -} // namespace zeromq -} // namespace gr
\ No newline at end of file diff --git a/blocklib/zeromq/test/.gitignore b/blocklib/zeromq/test/.gitignore deleted file mode 100644 index 01ecb66ff..000000000 --- a/blocklib/zeromq/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!meson.build
\ No newline at end of file diff --git a/blocklib/zeromq/test/meson.build b/blocklib/zeromq/test/meson.build deleted file mode 100644 index f271695c2..000000000 --- a/blocklib/zeromq/test/meson.build +++ /dev/null @@ -1,10 +0,0 @@ -################################################### -# QA -################################################### - -if GR_ENABLE_PYTHON - test('qa_zeromq_pushpull', py3, args : files('qa_zeromq_pushpull.py'), env: TEST_ENV) - test('qa_zeromq_pull_msg_source', py3, args : files('qa_zeromq_pull_msg_source.py'), env: TEST_ENV) - test('qa_zeromq_pubsub', py3, args : files('qa_zeromq_pubsub.py'), env: TEST_ENV) - test('qa_zeromq_reqrep', py3, args : files('qa_zeromq_reqrep.py'), env: TEST_ENV) -endif diff --git a/blocklib/zeromq/test/qa_zeromq_pubsub.py b/blocklib/zeromq/test/qa_zeromq_pubsub.py deleted file mode 100644 index 4334794d8..000000000 --- a/blocklib/zeromq/test/qa_zeromq_pubsub.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright 2014 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest -from gnuradio import blocks, zeromq -import pmtf -import time - - -def make_tag(key, value, offset, srcid=None): - - if srcid is None: - tag = gr.tag_t(offset, {key: pmtf.pmt(value)}) - else: - tag = gr.tag_t(offset, {key: pmtf.pmt(value), "srcid": pmtf.pmt(srcid)}) - return tag - - -# def compare_tags(a, b): -# return a.offset == b.offset and pmt.equal(a.key, b.key) and \ -# pmt.equal(a.value, b.value) and pmt.equal(a.srcid, b.srcid) - - -class qa_zeromq_pubsub (gr_unittest.TestCase): - - def setUp(self): - self.send_tb = gr.top_block() - self.recv_tb = gr.top_block() - - def tearDown(self): - self.send_tb = None - self.recv_tb = None - - def test_001(self): - vlen = 10 - src_data = list(range(vlen)) * 100 - src = blocks.vector_source_f(src_data, False, vlen) - zeromq_pub_sink = zeromq.pub_sink("tcp://127.0.0.1:0", 0) - address = zeromq_pub_sink.last_endpoint() - zeromq_sub_source = zeromq.sub_source(address, 0) - sink = blocks.vector_sink_f(vlen) - self.send_tb.connect(src, zeromq_pub_sink) - self.recv_tb.connect(zeromq_sub_source, sink) - self.recv_tb.start() - time.sleep(0.5) - self.send_tb.start() - time.sleep(0.5) - self.recv_tb.stop() - self.send_tb.stop() - # self.recv_tb.wait() - # self.send_tb.wait() - self.assertFloatTuplesAlmostEqual(sink.data(), src_data) - - def test_002(self): - # same as test_001, but insert a tag and set key filter - vlen = 10 - src_data = list(range(vlen)) * 100 - - src_tags = tuple([make_tag('key', 'val', 0, 'src'), - make_tag('key', 'val', 1, 'src')]) - - src = blocks.vector_source_f(src_data, False, vlen, tags=src_tags) - zeromq_pub_sink = zeromq.pub_sink( - "tcp://127.0.0.1:0", - 0, - pass_tags=True, - key="filter_key") - address = zeromq_pub_sink.last_endpoint() - zeromq_sub_source = zeromq.sub_source(address, 0, pass_tags=True, key="filter_key") - sink = blocks.vector_sink_f(vlen) - self.send_tb.connect(src, zeromq_pub_sink) - self.recv_tb.connect(zeromq_sub_source, sink) - - # start both flowgraphs - self.recv_tb.start() - time.sleep(0.5) - self.send_tb.start() - time.sleep(0.5) - self.recv_tb.stop() - self.send_tb.stop() - self.recv_tb.wait() - self.send_tb.wait() - - # compare data - self.assertFloatTuplesAlmostEqual(sink.data(), src_data) - - # compare all tags - rx_tags = sink.tags() - self.assertEqual(len(src_tags), len(rx_tags)) - - idx = 0 - for in_tag, out_tag in zip(src_tags, rx_tags): - print(idx) - print(in_tag) - print(out_tag) - self.assertTrue(in_tag == out_tag) - idx += 1 - - -if __name__ == '__main__': - gr_unittest.run(qa_zeromq_pubsub) diff --git a/blocklib/zeromq/test/qa_zeromq_pull_msg_source.py b/blocklib/zeromq/test/qa_zeromq_pull_msg_source.py deleted file mode 100644 index ff161b9c7..000000000 --- a/blocklib/zeromq/test/qa_zeromq_pull_msg_source.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2020 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -"""Unit tests for ZMQ PULL Message Source block""" - -import time -import zmq - -from gnuradio import gr, gr_unittest, blocks, zeromq -import pmtf - - -class qa_zeromq_pull_msg_source(gr_unittest.TestCase): - """Unit tests for ZMQ PULL Message Source block""" - - def setUp(self): - addr = 'tcp://127.0.0.1' - self.context = zmq.Context() - self.zmq_sock = self.context.socket(zmq.PUSH) - port = self.zmq_sock.bind_to_random_port(addr) - - self.zeromq_pull_msg_source = zeromq.pull_msg_source( - ('%s:%s' % (addr, port)), 100) - self.message_debug = blocks.message_debug() - self.tb = gr.top_block() - self.tb.connect( - (self.zeromq_pull_msg_source, 'out'), (self.message_debug, 'store')) - - self.tb.start() - time.sleep(0.1) - - def tearDown(self): - self.tb.stop() - self.tb.wait() - self.zeromq_pull_msg_source = None - self.message_debug = None - self.tb = None - self.zmq_sock.close() - self.context.term() - - def test_valid_pmt(self): - """Test receiving of valid PMT messages""" - msg = pmtf.pmt('test_valid_pmt') - self.zmq_sock.send(bytes(msg.serialize())) - for _ in range(10): - if self.message_debug.num_messages() > 0: - break - time.sleep(0.2) - self.assertEqual(1, self.message_debug.num_messages()) - self.assertEqual(msg(), self.message_debug.get_message(0)()) - - # def test_invalid_pmt(self): - # """Test receiving of invalid PMT messages""" - # self.zmq_sock.send_string('test_invalid_pmt') - # time.sleep(0.1) - # self.assertEqual(0, self.message_debug.num_messages()()) - - -if __name__ == '__main__': - gr_unittest.run(qa_zeromq_pull_msg_source) diff --git a/blocklib/zeromq/test/qa_zeromq_pushpull.py b/blocklib/zeromq/test/qa_zeromq_pushpull.py deleted file mode 100644 index ea18ed7b1..000000000 --- a/blocklib/zeromq/test/qa_zeromq_pushpull.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2014 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest, blocks, zeromq -import time - - -class qa_zeromq_pushpull (gr_unittest.TestCase): - - def setUp(self): - self.send_tb = gr.top_block() - self.recv_tb = gr.top_block() - - def tearDown(self): - self.send_tb = None - self.recv_tb = None - - def test_001(self): - vlen = 10 - src_data = list(range(vlen)) * 100 - src = blocks.vector_source_f(src_data, False, vlen) - zeromq_push_sink = zeromq.push_sink("tcp://127.0.0.1:0") - address = zeromq_push_sink.last_endpoint() - zeromq_pull_source = zeromq.pull_source(address, 0) - sink = blocks.vector_sink_f(vlen) - self.send_tb.connect(src, zeromq_push_sink) - self.recv_tb.connect(zeromq_pull_source, sink) - self.recv_tb.start() - # time.sleep(0.5) - self.send_tb.start() - time.sleep(0.5) - self.recv_tb.stop() - self.send_tb.stop() - self.assertFloatTuplesAlmostEqual(sink.data(), src_data) - - -if __name__ == '__main__': - gr_unittest.run(qa_zeromq_pushpull) diff --git a/blocklib/zeromq/test/qa_zeromq_reqrep.py b/blocklib/zeromq/test/qa_zeromq_reqrep.py deleted file mode 100644 index 733bf2f03..000000000 --- a/blocklib/zeromq/test/qa_zeromq_reqrep.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# Copyright 2014 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest -from gnuradio import blocks, zeromq -import time - - -class qa_zeromq_reqrep (gr_unittest.TestCase): - - def setUp(self): - self.send_tb = gr.top_block() - self.recv_tb = gr.top_block() - - def tearDown(self): - self.send_tb = None - self.recv_tb = None - - def test_001(self): - vlen = 10 - src_data = list(range(vlen)) * 100 - src = blocks.vector_source_f(src_data, False, vlen) - zeromq_rep_sink = zeromq.rep_sink("tcp://127.0.0.1:0", 0) - address = zeromq_rep_sink.last_endpoint() - zeromq_req_source = zeromq.req_source(address, 0) - sink = blocks.vector_sink_f(vlen) - self.send_tb.connect(src, zeromq_rep_sink) - self.recv_tb.connect(zeromq_req_source, sink) - self.recv_tb.start() - time.sleep(0.5) - self.send_tb.start() - time.sleep(0.5) - self.recv_tb.stop() - self.send_tb.stop() - self.recv_tb.wait() - self.send_tb.wait() - self.assertFloatTuplesAlmostEqual(sink.data(), src_data) - - -if __name__ == '__main__': - gr_unittest.run(qa_zeromq_reqrep) diff --git a/gr/include/gnuradio/buffer_cpu_host.h b/gr/include/gnuradio/buffer_cpu_host.h deleted file mode 100644 index fbc9a8429..000000000 --- a/gr/include/gnuradio/buffer_cpu_host.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include <algorithm> -#include <cstdint> -#include <cstring> -#include <memory> -#include <vector> - -#include <gnuradio/buffer_sm.h> - -namespace gr { -enum class buffer_cpu_host_type { H2H, D2D, H2D, D2H, UNKNOWN }; -class buffer_cpu_host_reader; -class buffer_cpu_host : public buffer_sm -{ -private: - std::vector<uint8_t> _host_buffer; - std::vector<uint8_t> _device_buffer; - buffer_cpu_host_type _transfer_type = buffer_cpu_host_type::H2H; - -public: - buffer_cpu_host(size_t num_items, - size_t item_size, - buffer_cpu_host_type type, - std::shared_ptr<buffer_properties> buf_properties); - - static buffer_uptr make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties); - - void* read_ptr(size_t index) override; - void* write_ptr() override; - - void post_write(int num_items) override; - - buffer_cpu_host_type transfer_type() { return _transfer_type; } - - buffer_reader_uptr add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize) override; - - virtual bool output_blocked_callback(bool force = false) override - { - switch (_transfer_type) { - case buffer_cpu_host_type::H2H: - case buffer_cpu_host_type::H2D: - case buffer_cpu_host_type::D2D: - case buffer_cpu_host_type::D2H: - return output_blocked_callback_logic(force, std::memmove); - default: - return false; - } - } -}; - -class buffer_cpu_host_reader : public buffer_sm_reader -{ -private: - buffer_cpu_host* _buffer_cpu_host; - -public: - buffer_cpu_host_reader(buffer_cpu_host* bufp, - std::shared_ptr<buffer_properties> buf_props, - size_t itemsize, - size_t read_index = 0) - : buffer_sm_reader(bufp, itemsize, buf_props, read_index), _buffer_cpu_host(bufp) - { - } - - virtual bool input_blocked_callback(size_t items_required) override - { - // Only singly mapped buffers need to do anything with this callback - // std::scoped_lock guard(*(_buffer->mutex())); - std::lock_guard<std::mutex> guard(*(_buffer->mutex())); - - auto items_avail = items_available(); - - // GR_LOG_DEBUG(d_debug_logger, - // "input_blocked_callback: items_avail {}, _read_index {}, " - // "_write_index {}, items_required {}", - // items_avail, - // _read_index, - // _buffer->write_index(), - // items_required); - - // GR_LOG_DEBUG(d_debug_logger, - // "input_blocked_callback: total_written {}, total_read {}", - // _buffer->total_written(), - // total_read()); - - - // Maybe adjust read pointers from min read index? - // This would mean that *all* readers must be > (passed) the write index - if (items_avail < items_required && _buffer->write_index() < read_index()) { - // GR_LOG_DEBUG(d_debug_logger, "Calling adjust_buffer_data "); - - switch (_buffer_cpu_host->transfer_type()) { - case buffer_cpu_host_type::H2H: - case buffer_cpu_host_type::H2D: - case buffer_cpu_host_type::D2D: - case buffer_cpu_host_type::D2H: - return _buffer_cpu_host->adjust_buffer_data(std::memcpy, std::memmove); - default: - return false; - } - } - - return false; - } -}; - -class buffer_cpu_host_properties : public buffer_properties -{ -public: - // using std::shared_ptr<buffer_properties> = sptr; - buffer_cpu_host_properties(buffer_cpu_host_type buffer_type_) - : buffer_properties(), _buffer_type(buffer_type_) - { - _bff = buffer_cpu_host::make; - } - buffer_cpu_host_type buffer_type() { return _buffer_type; } - static std::shared_ptr<buffer_properties> - make(buffer_cpu_host_type buffer_type_ = buffer_cpu_host_type::H2H) - { - return std::static_pointer_cast<buffer_properties>( - std::make_shared<buffer_cpu_host_properties>(buffer_type_)); - } - -private: - buffer_cpu_host_type _buffer_type; -}; - -#define BUFFER_CPU_HOST_ARGS_H2H \ - buffer_cpu_host_properties::make(buffer_cpu_host_type::H2H) -#define BUFFER_CPU_HOST_ARGS_H2D \ - buffer_cpu_host_properties::make(buffer_cpu_host_type::H2D) -#define BUFFER_CPU_HOST_ARGS_D2H \ - buffer_cpu_host_properties::make(buffer_cpu_host_type::D2H) -#define BUFFER_CPU_HOST_ARGS_D2D \ - buffer_cpu_host_properties::make(buffer_cpu_host_type::D2D) - - -} // namespace gr diff --git a/gr/include/gnuradio/buffer_cuda.h b/gr/include/gnuradio/buffer_cuda.h deleted file mode 100644 index 7874716bd..000000000 --- a/gr/include/gnuradio/buffer_cuda.h +++ /dev/null @@ -1,84 +0,0 @@ -#include <string.h> -#include <algorithm> -#include <cstdint> -#include <memory> -#include <mutex> -#include <vector> - -#include <gnuradio/buffer.h> -#include <cuda.h> -#include <cuda_runtime.h> - -namespace gr { -enum class buffer_cuda_type { D2D, H2D, D2H, UNKNOWN }; - -class buffer_cuda : public buffer -{ -private: - uint8_t* _host_buffer; - uint8_t* _device_buffer; - buffer_cuda_type _type = buffer_cuda_type::UNKNOWN; - cudaStream_t stream; - -public: - using sptr = std::shared_ptr<buffer_cuda>; - buffer_cuda(size_t num_items, - size_t item_size, - buffer_cuda_type type, - std::shared_ptr<buffer_properties> buf_properties); - ~buffer_cuda(); - - static buffer_uptr make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties); - - void* read_ptr(size_t read_index); - void* write_ptr(); - - virtual void post_write(int num_items); - - virtual buffer_reader_uptr add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize); -}; - -class buffer_cuda_reader : public buffer_reader -{ -public: - buffer_cuda_reader(buffer* bufp, - std::shared_ptr<buffer_properties> buf_props, - size_t itemsize, - size_t read_index) - : buffer_reader(bufp, buf_props, itemsize, read_index) - { - } - - virtual void post_read(int num_items); -}; - -class buffer_cuda_properties : public buffer_properties -{ -public: - // using std::shared_ptr<buffer_properties> = sptr; - buffer_cuda_properties(buffer_cuda_type buffer_type_) - : buffer_properties(), _buffer_type(buffer_type_) - { - _bff = buffer_cuda::make; - } - buffer_cuda_type buffer_type() { return _buffer_type; } - static std::shared_ptr<buffer_properties> - make(buffer_cuda_type buffer_type_ = buffer_cuda_type::D2D) - { - return std::static_pointer_cast<buffer_properties>( - std::make_shared<buffer_cuda_properties>(buffer_type_)); - } - -private: - buffer_cuda_type _buffer_type; -}; - - -} // namespace gr - -#define CUDA_BUFFER_ARGS_H2D buffer_cuda_properties::make(buffer_cuda_type::H2D) -#define CUDA_BUFFER_ARGS_D2H buffer_cuda_properties::make(buffer_cuda_type::D2H) -#define CUDA_BUFFER_ARGS_D2D buffer_cuda_properties::make(buffer_cuda_type::D2D) diff --git a/gr/include/gnuradio/buffer_cuda_pinned.h b/gr/include/gnuradio/buffer_cuda_pinned.h deleted file mode 100644 index 809902b06..000000000 --- a/gr/include/gnuradio/buffer_cuda_pinned.h +++ /dev/null @@ -1,67 +0,0 @@ -#include <string.h> -#include <algorithm> -#include <cstdint> -#include <memory> -#include <mutex> -#include <vector> - -#include <gnuradio/buffer.h> - -namespace gr { - - -class buffer_cuda_pinned : public buffer -{ -private: - uint8_t* _pinned_buffer; - -public: - using sptr = std::shared_ptr<buffer_cuda_pinned>; - buffer_cuda_pinned(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buf_properties); - ~buffer_cuda_pinned(); - - static buffer_uptr make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties); - void* read_ptr(size_t index); - void* write_ptr(); - virtual void post_write(int num_items); - - virtual buffer_reader_uptr add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize); -}; -class buffer_cuda_pinned_reader : public buffer_reader -{ -public: - buffer_cuda_pinned_reader(buffer* bufp, - std::shared_ptr<buffer_properties> buf_props, - size_t itemsize, - size_t read_index) - : buffer_reader(bufp, buf_props, itemsize, read_index) - { - } - - virtual void post_read(int num_items); -}; - -class buffer_cuda_pinned_properties : public buffer_properties -{ -public: - // using std::shared_ptr<buffer_properties> = sptr; - buffer_cuda_pinned_properties() : buffer_properties() - { - _bff = buffer_cuda_pinned::make; - } - static std::shared_ptr<buffer_properties> make() - { - return std::dynamic_pointer_cast<buffer_properties>( - std::make_shared<buffer_cuda_pinned_properties>()); - } -}; - - -} // namespace gr - -#define CUDA_BUFFER_PINNED_ARGS buffer_cuda_pinned_properties::make() diff --git a/gr/include/gnuradio/buffer_cuda_sm.h b/gr/include/gnuradio/buffer_cuda_sm.h deleted file mode 100644 index e8a38b7f0..000000000 --- a/gr/include/gnuradio/buffer_cuda_sm.h +++ /dev/null @@ -1,151 +0,0 @@ -#include <string.h> -#include <algorithm> -#include <cstdint> -#include <memory> -#include <mutex> -#include <vector> - -#include <gnuradio/buffer_sm.h> -#include <cuda.h> -#include <cuda_runtime.h> - -namespace gr { -enum class buffer_cuda_sm_type { D2D, H2D, D2H, UNKNOWN }; - -class buffer_cuda_sm : public buffer_sm -{ -private: - uint8_t* _host_buffer; - uint8_t* _device_buffer; - buffer_cuda_sm_type _type = buffer_cuda_sm_type::UNKNOWN; - cudaStream_t stream; - -public: - using sptr = std::shared_ptr<buffer_cuda_sm>; - buffer_cuda_sm(size_t num_items, - size_t item_size, - buffer_cuda_sm_type type, - std::shared_ptr<buffer_properties> buf_properties); - ~buffer_cuda_sm(); - - static buffer_uptr make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties); - - void* read_ptr(size_t read_index); - void* write_ptr(); - buffer_cuda_sm_type type() { return _type; } - - virtual void post_write(int num_items); - - virtual buffer_reader_uptr add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize); - - static void* cuda_memcpy(void* dest, const void* src, std::size_t count); - static void* cuda_memmove(void* dest, const void* src, std::size_t count); - - virtual bool output_blocked_callback(bool force = false) override - { - switch (_type) { - case buffer_cuda_sm_type::H2D: - return output_blocked_callback_logic(force, std::memmove); - case buffer_cuda_sm_type::D2D: - case buffer_cuda_sm_type::D2H: - return output_blocked_callback_logic(force, cuda_memmove); - default: - return false; - } - } -}; - -class buffer_cuda_sm_reader : public buffer_sm_reader -{ -private: - // logger_ptr d_logger; - // logger_ptr d_debug_logger; - - buffer_cuda_sm* _buffer_cuda_sm; - -public: - buffer_cuda_sm_reader(buffer_cuda_sm* buffer, - std::shared_ptr<buffer_properties> buf_props, - size_t itemsize, - size_t read_index) - : buffer_sm_reader(buffer, itemsize, buf_props, read_index) - { - _buffer_cuda_sm = buffer; - // gr::configure_default_loggers(d_logger, d_debug_logger, "buffer_cuda_sm"); - } - - // virtual void post_read(int num_items); - - virtual bool input_blocked_callback(size_t items_required) override - { - // Only singly mapped buffers need to do anything with this callback - // std::scoped_lock guard(*(_buffer->mutex())); - std::lock_guard<std::mutex> guard(*(_buffer->mutex())); - - auto items_avail = items_available(); - - // GR_LOG_DEBUG(d_debug_logger, - // "input_blocked_callback: items_avail {}, _read_index {}, " - // "_write_index {}, items_required {}", - // items_avail, - // _read_index, - // _buffer->write_index(), - // items_required); - - // GR_LOG_DEBUG(d_debug_logger, - // "input_blocked_callback: total_written {}, total_read {}", - // _buffer->total_written(), - // total_read()); - - - // Maybe adjust read pointers from min read index? - // This would mean that *all* readers must be > (passed) the write index - if (items_avail < items_required && _buffer->write_index() < read_index()) { - // GR_LOG_DEBUG(d_debug_logger, "Calling adjust_buffer_data "); - - switch (_buffer_cuda_sm->type()) { - case buffer_cuda_sm_type::H2D: - case buffer_cuda_sm_type::D2D: - return _buffer_sm->adjust_buffer_data(buffer_cuda_sm::cuda_memcpy, - buffer_cuda_sm::cuda_memmove); - case buffer_cuda_sm_type::D2H: - return _buffer_sm->adjust_buffer_data(std::memcpy, std::memmove); - default: - return false; - } - } - - return false; - } -}; - -class buffer_cuda_sm_properties : public buffer_properties -{ -public: - // using std::shared_ptr<buffer_properties> = sptr; - buffer_cuda_sm_properties(buffer_cuda_sm_type buffer_type_) - : buffer_properties(), _buffer_type(buffer_type_) - { - _bff = buffer_cuda_sm::make; - } - buffer_cuda_sm_type buffer_type() { return _buffer_type; } - static std::shared_ptr<buffer_properties> - make(buffer_cuda_sm_type buffer_type_ = buffer_cuda_sm_type::D2D) - { - return std::static_pointer_cast<buffer_properties>( - std::make_shared<buffer_cuda_sm_properties>(buffer_type_)); - } - -private: - buffer_cuda_sm_type _buffer_type; -}; - - -} // namespace gr - -#define CUDA_BUFFER_SM_ARGS_H2D buffer_cuda_sm_properties::make(buffer_cuda_sm_type::H2D) -#define CUDA_BUFFER_SM_ARGS_D2H buffer_cuda_sm_properties::make(buffer_cuda_sm_type::D2H) -#define CUDA_BUFFER_SM_ARGS_D2D buffer_cuda_sm_properties::make(buffer_cuda_sm_type::D2D) diff --git a/gr/include/gnuradio/buffer_net_zmq.h b/gr/include/gnuradio/buffer_net_zmq.h deleted file mode 100644 index af31c6110..000000000 --- a/gr/include/gnuradio/buffer_net_zmq.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include <algorithm> -#include <cstdint> -#include <cstring> -#include <memory> -#include <vector> - -#include <zmq.hpp> - -#include <gnuradio/buffer.h> - -namespace gr { - - -class buffer_net_zmq_reader; - -class buffer_net_zmq : public buffer -{ -private: - std::vector<uint8_t> _buffer; - - zmq::context_t _context; - zmq::socket_t _socket; - - -public: - using sptr = std::shared_ptr<buffer_net_zmq>; - buffer_net_zmq(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties, - int port); - ~buffer_net_zmq() override{}; - static buffer_uptr make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties); - - void* read_ptr(size_t index) override { return nullptr; } - size_t space_available() override { return _num_items; } - void* write_ptr() override { return _buffer.data(); } - - void post_write(int num_items) override - { - // send the data from buffer over the socket - d_debug_logger->debug("sending {} items", num_items); - auto res = _socket.send(zmq::buffer(write_ptr(), num_items * _item_size), - zmq::send_flags::none); - d_debug_logger->debug("send returned code {}", *res); - } - - buffer_reader_uptr add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize) override - { - // do nothing because readers will be added on zmq connect - return nullptr; - } -}; - -class buffer_net_zmq_reader : public buffer_reader -{ -private: - zmq::context_t _context; - zmq::socket_t _socket; - zmq::message_t _msg; - size_t _msg_idx = 0; - size_t _msg_size = 0; - - // Circular buffer for zmq to write into - gr::buffer_uptr _circbuf; - gr::buffer_reader_uptr _circbuf_rdr; - - logger_ptr d_logger; - logger_ptr d_debug_logger; - -public: - bool _recv_done = false; - static buffer_reader_uptr make(size_t itemsize, - std::shared_ptr<buffer_properties> buf_props); - buffer_net_zmq_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize, - const std::string& ipaddr, - int port); - - ~buffer_net_zmq_reader() override{}; - - bool read_info(buffer_info_t& info) override - { - auto ret = _circbuf_rdr->read_info(info); - return ret; - } - void* read_ptr() override { return _circbuf_rdr->read_ptr(); } - - // Tags not supported yet - const std::vector<tag_t>& tags() const override { return _circbuf->tags(); } - std::vector<tag_t> get_tags(size_t num_items) override { return {}; } - void post_read(int num_items) override - { - d_debug_logger->debug("post_read: {}", num_items); - _circbuf_rdr->post_read(num_items); - } -}; - - -class buffer_net_zmq_properties : public buffer_properties -{ -public: - // using std::shared_ptr<buffer_properties> = sptr; - buffer_net_zmq_properties(const std::string& ipaddr, int port) - : buffer_properties(), _ipaddr(ipaddr), _port(port) - { - _bff = buffer_net_zmq::make; - _brff = buffer_net_zmq_reader::make; - } - ~buffer_net_zmq_properties() override{}; - - static std::shared_ptr<buffer_properties> make(const std::string& ipaddr, - int port = 0) - { - return std::dynamic_pointer_cast<buffer_properties>( - std::make_shared<buffer_net_zmq_properties>(ipaddr, port)); - } - - static std::shared_ptr<buffer_properties> - make_from_params(const std::string& json_str); - - void set_port(int port) { _port = port; } - auto port() { return _port; } - auto ipaddr() { return _ipaddr; } - - std::string to_json() override; - -private: - std::string _ipaddr; - int _port; -}; - -} // namespace gr diff --git a/gr/include/gnuradio/buffer_sm.h b/gr/include/gnuradio/buffer_sm.h deleted file mode 100644 index 73a850eca..000000000 --- a/gr/include/gnuradio/buffer_sm.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include <algorithm> -#include <cstdint> -#include <cstring> -#include <memory> -#include <vector> - -#include <gnuradio/buffer.h> -// #include <gnuradio/logger.h> - -namespace gr { - -typedef void* (*memcpy_func_t)(void* dest, const void* src, std::size_t count); -typedef void* (*memmove_func_t)(void* dest, const void* src, std::size_t count); - -class buffer_sm_reader; -class buffer_sm : public buffer -{ -private: - std::vector<uint8_t> _buffer; - uint8_t* _raw_buffer; - - // logger_ptr d_logger; - // logger_ptr d_debug_logger; - -public: - using sptr = std::shared_ptr<buffer_sm>; - buffer_sm(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buf_properties); - - static buffer_uptr - make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties = nullptr); - - void* read_ptr(size_t index) override; - void* write_ptr() override; - - void post_write(int num_items) override; - - virtual bool - output_blocked_callback_logic(bool force = false, - memmove_func_t memmove_func = std::memmove); - - /*! - * \brief Return true if thread is ready to call the callback, false otherwise - */ - bool output_blkd_cb_ready(int output_multiple) override; - bool output_blocked_callback(bool force = false) override; - size_t space_available() override; - - bool write_info(buffer_info_t& info) override; - buffer_reader_uptr add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize) override; - - bool adjust_buffer_data(memcpy_func_t memcpy_func, memmove_func_t memmove_func); - - // Wipes away the default single mapped buffer and replaces it with something - // defined externally in the derived class - void set_bufp(uint8_t* ptr) - { - _raw_buffer = ptr; - _buffer.resize(0); - } -}; - -class buffer_sm_reader : public buffer_reader -{ -private: - logger_ptr d_logger; - logger_ptr d_debug_logger; - -protected: - buffer_sm* _buffer_sm; - -public: - buffer_sm_reader(buffer_sm* buffer, - size_t itemsize, - std::shared_ptr<buffer_properties> buf_props = nullptr, - size_t read_index = 0); - - void post_read(int num_items) override; - - /*! - * \brief Return true if thread is ready to call input_blocked_callback, - * false otherwise - */ - bool input_blkd_cb_ready(int items_required) override; - bool input_blocked_callback(size_t items_required) override; - size_t bytes_available() override; -}; - - -class buffer_sm_properties : public buffer_properties -{ -public: - buffer_sm_properties(); - - static std::shared_ptr<buffer_properties> make(); -}; - - -#define SM_BUFFER_ARGS buffer_sm_properties::make() - -} // namespace gr diff --git a/gr/include/gnuradio/meson.build b/gr/include/gnuradio/meson.build index 4c5e9d51f..64d995b5d 100644 --- a/gr/include/gnuradio/meson.build +++ b/gr/include/gnuradio/meson.build @@ -8,8 +8,6 @@ runtime_headers = [ 'block_group_properties.h', 'clonable_block.h', 'concurrent_queue.h', - 'buffer_cuda.h', - 'buffer_cuda_pinned.h', 'edge.h', 'flat_graph.h', 'flowgraph.h', @@ -43,12 +41,10 @@ runtime_headers = [ 'sptr_magic.h', 'realtime.h', 'runtime.h', - 'buffer_sm.h', 'executor.h', 'constants.h', 'registry.h', 'high_res_timer.h', - 'custom_lock.h' ] install_headers(runtime_headers, subdir : 'gnuradio') diff --git a/gr/include/moodycamel/LICENSE.md b/gr/include/moodycamel/LICENSE.md deleted file mode 100644 index 519338976..000000000 --- a/gr/include/moodycamel/LICENSE.md +++ /dev/null @@ -1,62 +0,0 @@ -This license file applies to everything in this repository except that which -is explicitly annotated as being written by other authors, i.e. the Boost -queue (included in the benchmarks for comparison), Intel's TBB library (ditto), -dlib::pipe (ditto), -the CDSChecker tool (used for verification), the Relacy model checker (ditto), -and Jeff Preshing's semaphore implementation (used in the blocking queue) which -has a zlib license (embedded in lightweightsempahore.h). - ---- - -Simplified BSD License: - -Copyright (c) 2013-2016, Cameron Desrochers. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, this list of -conditions and the following disclaimer in the documentation and/or other materials -provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---- - -I have also chosen to dual-license under the Boost Software License as an alternative to -the Simplified BSD license above: - -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/gr/include/moodycamel/blockingconcurrentqueue.h b/gr/include/moodycamel/blockingconcurrentqueue.h deleted file mode 100644 index 7db0ef364..000000000 --- a/gr/include/moodycamel/blockingconcurrentqueue.h +++ /dev/null @@ -1,615 +0,0 @@ -// Provides an efficient blocking version of moodycamel::ConcurrentQueue. -// ©2015-2020 Cameron Desrochers. Distributed under the terms of the simplified -// BSD license, available at the top of concurrentqueue.h. -// Also dual-licensed under the Boost Software License (see LICENSE.md) -// Uses Jeff Preshing's semaphore implementation (under the terms of its -// separate zlib license, see lightweightsemaphore.h). - -#pragma once - -#include "concurrentqueue.h" -#include "lightweightsemaphore.h" - -#include <type_traits> -#include <cerrno> -#include <chrono> -#include <ctime> -#include <memory> - -namespace moodycamel { -// This is a blocking version of the queue. It has an almost identical interface to -// the normal non-blocking version, with the addition of various wait_dequeue() methods -// and the removal of producer-specific dequeue methods. -template <typename T, typename Traits = ConcurrentQueueDefaultTraits> -class BlockingConcurrentQueue -{ -private: - typedef ::moodycamel::ConcurrentQueue<T, Traits> ConcurrentQueue; - typedef ::moodycamel::LightweightSemaphore LightweightSemaphore; - -public: - typedef typename ConcurrentQueue::producer_token_t producer_token_t; - typedef typename ConcurrentQueue::consumer_token_t consumer_token_t; - - typedef typename ConcurrentQueue::index_t index_t; - typedef typename ConcurrentQueue::size_t size_t; - typedef typename std::make_signed<size_t>::type ssize_t; - - static const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE; - static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = - ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD; - static const size_t EXPLICIT_INITIAL_INDEX_SIZE = - ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE; - static const size_t IMPLICIT_INITIAL_INDEX_SIZE = - ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE; - static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = - ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; - static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = - ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE; - static const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE; - -public: - // Creates a queue with at least `capacity` element slots; note that the - // actual number of elements that can be inserted without additional memory - // allocation depends on the number of producers and the block size (e.g. if - // the block size is equal to `capacity`, only a single block will be allocated - // up-front, which means only a single producer will be able to enqueue elements - // without an extra allocation -- blocks aren't shared between producers). - // This method is not thread safe -- it is up to the user to ensure that the - // queue is fully constructed before it starts being used by other threads (this - // includes making the memory effects of construction visible, possibly with a - // memory barrier). - explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) - : inner(capacity), - sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), - &BlockingConcurrentQueue::template destroy<LightweightSemaphore>) - { - assert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == - &((BlockingConcurrentQueue*)1)->inner && - "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); - if (!sema) { - MOODYCAMEL_THROW(std::bad_alloc()); - } - } - - BlockingConcurrentQueue(size_t minCapacity, - size_t maxExplicitProducers, - size_t maxImplicitProducers) - : inner(minCapacity, maxExplicitProducers, maxImplicitProducers), - sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), - &BlockingConcurrentQueue::template destroy<LightweightSemaphore>) - { - assert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == - &((BlockingConcurrentQueue*)1)->inner && - "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); - if (!sema) { - MOODYCAMEL_THROW(std::bad_alloc()); - } - } - - // Disable copying and copy assignment - BlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; - BlockingConcurrentQueue& - operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; - - // Moving is supported, but note that it is *not* a thread-safe operation. - // Nobody can use the queue while it's being moved, and the memory effects - // of that move must be propagated to other threads before they can use it. - // Note: When a queue is moved, its tokens are still valid but can only be - // used with the destination queue (i.e. semantically they are moved along - // with the queue itself). - BlockingConcurrentQueue(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT - : inner(std::move(other.inner)), - sema(std::move(other.sema)) - { - } - - inline BlockingConcurrentQueue& - operator=(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT - { - return swap_internal(other); - } - - // Swaps this queue's state with the other's. Not thread-safe. - // Swapping two queues does not invalidate their tokens, however - // the tokens that were created for one queue must be used with - // only the swapped queue (i.e. the tokens are tied to the - // queue's movable state, not the object itself). - inline void swap(BlockingConcurrentQueue& other) MOODYCAMEL_NOEXCEPT - { - swap_internal(other); - } - -private: - BlockingConcurrentQueue& swap_internal(BlockingConcurrentQueue& other) - { - if (this == &other) { - return *this; - } - - inner.swap(other.inner); - sema.swap(other.sema); - return *this; - } - -public: - // Enqueues a single item (by copying it). - // Allocates memory if required. Only fails if memory allocation fails (or implicit - // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, - // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(T const& item) - { - if ((details::likely)(inner.enqueue(item))) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues a single item (by moving it, if possible). - // Allocates memory if required. Only fails if memory allocation fails (or implicit - // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, - // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(T&& item) - { - if ((details::likely)(inner.enqueue(std::move(item)))) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues a single item (by copying it) using an explicit producer token. - // Allocates memory if required. Only fails if memory allocation fails (or - // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(producer_token_t const& token, T const& item) - { - if ((details::likely)(inner.enqueue(token, item))) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues a single item (by moving it, if possible) using an explicit producer - // token. Allocates memory if required. Only fails if memory allocation fails (or - // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(producer_token_t const& token, T&& item) - { - if ((details::likely)(inner.enqueue(token, std::move(item)))) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues several items. - // Allocates memory if required. Only fails if memory allocation fails (or - // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Note: Use std::make_move_iterator if the elements should be moved instead of - // copied. Thread-safe. - template <typename It> - inline bool enqueue_bulk(It itemFirst, size_t count) - { - if ((details::likely)(inner.enqueue_bulk(std::forward<It>(itemFirst), count))) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); - return true; - } - return false; - } - - // Enqueues several items using an explicit producer token. - // Allocates memory if required. Only fails if memory allocation fails - // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Note: Use std::make_move_iterator if the elements should be moved - // instead of copied. - // Thread-safe. - template <typename It> - inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) - { - if ((details::likely)( - inner.enqueue_bulk(token, std::forward<It>(itemFirst), count))) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); - return true; - } - return false; - } - - // Enqueues a single item (by copying it). - // Does not allocate memory. Fails if not enough room to enqueue (or implicit - // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - // is 0). - // Thread-safe. - inline bool try_enqueue(T const& item) - { - if (inner.try_enqueue(item)) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues a single item (by moving it, if possible). - // Does not allocate memory (except for one-time implicit producer). - // Fails if not enough room to enqueue (or implicit production is - // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). - // Thread-safe. - inline bool try_enqueue(T&& item) - { - if (inner.try_enqueue(std::move(item))) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues a single item (by copying it) using an explicit producer token. - // Does not allocate memory. Fails if not enough room to enqueue. - // Thread-safe. - inline bool try_enqueue(producer_token_t const& token, T const& item) - { - if (inner.try_enqueue(token, item)) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues a single item (by moving it, if possible) using an explicit producer - // token. Does not allocate memory. Fails if not enough room to enqueue. Thread-safe. - inline bool try_enqueue(producer_token_t const& token, T&& item) - { - if (inner.try_enqueue(token, std::move(item))) { - sema->signal(); - return true; - } - return false; - } - - // Enqueues several items. - // Does not allocate memory (except for one-time implicit producer). - // Fails if not enough room to enqueue (or implicit production is - // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). - // Note: Use std::make_move_iterator if the elements should be moved - // instead of copied. - // Thread-safe. - template <typename It> - inline bool try_enqueue_bulk(It itemFirst, size_t count) - { - if (inner.try_enqueue_bulk(std::forward<It>(itemFirst), count)) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); - return true; - } - return false; - } - - // Enqueues several items using an explicit producer token. - // Does not allocate memory. Fails if not enough room to enqueue. - // Note: Use std::make_move_iterator if the elements should be moved - // instead of copied. - // Thread-safe. - template <typename It> - inline bool - try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) - { - if (inner.try_enqueue_bulk(token, std::forward<It>(itemFirst), count)) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); - return true; - } - return false; - } - - - // Attempts to dequeue from the queue. - // Returns false if all producer streams appeared empty at the time they - // were checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename U> - inline bool try_dequeue(U& item) - { - if (sema->tryWait()) { - while (!inner.try_dequeue(item)) { - continue; - } - return true; - } - return false; - } - - // Attempts to dequeue from the queue using an explicit consumer token. - // Returns false if all producer streams appeared empty at the time they - // were checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename U> - inline bool try_dequeue(consumer_token_t& token, U& item) - { - if (sema->tryWait()) { - while (!inner.try_dequeue(token, item)) { - continue; - } - return true; - } - return false; - } - - // Attempts to dequeue several elements from the queue. - // Returns the number of items actually dequeued. - // Returns 0 if all producer streams appeared empty at the time they - // were checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename It> - inline size_t try_dequeue_bulk(It itemFirst, size_t max) - { - size_t count = 0; - max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); - while (count != max) { - count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count); - } - return count; - } - - // Attempts to dequeue several elements from the queue using an explicit consumer - // token. Returns the number of items actually dequeued. Returns 0 if all producer - // streams appeared empty at the time they were checked (so, the queue is likely but - // not guaranteed to be empty). Never allocates. Thread-safe. - template <typename It> - inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) - { - size_t count = 0; - max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); - while (count != max) { - count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count); - } - return count; - } - - - // Blocks the current thread until there's something to dequeue, then - // dequeues it. - // Never allocates. Thread-safe. - template <typename U> - inline void wait_dequeue(U& item) - { - while (!sema->wait()) { - continue; - } - while (!inner.try_dequeue(item)) { - continue; - } - } - - // Blocks the current thread until either there's something to dequeue - // or the timeout (specified in microseconds) expires. Returns false - // without setting `item` if the timeout expires, otherwise assigns - // to `item` and returns true. - // Using a negative timeout indicates an indefinite timeout, - // and is thus functionally equivalent to calling wait_dequeue. - // Never allocates. Thread-safe. - template <typename U> - inline bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs) - { - if (!sema->wait(timeout_usecs)) { - return false; - } - while (!inner.try_dequeue(item)) { - continue; - } - return true; - } - - // Blocks the current thread until either there's something to dequeue - // or the timeout expires. Returns false without setting `item` if the - // timeout expires, otherwise assigns to `item` and returns true. - // Never allocates. Thread-safe. - template <typename U, typename Rep, typename Period> - inline bool wait_dequeue_timed(U& item, - std::chrono::duration<Rep, Period> const& timeout) - { - return wait_dequeue_timed( - item, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count()); - } - - // Blocks the current thread until there's something to dequeue, then - // dequeues it using an explicit consumer token. - // Never allocates. Thread-safe. - template <typename U> - inline void wait_dequeue(consumer_token_t& token, U& item) - { - while (!sema->wait()) { - continue; - } - while (!inner.try_dequeue(token, item)) { - continue; - } - } - - // Blocks the current thread until either there's something to dequeue - // or the timeout (specified in microseconds) expires. Returns false - // without setting `item` if the timeout expires, otherwise assigns - // to `item` and returns true. - // Using a negative timeout indicates an indefinite timeout, - // and is thus functionally equivalent to calling wait_dequeue. - // Never allocates. Thread-safe. - template <typename U> - inline bool - wait_dequeue_timed(consumer_token_t& token, U& item, std::int64_t timeout_usecs) - { - if (!sema->wait(timeout_usecs)) { - return false; - } - while (!inner.try_dequeue(token, item)) { - continue; - } - return true; - } - - // Blocks the current thread until either there's something to dequeue - // or the timeout expires. Returns false without setting `item` if the - // timeout expires, otherwise assigns to `item` and returns true. - // Never allocates. Thread-safe. - template <typename U, typename Rep, typename Period> - inline bool wait_dequeue_timed(consumer_token_t& token, - U& item, - std::chrono::duration<Rep, Period> const& timeout) - { - return wait_dequeue_timed( - token, - item, - std::chrono::duration_cast<std::chrono::microseconds>(timeout).count()); - } - - // Attempts to dequeue several elements from the queue. - // Returns the number of items actually dequeued, which will - // always be at least one (this method blocks until the queue - // is non-empty) and at most max. - // Never allocates. Thread-safe. - template <typename It> - inline size_t wait_dequeue_bulk(It itemFirst, size_t max) - { - size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); - while (count != max) { - count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count); - } - return count; - } - - // Attempts to dequeue several elements from the queue. - // Returns the number of items actually dequeued, which can - // be 0 if the timeout expires while waiting for elements, - // and at most max. - // Using a negative timeout indicates an indefinite timeout, - // and is thus functionally equivalent to calling wait_dequeue_bulk. - // Never allocates. Thread-safe. - template <typename It> - inline size_t - wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs) - { - size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, - timeout_usecs); - while (count != max) { - count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count); - } - return count; - } - - // Attempts to dequeue several elements from the queue. - // Returns the number of items actually dequeued, which can - // be 0 if the timeout expires while waiting for elements, - // and at most max. - // Never allocates. Thread-safe. - template <typename It, typename Rep, typename Period> - inline size_t wait_dequeue_bulk_timed( - It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout) - { - return wait_dequeue_bulk_timed<It&>( - itemFirst, - max, - std::chrono::duration_cast<std::chrono::microseconds>(timeout).count()); - } - - // Attempts to dequeue several elements from the queue using an explicit consumer - // token. Returns the number of items actually dequeued, which will always be at least - // one (this method blocks until the queue is non-empty) and at most max. Never - // allocates. Thread-safe. - template <typename It> - inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) - { - size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); - while (count != max) { - count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count); - } - return count; - } - - // Attempts to dequeue several elements from the queue using an explicit consumer - // token. Returns the number of items actually dequeued, which can be 0 if the timeout - // expires while waiting for elements, and at most max. Using a negative timeout - // indicates an indefinite timeout, and is thus functionally equivalent to calling - // wait_dequeue_bulk. Never allocates. Thread-safe. - template <typename It> - inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, - It itemFirst, - size_t max, - std::int64_t timeout_usecs) - { - size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, - timeout_usecs); - while (count != max) { - count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count); - } - return count; - } - - // Attempts to dequeue several elements from the queue using an explicit consumer - // token. Returns the number of items actually dequeued, which can be 0 if the timeout - // expires while waiting for elements, and at most max. Never allocates. Thread-safe. - template <typename It, typename Rep, typename Period> - inline size_t - wait_dequeue_bulk_timed(consumer_token_t& token, - It itemFirst, - size_t max, - std::chrono::duration<Rep, Period> const& timeout) - { - return wait_dequeue_bulk_timed<It&>( - token, - itemFirst, - max, - std::chrono::duration_cast<std::chrono::microseconds>(timeout).count()); - } - - - // Returns an estimate of the total number of elements currently in the queue. This - // estimate is only accurate if the queue has completely stabilized before it is - // called (i.e. all enqueue and dequeue operations have completed and their memory - // effects are visible on the calling thread, and no further operations start while - // this method is being called). Thread-safe. - inline size_t size_approx() const { return (size_t)sema->availableApprox(); } - - - // Returns true if the underlying atomic variables used by - // the queue are lock-free (they should be on most platforms). - // Thread-safe. - static bool is_lock_free() { return ConcurrentQueue::is_lock_free(); } - - -private: - template <typename U, typename A1, typename A2> - static inline U* create(A1&& a1, A2&& a2) - { - void* p = (Traits::malloc)(sizeof(U)); - return p != nullptr ? new (p) U(std::forward<A1>(a1), std::forward<A2>(a2)) - : nullptr; - } - - template <typename U> - static inline void destroy(U* p) - { - if (p != nullptr) { - p->~U(); - } - (Traits::free)(p); - } - -private: - ConcurrentQueue inner; - std::unique_ptr<LightweightSemaphore, void (*)(LightweightSemaphore*)> sema; -}; - - -template <typename T, typename Traits> -inline void swap(BlockingConcurrentQueue<T, Traits>& a, - BlockingConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT -{ - a.swap(b); -} - -} // end namespace moodycamel diff --git a/gr/include/moodycamel/concurrentqueue.h b/gr/include/moodycamel/concurrentqueue.h deleted file mode 100644 index 2a5bbcd82..000000000 --- a/gr/include/moodycamel/concurrentqueue.h +++ /dev/null @@ -1,4506 +0,0 @@ -// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue. -// An overview, including benchmark results, is provided here: -// http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++ -// The full design is also described in excruciating detail at: -// http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue - -// Simplified BSD license: -// Copyright (c) 2013-2020, Cameron Desrochers. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Also dual-licensed under the Boost Software License (see LICENSE.md) - -#pragma once - -#if defined(__GNUC__) -// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and -// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings -// upon assigning any computed values) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" - -#ifdef MCDBGQ_USE_RELACY -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" -#endif -#endif - -#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) -// VS2019 with /W4 warns about constant conditional expressions but unless /std=c++17 or -// higher does not support `if constexpr`, so we have no choice but to simply disable the -// warning -#pragma warning(push) -#pragma warning(disable : 4127) // conditional expression is constant -#endif - -#if defined(__APPLE__) -#include "TargetConditionals.h" -#endif - -#ifdef MCDBGQ_USE_RELACY -#include "relacy/relacy_std.hpp" -#include "relacy_shims.h" -// We only use malloc/free anyway, and the delete macro messes up `= delete` method -// declarations. We'll override the default trait malloc ourselves without a macro. -#undef new -#undef delete -#undef malloc -#undef free -#else -#include <atomic> // Requires C++11. Sorry VS2010. -#include <cassert> -#endif -#include <type_traits> -#include <algorithm> -#include <array> -#include <climits> // for CHAR_BIT -#include <cstddef> // for max_align_t -#include <cstdint> -#include <cstdlib> -#include <limits> -#include <thread> // partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading -#include <utility> - -// Platform-specific definitions of a numeric thread ID type and an invalid value -namespace moodycamel { -namespace details { -template <typename thread_id_t> -struct thread_id_converter { - typedef thread_id_t thread_id_numeric_size_t; - typedef thread_id_t thread_id_hash_t; - static thread_id_hash_t prehash(thread_id_t const& x) { return x; } -}; -} // namespace details -} // namespace moodycamel -#if defined(MCDBGQ_USE_RELACY) -namespace moodycamel { -namespace details { -typedef std::uint32_t thread_id_t; -static const thread_id_t invalid_thread_id = 0xFFFFFFFFU; -static const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU; -static inline thread_id_t thread_id() { return rl::thread_index(); } -} // namespace details -} // namespace moodycamel -#elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__) -// No sense pulling in windows.h in a header, we'll manually declare the function -// we use and rely on backwards-compatibility for this not to break -extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void); -namespace moodycamel { -namespace details { -static_assert(sizeof(unsigned long) == sizeof(std::uint32_t), - "Expected size of unsigned long to be 32 bits on Windows"); -typedef std::uint32_t thread_id_t; -static const thread_id_t invalid_thread_id = - 0; // See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx -static const thread_id_t invalid_thread_id2 = - 0xFFFFFFFFU; // Not technically guaranteed to be invalid, but is never used in - // practice. Note that all Win32 thread IDs are presently multiples of 4. -static inline thread_id_t thread_id() -{ - return static_cast<thread_id_t>(::GetCurrentThreadId()); -} -} // namespace details -} // namespace moodycamel -#elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || \ - (defined(__APPLE__) && TARGET_OS_IPHONE) -namespace moodycamel { -namespace details { -static_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, - "std::thread::id is expected to be either 4 or 8 bytes"); - -typedef std::thread::id thread_id_t; -static const thread_id_t invalid_thread_id; // Default ctor creates invalid ID - -// Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's -// only used if MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't -// be. -static inline thread_id_t thread_id() { return std::this_thread::get_id(); } - -template <std::size_t> -struct thread_id_size { -}; -template <> -struct thread_id_size<4> { - typedef std::uint32_t numeric_t; -}; -template <> -struct thread_id_size<8> { - typedef std::uint64_t numeric_t; -}; - -template <> -struct thread_id_converter<thread_id_t> { - typedef thread_id_size<sizeof(thread_id_t)>::numeric_t thread_id_numeric_size_t; -#ifndef __APPLE__ - typedef std::size_t thread_id_hash_t; -#else - typedef thread_id_numeric_size_t thread_id_hash_t; -#endif - - static thread_id_hash_t prehash(thread_id_t const& x) - { -#ifndef __APPLE__ - return std::hash<std::thread::id>()(x); -#else - return *reinterpret_cast<thread_id_hash_t const*>(&x); -#endif - } -}; -} // namespace details -} // namespace moodycamel -#else -// Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475 -// In order to get a numeric thread ID in a platform-independent way, we use a -// thread-local static variable's address as a thread identifier :-) -#if defined(__GNUC__) || defined(__INTEL_COMPILER) -#define MOODYCAMEL_THREADLOCAL __thread -#elif defined(_MSC_VER) -#define MOODYCAMEL_THREADLOCAL __declspec(thread) -#else -// Assume C++11 compliant compiler -#define MOODYCAMEL_THREADLOCAL thread_local -#endif -namespace moodycamel { -namespace details { -typedef std::uintptr_t thread_id_t; -static const thread_id_t invalid_thread_id = 0; // Address can't be nullptr -static const thread_id_t invalid_thread_id2 = - 1; // Member accesses off a null pointer are also generally invalid. Plus it's not - // aligned. -inline thread_id_t thread_id() -{ - static MOODYCAMEL_THREADLOCAL int x; - return reinterpret_cast<thread_id_t>(&x); -} -} // namespace details -} // namespace moodycamel -#endif - -// Constexpr if -#ifndef MOODYCAMEL_CONSTEXPR_IF -#if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || __cplusplus > 201402L -#define MOODYCAMEL_CONSTEXPR_IF if constexpr -#define MOODYCAMEL_MAYBE_UNUSED [[maybe_unused]] -#else -#define MOODYCAMEL_CONSTEXPR_IF if -#define MOODYCAMEL_MAYBE_UNUSED -#endif -#endif - -// Exceptions -#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED -#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || \ - (defined(__GNUC__) && defined(__EXCEPTIONS)) || \ - (!defined(_MSC_VER) && !defined(__GNUC__)) -#define MOODYCAMEL_EXCEPTIONS_ENABLED -#endif -#endif -#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED -#define MOODYCAMEL_TRY try -#define MOODYCAMEL_CATCH(...) catch (__VA_ARGS__) -#define MOODYCAMEL_RETHROW throw -#define MOODYCAMEL_THROW(expr) throw(expr) -#else -#define MOODYCAMEL_TRY MOODYCAMEL_CONSTEXPR_IF(true) -#define MOODYCAMEL_CATCH(...) else MOODYCAMEL_CONSTEXPR_IF(false) -#define MOODYCAMEL_RETHROW -#define MOODYCAMEL_THROW(expr) -#endif - -#ifndef MOODYCAMEL_NOEXCEPT -#if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED) -#define MOODYCAMEL_NOEXCEPT -#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) true -#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) true -#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800 -// VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it -// shouldn't :-( We have to assume *all* non-trivial constructors may throw on VS2012! -#define MOODYCAMEL_NOEXCEPT _NOEXCEPT -#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) \ - (std::is_rvalue_reference<valueType>::value && \ - std::is_move_constructible<type>::value \ - ? std::is_trivially_move_constructible<type>::value \ - : std::is_trivially_copy_constructible<type>::value) -#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) \ - ((std::is_rvalue_reference<valueType>::value && std::is_move_assignable<type>::value \ - ? std::is_trivially_move_assignable<type>::value || \ - std::is_nothrow_move_assignable<type>::value \ - : std::is_trivially_copy_assignable<type>::value || \ - std::is_nothrow_copy_assignable<type>::value) && \ - MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) -#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900 -#define MOODYCAMEL_NOEXCEPT _NOEXCEPT -#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) \ - (std::is_rvalue_reference<valueType>::value && \ - std::is_move_constructible<type>::value \ - ? std::is_trivially_move_constructible<type>::value || \ - std::is_nothrow_move_constructible<type>::value \ - : std::is_trivially_copy_constructible<type>::value || \ - std::is_nothrow_copy_constructible<type>::value) -#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) \ - ((std::is_rvalue_reference<valueType>::value && std::is_move_assignable<type>::value \ - ? std::is_trivially_move_assignable<type>::value || \ - std::is_nothrow_move_assignable<type>::value \ - : std::is_trivially_copy_assignable<type>::value || \ - std::is_nothrow_copy_assignable<type>::value) && \ - MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) -#else -#define MOODYCAMEL_NOEXCEPT noexcept -#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr) -#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr) -#endif -#endif - -#ifndef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED -#ifdef MCDBGQ_USE_RELACY -#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED -#else -// VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling -// bug: http://sourceforge.net/p/mingw-w64/bugs/445 g++ <=4.7 doesn't support thread_local -// either. Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to -// compile but it's unconfirmed to actually work -#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ - (!defined(__MINGW32__) && !defined(__MINGW64__) || \ - !defined(__WINPTHREADS_VERSION)) && \ - (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && \ - (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && \ - !defined(_M_ARM) && !defined(__aarch64__) -// Assume `thread_local` is fully supported in all other C++11 compilers/platforms -//#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED // always disabled for now since -// several users report having problems with it on -#endif -#endif -#endif - -// VS2012 doesn't support deleted functions. -// In this case, we declare the function normally but don't define it. A link error will -// be generated if the function is called. -#ifndef MOODYCAMEL_DELETE_FUNCTION -#if defined(_MSC_VER) && _MSC_VER < 1800 -#define MOODYCAMEL_DELETE_FUNCTION -#else -#define MOODYCAMEL_DELETE_FUNCTION = delete -#endif -#endif - -namespace moodycamel { -namespace details { -#ifndef MOODYCAMEL_ALIGNAS -// VS2013 doesn't support alignas or alignof, and align() requires a constant literal -#if defined(_MSC_VER) && _MSC_VER <= 1800 -#define MOODYCAMEL_ALIGNAS(alignment) __declspec(align(alignment)) -#define MOODYCAMEL_ALIGNOF(obj) __alignof(obj) -#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) \ - typename details::Vs2013Aligned<std::alignment_of<obj>::value, T>::type -template <int Align, typename T> -struct Vs2013Aligned { -}; // default, unsupported alignment -template <typename T> -struct Vs2013Aligned<1, T> { - typedef __declspec(align(1)) T type; -}; -template <typename T> -struct Vs2013Aligned<2, T> { - typedef __declspec(align(2)) T type; -}; -template <typename T> -struct Vs2013Aligned<4, T> { - typedef __declspec(align(4)) T type; -}; -template <typename T> -struct Vs2013Aligned<8, T> { - typedef __declspec(align(8)) T type; -}; -template <typename T> -struct Vs2013Aligned<16, T> { - typedef __declspec(align(16)) T type; -}; -template <typename T> -struct Vs2013Aligned<32, T> { - typedef __declspec(align(32)) T type; -}; -template <typename T> -struct Vs2013Aligned<64, T> { - typedef __declspec(align(64)) T type; -}; -template <typename T> -struct Vs2013Aligned<128, T> { - typedef __declspec(align(128)) T type; -}; -template <typename T> -struct Vs2013Aligned<256, T> { - typedef __declspec(align(256)) T type; -}; -#else -template <typename T> -struct identity { - typedef T type; -}; -#define MOODYCAMEL_ALIGNAS(alignment) alignas(alignment) -#define MOODYCAMEL_ALIGNOF(obj) alignof(obj) -#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) \ - alignas(alignof(obj)) typename details::identity<T>::type -#endif -#endif -} // namespace details -} // namespace moodycamel - - -// TSAN can false report races in lock-free code. To enable TSAN to be used from projects -// that use this one, we can apply per-function compile-time suppression. See -// https://clang.llvm.org/docs/ThreadSanitizer.html#has-feature-thread-sanitizer -#define MOODYCAMEL_NO_TSAN -#if defined(__has_feature) -#if __has_feature(thread_sanitizer) -#undef MOODYCAMEL_NO_TSAN -#define MOODYCAMEL_NO_TSAN __attribute__((no_sanitize("thread"))) -#endif // TSAN -#endif // TSAN - -// Compiler-specific likely/unlikely hints -namespace moodycamel { -namespace details { -#if defined(__GNUC__) -static inline bool(likely)(bool x) { return __builtin_expect((x), true); } -static inline bool(unlikely)(bool x) { return __builtin_expect((x), false); } -#else -static inline bool(likely)(bool x) { return x; } -static inline bool(unlikely)(bool x) { return x; } -#endif -} // namespace details -} // namespace moodycamel - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG -#include "internal/concurrentqueue_internal_debug.h" -#endif - -namespace moodycamel { -namespace details { -template <typename T> -struct const_numeric_max { - static_assert(std::is_integral<T>::value, - "const_numeric_max can only be used with integers"); - static const T value = - std::numeric_limits<T>::is_signed - ? (static_cast<T>(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast<T>(1) - : static_cast<T>(-1); -}; - -#if defined(__GLIBCXX__) -typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while -#else -typedef std::max_align_t - std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std:: -#endif - -// Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even -// while supporting 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this -// with our own union. See issue #64. -typedef union { - std_max_align_t x; - long long y; - void* z; -} max_align_t; -} // namespace details - -// Default traits for the ConcurrentQueue. To change some of the -// traits without re-implementing all of them, inherit from this -// struct and shadow the declarations you wish to be different; -// since the traits are used as a template type parameter, the -// shadowed declarations will be used where defined, and the defaults -// otherwise. -struct ConcurrentQueueDefaultTraits { - // General-purpose size type. std::size_t is strongly recommended. - typedef std::size_t size_t; - - // The type used for the enqueue and dequeue indices. Must be at least as - // large as size_t. Should be significantly larger than the number of elements - // you expect to hold at once, especially if you have a high turnover rate; - // for example, on 32-bit x86, if you expect to have over a hundred million - // elements or pump several million elements through your queue in a very - // short space of time, using a 32-bit type *may* trigger a race condition. - // A 64-bit int type is recommended in that case, and in practice will - // prevent a race condition no matter the usage of the queue. Note that - // whether the queue is lock-free with a 64-int type depends on the whether - // std::atomic<std::uint64_t> is lock-free, which is platform-specific. - typedef std::size_t index_t; - - // Internally, all elements are enqueued and dequeued from multi-element - // blocks; this is the smallest controllable unit. If you expect few elements - // but many producers, a smaller block size should be favoured. For few producers - // and/or many elements, a larger block size is preferred. A sane default - // is provided. Must be a power of 2. - static const size_t BLOCK_SIZE = 32; - - // For explicit producers (i.e. when using a producer token), the block is - // checked for being empty by iterating through a list of flags, one per element. - // For large block sizes, this is too inefficient, and switching to an atomic - // counter-based approach is faster. The switch is made for block sizes strictly - // larger than this threshold. - static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32; - - // How many full blocks can be expected for a single explicit producer? This should - // reflect that number's maximum for optimal performance. Must be a power of 2. - static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32; - - // How many full blocks can be expected for a single implicit producer? This should - // reflect that number's maximum for optimal performance. Must be a power of 2. - static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32; - - // The initial size of the hash table mapping thread IDs to implicit producers. - // Note that the hash is resized every time it becomes half full. - // Must be a power of two, and either 0 or at least 1. If 0, implicit production - // (using the enqueue methods without an explicit producer token) is disabled. - static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32; - - // Controls the number of items that an explicit consumer (i.e. one with a token) - // must consume before it causes all consumers to rotate and move on to the next - // internal queue. - static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256; - - // The maximum number of elements (inclusive) that can be enqueued to a sub-queue. - // Enqueue operations that would cause this limit to be surpassed will fail. Note - // that this limit is enforced at the block level (for performance reasons), i.e. - // it's rounded up to the nearest block size. - static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max<size_t>::value; - - // The number of times to spin before sleeping when waiting on a semaphore. - // Recommended values are on the order of 1000-10000 unless the number of - // consumer threads exceeds the number of idle cores (in which case try 0-100). - // Only affects instances of the BlockingConcurrentQueue. - static const int MAX_SEMA_SPINS = 10000; - - -#ifndef MCDBGQ_USE_RELACY - // Memory allocation can be customized if needed. - // malloc should return nullptr on failure, and handle alignment like std::malloc. -#if defined(malloc) || defined(free) - // Gah, this is 2015, stop defining macros that break standard code already! - // Work around malloc/free being special macros: - static inline void* WORKAROUND_malloc(size_t size) { return malloc(size); } - static inline void WORKAROUND_free(void* ptr) { return free(ptr); } - static inline void*(malloc)(size_t size) { return WORKAROUND_malloc(size); } - static inline void(free)(void* ptr) { return WORKAROUND_free(ptr); } -#else - static inline void* malloc(size_t size) { return std::malloc(size); } - static inline void free(void* ptr) { return std::free(ptr); } -#endif -#else - // Debug versions when running under the Relacy race detector (ignore - // these in user code) - static inline void* malloc(size_t size) { return rl::rl_malloc(size, $); } - static inline void free(void* ptr) { return rl::rl_free(ptr, $); } -#endif -}; - - -// When producing or consuming many elements, the most efficient way is to: -// 1) Use one of the bulk-operation methods of the queue with a token -// 2) Failing that, use the bulk-operation methods without a token -// 3) Failing that, create a token and use that with the single-item methods -// 4) Failing that, use the single-parameter methods of the queue -// Having said that, don't create tokens willy-nilly -- ideally there should be -// a maximum of one token per thread (of each kind). -struct ProducerToken; -struct ConsumerToken; - -template <typename T, typename Traits> -class ConcurrentQueue; -template <typename T, typename Traits> -class BlockingConcurrentQueue; -class ConcurrentQueueTests; - - -namespace details { -struct ConcurrentQueueProducerTypelessBase { - ConcurrentQueueProducerTypelessBase* next; - std::atomic<bool> inactive; - ProducerToken* token; - - ConcurrentQueueProducerTypelessBase() : next(nullptr), inactive(false), token(nullptr) - { - } -}; - -template <bool use32> -struct _hash_32_or_64 { - static inline std::uint32_t hash(std::uint32_t h) - { - // MurmurHash3 finalizer -- see - // https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp Since - // the thread ID is already unique, all we really want to do is propagate that - // uniqueness evenly across all the bits, so that we can use a subset of the bits - // while reducing collisions significantly - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - return h ^ (h >> 16); - } -}; -template <> -struct _hash_32_or_64<1> { - static inline std::uint64_t hash(std::uint64_t h) - { - h ^= h >> 33; - h *= 0xff51afd7ed558ccd; - h ^= h >> 33; - h *= 0xc4ceb9fe1a85ec53; - return h ^ (h >> 33); - } -}; -template <std::size_t size> -struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> { -}; - -static inline size_t hash_thread_id(thread_id_t id) -{ - static_assert(sizeof(thread_id_t) <= 8, - "Expected a platform where thread IDs are at most 64-bit values"); - return static_cast<size_t>( - hash_32_or_64<sizeof(thread_id_converter<thread_id_t>::thread_id_hash_t)>::hash( - thread_id_converter<thread_id_t>::prehash(id))); -} - -template <typename T> -static inline bool circular_less_than(T a, T b) -{ -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4554) -#endif - static_assert( - std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, - "circular_less_than is intended to be used only with unsigned integer types"); - return static_cast<T>(a - b) > - static_cast<T>(static_cast<T>(1) << static_cast<T>(sizeof(T) * CHAR_BIT - 1)); -#ifdef _MSC_VER -#pragma warning(pop) -#endif -} - -template <typename U> -static inline char* align_for(char* ptr) -{ - const std::size_t alignment = std::alignment_of<U>::value; - return ptr + - (alignment - (reinterpret_cast<std::uintptr_t>(ptr) % alignment)) % alignment; -} - -template <typename T> -static inline T ceil_to_pow_2(T x) -{ - static_assert( - std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, - "ceil_to_pow_2 is intended to be used only with unsigned integer types"); - - // Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - --x; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - for (std::size_t i = 1; i < sizeof(T); i <<= 1) { - x |= x >> (i << 3); - } - ++x; - return x; -} - -template <typename T> -static inline void swap_relaxed(std::atomic<T>& left, std::atomic<T>& right) -{ - T temp = std::move(left.load(std::memory_order_relaxed)); - left.store(std::move(right.load(std::memory_order_relaxed)), - std::memory_order_relaxed); - right.store(std::move(temp), std::memory_order_relaxed); -} - -template <typename T> -static inline T const& nomove(T const& x) -{ - return x; -} - -template <bool Enable> -struct nomove_if { - template <typename T> - static inline T const& eval(T const& x) - { - return x; - } -}; - -template <> -struct nomove_if<false> { - template <typename U> - static inline auto eval(U&& x) -> decltype(std::forward<U>(x)) - { - return std::forward<U>(x); - } -}; - -template <typename It> -static inline auto deref_noexcept(It& it) MOODYCAMEL_NOEXCEPT -> decltype(*it) -{ - return *it; -} - -#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || \ - (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) -template <typename T> -struct is_trivially_destructible : std::is_trivially_destructible<T> { -}; -#else -template <typename T> -struct is_trivially_destructible : std::has_trivial_destructor<T> { -}; -#endif - -#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED -#ifdef MCDBGQ_USE_RELACY -typedef RelacyThreadExitListener ThreadExitListener; -typedef RelacyThreadExitNotifier ThreadExitNotifier; -#else -struct ThreadExitListener { - typedef void (*callback_t)(void*); - callback_t callback; - void* userData; - - ThreadExitListener* next; // reserved for use by the ThreadExitNotifier -}; - - -class ThreadExitNotifier -{ -public: - static void subscribe(ThreadExitListener* listener) - { - auto& tlsInst = instance(); - listener->next = tlsInst.tail; - tlsInst.tail = listener; - } - - static void unsubscribe(ThreadExitListener* listener) - { - auto& tlsInst = instance(); - ThreadExitListener** prev = &tlsInst.tail; - for (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) { - if (ptr == listener) { - *prev = ptr->next; - break; - } - prev = &ptr->next; - } - } - -private: - ThreadExitNotifier() : tail(nullptr) {} - ThreadExitNotifier(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; - ThreadExitNotifier& operator=(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; - - ~ThreadExitNotifier() - { - // This thread is about to exit, let everyone know! - assert(this == &instance() && - "If this assert fails, you likely have a buggy compiler! Change the " - "preprocessor conditions such that " - "MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined."); - for (auto ptr = tail; ptr != nullptr; ptr = ptr->next) { - ptr->callback(ptr->userData); - } - } - - // Thread-local - static inline ThreadExitNotifier& instance() - { - static thread_local ThreadExitNotifier notifier; - return notifier; - } - -private: - ThreadExitListener* tail; -}; -#endif -#endif - -template <typename T> -struct static_is_lock_free_num { - enum { value = 0 }; -}; -template <> -struct static_is_lock_free_num<signed char> { - enum { value = ATOMIC_CHAR_LOCK_FREE }; -}; -template <> -struct static_is_lock_free_num<short> { - enum { value = ATOMIC_SHORT_LOCK_FREE }; -}; -template <> -struct static_is_lock_free_num<int> { - enum { value = ATOMIC_INT_LOCK_FREE }; -}; -template <> -struct static_is_lock_free_num<long> { - enum { value = ATOMIC_LONG_LOCK_FREE }; -}; -template <> -struct static_is_lock_free_num<long long> { - enum { value = ATOMIC_LLONG_LOCK_FREE }; -}; -template <typename T> -struct static_is_lock_free : static_is_lock_free_num<typename std::make_signed<T>::type> { -}; -template <> -struct static_is_lock_free<bool> { - enum { value = ATOMIC_BOOL_LOCK_FREE }; -}; -template <typename U> -struct static_is_lock_free<U*> { - enum { value = ATOMIC_POINTER_LOCK_FREE }; -}; -} // namespace details - - -struct ProducerToken { - template <typename T, typename Traits> - explicit ProducerToken(ConcurrentQueue<T, Traits>& queue); - - template <typename T, typename Traits> - explicit ProducerToken(BlockingConcurrentQueue<T, Traits>& queue); - - ProducerToken(ProducerToken&& other) MOODYCAMEL_NOEXCEPT : producer(other.producer) - { - other.producer = nullptr; - if (producer != nullptr) { - producer->token = this; - } - } - - inline ProducerToken& operator=(ProducerToken&& other) MOODYCAMEL_NOEXCEPT - { - swap(other); - return *this; - } - - void swap(ProducerToken& other) MOODYCAMEL_NOEXCEPT - { - std::swap(producer, other.producer); - if (producer != nullptr) { - producer->token = this; - } - if (other.producer != nullptr) { - other.producer->token = &other; - } - } - - // A token is always valid unless: - // 1) Memory allocation failed during construction - // 2) It was moved via the move constructor - // (Note: assignment does a swap, leaving both potentially valid) - // 3) The associated queue was destroyed - // Note that if valid() returns true, that only indicates - // that the token is valid for use with a specific queue, - // but not which one; that's up to the user to track. - inline bool valid() const { return producer != nullptr; } - - ~ProducerToken() - { - if (producer != nullptr) { - producer->token = nullptr; - producer->inactive.store(true, std::memory_order_release); - } - } - - // Disable copying and assignment - ProducerToken(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; - ProducerToken& operator=(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; - -private: - template <typename T, typename Traits> - friend class ConcurrentQueue; - friend class ConcurrentQueueTests; - -protected: - details::ConcurrentQueueProducerTypelessBase* producer; -}; - - -struct ConsumerToken { - template <typename T, typename Traits> - explicit ConsumerToken(ConcurrentQueue<T, Traits>& q); - - template <typename T, typename Traits> - explicit ConsumerToken(BlockingConcurrentQueue<T, Traits>& q); - - ConsumerToken(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT - : initialOffset(other.initialOffset), - lastKnownGlobalOffset(other.lastKnownGlobalOffset), - itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), - currentProducer(other.currentProducer), - desiredProducer(other.desiredProducer) - { - } - - inline ConsumerToken& operator=(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT - { - swap(other); - return *this; - } - - void swap(ConsumerToken& other) MOODYCAMEL_NOEXCEPT - { - std::swap(initialOffset, other.initialOffset); - std::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset); - std::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent); - std::swap(currentProducer, other.currentProducer); - std::swap(desiredProducer, other.desiredProducer); - } - - // Disable copying and assignment - ConsumerToken(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; - ConsumerToken& operator=(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; - -private: - template <typename T, typename Traits> - friend class ConcurrentQueue; - friend class ConcurrentQueueTests; - -private: // but shared with ConcurrentQueue - std::uint32_t initialOffset; - std::uint32_t lastKnownGlobalOffset; - std::uint32_t itemsConsumedFromCurrent; - details::ConcurrentQueueProducerTypelessBase* currentProducer; - details::ConcurrentQueueProducerTypelessBase* desiredProducer; -}; - -// Need to forward-declare this swap because it's in a namespace. -// See -// http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces -template <typename T, typename Traits> -inline void -swap(typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& a, - typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT; - - -template <typename T, typename Traits = ConcurrentQueueDefaultTraits> -class ConcurrentQueue -{ -public: - typedef ::moodycamel::ProducerToken producer_token_t; - typedef ::moodycamel::ConsumerToken consumer_token_t; - - typedef typename Traits::index_t index_t; - typedef typename Traits::size_t size_t; - - static const size_t BLOCK_SIZE = static_cast<size_t>(Traits::BLOCK_SIZE); - static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = - static_cast<size_t>(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD); - static const size_t EXPLICIT_INITIAL_INDEX_SIZE = - static_cast<size_t>(Traits::EXPLICIT_INITIAL_INDEX_SIZE); - static const size_t IMPLICIT_INITIAL_INDEX_SIZE = - static_cast<size_t>(Traits::IMPLICIT_INITIAL_INDEX_SIZE); - static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = - static_cast<size_t>(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE); - static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = - static_cast<std::uint32_t>( - Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE); -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4307) // + integral constant overflow (that's what the ternary - // expression is for!) -#pragma warning(disable : 4309) // static_cast: Truncation of constant value -#endif - static const size_t MAX_SUBQUEUE_SIZE = - (details::const_numeric_max<size_t>::value - - static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) < - BLOCK_SIZE) - ? details::const_numeric_max<size_t>::value - : ((static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / - BLOCK_SIZE * BLOCK_SIZE); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - static_assert(!std::numeric_limits<size_t>::is_signed && - std::is_integral<size_t>::value, - "Traits::size_t must be an unsigned integral type"); - static_assert(!std::numeric_limits<index_t>::is_signed && - std::is_integral<index_t>::value, - "Traits::index_t must be an unsigned integral type"); - static_assert(sizeof(index_t) >= sizeof(size_t), - "Traits::index_t must be at least as wide as Traits::size_t"); - static_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), - "Traits::BLOCK_SIZE must be a power of 2 (and at least 2)"); - static_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && - !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & - (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), - "Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 " - "(and greater than 1)"); - static_assert( - (EXPLICIT_INITIAL_INDEX_SIZE > 1) && - !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), - "Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); - static_assert( - (IMPLICIT_INITIAL_INDEX_SIZE > 1) && - !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), - "Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); - static_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || - !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & - (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), - "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2"); - static_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || - INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, - "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 " - "to disable implicit enqueueing)"); - -public: - // Creates a queue with at least `capacity` element slots; note that the - // actual number of elements that can be inserted without additional memory - // allocation depends on the number of producers and the block size (e.g. if - // the block size is equal to `capacity`, only a single block will be allocated - // up-front, which means only a single producer will be able to enqueue elements - // without an extra allocation -- blocks aren't shared between producers). - // This method is not thread safe -- it is up to the user to ensure that the - // queue is fully constructed before it starts being used by other threads (this - // includes making the memory effects of construction visible, possibly with a - // memory barrier). - explicit ConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) - : producerListTail(nullptr), - producerCount(0), - initialBlockPoolIndex(0), - nextExplicitConsumerId(0), - globalExplicitConsumerOffset(0) - { - implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); - populate_initial_implicit_producer_hash(); - populate_initial_block_list(capacity / BLOCK_SIZE + - ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1)); - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - // Track all the producers using a fully-resolved typed list for - // each kind; this makes it possible to debug them starting from - // the root queue object (otherwise wacky casts are needed that - // don't compile in the debugger's expression evaluator). - explicitProducers.store(nullptr, std::memory_order_relaxed); - implicitProducers.store(nullptr, std::memory_order_relaxed); -#endif - } - - // Computes the correct amount of pre-allocated blocks for you based - // on the minimum number of elements you want available at any given - // time, and the maximum concurrent number of each type of producer. - ConcurrentQueue(size_t minCapacity, - size_t maxExplicitProducers, - size_t maxImplicitProducers) - : producerListTail(nullptr), - producerCount(0), - initialBlockPoolIndex(0), - nextExplicitConsumerId(0), - globalExplicitConsumerOffset(0) - { - implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); - populate_initial_implicit_producer_hash(); - size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * - (maxExplicitProducers + 1) + - 2 * (maxExplicitProducers + maxImplicitProducers); - populate_initial_block_list(blocks); - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - explicitProducers.store(nullptr, std::memory_order_relaxed); - implicitProducers.store(nullptr, std::memory_order_relaxed); -#endif - } - - // Note: The queue should not be accessed concurrently while it's - // being deleted. It's up to the user to synchronize this. - // This method is not thread safe. - ~ConcurrentQueue() - { - // Destroy producers - auto ptr = producerListTail.load(std::memory_order_relaxed); - while (ptr != nullptr) { - auto next = ptr->next_prod(); - if (ptr->token != nullptr) { - ptr->token->producer = nullptr; - } - destroy(ptr); - ptr = next; - } - - // Destroy implicit producer hash tables - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) - { - auto hash = implicitProducerHash.load(std::memory_order_relaxed); - while (hash != nullptr) { - auto prev = hash->prev; - if (prev != nullptr) { // The last hash is part of this object and was not - // allocated dynamically - for (size_t i = 0; i != hash->capacity; ++i) { - hash->entries[i].~ImplicitProducerKVP(); - } - hash->~ImplicitProducerHash(); - (Traits::free)(hash); - } - hash = prev; - } - } - - // Destroy global free list - auto block = freeList.head_unsafe(); - while (block != nullptr) { - auto next = block->freeListNext.load(std::memory_order_relaxed); - if (block->dynamicallyAllocated) { - destroy(block); - } - block = next; - } - - // Destroy initial free list - destroy_array(initialBlockPool, initialBlockPoolSize); - } - - // Disable copying and copy assignment - ConcurrentQueue(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; - ConcurrentQueue& operator=(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; - - // Moving is supported, but note that it is *not* a thread-safe operation. - // Nobody can use the queue while it's being moved, and the memory effects - // of that move must be propagated to other threads before they can use it. - // Note: When a queue is moved, its tokens are still valid but can only be - // used with the destination queue (i.e. semantically they are moved along - // with the queue itself). - ConcurrentQueue(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT - : producerListTail(other.producerListTail.load(std::memory_order_relaxed)), - producerCount(other.producerCount.load(std::memory_order_relaxed)), - initialBlockPoolIndex( - other.initialBlockPoolIndex.load(std::memory_order_relaxed)), - initialBlockPool(other.initialBlockPool), - initialBlockPoolSize(other.initialBlockPoolSize), - freeList(std::move(other.freeList)), - nextExplicitConsumerId( - other.nextExplicitConsumerId.load(std::memory_order_relaxed)), - globalExplicitConsumerOffset( - other.globalExplicitConsumerOffset.load(std::memory_order_relaxed)) - { - // Move the other one into this, and leave the other one as an empty queue - implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); - populate_initial_implicit_producer_hash(); - swap_implicit_producer_hashes(other); - - other.producerListTail.store(nullptr, std::memory_order_relaxed); - other.producerCount.store(0, std::memory_order_relaxed); - other.nextExplicitConsumerId.store(0, std::memory_order_relaxed); - other.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed); - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - explicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), - std::memory_order_relaxed); - other.explicitProducers.store(nullptr, std::memory_order_relaxed); - implicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), - std::memory_order_relaxed); - other.implicitProducers.store(nullptr, std::memory_order_relaxed); -#endif - - other.initialBlockPoolIndex.store(0, std::memory_order_relaxed); - other.initialBlockPoolSize = 0; - other.initialBlockPool = nullptr; - - reown_producers(); - } - - inline ConcurrentQueue& operator=(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT - { - return swap_internal(other); - } - - // Swaps this queue's state with the other's. Not thread-safe. - // Swapping two queues does not invalidate their tokens, however - // the tokens that were created for one queue must be used with - // only the swapped queue (i.e. the tokens are tied to the - // queue's movable state, not the object itself). - inline void swap(ConcurrentQueue& other) MOODYCAMEL_NOEXCEPT { swap_internal(other); } - -private: - ConcurrentQueue& swap_internal(ConcurrentQueue& other) - { - if (this == &other) { - return *this; - } - - details::swap_relaxed(producerListTail, other.producerListTail); - details::swap_relaxed(producerCount, other.producerCount); - details::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex); - std::swap(initialBlockPool, other.initialBlockPool); - std::swap(initialBlockPoolSize, other.initialBlockPoolSize); - freeList.swap(other.freeList); - details::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId); - details::swap_relaxed(globalExplicitConsumerOffset, - other.globalExplicitConsumerOffset); - - swap_implicit_producer_hashes(other); - - reown_producers(); - other.reown_producers(); - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - details::swap_relaxed(explicitProducers, other.explicitProducers); - details::swap_relaxed(implicitProducers, other.implicitProducers); -#endif - - return *this; - } - -public: - // Enqueues a single item (by copying it). - // Allocates memory if required. Only fails if memory allocation fails (or implicit - // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, - // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(T const& item) - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; - else return inner_enqueue<CanAlloc>(item); - } - - // Enqueues a single item (by moving it, if possible). - // Allocates memory if required. Only fails if memory allocation fails (or implicit - // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, - // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(T&& item) - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; - else return inner_enqueue<CanAlloc>(std::move(item)); - } - - // Enqueues a single item (by copying it) using an explicit producer token. - // Allocates memory if required. Only fails if memory allocation fails (or - // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(producer_token_t const& token, T const& item) - { - return inner_enqueue<CanAlloc>(token, item); - } - - // Enqueues a single item (by moving it, if possible) using an explicit producer - // token. Allocates memory if required. Only fails if memory allocation fails (or - // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Thread-safe. - inline bool enqueue(producer_token_t const& token, T&& item) - { - return inner_enqueue<CanAlloc>(token, std::move(item)); - } - - // Enqueues several items. - // Allocates memory if required. Only fails if memory allocation fails (or - // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Note: Use std::make_move_iterator if the elements should be moved instead of - // copied. Thread-safe. - template <typename It> - bool enqueue_bulk(It itemFirst, size_t count) - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; - else return inner_enqueue_bulk<CanAlloc>(itemFirst, count); - } - - // Enqueues several items using an explicit producer token. - // Allocates memory if required. Only fails if memory allocation fails - // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). - // Note: Use std::make_move_iterator if the elements should be moved - // instead of copied. - // Thread-safe. - template <typename It> - bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) - { - return inner_enqueue_bulk<CanAlloc>(token, itemFirst, count); - } - - // Enqueues a single item (by copying it). - // Does not allocate memory. Fails if not enough room to enqueue (or implicit - // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - // is 0). - // Thread-safe. - inline bool try_enqueue(T const& item) - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; - else return inner_enqueue<CannotAlloc>(item); - } - - // Enqueues a single item (by moving it, if possible). - // Does not allocate memory (except for one-time implicit producer). - // Fails if not enough room to enqueue (or implicit production is - // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). - // Thread-safe. - inline bool try_enqueue(T&& item) - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; - else return inner_enqueue<CannotAlloc>(std::move(item)); - } - - // Enqueues a single item (by copying it) using an explicit producer token. - // Does not allocate memory. Fails if not enough room to enqueue. - // Thread-safe. - inline bool try_enqueue(producer_token_t const& token, T const& item) - { - return inner_enqueue<CannotAlloc>(token, item); - } - - // Enqueues a single item (by moving it, if possible) using an explicit producer - // token. Does not allocate memory. Fails if not enough room to enqueue. Thread-safe. - inline bool try_enqueue(producer_token_t const& token, T&& item) - { - return inner_enqueue<CannotAlloc>(token, std::move(item)); - } - - // Enqueues several items. - // Does not allocate memory (except for one-time implicit producer). - // Fails if not enough room to enqueue (or implicit production is - // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). - // Note: Use std::make_move_iterator if the elements should be moved - // instead of copied. - // Thread-safe. - template <typename It> - bool try_enqueue_bulk(It itemFirst, size_t count) - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; - else return inner_enqueue_bulk<CannotAlloc>(itemFirst, count); - } - - // Enqueues several items using an explicit producer token. - // Does not allocate memory. Fails if not enough room to enqueue. - // Note: Use std::make_move_iterator if the elements should be moved - // instead of copied. - // Thread-safe. - template <typename It> - bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) - { - return inner_enqueue_bulk<CannotAlloc>(token, itemFirst, count); - } - - - // Attempts to dequeue from the queue. - // Returns false if all producer streams appeared empty at the time they - // were checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename U> - bool try_dequeue(U& item) - { - // Instead of simply trying each producer in turn (which could cause needless - // contention on the first producer), we score them heuristically. - size_t nonEmptyCount = 0; - ProducerBase* best = nullptr; - size_t bestSize = 0; - for (auto ptr = producerListTail.load(std::memory_order_acquire); - nonEmptyCount < 3 && ptr != nullptr; - ptr = ptr->next_prod()) { - auto size = ptr->size_approx(); - if (size > 0) { - if (size > bestSize) { - bestSize = size; - best = ptr; - } - ++nonEmptyCount; - } - } - - // If there was at least one non-empty queue but it appears empty at the time - // we try to dequeue from it, we need to make sure every queue's been tried - if (nonEmptyCount > 0) { - if ((details::likely)(best->dequeue(item))) { - return true; - } - for (auto ptr = producerListTail.load(std::memory_order_acquire); - ptr != nullptr; - ptr = ptr->next_prod()) { - if (ptr != best && ptr->dequeue(item)) { - return true; - } - } - } - return false; - } - - // Attempts to dequeue from the queue. - // Returns false if all producer streams appeared empty at the time they - // were checked (so, the queue is likely but not guaranteed to be empty). - // This differs from the try_dequeue(item) method in that this one does - // not attempt to reduce contention by interleaving the order that producer - // streams are dequeued from. So, using this method can reduce overall throughput - // under contention, but will give more predictable results in single-threaded - // consumer scenarios. This is mostly only useful for internal unit tests. - // Never allocates. Thread-safe. - template <typename U> - bool try_dequeue_non_interleaved(U& item) - { - for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; - ptr = ptr->next_prod()) { - if (ptr->dequeue(item)) { - return true; - } - } - return false; - } - - // Attempts to dequeue from the queue using an explicit consumer token. - // Returns false if all producer streams appeared empty at the time they - // were checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename U> - bool try_dequeue(consumer_token_t& token, U& item) - { - // The idea is roughly as follows: - // Every 256 items from one producer, make everyone rotate (increase the global - // offset) -> this means the highest efficiency consumer dictates the rotation - // speed of everyone else, more or less If you see that the global offset has - // changed, you must reset your consumption counter and move to your designated - // place If there's no items where you're supposed to be, keep moving until you - // find a producer with some items If the global offset has not changed but you've - // run out of items to consume, move over from your current position until you - // find an producer with something in it - - if (token.desiredProducer == nullptr || - token.lastKnownGlobalOffset != - globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { - if (!update_current_producer_after_rotation(token)) { - return false; - } - } - - // If there was at least one non-empty queue but it appears empty at the time - // we try to dequeue from it, we need to make sure every queue's been tried - if (static_cast<ProducerBase*>(token.currentProducer)->dequeue(item)) { - if (++token.itemsConsumedFromCurrent == - EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { - globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); - } - return true; - } - - auto tail = producerListTail.load(std::memory_order_acquire); - auto ptr = static_cast<ProducerBase*>(token.currentProducer)->next_prod(); - if (ptr == nullptr) { - ptr = tail; - } - while (ptr != static_cast<ProducerBase*>(token.currentProducer)) { - if (ptr->dequeue(item)) { - token.currentProducer = ptr; - token.itemsConsumedFromCurrent = 1; - return true; - } - ptr = ptr->next_prod(); - if (ptr == nullptr) { - ptr = tail; - } - } - return false; - } - - // Attempts to dequeue several elements from the queue. - // Returns the number of items actually dequeued. - // Returns 0 if all producer streams appeared empty at the time they - // were checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename It> - size_t try_dequeue_bulk(It itemFirst, size_t max) - { - size_t count = 0; - for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; - ptr = ptr->next_prod()) { - count += ptr->dequeue_bulk(itemFirst, max - count); - if (count == max) { - break; - } - } - return count; - } - - // Attempts to dequeue several elements from the queue using an explicit consumer - // token. Returns the number of items actually dequeued. Returns 0 if all producer - // streams appeared empty at the time they were checked (so, the queue is likely but - // not guaranteed to be empty). Never allocates. Thread-safe. - template <typename It> - size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) - { - if (token.desiredProducer == nullptr || - token.lastKnownGlobalOffset != - globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { - if (!update_current_producer_after_rotation(token)) { - return 0; - } - } - - size_t count = static_cast<ProducerBase*>(token.currentProducer) - ->dequeue_bulk(itemFirst, max); - if (count == max) { - if ((token.itemsConsumedFromCurrent += static_cast<std::uint32_t>(max)) >= - EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { - globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); - } - return max; - } - token.itemsConsumedFromCurrent += static_cast<std::uint32_t>(count); - max -= count; - - auto tail = producerListTail.load(std::memory_order_acquire); - auto ptr = static_cast<ProducerBase*>(token.currentProducer)->next_prod(); - if (ptr == nullptr) { - ptr = tail; - } - while (ptr != static_cast<ProducerBase*>(token.currentProducer)) { - auto dequeued = ptr->dequeue_bulk(itemFirst, max); - count += dequeued; - if (dequeued != 0) { - token.currentProducer = ptr; - token.itemsConsumedFromCurrent = static_cast<std::uint32_t>(dequeued); - } - if (dequeued == max) { - break; - } - max -= dequeued; - ptr = ptr->next_prod(); - if (ptr == nullptr) { - ptr = tail; - } - } - return count; - } - - - // Attempts to dequeue from a specific producer's inner queue. - // If you happen to know which producer you want to dequeue from, this - // is significantly faster than using the general-case try_dequeue methods. - // Returns false if the producer's queue appeared empty at the time it - // was checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename U> - inline bool try_dequeue_from_producer(producer_token_t const& producer, U& item) - { - return static_cast<ExplicitProducer*>(producer.producer)->dequeue(item); - } - - // Attempts to dequeue several elements from a specific producer's inner queue. - // Returns the number of items actually dequeued. - // If you happen to know which producer you want to dequeue from, this - // is significantly faster than using the general-case try_dequeue methods. - // Returns 0 if the producer's queue appeared empty at the time it - // was checked (so, the queue is likely but not guaranteed to be empty). - // Never allocates. Thread-safe. - template <typename It> - inline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, - It itemFirst, - size_t max) - { - return static_cast<ExplicitProducer*>(producer.producer) - ->dequeue_bulk(itemFirst, max); - } - - - // Returns an estimate of the total number of elements currently in the queue. This - // estimate is only accurate if the queue has completely stabilized before it is - // called (i.e. all enqueue and dequeue operations have completed and their memory - // effects are visible on the calling thread, and no further operations start while - // this method is being called). Thread-safe. - size_t size_approx() const - { - size_t size = 0; - for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; - ptr = ptr->next_prod()) { - size += ptr->size_approx(); - } - return size; - } - - - // Returns true if the underlying atomic variables used by - // the queue are lock-free (they should be on most platforms). - // Thread-safe. - static bool is_lock_free() - { - return details::static_is_lock_free<bool>::value == 2 && - details::static_is_lock_free<size_t>::value == 2 && - details::static_is_lock_free<std::uint32_t>::value == 2 && - details::static_is_lock_free<index_t>::value == 2 && - details::static_is_lock_free<void*>::value == 2 && - details::static_is_lock_free<typename details::thread_id_converter< - details::thread_id_t>::thread_id_numeric_size_t>::value == 2; - } - - -private: - friend struct ProducerToken; - friend struct ConsumerToken; - struct ExplicitProducer; - friend struct ExplicitProducer; - struct ImplicitProducer; - friend struct ImplicitProducer; - friend class ConcurrentQueueTests; - - enum AllocationMode { CanAlloc, CannotAlloc }; - - - /////////////////////////////// - // Queue methods - /////////////////////////////// - - template <AllocationMode canAlloc, typename U> - inline bool inner_enqueue(producer_token_t const& token, U&& element) - { - return static_cast<ExplicitProducer*>(token.producer) - ->ConcurrentQueue::ExplicitProducer::template enqueue<canAlloc>( - std::forward<U>(element)); - } - - template <AllocationMode canAlloc, typename U> - inline bool inner_enqueue(U&& element) - { - auto producer = get_or_add_implicit_producer(); - return producer == nullptr - ? false - : producer - ->ConcurrentQueue::ImplicitProducer::template enqueue<canAlloc>( - std::forward<U>(element)); - } - - template <AllocationMode canAlloc, typename It> - inline bool - inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) - { - return static_cast<ExplicitProducer*>(token.producer) - ->ConcurrentQueue::ExplicitProducer::template enqueue_bulk<canAlloc>( - itemFirst, count); - } - - template <AllocationMode canAlloc, typename It> - inline bool inner_enqueue_bulk(It itemFirst, size_t count) - { - auto producer = get_or_add_implicit_producer(); - return producer == nullptr - ? false - : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk< - canAlloc>(itemFirst, count); - } - - inline bool update_current_producer_after_rotation(consumer_token_t& token) - { - // Ah, there's been a rotation, figure out where we should be! - auto tail = producerListTail.load(std::memory_order_acquire); - if (token.desiredProducer == nullptr && tail == nullptr) { - return false; - } - auto prodCount = producerCount.load(std::memory_order_relaxed); - auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed); - if ((details::unlikely)(token.desiredProducer == nullptr)) { - // Aha, first time we're dequeueing anything. - // Figure out our local position - // Note: offset is from start, not end, but we're traversing from end -- - // subtract from count first - std::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount); - token.desiredProducer = tail; - for (std::uint32_t i = 0; i != offset; ++i) { - token.desiredProducer = - static_cast<ProducerBase*>(token.desiredProducer)->next_prod(); - if (token.desiredProducer == nullptr) { - token.desiredProducer = tail; - } - } - } - - std::uint32_t delta = globalOffset - token.lastKnownGlobalOffset; - if (delta >= prodCount) { - delta = delta % prodCount; - } - for (std::uint32_t i = 0; i != delta; ++i) { - token.desiredProducer = - static_cast<ProducerBase*>(token.desiredProducer)->next_prod(); - if (token.desiredProducer == nullptr) { - token.desiredProducer = tail; - } - } - - token.lastKnownGlobalOffset = globalOffset; - token.currentProducer = token.desiredProducer; - token.itemsConsumedFromCurrent = 0; - return true; - } - - - /////////////////////////// - // Free list - /////////////////////////// - - template <typename N> - struct FreeListNode { - FreeListNode() : freeListRefs(0), freeListNext(nullptr) {} - - std::atomic<std::uint32_t> freeListRefs; - std::atomic<N*> freeListNext; - }; - - // A simple CAS-based lock-free free list. Not the fastest thing in the world under - // heavy contention, but simple and correct (assuming nodes are never freed until - // after the free list is destroyed), and fairly speedy under low contention. - template <typename N> // N must inherit FreeListNode or have the same fields (and - // initialization of them) - struct FreeList { - FreeList() : freeListHead(nullptr) {} - FreeList(FreeList&& other) - : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) - { - other.freeListHead.store(nullptr, std::memory_order_relaxed); - } - void swap(FreeList& other) - { - details::swap_relaxed(freeListHead, other.freeListHead); - } - - FreeList(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; - FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; - - inline void add(N* node) - { -#ifdef MCDBGQ_NOLOCKFREE_FREELIST - debug::DebugLock lock(mutex); -#endif - // We know that the should-be-on-freelist bit is 0 at this point, so it's safe - // to set it using a fetch_add - if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, - std::memory_order_acq_rel) == 0) { - // Oh look! We were the last ones referencing this node, and we know - // we want to add it to the free list, so let's do it! - add_knowing_refcount_is_zero(node); - } - } - - inline N* try_get() - { -#ifdef MCDBGQ_NOLOCKFREE_FREELIST - debug::DebugLock lock(mutex); -#endif - auto head = freeListHead.load(std::memory_order_acquire); - while (head != nullptr) { - auto prevHead = head; - auto refs = head->freeListRefs.load(std::memory_order_relaxed); - if ((refs & REFS_MASK) == 0 || - !head->freeListRefs.compare_exchange_strong( - refs, - refs + 1, - std::memory_order_acquire, - std::memory_order_relaxed)) { - head = freeListHead.load(std::memory_order_acquire); - continue; - } - - // Good, reference count has been incremented (it wasn't at zero), which - // means we can read the next and not worry about it changing between now - // and the time we do the CAS - auto next = head->freeListNext.load(std::memory_order_relaxed); - if (freeListHead.compare_exchange_strong(head, - next, - std::memory_order_acquire, - std::memory_order_relaxed)) { - // Yay, got the node. This means it was on the list, which means - // shouldBeOnFreeList must be false no matter the refcount (because - // nobody else knows it's been taken off yet, it can't have been put - // back on). - assert((head->freeListRefs.load(std::memory_order_relaxed) & - SHOULD_BE_ON_FREELIST) == 0); - - // Decrease refcount twice, once for our ref, and once for the list's - // ref - head->freeListRefs.fetch_sub(2, std::memory_order_release); - return head; - } - - // OK, the head must have changed on us, but we still need to decrease the - // refcount we increased. Note that we don't need to release any memory - // effects, but we do need to ensure that the reference count decrement - // happens-after the CAS on the head. - refs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel); - if (refs == SHOULD_BE_ON_FREELIST + 1) { - add_knowing_refcount_is_zero(prevHead); - } - } - - return nullptr; - } - - // Useful for traversing the list when there's no contention (e.g. to destroy - // remaining nodes) - N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); } - - private: - inline void add_knowing_refcount_is_zero(N* node) - { - // Since the refcount is zero, and nobody can increase it once it's zero - // (except us, and we run only one copy of this method per node at a time, - // i.e. the single thread case), then we know we can safely change the next - // pointer of the node; however, once the refcount is back above zero, then - // other threads could increase it (happens under heavy contention, when the - // refcount goes to zero in between a load and a refcount increment of a node - // in try_get, then back up to something non-zero, then the refcount increment - // is done by the other thread) -- so, if the CAS to add the node to the - // actual list fails, decrease the refcount and leave the add operation to the - // next thread who puts the refcount back at zero (which could be us, hence - // the loop). - auto head = freeListHead.load(std::memory_order_relaxed); - while (true) { - node->freeListNext.store(head, std::memory_order_relaxed); - node->freeListRefs.store(1, std::memory_order_release); - if (!freeListHead.compare_exchange_strong(head, - node, - std::memory_order_release, - std::memory_order_relaxed)) { - // Hmm, the add failed, but we can only try again when the refcount - // goes back to zero - if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, - std::memory_order_release) == 1) { - continue; - } - } - return; - } - } - - private: - // Implemented like a stack, but where node order doesn't matter (nodes are - // inserted out of order under contention) - std::atomic<N*> freeListHead; - - static const std::uint32_t REFS_MASK = 0x7FFFFFFF; - static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000; - -#ifdef MCDBGQ_NOLOCKFREE_FREELIST - debug::DebugMutex mutex; -#endif - }; - - - /////////////////////////// - // Block - /////////////////////////// - - enum InnerQueueContext { implicit_context = 0, explicit_context = 1 }; - - struct Block { - Block() - : next(nullptr), - elementsCompletelyDequeued(0), - freeListRefs(0), - freeListNext(nullptr), - shouldBeOnFreeList(false), - dynamicallyAllocated(true) - { -#ifdef MCDBGQ_TRACKMEM - owner = nullptr; -#endif - } - - template <InnerQueueContext context> - inline bool is_empty() const - { - MOODYCAMEL_CONSTEXPR_IF(context == explicit_context && - BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) - { - // Check flags - for (size_t i = 0; i < BLOCK_SIZE; ++i) { - if (!emptyFlags[i].load(std::memory_order_relaxed)) { - return false; - } - } - - // Aha, empty; make sure we have all other memory effects that happened - // before the empty flags were set - std::atomic_thread_fence(std::memory_order_acquire); - return true; - } - else - { - // Check counter - if (elementsCompletelyDequeued.load(std::memory_order_relaxed) == - BLOCK_SIZE) { - std::atomic_thread_fence(std::memory_order_acquire); - return true; - } - assert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= - BLOCK_SIZE); - return false; - } - } - - // Returns true if the block is now empty (does not apply in explicit context) - template <InnerQueueContext context> - inline bool set_empty(MOODYCAMEL_MAYBE_UNUSED index_t i) - { - MOODYCAMEL_CONSTEXPR_IF(context == explicit_context && - BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) - { - // Set flag - assert(!emptyFlags[BLOCK_SIZE - 1 - - static_cast<size_t>( - i & static_cast<index_t>(BLOCK_SIZE - 1))] - .load(std::memory_order_relaxed)); - emptyFlags[BLOCK_SIZE - 1 - - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1))] - .store(true, std::memory_order_release); - return false; - } - else - { - // Increment counter - auto prevVal = - elementsCompletelyDequeued.fetch_add(1, std::memory_order_release); - assert(prevVal < BLOCK_SIZE); - return prevVal == BLOCK_SIZE - 1; - } - } - - // Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and - // count > 0). Returns true if the block is now empty (does not apply in explicit - // context). - template <InnerQueueContext context> - inline bool set_many_empty(MOODYCAMEL_MAYBE_UNUSED index_t i, size_t count) - { - MOODYCAMEL_CONSTEXPR_IF(context == explicit_context && - BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) - { - // Set flags - std::atomic_thread_fence(std::memory_order_release); - i = BLOCK_SIZE - 1 - - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1)) - - count + 1; - for (size_t j = 0; j != count; ++j) { - assert(!emptyFlags[i + j].load(std::memory_order_relaxed)); - emptyFlags[i + j].store(true, std::memory_order_relaxed); - } - return false; - } - else - { - // Increment counter - auto prevVal = elementsCompletelyDequeued.fetch_add( - count, std::memory_order_release); - assert(prevVal + count <= BLOCK_SIZE); - return prevVal + count == BLOCK_SIZE; - } - } - - template <InnerQueueContext context> - inline void set_all_empty() - { - MOODYCAMEL_CONSTEXPR_IF(context == explicit_context && - BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) - { - // Set all flags - for (size_t i = 0; i != BLOCK_SIZE; ++i) { - emptyFlags[i].store(true, std::memory_order_relaxed); - } - } - else - { - // Reset counter - elementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed); - } - } - - template <InnerQueueContext context> - inline void reset_empty() - { - MOODYCAMEL_CONSTEXPR_IF(context == explicit_context && - BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) - { - // Reset flags - for (size_t i = 0; i != BLOCK_SIZE; ++i) { - emptyFlags[i].store(false, std::memory_order_relaxed); - } - } - else - { - // Reset counter - elementsCompletelyDequeued.store(0, std::memory_order_relaxed); - } - } - - inline T* operator[](index_t idx) MOODYCAMEL_NOEXCEPT - { - return static_cast<T*>(static_cast<void*>(elements)) + - static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); - } - inline T const* operator[](index_t idx) const MOODYCAMEL_NOEXCEPT - { - return static_cast<T const*>(static_cast<void const*>(elements)) + - static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); - } - - private: - static_assert(std::alignment_of<T>::value <= sizeof(T), - "The queue does not support types with an alignment greater than " - "their size at this time"); - MOODYCAMEL_ALIGNED_TYPE_LIKE(char[sizeof(T) * BLOCK_SIZE], T) elements; - - public: - Block* next; - std::atomic<size_t> elementsCompletelyDequeued; - std::atomic<bool> emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - ? BLOCK_SIZE - : 1]; - - public: - std::atomic<std::uint32_t> freeListRefs; - std::atomic<Block*> freeListNext; - std::atomic<bool> shouldBeOnFreeList; - bool dynamicallyAllocated; // Perhaps a better name for this would be - // 'isNotPartOfInitialBlockPool' - -#ifdef MCDBGQ_TRACKMEM - void* owner; -#endif - }; - static_assert(std::alignment_of<Block>::value >= std::alignment_of<T>::value, - "Internal error: Blocks must be at least as aligned as the type they " - "are wrapping"); - - -#ifdef MCDBGQ_TRACKMEM -public: - struct MemStats; - -private: -#endif - - /////////////////////////// - // Producer base - /////////////////////////// - - struct ProducerBase : public details::ConcurrentQueueProducerTypelessBase { - ProducerBase(ConcurrentQueue* parent_, bool isExplicit_) - : tailIndex(0), - headIndex(0), - dequeueOptimisticCount(0), - dequeueOvercommit(0), - tailBlock(nullptr), - isExplicit(isExplicit_), - parent(parent_) - { - } - - virtual ~ProducerBase() {} - - template <typename U> - inline bool dequeue(U& element) - { - if (isExplicit) { - return static_cast<ExplicitProducer*>(this)->dequeue(element); - } - else { - return static_cast<ImplicitProducer*>(this)->dequeue(element); - } - } - - template <typename It> - inline size_t dequeue_bulk(It& itemFirst, size_t max) - { - if (isExplicit) { - return static_cast<ExplicitProducer*>(this)->dequeue_bulk(itemFirst, max); - } - else { - return static_cast<ImplicitProducer*>(this)->dequeue_bulk(itemFirst, max); - } - } - - inline ProducerBase* next_prod() const - { - return static_cast<ProducerBase*>(next); - } - - inline size_t size_approx() const - { - auto tail = tailIndex.load(std::memory_order_relaxed); - auto head = headIndex.load(std::memory_order_relaxed); - return details::circular_less_than(head, tail) - ? static_cast<size_t>(tail - head) - : 0; - } - - inline index_t getTail() const - { - return tailIndex.load(std::memory_order_relaxed); - } - - protected: - std::atomic<index_t> tailIndex; // Where to enqueue to next - std::atomic<index_t> headIndex; // Where to dequeue from next - - std::atomic<index_t> dequeueOptimisticCount; - std::atomic<index_t> dequeueOvercommit; - - Block* tailBlock; - - public: - bool isExplicit; - ConcurrentQueue* parent; - - protected: -#ifdef MCDBGQ_TRACKMEM - friend struct MemStats; -#endif - }; - - - /////////////////////////// - // Explicit queue - /////////////////////////// - - struct ExplicitProducer : public ProducerBase { - explicit ExplicitProducer(ConcurrentQueue* parent_) - : ProducerBase(parent_, true), - blockIndex(nullptr), - pr_blockIndexSlotsUsed(0), - pr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1), - pr_blockIndexFront(0), - pr_blockIndexEntries(nullptr), - pr_blockIndexRaw(nullptr) - { - size_t poolBasedIndexSize = - details::ceil_to_pow_2(parent_->initialBlockPoolSize) >> 1; - if (poolBasedIndexSize > pr_blockIndexSize) { - pr_blockIndexSize = poolBasedIndexSize; - } - - new_block_index(0); // This creates an index with double the number of current - // entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE - } - - ~ExplicitProducer() override - { - // Destruct any elements not yet dequeued. - // Since we're in the destructor, we can assume all elements - // are either completely dequeued or completely not (no halfways). - if (this->tailBlock != - nullptr) { // Note this means there must be a block index too - // First find the block that's partially dequeued, if any - Block* halfDequeuedBlock = nullptr; - if ((this->headIndex.load(std::memory_order_relaxed) & - static_cast<index_t>(BLOCK_SIZE - 1)) != 0) { - // The head's not on a block boundary, meaning a block somewhere is - // partially dequeued (or the head block is the tail block and was - // fully dequeued, but the head/tail are still not on a boundary) - size_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & - (pr_blockIndexSize - 1); - while (details::circular_less_than<index_t>( - pr_blockIndexEntries[i].base + BLOCK_SIZE, - this->headIndex.load(std::memory_order_relaxed))) { - i = (i + 1) & (pr_blockIndexSize - 1); - } - assert(details::circular_less_than<index_t>( - pr_blockIndexEntries[i].base, - this->headIndex.load(std::memory_order_relaxed))); - halfDequeuedBlock = pr_blockIndexEntries[i].block; - } - - // Start at the head block (note the first line in the loop gives us the - // head from the tail on the first iteration) - auto block = this->tailBlock; - do { - block = block->next; - if (block->ConcurrentQueue::Block::template is_empty< - explicit_context>()) { - continue; - } - - size_t i = 0; // Offset into block - if (block == halfDequeuedBlock) { - i = static_cast<size_t>( - this->headIndex.load(std::memory_order_relaxed) & - static_cast<index_t>(BLOCK_SIZE - 1)); - } - - // Walk through all the items in the block; if this is the tail block, - // we need to stop when we reach the tail index - auto lastValidIndex = - (this->tailIndex.load(std::memory_order_relaxed) & - static_cast<index_t>(BLOCK_SIZE - 1)) == 0 - ? BLOCK_SIZE - : static_cast<size_t>( - this->tailIndex.load(std::memory_order_relaxed) & - static_cast<index_t>(BLOCK_SIZE - 1)); - while (i != BLOCK_SIZE && - (block != this->tailBlock || i != lastValidIndex)) { - (*block)[i++]->~T(); - } - } while (block != this->tailBlock); - } - - // Destroy all blocks that we own - if (this->tailBlock != nullptr) { - auto block = this->tailBlock; - do { - auto nextBlock = block->next; - if (block->dynamicallyAllocated) { - destroy(block); - } - else { - this->parent->add_block_to_free_list(block); - } - block = nextBlock; - } while (block != this->tailBlock); - } - - // Destroy the block indices - auto header = static_cast<BlockIndexHeader*>(pr_blockIndexRaw); - while (header != nullptr) { - auto prev = static_cast<BlockIndexHeader*>(header->prev); - header->~BlockIndexHeader(); - (Traits::free)(header); - header = prev; - } - } - - template <AllocationMode allocMode, typename U> - inline bool enqueue(U&& element) - { - index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); - index_t newTailIndex = 1 + currentTailIndex; - if ((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) { - // We reached the end of a block, start a new one - auto startBlock = this->tailBlock; - auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; - if (this->tailBlock != nullptr && - this->tailBlock->next - ->ConcurrentQueue::Block::template is_empty<explicit_context>()) { - // We can re-use the block ahead of us, it's empty! - this->tailBlock = this->tailBlock->next; - this->tailBlock->ConcurrentQueue::Block::template reset_empty< - explicit_context>(); - - // We'll put the block on the block index (guaranteed to be room since - // we're conceptually removing the last block from it first -- except - // instead of removing then adding, we can just overwrite). Note that - // there must be a valid block index here, since even if allocation - // failed in the ctor, it would have been re-attempted when adding the - // first block to the queue; since there is such a block, a block - // index must have been successfully allocated. - } - else { - // Whatever head value we see here is >= the last value we saw here - // (relatively), and <= its current value. Since we have the most - // recent tail, the head must be - // <= to it. - auto head = this->headIndex.load(std::memory_order_relaxed); - assert(!details::circular_less_than<index_t>(currentTailIndex, head)); - if (!details::circular_less_than<index_t>( - head, currentTailIndex + BLOCK_SIZE) || - (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && - (MAX_SUBQUEUE_SIZE == 0 || - MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { - // We can't enqueue in another block because there's not enough - // leeway -- the tail could surpass the head by the time the block - // fills up! (Or we'll exceed the size limit, if the second part - // of the condition was true.) - return false; - } - // We're going to need a new block; check that the block index has - // room - if (pr_blockIndexRaw == nullptr || - pr_blockIndexSlotsUsed == pr_blockIndexSize) { - // Hmm, the circular block index is already full -- we'll need - // to allocate a new index. Note pr_blockIndexRaw can only be - // nullptr if the initial allocation failed in the constructor. - - MOODYCAMEL_CONSTEXPR_IF(allocMode == CannotAlloc) - { - return false; - } - else if (!new_block_index(pr_blockIndexSlotsUsed)) - { - return false; - } - } - - // Insert a new block in the circular linked list - auto newBlock = - this->parent - ->ConcurrentQueue::template requisition_block<allocMode>(); - if (newBlock == nullptr) { - return false; - } -#ifdef MCDBGQ_TRACKMEM - newBlock->owner = this; -#endif - newBlock->ConcurrentQueue::Block::template reset_empty< - explicit_context>(); - if (this->tailBlock == nullptr) { - newBlock->next = newBlock; - } - else { - newBlock->next = this->tailBlock->next; - this->tailBlock->next = newBlock; - } - this->tailBlock = newBlock; - ++pr_blockIndexSlotsUsed; - } - - MOODYCAMEL_CONSTEXPR_IF(!MOODYCAMEL_NOEXCEPT_CTOR( - T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) - { - // The constructor may throw. We want the element not to appear in the - // queue in that case (without corrupting the queue): - MOODYCAMEL_TRY - { - new ((*this->tailBlock)[currentTailIndex]) - T(std::forward<U>(element)); - } - MOODYCAMEL_CATCH(...) - { - // Revert change to the current block, but leave the new block - // available for next time - pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; - this->tailBlock = - startBlock == nullptr ? this->tailBlock : startBlock; - MOODYCAMEL_RETHROW; - } - } - else - { - (void)startBlock; - (void)originalBlockIndexSlotsUsed; - } - - // Add block to block index - auto& entry = blockIndex.load(std::memory_order_relaxed) - ->entries[pr_blockIndexFront]; - entry.base = currentTailIndex; - entry.block = this->tailBlock; - blockIndex.load(std::memory_order_relaxed) - ->front.store(pr_blockIndexFront, std::memory_order_release); - pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); - - MOODYCAMEL_CONSTEXPR_IF(!MOODYCAMEL_NOEXCEPT_CTOR( - T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) - { - this->tailIndex.store(newTailIndex, std::memory_order_release); - return true; - } - } - - // Enqueue - new ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element)); - - this->tailIndex.store(newTailIndex, std::memory_order_release); - return true; - } - - template <typename U> - bool dequeue(U& element) - { - auto tail = this->tailIndex.load(std::memory_order_relaxed); - auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); - if (details::circular_less_than<index_t>( - this->dequeueOptimisticCount.load(std::memory_order_relaxed) - - overcommit, - tail)) { - // Might be something to dequeue, let's give it a try - - // Note that this if is purely for performance purposes in the common case - // when the queue is empty and the values are eventually consistent -- we - // may enter here spuriously. - - // Note that whatever the values of overcommit and tail are, they are not - // going to change (unless we change them) and must be the same value at - // this point (inside the if) as when the if condition was evaluated. - - // We insert an acquire fence here to synchronize-with the release upon - // incrementing dequeueOvercommit below. This ensures that whatever the - // value we got loaded into overcommit, the load of dequeueOptisticCount - // in the fetch_add below will result in a value at least as recent as - // that (and therefore at least as large). Note that I believe a compiler - // (signal) fence here would be sufficient due to the nature of fetch_add - // (all read-modify-write operations are guaranteed to work on the latest - // value in the modification order), but unfortunately that can't be shown - // to be correct using only the C++11 standard. See - // http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case - std::atomic_thread_fence(std::memory_order_acquire); - - // Increment optimistic counter, then check if it went over the boundary - auto myDequeueCount = - this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); - - // Note that since dequeueOvercommit must be <= dequeueOptimisticCount - // (because dequeueOvercommit is only ever incremented after - // dequeueOptimisticCount -- this is enforced in the `else` block below), - // and since we now have a version of dequeueOptimisticCount that is at - // least as recent as overcommit (due to the release upon incrementing - // dequeueOvercommit and the acquire above that synchronizes with it), - // overcommit <= myDequeueCount. However, we can't assert this since both - // dequeueOptimisticCount and dequeueOvercommit may (independently) - // overflow; in such a case, though, the logic still holds since the - // difference between the two is maintained. - - // Note that we reload tail here in case it changed; it will be the same - // value as before or greater, since this load is sequenced after (happens - // after) the earlier load above. This is supported by read-read coherency - // (as defined in the standard), explained here: - // http://en.cppreference.com/w/cpp/atomic/memory_order - tail = this->tailIndex.load(std::memory_order_acquire); - if ((details::likely)(details::circular_less_than<index_t>( - myDequeueCount - overcommit, tail))) { - // Guaranteed to be at least one element to dequeue! - - // Get the index. Note that since there's guaranteed to be at least - // one element, this will never exceed tail. We need to do an - // acquire-release fence here since it's possible that whatever - // condition got us to this point was for an earlier enqueued element - // (that we already see the memory effects for), but that by the time - // we increment somebody else has incremented it, and we need to see - // the memory effects for *that* element, which is in such a case is - // necessarily visible on the thread that incremented it in the first - // place with the more current condition (they must have acquired a - // tail that is at least as recent). - auto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); - - - // Determine which block the element is in - - auto localBlockIndex = blockIndex.load(std::memory_order_acquire); - auto localBlockIndexHead = - localBlockIndex->front.load(std::memory_order_acquire); - - // We need to be careful here about subtracting and dividing because - // of index wrap-around. When an index wraps, we need to preserve the - // sign of the offset when dividing it by the block size (in order to - // get a correct signed block count offset in all cases): - auto headBase = localBlockIndex->entries[localBlockIndexHead].base; - auto blockBaseIndex = index & ~static_cast<index_t>(BLOCK_SIZE - 1); - auto offset = static_cast<size_t>( - static_cast<typename std::make_signed<index_t>::type>( - blockBaseIndex - headBase) / - BLOCK_SIZE); - auto block = localBlockIndex - ->entries[(localBlockIndexHead + offset) & - (localBlockIndex->size - 1)] - .block; - - // Dequeue - auto& el = *((*block)[index]); - if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { - // Make sure the element is still fully dequeued and destroyed - // even if the assignment throws - struct Guard { - Block* block; - index_t index; - - ~Guard() - { - (*block)[index]->~T(); - block->ConcurrentQueue::Block::template set_empty< - explicit_context>(index); - } - } guard = { block, index }; - - element = std::move(el); // NOLINT - } - else { - element = std::move(el); // NOLINT - el.~T(); // NOLINT - block->ConcurrentQueue::Block::template set_empty< - explicit_context>(index); - } - - return true; - } - else { - // Wasn't anything to dequeue after all; make the effective dequeue - // count eventually consistent - this->dequeueOvercommit.fetch_add( - 1, std::memory_order_release); // Release so that the fetch_add on - // dequeueOptimisticCount is - // guaranteed to happen before this - // write - } - } - - return false; - } - - template <AllocationMode allocMode, typename It> - bool MOODYCAMEL_NO_TSAN enqueue_bulk(It itemFirst, size_t count) - { - // First, we need to make sure we have enough room to enqueue all of the - // elements; this means pre-allocating blocks and putting them in the block - // index (but only if all the allocations succeeded). - index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); - auto startBlock = this->tailBlock; - auto originalBlockIndexFront = pr_blockIndexFront; - auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; - - Block* firstAllocatedBlock = nullptr; - - // Figure out how many blocks we'll need to allocate, and do so - size_t blockBaseDiff = - ((startTailIndex + count - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)) - - ((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)); - index_t currentTailIndex = - (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1); - if (blockBaseDiff > 0) { - // Allocate as many blocks as possible from ahead - while ( - blockBaseDiff > 0 && this->tailBlock != nullptr && - this->tailBlock->next != firstAllocatedBlock && - this->tailBlock->next - ->ConcurrentQueue::Block::template is_empty<explicit_context>()) { - blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE); - currentTailIndex += static_cast<index_t>(BLOCK_SIZE); - - this->tailBlock = this->tailBlock->next; - firstAllocatedBlock = firstAllocatedBlock == nullptr - ? this->tailBlock - : firstAllocatedBlock; - - auto& entry = blockIndex.load(std::memory_order_relaxed) - ->entries[pr_blockIndexFront]; - entry.base = currentTailIndex; - entry.block = this->tailBlock; - pr_blockIndexFront = - (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); - } - - // Now allocate as many blocks as necessary from the block pool - while (blockBaseDiff > 0) { - blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE); - currentTailIndex += static_cast<index_t>(BLOCK_SIZE); - - auto head = this->headIndex.load(std::memory_order_relaxed); - assert(!details::circular_less_than<index_t>(currentTailIndex, head)); - bool full = - !details::circular_less_than<index_t>( - head, currentTailIndex + BLOCK_SIZE) || - (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && - (MAX_SUBQUEUE_SIZE == 0 || - MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); - if (pr_blockIndexRaw == nullptr || - pr_blockIndexSlotsUsed == pr_blockIndexSize || full) { - MOODYCAMEL_CONSTEXPR_IF(allocMode == CannotAlloc) - { - // Failed to allocate, undo changes (but keep injected blocks) - pr_blockIndexFront = originalBlockIndexFront; - pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; - this->tailBlock = - startBlock == nullptr ? firstAllocatedBlock : startBlock; - return false; - } - else if (full || !new_block_index(originalBlockIndexSlotsUsed)) - { - // Failed to allocate, undo changes (but keep injected blocks) - pr_blockIndexFront = originalBlockIndexFront; - pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; - this->tailBlock = - startBlock == nullptr ? firstAllocatedBlock : startBlock; - return false; - } - - // pr_blockIndexFront is updated inside new_block_index, so we - // need to update our fallback value too (since we keep the new - // index even if we later fail) - originalBlockIndexFront = originalBlockIndexSlotsUsed; - } - - // Insert a new block in the circular linked list - auto newBlock = - this->parent - ->ConcurrentQueue::template requisition_block<allocMode>(); - if (newBlock == nullptr) { - pr_blockIndexFront = originalBlockIndexFront; - pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; - this->tailBlock = - startBlock == nullptr ? firstAllocatedBlock : startBlock; - return false; - } - -#ifdef MCDBGQ_TRACKMEM - newBlock->owner = this; -#endif - newBlock->ConcurrentQueue::Block::template set_all_empty< - explicit_context>(); - if (this->tailBlock == nullptr) { - newBlock->next = newBlock; - } - else { - newBlock->next = this->tailBlock->next; - this->tailBlock->next = newBlock; - } - this->tailBlock = newBlock; - firstAllocatedBlock = firstAllocatedBlock == nullptr - ? this->tailBlock - : firstAllocatedBlock; - - ++pr_blockIndexSlotsUsed; - - auto& entry = blockIndex.load(std::memory_order_relaxed) - ->entries[pr_blockIndexFront]; - entry.base = currentTailIndex; - entry.block = this->tailBlock; - pr_blockIndexFront = - (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); - } - - // Excellent, all allocations succeeded. Reset each block's emptiness - // before we fill them up, and publish the new block index front - auto block = firstAllocatedBlock; - while (true) { - block->ConcurrentQueue::Block::template reset_empty< - explicit_context>(); - if (block == this->tailBlock) { - break; - } - block = block->next; - } - - MOODYCAMEL_CONSTEXPR_IF(MOODYCAMEL_NOEXCEPT_CTOR( - T, - decltype(*itemFirst), - new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) - { - blockIndex.load(std::memory_order_relaxed) - ->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), - std::memory_order_release); - } - } - - // Enqueue, one block at a time - index_t newTailIndex = startTailIndex + static_cast<index_t>(count); - currentTailIndex = startTailIndex; - auto endBlock = this->tailBlock; - this->tailBlock = startBlock; - assert((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || - firstAllocatedBlock != nullptr || count == 0); - if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 && - firstAllocatedBlock != nullptr) { - this->tailBlock = firstAllocatedBlock; - } - while (true) { - index_t stopIndex = - (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - if (details::circular_less_than<index_t>(newTailIndex, stopIndex)) { - stopIndex = newTailIndex; - } - MOODYCAMEL_CONSTEXPR_IF(MOODYCAMEL_NOEXCEPT_CTOR( - T, - decltype(*itemFirst), - new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) - { - while (currentTailIndex != stopIndex) { - new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); - } - } - else - { - MOODYCAMEL_TRY - { - while (currentTailIndex != stopIndex) { - // Must use copy constructor even if move constructor is - // available because we may have to revert if there's an - // exception. Sorry about the horrible templated next line, - // but it was the only way to disable moving *at compile - // time*, which is important because a type may only define a - // (noexcept) move constructor, and so calls to the cctor will - // not compile, even if they are in an if branch that will - // never be executed - new ((*this->tailBlock)[currentTailIndex]) - T(details::nomove_if<!MOODYCAMEL_NOEXCEPT_CTOR( - T, - decltype(*itemFirst), - new (static_cast<T*>(nullptr)) - T(details::deref_noexcept( - itemFirst)))>::eval(*itemFirst)); - ++currentTailIndex; - ++itemFirst; - } - } - MOODYCAMEL_CATCH(...) - { - // Oh dear, an exception's been thrown -- destroy the elements - // that were enqueued so far and revert the entire bulk operation - // (we'll keep any allocated blocks in our linked list for later, - // though). - auto constructedStopIndex = currentTailIndex; - auto lastBlockEnqueued = this->tailBlock; - - pr_blockIndexFront = originalBlockIndexFront; - pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; - this->tailBlock = - startBlock == nullptr ? firstAllocatedBlock : startBlock; - - if (!details::is_trivially_destructible<T>::value) { - auto block = startBlock; - if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == - 0) { - block = firstAllocatedBlock; - } - currentTailIndex = startTailIndex; - while (true) { - stopIndex = (currentTailIndex & - ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - if (details::circular_less_than<index_t>( - constructedStopIndex, stopIndex)) { - stopIndex = constructedStopIndex; - } - while (currentTailIndex != stopIndex) { - (*block)[currentTailIndex++]->~T(); - } - if (block == lastBlockEnqueued) { - break; - } - block = block->next; - } - } - MOODYCAMEL_RETHROW; - } - } - - if (this->tailBlock == endBlock) { - assert(currentTailIndex == newTailIndex); - break; - } - this->tailBlock = this->tailBlock->next; - } - - MOODYCAMEL_CONSTEXPR_IF(!MOODYCAMEL_NOEXCEPT_CTOR( - T, - decltype(*itemFirst), - new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) - { - if (firstAllocatedBlock != nullptr) - blockIndex.load(std::memory_order_relaxed) - ->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), - std::memory_order_release); - } - - this->tailIndex.store(newTailIndex, std::memory_order_release); - return true; - } - - template <typename It> - size_t dequeue_bulk(It& itemFirst, size_t max) - { - auto tail = this->tailIndex.load(std::memory_order_relaxed); - auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); - auto desiredCount = static_cast<size_t>( - tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - - overcommit)); - if (details::circular_less_than<size_t>(0, desiredCount)) { - desiredCount = desiredCount < max ? desiredCount : max; - std::atomic_thread_fence(std::memory_order_acquire); - - auto myDequeueCount = this->dequeueOptimisticCount.fetch_add( - desiredCount, std::memory_order_relaxed); - - tail = this->tailIndex.load(std::memory_order_acquire); - auto actualCount = - static_cast<size_t>(tail - (myDequeueCount - overcommit)); - if (details::circular_less_than<size_t>(0, actualCount)) { - actualCount = desiredCount < actualCount ? desiredCount : actualCount; - if (actualCount < desiredCount) { - this->dequeueOvercommit.fetch_add(desiredCount - actualCount, - std::memory_order_release); - } - - // Get the first index. Note that since there's guaranteed to be at - // least actualCount elements, this will never exceed tail. - auto firstIndex = - this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); - - // Determine which block the first element is in - auto localBlockIndex = blockIndex.load(std::memory_order_acquire); - auto localBlockIndexHead = - localBlockIndex->front.load(std::memory_order_acquire); - - auto headBase = localBlockIndex->entries[localBlockIndexHead].base; - auto firstBlockBaseIndex = - firstIndex & ~static_cast<index_t>(BLOCK_SIZE - 1); - auto offset = static_cast<size_t>( - static_cast<typename std::make_signed<index_t>::type>( - firstBlockBaseIndex - headBase) / - BLOCK_SIZE); - auto indexIndex = - (localBlockIndexHead + offset) & (localBlockIndex->size - 1); - - // Iterate the blocks and dequeue - auto index = firstIndex; - do { - auto firstIndexInBlock = index; - index_t endIndex = - (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - endIndex = - details::circular_less_than<index_t>( - firstIndex + static_cast<index_t>(actualCount), endIndex) - ? firstIndex + static_cast<index_t>(actualCount) - : endIndex; - auto block = localBlockIndex->entries[indexIndex].block; - if (MOODYCAMEL_NOEXCEPT_ASSIGN( - T, - T&&, - details::deref_noexcept(itemFirst) = - std::move((*(*block)[index])))) { - while (index != endIndex) { - auto& el = *((*block)[index]); - *itemFirst++ = std::move(el); - el.~T(); - ++index; - } - } - else { - MOODYCAMEL_TRY - { - while (index != endIndex) { - auto& el = *((*block)[index]); - *itemFirst = std::move(el); - ++itemFirst; - el.~T(); - ++index; - } - } - MOODYCAMEL_CATCH(...) - { - // It's too late to revert the dequeue, but we can make - // sure that all the dequeued objects are properly - // destroyed and the block index (and empty count) are - // properly updated before we propagate the exception - do { - block = localBlockIndex->entries[indexIndex].block; - while (index != endIndex) { - (*block)[index++]->~T(); - } - block->ConcurrentQueue::Block:: - template set_many_empty<explicit_context>( - firstIndexInBlock, - static_cast<size_t>(endIndex - - firstIndexInBlock)); - indexIndex = - (indexIndex + 1) & (localBlockIndex->size - 1); - - firstIndexInBlock = index; - endIndex = - (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - endIndex = details::circular_less_than<index_t>( - firstIndex + - static_cast<index_t>(actualCount), - endIndex) - ? firstIndex + - static_cast<index_t>(actualCount) - : endIndex; - } while (index != firstIndex + actualCount); - - MOODYCAMEL_RETHROW; - } - } - block->ConcurrentQueue::Block::template set_many_empty< - explicit_context>( - firstIndexInBlock, - static_cast<size_t>(endIndex - firstIndexInBlock)); - indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); - } while (index != firstIndex + actualCount); - - return actualCount; - } - else { - // Wasn't anything to dequeue after all; make the effective dequeue - // count eventually consistent - this->dequeueOvercommit.fetch_add(desiredCount, - std::memory_order_release); - } - } - - return 0; - } - - private: - struct BlockIndexEntry { - index_t base; - Block* block; - }; - - struct BlockIndexHeader { - size_t size; - std::atomic<size_t> front; // Current slot (not next, like pr_blockIndexFront) - BlockIndexEntry* entries; - void* prev; - }; - - - bool new_block_index(size_t numberOfFilledSlotsToExpose) - { - auto prevBlockSizeMask = pr_blockIndexSize - 1; - - // Create the new block - pr_blockIndexSize <<= 1; - auto newRawPtr = static_cast<char*>((Traits::malloc)( - sizeof(BlockIndexHeader) + std::alignment_of<BlockIndexEntry>::value - 1 + - sizeof(BlockIndexEntry) * pr_blockIndexSize)); - if (newRawPtr == nullptr) { - pr_blockIndexSize >>= 1; // Reset to allow graceful retry - return false; - } - - auto newBlockIndexEntries = - reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>( - newRawPtr + sizeof(BlockIndexHeader))); - - // Copy in all the old indices, if any - size_t j = 0; - if (pr_blockIndexSlotsUsed != 0) { - auto i = - (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; - do { - newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; - i = (i + 1) & prevBlockSizeMask; - } while (i != pr_blockIndexFront); - } - - // Update everything - auto header = new (newRawPtr) BlockIndexHeader; - header->size = pr_blockIndexSize; - header->front.store(numberOfFilledSlotsToExpose - 1, - std::memory_order_relaxed); - header->entries = newBlockIndexEntries; - header->prev = pr_blockIndexRaw; // we link the new block to the old one so we - // can free it later - - pr_blockIndexFront = j; - pr_blockIndexEntries = newBlockIndexEntries; - pr_blockIndexRaw = newRawPtr; - blockIndex.store(header, std::memory_order_release); - - return true; - } - - private: - std::atomic<BlockIndexHeader*> blockIndex; - - // To be used by producer only -- consumer must use the ones in referenced by - // blockIndex - size_t pr_blockIndexSlotsUsed; - size_t pr_blockIndexSize; - size_t pr_blockIndexFront; // Next slot (not current) - BlockIndexEntry* pr_blockIndexEntries; - void* pr_blockIndexRaw; - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - public: - ExplicitProducer* nextExplicitProducer; - - private: -#endif - -#ifdef MCDBGQ_TRACKMEM - friend struct MemStats; -#endif - }; - - - ////////////////////////////////// - // Implicit queue - ////////////////////////////////// - - struct ImplicitProducer : public ProducerBase { - ImplicitProducer(ConcurrentQueue* parent_) - : ProducerBase(parent_, false), - nextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE), - blockIndex(nullptr) - { - new_block_index(); - } - - ~ImplicitProducer() override - { - // Note that since we're in the destructor we can assume that all - // enqueue/dequeue operations completed already; this means that all - // undequeued elements are placed contiguously across contiguous blocks, and - // that only the first and last remaining blocks can be only partially empty - // (all other remaining blocks must be completely full). - -#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED - // Unregister ourselves for thread termination notification - if (!this->inactive.load(std::memory_order_relaxed)) { - details::ThreadExitNotifier::unsubscribe(&threadExitListener); - } -#endif - - // Destroy all remaining elements! - auto tail = this->tailIndex.load(std::memory_order_relaxed); - auto index = this->headIndex.load(std::memory_order_relaxed); - Block* block = nullptr; - assert(index == tail || details::circular_less_than(index, tail)); - bool forceFreeLastBlock = - index != tail; // If we enter the loop, then the last (tail) block will - // not be freed - while (index != tail) { - if ((index & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 || - block == nullptr) { - if (block != nullptr) { - // Free the old block - this->parent->add_block_to_free_list(block); - } - - block = get_block_index_entry_for_index(index)->value.load( - std::memory_order_relaxed); - } - - ((*block)[index])->~T(); - ++index; - } - // Even if the queue is empty, there's still one block that's not on the free - // list (unless the head index reached the end of it, in which case the tail - // will be poised to create a new block). - if (this->tailBlock != nullptr && - (forceFreeLastBlock || - (tail & static_cast<index_t>(BLOCK_SIZE - 1)) != 0)) { - this->parent->add_block_to_free_list(this->tailBlock); - } - - // Destroy block index - auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); - if (localBlockIndex != nullptr) { - for (size_t i = 0; i != localBlockIndex->capacity; ++i) { - localBlockIndex->index[i]->~BlockIndexEntry(); - } - do { - auto prev = localBlockIndex->prev; - localBlockIndex->~BlockIndexHeader(); - (Traits::free)(localBlockIndex); - localBlockIndex = prev; - } while (localBlockIndex != nullptr); - } - } - - template <AllocationMode allocMode, typename U> - inline bool enqueue(U&& element) - { - index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); - index_t newTailIndex = 1 + currentTailIndex; - if ((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) { - // We reached the end of a block, start a new one - auto head = this->headIndex.load(std::memory_order_relaxed); - assert(!details::circular_less_than<index_t>(currentTailIndex, head)); - if (!details::circular_less_than<index_t>( - head, currentTailIndex + BLOCK_SIZE) || - (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && - (MAX_SUBQUEUE_SIZE == 0 || - MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { - return false; - } -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - debug::DebugLock lock(mutex); -#endif - // Find out where we'll be inserting this block in the block index - BlockIndexEntry* idxEntry; - if (!insert_block_index_entry<allocMode>(idxEntry, currentTailIndex)) { - return false; - } - - // Get ahold of a new block - auto newBlock = - this->parent - ->ConcurrentQueue::template requisition_block<allocMode>(); - if (newBlock == nullptr) { - rewind_block_index_tail(); - idxEntry->value.store(nullptr, std::memory_order_relaxed); - return false; - } -#ifdef MCDBGQ_TRACKMEM - newBlock->owner = this; -#endif - newBlock - ->ConcurrentQueue::Block::template reset_empty<implicit_context>(); - - MOODYCAMEL_CONSTEXPR_IF(!MOODYCAMEL_NOEXCEPT_CTOR( - T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) - { - // May throw, try to insert now before we publish the fact that we - // have this new block - MOODYCAMEL_TRY - { - new ((*newBlock)[currentTailIndex]) T(std::forward<U>(element)); - } - MOODYCAMEL_CATCH(...) - { - rewind_block_index_tail(); - idxEntry->value.store(nullptr, std::memory_order_relaxed); - this->parent->add_block_to_free_list(newBlock); - MOODYCAMEL_RETHROW; - } - } - - // Insert the new block into the index - idxEntry->value.store(newBlock, std::memory_order_relaxed); - - this->tailBlock = newBlock; - - MOODYCAMEL_CONSTEXPR_IF(!MOODYCAMEL_NOEXCEPT_CTOR( - T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) - { - this->tailIndex.store(newTailIndex, std::memory_order_release); - return true; - } - } - - // Enqueue - new ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element)); - - this->tailIndex.store(newTailIndex, std::memory_order_release); - return true; - } - - template <typename U> - bool dequeue(U& element) - { - // See ExplicitProducer::dequeue for rationale and explanation - index_t tail = this->tailIndex.load(std::memory_order_relaxed); - index_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); - if (details::circular_less_than<index_t>( - this->dequeueOptimisticCount.load(std::memory_order_relaxed) - - overcommit, - tail)) { - std::atomic_thread_fence(std::memory_order_acquire); - - index_t myDequeueCount = - this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); - tail = this->tailIndex.load(std::memory_order_acquire); - if ((details::likely)(details::circular_less_than<index_t>( - myDequeueCount - overcommit, tail))) { - index_t index = - this->headIndex.fetch_add(1, std::memory_order_acq_rel); - - // Determine which block the element is in - auto entry = get_block_index_entry_for_index(index); - - // Dequeue - auto block = entry->value.load(std::memory_order_relaxed); - auto& el = *((*block)[index]); - - if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - // Note: Acquiring the mutex with every dequeue instead of only - // when a block is released is very sub-optimal, but it is, after - // all, purely debug code. - debug::DebugLock lock(producer->mutex); -#endif - struct Guard { - Block* block; - index_t index; - BlockIndexEntry* entry; - ConcurrentQueue* parent; - - ~Guard() - { - (*block)[index]->~T(); - if (block->ConcurrentQueue::Block::template set_empty< - implicit_context>(index)) { - entry->value.store(nullptr, - std::memory_order_relaxed); - parent->add_block_to_free_list(block); - } - } - } guard = { block, index, entry, this->parent }; - - element = std::move(el); // NOLINT - } - else { - element = std::move(el); // NOLINT - el.~T(); // NOLINT - - if (block->ConcurrentQueue::Block::template set_empty< - implicit_context>(index)) { - { -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - debug::DebugLock lock(mutex); -#endif - // Add the block back into the global free pool (and - // remove from block index) - entry->value.store(nullptr, std::memory_order_relaxed); - } - this->parent->add_block_to_free_list( - block); // releases the above store - } - } - - return true; - } - else { - this->dequeueOvercommit.fetch_add(1, std::memory_order_release); - } - } - - return false; - } - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4706) // assignment within conditional expression -#endif - template <AllocationMode allocMode, typename It> - bool enqueue_bulk(It itemFirst, size_t count) - { - // First, we need to make sure we have enough room to enqueue all of the - // elements; this means pre-allocating blocks and putting them in the block - // index (but only if all the allocations succeeded). - - // Note that the tailBlock we start off with may not be owned by us any more; - // this happens if it was filled up exactly to the top (setting tailIndex to - // the first index of the next block which is not yet allocated), then - // dequeued completely (putting it on the free list) before we enqueue again. - - index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); - auto startBlock = this->tailBlock; - Block* firstAllocatedBlock = nullptr; - auto endBlock = this->tailBlock; - - // Figure out how many blocks we'll need to allocate, and do so - size_t blockBaseDiff = - ((startTailIndex + count - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)) - - ((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)); - index_t currentTailIndex = - (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1); - if (blockBaseDiff > 0) { -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - debug::DebugLock lock(mutex); -#endif - do { - blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE); - currentTailIndex += static_cast<index_t>(BLOCK_SIZE); - - // Find out where we'll be inserting this block in the block index - BlockIndexEntry* idxEntry = - nullptr; // initialization here unnecessary but compiler can't - // always tell - Block* newBlock; - bool indexInserted = false; - auto head = this->headIndex.load(std::memory_order_relaxed); - assert(!details::circular_less_than<index_t>(currentTailIndex, head)); - bool full = - !details::circular_less_than<index_t>( - head, currentTailIndex + BLOCK_SIZE) || - (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && - (MAX_SUBQUEUE_SIZE == 0 || - MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); - - if (full || - !(indexInserted = insert_block_index_entry<allocMode>( - idxEntry, currentTailIndex)) || - (newBlock = - this->parent->ConcurrentQueue::template requisition_block< - allocMode>()) == nullptr) { - // Index allocation or block allocation failed; revert any other - // allocations and index insertions done so far for this operation - if (indexInserted) { - rewind_block_index_tail(); - idxEntry->value.store(nullptr, std::memory_order_relaxed); - } - currentTailIndex = - (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1); - for (auto block = firstAllocatedBlock; block != nullptr; - block = block->next) { - currentTailIndex += static_cast<index_t>(BLOCK_SIZE); - idxEntry = get_block_index_entry_for_index(currentTailIndex); - idxEntry->value.store(nullptr, std::memory_order_relaxed); - rewind_block_index_tail(); - } - this->parent->add_blocks_to_free_list(firstAllocatedBlock); - this->tailBlock = startBlock; - - return false; - } - -#ifdef MCDBGQ_TRACKMEM - newBlock->owner = this; -#endif - newBlock->ConcurrentQueue::Block::template reset_empty< - implicit_context>(); - newBlock->next = nullptr; - - // Insert the new block into the index - idxEntry->value.store(newBlock, std::memory_order_relaxed); - - // Store the chain of blocks so that we can undo if later allocations - // fail, and so that we can find the blocks when we do the actual - // enqueueing - if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || - firstAllocatedBlock != nullptr) { - assert(this->tailBlock != nullptr); - this->tailBlock->next = newBlock; - } - this->tailBlock = newBlock; - endBlock = newBlock; - firstAllocatedBlock = - firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock; - } while (blockBaseDiff > 0); - } - - // Enqueue, one block at a time - index_t newTailIndex = startTailIndex + static_cast<index_t>(count); - currentTailIndex = startTailIndex; - this->tailBlock = startBlock; - assert((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || - firstAllocatedBlock != nullptr || count == 0); - if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 && - firstAllocatedBlock != nullptr) { - this->tailBlock = firstAllocatedBlock; - } - while (true) { - index_t stopIndex = - (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - if (details::circular_less_than<index_t>(newTailIndex, stopIndex)) { - stopIndex = newTailIndex; - } - MOODYCAMEL_CONSTEXPR_IF(MOODYCAMEL_NOEXCEPT_CTOR( - T, - decltype(*itemFirst), - new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) - { - while (currentTailIndex != stopIndex) { - new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); - } - } - else - { - MOODYCAMEL_TRY - { - while (currentTailIndex != stopIndex) { - new ((*this->tailBlock)[currentTailIndex]) - T(details::nomove_if<!MOODYCAMEL_NOEXCEPT_CTOR( - T, - decltype(*itemFirst), - new (static_cast<T*>(nullptr)) - T(details::deref_noexcept( - itemFirst)))>::eval(*itemFirst)); - ++currentTailIndex; - ++itemFirst; - } - } - MOODYCAMEL_CATCH(...) - { - auto constructedStopIndex = currentTailIndex; - auto lastBlockEnqueued = this->tailBlock; - - if (!details::is_trivially_destructible<T>::value) { - auto block = startBlock; - if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == - 0) { - block = firstAllocatedBlock; - } - currentTailIndex = startTailIndex; - while (true) { - stopIndex = (currentTailIndex & - ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - if (details::circular_less_than<index_t>( - constructedStopIndex, stopIndex)) { - stopIndex = constructedStopIndex; - } - while (currentTailIndex != stopIndex) { - (*block)[currentTailIndex++]->~T(); - } - if (block == lastBlockEnqueued) { - break; - } - block = block->next; - } - } - - currentTailIndex = - (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1); - for (auto block = firstAllocatedBlock; block != nullptr; - block = block->next) { - currentTailIndex += static_cast<index_t>(BLOCK_SIZE); - auto idxEntry = - get_block_index_entry_for_index(currentTailIndex); - idxEntry->value.store(nullptr, std::memory_order_relaxed); - rewind_block_index_tail(); - } - this->parent->add_blocks_to_free_list(firstAllocatedBlock); - this->tailBlock = startBlock; - MOODYCAMEL_RETHROW; - } - } - - if (this->tailBlock == endBlock) { - assert(currentTailIndex == newTailIndex); - break; - } - this->tailBlock = this->tailBlock->next; - } - this->tailIndex.store(newTailIndex, std::memory_order_release); - return true; - } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - template <typename It> - size_t dequeue_bulk(It& itemFirst, size_t max) - { - auto tail = this->tailIndex.load(std::memory_order_relaxed); - auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); - auto desiredCount = static_cast<size_t>( - tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - - overcommit)); - if (details::circular_less_than<size_t>(0, desiredCount)) { - desiredCount = desiredCount < max ? desiredCount : max; - std::atomic_thread_fence(std::memory_order_acquire); - - auto myDequeueCount = this->dequeueOptimisticCount.fetch_add( - desiredCount, std::memory_order_relaxed); - - tail = this->tailIndex.load(std::memory_order_acquire); - auto actualCount = - static_cast<size_t>(tail - (myDequeueCount - overcommit)); - if (details::circular_less_than<size_t>(0, actualCount)) { - actualCount = desiredCount < actualCount ? desiredCount : actualCount; - if (actualCount < desiredCount) { - this->dequeueOvercommit.fetch_add(desiredCount - actualCount, - std::memory_order_release); - } - - // Get the first index. Note that since there's guaranteed to be at - // least actualCount elements, this will never exceed tail. - auto firstIndex = - this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); - - // Iterate the blocks and dequeue - auto index = firstIndex; - BlockIndexHeader* localBlockIndex; - auto indexIndex = - get_block_index_index_for_index(index, localBlockIndex); - do { - auto blockStartIndex = index; - index_t endIndex = - (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - endIndex = - details::circular_less_than<index_t>( - firstIndex + static_cast<index_t>(actualCount), endIndex) - ? firstIndex + static_cast<index_t>(actualCount) - : endIndex; - - auto entry = localBlockIndex->index[indexIndex]; - auto block = entry->value.load(std::memory_order_relaxed); - if (MOODYCAMEL_NOEXCEPT_ASSIGN( - T, - T&&, - details::deref_noexcept(itemFirst) = - std::move((*(*block)[index])))) { - while (index != endIndex) { - auto& el = *((*block)[index]); - *itemFirst++ = std::move(el); - el.~T(); - ++index; - } - } - else { - MOODYCAMEL_TRY - { - while (index != endIndex) { - auto& el = *((*block)[index]); - *itemFirst = std::move(el); - ++itemFirst; - el.~T(); - ++index; - } - } - MOODYCAMEL_CATCH(...) - { - do { - entry = localBlockIndex->index[indexIndex]; - block = entry->value.load(std::memory_order_relaxed); - while (index != endIndex) { - (*block)[index++]->~T(); - } - - if (block->ConcurrentQueue::Block:: - template set_many_empty<implicit_context>( - blockStartIndex, - static_cast<size_t>(endIndex - - blockStartIndex))) { -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - debug::DebugLock lock(mutex); -#endif - entry->value.store(nullptr, - std::memory_order_relaxed); - this->parent->add_block_to_free_list(block); - } - indexIndex = (indexIndex + 1) & - (localBlockIndex->capacity - 1); - - blockStartIndex = index; - endIndex = - (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + - static_cast<index_t>(BLOCK_SIZE); - endIndex = details::circular_less_than<index_t>( - firstIndex + - static_cast<index_t>(actualCount), - endIndex) - ? firstIndex + - static_cast<index_t>(actualCount) - : endIndex; - } while (index != firstIndex + actualCount); - - MOODYCAMEL_RETHROW; - } - } - if (block->ConcurrentQueue::Block::template set_many_empty< - implicit_context>( - blockStartIndex, - static_cast<size_t>(endIndex - blockStartIndex))) { - { -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - debug::DebugLock lock(mutex); -#endif - // Note that the set_many_empty above did a release, - // meaning that anybody who acquires the block we're about - // to free can use it safely since our writes (and reads!) - // will have happened-before then. - entry->value.store(nullptr, std::memory_order_relaxed); - } - this->parent->add_block_to_free_list( - block); // releases the above store - } - indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); - } while (index != firstIndex + actualCount); - - return actualCount; - } - else { - this->dequeueOvercommit.fetch_add(desiredCount, - std::memory_order_release); - } - } - - return 0; - } - - private: - // The block size must be > 1, so any number with the low bit set is an invalid - // block base index - static const index_t INVALID_BLOCK_BASE = 1; - - struct BlockIndexEntry { - std::atomic<index_t> key; - std::atomic<Block*> value; - }; - - struct BlockIndexHeader { - size_t capacity; - std::atomic<size_t> tail; - BlockIndexEntry* entries; - BlockIndexEntry** index; - BlockIndexHeader* prev; - }; - - template <AllocationMode allocMode> - inline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, - index_t blockStartIndex) - { - auto localBlockIndex = blockIndex.load( - std::memory_order_relaxed); // We're the only writer thread, relaxed is OK - if (localBlockIndex == nullptr) { - return false; // this can happen if new_block_index failed in the - // constructor - } - size_t newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & - (localBlockIndex->capacity - 1); - idxEntry = localBlockIndex->index[newTail]; - if (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE || - idxEntry->value.load(std::memory_order_relaxed) == nullptr) { - - idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); - localBlockIndex->tail.store(newTail, std::memory_order_release); - return true; - } - - // No room in the old block index, try to allocate another one! - MOODYCAMEL_CONSTEXPR_IF(allocMode == CannotAlloc) { return false; } - else if (!new_block_index()) { return false; } - localBlockIndex = blockIndex.load(std::memory_order_relaxed); - newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & - (localBlockIndex->capacity - 1); - idxEntry = localBlockIndex->index[newTail]; - assert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE); - idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); - localBlockIndex->tail.store(newTail, std::memory_order_release); - return true; - } - - inline void rewind_block_index_tail() - { - auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); - localBlockIndex->tail.store( - (localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & - (localBlockIndex->capacity - 1), - std::memory_order_relaxed); - } - - inline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const - { - BlockIndexHeader* localBlockIndex; - auto idx = get_block_index_index_for_index(index, localBlockIndex); - return localBlockIndex->index[idx]; - } - - inline size_t - get_block_index_index_for_index(index_t index, - BlockIndexHeader*& localBlockIndex) const - { -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - debug::DebugLock lock(mutex); -#endif - index &= ~static_cast<index_t>(BLOCK_SIZE - 1); - localBlockIndex = blockIndex.load(std::memory_order_acquire); - auto tail = localBlockIndex->tail.load(std::memory_order_acquire); - auto tailBase = - localBlockIndex->index[tail]->key.load(std::memory_order_relaxed); - assert(tailBase != INVALID_BLOCK_BASE); - // Note: Must use division instead of shift because the index may wrap around, - // causing a negative offset, whose negativity we want to preserve - auto offset = static_cast<size_t>( - static_cast<typename std::make_signed<index_t>::type>(index - tailBase) / - BLOCK_SIZE); - size_t idx = (tail + offset) & (localBlockIndex->capacity - 1); - assert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == - index && - localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != - nullptr); - return idx; - } - - bool new_block_index() - { - auto prev = blockIndex.load(std::memory_order_relaxed); - size_t prevCapacity = prev == nullptr ? 0 : prev->capacity; - auto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity; - auto raw = static_cast<char*>((Traits::malloc)( - sizeof(BlockIndexHeader) + std::alignment_of<BlockIndexEntry>::value - 1 + - sizeof(BlockIndexEntry) * entryCount + - std::alignment_of<BlockIndexEntry*>::value - 1 + - sizeof(BlockIndexEntry*) * nextBlockIndexCapacity)); - if (raw == nullptr) { - return false; - } - - auto header = new (raw) BlockIndexHeader; - auto entries = reinterpret_cast<BlockIndexEntry*>( - details::align_for<BlockIndexEntry>(raw + sizeof(BlockIndexHeader))); - auto index = - reinterpret_cast<BlockIndexEntry**>(details::align_for<BlockIndexEntry*>( - reinterpret_cast<char*>(entries) + - sizeof(BlockIndexEntry) * entryCount)); - if (prev != nullptr) { - auto prevTail = prev->tail.load(std::memory_order_relaxed); - auto prevPos = prevTail; - size_t i = 0; - do { - prevPos = (prevPos + 1) & (prev->capacity - 1); - index[i++] = prev->index[prevPos]; - } while (prevPos != prevTail); - assert(i == prevCapacity); - } - for (size_t i = 0; i != entryCount; ++i) { - new (entries + i) BlockIndexEntry; - entries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed); - index[prevCapacity + i] = entries + i; - } - header->prev = prev; - header->entries = entries; - header->index = index; - header->capacity = nextBlockIndexCapacity; - header->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), - std::memory_order_relaxed); - - blockIndex.store(header, std::memory_order_release); - - nextBlockIndexCapacity <<= 1; - - return true; - } - - private: - size_t nextBlockIndexCapacity; - std::atomic<BlockIndexHeader*> blockIndex; - -#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED - public: - details::ThreadExitListener threadExitListener; - - private: -#endif - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - public: - ImplicitProducer* nextImplicitProducer; - - private: -#endif - -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX - mutable debug::DebugMutex mutex; -#endif -#ifdef MCDBGQ_TRACKMEM - friend struct MemStats; -#endif - }; - - - ////////////////////////////////// - // Block pool manipulation - ////////////////////////////////// - - void populate_initial_block_list(size_t blockCount) - { - initialBlockPoolSize = blockCount; - if (initialBlockPoolSize == 0) { - initialBlockPool = nullptr; - return; - } - - initialBlockPool = create_array<Block>(blockCount); - if (initialBlockPool == nullptr) { - initialBlockPoolSize = 0; - } - for (size_t i = 0; i < initialBlockPoolSize; ++i) { - initialBlockPool[i].dynamicallyAllocated = false; - } - } - - inline Block* try_get_block_from_initial_pool() - { - if (initialBlockPoolIndex.load(std::memory_order_relaxed) >= - initialBlockPoolSize) { - return nullptr; - } - - auto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed); - - return index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr; - } - - inline void add_block_to_free_list(Block* block) - { -#ifdef MCDBGQ_TRACKMEM - block->owner = nullptr; -#endif - freeList.add(block); - } - - inline void add_blocks_to_free_list(Block* block) - { - while (block != nullptr) { - auto next = block->next; - add_block_to_free_list(block); - block = next; - } - } - - inline Block* try_get_block_from_free_list() { return freeList.try_get(); } - - // Gets a free block from one of the memory pools, or allocates a new one (if - // applicable) - template <AllocationMode canAlloc> - Block* requisition_block() - { - auto block = try_get_block_from_initial_pool(); - if (block != nullptr) { - return block; - } - - block = try_get_block_from_free_list(); - if (block != nullptr) { - return block; - } - - MOODYCAMEL_CONSTEXPR_IF(canAlloc == CanAlloc) { return create<Block>(); } - else { return nullptr; } - } - - -#ifdef MCDBGQ_TRACKMEM -public: - struct MemStats { - size_t allocatedBlocks; - size_t usedBlocks; - size_t freeBlocks; - size_t ownedBlocksExplicit; - size_t ownedBlocksImplicit; - size_t implicitProducers; - size_t explicitProducers; - size_t elementsEnqueued; - size_t blockClassBytes; - size_t queueClassBytes; - size_t implicitBlockIndexBytes; - size_t explicitBlockIndexBytes; - - friend class ConcurrentQueue; - - private: - static MemStats getFor(ConcurrentQueue* q) - { - MemStats stats = { 0 }; - - stats.elementsEnqueued = q->size_approx(); - - auto block = q->freeList.head_unsafe(); - while (block != nullptr) { - ++stats.allocatedBlocks; - ++stats.freeBlocks; - block = block->freeListNext.load(std::memory_order_relaxed); - } - - for (auto ptr = q->producerListTail.load(std::memory_order_acquire); - ptr != nullptr; - ptr = ptr->next_prod()) { - bool implicit = dynamic_cast<ImplicitProducer*>(ptr) != nullptr; - stats.implicitProducers += implicit ? 1 : 0; - stats.explicitProducers += implicit ? 0 : 1; - - if (implicit) { - auto prod = static_cast<ImplicitProducer*>(ptr); - stats.queueClassBytes += sizeof(ImplicitProducer); - auto head = prod->headIndex.load(std::memory_order_relaxed); - auto tail = prod->tailIndex.load(std::memory_order_relaxed); - auto hash = prod->blockIndex.load(std::memory_order_relaxed); - if (hash != nullptr) { - for (size_t i = 0; i != hash->capacity; ++i) { - if (hash->index[i]->key.load(std::memory_order_relaxed) != - ImplicitProducer::INVALID_BLOCK_BASE && - hash->index[i]->value.load(std::memory_order_relaxed) != - nullptr) { - ++stats.allocatedBlocks; - ++stats.ownedBlocksImplicit; - } - } - stats.implicitBlockIndexBytes += - hash->capacity * - sizeof(typename ImplicitProducer::BlockIndexEntry); - for (; hash != nullptr; hash = hash->prev) { - stats.implicitBlockIndexBytes += - sizeof(typename ImplicitProducer::BlockIndexHeader) + - hash->capacity * - sizeof(typename ImplicitProducer::BlockIndexEntry*); - } - } - for (; details::circular_less_than<index_t>(head, tail); - head += BLOCK_SIZE) { - // auto block = prod->get_block_index_entry_for_index(head); - ++stats.usedBlocks; - } - } - else { - auto prod = static_cast<ExplicitProducer*>(ptr); - stats.queueClassBytes += sizeof(ExplicitProducer); - auto tailBlock = prod->tailBlock; - bool wasNonEmpty = false; - if (tailBlock != nullptr) { - auto block = tailBlock; - do { - ++stats.allocatedBlocks; - if (!block->ConcurrentQueue::Block::template is_empty< - explicit_context>() || - wasNonEmpty) { - ++stats.usedBlocks; - wasNonEmpty = wasNonEmpty || block != tailBlock; - } - ++stats.ownedBlocksExplicit; - block = block->next; - } while (block != tailBlock); - } - auto index = prod->blockIndex.load(std::memory_order_relaxed); - while (index != nullptr) { - stats.explicitBlockIndexBytes += - sizeof(typename ExplicitProducer::BlockIndexHeader) + - index->size * - sizeof(typename ExplicitProducer::BlockIndexEntry); - index = static_cast<typename ExplicitProducer::BlockIndexHeader*>( - index->prev); - } - } - } - - auto freeOnInitialPool = - q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= - q->initialBlockPoolSize - ? 0 - : q->initialBlockPoolSize - - q->initialBlockPoolIndex.load(std::memory_order_relaxed); - stats.allocatedBlocks += freeOnInitialPool; - stats.freeBlocks += freeOnInitialPool; - - stats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks; - stats.queueClassBytes += sizeof(ConcurrentQueue); - - return stats; - } - }; - - // For debugging only. Not thread-safe. - MemStats getMemStats() { return MemStats::getFor(this); } - -private: - friend struct MemStats; -#endif - - - ////////////////////////////////// - // Producer list manipulation - ////////////////////////////////// - - ProducerBase* recycle_or_create_producer(bool isExplicit) - { - bool recycled; - return recycle_or_create_producer(isExplicit, recycled); - } - - ProducerBase* recycle_or_create_producer(bool isExplicit, bool& recycled) - { -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH - debug::DebugLock lock(implicitProdMutex); -#endif - // Try to re-use one first - for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; - ptr = ptr->next_prod()) { - if (ptr->inactive.load(std::memory_order_relaxed) && - ptr->isExplicit == isExplicit) { - bool expected = true; - if (ptr->inactive.compare_exchange_strong(expected, - /* desired */ false, - std::memory_order_acquire, - std::memory_order_relaxed)) { - // We caught one! It's been marked as activated, the caller can have - // it - recycled = true; - return ptr; - } - } - } - - recycled = false; - return add_producer( - isExplicit ? static_cast<ProducerBase*>(create<ExplicitProducer>(this)) - : create<ImplicitProducer>(this)); - } - - ProducerBase* add_producer(ProducerBase* producer) - { - // Handle failed memory allocation - if (producer == nullptr) { - return nullptr; - } - - producerCount.fetch_add(1, std::memory_order_relaxed); - - // Add it to the lock-free list - auto prevTail = producerListTail.load(std::memory_order_relaxed); - do { - producer->next = prevTail; - } while (!producerListTail.compare_exchange_weak( - prevTail, producer, std::memory_order_release, std::memory_order_relaxed)); - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - if (producer->isExplicit) { - auto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed); - do { - static_cast<ExplicitProducer*>(producer)->nextExplicitProducer = - prevTailExplicit; - } while (!explicitProducers.compare_exchange_weak( - prevTailExplicit, - static_cast<ExplicitProducer*>(producer), - std::memory_order_release, - std::memory_order_relaxed)); - } - else { - auto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed); - do { - static_cast<ImplicitProducer*>(producer)->nextImplicitProducer = - prevTailImplicit; - } while (!implicitProducers.compare_exchange_weak( - prevTailImplicit, - static_cast<ImplicitProducer*>(producer), - std::memory_order_release, - std::memory_order_relaxed)); - } -#endif - - return producer; - } - - void reown_producers() - { - // After another instance is moved-into/swapped-with this one, all the - // producers we stole still think their parents are the other queue. - // So fix them up! - for (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; - ptr = ptr->next_prod()) { - ptr->parent = this; - } - } - - - ////////////////////////////////// - // Implicit producer hash - ////////////////////////////////// - - struct ImplicitProducerKVP { - std::atomic<details::thread_id_t> key; - ImplicitProducer* value; // No need for atomicity since it's only read by the - // thread that sets it in the first place - - ImplicitProducerKVP() : value(nullptr) {} - - ImplicitProducerKVP(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT - { - key.store(other.key.load(std::memory_order_relaxed), - std::memory_order_relaxed); - value = other.value; - } - - inline ImplicitProducerKVP& - operator=(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT - { - swap(other); - return *this; - } - - inline void swap(ImplicitProducerKVP& other) MOODYCAMEL_NOEXCEPT - { - if (this != &other) { - details::swap_relaxed(key, other.key); - std::swap(value, other.value); - } - } - }; - - template <typename XT, typename XTraits> - friend void moodycamel::swap( - typename ConcurrentQueue<XT, XTraits>::ImplicitProducerKVP&, - typename ConcurrentQueue<XT, XTraits>::ImplicitProducerKVP&) MOODYCAMEL_NOEXCEPT; - - struct ImplicitProducerHash { - size_t capacity; - ImplicitProducerKVP* entries; - ImplicitProducerHash* prev; - }; - - inline void populate_initial_implicit_producer_hash() - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { return; } - else - { - implicitProducerHashCount.store(0, std::memory_order_relaxed); - auto hash = &initialImplicitProducerHash; - hash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; - hash->entries = &initialImplicitProducerHashEntries[0]; - for (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) { - initialImplicitProducerHashEntries[i].key.store( - details::invalid_thread_id, std::memory_order_relaxed); - } - hash->prev = nullptr; - implicitProducerHash.store(hash, std::memory_order_relaxed); - } - } - - void swap_implicit_producer_hashes(ConcurrentQueue& other) - { - MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { return; } - else - { - // Swap (assumes our implicit producer hash is initialized) - initialImplicitProducerHashEntries.swap( - other.initialImplicitProducerHashEntries); - initialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0]; - other.initialImplicitProducerHash.entries = - &other.initialImplicitProducerHashEntries[0]; - - details::swap_relaxed(implicitProducerHashCount, - other.implicitProducerHashCount); - - details::swap_relaxed(implicitProducerHash, other.implicitProducerHash); - if (implicitProducerHash.load(std::memory_order_relaxed) == - &other.initialImplicitProducerHash) { - implicitProducerHash.store(&initialImplicitProducerHash, - std::memory_order_relaxed); - } - else { - ImplicitProducerHash* hash; - for (hash = implicitProducerHash.load(std::memory_order_relaxed); - hash->prev != &other.initialImplicitProducerHash; - hash = hash->prev) { - continue; - } - hash->prev = &initialImplicitProducerHash; - } - if (other.implicitProducerHash.load(std::memory_order_relaxed) == - &initialImplicitProducerHash) { - other.implicitProducerHash.store(&other.initialImplicitProducerHash, - std::memory_order_relaxed); - } - else { - ImplicitProducerHash* hash; - for (hash = other.implicitProducerHash.load(std::memory_order_relaxed); - hash->prev != &initialImplicitProducerHash; - hash = hash->prev) { - continue; - } - hash->prev = &other.initialImplicitProducerHash; - } - } - } - - // Only fails (returns nullptr) if memory allocation fails - ImplicitProducer* get_or_add_implicit_producer() - { - // Note that since the data is essentially thread-local (key is thread ID), - // there's a reduced need for fences (memory ordering is already consistent - // for any individual thread), except for the current table itself. - - // Start by looking for the thread ID in the current and all previous hash tables. - // If it's not found, it must not be in there yet, since this same thread would - // have added it previously to one of the tables that we traversed. - - // Code and algorithm adapted from - // http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table - -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH - debug::DebugLock lock(implicitProdMutex); -#endif - - auto id = details::thread_id(); - auto hashedId = details::hash_thread_id(id); - - auto mainHash = implicitProducerHash.load(std::memory_order_acquire); - assert(mainHash != - nullptr); // silence clang-tidy and MSVC warnings (hash cannot be null) - for (auto hash = mainHash; hash != nullptr; hash = hash->prev) { - // Look for the id in this hash - auto index = hashedId; - while (true) { // Not an infinite loop because at least one slot is free in - // the hash table - index &= hash->capacity - 1; - - auto probedKey = hash->entries[index].key.load(std::memory_order_relaxed); - if (probedKey == id) { - // Found it! If we had to search several hashes deep, though, we - // should lazily add it to the current main hash table to avoid the - // extended search next time. Note there's guaranteed to be room in - // the current hash table since every subsequent table implicitly - // reserves space for all previous tables (there's only one - // implicitProducerHashCount). - auto value = hash->entries[index].value; - if (hash != mainHash) { - index = hashedId; - while (true) { - index &= mainHash->capacity - 1; - probedKey = mainHash->entries[index].key.load( - std::memory_order_relaxed); - auto empty = details::invalid_thread_id; -#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED - auto reusable = details::invalid_thread_id2; - if ((probedKey == empty && - mainHash->entries[index].key.compare_exchange_strong( - empty, - id, - std::memory_order_relaxed, - std::memory_order_relaxed)) || - (probedKey == reusable && - mainHash->entries[index].key.compare_exchange_strong( - reusable, - id, - std::memory_order_acquire, - std::memory_order_acquire))) { -#else - if ((probedKey == empty && - mainHash->entries[index].key.compare_exchange_strong( - empty, - id, - std::memory_order_relaxed, - std::memory_order_relaxed))) { -#endif - mainHash->entries[index].value = value; - break; - } - ++index; - } - } - - return value; - } - if (probedKey == details::invalid_thread_id) { - break; // Not in this hash table - } - ++index; - } - } - - // Insert! - auto newCount = - 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed); - while (true) { - // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) - if (newCount >= (mainHash->capacity >> 1) && - !implicitProducerHashResizeInProgress.test_and_set( - std::memory_order_acquire)) { - // We've acquired the resize lock, try to allocate a bigger hash table. - // Note the acquire fence synchronizes with the release fence at the end - // of this block, and hence when we reload implicitProducerHash it must be - // the most recent version (it only gets changed within this locked - // block). - mainHash = implicitProducerHash.load(std::memory_order_acquire); - if (newCount >= (mainHash->capacity >> 1)) { - auto newCapacity = mainHash->capacity << 1; - while (newCount >= (newCapacity >> 1)) { - newCapacity <<= 1; - } - auto raw = static_cast<char*>( - (Traits::malloc)(sizeof(ImplicitProducerHash) + - std::alignment_of<ImplicitProducerKVP>::value - - 1 + sizeof(ImplicitProducerKVP) * newCapacity)); - if (raw == nullptr) { - // Allocation failed - implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); - implicitProducerHashResizeInProgress.clear( - std::memory_order_relaxed); - return nullptr; - } - - auto newHash = new (raw) ImplicitProducerHash; - newHash->capacity = static_cast<size_t>(newCapacity); - newHash->entries = reinterpret_cast<ImplicitProducerKVP*>( - details::align_for<ImplicitProducerKVP>( - raw + sizeof(ImplicitProducerHash))); - for (size_t i = 0; i != newCapacity; ++i) { - new (newHash->entries + i) ImplicitProducerKVP; - newHash->entries[i].key.store(details::invalid_thread_id, - std::memory_order_relaxed); - } - newHash->prev = mainHash; - implicitProducerHash.store(newHash, std::memory_order_release); - implicitProducerHashResizeInProgress.clear(std::memory_order_release); - mainHash = newHash; - } - else { - implicitProducerHashResizeInProgress.clear(std::memory_order_release); - } - } - - // If it's < three-quarters full, add to the old one anyway so that we don't - // have to wait for the next table to finish being allocated by another thread - // (and if we just finished allocating above, the condition will always be - // true) - if (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) { - bool recycled; - auto producer = static_cast<ImplicitProducer*>( - recycle_or_create_producer(false, recycled)); - if (producer == nullptr) { - implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); - return nullptr; - } - if (recycled) { - implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); - } - -#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED - producer->threadExitListener.callback = - &ConcurrentQueue::implicit_producer_thread_exited_callback; - producer->threadExitListener.userData = producer; - details::ThreadExitNotifier::subscribe(&producer->threadExitListener); -#endif - - auto index = hashedId; - while (true) { - index &= mainHash->capacity - 1; - auto probedKey = - mainHash->entries[index].key.load(std::memory_order_relaxed); - - auto empty = details::invalid_thread_id; -#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED - auto reusable = details::invalid_thread_id2; - if ((probedKey == empty && - mainHash->entries[index].key.compare_exchange_strong( - empty, - id, - std::memory_order_relaxed, - std::memory_order_relaxed)) || - (probedKey == reusable && - mainHash->entries[index].key.compare_exchange_strong( - reusable, - id, - std::memory_order_acquire, - std::memory_order_acquire))) { -#else - if ((probedKey == empty && - mainHash->entries[index].key.compare_exchange_strong( - empty, - id, - std::memory_order_relaxed, - std::memory_order_relaxed))) { -#endif - mainHash->entries[index].value = producer; - break; - } - ++index; - } - return producer; - } - - // Hmm, the old hash is quite full and somebody else is busy allocating a new - // one. We need to wait for the allocating thread to finish (if it succeeds, - // we add, if not, we try to allocate ourselves). - mainHash = implicitProducerHash.load(std::memory_order_acquire); - } - } // namespace moodycamel - -#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED - void implicit_producer_thread_exited(ImplicitProducer* producer) - { - // Remove from thread exit listeners - details::ThreadExitNotifier::unsubscribe(&producer->threadExitListener); - - // Remove from hash -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH - debug::DebugLock lock(implicitProdMutex); -#endif - auto hash = implicitProducerHash.load(std::memory_order_acquire); - assert(hash != nullptr); // The thread exit listener is only registered if we were - // added to a hash in the first place - auto id = details::thread_id(); - auto hashedId = details::hash_thread_id(id); - details::thread_id_t probedKey; - - // We need to traverse all the hashes just in case other threads aren't on the - // current one yet and are trying to add an entry thinking there's a free slot - // (because they reused a producer) - for (; hash != nullptr; hash = hash->prev) { - auto index = hashedId; - do { - index &= hash->capacity - 1; - probedKey = hash->entries[index].key.load(std::memory_order_relaxed); - if (probedKey == id) { - hash->entries[index].key.store(details::invalid_thread_id2, - std::memory_order_release); - break; - } - ++index; - } while (probedKey != - details::invalid_thread_id); // Can happen if the hash has changed - // but we weren't put back in it yet, or - // if we weren't added to this hash in - // the first place - } - - // Mark the queue as being recyclable - producer->inactive.store(true, std::memory_order_release); - } - - static void implicit_producer_thread_exited_callback(void* userData) - { - auto producer = static_cast<ImplicitProducer*>(userData); - auto queue = producer->parent; - queue->implicit_producer_thread_exited(producer); - } -#endif - - ////////////////////////////////// - // Utility functions - ////////////////////////////////// - - template <typename TAlign> - static inline void* aligned_malloc(size_t size) - { - MOODYCAMEL_CONSTEXPR_IF(std::alignment_of<TAlign>::value <= - std::alignment_of<details::max_align_t>::value) - return (Traits::malloc)(size); - else - { - size_t alignment = std::alignment_of<TAlign>::value; - void* raw = (Traits::malloc)(size + alignment - 1 + sizeof(void*)); - if (!raw) - return nullptr; - char* ptr = - details::align_for<TAlign>(reinterpret_cast<char*>(raw) + sizeof(void*)); - *(reinterpret_cast<void**>(ptr) - 1) = raw; - return ptr; - } - } - - template <typename TAlign> - static inline void aligned_free(void* ptr) - { - MOODYCAMEL_CONSTEXPR_IF(std::alignment_of<TAlign>::value <= - std::alignment_of<details::max_align_t>::value) - return (Traits::free)(ptr); - else(Traits::free)(ptr ? *(reinterpret_cast<void**>(ptr) - 1) : nullptr); - } - - template <typename U> - static inline U* create_array(size_t count) - { - assert(count > 0); - U* p = static_cast<U*>(aligned_malloc<U>(sizeof(U) * count)); - if (p == nullptr) - return nullptr; - - for (size_t i = 0; i != count; ++i) - new (p + i) U(); - return p; - } - - template <typename U> - static inline void destroy_array(U* p, size_t count) - { - if (p != nullptr) { - assert(count > 0); - for (size_t i = count; i != 0;) - (p + --i)->~U(); - } - aligned_free<U>(p); - } - - template <typename U> - static inline U* create() - { - void* p = aligned_malloc<U>(sizeof(U)); - return p != nullptr ? new (p) U : nullptr; - } - - template <typename U, typename A1> - static inline U* create(A1&& a1) - { - void* p = aligned_malloc<U>(sizeof(U)); - return p != nullptr ? new (p) U(std::forward<A1>(a1)) : nullptr; - } - - template <typename U> - static inline void destroy(U* p) - { - if (p != nullptr) - p->~U(); - aligned_free<U>(p); - } - -private: - std::atomic<ProducerBase*> producerListTail; - std::atomic<std::uint32_t> producerCount; - - std::atomic<size_t> initialBlockPoolIndex; - Block* initialBlockPool; - size_t initialBlockPoolSize; - -#ifndef MCDBGQ_USEDEBUGFREELIST - FreeList<Block> freeList; -#else - debug::DebugFreeList<Block> freeList; -#endif - - std::atomic<ImplicitProducerHash*> implicitProducerHash; - std::atomic<size_t> implicitProducerHashCount; // Number of slots logically used - ImplicitProducerHash initialImplicitProducerHash; - std::array<ImplicitProducerKVP, INITIAL_IMPLICIT_PRODUCER_HASH_SIZE> - initialImplicitProducerHashEntries; - std::atomic_flag implicitProducerHashResizeInProgress; - - std::atomic<std::uint32_t> nextExplicitConsumerId; - std::atomic<std::uint32_t> globalExplicitConsumerOffset; - -#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH - debug::DebugMutex implicitProdMutex; -#endif - -#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG - std::atomic<ExplicitProducer*> explicitProducers; - std::atomic<ImplicitProducer*> implicitProducers; -#endif -}; - - -template <typename T, typename Traits> -ProducerToken::ProducerToken(ConcurrentQueue<T, Traits>& queue) - : producer(queue.recycle_or_create_producer(true)) -{ - if (producer != nullptr) { - producer->token = this; - } -} - -template <typename T, typename Traits> -ProducerToken::ProducerToken(BlockingConcurrentQueue<T, Traits>& queue) - : producer(reinterpret_cast<ConcurrentQueue<T, Traits>*>(&queue) - ->recycle_or_create_producer(true)) -{ - if (producer != nullptr) { - producer->token = this; - } -} - -template <typename T, typename Traits> -ConsumerToken::ConsumerToken(ConcurrentQueue<T, Traits>& queue) - : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) -{ - initialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release); - lastKnownGlobalOffset = static_cast<std::uint32_t>(-1); -} - -template <typename T, typename Traits> -ConsumerToken::ConsumerToken(BlockingConcurrentQueue<T, Traits>& queue) - : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) -{ - initialOffset = reinterpret_cast<ConcurrentQueue<T, Traits>*>(&queue) - ->nextExplicitConsumerId.fetch_add(1, std::memory_order_release); - lastKnownGlobalOffset = static_cast<std::uint32_t>(-1); -} - -template <typename T, typename Traits> -inline void swap(ConcurrentQueue<T, Traits>& a, - ConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT -{ - a.swap(b); -} - -inline void swap(ProducerToken& a, ProducerToken& b) MOODYCAMEL_NOEXCEPT { a.swap(b); } - -inline void swap(ConsumerToken& a, ConsumerToken& b) MOODYCAMEL_NOEXCEPT { a.swap(b); } - -template <typename T, typename Traits> -inline void -swap(typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& a, - typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT -{ - a.swap(b); -} - -} // namespace moodycamel - -#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) -#pragma warning(pop) -#endif - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif diff --git a/gr/include/moodycamel/lightweightsemaphore.h b/gr/include/moodycamel/lightweightsemaphore.h deleted file mode 100644 index 72658b026..000000000 --- a/gr/include/moodycamel/lightweightsemaphore.h +++ /dev/null @@ -1,415 +0,0 @@ -// Provides an efficient implementation of a semaphore (LightweightSemaphore). -// This is an extension of Jeff Preshing's sempahore implementation (licensed -// under the terms of its separate zlib license) that has been adapted and -// extended by Cameron Desrochers. - -#pragma once - -#include <type_traits> // For std::make_signed<T> -#include <atomic> -#include <cstddef> // For std::size_t - -#if defined(_WIN32) -// Avoid including windows.h in a header; we only need a handful of -// items, so we'll redeclare them here (this is relatively safe since -// the API generally has to remain stable between Windows versions). -// I know this is an ugly hack but it still beats polluting the global -// namespace with thousands of generic names or adding a .cpp for nothing. -extern "C" { -struct _SECURITY_ATTRIBUTES; -__declspec(dllimport) void* __stdcall CreateSemaphoreW( - _SECURITY_ATTRIBUTES* lpSemaphoreAttributes, - long lInitialCount, - long lMaximumCount, - const wchar_t* lpName); -__declspec(dllimport) int __stdcall CloseHandle(void* hObject); -__declspec(dllimport) unsigned long __stdcall WaitForSingleObject( - void* hHandle, unsigned long dwMilliseconds); -__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, - long lReleaseCount, - long* lpPreviousCount); -} -#elif defined(__MACH__) -#include <mach/mach.h> -#elif defined(__unix__) -#include <semaphore.h> -#endif - -namespace moodycamel { -namespace details { - -// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's -// portable + lightweight semaphore implementations, originally from -// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h -// LICENSE: -// Copyright (c) 2015 Jeff Preshing -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgement in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. -#if defined(_WIN32) -class Semaphore -{ -private: - void* m_hSema; - - Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; - Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; - -public: - Semaphore(int initialCount = 0) - { - assert(initialCount >= 0); - const long maxLong = 0x7fffffff; - m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr); - assert(m_hSema); - } - - ~Semaphore() { CloseHandle(m_hSema); } - - bool wait() - { - const unsigned long infinite = 0xffffffff; - return WaitForSingleObject(m_hSema, infinite) == 0; - } - - bool try_wait() { return WaitForSingleObject(m_hSema, 0) == 0; } - - bool timed_wait(std::uint64_t usecs) - { - return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0; - } - - void signal(int count = 1) - { - while (!ReleaseSemaphore(m_hSema, count, nullptr)) - ; - } -}; -#elif defined(__MACH__) -//--------------------------------------------------------- -// Semaphore (Apple iOS and OSX) -// Can't use POSIX semaphores due to -// http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html -//--------------------------------------------------------- -class Semaphore -{ -private: - semaphore_t m_sema; - - Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; - Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; - -public: - Semaphore(int initialCount = 0) - { - assert(initialCount >= 0); - kern_return_t rc = - semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount); - assert(rc == KERN_SUCCESS); - (void)rc; - } - - ~Semaphore() { semaphore_destroy(mach_task_self(), m_sema); } - - bool wait() { return semaphore_wait(m_sema) == KERN_SUCCESS; } - - bool try_wait() { return timed_wait(0); } - - bool timed_wait(std::uint64_t timeout_usecs) - { - mach_timespec_t ts; - ts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000); - ts.tv_nsec = static_cast<int>((timeout_usecs % 1000000) * 1000); - - // added in OSX 10.10: - // https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html - kern_return_t rc = semaphore_timedwait(m_sema, ts); - return rc == KERN_SUCCESS; - } - - void signal() - { - while (semaphore_signal(m_sema) != KERN_SUCCESS) - ; - } - - void signal(int count) - { - while (count-- > 0) { - while (semaphore_signal(m_sema) != KERN_SUCCESS) - ; - } - } -}; -#elif defined(__unix__) -//--------------------------------------------------------- -// Semaphore (POSIX, Linux) -//--------------------------------------------------------- -class Semaphore -{ -private: - sem_t m_sema; - - Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; - Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; - -public: - Semaphore(int initialCount = 0) - { - assert(initialCount >= 0); - int rc = sem_init(&m_sema, 0, static_cast<unsigned int>(initialCount)); - assert(rc == 0); - (void)rc; - } - - ~Semaphore() { sem_destroy(&m_sema); } - - bool wait() - { - // http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error - int rc; - do { - rc = sem_wait(&m_sema); - } while (rc == -1 && errno == EINTR); - return rc == 0; - } - - bool try_wait() - { - int rc; - do { - rc = sem_trywait(&m_sema); - } while (rc == -1 && errno == EINTR); - return rc == 0; - } - - bool timed_wait(std::uint64_t usecs) - { - struct timespec ts; - const int usecs_in_1_sec = 1000000; - const int nsecs_in_1_sec = 1000000000; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += (time_t)(usecs / usecs_in_1_sec); - ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000; - // sem_timedwait bombs if you have more than 1e9 in tv_nsec - // so we have to clean things up before passing it in - if (ts.tv_nsec >= nsecs_in_1_sec) { - ts.tv_nsec -= nsecs_in_1_sec; - ++ts.tv_sec; - } - - int rc; - do { - rc = sem_timedwait(&m_sema, &ts); - } while (rc == -1 && errno == EINTR); - return rc == 0; - } - - void signal() - { - while (sem_post(&m_sema) == -1) - ; - } - - void signal(int count) - { - while (count-- > 0) { - while (sem_post(&m_sema) == -1) - ; - } - } -}; -#else -#error Unsupported platform! (No semaphore wrapper available) -#endif - -} // end namespace details - - -//--------------------------------------------------------- -// LightweightSemaphore -//--------------------------------------------------------- -class LightweightSemaphore -{ -public: - typedef std::make_signed<std::size_t>::type ssize_t; - -private: - std::atomic<ssize_t> m_count; - details::Semaphore m_sema; - int m_maxSpins; - - bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) - { - ssize_t oldCount; - int spin = m_maxSpins; - while (--spin >= 0) { - oldCount = m_count.load(std::memory_order_relaxed); - if ((oldCount > 0) && - m_count.compare_exchange_strong(oldCount, - oldCount - 1, - std::memory_order_acquire, - std::memory_order_relaxed)) - return true; - std::atomic_signal_fence( - std::memory_order_acquire); // Prevent the compiler from collapsing the - // loop. - } - oldCount = m_count.fetch_sub(1, std::memory_order_acquire); - if (oldCount > 0) - return true; - if (timeout_usecs < 0) { - if (m_sema.wait()) - return true; - } - if (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs)) - return true; - // At this point, we've timed out waiting for the semaphore, but the - // count is still decremented indicating we may still be waiting on - // it. So we have to re-adjust the count, but only if the semaphore - // wasn't signaled enough times for us too since then. If it was, we - // need to release the semaphore too. - while (true) { - oldCount = m_count.load(std::memory_order_acquire); - if (oldCount >= 0 && m_sema.try_wait()) - return true; - if (oldCount < 0 && - m_count.compare_exchange_strong(oldCount, - oldCount + 1, - std::memory_order_relaxed, - std::memory_order_relaxed)) - return false; - } - } - - ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1) - { - assert(max > 0); - ssize_t oldCount; - int spin = m_maxSpins; - while (--spin >= 0) { - oldCount = m_count.load(std::memory_order_relaxed); - if (oldCount > 0) { - ssize_t newCount = oldCount > max ? oldCount - max : 0; - if (m_count.compare_exchange_strong(oldCount, - newCount, - std::memory_order_acquire, - std::memory_order_relaxed)) - return oldCount - newCount; - } - std::atomic_signal_fence(std::memory_order_acquire); - } - oldCount = m_count.fetch_sub(1, std::memory_order_acquire); - if (oldCount <= 0) { - if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || - (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs))) { - while (true) { - oldCount = m_count.load(std::memory_order_acquire); - if (oldCount >= 0 && m_sema.try_wait()) - break; - if (oldCount < 0 && - m_count.compare_exchange_strong(oldCount, - oldCount + 1, - std::memory_order_relaxed, - std::memory_order_relaxed)) - return 0; - } - } - } - if (max > 1) - return 1 + tryWaitMany(max - 1); - return 1; - } - -public: - LightweightSemaphore(ssize_t initialCount = 0, int maxSpins = 10000) - : m_count(initialCount), m_maxSpins(maxSpins) - { - assert(initialCount >= 0); - assert(maxSpins >= 0); - } - - bool tryWait() - { - ssize_t oldCount = m_count.load(std::memory_order_relaxed); - while (oldCount > 0) { - if (m_count.compare_exchange_weak(oldCount, - oldCount - 1, - std::memory_order_acquire, - std::memory_order_relaxed)) - return true; - } - return false; - } - - bool wait() { return tryWait() || waitWithPartialSpinning(); } - - bool wait(std::int64_t timeout_usecs) - { - return tryWait() || waitWithPartialSpinning(timeout_usecs); - } - - // Acquires between 0 and (greedily) max, inclusive - ssize_t tryWaitMany(ssize_t max) - { - assert(max >= 0); - ssize_t oldCount = m_count.load(std::memory_order_relaxed); - while (oldCount > 0) { - ssize_t newCount = oldCount > max ? oldCount - max : 0; - if (m_count.compare_exchange_weak(oldCount, - newCount, - std::memory_order_acquire, - std::memory_order_relaxed)) - return oldCount - newCount; - } - return 0; - } - - // Acquires at least one, and (greedily) at most max - ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs) - { - assert(max >= 0); - ssize_t result = tryWaitMany(max); - if (result == 0 && max > 0) - result = waitManyWithPartialSpinning(max, timeout_usecs); - return result; - } - - ssize_t waitMany(ssize_t max) - { - ssize_t result = waitMany(max, -1); - assert(result > 0); - return result; - } - - void signal(ssize_t count = 1) - { - assert(count >= 0); - ssize_t oldCount = m_count.fetch_add(count, std::memory_order_release); - ssize_t toRelease = -oldCount < count ? -oldCount : count; - if (toRelease > 0) { - m_sema.signal((int)toRelease); - } - } - - std::size_t availableApprox() const - { - ssize_t count = m_count.load(std::memory_order_relaxed); - return count > 0 ? static_cast<std::size_t>(count) : 0; - } -}; - -} // end namespace moodycamel diff --git a/gr/include/moodycamel/meson.build b/gr/include/moodycamel/meson.build deleted file mode 100644 index 12a34e6ad..000000000 --- a/gr/include/moodycamel/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -install_headers([ - 'blockingconcurrentqueue.h', - 'concurrentqueue.h', - 'lightweightsemaphore.h' -], subdir : 'moodycamel') diff --git a/gr/lib/buffer_cpu_host.cc b/gr/lib/buffer_cpu_host.cc deleted file mode 100644 index 0623d166f..000000000 --- a/gr/lib/buffer_cpu_host.cc +++ /dev/null @@ -1,96 +0,0 @@ -#include <string.h> -#include <algorithm> -#include <cstdint> -#include <memory> -#include <mutex> -#include <vector> - -#include <gnuradio/buffer_cpu_host.h> - -namespace gr { -buffer_cpu_host::buffer_cpu_host(size_t num_items, - size_t item_size, - buffer_cpu_host_type type, - std::shared_ptr<buffer_properties> buf_properties) - : gr::buffer_sm(num_items, item_size, buf_properties), _transfer_type(type) -{ - _host_buffer.resize(_buf_size); - _device_buffer.resize(_buf_size); - - set_type("buffer_cpu_host_" + std::to_string((int)_transfer_type)); -} - -buffer_uptr buffer_cpu_host::make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties) -{ - auto cbp = std::static_pointer_cast<buffer_cpu_host_properties>(buffer_properties); - if (cbp != nullptr) { - return buffer_uptr(new buffer_cpu_host( - num_items, item_size, cbp->buffer_type(), buffer_properties)); - } - else { - throw std::runtime_error( - "Failed to cast buffer properties to buffer_cpu_host_properties"); - } -} - -void* buffer_cpu_host::read_ptr(size_t index) -{ - if (_transfer_type == buffer_cpu_host_type::D2H || - _transfer_type == buffer_cpu_host_type::H2H) { - return (void*)&_host_buffer[index]; - } - else { - return (void*)&_device_buffer[index]; - } -} -void* buffer_cpu_host::write_ptr() -{ - if (_transfer_type == buffer_cpu_host_type::H2D || - _transfer_type == buffer_cpu_host_type::H2H) { - return (void*)&_host_buffer[_write_index]; - } - else { - return (void*)&_device_buffer[_write_index]; - } -} - -void buffer_cpu_host::post_write(int num_items) -{ - std::lock_guard<std::mutex> guard(_buf_mutex); - - size_t bytes_written = num_items * _item_size; - size_t wi1 = _write_index; - - // num_items were written to the buffer - - if (_transfer_type == buffer_cpu_host_type::H2D) { - memcpy(&_device_buffer[wi1], &_host_buffer[wi1], bytes_written); - } - else if (_transfer_type == buffer_cpu_host_type::D2H) { - memcpy(&_host_buffer[wi1], &_device_buffer[wi1], bytes_written); - } - - // advance the write pointer - _write_index += bytes_written; - if (_write_index == _buf_size) { - _write_index = 0; - } - if (_write_index > _buf_size) { - throw std::runtime_error("buffer_sm: Wrote too far into buffer"); - } - _total_written += num_items; -} - -buffer_reader_uptr -buffer_cpu_host::add_reader(std::shared_ptr<buffer_properties> buf_props, size_t itemsize) -{ - auto r = - std::make_unique<buffer_cpu_host_reader>(this, buf_props, itemsize, _write_index); - _readers.push_back(r.get()); - return r; -} - - -} // namespace gr diff --git a/gr/lib/buffer_cuda.cc b/gr/lib/buffer_cuda.cc deleted file mode 100644 index 73a1e61f4..000000000 --- a/gr/lib/buffer_cuda.cc +++ /dev/null @@ -1,162 +0,0 @@ -#include <cuda.h> -#include <cuda_runtime.h> -#include <string.h> -#include <algorithm> -#include <cstdint> -#include <memory> -#include <mutex> -#include <vector> - -#include <gnuradio/buffer_cuda.h> - - -namespace gr { -buffer_cuda::buffer_cuda(size_t num_items, - size_t item_size, - buffer_cuda_type type, - std::shared_ptr<buffer_properties> buf_properties) - : gr::buffer(num_items, item_size, buf_properties), _type(type) -{ - // _host_buffer.resize(_buf_size * 2); // double circular buffer - cudaMallocHost( - &_host_buffer, - _buf_size * - 2); // double circular buffer - should do something more intelligent here - cudaMalloc( - &_device_buffer, - _buf_size * - 2); // double circular buffer - should do something more intelligent here - set_type("buffer_cuda_" + std::to_string((int)_type)); - - cudaStreamCreate(&stream); -} -buffer_cuda::~buffer_cuda() -{ - cudaFree(_device_buffer); - cudaFree(_host_buffer); -} - -buffer_uptr buffer_cuda::make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties) -{ - auto cbp = std::static_pointer_cast<buffer_cuda_properties>(buffer_properties); - if (cbp != nullptr) { - return buffer_uptr( - new buffer_cuda(num_items, item_size, cbp->buffer_type(), buffer_properties)); - } - else { - throw std::runtime_error( - "Failed to cast buffer properties to buffer_cuda_properties"); - } -} - -void* buffer_cuda::read_ptr(size_t index) -{ - if (_type == buffer_cuda_type::D2H) { - return (void*)&_host_buffer[index]; - } - else { - return (void*)&_device_buffer[index]; - } -} -void* buffer_cuda::write_ptr() -{ - if (_type == buffer_cuda_type::H2D) { - return (void*)&_host_buffer[_write_index]; - } - else { - return (void*)&_device_buffer[_write_index]; - } -} - -void buffer_cuda_reader::post_read(int num_items) -{ - std::lock_guard<std::mutex> guard(_rdr_mutex); - // advance the read pointer - _read_index += num_items * _itemsize; - if (_read_index >= _buffer->buf_size()) { - _read_index -= _buffer->buf_size(); - } - _total_read += num_items; -} -void buffer_cuda::post_write(int num_items) -{ - std::lock_guard<std::mutex> guard(_buf_mutex); - - size_t bytes_written = num_items * _item_size; - size_t wi1 = _write_index; - size_t wi2 = _write_index + _buf_size; - // num_items were written to the buffer - // copy the data to the second half of the buffer - - size_t num_bytes_1 = std::min(_buf_size - wi1, bytes_written); - size_t num_bytes_2 = bytes_written - num_bytes_1; - - if (_type == buffer_cuda_type::H2D) { - cudaMemcpyAsync(&_device_buffer[wi1], - &_host_buffer[wi1], - bytes_written, - cudaMemcpyHostToDevice, - stream); - - // memcpy(&_host_buffer[wi2], &_host_buffer[wi1], num_bytes_1); - cudaMemcpyAsync(&_device_buffer[wi2], - &_device_buffer[wi1], - num_bytes_1, - cudaMemcpyDeviceToDevice, - stream); - if (num_bytes_2) { - // memcpy(&_host_buffer[0], &_host_buffer[_buf_size], num_bytes_2); - cudaMemcpyAsync(&_device_buffer[0], - &_device_buffer[_buf_size], - num_bytes_2, - cudaMemcpyDeviceToDevice, - stream); - } - } - else if (_type == buffer_cuda_type::D2H) { - cudaMemcpyAsync(&_host_buffer[wi1], - &_device_buffer[wi1], - bytes_written, - cudaMemcpyDeviceToHost, - stream); - - memcpy(&_host_buffer[wi2], &_host_buffer[wi1], num_bytes_1); - - if (num_bytes_2) { - memcpy(&_host_buffer[0], &_host_buffer[_buf_size], num_bytes_2); - } - } - else // D2D - { - cudaMemcpyAsync(&_device_buffer[wi2], - &_device_buffer[wi1], - num_bytes_1, - cudaMemcpyDeviceToDevice); - if (num_bytes_2) - cudaMemcpyAsync(&_device_buffer[0], - &_device_buffer[_buf_size], - num_bytes_2, - cudaMemcpyDeviceToDevice, - stream); - } - // advance the write pointer - _write_index += bytes_written; - if (_write_index >= _buf_size) { - _write_index -= _buf_size; - } - _total_written += num_items; - cudaStreamSynchronize(stream); -} - -buffer_reader_uptr buffer_cuda::add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize) -{ - auto r = - std::make_unique<buffer_cuda_reader>(this, buf_props, itemsize, _write_index); - _readers.push_back(r.get()); - return r; -} - -} // namespace gr diff --git a/gr/lib/buffer_cuda_pinned.cc b/gr/lib/buffer_cuda_pinned.cc deleted file mode 100644 index 3a1de05de..000000000 --- a/gr/lib/buffer_cuda_pinned.cc +++ /dev/null @@ -1,80 +0,0 @@ -#include <string.h> -#include <algorithm> -#include <cstdint> -#include <memory> -#include <mutex> -#include <vector> - -#include <cuda.h> -#include <cuda_runtime.h> - -#include <gnuradio/buffer_cuda_pinned.h> - -namespace gr { -buffer_cuda_pinned::buffer_cuda_pinned(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buf_properties) - : buffer(num_items, item_size, buf_properties) -{ - if (!cudaHostAlloc((void**)&_pinned_buffer, _buf_size * 2, 0) == cudaSuccess) { - throw std::runtime_error("Failed to allocate CUDA pinned memory"); - } -} -buffer_cuda_pinned::~buffer_cuda_pinned() { cudaFree(_pinned_buffer); } - -buffer_uptr buffer_cuda_pinned::make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties) -{ - return buffer_uptr(new buffer_cuda_pinned(num_items, item_size, buffer_properties)); -} - -void* buffer_cuda_pinned::read_ptr(size_t index) { return (void*)&_pinned_buffer[index]; } -void* buffer_cuda_pinned::write_ptr() { return (void*)&_pinned_buffer[_write_index]; } - -void buffer_cuda_pinned_reader::post_read(int num_items) -{ - std::lock_guard<std::mutex> guard(_rdr_mutex); - // advance the read pointer - _read_index += num_items * _itemsize; - if (_read_index >= _buffer->buf_size()) { - _read_index -= _buffer->buf_size(); - } - _total_read += num_items; -} - -void buffer_cuda_pinned::post_write(int num_items) -{ - std::lock_guard<std::mutex> guard(_buf_mutex); - - size_t bytes_written = num_items * _item_size; - size_t wi1 = _write_index; - size_t wi2 = _write_index + _buf_size; - // num_items were written to the buffer - // copy the data to the second half of the buffer - - size_t num_bytes_1 = std::min(_buf_size - wi1, bytes_written); - size_t num_bytes_2 = bytes_written - num_bytes_1; - - memcpy(&_pinned_buffer[wi2], &_pinned_buffer[wi1], num_bytes_1); - if (num_bytes_2) - memcpy(&_pinned_buffer[0], &_pinned_buffer[_buf_size], num_bytes_2); - - // advance the write pointer - _write_index += bytes_written; - if (_write_index >= _buf_size) { - _write_index -= _buf_size; - } -} - -buffer_reader_uptr -buffer_cuda_pinned::add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize) -{ - auto r = std::make_unique<buffer_cuda_pinned_reader>( - this, buf_props, itemsize, _write_index); - _readers.push_back(r.get()); - return r; -} - -} // namespace gr diff --git a/gr/lib/buffer_cuda_sm.cc b/gr/lib/buffer_cuda_sm.cc deleted file mode 100644 index 7e8bc88d9..000000000 --- a/gr/lib/buffer_cuda_sm.cc +++ /dev/null @@ -1,164 +0,0 @@ -#include <cuda.h> -#include <cuda_runtime.h> -#include <string.h> -#include <algorithm> -#include <cstdint> -#include <memory> -#include <mutex> -#include <vector> - -#include <gnuradio/buffer_cuda_sm.h> - -namespace gr { -buffer_cuda_sm::buffer_cuda_sm(size_t num_items, - size_t item_size, - buffer_cuda_sm_type type, - std::shared_ptr<buffer_properties> buf_properties) - : gr::buffer_sm(num_items, item_size, buf_properties), _type(type) -{ - // _host_buffer.resize(_buf_size * 2); // double circular buffer - cudaMallocHost(&_host_buffer, _buf_size); - cudaMalloc(&_device_buffer, _buf_size); - set_type("buffer_cuda_sm_" + std::to_string((int)_type)); - - cudaStreamCreate(&stream); -} -buffer_cuda_sm::~buffer_cuda_sm() -{ - cudaFree(_device_buffer); - cudaFree(_host_buffer); -} - -buffer_uptr buffer_cuda_sm::make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties) -{ - auto cbp = std::static_pointer_cast<buffer_cuda_sm_properties>(buffer_properties); - if (cbp != nullptr) { - return buffer_uptr(new buffer_cuda_sm( - num_items, item_size, cbp->buffer_type(), buffer_properties)); - } - else { - throw std::runtime_error( - "Failed to cast buffer properties to buffer_cuda_sm_properties"); - } -} - -void* buffer_cuda_sm::read_ptr(size_t index) -{ - if (_type == buffer_cuda_sm_type::D2H) { - return (void*)&_host_buffer[index]; - } - else { - return (void*)&_device_buffer[index]; - } -} -void* buffer_cuda_sm::write_ptr() -{ - if (_type == buffer_cuda_sm_type::H2D) { - return (void*)&_host_buffer[_write_index]; - } - else { - return (void*)&_device_buffer[_write_index]; - } -} - -void buffer_cuda_sm::post_write(int num_items) -{ - std::lock_guard<std::mutex> guard(_buf_mutex); - - size_t bytes_written = num_items * _item_size; - size_t wi1 = _write_index; - - // num_items were written to the buffer - - if (_type == buffer_cuda_sm_type::H2D) { - cudaMemcpyAsync(&_device_buffer[wi1], - &_host_buffer[wi1], - bytes_written, - cudaMemcpyHostToDevice, - stream); - } - else if (_type == buffer_cuda_sm_type::D2H) { - cudaMemcpyAsync(&_host_buffer[wi1], - &_device_buffer[wi1], - bytes_written, - cudaMemcpyDeviceToHost, - stream); - } - - // advance the write pointer - _write_index += bytes_written; - if (_write_index == _buf_size) { - _write_index = 0; - } - if (_write_index > _buf_size) { - throw std::runtime_error("buffer_sm: Wrote too far into buffer"); - } - _total_written += num_items; - cudaStreamSynchronize(stream); -} - -buffer_reader_uptr -buffer_cuda_sm::add_reader(std::shared_ptr<buffer_properties> buf_props, size_t itemsize) -{ - auto r = - std::make_unique<buffer_cuda_sm_reader>(this, buf_props, itemsize, _write_index); - _readers.push_back(r.get()); - return r; -} - -void* buffer_cuda_sm::cuda_memcpy(void* dest, const void* src, std::size_t count) -{ - cudaError_t rc = cudaSuccess; - rc = cudaMemcpy(dest, src, count, cudaMemcpyDeviceToDevice); - if (rc) { - std::ostringstream msg; - msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " - << cudaGetErrorString(rc); - throw std::runtime_error(msg.str()); - } - - return dest; -} - -void* buffer_cuda_sm::cuda_memmove(void* dest, const void* src, std::size_t count) -{ - // Would a kernel that checks for overlap and then copies front-to-back or - // back-to-front be faster than using cudaMemcpy with a temp buffer? - - // Allocate temp buffer - void* tempBuffer = nullptr; - cudaError_t rc = cudaSuccess; - rc = cudaMalloc((void**)&tempBuffer, count); - if (rc) { - std::ostringstream msg; - msg << "Error allocating device buffer: " << cudaGetErrorName(rc) << " -- " - << cudaGetErrorString(rc); - throw std::runtime_error(msg.str()); - } - - // First copy data from source to temp buffer - rc = cudaMemcpy(tempBuffer, src, count, cudaMemcpyDeviceToDevice); - if (rc) { - std::ostringstream msg; - msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " - << cudaGetErrorString(rc); - throw std::runtime_error(msg.str()); - } - - // Then copy data from temp buffer to destination to avoid overlap - rc = cudaMemcpy(dest, tempBuffer, count, cudaMemcpyDeviceToDevice); - if (rc) { - std::ostringstream msg; - msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " - << cudaGetErrorString(rc); - throw std::runtime_error(msg.str()); - } - - cudaFree(tempBuffer); - - return dest; -} - -} // namespace gr diff --git a/gr/lib/buffer_net_zmq.cc b/gr/lib/buffer_net_zmq.cc deleted file mode 100644 index 0236e028a..000000000 --- a/gr/lib/buffer_net_zmq.cc +++ /dev/null @@ -1,175 +0,0 @@ -#include <gnuradio/buffer_cpu_vmcirc.h> -#include <gnuradio/buffer_net_zmq.h> -#include <nlohmann/json.hpp> -#include <chrono> -#include <thread> -namespace gr { - - -std::shared_ptr<buffer_properties> -buffer_net_zmq_properties::make_from_params(const std::string& json_str) -{ - auto json_obj = nlohmann::json::parse(json_str); - return make(json_obj["ipaddr"], json_obj["port"]); -} - -buffer_uptr buffer_net_zmq::make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties) -{ - - auto zbp = std::static_pointer_cast<buffer_net_zmq_properties>(buffer_properties); - if (zbp != nullptr) { - return buffer_uptr( - new buffer_net_zmq(num_items, item_size, buffer_properties, zbp->port())); - } - else { - throw std::runtime_error( - "Failed to cast buffer properties to buffer_net_zmq_properties"); - } -} - -buffer_net_zmq::buffer_net_zmq(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buf_properties, - int port) - : buffer(num_items, item_size, buf_properties), - _context(1), - _socket(_context, zmq::socket_type::push) -{ - gr::configure_default_loggers(d_logger, d_debug_logger, "buffer_net_zmq"); - set_type("buffer_net_zmq"); - _buffer.resize(_buf_size); - _socket.set(zmq::sockopt::sndhwm, 1); - _socket.set(zmq::sockopt::rcvhwm, 1); - std::string endpoint = "tcp://*:" + std::to_string(port); - std::cout << "snd_endpoint: " << endpoint << std::endl; - _socket.bind(endpoint); -} - - -/****************************************************************************/ -/* READER METHODS */ -/****************************************************************************/ - - -buffer_reader_uptr -buffer_net_zmq_reader::make(size_t itemsize, std::shared_ptr<buffer_properties> buf_props) -{ - auto zbp = std::static_pointer_cast<buffer_net_zmq_properties>(buf_props); - if (zbp != nullptr) { - return std::make_unique<buffer_net_zmq_reader>( - buf_props, itemsize, zbp->ipaddr(), zbp->port()); - } - else { - throw std::runtime_error( - "Failed to cast buffer properties to buffer_net_zmq_properties"); - } -} - -buffer_net_zmq_reader::buffer_net_zmq_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize, - const std::string& ipaddr, - int port) - : buffer_reader(nullptr, buf_props, itemsize, 0), - _context(1), - _socket(_context, zmq::socket_type::pull) -{ - gr::configure_default_loggers(d_logger, d_debug_logger, "buffer_net_zmq_reader"); - auto bufprops = std::make_shared<buffer_cpu_vmcirc_properties>(); - _circbuf = gr::buffer_cpu_vmcirc::make( - 8192, - itemsize, - bufprops); // FIXME - make nitems a buffer reader factory parameter - _circbuf_rdr = _circbuf->add_reader(bufprops, itemsize); - - // auto b = (float *)_circbuf->write_ptr(); - - // for (int i=0; i<8192; i++) - // { - // b[i] = i; - // } - // _circbuf->post_write(8192); - - // buffer_info_t info; - // _circbuf_rdr->read_info(info); - // auto br = (float *)_circbuf_rdr->read_ptr(); - - - // _circbuf_rdr->post_read(4096); - // br = (float *) _circbuf_rdr->read_ptr(); - - - std::string endpoint = "tcp://" + ipaddr + ":" + std::to_string(port); - d_debug_logger->debug("rcv_endpoint: {}", endpoint); - _socket.set(zmq::sockopt::sndhwm, 1); - _socket.set(zmq::sockopt::rcvhwm, 1); - // _socket.setsockopt(ZMQ_SUBSCRIBE, "", 0); - _socket.connect(endpoint); - d_debug_logger->debug(" ... connected"); - - std::thread t([this]() { - while (!this->_recv_done) { - // zmq::message_t msg{}; - // See how much room we have in the circular buffer - buffer_info_t wi; - _circbuf->write_info(wi); - - auto n_bytes_left_in_msg = _msg.size() - _msg_idx; - auto n_bytes_in_circbuf = wi.n_items * wi.item_size; - auto bytes_to_write = std::min(n_bytes_in_circbuf, n_bytes_left_in_msg); - auto items_to_write = bytes_to_write / wi.item_size; - bytes_to_write = items_to_write * wi.item_size; - - if (n_bytes_in_circbuf <= 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - if (bytes_to_write > 0) { - memcpy(wi.ptr, (uint8_t*)_msg.data() + _msg_idx, bytes_to_write); - d_debug_logger->debug("copied {} items", bytes_to_write / wi.item_size); - _msg_idx += bytes_to_write; - n_bytes_left_in_msg = _msg.size() - _msg_idx; - _circbuf->post_write(items_to_write); - notify_scheduler(); - } - - if (n_bytes_left_in_msg == 0) { - _msg.rebuild(); - d_debug_logger->debug("going into recv"); - auto r = _socket.recv(_msg, zmq::recv_flags::none); - if (r) { - d_debug_logger->debug("received msg with size {} items", - _msg.size() / wi.item_size); - _msg_idx = 0; - } - } - // GR_LOG_DEBUG(d_debug_logger, "recv: {}", wi.n_items); - // auto ret = this->_socket.recv( - // zmq::mutable_buffer(_circbuf->write_ptr(), wi.n_items * wi.item_size), - // zmq::recv_flags::none); - - // _circbuf->post_write(wi.n_items); - // notify_scheduler(); - // auto recbuf = *ret; - // assert(recbuf.size == wi.n_items * wi.item_size); - - // GR_LOG_DEBUG(d_debug_logger, "nbytesrcv: {}", recbuf.size); - // std::cout << " ---> msg received " << msg.size() << " bytes" << - // std::endl; - } - }); - - t.detach(); -} - -std::string buffer_net_zmq_properties::to_json() -{ - nlohmann::json j = { { "id", "buffer_net_zmq_properties" }, - { "parameters", { { "ipaddr", _ipaddr }, { "port", _port } } } }; - - return j.dump(); -} - -} // namespace gr diff --git a/gr/lib/buffer_sm.cc b/gr/lib/buffer_sm.cc deleted file mode 100644 index 6766b1062..000000000 --- a/gr/lib/buffer_sm.cc +++ /dev/null @@ -1,374 +0,0 @@ -#include <gnuradio/buffer_sm.h> - -#include <gnuradio/logger.h> - -namespace gr { - -buffer_reader_uptr buffer_sm::add_reader(std::shared_ptr<buffer_properties> buf_props, - size_t itemsize) -{ - auto r = std::make_unique<buffer_sm_reader>(this, itemsize, buf_props, _write_index); - _readers.push_back(r.get()); - return r; -} - -buffer_sm::buffer_sm(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buf_properties) - : buffer(num_items, item_size, buf_properties) -{ - _buffer.resize(_buf_size); // singly mapped buffer - _raw_buffer = _buffer.data(); - _write_index = 0; - - set_type("buffer_sm"); - - - gr::configure_default_loggers(d_logger, d_debug_logger, _type); -} - -buffer_uptr buffer_sm::make(size_t num_items, - size_t item_size, - std::shared_ptr<buffer_properties> buffer_properties) -{ - return buffer_uptr(new buffer_sm(num_items, item_size, buffer_properties)); -} - -void* buffer_sm::read_ptr(size_t index) { return (void*)&_raw_buffer[index]; } -void* buffer_sm::write_ptr() { return (void*)&_raw_buffer[_write_index]; } - -void buffer_sm::post_write(int num_items) -{ - std::scoped_lock guard(_buf_mutex); - - size_t bytes_written = num_items * _item_size; - // num_items were written to the buffer - - // advance the write pointer - _write_index += bytes_written; - if (_write_index == _buf_size) { - _write_index = 0; - } - if (_write_index > _buf_size) { - throw std::runtime_error("buffer_sm: Wrote too far into buffer"); - } - _total_written += num_items; -} - -bool buffer_sm::output_blkd_cb_ready(int output_multiple) -{ - uint32_t space_avail = 0; - { - std::unique_lock<std::mutex>(*this->mutex()); - space_avail = space_available(); - } - return ((space_avail > 0) && - ((space_avail / output_multiple) * output_multiple == 0)); -} - -bool buffer_sm::output_blocked_callback_logic(bool force, memmove_func_t memmove_func) -{ - auto space_avail = space_available(); - - // if (((space_avail > 0) && ((space_avail / output_multiple) * output_multiple == - // 0)) || - if ((space_avail > 0) || force) { - // Find reader with the smallest read index - uint32_t min_read_idx = _readers[0]->read_index(); - uint64_t min_read_idx_nitems = _readers[0]->total_read(); - for (size_t idx = 1; idx < _readers.size(); ++idx) { - // Record index of reader with minimum read-index - if (_readers[idx]->read_index() < min_read_idx) { - min_read_idx = _readers[idx]->read_index(); - min_read_idx_nitems = _readers[idx]->total_read(); - } - } - - d_debug_logger->debug("output_blocked_callback, space_avail {}, min_read_idx {}, " - "_write_index {}", - space_avail, - min_read_idx, - _write_index); - - // Make sure we have enough room to start writing back at the beginning - if ((min_read_idx == 0) || (min_read_idx > _write_index) || - (min_read_idx == _write_index && min_read_idx_nitems != total_written())) { - return false; - } - - // Determine how much "to be read" data needs to be moved - auto to_move_bytes = _write_index - min_read_idx; - - if (to_move_bytes > min_read_idx) { - return false; - } - - - d_debug_logger->debug("output_blocked_callback, moving {} bytes", to_move_bytes); - - // Shift "to be read" data back to the beginning of the buffer - std::memmove(_raw_buffer, _raw_buffer + (min_read_idx), to_move_bytes); - - // Adjust write index and each reader index - _write_index -= min_read_idx; - - for (size_t idx = 0; idx < _readers.size(); ++idx) { - d_debug_logger->debug("output_blocked_callback,setting _read_index to {}", - _readers[idx]->read_index() - min_read_idx); - _readers[idx]->set_read_index(_readers[idx]->read_index() - min_read_idx); - } - - return true; - } - - return false; -} - -bool buffer_sm::output_blocked_callback(bool force) -{ - std::scoped_lock guard(_buf_mutex); - - return output_blocked_callback_logic(force, std::memmove); -} - -size_t buffer_sm::space_available() -{ - // Find the max number of items available across readers - - uint64_t min_items_read = std::numeric_limits<uint64_t>::max(); - size_t min_read_idx = 0; - for (size_t idx = 0; idx < _readers.size(); idx++) { - std::scoped_lock lck{ *(_readers[idx]->mutex()) }; - auto total_read = _readers[idx]->total_read(); - if (total_read < min_items_read) { - min_items_read = total_read; - min_read_idx = _readers[idx]->read_index(); - } - } - - size_t space = (_buf_size - _write_index) / _item_size; - - if (min_read_idx == _write_index) { - // If the (min) read index and write index are equal then the buffer - // is either completely empty or completely full depending on if - // the number of items read matches the number written - if (min_items_read != total_written()) { - space = 0; - } - } - else if (min_read_idx > _write_index) { - space = (min_read_idx - _write_index) / _item_size; - } - - if (space == 0) - return space; - // Only half fill the buffer - // Leave extra space in case the reader gets stuck and needs realignment - - space = std::min(space, _num_items); - - return space; -} - -bool buffer_sm::write_info(buffer_info_t& info) -{ - std::scoped_lock guard(_buf_mutex); - - info.ptr = write_ptr(); - info.n_items = space_available(); - if (info.n_items < 0) - info.n_items = 0; - info.item_size = _item_size; - info.total_items = _total_written; - - return true; -} - -bool buffer_sm::adjust_buffer_data(memcpy_func_t memcpy_func, memmove_func_t memmove_func) -{ - - // Find reader with the smallest read index that is greater than the - // write index - // auto min_reader_index = std::numeric_limits<size_t>::max(); - auto min_read_idx = std::numeric_limits<size_t>::max(); - for (size_t idx = 0; idx < _readers.size(); ++idx) { - if (_readers[idx]->read_index() > write_index()) { - // Record index of reader with minimum read-index - // FIXME: What if one of the readers has wrapped back around? - // -- in that case this should use items_available() callback - if (_readers[idx]->read_index() < min_read_idx) { - min_read_idx = _readers[idx]->read_index(); - // min_reader_index = idx; - } - } - } - - // Note items_avail might be zero, that's okay. - auto max_bytes_avail = _buf_size - min_read_idx; - auto max_items_avail = max_bytes_avail / _item_size; - auto gap = min_read_idx - _write_index; - if (_write_index > min_read_idx || max_bytes_avail > gap) { - return false; - } - - // GR_LOG_DEBUG(d_debug_logger, - // "adust_buffer_data: max_bytes_avail {}, gap {}", - // max_bytes_avail, - // gap); - - - // Shift existing data down to make room for blocked data at end of buffer - auto move_data_size = _write_index; - auto dest = _raw_buffer + max_bytes_avail; - memmove_func(dest, _raw_buffer, move_data_size); - - // Next copy the data from the end of the buffer back to the beginning - auto avail_data_size = max_bytes_avail; - auto src = _raw_buffer + min_read_idx; - memcpy_func(_raw_buffer, src, avail_data_size); - - // Finally adjust all reader pointers - for (size_t idx = 0; idx < _readers.size(); ++idx) { - // GR_LOG_DEBUG(d_debug_logger, - // "adjust_buffer_data,setting _read_index to {}", - // _readers[idx]->read_index() - min_read_idx); - _readers[idx]->set_read_index(max_items_avail - _readers[idx]->items_available()); - } - - // Now adjust write pointer - _write_index += max_items_avail; - - return true; -} - - -buffer_sm_reader::buffer_sm_reader(buffer_sm* bufp, - size_t itemsize, - std::shared_ptr<buffer_properties> buf_props, - size_t read_index) - : buffer_reader(bufp, buf_props, itemsize, read_index), _buffer_sm(bufp) -{ - gr::configure_default_loggers(d_logger, d_debug_logger, "buffer_sm_reader"); -} - -void buffer_sm_reader::post_read(int num_items) -{ - std::scoped_lock guard(_rdr_mutex); - - // GR_LOG_DEBUG( - // d_debug_logger, "post_read: _read_index {}, num_items {}", _read_index, num_items); - - // advance the read pointer - _read_index += num_items * _itemsize; //_buffer->item_size(); - _total_read += num_items; - if (_read_index == _buffer->buf_size()) { - _read_index = 0; - } - if (_read_index > _buffer->buf_size()) { - // GR_LOG_INFO(d_logger, - // "too far: num_items {}, prev_index {}, post_index {}", - // num_items, - // _read_index - num_items * _buffer->item_size(), - // _read_index); - - // // throw std::runtime_error("buffer_sm_reader: Wrote too far into buffer"); - } - - // GR_LOG_DEBUG(d_debug_logger, "post_read: _read_index {}", _read_index); -} - -bool buffer_sm_reader::input_blocked_callback(size_t items_required) -{ - // Only singly mapped buffers need to do anything with this callback - std::scoped_lock guard(*(_buffer->mutex())); - - auto items_avail = items_available(); - - // GR_LOG_DEBUG(d_debug_logger, - // "input_blocked_callback: items_avail {}, _read_index {}, " - // "_write_index {}, items_required {}", - // items_avail, - // _read_index, - // _buffer->write_index(), - // items_required); - - // GR_LOG_DEBUG(d_debug_logger, - // "input_blocked_callback: total_written {}, total_read {}", - // _buffer->total_written(), - // total_read()); - - - // Maybe adjust read pointers from min read index? - // This would mean that *all* readers must be > (passed) the write index - if (items_avail < items_required && _buffer->write_index() < read_index()) { - // GR_LOG_DEBUG(d_debug_logger, "Calling adjust_buffer_data "); - return _buffer_sm->adjust_buffer_data(std::memcpy, std::memmove); - } - - return false; -} - -size_t buffer_sm_reader::bytes_available() -{ - // Can only read up to to the write_index, or the end of the buffer - // there is no wraparound - - size_t ret = 0; - - size_t w = _buffer->write_index(); - size_t r = _read_index; - - if (w < r) { - ret = (_buffer->buf_size() - r); - } - else if (w == r && total_read() < _buffer->total_written()) { - ret = (_buffer->buf_size() - r); - } - else { - ret = (w - r); - } - - // return ret; - - // GR_LOG_DEBUG(d_debug_logger, - // "items_available: write_index {}, read_index {}, ret {}, total_read " - // "{}, total_written {}", - // w, - // r, - // ret, - // total_read(), - // _buffer->total_written()); - - // if (_itemsize*(_buffer->total_written() - total_read()) < ret) { - // d_debug_logger->debug( - // "check_math {} {} {} {}", - // _buffer->total_written() - total_read(), - // ret, - // total_read(), - // _buffer->total_written()); - // } - - return ret; // in bytes -} - -bool buffer_sm_reader::input_blkd_cb_ready(int items_required) -{ - std::unique_lock<std::mutex>(*_buffer->mutex()); - - return ( - ((_buffer->buf_size() * _itemsize - _read_index) < (uint32_t)items_required) && - (_buffer->write_index() < _read_index)); -} - -buffer_sm_properties::buffer_sm_properties() : buffer_properties() -{ - _bff = buffer_sm::make; -} - -std::shared_ptr<buffer_properties> buffer_sm_properties::make() -{ - return std::static_pointer_cast<buffer_properties>( - std::make_shared<buffer_sm_properties>()); -} - -} // namespace gr diff --git a/gr/lib/meson.build b/gr/lib/meson.build index a809cea2e..dbee9c491 100644 --- a/gr/lib/meson.build +++ b/gr/lib/meson.build @@ -32,7 +32,6 @@ runtime_sources = [ 'block.cc', 'port.cc', 'buffer.cc', - 'buffer_sm.cc', 'buffer_management.cc', 'buffer_cpu_simple.cc', 'realtime.cc', @@ -56,13 +55,11 @@ runtime_sources = [ 'buffer_cpu_vmcirc_sysv_shm.cc', # mmap requires librt - FIXME - handle this a conditional dependency 'buffer_cpu_vmcirc_mmap_shm_open.cc', - 'buffer_net_zmq.cc', 'sptr_magic.cc', 'hier_block.cc', 'prefs.cc', 'tag.cc', 'registry.cc', - 'buffer_cpu_host.cc' ] if IMPLEMENT_CUDA diff --git a/gr/meson.build b/gr/meson.build index 2627dfa6b..62ed6711a 100644 --- a/gr/meson.build +++ b/gr/meson.build @@ -1,5 +1,4 @@ subdir('include/gnuradio') -subdir('include/moodycamel') subdir('lib') if (get_option('enable_python')) diff --git a/gr/python/gnuradio/gr/bindings/buffer_net_zmq_pybind.cc b/gr/python/gnuradio/gr/bindings/buffer_net_zmq_pybind.cc deleted file mode 100644 index 3effa205c..000000000 --- a/gr/python/gnuradio/gr/bindings/buffer_net_zmq_pybind.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2020 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include <pybind11/complex.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -namespace py = pybind11; - -#include <gnuradio/buffer_net_zmq.h> -// pydoc.h is automatically generated in the build directory -// #include <edge_pydoc.h> - -void bind_buffer_net_zmq(py::module& m) -{ - using buffer_net_zmq_properties = ::gr::buffer_net_zmq_properties; - - py::class_<buffer_net_zmq_properties, - gr::buffer_properties, - std::shared_ptr<buffer_net_zmq_properties>>(m, "buffer_net_zmq_properties") - // .def(py::init( - // [](const std::string& ipaddr, int port) { - // return ::gr::buffer_net_zmq_properties::make(ipaddr, port); - // }), py::arg("ipaddr"), py::arg("port")) - .def_static( - "make", &buffer_net_zmq_properties::make, py::arg("ipaddr"), py::arg("port")) - .def_static("make_from_params", - &buffer_net_zmq_properties::make_from_params, - py::arg("json_str")) - .def("to_json", &buffer_net_zmq_properties::to_json); -} diff --git a/gr/python/gnuradio/gr/bindings/gr_pybind.cc b/gr/python/gnuradio/gr/bindings/gr_pybind.cc index 1ec5bc33d..8a43a6c1d 100644 --- a/gr/python/gnuradio/gr/bindings/gr_pybind.cc +++ b/gr/python/gnuradio/gr/bindings/gr_pybind.cc @@ -35,7 +35,6 @@ void bind_buffer(py::module&); void bind_vmcircbuf(py::module&); void bind_constants(py::module&); void bind_python_block(py::module&); -void bind_buffer_net_zmq(py::module& m); void bind_runtime(py::module&); void bind_runtime_proxy(py::module&); void bind_graph_utils(py::module&); @@ -77,7 +76,6 @@ PYBIND11_MODULE(gr_python, m) bind_flowgraph(m); bind_scheduler(m); bind_buffer(m); - bind_buffer_net_zmq(m); bind_vmcircbuf(m); bind_constants(m); bind_python_block(m); diff --git a/gr/python/gnuradio/gr/bindings/meson.build b/gr/python/gnuradio/gr/bindings/meson.build index 23421526b..55ad0ec83 100644 --- a/gr/python/gnuradio/gr/bindings/meson.build +++ b/gr/python/gnuradio/gr/bindings/meson.build @@ -13,7 +13,6 @@ runtime_pybind_sources = files([ 'scheduler_pybind.cc', 'buffer_pybind.cc', 'buffer_cpu_vmcirc_pybind.cc', - 'buffer_net_zmq_pybind.cc', 'constants_pybind.cc', 'python_block_pybind.cc', 'runtime_pybind.cc', diff --git a/gr/test/meson.build b/gr/test/meson.build index 86be691d4..9c3f5fa78 100644 --- a/gr/test/meson.build +++ b/gr/test/meson.build @@ -5,12 +5,12 @@ qa_srcs = ['qa_host_buffer', deps = [gnuradio_gr_dep, gtest_dep,] -foreach qa : qa_srcs - e = executable(qa, - qa + '.cc', - include_directories : incdir, - link_language : 'cpp', - dependencies: deps, - install : false) - test(qa, e, env: TEST_ENV) -endforeach
\ No newline at end of file +# foreach qa : qa_srcs +# e = executable(qa, +# qa + '.cc', +# include_directories : incdir, +# link_language : 'cpp', +# dependencies: deps, +# install : false) +# test(qa, e, env: TEST_ENV) +# endforeach
\ No newline at end of file diff --git a/gr/test/qa_host_buffer.cc b/gr/test/qa_host_buffer.cc deleted file mode 100644 index 326611f29..000000000 --- a/gr/test/qa_host_buffer.cc +++ /dev/null @@ -1,281 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2021 BlackLynx Inc. - * Copyright 2022 Josh Morman - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include <gtest/gtest.h> - -#include <gnuradio/block.h> -#include <gnuradio/buffer_cpu_host.h> - -#include <cstdlib> -#include <iostream> - - -using namespace gr; - -// ---------------------------------------------------------------------------- -// Basic checks for buffer_single_mapped using the buffer_cpu_host implementation -// of the interface for testing. -// ---------------------------------------------------------------------------- -TEST(HostBuffer, t0) -{ - size_t nitems = 65536 / sizeof(int); - - auto buf_props = BUFFER_CPU_HOST_ARGS_H2D; - auto buf = buf_props->factory()(nitems, 1, buf_props); - auto rdr1 = buf->add_reader(buf_props, 1); - - EXPECT_TRUE(buf->space_available() == nitems); - EXPECT_TRUE(rdr1->items_available() == 0); - - for (size_t idx = 1; idx <= 16; ++idx) { - buf->post_write(1000); - EXPECT_TRUE(buf->space_available() == (nitems - (idx * 1000))); - - EXPECT_TRUE(rdr1->items_available() == (idx * 1000)); - } - - EXPECT_TRUE(buf->space_available() == 384); - - buf->post_write(buf->space_available()); - EXPECT_TRUE(buf->space_available() == 0); - EXPECT_TRUE(rdr1->items_available() == nitems); - EXPECT_TRUE(buf->space_available() == 0); -} - -// ---------------------------------------------------------------------------- -// Basic checks for buffer_single_mapped using the buffer_cpu_host implementation -// of the interface for testing. -// ---------------------------------------------------------------------------- -TEST(HostBuffer, t1) -{ - size_t nitems = 65536 / sizeof(int); - - auto buf_props = BUFFER_CPU_HOST_ARGS_H2D; - auto buf = buf_props->factory()(nitems, 1, buf_props); - auto rdr1 = buf->add_reader(buf_props, 1); - - size_t space = buf->space_available(); - EXPECT_TRUE(nitems == space); - - EXPECT_TRUE(rdr1->items_available() == 0); - - buf->post_write(nitems); - EXPECT_TRUE(buf->space_available() == 0); - EXPECT_TRUE(rdr1->items_available() == nitems); - - for (size_t idx = 1; idx <= 16; ++idx) { - rdr1->post_read(1000); - EXPECT_TRUE(rdr1->items_available() == (nitems - (idx * 1000))); - - space = buf->space_available(); - EXPECT_TRUE(space == (idx * 1000)); - } - - EXPECT_TRUE(rdr1->items_available() == 384); - rdr1->post_read(384); - EXPECT_TRUE(rdr1->items_available() == 0); -} - -// ---------------------------------------------------------------------------- -// Basic check reader/write wrapping of buffer_single_mapped with 1 reader. -// ---------------------------------------------------------------------------- -TEST(HostBuffer, t2) -{ - size_t nitems = 65536 / sizeof(int); - - auto buf_props = BUFFER_CPU_HOST_ARGS_H2D; - auto buf = buf_props->factory()(nitems, 1, buf_props); - auto rdr1 = buf->add_reader(buf_props, 1); - - size_t space = buf->space_available(); - EXPECT_TRUE(nitems == space); - EXPECT_TRUE(rdr1->items_available() == 0); - - buf->post_write(nitems); - EXPECT_TRUE(buf->space_available() == 0); - - for (size_t idx = 1; idx <= 16; ++idx) { - rdr1->post_read(1000); - EXPECT_TRUE(rdr1->items_available() == (nitems - (idx * 1000))); - - space = buf->space_available(); - - if (idx <= 9) - EXPECT_TRUE(space == (idx * 1000)); - else - EXPECT_TRUE(space == ((idx * 1000) - (nitems / 2))); - - if (idx == 9) { - buf->post_write(nitems / 2); - } - } - - // At this point we can only read up until the end of the buffer even though - // additional data is available at the beginning of the buffer - EXPECT_TRUE(rdr1->items_available() == 384); - rdr1->post_read(384); - - // Now the (nitems / 2) at the beginning of the buffer should be available - EXPECT_TRUE(rdr1->items_available() == (nitems / 2)); - - for (size_t idx = 0; idx < 4; ++idx) - rdr1->post_read(1024); - - EXPECT_TRUE(buf->space_available() == (nitems / 2)); - EXPECT_TRUE(rdr1->items_available() == (nitems / 4)); - - for (size_t idx = 0; idx < 4; ++idx) - rdr1->post_read(1000); - - EXPECT_TRUE(buf->space_available() == (nitems / 2)); - EXPECT_TRUE(rdr1->items_available() == 96); - - rdr1->post_read(96); - EXPECT_TRUE(rdr1->items_available() == 0); - - EXPECT_TRUE(buf->space_available() == (nitems / 2)); -} - -// ---------------------------------------------------------------------------- -// Basic check reader/write wrapping of buffer_single_mapped with 2 readers. -// ---------------------------------------------------------------------------- -TEST(HostBuffer, t3) -{ - size_t nitems = 65536 / sizeof(int); - - auto buf_props = BUFFER_CPU_HOST_ARGS_H2D; - auto buf = buf_props->factory()(nitems, 1, buf_props); - auto rdr1 = buf->add_reader(buf_props, 1); - auto rdr2 = buf->add_reader(buf_props, 1); - - size_t space = buf->space_available(); - EXPECT_TRUE(nitems == space); - EXPECT_TRUE(rdr1->items_available() == 0); - EXPECT_TRUE(rdr2->items_available() == 0); - - buf->post_write(nitems); - EXPECT_TRUE(buf->space_available() == 0); - EXPECT_TRUE(rdr1->items_available() == nitems); - EXPECT_TRUE(rdr2->items_available() == nitems); - - for (size_t idx = 1; idx <= 16; ++idx) { - rdr1->post_read(1000); - EXPECT_TRUE(rdr1->items_available() == (nitems - (idx * 1000))); - - // Reader 2 hasn't read anything so space available should remain 0 - EXPECT_TRUE(buf->space_available() == 0); - } - - size_t last_rdr1_available = rdr1->items_available(); - size_t increment = last_rdr1_available / 4; - - for (size_t idx = 1; idx <= 16; ++idx) { - rdr2->post_read(1000); - EXPECT_TRUE(rdr2->items_available() == (nitems - (idx * 1000))); - - EXPECT_TRUE(rdr1->items_available() == last_rdr1_available); - if (idx % 4 == 0) { - rdr1->post_read(increment); - EXPECT_TRUE(rdr1->items_available() == (last_rdr1_available - increment)); - last_rdr1_available = rdr1->items_available(); - } - - EXPECT_TRUE(buf->space_available() == (idx * 1000)); - } -} - -// ---------------------------------------------------------------------------- -// Basic check of output blocked callback -// ---------------------------------------------------------------------------- -TEST(HostBuffer, t4) -{ - size_t nitems = 65536 / sizeof(int); - - auto buf_props = BUFFER_CPU_HOST_ARGS_H2D; - auto buf = buf_props->factory()(nitems, 1, buf_props); - auto rdr1 = buf->add_reader(buf_props, 1); - - EXPECT_TRUE(nitems == buf->space_available()); - EXPECT_TRUE(rdr1->items_available() == 0); - - buf->post_write(nitems / 2); - EXPECT_TRUE(buf->space_available() == (nitems / 2)); - EXPECT_TRUE(rdr1->items_available() == (nitems / 2)); - - rdr1->post_read(nitems / 2); - EXPECT_TRUE(buf->space_available() == (nitems / 2)); - EXPECT_TRUE(rdr1->items_available() == 0); - - buf->post_write(8000); - EXPECT_TRUE(buf->space_available() == 192); - - bool ready = buf->output_blkd_cb_ready(200); - EXPECT_TRUE(ready == true); - - bool success = buf->output_blocked_callback(200); - EXPECT_TRUE(success == true); - EXPECT_TRUE(buf->space_available() == 8384); - EXPECT_TRUE(rdr1->items_available() == 8000); - - rdr1->post_read(4000); - EXPECT_TRUE(buf->space_available() == 8384); - EXPECT_TRUE(rdr1->items_available() == 4000); - - buf->post_write(4000); - EXPECT_TRUE(buf->space_available() == 4384); - EXPECT_TRUE(rdr1->items_available() == 8000); - - rdr1->post_read(8000); - EXPECT_TRUE(buf->space_available() == 4384); - EXPECT_TRUE(rdr1->items_available() == 0); -} - -// ---------------------------------------------------------------------------- -// Basic check of input blocked callback -// ---------------------------------------------------------------------------- -TEST(HostBuffer, t5) -{ - size_t nitems = 65536 / sizeof(int); - - auto buf_props = BUFFER_CPU_HOST_ARGS_H2D; - auto buf = buf_props->factory()(nitems, 1, buf_props); - auto rdr1 = buf->add_reader(buf_props, 1); - - EXPECT_TRUE(nitems == buf->space_available()); - EXPECT_TRUE(rdr1->items_available() == 0); - - buf->post_write(16000); - EXPECT_TRUE(buf->space_available() == 384); - EXPECT_TRUE(rdr1->items_available() == 16000); - - rdr1->post_read(16000); - EXPECT_TRUE(buf->space_available() == 384); - EXPECT_TRUE(rdr1->items_available() == 0); - - buf->post_write(384); - EXPECT_TRUE(buf->space_available() == 16000); - EXPECT_TRUE(rdr1->items_available() == 384); - - buf->post_write(116); - EXPECT_TRUE(buf->space_available() == 15884); - EXPECT_TRUE(rdr1->items_available() == 384); - - bool ready = rdr1->input_blkd_cb_ready(400); - EXPECT_TRUE(ready == true); - - bool success = rdr1->input_blocked_callback(400); - EXPECT_TRUE(success == true); - EXPECT_TRUE(rdr1->items_available() == 500); - - rdr1->post_read(500); - EXPECT_TRUE(buf->space_available() == 15884); - EXPECT_TRUE(rdr1->items_available() == 0); -} diff --git a/meson.build b/meson.build index 01bd5cabc..00f3f9811 100644 --- a/meson.build +++ b/meson.build @@ -96,15 +96,9 @@ if (get_option('enable_testing')) TEST_ENV.prepend('LD_LIBRARY_PATH', join_paths( meson.build_root(),'schedulers','nbt','lib'), join_paths( meson.build_root(),'runtime','lib'), - join_paths( meson.build_root(),'blocklib','analog','lib'), join_paths( meson.build_root(),'blocklib','blocks','lib'), - join_paths( meson.build_root(),'blocklib','fec','lib'), - join_paths( meson.build_root(),'blocklib','fft','lib'), - join_paths( meson.build_root(),'blocklib','fileio','lib'), - join_paths( meson.build_root(),'blocklib','filter','lib'), join_paths( meson.build_root(),'blocklib','math','lib'), join_paths( meson.build_root(),'blocklib','streamops','lib'), - join_paths( meson.build_root(),'blocklib','soapy','lib'), join_paths( meson.build_root(),'kernel','analog','lib'), join_paths( meson.build_root(),'kernel','digital','lib'), diff --git a/schedulers/nbt/include/gnuradio/schedulers/nbt/scheduler_nbt.h b/schedulers/nbt/include/gnuradio/schedulers/nbt/scheduler_nbt.h index d6571c9f7..5122d2b79 100644 --- a/schedulers/nbt/include/gnuradio/schedulers/nbt/scheduler_nbt.h +++ b/schedulers/nbt/include/gnuradio/schedulers/nbt/scheduler_nbt.h @@ -1,5 +1,4 @@ #include <gnuradio/block_group_properties.h> -#include <gnuradio/buffer_cpu_host.h> #include <gnuradio/buffer_cpu_vmcirc.h> // #include <gnuradio/buffer_cpu_simple.h> #include <gnuradio/graph_utils.h> @@ -26,14 +25,8 @@ public: } scheduler_nbt(const scheduler_nbt_options& opts) : scheduler(opts.name), _opts(opts) { - if (opts.default_buffer_type == "cpu_host") { - _default_buf_properties = - buffer_cpu_host_properties::make(buffer_cpu_host_type::H2H); - } - else { - _default_buf_properties = - buffer_cpu_vmcirc_properties::make(buffer_cpu_vmcirc_type::AUTO); - } + _default_buf_properties = + buffer_cpu_vmcirc_properties::make(buffer_cpu_vmcirc_type::AUTO); } ~scheduler_nbt() override{}; diff --git a/test/meson.build b/test/meson.build index 9ef0b73fd..58b8cca11 100644 --- a/test/meson.build +++ b/test/meson.build @@ -3,10 +3,7 @@ qa_srcs = ['qa_default_runtime', 'qa_scheduler_nbt', 'qa_block_grouping', - 'qa_single_mapped_buffers', 'qa_message_ports', - 'qa_tags', - 'qa_zmq_buffers', 'qa_hier_block', 'qa_reflection', ] diff --git a/test/qa_single_mapped_buffers.cc b/test/qa_single_mapped_buffers.cc deleted file mode 100644 index 1862bcdba..000000000 --- a/test/qa_single_mapped_buffers.cc +++ /dev/null @@ -1,139 +0,0 @@ -#include <gtest/gtest.h> - -#include <chrono> -#include <iostream> -#include <thread> - -#include <gnuradio/blocks/vector_sink.h> -#include <gnuradio/blocks/vector_source.h> -#include <gnuradio/buffer_sm.h> -#include <gnuradio/flowgraph.h> -#include <gnuradio/math/multiply_const.h> -#include <gnuradio/runtime.h> -#include <gnuradio/schedulers/nbt/scheduler_nbt.h> - -using namespace gr; - - -TEST(SchedulerMTSingleBuffers, SingleMappedSimple) -{ - int nsamples = 1000000; - std::vector<gr_complex> input_data(nsamples); - std::vector<gr_complex> expected_data(nsamples); - - float k = 1.0; - for (int i = 0; i < nsamples; i++) { - input_data[i] = gr_complex(2 * i, 2 * i + 1); - } - - int nblocks = 2; - size_t veclen = 1; - auto src = blocks::vector_source_c::make({ input_data }); - auto snk = blocks::vector_sink_c::make({}); - std::vector<math::multiply_const_cc::sptr> mult_blks(nblocks); - - for (int i = 0; i < nblocks; i++) { - mult_blks[i] = math::multiply_const_cc::make_cpu({ k, veclen }); - } - - auto fg = flowgraph::make(); - - fg->connect(src, 0, mult_blks[0], 0); - for (int i = 1; i < nblocks; i++) { - fg->connect(mult_blks[i - 1], 0, mult_blks[i], 0) - ->set_custom_buffer(SM_BUFFER_ARGS); - } - fg->connect(mult_blks[nblocks - 1], 0, snk, 0); - - auto rt = runtime::make(); - rt->initialize(fg); - rt->start(); - rt->wait(); - - - for (int i = 0; i < nsamples; i++) { - expected_data[i] = gr_complex(k * 2 * i, k * (2 * i + 1)); - } - - - auto d = snk->data(); - EXPECT_EQ(d, expected_data); - EXPECT_EQ(d.size(), expected_data.size()); - - for (size_t i = 0; i < expected_data.size(); i++) { - if (d[i] != expected_data[i]) { - std::cout << i << ": " << d[i] << " " << expected_data[i] << std::endl; - } - } -} - - -#if 1 -// Test the case where we have multiple readers to a single block -TEST(SchedulerMTSingleBuffers, SingleMappedFanout) -{ - int nsamples = 1000000; - std::vector<gr_complex> input_data(nsamples); - std::vector<gr_complex> expected_data(nsamples); - - float k = 1.0; - for (int i = 0; i < nsamples; i++) { - input_data[i] = gr_complex(2 * i, 2 * i + 1); - expected_data[i] = gr_complex(k * 2 * i, k * (2 * i + 1)); - } - - auto nblocks = 4; - - - size_t veclen = 1; - auto src = blocks::vector_source_c::make({ input_data }); - std::vector<blocks::vector_sink_c::sptr> sink_blks(nblocks); - std::vector<math::multiply_const_cc::sptr> mult_blks(nblocks); - - for (int i = 0; i < nblocks; i++) { - mult_blks[i] = math::multiply_const_cc::make_cpu({ k, veclen }); - sink_blks[i] = blocks::vector_sink_c::make({}); - } - flowgraph_sptr fg(new flowgraph()); - - for (int i = 0; i < nblocks; i++) { - fg->connect(src, 0, mult_blks[i], 0)->set_custom_buffer(SM_BUFFER_ARGS); - fg->connect(mult_blks[i], 0, sink_blks[i], 0)->set_custom_buffer(SM_BUFFER_ARGS); - } - - auto rt = runtime::make(); - rt->initialize(fg); - rt->start(); - rt->wait(); - - for (int n = 0; n < nblocks; n++) { - - auto d = sink_blks[n]->data(); - EXPECT_EQ(d.size(), expected_data.size()); - if (d.size() == expected_data.size()) { - EXPECT_EQ(d, expected_data); - - for (size_t i = 0; i < expected_data.size(); i++) { - if (d[i] != expected_data[i]) { - std::cout << n << " " << i << ": " << d[i] << " " << expected_data[i] - << std::endl; - } - } - } - else { - if (d.size() < expected_data.size()) { - auto e = std::vector<gr_complex>(expected_data.begin(), - expected_data.begin() + d.size()); - EXPECT_EQ(d, e); - - for (size_t i = 0; i < e.size(); i++) { - if (d[i] != e[i]) { - std::cout << n << " " << i << ": " << d[i] << " " << e[i] - << std::endl; - } - } - } - } - } -} -#endif diff --git a/test/qa_tags.cc b/test/qa_tags.cc deleted file mode 100644 index 471b5608f..000000000 --- a/test/qa_tags.cc +++ /dev/null @@ -1,251 +0,0 @@ -#include <gtest/gtest.h> - -#include <chrono> -#include <iostream> -#include <thread> - -#include <gnuradio/blocks/null_sink.h> -#include <gnuradio/blocks/null_source.h> -#include <gnuradio/blocks/vector_sink.h> -#include <gnuradio/blocks/vector_source.h> -#include <gnuradio/buffer_cpu_vmcirc.h> -#include <gnuradio/flowgraph.h> -#include <gnuradio/runtime.h> -#include <gnuradio/schedulers/nbt/scheduler_nbt.h> -#include <gnuradio/streamops/annotator.h> -#include <gnuradio/streamops/head.h> - -using namespace gr; - -TEST(SchedulerMTTags, OneToOne) -{ - size_t N = 40000; - auto fg = flowgraph::make(); - auto src = gr::blocks::null_source::make({}); - auto head = gr::streamops::head::make_cpu({ N }); - auto ann0 = gr::streamops::annotator::make_cpu( - { 10000, 1, 2, tag_propagation_policy_t::TPP_ONE_TO_ONE }); - auto ann1 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ONE_TO_ONE }); - auto ann2 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ONE_TO_ONE }); - auto snk0 = gr::blocks::null_sink::make({}); - auto snk1 = gr::blocks::null_sink::make({}); - - // using 1-to-1 tag propagation without having equal number of - // ins and outs. Make sure this works; will just exit run early. - fg->connect(src, 0, head, 0); - fg->connect(head, 0, ann0, 0); - fg->connect(ann0, 0, ann1, 0); - fg->connect(ann0, 1, ann2, 0); - fg->connect(ann1, 0, snk0, 0); - fg->connect(ann2, 0, snk1, 0); - - std::cerr << std::endl - << "NOTE: This is supposed to produce an error from block_executor" - << std::endl; - - auto rt = runtime::make(); - rt->initialize(fg); - rt->start(); - rt->wait(); - - std::vector<gr::tag_t> tags0 = ann0->data(); - std::vector<gr::tag_t> tags1 = ann1->data(); - std::vector<gr::tag_t> tags2 = ann2->data(); - - // The first annotator does not receive any tags from the null sink upstream - EXPECT_EQ(tags0.size(), 0); - EXPECT_EQ(tags1.size(), 4); - EXPECT_EQ(tags2.size(), 4); -} - -TEST(SchedulerMTTags, t1) -{ - size_t N = 40000; - auto fg = flowgraph::make(); - auto src = gr::blocks::null_source::make({}); - auto head = gr::streamops::head::make_cpu({ N }); - auto ann0 = gr::streamops::annotator::make_cpu( - { 10000, 1, 2, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann1 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann2 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann3 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann4 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - - auto snk0 = gr::blocks::null_sink::make({}); - auto snk1 = gr::blocks::null_sink::make({}); - - fg->connect(src, 0, head, 0); - fg->connect(head, 0, ann0, 0); - - fg->connect(ann0, 0, ann1, 0); - fg->connect(ann0, 1, ann2, 0); - fg->connect(ann1, 0, ann3, 0); - fg->connect(ann2, 0, ann4, 0); - - fg->connect(ann3, 0, snk0, 0); - fg->connect(ann4, 0, snk1, 0); - - auto rt = runtime::make(); - rt->initialize(fg); - rt->start(); - rt->wait(); - - std::vector<gr::tag_t> tags0 = ann0->data(); - std::vector<gr::tag_t> tags3 = ann3->data(); - std::vector<gr::tag_t> tags4 = ann4->data(); - - // The first annotator does not receive any tags from the null sink upstream - EXPECT_EQ(tags0.size(), (size_t)0); - EXPECT_EQ(tags3.size(), (size_t)8); - EXPECT_EQ(tags4.size(), (size_t)8); -} - -TEST(SchedulerMTTags, t2) -{ - size_t N = 40000; - auto fg = flowgraph::make(); - auto src = gr::blocks::null_source::make({}); - auto head = gr::streamops::head::make_cpu({ N }); - auto ann0 = gr::streamops::annotator::make_cpu( - { 10000, 1, 2, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann1 = gr::streamops::annotator::make_cpu( - { 10000, 2, 3, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann2 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann3 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann4 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto snk0 = gr::blocks::null_sink::make({}); - auto snk1 = gr::blocks::null_sink::make({}); - auto snk2 = gr::blocks::null_sink::make({}); - - fg->connect(src, 0, head, 0); - fg->connect(head, 0, ann0, 0); - - fg->connect(ann0, 0, ann1, 0); - fg->connect(ann0, 1, ann1, 1); - fg->connect(ann1, 0, ann2, 0); - fg->connect(ann1, 1, ann3, 0); - fg->connect(ann1, 2, ann4, 0); - - fg->connect(ann2, 0, snk0, 0); - fg->connect(ann3, 0, snk1, 0); - fg->connect(ann4, 0, snk2, 0); - - - auto rt = runtime::make(); - rt->initialize(fg); - rt->start(); - rt->wait(); - - std::vector<gr::tag_t> tags0 = ann0->data(); - std::vector<gr::tag_t> tags1 = ann1->data(); - std::vector<gr::tag_t> tags2 = ann2->data(); - std::vector<gr::tag_t> tags3 = ann4->data(); - std::vector<gr::tag_t> tags4 = ann4->data(); - - // The first annotator does not receive any tags from the null sink upstream - EXPECT_EQ(tags0.size(), (size_t)0); - EXPECT_EQ(tags1.size(), (size_t)8); - - // Make sure the rest all have 12 tags - EXPECT_EQ(tags2.size(), (size_t)12); - EXPECT_EQ(tags3.size(), (size_t)12); - EXPECT_EQ(tags4.size(), (size_t)12); -} - -TEST(SchedulerMTTags, t3) -{ - size_t N = 40000; - auto fg = flowgraph::make(); - auto src = gr::blocks::null_source::make({}); - auto head = gr::streamops::head::make_cpu({ N }); - auto ann0 = gr::streamops::annotator::make_cpu( - { 10000, 2, 2, tag_propagation_policy_t::TPP_ONE_TO_ONE }); - auto ann1 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann2 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL }); - auto ann3 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ONE_TO_ONE }); - auto ann4 = gr::streamops::annotator::make_cpu( - { 10000, 1, 1, tag_propagation_policy_t::TPP_ONE_TO_ONE }); - auto snk0 = gr::blocks::null_sink::make({}); - auto snk1 = gr::blocks::null_sink::make({}); - - fg->connect(src, 0, head, 0); - fg->connect(head, 0, ann0, 0); - fg->connect(head, 0, ann0, 1); - - fg->connect(ann0, 0, ann1, 0); - fg->connect(ann0, 1, ann2, 0); - fg->connect(ann1, 0, ann3, 0); - fg->connect(ann2, 0, ann4, 0); - - fg->connect(ann3, 0, snk0, 0); - fg->connect(ann4, 0, snk1, 0); - - auto sched = schedulers::scheduler_nbt::make(); - sched->add_block_group({ src, head, ann0, ann1, ann2, ann3, ann4, snk0, snk1 }); - auto rt = runtime::make(); - rt->add_scheduler(sched); - rt->initialize(fg); - rt->start(); - rt->wait(); - auto tags0 = ann0->data(); - auto tags3 = ann3->data(); - auto tags4 = ann4->data(); - - // The first annotator does not receive any tags from the null sink upstream - EXPECT_EQ(tags0.size(), (size_t)0); - EXPECT_EQ(tags3.size(), (size_t)8); - EXPECT_EQ(tags4.size(), (size_t)8); -} - - -#if 0 // TODO Rate Change Blocks -TEST(SchedulerMTTags, t5) -{ - int N = 40000; - - auto fg = flowgraph::make(); - auto src = gr::blocks::null_source::make({sizeof(int)}); - auto head = gr::streamops::head::make_cpu(sizeof(int), N); - auto ann0 = gr::streamops::annotator::make_cpu( - 10000, 1, 2, tag_propagation_policy_t::TPP_ALL_TO_ALL); - auto ann1 = gr::streamops::annotator::make_cpu( - 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL); - auto ann2 = gr::streamops::annotator::make_cpu( - 10000, 1, 1, tag_propagation_policy_t::TPP_ALL_TO_ALL); - auto snk0 = gr::blocks::null_sink::make(sizeof(int)); - - // Rate change blocks - gr::blocks::keep_one_in_n::sptr dec10( - gr::blocks::keep_one_in_n::make(sizeof(float), 10)); - - tb->connect(src, 0, head, 0); - tb->connect(head, 0, ann0, 0); - tb->connect(ann0, 0, ann1, 0); - tb->connect(ann1, 0, dec10, 0); - tb->connect(dec10, 0, ann2, 0); - tb->connect(ann2, 0, snk0, 0); - - tb->run(); - - std::vector<gr::tag_t> tags0 = ann0->data(); - std::vector<gr::tag_t> tags1 = ann1->data(); - std::vector<gr::tag_t> tags2 = ann2->data(); - - // The first annotator does not receive any tags from the null sink upstream - BOOST_REQUIRE_EQUAL(tags0.size(), (size_t)0); - BOOST_REQUIRE_EQUAL(tags1.size(), (size_t)4); - BOOST_REQUIRE_EQUAL(tags2.size(), (size_t)8); -} -#endif
\ No newline at end of file diff --git a/test/qa_zmq_buffers.cc b/test/qa_zmq_buffers.cc deleted file mode 100644 index 5a94039bb..000000000 --- a/test/qa_zmq_buffers.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include <gtest/gtest.h> - -#include <chrono> -#include <iostream> -#include <thread> - -#include <gnuradio/blocks/vector_sink.h> -#include <gnuradio/blocks/vector_source.h> -#include <gnuradio/buffer_cpu_vmcirc.h> -#include <gnuradio/buffer_net_zmq.h> -#include <gnuradio/flowgraph.h> -#include <gnuradio/math/multiply_const.h> -#include <gnuradio/runtime.h> -#include <gnuradio/schedulers/nbt/scheduler_nbt.h> -#include <gnuradio/streamops/copy.h> -#include <gnuradio/streamops/head.h> - -using namespace gr; - -TEST(SchedulerMTTest, ZMQBuffers) -{ - size_t nsamples = 100000; - std::vector<float> input_data(nsamples); - for (size_t i = 0; i < nsamples; i++) { - input_data[i] = i; - } - auto src = blocks::vector_source_f::make({ input_data, true }); - // auto copy1 = streamops::copy::make({sizeof(float)}); - auto copy2 = streamops::copy::make({ sizeof(float) }); - auto hd = streamops::head::make({ nsamples, sizeof(float) }); - auto snk1 = blocks::vector_sink_f::make({}); - - flowgraph_sptr fg(new flowgraph()); - // fg->connect(src, 0, copy1, 0); - fg->connect(src, 0, copy2, 0) - ->set_custom_buffer(buffer_net_zmq_properties::make("127.0.0.1", 1234)); - fg->connect(copy2, 0, hd, 0); - fg->connect(hd, 0, snk1, 0); - - auto rt = runtime::make(); - rt->initialize(fg); - rt->start(); - rt->wait(); - - EXPECT_EQ(snk1->data().size(), input_data.size()); - EXPECT_EQ(snk1->data(), input_data); - - auto data = snk1->data(); - for (size_t i = 0; i < data.size(); i++) { - if (input_data[i] != data[i]) { - std::cout << i << ": " << input_data[i] << " " << data[i] << std::endl; - } - } -} |