Skip to content

Commit ae7d566

Browse files
iamsergioSergio Martins
authored and
Sergio Martins
committed
Add kGraphGRC message
Part of task #246 Signed-off-by: Sergio Martins <[email protected]>
1 parent dd679b0 commit ae7d566

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

core/include/gnuradio-4.0/Graph.hpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434

3535
namespace gr {
3636

37+
class Graph;
38+
std::string saveGrc(PluginLoader& loader, const gr::Graph& rootGraph);
39+
inline Graph loadGrc(PluginLoader& loader, std::string_view yamlSrc, std::source_location location = std::source_location::current());
40+
3741
namespace graph::property {
3842
inline static const char* kEmplaceBlock = "EmplaceBlock";
3943
inline static const char* kRemoveBlock = "RemoveBlock";
@@ -54,6 +58,8 @@ inline static const char* kEdgeRemoved = "EdgeRemoved";
5458
inline static const char* kGraphInspect = "GraphInspect";
5559
inline static const char* kGraphInspected = "GraphInspected";
5660

61+
inline static const char* kGraphGRC = "GraphGRC";
62+
5763
inline static const char* kRegistryBlockTypes = "RegistryBlockTypes";
5864

5965
inline static const char* kSubgraphExportPort = "SubgraphExportPort";
@@ -344,6 +350,7 @@ class Graph : public gr::Block<Graph> {
344350
propertyCallbacks[graph::property::kEmplaceEdge] = std::mem_fn(&Graph::propertyCallbackEmplaceEdge);
345351
propertyCallbacks[graph::property::kRemoveEdge] = std::mem_fn(&Graph::propertyCallbackRemoveEdge);
346352
propertyCallbacks[graph::property::kGraphInspect] = std::mem_fn(&Graph::propertyCallbackGraphInspect);
353+
propertyCallbacks[graph::property::kGraphGRC] = std::mem_fn(&Graph::propertyCallbackGraphGRC);
347354
propertyCallbacks[graph::property::kRegistryBlockTypes] = std::mem_fn(&Graph::propertyCallbackRegistryBlockTypes);
348355
}
349356

@@ -702,6 +709,25 @@ class Graph : public gr::Block<Graph> {
702709
return message;
703710
}
704711

712+
std::optional<Message> propertyCallbackGraphGRC([[maybe_unused]] std::string_view propertyName, Message message) {
713+
assert(propertyName == graph::property::kGraphGRC);
714+
715+
if (message.cmd == message::Command::Get) {
716+
message.data = property_map{{"value", gr::saveGrc(*_pluginLoader, *this)}};
717+
} else if (message.cmd == message::Command::Set) {
718+
const auto& data = message.data.value();
719+
auto yamlContent = std::get<std::string>(data.at("value"s));
720+
*this = gr::loadGrc(*_pluginLoader, yamlContent);
721+
722+
setTopologyChanged();
723+
724+
} else {
725+
throw gr::exception(fmt::format("Unexpected command type {}", message.cmd));
726+
}
727+
728+
return message;
729+
}
730+
705731
std::optional<Message> propertyCallbackRegistryBlockTypes([[maybe_unused]] std::string_view propertyName, Message message) {
706732
assert(propertyName == graph::property::kRegistryBlockTypes);
707733
message.data = property_map{{"types", _pluginLoader->knownBlocks()}};
@@ -1467,7 +1493,7 @@ inline gr::property_map saveGraphToMap(PluginLoader& loader, const gr::Graph& ro
14671493

14681494
} // namespace detail
14691495

1470-
inline gr::Graph loadGrc(PluginLoader& loader, std::string_view yamlSrc, std::source_location location = std::source_location::current()) {
1496+
inline gr::Graph loadGrc(PluginLoader& loader, std::string_view yamlSrc, std::source_location location) {
14711497
Graph resultGraph;
14721498
const auto yaml = pmtv::yaml::deserialize(yamlSrc);
14731499
if (!yaml) {

core/test/qa_GraphMessages.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#include "message_utils.hpp"
1212

13+
#include <filesystem>
14+
1315
using namespace std::chrono_literals;
1416
using namespace std::string_literals;
1517

@@ -305,6 +307,47 @@ const boost::ut::suite NonRunningGraphTests = [] {
305307
}
306308
};
307309
};
310+
311+
"GRC tests"_test = [] {
312+
gr::MsgPortOut toGraph;
313+
gr::Graph testGraph(context->loader);
314+
gr::MsgPortIn fromGraph;
315+
316+
expect(eq(ConnectionResult::SUCCESS, toGraph.connect(testGraph.msgIn)));
317+
expect(eq(ConnectionResult::SUCCESS, testGraph.msgOut.connect(fromGraph)));
318+
319+
testGraph.emplaceBlock("gr::testing::Copy<float32>", {});
320+
testGraph.emplaceBlock("gr::testing::Copy<float32>", {});
321+
322+
expect(eq(getNReplyMessages(fromGraph), 2UZ)); // consume 2 messages from emplace
323+
consumeAllReplyMessages(fromGraph);
324+
expect(eq(getNReplyMessages(fromGraph), 0UZ));
325+
326+
sendMessage<Get>(toGraph, testGraph.unique_name, graph::property::kGraphGRC, {});
327+
expect(nothrow([&] { testGraph.processScheduledMessages(); })) << "manually execute processing of messages";
328+
329+
expect(eq(getNReplyMessages(fromGraph), 1UZ));
330+
const Message reply = getAndConsumeFirstReplyMessage(fromGraph);
331+
332+
expect(reply.data.has_value()) << "Reply should contain data";
333+
if (reply.data.has_value()) {
334+
const auto& data = reply.data.value();
335+
expect(data.contains("value")) << "Reply should contain 'value' field";
336+
const auto& yaml = std::get<std::string>(data.at("value"));
337+
expect(!yaml.empty()) << "YAML string should not be empty";
338+
fmt::println("YAML content:\n{}", yaml);
339+
340+
// verify well formed by loading from yaml
341+
auto graphFromYaml = gr::loadGrc(context->loader, yaml);
342+
expect(eq(graphFromYaml.blocks().size(), 2UZ)) << fmt::format("Expected 2 blocks in loaded graph, got {} blocks", graphFromYaml.blocks().size());
343+
344+
"Set GRC YAML"_test = [&] {
345+
sendMessage<Set>(toGraph, testGraph.unique_name, graph::property::kGraphGRC, {{"value", yaml}});
346+
expect(nothrow([&] { testGraph.processScheduledMessages(); })) << "manually execute processing of messages";
347+
expect(eq(testGraph.blocks().size(), 2UZ)) << "Expected 2 blocks after reloading GRC";
348+
};
349+
}
350+
};
308351
};
309352

310353
const boost::ut::suite RunningGraphTests = [] {

0 commit comments

Comments
 (0)