GNU Radio 3.6.5.1 C++ API
gr_basic_block.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006,2008,2009,2011 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifndef INCLUDED_GR_BASIC_BLOCK_H
24 #define INCLUDED_GR_BASIC_BLOCK_H
25 
26 #include <gr_core_api.h>
27 #include <gr_runtime_types.h>
28 #include <gr_sptr_magic.h>
29 #include <boost/enable_shared_from_this.hpp>
30 #include <boost/function.hpp>
31 #include <gr_msg_accepter.h>
32 #include <string>
33 #include <deque>
34 #include <map>
35 #include <gr_io_signature.h>
36 #include <gruel/thread.h>
37 #include <boost/foreach.hpp>
38 #include <boost/thread/condition_variable.hpp>
39 #include <iostream>
40 
41 /*!
42  * \brief The abstract base class for all signal processing blocks.
43  * \ingroup internal
44  *
45  * Basic blocks are the bare abstraction of an entity that has a name,
46  * a set of inputs and outputs, and a message queue. These are never instantiated
47  * directly; rather, this is the abstract parent class of both gr_hier_block,
48  * which is a recursive container, and gr_block, which implements actual
49  * signal processing functions.
50  */
51 
52 class GR_CORE_API gr_basic_block : public gr_msg_accepter, public boost::enable_shared_from_this<gr_basic_block>
53 {
54  typedef boost::function<void(pmt::pmt_t)> msg_handler_t;
55 
56  private:
57 
58  //msg_handler_t d_msg_handler;
59  typedef std::map<pmt::pmt_t , msg_handler_t, pmt::pmt_comperator> d_msg_handlers_t;
60  d_msg_handlers_t d_msg_handlers;
61 
62  typedef std::deque<pmt::pmt_t> msg_queue_t;
63  typedef std::map<pmt::pmt_t, msg_queue_t, pmt::pmt_comperator> msg_queue_map_t;
64  typedef std::map<pmt::pmt_t, msg_queue_t, pmt::pmt_comperator>::iterator msg_queue_map_itr;
65  std::map<pmt::pmt_t, boost::shared_ptr<boost::condition_variable>, pmt::pmt_comperator> msg_queue_ready;
66 
67  gruel::mutex mutex; //< protects all vars
68 
69  protected:
70  friend class gr_flowgraph;
71  friend class gr_flat_flowgraph; // TODO: will be redundant
72  friend class gr_tpb_thread_body;
73 
74  enum vcolor { WHITE, GREY, BLACK };
75 
76  std::string d_name;
81  std::string d_symbol_name;
82  std::string d_symbol_alias;
84  msg_queue_map_t msg_queue;
85 
86  gr_basic_block(void){} //allows pure virtual interface sub-classes
87 
88  //! Protected constructor prevents instantiation by non-derived classes
89  gr_basic_block(const std::string &name,
90  gr_io_signature_sptr input_signature,
91  gr_io_signature_sptr output_signature);
92 
93  //! may only be called during constructor
95  d_input_signature = iosig;
96  }
97 
98  //! may only be called during constructor
100  d_output_signature = iosig;
101  }
102 
103  /*!
104  * \brief Allow the flowgraph to set for sorting and partitioning
105  */
106  void set_color(vcolor color) { d_color = color; }
107  vcolor color() const { return d_color; }
108 
109  /*!
110  * \brief Tests if there is a handler attached to port \p which_port
111  */
112  bool has_msg_handler(pmt::pmt_t which_port) {
113  return (d_msg_handlers.find(which_port) != d_msg_handlers.end());
114  }
115 
116  /*
117  * This function is called by the runtime system to dispatch messages.
118  *
119  * The thread-safety guarantees mentioned in set_msg_handler are implemented
120  * by the callers of this method.
121  */
122  virtual void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg)
123  {
124  // AA Update this
125  if(has_msg_handler(which_port)) { // Is there a handler?
126  d_msg_handlers[which_port](msg); // Yes, invoke it.
127  }
128  }
129 
130  // Message passing interface
132 
133  public:
134  virtual ~gr_basic_block();
135  long unique_id() const { return d_unique_id; }
136  long symbolic_id() const { return d_symbolic_id; }
137  std::string name() const { return d_name; }
138  std::string symbol_name() const { return d_symbol_name; }
139  gr_io_signature_sptr input_signature() const { return d_input_signature; }
140  gr_io_signature_sptr output_signature() const { return d_output_signature; }
141  gr_basic_block_sptr to_basic_block(); // Needed for Python type coercion
142  bool alias_set() { return !d_symbol_alias.empty(); }
143  std::string alias(){ return alias_set()?d_symbol_alias:symbol_name(); }
144  pmt::pmt_t alias_pmt(){ return pmt::pmt_intern(alias()); }
145  void set_block_alias(std::string name);
146 
147  // ** Message passing interface **
148  void message_port_register_in(pmt::pmt_t port_id);
149  void message_port_register_out(pmt::pmt_t port_id);
150  void message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg);
151  void message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target);
152  void message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target);
153 
154  virtual bool message_port_is_hier(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier\n"; return false; }
155  virtual bool message_port_is_hier_in(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier_in\n"; return false; }
156  virtual bool message_port_is_hier_out(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier_out\n"; return false; }
157 
158  /*!
159  * \brief Get input message port names.
160  *
161  * Returns the available input message ports for a block. The
162  * return object is a PMT vector that is filled with PMT symbols.
163  */
164  pmt::pmt_t message_ports_in();
165 
166  /*!
167  * \brief Get output message port names.
168  *
169  * Returns the available output message ports for a block. The
170  * return object is a PMT vector that is filled with PMT symbols.
171  */
172  pmt::pmt_t message_ports_out();
173 
174  /*!
175  * Accept msg, place in queue, arrange for thread to be awakened if it's not already.
176  */
177  void _post(pmt::pmt_t which_port, pmt::pmt_t msg);
178 
179  //! is the queue empty?
180  //bool empty_p(const pmt::pmt_t &which_port) const { return msg_queue[which_port].empty(); }
181  bool empty_p(pmt::pmt_t which_port) {
182  if(msg_queue.find(which_port) == msg_queue.end())
183  throw std::runtime_error("port does not exist!");
184  return msg_queue[which_port].empty();
185  }
186  bool empty_p() {
187  bool rv = true;
188  BOOST_FOREACH(msg_queue_map_t::value_type &i, msg_queue) {
189  rv &= msg_queue[i.first].empty();
190  }
191  return rv;
192  }
193 
194  //! How many messages in the queue?
195  size_t nmsgs(pmt::pmt_t which_port) {
196  if(msg_queue.find(which_port) == msg_queue.end())
197  throw std::runtime_error("port does not exist!");
198  return msg_queue[which_port].size();
199  }
200 
201  //| Acquires and release the mutex
202  void insert_tail( pmt::pmt_t which_port, pmt::pmt_t msg);
203  /*!
204  * \returns returns pmt at head of queue or pmt_t() if empty.
205  */
206  pmt::pmt_t delete_head_nowait( pmt::pmt_t which_port);
207 
208  /*!
209  * \returns returns pmt at head of queue or pmt_t() if empty.
210  */
211  pmt::pmt_t delete_head_blocking( pmt::pmt_t which_port);
212 
213  msg_queue_t::iterator get_iterator(pmt::pmt_t which_port){
214  return msg_queue[which_port].begin();
215  }
216 
217  void erase_msg(pmt::pmt_t which_port, msg_queue_t::iterator it){
218  msg_queue[which_port].erase(it);
219  }
220 
221  virtual bool has_msg_port(pmt::pmt_t which_port){
222  if(msg_queue.find(which_port) != msg_queue.end()){
223  return true;
224  }
225  if(pmt::pmt_dict_has_key(message_subscribers, which_port)){
226  return true;
227  }
228  return false;
229  }
230 
231 
232  /*!
233  * \brief Confirm that ninputs and noutputs is an acceptable combination.
234  *
235  * \param ninputs number of input streams connected
236  * \param noutputs number of output streams connected
237  *
238  * \returns true if this is a valid configuration for this block.
239  *
240  * This function is called by the runtime system whenever the
241  * topology changes. Most classes do not need to override this.
242  * This check is in addition to the constraints specified by the input
243  * and output gr_io_signatures.
244  */
245  virtual bool check_topology(int ninputs, int noutputs) { (void) ninputs; (void) noutputs; return true; }
246 
247  /*!
248  * \brief Set the callback that is fired when messages are available.
249  *
250  * \p msg_handler can be any kind of function pointer or function object
251  * that has the signature:
252  * <pre>
253  * void msg_handler(pmt::pmt msg);
254  * </pre>
255  *
256  * (You may want to use boost::bind to massage your callable into the
257  * correct form. See gr_nop.{h,cc} for an example that sets up a class
258  * method as the callback.)
259  *
260  * Blocks that desire to handle messages must call this method in their
261  * constructors to register the handler that will be invoked when messages
262  * are available.
263  *
264  * If the block inherits from gr_block, the runtime system will ensure that
265  * msg_handler is called in a thread-safe manner, such that work and
266  * msg_handler will never be called concurrently. This allows msg_handler
267  * to update state variables without having to worry about thread-safety
268  * issues with work, general_work or another invocation of msg_handler.
269  *
270  * If the block inherits from gr_hier_block2, the runtime system will
271  * ensure that no reentrant calls are made to msg_handler.
272  */
273  //template <typename T> void set_msg_handler(T msg_handler){
274  // d_msg_handler = msg_handler_t(msg_handler);
275  //}
276  template <typename T> void set_msg_handler(pmt::pmt_t which_port, T msg_handler){
277  if(msg_queue.find(which_port) == msg_queue.end()){
278  throw std::runtime_error("attempt to set_msg_handler() on bad input message port!"); }
279  d_msg_handlers[which_port] = msg_handler_t(msg_handler);
280  }
281 };
282 
284 {
285  return lhs->unique_id() < rhs->unique_id();
286 }
287 
288 typedef std::vector<gr_basic_block_sptr> gr_basic_block_vector_t;
289 typedef std::vector<gr_basic_block_sptr>::iterator gr_basic_block_viter_t;
290 
292 
293 inline std::ostream &operator << (std::ostream &os, gr_basic_block_sptr basic_block)
294 {
295  os << basic_block->name() << "(" << basic_block->unique_id() << ")";
296  return os;
297 }
298 
299 #endif /* INCLUDED_GR_BASIC_BLOCK_H */