USRP Hardware Driver and USRP Manual Version: 4.3.0.0+ds1-1
UHD and USRP Manual
expert_nodes.hpp
Go to the documentation of this file.
1//
2// Copyright 2016 Ettus Research
3// Copyright 2018 Ettus Research, a National Instruments Company
4//
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
7
8#pragma once
9
10#include <uhd/config.hpp>
11#include <uhd/exception.hpp>
15#include <stdint.h>
16#include <boost/core/demangle.hpp>
17#include <functional>
18#include <iostream>
19#include <list>
20#include <memory>
21#include <mutex>
22#include <sstream>
23#include <thread>
24
25namespace uhd { namespace experts {
26
30
39{
40public:
41 typedef std::function<void(std::string)> callback_func_t;
42
43 virtual ~dag_vertex_t() {}
44
45 // Getters for basic info about the node
46 inline node_class_t get_class() const
47 {
48 return _class;
49 }
50
51 inline const std::string& get_name() const
52 {
53 return _name;
54 }
55
56 virtual const std::string& get_dtype() const = 0;
57
58 virtual std::string to_string() const = 0;
59
60 // Graph resolution specific
61 virtual bool is_dirty() const = 0;
62 virtual void mark_clean() = 0;
63 virtual void resolve() = 0;
64
65 // External callbacks
66 virtual void set_write_callback(const callback_func_t& func) = 0;
67 virtual bool has_write_callback() const = 0;
68 virtual void clear_write_callback() = 0;
69 virtual void set_read_callback(const callback_func_t& func) = 0;
70 virtual bool has_read_callback() const = 0;
71 virtual void clear_read_callback() = 0;
72
73protected:
74 dag_vertex_t(const node_class_t c, const std::string& n) : _class(c), _name(n) {}
75
76private:
77 const node_class_t _class;
78 const std::string _name;
79};
80
82{
83public:
84 // Generic implementation
85 template <typename data_t>
86 static std::string print(const data_t& val)
87 {
88 std::ostringstream os;
89 os << val;
90 return os.str();
91 }
92
93 static std::string print(const uint8_t& val)
94 {
95 std::ostringstream os;
96 os << int(val);
97 return os.str();
98 }
99
100 static std::string print(const time_spec_t time)
101 {
102 std::ostringstream os;
103 os << time.get_real_secs();
104 return os.str();
105 }
106};
107
126template <typename data_t>
128{
129public:
130 // A data_node_t instance can have a type of CLASS_DATA or CLASS_PROPERTY
131 // In general a data node is a property if it can be accessed and modified
132 // from the outside world (of experts) using read and write callbacks. We
133 // assume that if a callback mutex is passed into the data node that it will
134 // be accessed from the outside and tag the data node as a PROPERTY.
135 data_node_t(const std::string& name, std::recursive_mutex* mutex = NULL)
136 : dag_vertex_t(mutex ? CLASS_PROPERTY : CLASS_DATA, name)
137 , _callback_mutex(mutex)
138 , _data()
139 , _author(AUTHOR_NONE)
140 {
141 }
142
144 const std::string& name, const data_t& value, std::recursive_mutex* mutex = NULL)
145 : dag_vertex_t(mutex ? CLASS_PROPERTY : CLASS_DATA, name)
146 , _callback_mutex(mutex)
147 , _data(value)
148 , _author(AUTHOR_NONE)
149 {
150 }
151
152 // Basic info
153 const std::string& get_dtype() const override
154 {
155 static const std::string dtype(boost::core::demangle(typeid(data_t).name()));
156 return dtype;
157 }
158
159 std::string to_string() const override
160 {
162 }
163
165 {
166 return _author;
167 }
168
169 // Graph resolution specific
170 bool is_dirty() const override
171 {
172 return _data.is_dirty();
173 }
174
175 void mark_clean() override
176 {
177 _data.mark_clean();
178 }
179
180 void resolve() override
181 {
182 // NOP
183 }
184
185 // Data node specific setters and getters (for the framework)
186 void set(const data_t& value)
187 {
188 _data = value;
189 _author = AUTHOR_EXPERT;
190 }
191
192 const data_t& get() const
193 {
194 return _data;
195 }
196
197 // Data node specific setters and getters (for external entities)
198 void commit(const data_t& value)
199 {
200 if (_callback_mutex == NULL)
202 "node " + get_name() + " is missing the callback mutex");
203 std::lock_guard<std::recursive_mutex> lock(*_callback_mutex);
204 set(value);
205 _author = AUTHOR_USER;
206 if (is_dirty() and has_write_callback()) {
207 _wr_callback(
208 std::string(get_name())); // Put the name on the stack before calling
209 }
210 }
211
212 const data_t retrieve() const
213 {
214 if (_callback_mutex == NULL)
216 "node " + get_name() + " is missing the callback mutex");
217 std::lock_guard<std::recursive_mutex> lock(*_callback_mutex);
218 if (has_read_callback()) {
219 _rd_callback(std::string(get_name()));
220 }
221 return get();
222 }
223
224private:
225 // External callbacks
226 void set_write_callback(const callback_func_t& func) override
227 {
228 _wr_callback = func;
229 }
230
231 bool has_write_callback() const override
232 {
233 return bool(_wr_callback);
234 }
235
236 void clear_write_callback() override
237 {
238 _wr_callback = nullptr;
239 }
240
241 void set_read_callback(const callback_func_t& func) override
242 {
243 _rd_callback = func;
244 }
245
246 bool has_read_callback() const override
247 {
248 return bool(_rd_callback);
249 }
250
251 void clear_read_callback() override
252 {
253 _rd_callback = nullptr;
254 }
255
256 std::recursive_mutex* _callback_mutex;
257 callback_func_t _rd_callback;
258 callback_func_t _wr_callback;
259 dirty_tracked<data_t> _data;
260 node_author_t _author;
261};
262
272{
273public:
274 virtual ~node_retriever_t() {}
275 virtual const dag_vertex_t& lookup(const std::string& name) const = 0;
276
277private:
278 friend class data_accessor_t;
279 virtual dag_vertex_t& retrieve(const std::string& name) const = 0;
280};
281
290{
291public:
292 virtual ~data_accessor_t() {}
293
294 virtual bool is_reader() const = 0;
295 virtual bool is_writer() const = 0;
296 virtual dag_vertex_t& node() const = 0;
297
298protected:
299 data_accessor_t(const node_retriever_t& r, const std::string& n)
300 : _vertex(r.retrieve(n))
301 {
302 }
304};
305
306template <typename data_t>
308{
309public:
311
312 bool is_reader() const override
313 {
314 return _access == ACCESS_READER;
315 }
316
317 bool is_writer() const override
318 {
319 return _access == ACCESS_WRITER;
320 }
321
322 inline bool is_dirty() const
323 {
324 return _datanode->is_dirty();
325 }
326
327 inline node_class_t get_class() const
328 {
329 return _datanode->get_class();
330 }
331
333 {
334 return _datanode->get_author();
335 }
336
337protected:
339 const node_retriever_t& r, const std::string& n, const node_access_t a)
340 : data_accessor_t(r, n), _datanode(NULL), _access(a)
341 {
342 _datanode = dynamic_cast<data_node_t<data_t>*>(&node());
343 if (_datanode == NULL) {
344 throw uhd::type_error("Expected data type for node " + n + " was "
345 + boost::core::demangle(typeid(data_t).name())
346 + " but got " + node().get_dtype());
347 }
348 }
349
352
353private:
354 dag_vertex_t& node() const override
355 {
356 return _vertex;
357 }
358};
359
367template <typename data_t>
368class data_reader_t : public data_accessor_base<data_t>
369{
370public:
371 data_reader_t(const node_retriever_t& retriever, const std::string& node)
372 : data_accessor_base<data_t>(retriever, node, ACCESS_READER)
373 {
374 }
375
376 inline const data_t& get() const
377 {
379 }
380
381 inline operator const data_t&() const
382 {
383 return get();
384 }
385
386 inline bool operator==(const data_t& rhs)
387 {
388 return get() == rhs;
389 }
390
391 inline bool operator!=(const data_t& rhs)
392 {
393 return !(get() == rhs);
394 }
395
396 friend std::ostream& operator<<(std::ostream& os, const data_reader_t& reader)
397 {
398 os << reader.get();
399 return os;
400 }
401};
402
410template <typename data_t>
411class data_writer_t : public data_accessor_base<data_t>
412{
413public:
414 data_writer_t(const node_retriever_t& retriever, const std::string& node)
415 : data_accessor_base<data_t>(retriever, node, ACCESS_WRITER)
416 {
417 }
418
419 inline const data_t& get() const
420 {
422 }
423
424 inline operator const data_t&() const
425 {
426 return get();
427 }
428
429 inline bool operator==(const data_t& rhs)
430 {
431 return get() == rhs;
432 }
433
434 inline bool operator!=(const data_t& rhs)
435 {
436 return !(get() == rhs);
437 }
438
439 inline void set(const data_t& value)
440 {
442 }
443
444 inline data_writer_t<data_t>& operator=(const data_t& value)
445 {
446 set(value);
447 return *this;
448 }
449
451 {
452 set(value.get());
453 return *this;
454 }
455};
456
468{
469public:
470 worker_node_t(const std::string& name) : dag_vertex_t(CLASS_WORKER, name) {}
471
472 // Worker node specific
473 std::list<std::string> get_inputs() const
474 {
475 std::list<std::string> retval;
476 for (data_accessor_t* acc : _inputs) {
477 retval.push_back(acc->node().get_name());
478 }
479 return retval;
480 }
481
482 std::list<std::string> get_outputs() const
483 {
484 std::list<std::string> retval;
485 for (data_accessor_t* acc : _outputs) {
486 retval.push_back(acc->node().get_name());
487 }
488 return retval;
489 }
490
491protected:
492 // This function is used to bind data accessors
493 // to this worker. Accessors can be read/write
494 // and the binding will ensure proper dependency
495 // handling.
497 {
498 if (accessor.is_reader()) {
499 _inputs.push_back(&accessor);
500 } else if (accessor.is_writer()) {
501 _outputs.push_back(&accessor);
502 } else {
503 throw uhd::assertion_error("Invalid accessor type");
504 }
505 }
506
507private:
508 // Graph resolution specific
509 bool is_dirty() const override
510 {
511 bool inputs_dirty = false;
512 for (data_accessor_t* acc : _inputs) {
513 inputs_dirty |= acc->node().is_dirty();
514 }
515 return inputs_dirty;
516 }
517
518 void mark_clean() override
519 {
520 for (data_accessor_t* acc : _inputs) {
521 acc->node().mark_clean();
522 }
523 }
524
525 void resolve() override = 0;
526
527 // Basic type info
528 const std::string& get_dtype() const override
529 {
530 static const std::string dtype = "<worker>";
531 return dtype;
532 }
533
534 std::string to_string() const override
535 {
536 return "<worker>";
537 }
538
539 // Workers don't have callbacks so implement stubs
540 void set_write_callback(const callback_func_t&) override {}
541 bool has_write_callback() const override
542 {
543 return false;
544 }
545 void clear_write_callback() override {}
546 void set_read_callback(const callback_func_t&) override {}
547 bool has_read_callback() const override
548 {
549 return false;
550 }
551 void clear_read_callback() override {}
552
553 std::list<data_accessor_t*> _inputs;
554 std::list<data_accessor_t*> _outputs;
555};
556
557}} // namespace uhd::experts
Definition: expert_nodes.hpp:39
virtual bool is_dirty() const =0
virtual void set_write_callback(const callback_func_t &func)=0
dag_vertex_t(const node_class_t c, const std::string &n)
Definition: expert_nodes.hpp:74
virtual ~dag_vertex_t()
Definition: expert_nodes.hpp:43
virtual bool has_read_callback() const =0
virtual const std::string & get_dtype() const =0
virtual void mark_clean()=0
virtual bool has_write_callback() const =0
virtual void clear_read_callback()=0
virtual std::string to_string() const =0
std::function< void(std::string)> callback_func_t
Definition: expert_nodes.hpp:41
virtual void resolve()=0
virtual void set_read_callback(const callback_func_t &func)=0
virtual void clear_write_callback()=0
const std::string & get_name() const
Definition: expert_nodes.hpp:51
node_class_t get_class() const
Definition: expert_nodes.hpp:46
Definition: expert_nodes.hpp:308
bool is_reader() const override
Definition: expert_nodes.hpp:312
const node_access_t _access
Definition: expert_nodes.hpp:351
bool is_dirty() const
Definition: expert_nodes.hpp:322
node_author_t get_author() const
Definition: expert_nodes.hpp:332
~data_accessor_base() override
Definition: expert_nodes.hpp:310
bool is_writer() const override
Definition: expert_nodes.hpp:317
node_class_t get_class() const
Definition: expert_nodes.hpp:327
data_accessor_base(const node_retriever_t &r, const std::string &n, const node_access_t a)
Definition: expert_nodes.hpp:338
data_node_t< data_t > * _datanode
Definition: expert_nodes.hpp:350
Definition: expert_nodes.hpp:290
dag_vertex_t & _vertex
Definition: expert_nodes.hpp:303
virtual bool is_writer() const =0
data_accessor_t(const node_retriever_t &r, const std::string &n)
Definition: expert_nodes.hpp:299
virtual dag_vertex_t & node() const =0
virtual ~data_accessor_t()
Definition: expert_nodes.hpp:292
virtual bool is_reader() const =0
Definition: expert_nodes.hpp:82
static std::string print(const uint8_t &val)
Definition: expert_nodes.hpp:93
static std::string print(const time_spec_t time)
Definition: expert_nodes.hpp:100
static std::string print(const data_t &val)
Definition: expert_nodes.hpp:86
Definition: expert_nodes.hpp:128
data_node_t(const std::string &name, std::recursive_mutex *mutex=NULL)
Definition: expert_nodes.hpp:135
void set(const data_t &value)
Definition: expert_nodes.hpp:186
void commit(const data_t &value)
Definition: expert_nodes.hpp:198
const data_t retrieve() const
Definition: expert_nodes.hpp:212
const data_t & get() const
Definition: expert_nodes.hpp:192
void resolve() override
Definition: expert_nodes.hpp:180
node_author_t get_author() const
Definition: expert_nodes.hpp:164
std::string to_string() const override
Definition: expert_nodes.hpp:159
const std::string & get_dtype() const override
Definition: expert_nodes.hpp:153
data_node_t(const std::string &name, const data_t &value, std::recursive_mutex *mutex=NULL)
Definition: expert_nodes.hpp:143
void mark_clean() override
Definition: expert_nodes.hpp:175
bool is_dirty() const override
Definition: expert_nodes.hpp:170
Definition: expert_nodes.hpp:369
const data_t & get() const
Definition: expert_nodes.hpp:376
bool operator==(const data_t &rhs)
Definition: expert_nodes.hpp:386
data_reader_t(const node_retriever_t &retriever, const std::string &node)
Definition: expert_nodes.hpp:371
bool operator!=(const data_t &rhs)
Definition: expert_nodes.hpp:391
friend std::ostream & operator<<(std::ostream &os, const data_reader_t &reader)
Definition: expert_nodes.hpp:396
Definition: expert_nodes.hpp:412
const data_t & get() const
Definition: expert_nodes.hpp:419
data_writer_t< data_t > & operator=(const data_t &value)
Definition: expert_nodes.hpp:444
void set(const data_t &value)
Definition: expert_nodes.hpp:439
data_writer_t< data_t > & operator=(const data_writer_t< data_t > &value)
Definition: expert_nodes.hpp:450
bool operator!=(const data_t &rhs)
Definition: expert_nodes.hpp:434
bool operator==(const data_t &rhs)
Definition: expert_nodes.hpp:429
data_writer_t(const node_retriever_t &retriever, const std::string &node)
Definition: expert_nodes.hpp:414
Definition: expert_nodes.hpp:272
virtual ~node_retriever_t()
Definition: expert_nodes.hpp:274
virtual const dag_vertex_t & lookup(const std::string &name) const =0
Definition: expert_nodes.hpp:468
std::list< std::string > get_inputs() const
Definition: expert_nodes.hpp:473
worker_node_t(const std::string &name)
Definition: expert_nodes.hpp:470
std::list< std::string > get_outputs() const
Definition: expert_nodes.hpp:482
void bind_accessor(data_accessor_t &accessor)
Definition: expert_nodes.hpp:496
Definition: time_spec.hpp:31
double get_real_secs(void) const
node_author_t
Definition: expert_nodes.hpp:29
@ AUTHOR_USER
Definition: expert_nodes.hpp:29
@ AUTHOR_EXPERT
Definition: expert_nodes.hpp:29
@ AUTHOR_NONE
Definition: expert_nodes.hpp:29
node_access_t
Definition: expert_nodes.hpp:28
@ ACCESS_WRITER
Definition: expert_nodes.hpp:28
@ ACCESS_READER
Definition: expert_nodes.hpp:28
node_class_t
Definition: expert_nodes.hpp:27
@ CLASS_WORKER
Definition: expert_nodes.hpp:27
@ CLASS_DATA
Definition: expert_nodes.hpp:27
@ CLASS_PROPERTY
Definition: expert_nodes.hpp:27
Definition: build_info.hpp:12
boost::noncopyable noncopyable
Definition: noncopyable.hpp:45
Definition: exception.hpp:48
Definition: exception.hpp:96