Skip to content

Commit

Permalink
Add blocks defined in the blocklib to the blocks registry (#288)
Browse files Browse the repository at this point in the history
* Add blocks defined in the blocklib to the blocks registry
  - Blocks that can be added to the blocks registry have been added
  - Small block registry refactoring
  - Replaced `ENABLE_REFLECTION_FOR_TEMPLATE_FULL` with `ENABLE_REFLECTION_FOR_TEMPLATE` where possible

* Revamped the block registry to support NTTPs and not to need macros

* Make block naming more stable 
   meta::type_name has an issue of being compiler and platform dependent.
   Instead of using that for block type to string conversion, use reflcpp
   and generate template parameter list for the block type manually.

* Call ut run directly to avoid test end issues

Co-authored-by: Ralph J. Steinhagen <[email protected]>
  • Loading branch information
ivan-cukic and RalphSteinhagen authored Mar 4, 2024
1 parent cb1a8ea commit fc33c17
Show file tree
Hide file tree
Showing 43 changed files with 602 additions and 349 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ if (ENABLE_TESTING AND UNIX AND NOT APPLE)
if (ENABLE_COVERAGE)
message("Coverage reporting enabled")
include(cmake/CodeCoverage.cmake) # https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake # (License: BSL-1.0)
target_compile_options(gnuradio-options INTERFACE --coverage -O0 -g -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0) # fortify_source is not possible without optimization
target_compile_options(gnuradio-options INTERFACE --coverage -O0 -g -gz -gdwarf-2 -gstrict-dwarf -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0) # fortify_source is not possible without optimization
target_link_libraries(gnuradio-options INTERFACE --coverage)
append_coverage_compiler_flags()
set(GCOVR_ADDITIONAL_ARGS "--merge-mode-functions=merge-use-line-min")
Expand Down
1 change: 1 addition & 0 deletions bench/benchmark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ for details see: https://www.kernel.org/doc/Documentation/sysctl/kernel.txt)";
&& (ioctl(_fd_misses, PERF_EVENT_IOC_DISABLE) == -1 || ioctl(_fd_accesses, PERF_EVENT_IOC_DISABLE) == -1 || ioctl(_fd_branch_misses, PERF_EVENT_IOC_DISABLE) == -1
|| ioctl(_fd_branch, PERF_EVENT_IOC_DISABLE) == -1 || ioctl(_fd_instructions, PERF_EVENT_IOC_DISABLE) == -1 || ioctl(_fd_ctx_switches, PERF_EVENT_IOC_DISABLE) == -1)) {
print_access_right_msg("could not PERF_EVENT_IOC_DISABLE");
return;
}
close(_fd_misses);
close(_fd_accesses);
Expand Down
4 changes: 3 additions & 1 deletion blocks/basic/include/gnuradio-4.0/basic/DataSink.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define GNURADIO_DATA_SINK_HPP

#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>
#include <gnuradio-4.0/CircularBuffer.hpp>
#include <gnuradio-4.0/DataSet.hpp>
#include <gnuradio-4.0/HistoryBuffer.hpp>
Expand Down Expand Up @@ -992,6 +993,7 @@ class DataSink : public Block<DataSink<T>> {

} // namespace gr::basic

ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (gr::basic::DataSink<T>), in, sample_rate, signal_name, signal_unit, signal_min, signal_max);
ENABLE_REFLECTION_FOR_TEMPLATE(gr::basic::DataSink, in, sample_rate, signal_name, signal_unit, signal_min, signal_max);
auto registerDataSink = gr::registerBlock<gr::basic::DataSink, float, double>(gr::globalBlockRegistry());

#endif
7 changes: 4 additions & 3 deletions blocks/basic/include/gnuradio-4.0/basic/FunctionGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
#define GNURADIO_FUNCTION_GENERATOR_HPP

#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>
#include <gnuradio-4.0/Tag.hpp>

#include <magic_enum.hpp>
#include <magic_enum_utility.hpp>
#include <numbers>

namespace gr::basic {

Expand Down Expand Up @@ -321,7 +322,7 @@ struct FunctionGenerator : public gr::Block<FunctionGenerator<T>, BlockingIO<tru

} // namespace gr::basic

ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (gr::basic::FunctionGenerator<T>), in, out, sample_rate, signal_type, start_value, final_value, duration, round_off_time, impulse_time0,
impulse_time1, trigger_meta_info);
ENABLE_REFLECTION_FOR_TEMPLATE(gr::basic::FunctionGenerator, in, out, sample_rate, signal_type, start_value, final_value, duration, round_off_time, impulse_time0, impulse_time1, trigger_meta_info);
auto registerFunctionGenerator = gr::registerBlock<gr::basic::FunctionGenerator, float, double>(gr::globalBlockRegistry());

