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