/* -*- c++ -*- */ /* * Copyright 2012 Free Software Foundation, Inc. * * This file is part of GNU Radio * * GNU Radio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GNU Radio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifndef RPCREGISTERHELPERS_H #define RPCREGISTERHELPERS_H #include <stdio.h> #include <sstream> #include <iostream> #include <gnuradio/rpcserver_booter_base.h> #include <gnuradio/rpcmanager.h> #include <gnuradio/rpcserver_selector.h> #include <gnuradio/rpcserver_base.h> #include <gnuradio/block_registry.h> // Base classes template<typename T, typename Tto> class rpcextractor_base : public virtual gr::messages::msg_accepter { public: rpcextractor_base(T* source, void (T::*func)(Tto)) : _source(source), _func(func) {;} ~rpcextractor_base() {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { throw std::runtime_error("rpcextractor_base: no post defined for this data type.\n"); } protected: T* _source; void (T::*_func)(Tto); }; template<typename T, typename Tto> class rpcbasic_extractor : public virtual rpcextractor_base<T,Tto> { public: rpcbasic_extractor(T* source, void (T::*func)(Tto)) : rpcextractor_base<T,Tto>(source, func) {;} }; template<typename T, typename Tfrom> class rpcinserter_base : public virtual gr::messages::msg_producer { public: rpcinserter_base(T* source, Tfrom (T::*func)()) : _source(source), _func(func) {;} rpcinserter_base() {;} pmt::pmt_t retrieve() { assert(0); return pmt::pmt_t(); } protected: T* _source; Tfrom (T::*_func)(); }; template<typename T, typename Tfrom> class rpcbasic_inserter : public virtual rpcinserter_base<T,Tfrom> { public: rpcbasic_inserter(T* source, Tfrom (T::*func)()const) : rpcinserter_base<T,Tfrom>(source, func) {;} rpcbasic_inserter(T* source, Tfrom (T::*func)()) : rpcinserter_base<T,Tfrom>(source, func) {;} pmt::pmt_t retrieve() { return pmt::mp((rpcinserter_base<T,Tfrom>:: _source->*rpcinserter_base<T,Tfrom>::_func)()); } }; // Specialized Extractor Templates template<typename T> class rpcbasic_extractor<T,double> : public virtual rpcextractor_base<T,double> { public: rpcbasic_extractor(T* source, void (T::*func)(double)) : rpcextractor_base<T,double>(source, func) {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { (rpcextractor_base<T,double>::_source->*rpcextractor_base<T,double>::_func) (pmt::to_double(msg)); } }; template<typename T> class rpcbasic_extractor<T,float> : public virtual rpcextractor_base<T,float> { public: rpcbasic_extractor(T* source, void (T::*func)(float)) : rpcextractor_base<T,float>(source, func) {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { (rpcextractor_base<T,float>::_source->*rpcextractor_base<T,float>::_func) (pmt::to_double(msg)); } }; template<typename T> class rpcbasic_extractor<T,long> : public virtual rpcextractor_base<T,long> { public: rpcbasic_extractor(T* source, void (T::*func)(long)) : rpcextractor_base<T,long>(source, func) {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { (rpcextractor_base<T,long>::_source->*rpcextractor_base<T,long>::_func) (pmt::to_long(msg)); } }; template<typename T> class rpcbasic_extractor<T,int> : public virtual rpcextractor_base<T,int> { public: rpcbasic_extractor(T* source, void (T::*func)(int)) : rpcextractor_base<T,int>(source, func) {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { (rpcextractor_base<T,int>::_source->*rpcextractor_base<T,int>::_func) (pmt::to_long(msg)); } }; template<typename T> class rpcbasic_extractor<T,bool> : public virtual rpcextractor_base<T,bool> { public: rpcbasic_extractor(T* source, void (T::*func)(bool)) : rpcextractor_base<T,bool>(source, func) {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { (rpcextractor_base<T,bool>::_source->*rpcextractor_base<T,bool>::_func) (pmt::to_bool(msg)); } }; template<typename T> class rpcbasic_extractor<T,std::complex<double> > : public virtual rpcextractor_base<T,std::complex<double> > { public: rpcbasic_extractor(T* source, void (T::*func)(std::complex<double>)) : rpcextractor_base<T,std::complex<double> >(source, func) {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { (rpcextractor_base<T,std::complex<double> >:: _source->*rpcextractor_base<T,std::complex<double> >::_func)(pmt::to_complex(msg)); } }; template<typename T> class rpcbasic_extractor<T,std::string> : public virtual rpcextractor_base<T,std::string> { public: rpcbasic_extractor(T* source, void (T::*func)(std::string)) : rpcextractor_base<T,std::string>(source, func) {;} void post(pmt::pmt_t which_port, pmt::pmt_t msg) { (rpcextractor_base<T,std::string>:: _source->*rpcextractor_base<T,std::string>::_func)(pmt::symbol_to_string(msg)); } }; template<typename T> class rpcbasic_inserter<T,uint64_t> : public virtual rpcinserter_base<T,uint64_t> { public: rpcbasic_inserter(T* source, uint64_t (T::*func)() const) : rpcinserter_base<T,uint64_t>(source, func) {;} rpcbasic_inserter(T* source, uint64_t (T::*func)()) : rpcinserter_base<T,uint64_t>(source, func) {;} pmt::pmt_t retrieve() { return pmt::from_uint64((rpcinserter_base<T,uint64_t>:: _source->*rpcinserter_base<T,uint64_t>::_func)()); } }; template<typename T> class rpcbasic_inserter<T,std::vector< int > > : public virtual rpcinserter_base<T,std::vector< int > > { public: rpcbasic_inserter(T* source, std::vector<int > (T::*func)() const) : rpcinserter_base<T,std::vector<int > >(source, func) {;} rpcbasic_inserter(T* source, std::vector<int > (T::*func)()) : rpcinserter_base<T,std::vector<int > >(source, func) {;} pmt::pmt_t retrieve() { std::vector< int > vec((rpcinserter_base<T,std::vector<int > >:: _source->*rpcinserter_base<T,std::vector< int > >::_func)()); return pmt::init_s32vector(vec.size(), &vec[0]); } }; template<typename T> class rpcbasic_inserter<T,std::vector< std::complex<float> > > : public virtual rpcinserter_base<T,std::vector< std::complex<float> > > { public: rpcbasic_inserter(T* source, std::vector<std::complex<float> > (T::*func)() const) : rpcinserter_base<T,std::vector<std::complex<float> > >(source, func) {;} rpcbasic_inserter(T* source, std::vector<std::complex<float> > (T::*func)()) : rpcinserter_base<T,std::vector<std::complex<float> > >(source, func) {;} pmt::pmt_t retrieve() { std::vector< std::complex<float> > vec((rpcinserter_base<T,std::vector<std::complex<float> > >:: _source->*rpcinserter_base<T,std::vector< std::complex<float> > >::_func)()); return pmt::init_c32vector(vec.size(), &vec[0]); } }; template<typename T> class rpcbasic_inserter<T,std::vector< float> > : public virtual rpcinserter_base<T,std::vector< float > > { public: rpcbasic_inserter(T* source, std::vector<float> (T::*func)() const) : rpcinserter_base<T,std::vector<float > >(source, func) {;} rpcbasic_inserter(T* source, std::vector<float> (T::*func)()) : rpcinserter_base<T,std::vector<float> >(source, func) {;} pmt::pmt_t retrieve() { std::vector< float > vec((rpcinserter_base<T,std::vector<float> >:: _source->*rpcinserter_base<T,std::vector< float> >::_func)()); return pmt::init_f32vector(vec.size(), &vec[0]); } }; template<typename T> class rpcbasic_inserter<T,std::vector< uint8_t> > : public virtual rpcinserter_base<T,std::vector< uint8_t > > { public: rpcbasic_inserter(T* source, std::vector<uint8_t> (T::*func)() const) : rpcinserter_base<T,std::vector<uint8_t > >(source, func) {;} rpcbasic_inserter(T* source, std::vector<uint8_t> (T::*func)()) : rpcinserter_base<T,std::vector<uint8_t> >(source, func) {;} pmt::pmt_t retrieve() { std::vector< uint8_t > vec((rpcinserter_base<T,std::vector<uint8_t> >:: _source->*rpcinserter_base<T,std::vector< uint8_t> >::_func)()); return pmt::init_u8vector(vec.size(), &vec[0]); } }; template <typename T> struct rpc_register_base { rpc_register_base() {count++;} protected: static int count; }; // Base class to inherit from and create universal shared pointers. class rpcbasic_base { public: rpcbasic_base() {} virtual ~rpcbasic_base() {}; }; typedef boost::shared_ptr<rpcbasic_base> rpcbasic_sptr; template<typename T, typename Tto> struct rpcbasic_register_set : public rpcbasic_base { // Function used to add a 'set' RPC call using a basic_block's alias. rpcbasic_register_set(const std::string& block_alias, const char* functionbase, void (T::*function)(Tto), const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, DisplayType display_ = DISPNULL) { d_min = min; d_max = max; d_def = def; d_units = units_; d_desc = desc_; d_minpriv = minpriv_; d_display = display_; d_object = dynamic_cast<T*>(global_block_registry.block_lookup(pmt::intern(block_alias)).get()); #ifdef RPCSERVER_ENABLED callbackregister_base::configureCallback_t extractor(new rpcbasic_extractor<T,Tto>(d_object, function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); std::ostringstream oss(std::ostringstream::out); oss << block_alias << "::" << functionbase; d_id = oss.str(); //std::cerr << "REGISTERING SET: " << d_id << " " << desc_ << std::endl; rpcmanager::get()->i()->registerConfigureCallback(d_id, extractor); #endif } // Function used to add a 'set' RPC call using a name and the object rpcbasic_register_set(const std::string& name, const char* functionbase, T* obj, void (T::*function)(Tto), const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, DisplayType display_ = DISPNULL) { d_min = min; d_max = max; d_def = def; d_units = units_; d_desc = desc_; d_minpriv = minpriv_; d_display = display_; d_object = obj; #ifdef RPCSERVER_ENABLED callbackregister_base::configureCallback_t extractor(new rpcbasic_extractor<T,Tto>(d_object, function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); std::ostringstream oss(std::ostringstream::out); oss << name << "::" << functionbase; d_id = oss.str(); //std::cerr << "REGISTERING SET: " << d_id << " " << desc_ << std::endl; rpcmanager::get()->i()->registerConfigureCallback(d_id, extractor); #endif } ~rpcbasic_register_set() { #ifdef RPCSERVER_ENABLED rpcmanager::get()->i()->unregisterConfigureCallback(d_id); #endif } pmt::pmt_t min() const { return d_min; } pmt::pmt_t max() const { return d_max; } pmt::pmt_t def() const { return d_def; } std::string units() const { return d_units; } std::string description() const { return d_desc; } priv_lvl_t privilege_level() const { return d_minpriv; } DisplayType default_display() const { return d_display; } void set_min(pmt::pmt_t p) { d_min = p; } void set_max(pmt::pmt_t p) { d_max = p; } void set_def(pmt::pmt_t p) { d_def = p; } void units(std::string u) { d_units = u; } void description(std::string d) { d_desc = d; } void privilege_level(priv_lvl_t p) { d_minpriv = p; } void default_display(DisplayType d) { d_display = d; } private: std::string d_id; pmt::pmt_t d_min, d_max, d_def; std::string d_units, d_desc; priv_lvl_t d_minpriv; DisplayType d_display; T *d_object; }; template<typename T, typename Tfrom> class rpcbasic_register_get : public rpcbasic_base { public: // Function used to add a 'set' RPC call using a basic_block's alias. // primary constructor to allow for T get() functions rpcbasic_register_get(const std::string& block_alias, const char* functionbase, Tfrom (T::*function)(), const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, DisplayType display_ = DISPNULL) { d_min = min; d_max = max; d_def = def; d_units = units_; d_desc = desc_; d_minpriv = minpriv_; d_display = display_; d_object = dynamic_cast<T*>(global_block_registry.block_lookup(pmt::intern(block_alias)).get()); #ifdef RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); std::ostringstream oss(std::ostringstream::out); oss << block_alias << "::" << functionbase; d_id = oss.str(); //std::cerr << "REGISTERING GET: " << d_id << " " << desc_ << std::endl; rpcmanager::get()->i()->registerQueryCallback(d_id, inserter); #endif } // alternate constructor to allow for T get() const functions rpcbasic_register_get(const std::string& block_alias, const char* functionbase, Tfrom (T::*function)() const, const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, DisplayType display_ = DISPNULL) { d_min = min; d_max = max; d_def = def; d_units = units_; d_desc = desc_; d_minpriv = minpriv_; d_display = display_; d_object = dynamic_cast<T*>(global_block_registry.block_lookup(pmt::intern(block_alias)).get()); #ifdef RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, (Tfrom (T::*)())function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); std::ostringstream oss(std::ostringstream::out); oss << block_alias << "::" << functionbase; d_id = oss.str(); //std::cerr << "REGISTERING GET CONST: " << d_id << " " << desc_ << " " << display_ << std::endl; rpcmanager::get()->i()->registerQueryCallback(d_id, inserter); #endif } // Function used to add a 'set' RPC call using a name and the object // primary constructor to allow for T get() functions rpcbasic_register_get(const std::string& name, const char* functionbase, T* obj, Tfrom (T::*function)(), const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, DisplayType display_ = DISPNULL) { d_min = min; d_max = max; d_def = def; d_units = units_; d_desc = desc_; d_minpriv = minpriv_; d_display = display_; d_object = obj; #ifdef RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); std::ostringstream oss(std::ostringstream::out); oss << name << "::" << functionbase; d_id = oss.str(); //std::cerr << "REGISTERING GET: " << d_id << " " << desc_ << std::endl; rpcmanager::get()->i()->registerQueryCallback(d_id, inserter); #endif } // alternate constructor to allow for T get() const functions rpcbasic_register_get(const std::string& name, const char* functionbase, T* obj, Tfrom (T::*function)() const, const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, DisplayType display_ = DISPNULL) { d_min = min; d_max = max; d_def = def; d_units = units_; d_desc = desc_; d_minpriv = minpriv_; d_display = display_; d_object = obj; #ifdef RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, (Tfrom (T::*)())function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); std::ostringstream oss(std::ostringstream::out); oss << name << "::" << functionbase; d_id = oss.str(); //std::cerr << "REGISTERING GET CONST: " << d_id << " " << desc_ << " " << display_ << std::endl; rpcmanager::get()->i()->registerQueryCallback(d_id, inserter); #endif } ~rpcbasic_register_get() { #ifdef RPCSERVER_ENABLED rpcmanager::get()->i()->unregisterQueryCallback(d_id); #endif } pmt::pmt_t min() const { return d_min; } pmt::pmt_t max() const { return d_max; } pmt::pmt_t def() const { return d_def; } std::string units() const { return d_units; } std::string description() const { return d_desc; } priv_lvl_t privilege_level() const { return d_minpriv; } DisplayType default_display() const { return d_display; } void set_min(pmt::pmt_t p) { d_min = p; } void set_max(pmt::pmt_t p) { d_max = p; } void set_def(pmt::pmt_t p) { d_def = p; } void units(std::string u) { d_units = u; } void description(std::string d) { d_desc = d; } void privilege_level(priv_lvl_t p) { d_minpriv = p; } void default_display(DisplayType d) { d_display = d; } private: std::string d_id; pmt::pmt_t d_min, d_max, d_def; std::string d_units, d_desc; priv_lvl_t d_minpriv; DisplayType d_display; T *d_object; }; /* * This class can wrap a pre-existing variable type for you * it will define the getter and rpcregister call for you. * * It should be used for read-only getters. * */ template<typename Tfrom> class rpcbasic_register_variable : public rpcbasic_base { protected: rpcbasic_register_get< rpcbasic_register_variable<Tfrom>, Tfrom > d_rpc_reg; Tfrom *d_variable; Tfrom get() { return *d_variable; } public: // empty constructor which should never be called but needs to exist for ues in varous STL data structures void setptr(Tfrom* _variable){ rpcbasic_register_variable<Tfrom>::d_variable = _variable; } rpcbasic_register_variable() : d_rpc_reg("FAIL", "FAIL", this, &rpcbasic_register_variable::get, pmt::PMT_NIL, pmt::PMT_NIL, pmt::PMT_NIL, DISPNULL, "FAIL", "FAIL", RPC_PRIVLVL_MIN), d_variable(NULL) { throw std::runtime_error("ERROR: rpcbasic_register_variable called with no args. If this happens, someone has tried to use rpcbasic_register_variable incorrectly."); }; rpcbasic_register_variable(const std::string& namebase, const char* functionbase, Tfrom *variable, const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, DisplayType display_=DISPNULL) : d_rpc_reg(namebase, functionbase, this, &rpcbasic_register_variable::get, min, max, def, units_, desc_, minpriv_, display_), d_variable(variable) { //std::cerr << "REGISTERING VAR: " << " " << desc_ << std::endl; } }; template<typename Tfrom> class rpcbasic_register_variable_rw : public rpcbasic_register_variable<Tfrom> { private: rpcbasic_register_set< rpcbasic_register_variable_rw<Tfrom>, Tfrom > d_rpc_regset; public: // empty constructor which should never be called but needs to exist for ues in varous STL data structures rpcbasic_register_variable_rw() : d_rpc_regset("FAIL","FAIL",this,&rpcbasic_register_variable<Tfrom>::get,pmt::PMT_NIL,pmt::PMT_NIL,pmt::PMT_NIL,DISPNULL,"FAIL","FAIL",RPC_PRIVLVL_MIN) { throw std::runtime_error("ERROR: rpcbasic_register_variable_rw called with no args. if this happens someone used rpcbasic_register_variable_rw incorrectly.\n"); }; void set(Tfrom _variable){ *(rpcbasic_register_variable<Tfrom>::d_variable) = _variable; } rpcbasic_register_variable_rw( const std::string& namebase, const char* functionbase, Tfrom *variable, const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, const char* units_ = "", const char* desc_ = "", priv_lvl_t minpriv = RPC_PRIVLVL_MIN, DisplayType display_=DISPNULL) : rpcbasic_register_variable<Tfrom>(namebase,functionbase,variable,min,max,def,units_,desc_), d_rpc_regset(namebase,functionbase,this,&rpcbasic_register_variable_rw::set,min,max,def,units_,desc_,minpriv,display_) { // no action } }; #endif