GNU Radio 3.6.5 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   //msg_handler_t        d_msg_handler;
00059   typedef std::map<pmt::pmt_t , msg_handler_t, pmt::pmt_comperator> d_msg_handlers_t;
00060   d_msg_handlers_t d_msg_handlers;
00061   
00062   typedef std::deque<pmt::pmt_t>    msg_queue_t;
00063   typedef std::map<pmt::pmt_t, msg_queue_t, pmt::pmt_comperator>    msg_queue_map_t;
00064   typedef std::map<pmt::pmt_t, msg_queue_t, pmt::pmt_comperator>::iterator msg_queue_map_itr;
00065   std::map<pmt::pmt_t, boost::shared_ptr<boost::condition_variable>, pmt::pmt_comperator> msg_queue_ready;
00066   
00067   gruel::mutex          mutex;          //< protects all vars
00068   
00069  protected:
00070   friend class gr_flowgraph;
00071   friend class gr_flat_flowgraph; // TODO: will be redundant
00072   friend class gr_tpb_thread_body;
00073   
00074   enum vcolor { WHITE, GREY, BLACK };
00075   
00076   std::string          d_name;
00077   gr_io_signature_sptr d_input_signature;
00078   gr_io_signature_sptr d_output_signature;
00079   long                 d_unique_id;
00080   long                 d_symbolic_id;
00081   std::string          d_symbol_name;
00082   std::string          d_symbol_alias;
00083   vcolor               d_color;
00084   msg_queue_map_t msg_queue;
00085   
00086   gr_basic_block(void){} //allows pure virtual interface sub-classes
00087   
00088   //! Protected constructor prevents instantiation by non-derived classes
00089   gr_basic_block(const std::string &name,
00090                  gr_io_signature_sptr input_signature,
00091                  gr_io_signature_sptr output_signature);
00092   
00093   //! may only be called during constructor
00094   void set_input_signature(gr_io_signature_sptr iosig) {
00095     d_input_signature = iosig;
00096   }
00097   
00098   //! may only be called during constructor
00099   void set_output_signature(gr_io_signature_sptr iosig) {
00100     d_output_signature = iosig;
00101   }
00102   
00103   /*!
00104    * \brief Allow the flowgraph to set for sorting and partitioning
00105    */
00106   void set_color(vcolor color) { d_color = color; }
00107   vcolor color() const { return d_color; }
00108 
00109   /*!
00110    * \brief Tests if there is a handler attached to port \p which_port
00111    */
00112    bool has_msg_handler(pmt::pmt_t which_port) {
00113      return (d_msg_handlers.find(which_port) != d_msg_handlers.end());
00114    }
00115 
00116   /*
00117    * This function is called by the runtime system to dispatch messages.
00118    *
00119    * The thread-safety guarantees mentioned in set_msg_handler are implemented
00120    * by the callers of this method.
00121    */
00122   virtual void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg)
00123   {
00124     // AA Update this
00125     if(has_msg_handler(which_port)) {  // Is there a handler?
00126       d_msg_handlers[which_port](msg); // Yes, invoke it.
00127     }
00128   }
00129   
00130   // Message passing interface
00131   pmt::pmt_t message_subscribers;
00132   
00133  public:
00134   virtual ~gr_basic_block();
00135   long unique_id() const { return d_unique_id; }
00136   long symbolic_id() const { return d_symbolic_id; }
00137   std::string name() const { return d_name; }
00138   std::string symbol_name() const { return d_symbol_name; }
00139   gr_io_signature_sptr input_signature() const  { return d_input_signature; }
00140   gr_io_signature_sptr output_signature() const { return d_output_signature; }
00141   gr_basic_block_sptr to_basic_block(); // Needed for Python type coercion
00142   bool alias_set() { return !d_symbol_alias.empty(); }
00143   std::string alias(){ return alias_set()?d_symbol_alias:symbol_name(); }
00144   pmt::pmt_t alias_pmt(){ return pmt::pmt_intern(alias()); }
00145   void set_block_alias(std::string name);
00146   
00147   // ** Message passing interface **
00148   void message_port_register_in(pmt::pmt_t port_id);
00149   void message_port_register_out(pmt::pmt_t port_id);
00150   void message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg);
00151   void message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target);
00152   void message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target);
00153   
00154   virtual bool message_port_is_hier(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier\n"; return false; }
00155   virtual bool message_port_is_hier_in(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier_in\n"; return false; }
00156   virtual bool message_port_is_hier_out(pmt::pmt_t port_id) { (void) port_id; std::cout << "is_hier_out\n"; return false; }
00157   
00158   /*!
00159    * \brief Get input message port names.
00160    *
00161    * Returns the available input message ports for a block. The
00162    * return object is a PMT vector that is filled with PMT symbols.
00163    */
00164   pmt::pmt_t message_ports_in();
00165   
00166   /*!
00167    * \brief Get output message port names.
00168    *
00169    * Returns the available output message ports for a block. The
00170    * return object is a PMT vector that is filled with PMT symbols.
00171    */
00172   pmt::pmt_t message_ports_out();
00173   
00174   /*!
00175    * Accept msg, place in queue, arrange for thread to be awakened if it's not already.
00176    */
00177   void _post(pmt::pmt_t which_port, pmt::pmt_t msg);
00178   
00179   //! is the queue empty?
00180   //bool empty_p(const pmt::pmt_t &which_port) const { return msg_queue[which_port].empty(); }
00181   bool empty_p(pmt::pmt_t which_port) { 
00182     if(msg_queue.find(which_port) == msg_queue.end())
00183       throw std::runtime_error("port does not exist!");
00184     return msg_queue[which_port].empty(); 
00185   }
00186   bool empty_p() { 
00187     bool rv = true;
00188     BOOST_FOREACH(msg_queue_map_t::value_type &i, msg_queue) {
00189       rv &= msg_queue[i.first].empty();
00190     }
00191     return rv;
00192   }
00193 
00194   //! How many messages in the queue?
00195   size_t nmsgs(pmt::pmt_t which_port) { 
00196     if(msg_queue.find(which_port) == msg_queue.end())
00197       throw std::runtime_error("port does not exist!");
00198     return msg_queue[which_port].size(); 
00199   }
00200   
00201   //| Acquires and release the mutex
00202   void insert_tail( pmt::pmt_t which_port, pmt::pmt_t msg);
00203   /*!
00204    * \returns returns pmt at head of queue or pmt_t() if empty.
00205    */
00206   pmt::pmt_t delete_head_nowait( pmt::pmt_t which_port);
00207   
00208   /*!
00209    * \returns returns pmt at head of queue or pmt_t() if empty.
00210    */
00211   pmt::pmt_t delete_head_blocking( pmt::pmt_t which_port);
00212   
00213   msg_queue_t::iterator get_iterator(pmt::pmt_t which_port){
00214     return msg_queue[which_port].begin();
00215   }
00216 
00217   void erase_msg(pmt::pmt_t which_port, msg_queue_t::iterator it){
00218     msg_queue[which_port].erase(it);
00219   }
00220   
00221   virtual bool has_msg_port(pmt::pmt_t which_port){
00222     if(msg_queue.find(which_port) != msg_queue.end()){
00223       return true;
00224     }
00225     if(pmt::pmt_dict_has_key(message_subscribers, which_port)){
00226       return true;
00227     }
00228     return false;
00229   }
00230   
00231   
00232   /*!
00233    * \brief Confirm that ninputs and noutputs is an acceptable combination.
00234    *
00235    * \param ninputs     number of input streams connected
00236    * \param noutputs    number of output streams connected
00237    *
00238    * \returns true if this is a valid configuration for this block.
00239    *
00240    * This function is called by the runtime system whenever the
00241    * topology changes.  Most classes do not need to override this.
00242    * This check is in addition to the constraints specified by the input
00243    * and output gr_io_signatures.
00244    */
00245   virtual bool check_topology(int ninputs, int noutputs) { (void) ninputs; (void) noutputs; return true; }
00246   
00247   /*!
00248    * \brief Set the callback that is fired when messages are available.
00249    *
00250    * \p msg_handler can be any kind of function pointer or function object
00251    * that has the signature:
00252    * <pre>
00253    *    void msg_handler(pmt::pmt msg);
00254    * </pre>
00255    *
00256    * (You may want to use boost::bind to massage your callable into the
00257    * correct form.  See gr_nop.{h,cc} for an example that sets up a class
00258    * method as the callback.)
00259    *
00260    * Blocks that desire to handle messages must call this method in their
00261    * constructors to register the handler that will be invoked when messages
00262    * are available.
00263    *
00264    * If the block inherits from gr_block, the runtime system will ensure that
00265    * msg_handler is called in a thread-safe manner, such that work and
00266    * msg_handler will never be called concurrently.  This allows msg_handler
00267    * to update state variables without having to worry about thread-safety
00268    * issues with work, general_work or another invocation of msg_handler.
00269    *
00270    * If the block inherits from gr_hier_block2, the runtime system will
00271    * ensure that no reentrant calls are made to msg_handler.
00272    */
00273   //template <typename T> void set_msg_handler(T msg_handler){
00274   //  d_msg_handler = msg_handler_t(msg_handler);
00275   //}
00276   template <typename T> void set_msg_handler(pmt::pmt_t which_port, T msg_handler){
00277     if(msg_queue.find(which_port) == msg_queue.end()){ 
00278       throw std::runtime_error("attempt to set_msg_handler() on bad input message port!"); }
00279     d_msg_handlers[which_port] = msg_handler_t(msg_handler);
00280   }
00281 };
00282 
00283 inline bool operator<(gr_basic_block_sptr lhs, gr_basic_block_sptr rhs)
00284 {
00285   return lhs->unique_id() < rhs->unique_id();
00286 }
00287 
00288 typedef std::vector<gr_basic_block_sptr> gr_basic_block_vector_t;
00289 typedef std::vector<gr_basic_block_sptr>::iterator gr_basic_block_viter_t;
00290 
00291 GR_CORE_API long gr_basic_block_ncurrently_allocated();
00292 
00293 inline std::ostream &operator << (std::ostream &os, gr_basic_block_sptr basic_block)
00294 {
00295   os << basic_block->name() << "(" << basic_block->unique_id() << ")";
00296   return os;
00297 }
00298 
00299 #endif /* INCLUDED_GR_BASIC_BLOCK_H */