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