Loading...
Searching...
No Matches
expert_nodes.hpp
Go to the documentation of this file.
//
// Copyright 2016 Ettus Research
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#pragma once
#include <uhd/config.hpp>
#include <uhd/exception.hpp>
#include <uhd/types/device_addr.hpp>
#include <uhd/types/time_spec.hpp>
#include <uhd/utils/dirty_tracked.hpp>
#include <uhd/utils/noncopyable.hpp>
#include <stdint.h>
#include <boost/core/demangle.hpp>
#include <functional>
#include <iostream>
#include <list>
#include <memory>
#include <mutex>
#include <sstream>
#include <thread>
namespace uhd { namespace experts {
enum node_class_t { CLASS_WORKER, CLASS_DATA, CLASS_PROPERTY };
enum node_access_t { ACCESS_READER, ACCESS_WRITER };
enum node_author_t { AUTHOR_NONE, AUTHOR_USER, AUTHOR_EXPERT };
class dag_vertex_t : private uhd::noncopyable
{
public:
typedef std::function<void(std::string)> callback_func_t;
virtual ~dag_vertex_t() {}
// Getters for basic info about the node
inline node_class_t get_class() const
{
return _class;
}
inline const std::string& get_name() const
{
return _name;
}
virtual const std::string& get_dtype() const = 0;
virtual std::string to_string() const = 0;
// Graph resolution specific
virtual bool is_dirty() const = 0;
virtual void mark_clean() = 0;
virtual void force_dirty() = 0;
virtual void resolve() = 0;
// External callbacks
virtual void set_write_callback(const callback_func_t& func) = 0;
virtual bool has_write_callback() const = 0;
virtual void clear_write_callback() = 0;
virtual void set_read_callback(const callback_func_t& func) = 0;
virtual bool has_read_callback() const = 0;
virtual void clear_read_callback() = 0;
protected:
dag_vertex_t(const node_class_t c, const std::string& n) : _class(c), _name(n) {}
private:
const node_class_t _class;
const std::string _name;
};
class data_node_printer
{
public:
// Generic implementation
template <typename data_t>
static std::string print(const data_t& val)
{
std::ostringstream os;
os << val;
return os.str();
}
static std::string print(const uint8_t& val)
{
std::ostringstream os;
os << int(val);
return os.str();
}
static std::string print(const time_spec_t time)
{
std::ostringstream os;
os << time.get_real_secs();
return os.str();
}
static std::string print(const device_addr_t addr)
{
std::ostringstream os;
os << addr.to_string();
return os.str();
}
};
template <typename data_t>
class data_node_t : public dag_vertex_t
{
public:
// A data_node_t instance can have a type of CLASS_DATA or CLASS_PROPERTY
// In general a data node is a property if it can be accessed and modified
// from the outside world (of experts) using read and write callbacks. We
// assume that if a callback mutex is passed into the data node that it will
// be accessed from the outside and tag the data node as a PROPERTY.
data_node_t(const std::string& name, std::recursive_mutex* mutex = NULL)
: dag_vertex_t(mutex ? CLASS_PROPERTY : CLASS_DATA, name)
, _callback_mutex(mutex)
, _data()
, _author(AUTHOR_NONE)
{
}
data_node_t(
const std::string& name, const data_t& value, std::recursive_mutex* mutex = NULL)
: dag_vertex_t(mutex ? CLASS_PROPERTY : CLASS_DATA, name)
, _callback_mutex(mutex)
, _data(value)
, _author(AUTHOR_NONE)
{
}
// Basic info
const std::string& get_dtype() const override
{
static const std::string dtype(boost::core::demangle(typeid(data_t).name()));
return dtype;
}
std::string to_string() const override
{
return data_node_printer::print(get());
}
inline node_author_t get_author() const
{
return _author;
}
// Graph resolution specific
bool is_dirty() const override
{
return _data.is_dirty();
}
void mark_clean() override
{
_data.mark_clean();
}
void force_dirty() override
{
_data.force_dirty();
}
void resolve() override
{
// NOP
}
// Data node specific setters and getters (for the framework)
void set(const data_t& value)
{
_data = value;
_author = AUTHOR_EXPERT;
}
const data_t& get() const
{
return _data;
}
// Data node specific setters and getters (for external entities)
void commit(const data_t& value)
{
if (_callback_mutex == NULL)
throw uhd::assertion_error(
"node " + get_name() + " is missing the callback mutex");
std::lock_guard<std::recursive_mutex> lock(*_callback_mutex);
set(value);
_author = AUTHOR_USER;
if (is_dirty() and has_write_callback()) {
_wr_callback(
std::string(get_name())); // Put the name on the stack before calling
}
}
data_t retrieve() const
{
if (_callback_mutex == NULL)
throw uhd::assertion_error(
"node " + get_name() + " is missing the callback mutex");
std::lock_guard<std::recursive_mutex> lock(*_callback_mutex);
if (has_read_callback()) {
_rd_callback(std::string(get_name()));
}
return get();
}
private:
// External callbacks
void set_write_callback(const callback_func_t& func) override
{
_wr_callback = func;
}
bool has_write_callback() const override
{
return bool(_wr_callback);
}
void clear_write_callback() override
{
_wr_callback = nullptr;
}
void set_read_callback(const callback_func_t& func) override
{
_rd_callback = func;
}
bool has_read_callback() const override
{
return bool(_rd_callback);
}
void clear_read_callback() override
{
_rd_callback = nullptr;
}
std::recursive_mutex* _callback_mutex;
callback_func_t _rd_callback;
callback_func_t _wr_callback;
dirty_tracked<data_t> _data;
node_author_t _author;
};
class node_retriever_t
{
public:
virtual ~node_retriever_t() {}
virtual const dag_vertex_t& lookup(const std::string& name) const = 0;
private:
friend class data_accessor_t;
virtual dag_vertex_t& retrieve(const std::string& name) const = 0;
};
class data_accessor_t
{
public:
virtual ~data_accessor_t() {}
virtual bool is_reader() const = 0;
virtual bool is_writer() const = 0;
virtual dag_vertex_t& node() const = 0;
protected:
data_accessor_t(const node_retriever_t& r, const std::string& n)
: _vertex(r.retrieve(n))
{
}
dag_vertex_t& _vertex;
};
template <typename data_t>
class data_accessor_base : public data_accessor_t
{
public:
~data_accessor_base() override {}
bool is_reader() const override
{
return _access == ACCESS_READER;
}
bool is_writer() const override
{
return _access == ACCESS_WRITER;
}
inline bool is_dirty() const
{
return _datanode->is_dirty();
}
inline node_class_t get_class() const
{
return _datanode->get_class();
}
inline node_author_t get_author() const
{
return _datanode->get_author();
}
protected:
data_accessor_base(
const node_retriever_t& r, const std::string& n, const node_access_t a)
: data_accessor_t(r, n), _datanode(NULL), _access(a)
{
_datanode = dynamic_cast<data_node_t<data_t>*>(&node());
if (_datanode == NULL) {
throw uhd::type_error("Expected data type for node " + n + " was "
+ boost::core::demangle(typeid(data_t).name())
+ " but got " + node().get_dtype());
}
}
data_node_t<data_t>* _datanode;
const node_access_t _access;
private:
dag_vertex_t& node() const override
{
return _vertex;
}
};
template <typename data_t>
class data_reader_t : public data_accessor_base<data_t>
{
public:
data_reader_t(const node_retriever_t& retriever, const std::string& node)
: data_accessor_base<data_t>(retriever, node, ACCESS_READER)
{
}
inline const data_t& get() const
{
return data_accessor_base<data_t>::_datanode->get();
}
inline operator const data_t&() const
{
return get();
}
inline bool operator==(const data_t& rhs)
{
return get() == rhs;
}
inline bool operator!=(const data_t& rhs)
{
return !(get() == rhs);
}
friend std::ostream& operator<<(std::ostream& os, const data_reader_t& reader)
{
os << reader.get();
return os;
}
};
template <typename data_t>
class data_writer_t : public data_accessor_base<data_t>
{
public:
data_writer_t(const node_retriever_t& retriever, const std::string& node)
: data_accessor_base<data_t>(retriever, node, ACCESS_WRITER)
{
}
inline const data_t& get() const
{
return data_accessor_base<data_t>::_datanode->get();
}
inline operator const data_t&() const
{
return get();
}
inline bool operator==(const data_t& rhs)
{
return get() == rhs;
}
inline bool operator!=(const data_t& rhs)
{
return !(get() == rhs);
}
inline void set(const data_t& value)
{
data_accessor_base<data_t>::_datanode->set(value);
}
inline data_writer_t<data_t>& operator=(const data_t& value)
{
set(value);
return *this;
}
inline data_writer_t<data_t>& operator=(const data_writer_t<data_t>& value)
{
set(value.get());
return *this;
}
};
class worker_node_t : public dag_vertex_t
{
public:
worker_node_t(const std::string& name) : dag_vertex_t(CLASS_WORKER, name) {}
// Worker node specific
std::list<std::string> get_inputs() const
{
std::list<std::string> retval;
for (data_accessor_t* acc : _inputs) {
retval.push_back(acc->node().get_name());
}
return retval;
}
std::list<std::string> get_outputs() const
{
std::list<std::string> retval;
for (data_accessor_t* acc : _outputs) {
retval.push_back(acc->node().get_name());
}
return retval;
}
protected:
// This function is used to bind data accessors
// to this worker. Accessors can be read/write
// and the binding will ensure proper dependency
// handling.
void bind_accessor(data_accessor_t& accessor)
{
if (accessor.is_reader()) {
_inputs.push_back(&accessor);
} else if (accessor.is_writer()) {
_outputs.push_back(&accessor);
} else {
throw uhd::assertion_error("Invalid accessor type");
}
}
private:
// Graph resolution specific
bool is_dirty() const override
{
bool inputs_dirty = false;
for (data_accessor_t* acc : _inputs) {
inputs_dirty |= acc->node().is_dirty();
}
return inputs_dirty;
}
void mark_clean() override
{
for (data_accessor_t* acc : _inputs) {
acc->node().mark_clean();
}
}
void force_dirty() override
{
for (data_accessor_t* acc : _outputs) {
acc->node().force_dirty();
}
}
void resolve() override = 0;
// Basic type info
const std::string& get_dtype() const override
{
static const std::string dtype = "<worker>";
return dtype;
}
std::string to_string() const override
{
return "<worker>";
}
// Workers don't have callbacks so implement stubs
void set_write_callback(const callback_func_t&) override {}
bool has_write_callback() const override
{
return false;
}
void clear_write_callback() override {}
void set_read_callback(const callback_func_t&) override {}
bool has_read_callback() const override
{
return false;
}
void clear_read_callback() override {}
std::list<data_accessor_t*> _inputs;
std::list<data_accessor_t*> _outputs;
};
}} // namespace uhd::experts
uhd::device_addr_t
Definition device_addr.hpp:39
uhd::device_addr_t::to_string
std::string to_string(void) const
uhd::experts::dag_vertex_t
Definition expert_nodes.hpp:40
uhd::experts::dag_vertex_t::is_dirty
virtual bool is_dirty() const =0
uhd::experts::dag_vertex_t::set_write_callback
virtual void set_write_callback(const callback_func_t &func)=0
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
uhd::experts::dag_vertex_t::~dag_vertex_t
virtual ~dag_vertex_t()
Definition expert_nodes.hpp:44
uhd::experts::dag_vertex_t::has_read_callback
virtual bool has_read_callback() const =0
uhd::experts::dag_vertex_t::get_dtype
virtual const std::string & get_dtype() const =0
uhd::experts::dag_vertex_t::mark_clean
virtual void mark_clean()=0
uhd::experts::dag_vertex_t::has_write_callback
virtual bool has_write_callback() const =0
uhd::experts::dag_vertex_t::clear_read_callback
virtual void clear_read_callback()=0
uhd::experts::dag_vertex_t::to_string
virtual std::string to_string() const =0
uhd::experts::dag_vertex_t::callback_func_t
std::function< void(std::string)> callback_func_t
Definition expert_nodes.hpp:42
uhd::experts::dag_vertex_t::force_dirty
virtual void force_dirty()=0
uhd::experts::dag_vertex_t::resolve
virtual void resolve()=0
uhd::experts::dag_vertex_t::set_read_callback
virtual void set_read_callback(const callback_func_t &func)=0
uhd::experts::dag_vertex_t::clear_write_callback
virtual void clear_write_callback()=0
uhd::experts::dag_vertex_t::get_name
const std::string & get_name() const
Definition expert_nodes.hpp:52
uhd::experts::dag_vertex_t::get_class
node_class_t get_class() const
Definition expert_nodes.hpp:47
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
uhd::experts::data_accessor_base::is_dirty
bool is_dirty() const
Definition expert_nodes.hpp:336
uhd::experts::data_accessor_base::get_author
node_author_t get_author() const
Definition expert_nodes.hpp:346
uhd::experts::data_accessor_base::~data_accessor_base
~data_accessor_base() override
Definition expert_nodes.hpp:324
uhd::experts::data_accessor_base::is_writer
bool is_writer() const override
Definition expert_nodes.hpp:331
uhd::experts::data_accessor_base::get_class
node_class_t get_class() const
Definition expert_nodes.hpp:341
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::experts::data_accessor_base::_datanode
data_node_t< data_t > * _datanode
Definition expert_nodes.hpp:364
uhd::experts::data_accessor_t
Definition expert_nodes.hpp:304
uhd::experts::data_accessor_t::_vertex
dag_vertex_t & _vertex
Definition expert_nodes.hpp:317
uhd::experts::data_accessor_t::is_writer
virtual bool is_writer() const =0
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::data_accessor_t::node
virtual dag_vertex_t & node() const =0
uhd::experts::data_accessor_t::~data_accessor_t
virtual ~data_accessor_t()
Definition expert_nodes.hpp:306
uhd::experts::data_accessor_t::is_reader
virtual bool is_reader() const =0
uhd::experts::data_node_printer
Definition expert_nodes.hpp:84
uhd::experts::data_node_printer::print
static std::string print(const uint8_t &val)
Definition expert_nodes.hpp:95
uhd::experts::data_node_printer::print
static std::string print(const device_addr_t addr)
Definition expert_nodes.hpp:109
uhd::experts::data_node_printer::print
static std::string print(const time_spec_t time)
Definition expert_nodes.hpp:102
uhd::experts::data_node_printer::print
static std::string print(const data_t &val)
Definition expert_nodes.hpp:88
uhd::experts::data_node_t
Definition expert_nodes.hpp:137
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
uhd::experts::data_node_t::set
void set(const data_t &value)
Definition expert_nodes.hpp:200
uhd::experts::data_node_t::retrieve
data_t retrieve() const
Definition expert_nodes.hpp:226
uhd::experts::data_node_t::commit
void commit(const data_t &value)
Definition expert_nodes.hpp:212
uhd::experts::data_node_t::force_dirty
void force_dirty() override
Definition expert_nodes.hpp:189
uhd::experts::data_node_t::get
const data_t & get() const
Definition expert_nodes.hpp:206
uhd::experts::data_node_t::resolve
void resolve() override
Definition expert_nodes.hpp:194
uhd::experts::data_node_t::get_author
node_author_t get_author() const
Definition expert_nodes.hpp:173
uhd::experts::data_node_t::to_string
std::string to_string() const override
Definition expert_nodes.hpp:168
uhd::experts::data_node_t::get_dtype
const std::string & get_dtype() const override
Definition expert_nodes.hpp:162
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_node_t::mark_clean
void mark_clean() override
Definition expert_nodes.hpp:184
uhd::experts::data_node_t::is_dirty
bool is_dirty() const override
Definition expert_nodes.hpp:179
uhd::experts::data_reader_t::get
const data_t & get() const
Definition expert_nodes.hpp:390
uhd::experts::data_reader_t::operator==
bool operator==(const data_t &rhs)
Definition expert_nodes.hpp:400
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_reader_t::operator!=
bool operator!=(const data_t &rhs)
Definition expert_nodes.hpp:405
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::data_writer_t::get
const data_t & get() const
Definition expert_nodes.hpp:433
uhd::experts::data_writer_t::operator=
data_writer_t< data_t > & operator=(const data_t &value)
Definition expert_nodes.hpp:458
uhd::experts::data_writer_t::set
void set(const data_t &value)
Definition expert_nodes.hpp:453
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_writer_t::operator!=
bool operator!=(const data_t &rhs)
Definition expert_nodes.hpp:448
uhd::experts::data_writer_t::operator==
bool operator==(const data_t &rhs)
Definition expert_nodes.hpp:443
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::node_retriever_t
Definition expert_nodes.hpp:286
uhd::experts::node_retriever_t::~node_retriever_t
virtual ~node_retriever_t()
Definition expert_nodes.hpp:288
uhd::experts::node_retriever_t::lookup
virtual const dag_vertex_t & lookup(const std::string &name) const =0
uhd::experts::node_retriever_t::data_accessor_t
friend class data_accessor_t
Definition expert_nodes.hpp:292
uhd::experts::worker_node_t::get_inputs
std::list< std::string > get_inputs() const
Definition expert_nodes.hpp:487
uhd::experts::worker_node_t::worker_node_t
worker_node_t(const std::string &name)
Definition expert_nodes.hpp:484
uhd::experts::worker_node_t::get_outputs
std::list< std::string > get_outputs() const
Definition expert_nodes.hpp:496
uhd::experts::worker_node_t::bind_accessor
void bind_accessor(data_accessor_t &accessor)
Definition expert_nodes.hpp:510
uhd::time_spec_t
Definition time_spec.hpp:31
uhd::time_spec_t::get_real_secs
double get_real_secs(void) const
config.hpp
device_addr.hpp
dirty_tracked.hpp
exception.hpp
uhd::experts
Definition expert_container.hpp:16
uhd::experts::node_author_t
node_author_t
Definition expert_nodes.hpp:30
uhd::experts::AUTHOR_USER
@ AUTHOR_USER
Definition expert_nodes.hpp:30
uhd::experts::AUTHOR_EXPERT
@ AUTHOR_EXPERT
Definition expert_nodes.hpp:30
uhd::experts::AUTHOR_NONE
@ AUTHOR_NONE
Definition expert_nodes.hpp:30
uhd::experts::node_access_t
node_access_t
Definition expert_nodes.hpp:29
uhd::experts::ACCESS_WRITER
@ ACCESS_WRITER
Definition expert_nodes.hpp:29
uhd::experts::ACCESS_READER
@ ACCESS_READER
Definition expert_nodes.hpp:29
uhd::experts::node_class_t
node_class_t
Definition expert_nodes.hpp:28
uhd::experts::CLASS_WORKER
@ CLASS_WORKER
Definition expert_nodes.hpp:28
uhd::experts::CLASS_DATA
@ CLASS_DATA
Definition expert_nodes.hpp:28
uhd::experts::CLASS_PROPERTY
@ CLASS_PROPERTY
Definition expert_nodes.hpp:28
uhd
Definition build_info.hpp:12
uhd::noncopyable
boost::noncopyable noncopyable
Definition noncopyable.hpp:45
noncopyable.hpp
uhd::assertion_error
Definition exception.hpp:48
uhd::type_error
Definition exception.hpp:96
time_spec.hpp