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