SatDump 2.0.0-alpha-520736c72
Loading...
Searching...
No Matches
flowgraph.h
1#pragma once
2
3#include "nlohmann/json.hpp"
4#include <exception>
5#include <mutex>
6#include <string>
7#include <vector>
8
10#include "core/style.h"
11#include "imgui/imgui.h"
12#include "imgui/imgui_stdlib.h"
13#include "logger.h"
14
15#include "dsp/block.h"
16
17#include "common/widgets/json_editor.h"
18
19// #include "variable_manager.h"
20
21#include "node_int.h"
22
23namespace satdump
24{
25 namespace ndsp
26 {
27 class Flowgraph
28 {
29 public:
31 {
32 std::string menuname;
33 std::function<std::shared_ptr<NodeInternal>(const Flowgraph *f)> func;
34 };
35 std::map<std::string, NodeInternalReg> node_internal_registry;
36
37 public:
38 class Node
39 {
40 friend class Flowgraph;
41
42 private:
43 Flowgraph *_f;
44
45 const int id;
46 const std::string title;
47 const std::string internal_id;
48 const std::shared_ptr<NodeInternal> internal;
49
50 bool pos_was_set = false;
51 float pos_x = 0;
52 float pos_y = 0;
53
54 bool disabled = false;
55
56 struct InOut
57 {
58 int id;
59 std::string name;
60 bool is_out;
61
62 BlockIOType type;
63
64 NLOHMANN_DEFINE_TYPE_INTRUSIVE(InOut, id, name, is_out);
65 };
66
67 std::vector<InOut> node_io;
68
69 void updateIO()
70 {
71 node_io.clear();
72 for (auto &io : internal->blk->get_inputs())
73 node_io.push_back({_f->getNewNodeIOID(&node_io), io.name, false, io.type});
74 for (auto &io : internal->blk->get_outputs())
75 node_io.push_back({_f->getNewNodeIOID(&node_io), io.name, true, io.type});
76 }
77
78 public:
79 Node(Flowgraph *f, std::string id, std::shared_ptr<NodeInternal> i) : _f(f), id(f->getNewNodeID()), internal_id(id), title(i->blk->d_id), internal(i) { updateIO(); }
80
81 Node(Flowgraph *f, nlohmann::json j, std::shared_ptr<NodeInternal> i)
82 : id(j["id"]), internal_id(j["int_id"]), title(i->blk->d_id), node_io(j["io"].get<std::vector<InOut>>()), internal(i)
83 {
84 if (j.contains("int_cfg"))
85 internal->setP(j["int_cfg"]);
86
87 pos_x = j.contains("pos_x") ? j["pos_x"].get<float>() : 0;
88 pos_y = j.contains("pos_y") ? j["pos_y"].get<float>() : 0;
89
90 if (j.contains("disabled"))
91 disabled = j["disabled"];
92 }
93
94 nlohmann::json getJSON()
95 {
96 nlohmann::json j;
97 j["id"] = id;
98 j["io"] = node_io;
99 j["int_id"] = internal_id;
100 j["int_cfg"] = internal->getP();
101 j["pos_x"] = pos_x;
102 j["pos_y"] = pos_y;
103 j["disabled"] = disabled;
104 return j;
105 }
106 };
107
108 struct Link
109 {
110 int id;
111 int start;
112 int end;
113
114 NLOHMANN_DEFINE_TYPE_INTRUSIVE(Link, id, start, end);
115 };
116
117 private:
118 std::mutex flow_mtx;
119
120 std::vector<std::shared_ptr<Node>> nodes;
121 std::vector<Link> links;
122
123 int getNewNodeID();
124 int getNewNodeIOID(std::vector<Node::InOut> *ptr = nullptr);
125 int getNewLinkID();
126
127 void renderAddMenu(std::pair<const std::string, NodeInternalReg> &opt, std::vector<std::string> cats, int pos);
128
129 public:
130 bool debug_mode = false;
131
132 public:
133 Flowgraph();
134 ~Flowgraph();
135
136 std::map<std::string, double> variables;
137
138 std::shared_ptr<Node> addNode(std::string id, std::shared_ptr<NodeInternal> i)
139 {
140 auto ptr = std::make_shared<Node>(this, id, i);
141 nodes.push_back(ptr);
142 return ptr;
143 }
144
145 void render();
146
147 nlohmann::json getJSON()
148 {
149 std::lock_guard<std::mutex> lg(flow_mtx);
150 nlohmann::json j;
151 for (auto &n : nodes)
152 j["nodes"][n->id] = n->getJSON();
153 j["links"] = links;
154 j["vars"] = variables;
155 return j;
156 }
157
158 void setJSON(nlohmann::json j)
159 {
160 std::lock_guard<std::mutex> lg(flow_mtx);
161 if (j.contains("vars"))
162 variables = j["vars"];
163
164 nodes.clear();
165 links.clear();
166
167 for (auto &n : j["nodes"].items())
168 {
169 if (n.value().contains("int_id"))
170 {
171 if (node_internal_registry.count(n.value()["int_id"]))
172 {
173 try
174 {
175 auto i = node_internal_registry[n.value()["int_id"]].func(this);
176 auto nn = std::make_shared<Node>(this, n.value(), i);
177 nodes.push_back(nn);
178 }
179 catch (std::exception &e)
180 {
181 logger->error("Error adding node with ID : " + n.value()["int_id"].get<std::string>() + ", Error : %s", e.what());
182 }
183 }
184 else
185 {
186 logger->error("Could not find node with ID : " + n.value()["int_id"].get<std::string>());
187 }
188 }
189 else
190 {
191 logger->error("Node is missing int_id!");
192 }
193 }
194
195 // Links need to be filtered in case some blocks are missing!
196 std::vector<Link> tmp_links = j["links"];
197
198 for (auto &link : tmp_links)
199 {
200 bool got_in = false, got_ou = false;
201 for (auto &n : nodes)
202 {
203 for (auto &io : n->node_io)
204 {
205 if (io.id == link.start)
206 got_in = true;
207 if (io.id == link.end)
208 got_ou = true;
209 }
210 }
211
212 if (got_in && got_ou)
213 links.push_back(link);
214 }
215
216 // Update node IOs to reflect the proper types on links
217 for (auto &n : nodes)
218 {
219 size_t ic = 0, oc = 0;
220 for (auto &io : n->node_io)
221 {
222 if (io.is_out)
223 {
224 if (n->internal->blk->get_outputs().size() > oc)
225 io.type = n->internal->blk->get_outputs()[oc].type;
226 oc++;
227 }
228 else
229 {
230 if (n->internal->blk->get_inputs().size() > ic)
231 io.type = n->internal->blk->get_inputs()[ic++].type;
232 ic++;
233 }
234 }
235 }
236 }
237
238 public:
239 bool is_running = false;
240
241 void run();
242 void stop();
243 };
244 } // namespace ndsp
245} // namespace satdump
BlockIOType
Block IO types.
Definition block.h:26