USRP Hardware Driver and USRP Manual  Version: 4.4.0.HEAD-0-g5fac246b
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>
12 #include <uhd/types/time_spec.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 
25 namespace uhd { namespace experts {
26 
30 
39 {
40 public:
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 
73 protected:
74  dag_vertex_t(const node_class_t c, const std::string& n) : _class(c), _name(n) {}
75 
76 private:
77  const node_class_t _class;
78  const std::string _name;
79 };
80 
82 {
83 public:
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 
126 template <typename data_t>
127 class data_node_t : public dag_vertex_t
128 {
129 public:
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  {
161  return data_node_printer::print(get());
162  }
163 
164  inline node_author_t get_author() const
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)
201  throw uhd::assertion_error(
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)
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  if (has_read_callback()) {
219  _rd_callback(std::string(get_name()));
220  }
221  return get();
222  }
223 
224 private:
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 {
273 public:
274  virtual ~node_retriever_t() {}
275  virtual const dag_vertex_t& lookup(const std::string& name) const = 0;
276 
277 private:
278  friend class data_accessor_t;
279  virtual dag_vertex_t& retrieve(const std::string& name) const = 0;
280 };
281 
290 {
291 public:
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 
298 protected:
299  data_accessor_t(const node_retriever_t& r, const std::string& n)
300  : _vertex(r.retrieve(n))
301  {
302  }
304 };
305 
306 template <typename data_t>
308 {
309 public:
310  ~data_accessor_base() override {}
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 
332  inline node_author_t get_author() const
333  {
334  return _datanode->get_author();
335  }
336 
337 protected:
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 
353 private:
354  dag_vertex_t& node() const override
355  {
356  return _vertex;
357  }
358 };
359 
367 template <typename data_t>
368 class data_reader_t : public data_accessor_base<data_t>
369 {
370 public:
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 
410 template <typename data_t>
411 class data_writer_t : public data_accessor_base<data_t>
412 {
413 public:
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 {
469 public:
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 
491 protected:
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 
507 private:
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
uhd::experts::ACCESS_READER
@ ACCESS_READER
Definition: expert_nodes.hpp:28
uhd::experts::data_accessor_t::_vertex
dag_vertex_t & _vertex
Definition: expert_nodes.hpp:303
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:434
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:338
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:439
uhd::experts::dag_vertex_t::to_string
virtual std::string to_string() const =0
uhd::experts::data_node_t::data_node_t
data_node_t(const std::string &name, std::recursive_mutex *mutex=NULL)
Definition: expert_nodes.hpp:135
time_spec.hpp
uhd::experts::worker_node_t::get_inputs
std::list< std::string > get_inputs() const
Definition: expert_nodes.hpp:473
uhd::experts::data_writer_t::get
const data_t & get() const
Definition: expert_nodes.hpp:419
config.hpp
uhd::experts::node_class_t
node_class_t
Definition: expert_nodes.hpp:27
uhd::experts::dag_vertex_t::get_name
const std::string & get_name() const
Definition: expert_nodes.hpp:51
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:496
uhd::experts::data_node_t::get
const data_t & get() const
Definition: expert_nodes.hpp:192
uhd::experts::data_reader_t
Definition: expert_nodes.hpp:368
uhd::experts::worker_node_t
Definition: expert_nodes.hpp:467
uhd::experts::data_node_t::get_author
node_author_t get_author() const
Definition: expert_nodes.hpp:164
uhd::experts::data_reader_t::data_reader_t
data_reader_t(const node_retriever_t &retriever, const std::string &node)
Definition: expert_nodes.hpp:371
uhd::experts::data_node_t::is_dirty
bool is_dirty() const override
Definition: expert_nodes.hpp:170
uhd::experts::data_node_t::mark_clean
void mark_clean() override
Definition: expert_nodes.hpp:175
uhd::experts::CLASS_PROPERTY
@ CLASS_PROPERTY
Definition: expert_nodes.hpp:27
uhd::experts::AUTHOR_EXPERT
@ AUTHOR_EXPERT
Definition: expert_nodes.hpp:29
uhd::experts::data_node_t::set
void set(const data_t &value)
Definition: expert_nodes.hpp:186
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:143
uhd::experts::data_writer_t::operator=
data_writer_t< data_t > & operator=(const data_writer_t< data_t > &value)
Definition: expert_nodes.hpp:450
uhd::experts::data_node_printer::print
static std::string print(const uint8_t &val)
Definition: expert_nodes.hpp:93
uhd::experts::data_node_t::get_dtype
const std::string & get_dtype() const override
Definition: expert_nodes.hpp:153
uhd::experts::AUTHOR_NONE
@ AUTHOR_NONE
Definition: expert_nodes.hpp:29
uhd::experts::data_accessor_base::get_author
node_author_t get_author() const
Definition: expert_nodes.hpp:332
uhd::experts::data_accessor_base::is_reader
bool is_reader() const override
Definition: expert_nodes.hpp:312
uhd::experts::data_accessor_base::_access
const node_access_t _access
Definition: expert_nodes.hpp:351
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:159
uhd::experts::dag_vertex_t::get_class
node_class_t get_class() const
Definition: expert_nodes.hpp:46
uhd::experts::data_accessor_base::is_writer
bool is_writer() const override
Definition: expert_nodes.hpp:317
uhd::experts::data_reader_t::operator==
bool operator==(const data_t &rhs)
Definition: expert_nodes.hpp:386
uhd::experts::data_accessor_base::~data_accessor_base
~data_accessor_base() override
Definition: expert_nodes.hpp:310
uhd::experts::data_accessor_base::is_dirty
bool is_dirty() const
Definition: expert_nodes.hpp:322
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:86
uhd::experts::node_retriever_t::~node_retriever_t
virtual ~node_retriever_t()
Definition: expert_nodes.hpp:274
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:292
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:29
uhd::experts::data_accessor_base::get_class
node_class_t get_class() const
Definition: expert_nodes.hpp:327
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::retrieve
const data_t retrieve() const
Definition: expert_nodes.hpp:212
uhd::experts::data_node_t
Definition: expert_nodes.hpp:127
uhd::experts::data_reader_t::operator!=
bool operator!=(const data_t &rhs)
Definition: expert_nodes.hpp:391
uhd::experts::data_accessor_t::data_accessor_t
data_accessor_t(const node_retriever_t &r, const std::string &n)
Definition: expert_nodes.hpp:299
uhd::experts::worker_node_t::get_outputs
std::list< std::string > get_outputs() const
Definition: expert_nodes.hpp:482
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:470
uhd::experts::data_node_t::commit
void commit(const data_t &value)
Definition: expert_nodes.hpp:198
uhd::experts::node_access_t
node_access_t
Definition: expert_nodes.hpp:28
dirty_tracked.hpp
uhd::experts::node_retriever_t
Definition: expert_nodes.hpp:271
uhd::type_error
Definition: exception.hpp:95
uhd::experts::data_node_t::resolve
void resolve() override
Definition: expert_nodes.hpp:180
uhd::experts::data_accessor_t
Definition: expert_nodes.hpp:289
exception.hpp
uhd::experts::data_reader_t::get
const data_t & get() const
Definition: expert_nodes.hpp:376
uhd::experts::data_reader_t::operator<<
friend std::ostream & operator<<(std::ostream &os, const data_reader_t &reader)
Definition: expert_nodes.hpp:396
uhd::experts::CLASS_DATA
@ CLASS_DATA
Definition: expert_nodes.hpp:27
uhd::experts::node_author_t
node_author_t
Definition: expert_nodes.hpp:29
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:414
uhd::experts::data_node_printer::print
static std::string print(const time_spec_t time)
Definition: expert_nodes.hpp:100
uhd::experts::dag_vertex_t::~dag_vertex_t
virtual ~dag_vertex_t()
Definition: expert_nodes.hpp:43
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:41
uhd::experts::data_writer_t
Definition: expert_nodes.hpp:411
uhd::experts::dag_vertex_t
Definition: expert_nodes.hpp:38
uhd::noncopyable
boost::noncopyable noncopyable
Definition: noncopyable.hpp:45
uhd::experts::data_accessor_base
Definition: expert_nodes.hpp:307
uhd::experts::dag_vertex_t::clear_read_callback
virtual void clear_read_callback()=0
uhd::experts::CLASS_WORKER
@ CLASS_WORKER
Definition: expert_nodes.hpp:27
uhd::experts::ACCESS_WRITER
@ ACCESS_WRITER
Definition: expert_nodes.hpp:28
uhd::experts::data_writer_t::operator==
bool operator==(const data_t &rhs)
Definition: expert_nodes.hpp:429
uhd::experts::data_writer_t::operator=
data_writer_t< data_t > & operator=(const data_t &value)
Definition: expert_nodes.hpp:444
uhd::experts::data_accessor_t::is_writer
virtual bool is_writer() const =0
uhd::experts::data_node_printer
Definition: expert_nodes.hpp:81
uhd::experts::data_accessor_base::_datanode
data_node_t< data_t > * _datanode
Definition: expert_nodes.hpp:350
uhd::experts::dag_vertex_t::dag_vertex_t
dag_vertex_t(const node_class_t c, const std::string &n)
Definition: expert_nodes.hpp:74