#endif // GNURADIO_FUNCTION_GENERATOR_HPP
2 changes: 2 additions & 0 deletions blocks/basic/include/gnuradio-4.0/basic/Selector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define GNURADIO_SELECTOR_HPP

#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>

#include <gnuradio-4.0/meta/utils.hpp>

Expand Down Expand Up @@ -193,6 +194,7 @@ struct Selector : Block<Selector<T>, SelectorDoc> {
} // namespace gr::basic

ENABLE_REFLECTION_FOR_TEMPLATE(gr::basic::Selector, select, inputs, monitor, outputs, n_inputs, n_outputs, map_in, map_out, back_pressure);
auto registerSelector = gr::registerBlock<gr::basic::Selector, float, double>(gr::globalBlockRegistry());
static_assert(gr::HasProcessBulkFunction<gr::basic::Selector<double>>);

#endif // include guard
5 changes: 4 additions & 1 deletion blocks/basic/include/gnuradio-4.0/basic/SignalGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define GNURADIO_SIGNAL_GENERATOR_HPP

#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>

#include <numbers>

namespace gr::basic {
Expand Down Expand Up @@ -119,6 +121,7 @@ struct SignalGenerator : public gr::Block<SignalGenerator<T>, BlockingIO<true>,

} // namespace gr::basic

ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (gr::basic::SignalGenerator<T>), in, out, sample_rate, signal_type, frequency, amplitude, offset, phase);
ENABLE_REFLECTION_FOR_TEMPLATE(gr::basic::SignalGenerator, in, out, sample_rate, signal_type, frequency, amplitude, offset, phase);
auto registerSignalGenerator = gr::registerBlock<gr::basic::SignalGenerator, double, float>(gr::globalBlockRegistry());

#endif // GNURADIO_SIGNAL_GENERATOR_HPP
13 changes: 4 additions & 9 deletions blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <string_view>

#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>
#include <gnuradio-4.0/Graph.hpp>
#include <gnuradio-4.0/reflection.hpp>

Expand Down Expand Up @@ -103,13 +104,7 @@ struct MultiAdder : public gr::Block<MultiAdder<T>> {

ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (MultiAdder<T>), inputs, out, n_inputs);

template<typename Registry>
void
registerBuiltinBlocks(Registry *registry) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
GP_REGISTER_BLOCK_RUNTIME(registry, builtin_multiply, double, float);
GP_REGISTER_BLOCK_RUNTIME(registry, builtin_counter, double, float);
#pragma GCC diagnostic pop
}
auto registerMultiply = gr::registerBlock<builtin_multiply, double, float>(gr::globalBlockRegistry());
auto registerCounter = gr::registerBlock<builtin_counter, double, float>(gr::globalBlockRegistry());

#endif // include guard
2 changes: 2 additions & 0 deletions blocks/basic/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
add_ut_test(qa_Selector)
add_ut_test(qa_sources)
add_ut_test(qa_DataSink)

add_ut_test(qa_BasicKnownBlocks)
36 changes: 36 additions & 0 deletions blocks/basic/test/qa_BasicKnownBlocks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <boost/ut.hpp>

#include <gnuradio-4.0/basic/clock_source.hpp>
#include <gnuradio-4.0/basic/common_blocks.hpp>
#include <gnuradio-4.0/basic/DataSink.hpp>
#include <gnuradio-4.0/basic/FunctionGenerator.hpp>
#include <gnuradio-4.0/basic/Selector.hpp>
#include <gnuradio-4.0/basic/SignalGenerator.hpp>

const boost::ut::suite KnownBlockTests = [] {
using namespace boost::ut;
using namespace std::string_literals;

"Registered"_test = [] {
auto known = gr::globalBlockRegistry().knownBlocks();
std::ranges::sort(known);

std::vector<std::string> desired{
//
"builtin_counter"s, //
"builtin_multiply"s, //
"gr::basic::DataSink"s, //
"gr::basic::FunctionGenerator"s, //
"gr::basic::Selector"s, //
"gr::basic::SignalGenerator"s //
};
std::ranges::sort(desired);

expect((std::ranges::includes(known, desired)));
};
};

int
main() {
return boost::ut::cfg<boost::ut::override>.run();
}
13 changes: 10 additions & 3 deletions blocks/filter/include/gnuradio-4.0/filter/time_domain_filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <numeric>

#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>
#include <gnuradio-4.0/HistoryBuffer.hpp>

