GNU Radio Manual and C++ API Reference  3.9.4.0
The Free & Open Software Radio Ecosystem
basic_block.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006,2008,2009,2011,2013 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * SPDX-License-Identifier: GPL-3.0-or-later
8  *
9  */
10 
11 #ifndef INCLUDED_GR_BASIC_BLOCK_H
12 #define INCLUDED_GR_BASIC_BLOCK_H
13 
14 #include <gnuradio/api.h>
15 #include <gnuradio/io_signature.h>
16 #include <gnuradio/logger.h>
17 #include <gnuradio/msg_accepter.h>
18 #include <gnuradio/runtime_types.h>
19 #include <gnuradio/sptr_magic.h>
20 #include <gnuradio/thread/thread.h>
21 #include <boost/thread/condition_variable.hpp>
22 #include <deque>
23 #include <functional>
24 #include <map>
25 #include <string>
26 
28 
29 namespace gr {
30 
31 /*!
32  * \brief The abstract base class for all signal processing blocks.
33  * \ingroup internal
34  *
35  * Basic blocks are the bare abstraction of an entity that has a
36  * name, a set of inputs and outputs, and a message queue. These
37  * are never instantiated directly; rather, this is the abstract
38  * parent class of both gr_hier_block, which is a recursive
39  * container, and block, which implements actual signal
40  * processing functions.
41  */
43  public std::enable_shared_from_this<basic_block>
44 {
45  typedef std::function<void(pmt::pmt_t)> msg_handler_t;
46 
47 private:
48  typedef std::map<pmt::pmt_t, msg_handler_t, pmt::comparator> d_msg_handlers_t;
49  d_msg_handlers_t d_msg_handlers;
50 
51  typedef std::deque<pmt::pmt_t> msg_queue_t;
52  typedef std::map<pmt::pmt_t, msg_queue_t, pmt::comparator> msg_queue_map_t;
53  typedef std::map<pmt::pmt_t, msg_queue_t, pmt::comparator>::iterator
54  msg_queue_map_itr;
55 
56  gr::thread::mutex mutex; //< protects all vars
57 
58 protected:
59  friend class flowgraph;
60  friend class flat_flowgraph; // TODO: will be redundant
61  friend class tpb_thread_body;
62 
63  enum vcolor { WHITE, GREY, BLACK };
64 
65  std::string d_name;
70  std::string d_symbol_name;
71  std::string d_symbol_alias;
73  bool d_rpc_set;
74 
75  /*! Used by blocks to access the logger system.
76  */
77  gr::logger_ptr d_logger; //! Default logger
78  gr::logger_ptr d_debug_logger; //! Verbose logger
79 
80  msg_queue_map_t msg_queue;
81  std::vector<rpcbasic_sptr> d_rpc_vars; // container for all RPC variables
82 
83  basic_block(void) {} // allows pure virtual interface sub-classes
84 
85  //! Protected constructor prevents instantiation by non-derived classes
86  basic_block(const std::string& name,
87  gr::io_signature::sptr input_signature,
88  gr::io_signature::sptr output_signature);
89 
90  //! may only be called during constructor
91  void set_input_signature(gr::io_signature::sptr iosig) { d_input_signature = iosig; }
92 
93  //! may only be called during constructor
95  {
96  d_output_signature = iosig;
97  }
98 
99  /*!
100  * \brief Allow the flowgraph to set for sorting and partitioning
101  */
102  void set_color(vcolor color) { d_color = color; }
103  vcolor color() const { return d_color; }
104 
105  /*!
106  * \brief Tests if there is a handler attached to port \p which_port
107  */
108  virtual bool has_msg_handler(pmt::pmt_t which_port)
109  {
110  return (d_msg_handlers.find(which_port) != d_msg_handlers.end());
111  }
112 
113  /*
114  * This function is called by the runtime system to dispatch messages.
115  *
116  * The thread-safety guarantees mentioned in set_msg_handler are
117  * implemented by the callers of this method.
118  */
119  virtual void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg)
120  {
121  // AA Update this
122  if (has_msg_handler(which_port)) { // Is there a handler?
123  d_msg_handlers[which_port](msg); // Yes, invoke it.
124  }
125  }
126 
127  // Message passing interface
129 
130 public:
131  pmt::pmt_t message_subscribers(pmt::pmt_t port);
132  ~basic_block() override;
133  long unique_id() const { return d_unique_id; }
134  long symbolic_id() const { return d_symbolic_id; }
135 
136  /*! The name of the block */
137  std::string name() const { return d_name; }
138 
139  /*!
140  * The sybolic name of the block, which is used in the
141  * block_registry. The name is assigned by the block's constructor
142  * and never changes during the life of the block.
143  */
144  std::string symbol_name() const { return d_symbol_name; }
145  std::string identifier() const
146  {
147  return this->name() + "(" + std::to_string(this->unique_id()) + ")";
148  }
149 
150  gr::io_signature::sptr input_signature() const { return d_input_signature; }
151  gr::io_signature::sptr output_signature() const { return d_output_signature; }
152  basic_block_sptr to_basic_block(); // Needed for Python type coercion
153 
154  /*!
155  * True if the block has an alias (see set_block_alias).
156  */
157  bool alias_set() const { return !d_symbol_alias.empty(); }
158 
159  /*!
160  * Returns the block's alias as a string.
161  */
162  std::string alias() const { return alias_set() ? d_symbol_alias : symbol_name(); }
163 
164  /*!
165  * Returns the block's alias as PMT.
166  */
167  pmt::pmt_t alias_pmt() const { return pmt::intern(alias()); }
168 
169  /*!
170  * Set's a new alias for the block; also adds an entry into the
171  * block_registry to get the block using either the alias or the
172  * original symbol name.
173  */
174  void set_block_alias(std::string name);
175 
176  // ** Message passing interface **
177  void message_port_register_in(pmt::pmt_t port_id);
178  void message_port_register_out(pmt::pmt_t port_id);
179  void message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg);
180  void message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target);
181  void message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target);
182 
183  virtual bool message_port_is_hier(pmt::pmt_t port_id)
184  {
185  (void)port_id;
186  return false;
187  }
188  virtual bool message_port_is_hier_in(pmt::pmt_t port_id)
189  {
190  (void)port_id;
191  return false;
192  }
193  virtual bool message_port_is_hier_out(pmt::pmt_t port_id)
194  {
195  (void)port_id;
196  return false;
197  }
198 
199  /*!
200  * \brief Get input message port names.
201  *
202  * Returns the available input message ports for a block. The
203  * return object is a PMT vector that is filled with PMT symbols.
204  */
205  pmt::pmt_t message_ports_in();
206 
207  /*!
208  * \brief Get output message port names.
209  *
210  * Returns the available output message ports for a block. The
211  * return object is a PMT vector that is filled with PMT symbols.
212  */
213  pmt::pmt_t message_ports_out();
214 
215  /*!
216  * Accept msg, place in queue, arrange for thread to be awakened if it's not already.
217  */
218  void _post(pmt::pmt_t which_port, pmt::pmt_t msg);
219 
220  //! is the queue empty?
221  bool empty_p(pmt::pmt_t which_port)
222  {
223  if (msg_queue.find(which_port) == msg_queue.end())
224  throw std::runtime_error("port does not exist!");
225  return msg_queue[which_port].empty();
226  }
227  bool empty_p()
228  {
229  bool rv = true;
230  for (const auto& i : msg_queue) {
231  rv &= msg_queue[i.first].empty();
232  }
233  return rv;
234  }
235 
236  //! are all msg ports with handlers empty?
237  bool empty_handled_p(pmt::pmt_t which_port)
238  {
239  return (empty_p(which_port) || !has_msg_handler(which_port));
240  }
242  {
243  bool rv = true;
244  for (const auto& i : msg_queue) {
245  rv &= empty_handled_p(i.first);
246  }
247  return rv;
248  }
249 
250  //! How many messages in the queue?
251  size_t nmsgs(pmt::pmt_t which_port)
252  {
253  if (msg_queue.find(which_port) == msg_queue.end())
254  throw std::runtime_error("port does not exist!");
255  return msg_queue[which_port].size();
256  }
257 
258  //| Acquires and release the mutex
259  void insert_tail(pmt::pmt_t which_port, pmt::pmt_t msg);
260  /*!
261  * \returns returns pmt at head of queue or pmt::pmt_t() if empty.
262  */
263  pmt::pmt_t delete_head_nowait(pmt::pmt_t which_port);
264 
265  msg_queue_t::iterator get_iterator(pmt::pmt_t which_port)
266  {
267  return msg_queue[which_port].begin();
268  }
269 
270  void erase_msg(pmt::pmt_t which_port, msg_queue_t::iterator it)
271  {
272  msg_queue[which_port].erase(it);
273  }
274 
275  virtual bool has_msg_port(pmt::pmt_t which_port)
276  {
277  if (msg_queue.find(which_port) != msg_queue.end()) {
278  return true;
279  }
280  if (pmt::dict_has_key(d_message_subscribers, which_port)) {
281  return true;
282  }
283  return false;
284  }
285 
286  const msg_queue_map_t& get_msg_map(void) const { return msg_queue; }
287 
288 #ifdef GR_CTRLPORT
289  /*!
290  * \brief Add an RPC variable (get or set).
291  *
292  * Using controlport, we create new getters/setters and need to
293  * store them. Each block has a vector to do this, and these never
294  * need to be accessed again once they are registered with the RPC
295  * backend. This function takes a
296  * std::shared_sptr<rpcbasic_base> so that when the block is
297  * deleted, all RPC registered variables are cleaned up.
298  *
299  * \param s an rpcbasic_sptr of the new RPC variable register to store.
300  */
301  void add_rpc_variable(rpcbasic_sptr s) { d_rpc_vars.push_back(s); }
302 #endif /* GR_CTRLPORT */
303 
304  /*!
305  * \brief Set up the RPC registered variables.
306  *
307  * This must be overloaded by a block that wants to use
308  * controlport. This is where rpcbasic_register_{get,set} pointers
309  * are created, which then get wrapped as shared pointers
310  * (rpcbasic_sptr(...)) and stored using add_rpc_variable.
311  */
312  virtual void setup_rpc(){};
313 
314  /*!
315  * \brief Ask if this block has been registered to the RPC.
316  *
317  * We can only register a block once, so we use this to protect us
318  * from calling it multiple times.
319  */
320  bool is_rpc_set() { return d_rpc_set; }
321 
322  /*!
323  * \brief When the block is registered with the RPC, set this.
324  */
325  void rpc_set() { d_rpc_set = true; }
326 
327  /*!
328  * \brief Confirm that ninputs and noutputs is an acceptable combination.
329  *
330  * \param ninputs number of input streams connected
331  * \param noutputs number of output streams connected
332  *
333  * \returns true if this is a valid configuration for this block.
334  *
335  * This function is called by the runtime system whenever the
336  * topology changes. Most classes do not need to override this.
337  * This check is in addition to the constraints specified by the
338  * input and output gr::io_signatures.
339  */
340  virtual bool check_topology(int ninputs, int noutputs)
341  {
342  (void)ninputs;
343  (void)noutputs;
344  return true;
345  }
346 
347  /*!
348  * \brief Set the callback that is fired when messages are available.
349  *
350  * \p msg_handler can be any kind of function pointer or function object
351  * that has the signature:
352  * <pre>
353  * void msg_handler(pmt::pmt msg);
354  * </pre>
355  *
356  * (You may want to use boost::bind to massage your callable into
357  * the correct form. See gr::blocks::nop for an example that sets
358  * up a class method as the callback.)
359  *
360  * Blocks that desire to handle messages must call this method in
361  * their constructors to register the handler that will be invoked
362  * when messages are available.
363  *
364  * If the block inherits from block, the runtime system will
365  * ensure that msg_handler is called in a thread-safe manner, such
366  * that work and msg_handler will never be called concurrently.
367  * This allows msg_handler to update state variables without
368  * having to worry about thread-safety issues with work,
369  * general_work or another invocation of msg_handler.
370  *
371  * If the block inherits from hier_block2, the runtime system
372  * will ensure that no reentrant calls are made to msg_handler.
373  */
374  template <typename T>
376  {
377  if (msg_queue.find(which_port) == msg_queue.end()) {
378  throw std::runtime_error(
379  "attempt to set_msg_handler() on bad input message port!");
380  }
381  d_msg_handlers[which_port] = msg_handler_t(msg_handler);
382  }
383 
384  virtual void set_processor_affinity(const std::vector<int>& mask) = 0;
385 
386  virtual void unset_processor_affinity() = 0;
387 
388  virtual std::vector<int> processor_affinity() = 0;
389 
390  virtual void set_log_level(std::string level) = 0;
391 
392  virtual std::string log_level() = 0;
393 };
394 
395 inline bool operator<(basic_block_sptr lhs, basic_block_sptr rhs)
396 {
397  return lhs->unique_id() < rhs->unique_id();
398 }
399 
400 typedef std::vector<basic_block_sptr> basic_block_vector_t;
401 typedef std::vector<basic_block_sptr>::iterator basic_block_viter_t;
402 
404 
405 inline std::ostream& operator<<(std::ostream& os, basic_block_sptr basic_block)
406 {
407  os << basic_block->identifier();
408  return os;
409 }
410 
411 } /* namespace gr */
412 
413 #endif /* INCLUDED_GR_BASIC_BLOCK_H */
gr::basic_block::empty_p
bool empty_p()
Definition: basic_block.h:227
gr::msg_handler
abstract class of message handlers
Definition: msg_handler.h:26
gr::basic_block::dispatch_msg
virtual void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg)
Definition: basic_block.h:119
gr::basic_block::is_rpc_set
bool is_rpc_set()
Ask if this block has been registered to the RPC.
Definition: basic_block.h:320
gr::msg_accepter
Accepts messages and inserts them into a message queue, then notifies subclass gr::basic_block there ...
Definition: msg_accepter.h:24
gr::basic_block::message_port_is_hier
virtual bool message_port_is_hier(pmt::pmt_t port_id)
Definition: basic_block.h:183
gr::basic_block::d_rpc_set
bool d_rpc_set
Definition: basic_block.h:73
gr::basic_block::name
std::string name() const
Definition: basic_block.h:137
gr::basic_block::msg_queue
msg_queue_map_t msg_queue
Verbose logger.
Definition: basic_block.h:80
gr::basic_block::set_color
void set_color(vcolor color)
Allow the flowgraph to set for sorting and partitioning.
Definition: basic_block.h:102
gr::basic_block::has_msg_handler
virtual bool has_msg_handler(pmt::pmt_t which_port)
Tests if there is a handler attached to port which_port.
Definition: basic_block.h:108
gr::basic_block::alias
std::string alias() const
Definition: basic_block.h:162
gr::basic_block::set_output_signature
void set_output_signature(gr::io_signature::sptr iosig)
may only be called during constructor
Definition: basic_block.h:94
logger.h
io_signature.h
gr::basic_block::erase_msg
void erase_msg(pmt::pmt_t which_port, msg_queue_t::iterator it)
Definition: basic_block.h:270
gr::basic_block::d_unique_id
long d_unique_id
Definition: basic_block.h:68
gr::basic_block::d_logger
gr::logger_ptr d_logger
Definition: basic_block.h:77
gr::basic_block::set_input_signature
void set_input_signature(gr::io_signature::sptr iosig)
may only be called during constructor
Definition: basic_block.h:91
gr::basic_block::setup_rpc
virtual void setup_rpc()
Set up the RPC registered variables.
Definition: basic_block.h:312
gr::basic_block::d_symbol_alias
std::string d_symbol_alias
Definition: basic_block.h:71
gr::basic_block::get_msg_map
const msg_queue_map_t & get_msg_map(void) const
Definition: basic_block.h:286
gr::flowgraph
Class representing a directed, acyclic graph of basic blocks.
Definition: flowgraph.h:150
gr::basic_block::symbolic_id
long symbolic_id() const
Definition: basic_block.h:134
runtime_types.h
gr::basic_block::vcolor
vcolor
Definition: basic_block.h:63
gr::basic_block::message_port_is_hier_out
virtual bool message_port_is_hier_out(pmt::pmt_t port_id)
Definition: basic_block.h:193
gr::basic_block::d_symbol_name
std::string d_symbol_name
Definition: basic_block.h:70
gr::basic_block::d_name
std::string d_name
Definition: basic_block.h:65
gr::basic_block::empty_p
bool empty_p(pmt::pmt_t which_port)
is the queue empty?
Definition: basic_block.h:221
pmt::dict_has_key
PMT_API bool dict_has_key(const pmt_t &dict, const pmt_t &key)
Return true if key exists in dict.
gr::basic_block::symbol_name
std::string symbol_name() const
Definition: basic_block.h:144
gr::basic_block::alias_pmt
pmt::pmt_t alias_pmt() const
Definition: basic_block.h:167
gr::basic_block::rpc_set
void rpc_set()
When the block is registered with the RPC, set this.
Definition: basic_block.h:325
GR_RUNTIME_API
#define GR_RUNTIME_API
Definition: gnuradio-runtime/include/gnuradio/api.h:18
gr::basic_block::empty_handled_p
bool empty_handled_p(pmt::pmt_t which_port)
are all msg ports with handlers empty?
Definition: basic_block.h:237
gr::basic_block::has_msg_port
virtual bool has_msg_port(pmt::pmt_t which_port)
Definition: basic_block.h:275
gr::thread::mutex
boost::mutex mutex
Definition: thread.h:37
msg_accepter.h
gr::basic_block::d_symbolic_id
long d_symbolic_id
Definition: basic_block.h:69
gr::basic_block_ncurrently_allocated
GR_RUNTIME_API long basic_block_ncurrently_allocated()
gr::basic_block::WHITE
@ WHITE
Definition: basic_block.h:63
rpcregisterhelpers.h
gr::basic_block::d_input_signature
gr::io_signature::sptr d_input_signature
Definition: basic_block.h:66
gr::basic_block
The abstract base class for all signal processing blocks.
Definition: basic_block.h:42
gr::basic_block::output_signature
gr::io_signature::sptr output_signature() const
Definition: basic_block.h:151
gr::basic_block::d_color
vcolor d_color
Definition: basic_block.h:72
gr::logger_ptr
log4cpp::Category * logger_ptr
GR_LOG macros.
Definition: logger.h:60
pmt::pmt_t
std::shared_ptr< pmt_base > pmt_t
typedef for shared pointer (transparent reference counting).
Definition: pmt.h:84
gr::basic_block::d_rpc_vars
std::vector< rpcbasic_sptr > d_rpc_vars
Definition: basic_block.h:81
gr::operator<
bool operator<(basic_block_sptr lhs, basic_block_sptr rhs)
Definition: basic_block.h:395
gr::basic_block::basic_block
basic_block(void)
Definition: basic_block.h:83
api.h
gr::basic_block::color
vcolor color() const
Definition: basic_block.h:103
gr::basic_block::d_message_subscribers
pmt::pmt_t d_message_subscribers
Definition: basic_block.h:128
gr::basic_block::set_msg_handler
void set_msg_handler(pmt::pmt_t which_port, T msg_handler)
Set the callback that is fired when messages are available.
Definition: basic_block.h:375
gr::basic_block::message_port_is_hier_in
virtual bool message_port_is_hier_in(pmt::pmt_t port_id)
Definition: basic_block.h:188
gr
GNU Radio logging wrapper for log4cpp library (C++ port of log4j)
Definition: basic_block.h:29
gr::basic_block::check_topology
virtual bool check_topology(int ninputs, int noutputs)
Confirm that ninputs and noutputs is an acceptable combination.
Definition: basic_block.h:340
gr::basic_block_viter_t
std::vector< basic_block_sptr >::iterator basic_block_viter_t
Definition: basic_block.h:401
gr::basic_block::empty_handled_p
bool empty_handled_p()
Definition: basic_block.h:241
gr::io_signature::sptr
std::shared_ptr< io_signature > sptr
Definition: io_signature.h:34
gr::basic_block::nmsgs
size_t nmsgs(pmt::pmt_t which_port)
How many messages in the queue?
Definition: basic_block.h:251
gr::basic_block::identifier
std::string identifier() const
Definition: basic_block.h:145
pmt::intern
PMT_API pmt_t intern(const std::string &s)
Alias for pmt_string_to_symbol.
gr::basic_block::alias_set
bool alias_set() const
Definition: basic_block.h:157
gr::operator<<
std::ostream & operator<<(std::ostream &os, basic_block_sptr basic_block)
Definition: basic_block.h:405
gr::msg_queue
thread-safe message queue
Definition: msg_queue.h:24
thread.h
gr::basic_block_vector_t
std::vector< basic_block_sptr > basic_block_vector_t
Definition: basic_block.h:400
sptr_magic.h
gr::basic_block::get_iterator
msg_queue_t::iterator get_iterator(pmt::pmt_t which_port)
Definition: basic_block.h:265
gr::basic_block::d_output_signature
gr::io_signature::sptr d_output_signature
Definition: basic_block.h:67
gr::basic_block::d_debug_logger
gr::logger_ptr d_debug_logger
Default logger.
Definition: basic_block.h:78
gr::basic_block::input_signature
gr::io_signature::sptr input_signature() const
Definition: basic_block.h:150
gr::basic_block::unique_id
long unique_id() const
Definition: basic_block.h:133