Skip to content

Commit

Permalink
added Dashboard-ImPlotSink UI unit-test (#252)
Browse files Browse the repository at this point in the history
Signed-off-by: rstein <[email protected]>
  • Loading branch information
RalphSteinhagen authored Dec 19, 2024
1 parent ecf6954 commit 8d39525
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 182 deletions.
4 changes: 2 additions & 2 deletions cmake/DependenciesSHAs.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
set(GIT_SHA_GNURADIO4 db0a2bcc4a14759c992ca89661f687b87d93e923 CACHE STRING "" FORCE) # main as of 2024-12-09
set(GIT_SHA_GNURADIO4 0da51c551ed2317c7afafa066971d2eac8617ae1 CACHE STRING "" FORCE) # main as of 2024-12-19

set(GIT_SHA_OPENCMW_CPP bb8996babab2000a4ae3612ea146a551a96e59c4 CACHE STRING "" FORCE) # main as of 2024-10-18

set(GIT_SHA_UT v2.0.1 CACHE STRING "" FORCE) # latest version as of 2023-12-19

set(GIT_SHA_GR_DIGITIZERS 749394c12285887eb8840ac4cd0c46f1d21b46b4 CACHE STRING "" FORCE) # dev-prototype as of 2024-11-06
set(GIT_SHA_GR_DIGITIZERS fbbcf42cdf51513bad3415fb35363b58fd4ebb16 CACHE STRING "" FORCE) # main as of 2024-12-18
2 changes: 1 addition & 1 deletion src/service/gnuradio/examples/function_generator.grc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
blocks:
- name: !!str ClockSource
id: !!str gr::basic::ClockSource
template_args: !!str "float"
template_args: !!str "unsigned char"
parameters:
do_zero_order_hold: !!bool true
n_samples_max: !!uint32 0
Expand Down
2 changes: 1 addition & 1 deletion src/service/gnuradio/examples/signal_generator.grc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
blocks:
- name: !!str ClockSource
id: !!str gr::basic::ClockSource
template_args: !!str "float"
template_args: !!str "unsigned char"
parameters:
do_zero_order_hold: !!bool true
n_samples_max: !!uint32 0
Expand Down
2 changes: 1 addition & 1 deletion src/service/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void registerTestBlocks(Registry& registry) {
gr::registerBlock<fair::picoscope::Picoscope4000a, fair::picoscope::AcquisitionMode::Streaming, float, std::int16_t>(registry); // ommitting gr::UncertainValue<float> for now, which would also be supported by picoscope block
gr::registerBlock<gr::basic::FunctionGenerator, float>(registry);
gr::registerBlock<gr::basic::SignalGenerator, float>(registry);
gr::registerBlock<gr::basic::DefaultClockSource, float>(registry);
gr::registerBlock<gr::basic::DefaultClockSource, std::uint8_t>(registry);
gr::registerBlock<MultiAdder, float>(registry);
fmt::print("providedBlocks:\n");
for (auto& blockName : registry.providedBlocks()) {
Expand Down
9 changes: 9 additions & 0 deletions src/ui/Dashboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,16 @@ void Dashboard::load(const std::string& grcData, const std::string& dashboardDat
localFlowGraph.parse(grcData);
// Load is called after parsing the flowgraph so that we already have the list of sources
doLoad(dashboardData);
} catch (const gr::exception& e) {
#ifndef NDEBUG
fmt::println(stderr, "Dashboard::load(const std::string& grcData,const std::string& dashboardData): error: {}", e);
#endif
components::Notification::error(fmt::format("Error: {}", e.what()));
App::instance().closeDashboard();
} catch (const std::exception& e) {
#ifndef NDEBUG
fmt::println(stderr, "Dashboard::load(const std::string& grcData,const std::string& dashboardData): error: {}", e.what());
#endif
components::Notification::error(fmt::format("Error: {}", e.what()));
App::instance().closeDashboard();
}
Expand Down
94 changes: 65 additions & 29 deletions src/ui/Flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,28 @@ auto typeToName() {
}

std::string valueTypeName(auto& port) {
static const std::map<std::string, std::string> mangledToName{{typeToName<float>(), "float"s}, {typeToName<double>(), "double"s},

{typeToName<std::complex<float>>(), "std::complex<float>"s}, {typeToName<std::complex<double>>(), "std::complex<double>"s},

{typeToName<gr::DataSet<float>>(), "gr::DataSet<float>"s}, {typeToName<gr::DataSet<double>>(), "gr::DataSet<double>"s},

{typeToName<std::int8_t>(), "std::int8_t"s}, {typeToName<std::int16_t>(), "std::int16_t"s}, {typeToName<std::int32_t>(), "std::int32_t"s}, {typeToName<std::int64_t>(), "std::int64_t"s}};
static const std::map<std::string, std::string> mangledToName{ //
{typeToName<float>(), "float"s}, //
{typeToName<double>(), "double"s}, //
{typeToName<std::complex<float>>(), "std::complex<float>"s}, //
{typeToName<std::complex<double>>(), "std::complex<double>"s}, //
{typeToName<gr::DataSet<float>>(), "gr::DataSet<float>"s}, //
{typeToName<gr::DataSet<double>>(), "gr::DataSet<double>"s}, //
{typeToName<std::int8_t>(), "std::int8_t"s}, //
{typeToName<std::int16_t>(), "std::int16_t"s}, //
{typeToName<std::int32_t>(), "std::int32_t"s}, //
{typeToName<std::int64_t>(), "std::int64_t"s}, //
{typeToName<std::uint8_t>(), "std::uint8_t"s}, //
{typeToName<std::uint16_t>(), "std::uint16_t"s}, //
{typeToName<std::uint32_t>(), "std::uint32_t"s}, //
{typeToName<std::uint64_t>(), "std::uint64_t"s}}; //

if (auto it = mangledToName.find(port.defaultValue().type().name()); it != mangledToName.end()) {
return it->second;
} else {
return "unknown_type"s;
}

throw gr::exception(fmt::format("valueTypeName(auto& port) - could not identify port data type '{}'", port.defaultValue().type().name()));
return "unknown_type"s;
}

const std::string& DataType::toString() const {
Expand Down Expand Up @@ -137,7 +146,8 @@ void BlockRegistry::addBlockDefinitionsFromPluginLoader(gr::PluginLoader& plugin

void BlockRegistry::addBlockDefinition(std::unique_ptr<BlockDefinition>&& t) { _types.insert({t->name, std::move(t)}); }

Block::Block(std::string_view name, const BlockDefinition* t, gr::property_map settings) : name(name), m_type(t), m_settings(std::move(settings)) { //
Block::Block(std::string_view name, const BlockDefinition* t, gr::property_map settings) : name(name), m_type(t), m_settings(std::move(settings)) {
//
setCurrentInstantiation(m_type->instantiations.cbegin()->first);
}

Expand All @@ -151,10 +161,11 @@ void Block::setSetting(const std::string& settingName, const pmtv::pmt& p) {
App::instance().sendMessage(msg);
}

void Block::updateSettings(const gr::property_map& settings) {
void Block::updateSettings(const gr::property_map& settings, const std::map<pmtv::pmt, std::vector<std::pair<gr::SettingsCtx, gr::property_map>>, gr::settings::PMTCompare>& stagedSettings) {
for (const auto& [k, v] : settings) {
m_settings[k] = v;
}
_storedSettings = stagedSettings;
}

void Block::update() {
Expand Down Expand Up @@ -210,16 +221,24 @@ void Block::update() {
if (t == "std::complex<float>") {
return DataType::ComplexFloat32;
}
// if (t == "std::complex<std::int64_t>") return DataType::ComplexInt64;
// if (t == "std::complex<std::int32_t>") return DataType::ComplexInt32;
// if (t == "std::complex<std::int16_t>") return DataType::ComplexInt16;
// if (t == "std::complex<std::int8_t>") return DataType::ComplexInt8;
if (t == "double") {
return dataset ? DataType::DataSetFloat64 : DataType::Float64;
}
if (t == "float") {
return dataset ? DataType::DataSetFloat32 : DataType::Float32;
}
if (t == "std::uint64_t") {
return DataType::UInt64;
}
if (t == "std::uint32_t" || t == "unsigned int") {
return DataType::UInt32;
}
if (t == "std::uint16_t" || t == "unsigned short") {
return DataType::UInt16;
}
if (t == "std::uint8_t") {
return DataType::UInt8;
}
if (t == "std::int64_t") {
return DataType::Int64;
}
Expand All @@ -232,7 +251,6 @@ void Block::update() {
if (t == "std::int8_t") {
return DataType::Int8;
}

if (t == "gr::DataSet<float>") {
return DataType::DataSetFloat32;
}
Expand All @@ -246,15 +264,14 @@ void Block::update() {
if (t == "bus") {
return DataType::BusConnection;
}
if (t == "") {
if (t.empty()) {
return DataType::Wildcard;
}
if (t == "untyped") {
return DataType::Untyped;
}

fmt::print("unhandled type {}\n", t);
assert(0);
throw gr::exception(fmt::format("unhandled data type: '{}'\n", t));
return DataType::Untyped;
};
auto getType = [&](const std::string& t, bool dataset) {
Expand Down Expand Up @@ -322,28 +339,32 @@ void FlowGraph::parse(const std::filesystem::path& file) {
void FlowGraph::parse(const std::string& str) {
clear();

auto grGraph = [this, &str]() {
gr::Graph grGraph = [this, &str]() -> gr::Graph {
try {
return gr::loadGrc(*_pluginLoader, str);
} catch (const gr::exception&) {
throw;
} catch (const std::string& e) {
throw std::runtime_error(e);
throw gr::exception(e);
} catch (...) {
throw std::current_exception();
}
}();

grGraph.forEachBlock([&](const auto& grBlock) {
auto typeName = grBlock.typeName();
typeName = std::string_view(typeName.begin(), typeName.find('<'));
auto type = BlockRegistry::instance().get(typeName);
auto typeName = grBlock.typeName();
typeName = std::string_view(typeName.begin(), typeName.find('<'));
const BlockDefinition* type = BlockRegistry::instance().get(typeName);
if (!type) {
auto msg = fmt::format("Block type '{}' is unknown.", typeName);
components::Notification::error(msg);
throw std::runtime_error(msg);
throw gr::exception(msg);
}

auto block = type->createBlock(grBlock.name());
block->m_uniqueName = grBlock.uniqueName();
block->m_metaInformation = grBlock.metaInformation();
block->updateSettings(grBlock.settings().get());
block->updateSettings(grBlock.settings().get(), grBlock.settings().getStoredAll());
addBlock(std::move(block));
});

Expand All @@ -358,6 +379,9 @@ void FlowGraph::parse(const std::string& str) {
if (definition.topLevel >= ports.size()) {
auto msg = fmt::format("Cannot connect, index {} is not valid (only {} ports available)", definition.topLevel, ports.size());
components::Notification::error(msg);
#ifndef NDEBUG
throw std::runtime_error(msg);
#endif
}
// TODO check subIndex once we support port collections
return std::pair{ports.begin() + definition.topLevel, definition.subIndex};
Expand Down Expand Up @@ -507,10 +531,15 @@ Connection* FlowGraph::connect(Block::Port* a, Block::Port* b) {
std::swap(a, b);
}

auto ain = std::size_t(a - a->owningUiBlock->outputs().data());
auto bin = std::size_t(b - b->owningUiBlock->inputs().data());
const auto ain = std::size_t(a - a->owningUiBlock->outputs().data());
const auto bin = std::size_t(b - b->owningUiBlock->inputs().data());

fmt::print("connect {}.{} to {}.{}\n", a->owningUiBlock->name, ain, b->owningUiBlock->name, bin);
if (a->rawPortType != b->rawPortType) {
fmt::println("incompatible block connection: {}.{}({}) to {}.{}({})", //
a->owningUiBlock->name, ain, a->rawPortType, b->owningUiBlock->name, bin, b->rawPortType);
} else {
fmt::println("connect {}.{}({}) to {}.{}({})", a->owningUiBlock->name, ain, a->rawPortType, b->owningUiBlock->name, bin, b->rawPortType);
}

auto it = m_connections.insert(Connection(a->owningUiBlock, ain, b->owningUiBlock, bin));
a->portConnections.push_back(&(*it));
Expand Down Expand Up @@ -557,6 +586,13 @@ static std::unique_ptr<gr::BlockModel> createGRBlock(gr::PluginLoader& loader, c
}

grBlock->settings().set(params);
// using StoredSettingsType = std::map<pmtv::pmt, std::vector<std::pair<gr::SettingsCtx, gr::property_map>>, gr::settings::PMTCompare>;
for (const auto& [_, vec] : block.storedSettings()) {
for (const auto& [ctx, map] : vec) {
std::ignore = grBlock->settings().set(map, ctx);
}
}

grBlock->settings().applyStagedParameters();
return grBlock;
}
Expand Down
44 changes: 33 additions & 11 deletions src/ui/Flowgraph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ struct DataType {
Float32,
DataSetFloat32,
DataSetFloat64,
UInt64,
UInt32,
UInt16,
UInt8,
Int64,
Int32,
Int16,
Expand Down Expand Up @@ -143,6 +147,7 @@ struct DataType {
}

constexpr inline DataType() {}

constexpr inline DataType(Id id) : m_id(id) {}

const std::string& toString() const;
Expand Down Expand Up @@ -171,14 +176,18 @@ class BlockInstantiationDefinition {

std::string defaultValue;
};

template<typename T>
struct NumberParameter {
inline explicit NumberParameter(T v) : defaultValue(v) {}

T defaultValue;
};

struct StringParameter {
std::string defaultValue;
};

struct Parameter {
std::string id;
std::string label;
Expand All @@ -192,12 +201,15 @@ class BlockInstantiationDefinition {
auto data_inputs() {
return inputs | std::views::filter([](const PortDefinition& p) { return p.type != "message"; });
}

auto message_inputs() {
return inputs | std::views::filter([](const PortDefinition& p) { return p.type == "message"; });
}

auto data_outputs() {
return outputs | std::views::filter([](const PortDefinition& p) { return p.type != "message"; });
}

auto message_outputs() {
return outputs | std::views::filter([](const PortDefinition& p) { return p.type == "message"; });
}
Expand Down Expand Up @@ -256,21 +268,23 @@ struct BlockRegistry {

class Block {
public:
using StoredSettingsType = std::map<pmtv::pmt, std::vector<std::pair<gr::SettingsCtx, gr::property_map>>, gr::settings::PMTCompare>;

class Port {
public:
enum class Direction {
Input,
Output,
};

Block* owningUiBlock;
const std::string name;
const std::string rawPortType;
bool isDataset;
const Direction portDirection;
Block* owningUiBlock = nullptr;
const std::string name{};
const std::string rawPortType{};
bool isDataset = false;
const Direction portDirection{};

DataType portDataType;
std::vector<Connection*> portConnections;
DataType portDataType{};
std::vector<Connection*> portConnections{};
};

struct EnumParameter {
Expand All @@ -284,10 +298,12 @@ class Block {
return *this;
}
};

template<typename T>
struct NumberParameter {
T value;
};

struct RawParameter {
std::string value;
};
Expand All @@ -310,21 +326,26 @@ class Block {

const auto& inputs() const { return m_inputs; }
const auto& outputs() const { return m_outputs; }
auto dataInputs() const {

auto dataInputs() const {
return m_inputs | std::views::filter([](const Port& p) { return p.portDataType != DataType::AsyncMessage; });
}

auto dataOutputs() const {
return m_outputs | std::views::filter([](const Port& p) { return p.portDataType != DataType::AsyncMessage; });
}

auto messageInputs() const {
return m_inputs | std::views::filter([](const Port& p) { return p.portDataType == DataType::AsyncMessage; });
}

auto messageOutputs() const {
return m_outputs | std::views::filter([](const Port& p) { return p.portDataType == DataType::AsyncMessage; });
}

void setSetting(const std::string& name, const pmtv::pmt& par);
const auto& settings() const { return m_settings; }
void setSetting(const std::string& name, const pmtv::pmt& par);
const auto& settings() const { return m_settings; }
const StoredSettingsType& storedSettings() const { return _storedSettings; }

void update();

Expand All @@ -335,13 +356,14 @@ class Block {
auto& inputs() { return m_inputs; }
auto& outputs() { return m_outputs; }

void updateSettings(const gr::property_map& settings);
void updateSettings(const gr::property_map& settings, const StoredSettingsType& stagedSettings = {});
const gr::property_map& metaInformation() const { return m_metaInformation; }

protected:
std::vector<Port> m_inputs;
std::vector<Port> m_outputs;
gr::property_map m_settings;
StoredSettingsType _storedSettings{};
bool m_updated = false;
FlowGraph* m_flowGraph = nullptr;
const BlockDefinition* m_type;
Expand Down
Loading

0 comments on commit 8d39525

Please sign in to comment.