namespace gr::filter {
Expand Down Expand Up @@ -40,7 +41,7 @@ enum class IIRForm {
DF_I, /// direct form I: preferred for fixed-point arithmetics (e.g. no overflow)
DF_II, /// direct form II: preferred for floating-point arithmetics (less operations)
DF_I_TRANSPOSED,
DF_II_TRANSPOSED
DF_II_TRANSPOSED,
};

template<typename T, IIRForm form = std::is_floating_point_v<T> ? IIRForm::DF_II : IIRForm::DF_I>
Expand Down Expand Up @@ -91,7 +92,7 @@ a are the feedback coefficients
return std::inner_product(b.cbegin(), b.cend(), outputHistory.cbegin(), static_cast<T>(0));
} else if constexpr (form == IIRForm::DF_II_TRANSPOSED) {
// y[n] = b_0*f[n] + \sum_(k=1)^N(b_k*f[n−k] − a_k*y[n−k])
const T output = b[0] * input //
const T output = b[0] * input //
+ std::inner_product(b.cbegin() + 1, b.cend(), inputHistory.cbegin(), static_cast<T>(0)) //
- std::inner_product(a.cbegin() + 1, a.cend(), outputHistory.cbegin(), static_cast<T>(0));

Expand All @@ -104,7 +105,13 @@ a are the feedback coefficients

} // namespace gr::filter

ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (gr::filter::fir_filter<T>), in, out, b);
ENABLE_REFLECTION_FOR_TEMPLATE(gr::filter::fir_filter, in, out, b);
ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T, gr::filter::IIRForm form), (gr::filter::iir_filter<T, form>), in, out, b, a);

auto registerFirFilter = gr::registerBlock<gr::filter::fir_filter, double, float>(gr::globalBlockRegistry());
auto registerIirFilter = gr::registerBlock<gr::filter::iir_filter, gr::filter::IIRForm::DF_I, double, float>(gr::globalBlockRegistry())
| gr::registerBlock<gr::filter::iir_filter, gr::filter::IIRForm::DF_II, double, float>(gr::globalBlockRegistry())
| gr::registerBlock<gr::filter::iir_filter, gr::filter::IIRForm::DF_I_TRANSPOSED, double, float>(gr::globalBlockRegistry())
| gr::registerBlock<gr::filter::iir_filter, gr::filter::IIRForm::DF_II_TRANSPOSED, double, float>(gr::globalBlockRegistry());

#endif // GNURADIO_TIME_DOMAIN_FILTER_HPP
2 changes: 1 addition & 1 deletion blocks/fourier/test/qa_fourier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct CountSource : public gr::Block<CountSource<T>> {
}
};

ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (CountSource<T>), out, count, nSamples);
ENABLE_REFLECTION_FOR_TEMPLATE(CountSource, out, count, nSamples);

template<typename T>
std::vector<T>
Expand Down
102 changes: 64 additions & 38 deletions blocks/http/include/gnuradio-4.0/http/HttpBlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,26 @@
#define GNURADIO_HTTP_BLOCK_HPP

#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>
#include <gnuradio-4.0/Graph.hpp>
#include <gnuradio-4.0/reflection.hpp>
#include <pmtv/pmt.hpp>

#include <semaphore>
#include <queue>

#ifdef __GNUC__
#pragma GCC diagnostic push // ignore warning of external libraries that from this lib-context we do not have any control over
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wuseless-cast"
#endif
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <magic_enum.hpp>
#include <magic_enum_utility.hpp>
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
Expand All @@ -20,10 +36,10 @@ using namespace std::chrono_literals;

