GNU Radio 3.7.1 C++ API
pycallback_object.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /* 
00003  * Copyright 2012 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 #include <iostream>
00024 #include <gnuradio/rpcregisterhelpers.h>
00025 #include <gnuradio/ice_application_base.h>
00026 #include <gnuradio/IcePy_Communicator.h>
00027 #include <pythread.h>
00028 #include <boost/format.hpp>
00029 
00030 enum pyport_t {
00031   PYPORT_STRING,
00032   PYPORT_FLOAT
00033 };
00034 
00035 class Instance 
00036 {
00037 public:
00038   static boost::shared_ptr<ice_application_common> get_application()
00039   {
00040     return ice_application_common::Instance();
00041   }
00042   static Ice::CommunicatorPtr get_swig_communicator()
00043   {
00044     return get_application()->communicator();
00045   }
00046 };
00047 
00048 int pycallback_object_count = 500;
00049 
00050 // a simple to-PMT converter template class-function
00051 template <class myType> class pmt_assist
00052 {
00053 public:
00054   static pmt::pmt_t make(myType _val) 
00055   { 
00056     return pmt::mp(_val);
00057   }
00058 };
00059 
00060 /* template specializations for vectors that cant use pmt::mp() */
00061 template<>
00062 pmt::pmt_t pmt_assist<std::vector<float> >::make(std::vector<float> _val)
00063 {
00064   return pmt::init_f32vector(_val.size(), &_val[0]);
00065 }
00066 
00067 template<>
00068 pmt::pmt_t pmt_assist<std::vector<gr_complex> >::make(std::vector<gr_complex> _val)
00069 {
00070   return pmt::init_c32vector(_val.size(), &_val[0]); 
00071 }
00072 
00073 template <class myType> class pycallback_object
00074 {
00075 public:
00076   pycallback_object(std::string name, std::string functionbase,
00077                     std::string units, std::string desc,
00078                     myType min, myType max, myType deflt,
00079                     DisplayType dtype) :
00080     d_callback(NULL),
00081     d_functionbase(functionbase), d_units(units), d_desc(desc),
00082     d_min(min), d_max(max), d_deflt(deflt), d_dtype(dtype),
00083     d_name(name), d_id(pycallback_object_count++)
00084   {
00085     d_callback = NULL;
00086     setup_rpc();
00087   }
00088 
00089   void add_rpc_variable(rpcbasic_sptr s)
00090   {
00091     d_rpc_vars.push_back(s);
00092   }
00093 
00094   myType get() {
00095     myType rVal;
00096     if(d_callback == NULL) {
00097       printf("WARNING: pycallback_object get() called without py callback set!\n");
00098       return rVal;
00099     }
00100     else {
00101       // obtain  PyGIL
00102       PyGILState_STATE state = PyGILState_Ensure();
00103 
00104       PyObject *func;
00105       //PyObject *arglist;
00106       PyObject *result;
00107    
00108       func = (PyObject *) d_callback;               // Get Python function
00109       //arglist = Py_BuildValue("");             // Build argument list
00110       result = PyEval_CallObject(func,NULL);     // Call Python
00111       //result = PyEval_CallObject(func,arglist);     // Call Python
00112       //Py_DECREF(arglist);                           // Trash arglist
00113       if(result) {                                 // If no errors, return double
00114         rVal = pyCast(result);
00115       }
00116       Py_XDECREF(result);
00117 
00118       // release  PyGIL
00119       PyGILState_Release(state);
00120       return rVal;
00121     }
00122   }
00123   
00124   void set_callback(PyObject *cb)
00125   {
00126     d_callback = cb;
00127   }
00128   
00129   void setup_rpc()
00130   {
00131 #ifdef GR_CTRLPORT
00132     add_rpc_variable(
00133       rpcbasic_sptr(new rpcbasic_register_get<pycallback_object, myType>(
00134         (boost::format("%s%d") % d_name % d_id).str() , d_functionbase.c_str(),
00135     this, &pycallback_object::get, pmt_assist<myType>::make(d_min),
00136         pmt_assist<myType>::make(d_max), pmt_assist<myType>::make(d_deflt),
00137         d_units.c_str(), d_desc.c_str(), RPC_PRIVLVL_MIN, d_dtype)));
00138 #endif /* GR_CTRLPORT */
00139   }
00140 
00141 private:
00142   PyObject* d_callback;
00143   std::string d_functionbase, d_units, d_desc;
00144   myType d_min, d_max, d_deflt;
00145   DisplayType d_dtype;
00146 
00147   myType pyCast(PyObject* obj) {
00148     printf("TYPE NOT IMPLEMENTED!\n");
00149     assert(0);
00150   };
00151   std::vector<boost::any> d_rpc_vars; // container for all RPC variables
00152   std::string d_name;
00153   int d_id;
00154 
00155 };
00156 
00157 
00158 // template specialization conversion functions
00159 // get data out of the PyObject and into the real world
00160 template<> 
00161 std::string pycallback_object<std::string>::pyCast(PyObject* obj)
00162 {
00163   return std::string(PyString_AsString(obj));
00164 }
00165 
00166 template<> 
00167 double pycallback_object<double>::pyCast(PyObject* obj)
00168 {
00169   return PyFloat_AsDouble(obj);
00170 }
00171 
00172 template<> 
00173 float pycallback_object<float>::pyCast(PyObject* obj)
00174 {
00175   return (float)PyFloat_AsDouble(obj);
00176 }
00177 
00178 template<> 
00179 int pycallback_object<int>::pyCast(PyObject* obj)
00180 {
00181   return PyInt_AsLong(obj);
00182 }
00183 
00184 template<> 
00185 std::vector<float> pycallback_object<std::vector<float> >::pyCast(PyObject* obj)
00186 {
00187   int size = PyObject_Size(obj);
00188   std::vector<float> rval(size);
00189   for(int i=0; i<size; i++) {
00190     rval[i] = (float)PyFloat_AsDouble(PyList_GetItem(obj, i));
00191   }
00192   return rval;
00193 }
00194 
00195 template<> 
00196 std::vector<gr_complex> pycallback_object<std::vector<gr_complex> >::pyCast(PyObject* obj)
00197 {
00198   int size = PyObject_Size(obj);
00199   std::vector<gr_complex> rval(size);
00200   for(int i=0; i<size; i++){ rval[i] = \
00201       gr_complex((float)PyComplex_RealAsDouble(PyList_GetItem(obj, i)),
00202                  (float)PyComplex_ImagAsDouble(PyList_GetItem(obj, i))); 
00203   }
00204   return rval;
00205 }
00206 // TODO: add more template specializations as needed!