GNU Radio 3.6.3 C++ API
gr_basic_block.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2006,2008,2009,2011 Free Software Foundation, Inc.
00004  *
00005  * This file is part of GNU Radio
00006  *
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3, or (at your option)
00010  * any later version.
00011  *
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 51 Franklin Street,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022 
00023 #ifndef INCLUDED_GR_BASIC_BLOCK_H
00024 #define INCLUDED_GR_BASIC_BLOCK_H
00025 
00026 #include <gr_core_api.h>
00027 #include <gr_runtime_types.h>
00028 #include <gr_sptr_magic.h>
00029 #include <boost/enable_shared_from_this.hpp>
00030 #include <boost/function.hpp>
00031 #include <gr_msg_accepter.h>
00032 #include <string>
00033 #include <deque>
00034 #include <map>
00035 #include <gr_io_signature.h>
00036 #include <gruel/thread.h>
00037 #include <boost/foreach.hpp>
00038 #include <boost/thread/condition_variable.hpp>
00039 #include <iostream>
00040 
00041 /*!
00042  * \brief The abstract base class for all signal processing blocks.
00043  * \ingroup internal
00044  *
00045  * Basic blocks are the bare abstraction of an entity that has a name,
00046  * a set of inputs and outputs, and a message queue.  These are never instantiated
00047  * directly; rather, this is the abstract parent class of both gr_hier_block,
00048  * which is a recursive container, and gr_block, which implements actual
00049  * signal processing functions.
00050  */
00051 
00052 class GR_CORE_API gr_basic_block : public gr_msg_accepter, public boost::enable_shared_from_this<gr_basic_block>
00053 {
00054   typedef boost::function<void(pmt::pmt_t)> msg_handler_t;
00055   
00056  private:
00057   /*
00058    * This function is called by the runtime system to dispatch messages.
00059    *
00060    * The thread-safety guarantees mentioned in set_msg_handler are implemented
00061    * by the callers of this method.
00062    */
00063   void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg)
00064   {
00065     // AA Update this
00066     if (d_msg_handlers.find(which_port) != d_msg_handlers.end()) // Is there a handler?
00067       d_msg_handlers[which_port](msg); // Yes, invoke it.
00068   };
00069   
00070   //msg_handler_t        d_msg_handler;
00071   typedef std::map<pmt::pmt_t , msg_handler_t, pmt::pmt_comperator> d_msg_handlers_t;
00072   d_msg_handlers_t d_msg_handlers;
00073   
00074   typedef std::deque<pmt::pmt_t>    msg_queue_t;
00075   typedef std::map<pmt::pmt_t, msg_queue_t, pmt::pmt_comperator>    msg_queue_map_t;
00076   typedef std::map<pmt::pmt_t, msg_queue_t, pmt::pmt_comperator>::iterator msg_queue_map_itr;
00077   std::map<pmt::pmt_t, boost::shared_ptr<boost::condition_variable>, pmt::pmt_comperator> msg_queue_ready;
00078   
00079   gruel::mutex          mutex;          //< protects all vars
00080   
00081  protected:
00082   friend class gr_flowgraph;
00083   friend class gr_flat_flowgraph; // TODO: will be redundant
00084   friend class gr_tpb_thread_body;
00085   
00086   enum vcolor { WHITE, GREY, BLACK };
00087   
00088   std::string          d_name;
00089   gr_io_signature_sptr d_input_signature;
00090   gr_io_signature_sptr d_output_signature;
00091   long                 d_unique_id;
00092   long                 d_symbolic_id;
00093   std::string          d_symbol_name;
00094   std::string          d_symbol_alias;
00095   vcolor               d_color;
00096   msg_queue_map_t msg_queue;
00097   
00098   gr_basic_block(void){} //allows pure virtual interface sub-classes
00099   
00100   //! Protected constructor prevents instantiation by non-derived classes
00101   gr_basic_block(const std::string &name,
00102                  gr_io_signature_sptr input_signature,
00103                  gr_io_signature_sptr output_signature);
00104   
00105   //! may only be called during constructor
00106   void set_input_signature(gr_io_signature_sptr iosig) {
00107     d_input_signature = iosig;
00108   }
00109   
00110   //! may only be called during constructor
00111   void set_output_signature(gr_io_signature_sptr iosig) {
00112     d_output_signature = iosig;
00113   }
00114   
00115   /*!
00116    * \brief Allow the flowgraph to set for sorting and partitioning
00117    */
00118   void set_color(vcolor color) { d_color = color; }
00119   vcolor color() const { return d_color; }
00120   
00121   // Message passing interface
00122   pmt::pmt_t message_subscribers;
00123   
00124  public:
00125   virtual ~gr_basic_block();
00126   long unique_id() const { return d_unique_id; }
00127   long symbolic_id() const { return d_symbolic_id; }
00128   std::string name() const { return d_name; }
00129   std::string symbol_name() const { return d_symbol_name; }
00130   gr_io_signature_sptr input_signature() const  { return d_input_signature; }
00131   gr_io_signature_sptr output_signature() const { return d_output_signature; }
00132   gr_basic_block_sptr to_basic_block(); // Needed for Python type coercion
00133   bool alias_set() { return !d_symbol_alias.empty(); }
00134   std::string alias(){ return alias_set()?d_symbol_alias:symbol_name(); }
00135   pmt::pmt_t alias_pmt(){ return pmt::pmt_intern(alias()); }
00136   void set_block_alias(std::string name);
00137   
00138   // ** Message passing interface **
00139   void message_port_register_in(pmt::pmt_t port_id);
00140   void message_port_register_out(pmt::pmt_t port_id);
00141   void message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg);
00142   void message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target);
00143   void message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target);
00144   
00145   virtual bool message_port_is_hier(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier\n"; return false; }
00146   virtual bool message_port_is_hier_in(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier_in\n"; return false; }
00147   virtual bool message_port_is_hier_out(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier_out\n"; return false; }
00148   
00149   /*!
00150    * \brief Get input message port names.
00151    *
00152    * Returns the available input message ports for a block. The
00153    * return object is a PMT vector that is filled with PMT symbols.
00154    */
00155   pmt::pmt_t message_ports_in();
00156   
00157   /*!
00158    * \brief Get output message port names.
00159    *
00160    * Returns the available output message ports for a block. The
00161    * return object is a PMT vector that is filled with PMT symbols.
00162    */
00163   pmt::pmt_t message_ports_out();
00164   
00165   /*!
00166    * Accept msg, place in queue, arrange for thread to be awakened if it's not already.
00167    */
00168   void _post(pmt::pmt_t which_port, pmt::pmt_t msg);
00169   
00170   //! is the queue empty?
00171   //bool empty_p(const pmt::pmt_t &which_port) const { return msg_queue[which_port].empty(); }
00172   bool empty_p(pmt::pmt_t which_port) { 
00173     if(msg_queue.find(which_port) == msg_queue.end())
00174       throw std::runtime_error("port does not exist!");
00175     return msg_queue[which_port].empty(); 
00176   }
00177   bool empty_p() { 
00178     bool rv = true;
00179     BOOST_FOREACH(msg_queue_map_t::value_type &i, msg_queue){ rv &= msg_queue[i.first].empty(); }
00180     return rv;
00181   }
00182   
00183   //| Acquires and release the mutex
00184   void insert_tail( pmt::pmt_t which_port, pmt::pmt_t msg);
00185   /*!
00186    * \returns returns pmt at head of queue or pmt_t() if empty.
00187    */
00188   pmt::pmt_t delete_head_nowait( pmt::pmt_t which_port);
00189   
00190   /*!
00191    * \returns returns pmt at head of queue or pmt_t() if empty.
00192    */
00193   pmt::pmt_t delete_head_blocking( pmt::pmt_t which_port);
00194   
00195   msg_queue_t::iterator get_iterator(pmt::pmt_t which_port){
00196     return msg_queue[which_port].begin();
00197   }
00198 
00199   void erase_msg(pmt::pmt_t which_port, msg_queue_t::iterator it){
00200     msg_queue[which_port].erase(it);
00201   }
00202   
00203   virtual bool has_msg_port(pmt::pmt_t which_port){
00204     if(msg_queue.find(which_port) != msg_queue.end()){
00205       return true;
00206     }
00207     if(pmt::pmt_dict_has_key(message_subscribers, which_port)){
00208       return true;
00209     }
00210     return false;
00211   }
00212   
00213   
00214   /*!
00215    * \brief Confirm that ninputs and noutputs is an acceptable combination.
00216    *
00217    * \param ninputs     number of input streams connected
00218    * \param noutputs    number of output streams connected
00219    *
00220    * \returns true if this is a valid configuration for this block.
00221    *
00222    * This function is called by the runtime system whenever the
00223    * topology changes.  Most classes do not need to override this.
00224    * This check is in addition to the constraints specified by the input
00225    * and output gr_io_signatures.
00226    */
00227   virtual bool check_topology(int ninputs, int noutputs) { (void) ninputs; (void) noutputs; return true; }
00228   
00229   /*!
00230    * \brief Set the callback that is fired when messages are available.
00231    *
00232    * \p msg_handler can be any kind of function pointer or function object
00233    * that has the signature:
00234    * <pre>
00235    *    void msg_handler(pmt::pmt msg);
00236    * </pre>
00237    *
00238    * (You may want to use boost::bind to massage your callable into the
00239    * correct form.  See gr_nop.{h,cc} for an example that sets up a class
00240    * method as the callback.)
00241    *
00242    * Blocks that desire to handle messages must call this method in their
00243    * constructors to register the handler that will be invoked when messages
00244    * are available.
00245    *
00246    * If the block inherits from gr_block, the runtime system will ensure that
00247    * msg_handler is called in a thread-safe manner, such that work and
00248    * msg_handler will never be called concurrently.  This allows msg_handler
00249    * to update state variables without having to worry about thread-safety
00250    * issues with work, general_work or another invocation of msg_handler.
00251    *
00252    * If the block inherits from gr_hier_block2, the runtime system will
00253    * ensure that no reentrant calls are made to msg_handler.
00254    */
00255   //template <typename T> void set_msg_handler(T msg_handler){
00256   //  d_msg_handler = msg_handler_t(msg_handler);
00257   //}
00258   template <typename T> void set_msg_handler(pmt::pmt_t which_port, T msg_handler){
00259     if(msg_queue.find(which_port) == msg_queue.end()){ 
00260       throw std::runtime_error("attempt to set_msg_handler() on bad input message port!"); }
00261     d_msg_handlers[which_port] = msg_handler_t(msg_handler);
00262   }
00263 };
00264 
00265 inline bool operator<(gr_basic_block_sptr lhs, gr_basic_block_sptr rhs)
00266 {
00267   return lhs->unique_id() < rhs->unique_id();
00268 }
00269 
00270 typedef std::vector<gr_basic_block_sptr> gr_basic_block_vector_t;
00271 typedef std::vector<gr_basic_block_sptr>::iterator gr_basic_block_viter_t;
00272 
00273 GR_CORE_API long gr_basic_block_ncurrently_allocated();
00274 
00275 inline std::ostream &operator << (std::ostream &os, gr_basic_block_sptr basic_block)
00276 {
00277   os << basic_block->name() << "(" << basic_block->unique_id() << ")";
00278   return os;
00279 }
00280 
00281 #endif /* INCLUDED_GR_BASIC_BLOCK_H */