namespace gr::http {

enum class RequestType {
GET,
SUBSCRIBE,
POST,
enum class RequestType : char {
GET = 1,
SUBSCRIBE = 2,
POST = 3,
};

using HttpBlockDoc = Doc<R""(
Expand Down Expand Up @@ -79,7 +95,7 @@ class HttpBlock : public gr::Block<HttpBlock<T>, BlockingIO<false>, HttpBlockDoc
doRequestEmscripten() {
emscripten_fetch_attr_t attr;
emscripten_fetch_attr_init(&attr);
if (type == RequestType::POST) {
if (_type == RequestType::POST) {
strcpy(attr.requestMethod, "POST");
if (!parameters.empty()) {
attr.requestData = parameters.c_str();
Expand Down Expand Up @@ -107,7 +123,7 @@ class HttpBlock : public gr::Block<HttpBlock<T>, BlockingIO<false>, HttpBlockDoc

void
runThreadEmscripten() {
if (type == RequestType::SUBSCRIBE) {
if (_type == RequestType::SUBSCRIBE) {
while (!_shutdownThread) {
// long polling, just keep doing requests
std::thread thread{ &HttpBlock::doRequestEmscripten, this };
Expand All @@ -129,7 +145,7 @@ class HttpBlock : public gr::Block<HttpBlock<T>, BlockingIO<false>, HttpBlockDoc
runThreadNative() {
_client = std::make_unique<httplib::Client>(url);
_client->set_follow_location(true);
if (type == RequestType::SUBSCRIBE) {
if (_type == RequestType::SUBSCRIBE) {
// it's long polling, be generous with timeouts
_client->set_read_timeout(1h);
_client->Get(endpoint, [&](const char *data, size_t len) {
Expand All @@ -147,7 +163,7 @@ class HttpBlock : public gr::Block<HttpBlock<T>, BlockingIO<false>, HttpBlockDoc
while (_pendingRequests > 0) {
_pendingRequests--;
httplib::Result resp;
if (type == RequestType::POST) {
if (_type == RequestType::POST) {
resp = parameters.empty() ? _client->Post(endpoint) : _client->Post(endpoint, parameters, "application/x-www-form-urlencoded");
} else {
resp = _client->Get(endpoint);
Expand Down Expand Up @@ -181,54 +197,63 @@ class HttpBlock : public gr::Block<HttpBlock<T>, BlockingIO<false>, HttpBlockDoc
}

void
runThread() {
startThread() {
if (_thread) {
_thread.reset();
}
_thread = std::shared_ptr<std::thread>(new std::thread([this]() {
#ifdef __EMSCRIPTEN__
runThreadEmscripten();
runThreadEmscripten();
#else
runThreadNative();
runThreadNative();
#endif
}

void
startThread() {
_thread = std::shared_ptr<std::thread>(new std::thread([this]() { runThread(); }), [this](std::thread *t) {
_shutdownThread = true;
_ready.release();
}),
[this](std::thread *t) {
if (auto ret = this->changeStateTo(gr::lifecycle::State::REQUESTED_STOP); !ret) {
throw std::invalid_argument(fmt::format("{}::startThread() could not change state to REQUESTED_STOP", this->name));
}
_shutdownThread = true;
_ready.release();
#ifndef __EMSCRIPTEN__
_client->stop();
if (_client) {
_client->stop();
}
#endif
if (t->joinable()) {
t->join();
}
_shutdownThread = false;
delete t;

std::ignore = this->changeStateTo(gr::lifecycle::State::STOPPED);
});
if (t->joinable()) {
t->join();
}
_shutdownThread = false;
delete t;
if (auto ret = this->changeStateTo(gr::lifecycle::State::STOPPED); !ret) {
throw std::invalid_argument(fmt::format("{}::startThread() could not change state to STOPPED", this->name));
}
});
}

void
stopThread() {
_thread.reset();
}

gr::http::RequestType _type = gr::http::RequestType::GET;

public:
PortOut<pmtv::map_t> out;

std::string url;
std::string endpoint;
gr::http::RequestType type = gr::http::RequestType::GET;
std::string parameters; // x-www-form-urlencoded encoded POST parameters

explicit HttpBlock(const std::string &_url, const std::string &_endpoint = "/", const RequestType _type = RequestType::GET, const std::string &_parameters = "")
: url(_url), endpoint(_endpoint), type(_type), parameters(_parameters) {}
std::string url;
std::string endpoint = "/";
std::string type = std::string(magic_enum::enum_name(_type));
std::string parameters; // x-www-form-urlencoded encoded POST parameters

~HttpBlock() { stopThread(); }

void
settingsChanged(const property_map & /*oldSettings*/, property_map &newSettings) noexcept {
settingsChanged(const property_map & /*oldSettings*/, property_map &newSettings) {
if (newSettings.contains("url") || newSettings.contains("type")) {
// other setting changes are hot-swappble without restarting the Client
if (newSettings.contains("type")) {
_type = magic_enum::enum_cast<gr::http::RequestType>(type, magic_enum::case_insensitive).value_or(_type);
}
// other setting changes are hot-swappable without restarting the Client
startThread();
}
}
Expand Down Expand Up @@ -263,7 +288,7 @@ class HttpBlock : public gr::Block<HttpBlock<T>, BlockingIO<false>, HttpBlockDoc
void
processMessages(gr::MsgPortInNamed<"__Builtin"> &, std::span<const gr::Message> message) {
std::ranges::for_each(message, [this](auto &m) {
if (type == RequestType::SUBSCRIBE) {
if (_type == RequestType::SUBSCRIBE) {
if (m.contains("active")) {
// for long polling, the subscription should stay active, if and only if the messages's "active" member is truthy
if (std::get<bool>(m.at("active"))) {
Expand All @@ -286,6 +311,7 @@ static_assert(gr::BlockLike<http::HttpBlock<uint8_t>>);

} // namespace gr::http

ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (gr::http::HttpBlock<T>), out, url, endpoint);
ENABLE_REFLECTION_FOR_TEMPLATE(gr::http::HttpBlock, out, url, endpoint, type, parameters);
auto registerHttpBlock = gr::registerBlock<gr::http::HttpBlock, float, double>(gr::globalBlockRegistry());

#endif // GNURADIO_HTTP_BLOCK_HPP
Loading

0 comments on commit fc33c17

Please sign in to comment.