diff options
-rw-r--r-- | gnuradio-runtime/include/gnuradio/CMakeLists.txt | 2 | ||||
-rw-r--r-- | gnuradio-runtime/include/gnuradio/block_gateway.h | 282 | ||||
-rw-r--r-- | gnuradio-runtime/include/gnuradio/feval.h | 175 | ||||
-rw-r--r-- | gnuradio-runtime/include/gnuradio/py_feval.h | 86 | ||||
-rw-r--r-- | gnuradio-runtime/lib/CMakeLists.txt | 5 | ||||
-rw-r--r-- | gnuradio-runtime/lib/block_gateway_impl.cc | 137 | ||||
-rw-r--r-- | gnuradio-runtime/lib/block_gateway_impl.h | 56 | ||||
-rw-r--r-- | gnuradio-runtime/lib/feval.cc | 74 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gr/qa_feval.py | 99 |
9 files changed, 99 insertions, 817 deletions
diff --git a/gnuradio-runtime/include/gnuradio/CMakeLists.txt b/gnuradio-runtime/include/gnuradio/CMakeLists.txt index 056af5d6f4..d8e9c193ee 100644 --- a/gnuradio-runtime/include/gnuradio/CMakeLists.txt +++ b/gnuradio-runtime/include/gnuradio/CMakeLists.txt @@ -23,7 +23,6 @@ install(FILES constants.h endianness.h expj.h - feval.h flowgraph.h fxpt.h fxpt_nco.h @@ -42,7 +41,6 @@ install(FILES msg_queue.h nco.h prefs.h - py_feval.h pycallback_object.h random.h realtime.h diff --git a/gnuradio-runtime/include/gnuradio/block_gateway.h b/gnuradio-runtime/include/gnuradio/block_gateway.h index bcf3a7b27d..e8e1df87e3 100644 --- a/gnuradio-runtime/include/gnuradio/block_gateway.h +++ b/gnuradio-runtime/include/gnuradio/block_gateway.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2011-2013,2017 Free Software Foundation, Inc. + * Copyright 2011-2013,2017,2020 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -13,219 +13,55 @@ #include <gnuradio/api.h> #include <gnuradio/block.h> -#include <gnuradio/feval.h> +#include <string> -namespace gr { - -/*! - * The work type enum tells the gateway what kind of block to - * implement. The choices are familiar gnuradio block overloads - * (sync, decim, interp). - */ -enum block_gw_work_type { - GR_BLOCK_GW_WORK_GENERAL, - GR_BLOCK_GW_WORK_SYNC, - GR_BLOCK_GW_WORK_DECIM, - GR_BLOCK_GW_WORK_INTERP, -}; - -//! Magic return values from general_work, \ref gr::block::WORK_CALLED_PRODUCE -enum block_gw_work_return_type { WORK_CALLED_PRODUCE = -2, WORK_DONE = -1 }; -enum tag_propagation_policy_t { - TPP_DONT = 0, - TPP_ALL_TO_ALL = 1, - TPP_ONE_TO_ONE = 2, - TPP_CUSTOM = 3 -}; - -/*! - * Shared message structure between python and gateway. - * Each action type represents a scheduler-called function. - */ -struct block_gw_message_type { - enum action_type { - ACTION_GENERAL_WORK, // dispatch work - ACTION_WORK, // dispatch work - ACTION_FORECAST, // dispatch forecast - ACTION_START, // dispatch start - ACTION_STOP, // dispatch stop - }; - - action_type action; - - int general_work_args_noutput_items; - std::vector<int> general_work_args_ninput_items; - std::vector<void*> general_work_args_input_items; // TODO this should be const void*, - // but swig can't int cast it right - std::vector<void*> general_work_args_output_items; - int general_work_args_return_value; - - int work_args_ninput_items; - int work_args_noutput_items; - std::vector<void*> work_args_input_items; // TODO this should be const void*, but swig - // can't int cast it right - std::vector<void*> work_args_output_items; - int work_args_return_value; - - int forecast_args_noutput_items; - std::vector<int> forecast_args_ninput_items_required; +#include <pybind11/pybind11.h> // must be first +#include <pybind11/stl.h> +namespace py = pybind11; - bool start_args_return_value; - - bool stop_args_return_value; -}; +namespace gr { /*! * The gateway block which performs all the magic. * * The gateway provides access to all the gr::block routines. - * The methods prefixed with gr::block__ are renamed - * to class methods without the prefix in python. */ +typedef enum { + GW_BLOCK_GENERAL = 0, + GW_BLOCK_SYNC, + GW_BLOCK_DECIM, + GW_BLOCK_INTERP +} gw_block_t; + class GR_RUNTIME_API block_gateway : virtual public gr::block { +private: + py::handle d_py_handle; public: // gr::block_gateway::sptr typedef std::shared_ptr<block_gateway> sptr; /*! * Make a new gateway block. - * \param handler the swig director object with callback + * \param py_object the pybind11 object with callback * \param name the name of the block (Ex: "Shirley") * \param in_sig the input signature for this block * \param out_sig the output signature for this block - * \param work_type the type of block overload to implement - * \param factor the decimation or interpolation factor * \return a new gateway block */ - static sptr make(gr::feval_ll* handler, + static sptr make(const py::object& py_handle, const std::string& name, gr::io_signature::sptr in_sig, - gr::io_signature::sptr out_sig, - const block_gw_work_type work_type, - const unsigned factor); - - //! Provide access to the shared message object - virtual block_gw_message_type& block_message(void) = 0; - - long block__unique_id(void) const { return gr::block::unique_id(); } - - std::string block__name(void) const { return gr::block::name(); } - - unsigned block__history(void) const { return gr::block::history(); } - - void block__set_history(unsigned history) { return gr::block::set_history(history); } - - void block__set_block_alias(std::string alias) - { - return gr::block::set_block_alias(alias); - } - - std::string block__alias(void) const { return gr::block::alias(); } - - void block__set_processor_affinity(std::vector<int> mask) - { - return gr::block::set_processor_affinity(mask); - } - - void block__set_fixed_rate(bool fixed_rate) - { - return gr::block::set_fixed_rate(fixed_rate); - } - - bool block__fixed_rate(void) const { return gr::block::fixed_rate(); } - - void block__set_output_multiple(int multiple) - { - return gr::block::set_output_multiple(multiple); - } - - void block__set_min_output_buffer(int port, long size) - { - return gr::block::set_min_output_buffer(port, size); - } - - void block__set_min_output_buffer(long size) - { - return gr::block::set_min_output_buffer(size); - } - - long block__max_output_buffer(size_t i) { return gr::block::max_output_buffer(i); } - - void block__set_max_output_buffer(long max_output_buffer) - { - gr::block::set_max_output_buffer(max_output_buffer); - } - - void block__set_max_output_buffer(int port, long max_output_buffer) - { - gr::block::set_max_output_buffer(port, max_output_buffer); - } - - int block__output_multiple(void) const { return gr::block::output_multiple(); } + gr::io_signature::sptr out_sig); - void block__consume(int which_input, int how_many_items) - { - return gr::block::consume(which_input, how_many_items); - } - - void block__consume_each(int how_many_items) - { - return gr::block::consume_each(how_many_items); - } - void block__produce(int which_output, int how_many_items) - { - return gr::block::produce(which_output, how_many_items); - } - - void block__set_relative_rate(double relative_rate) - { - return gr::block::set_relative_rate(relative_rate); - } - - void block__set_inverse_relative_rate(double inverse_relative_rate) - { - return gr::block::set_inverse_relative_rate(inverse_relative_rate); - } - - void block__set_relative_rate(uint64_t interpolation, uint64_t decimation) - { - return gr::block::set_relative_rate(interpolation, decimation); - } - - double block__relative_rate(void) const { return gr::block::relative_rate(); } - - uint64_t block__relative_rate_i(void) const { return gr::block::relative_rate_i(); } - - uint64_t block__relative_rate_d(void) const { return gr::block::relative_rate_d(); } - - uint64_t block__nitems_read(unsigned int which_input) - { - return gr::block::nitems_read(which_input); - } - - uint64_t block__nitems_written(unsigned int which_output) - { - return gr::block::nitems_written(which_output); - } - - block::tag_propagation_policy_t block__tag_propagation_policy(void) - { - return gr::block::tag_propagation_policy(); - } - - void block__set_tag_propagation_policy(block::tag_propagation_policy_t p) - { - return gr::block::set_tag_propagation_policy(p); - } - - void block__add_item_tag(unsigned int which_output, const tag_t& tag) + // Protected members of gr::block trampolined here for python blocks to use + void _add_item_tag(unsigned int which_output, const tag_t& tag) { return gr::block::add_item_tag(which_output, tag); } - void block__add_item_tag(unsigned int which_output, + void _add_item_tag(unsigned int which_output, uint64_t abs_offset, const pmt::pmt_t& key, const pmt::pmt_t& value, @@ -234,7 +70,8 @@ public: return gr::block::add_item_tag(which_output, abs_offset, key, value, srcid); } - std::vector<tag_t> block__get_tags_in_range(unsigned int which_input, + + std::vector<tag_t> _get_tags_in_range(unsigned int which_input, uint64_t abs_start, uint64_t abs_end) { @@ -243,7 +80,7 @@ public: return tags; } - std::vector<tag_t> block__get_tags_in_range(unsigned int which_input, + std::vector<tag_t> _get_tags_in_range(unsigned int which_input, uint64_t abs_start, uint64_t abs_end, const pmt::pmt_t& key) @@ -253,7 +90,7 @@ public: return tags; } - std::vector<tag_t> block__get_tags_in_window(unsigned int which_input, + std::vector<tag_t> _get_tags_in_window(unsigned int which_input, uint64_t rel_start, uint64_t rel_end) { @@ -262,7 +99,7 @@ public: return tags; } - std::vector<tag_t> block__get_tags_in_window(unsigned int which_input, + std::vector<tag_t> _get_tags_in_window(unsigned int which_input, uint64_t rel_start, uint64_t rel_end, const pmt::pmt_t& key) @@ -272,73 +109,12 @@ public: return tags; } - /* Message passing interface */ - void block__message_port_register_in(pmt::pmt_t port_id) - { - gr::basic_block::message_port_register_in(port_id); - } - - void block__message_port_register_out(pmt::pmt_t port_id) - { - gr::basic_block::message_port_register_out(port_id); - } - - void block__message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg) - { - gr::basic_block::message_port_pub(port_id, msg); - } - - void block__message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target) - { - gr::basic_block::message_port_sub(port_id, target); - } - - void block__message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target) - { - gr::basic_block::message_port_unsub(port_id, target); - } - - pmt::pmt_t block__message_subscribers(pmt::pmt_t which_port) - { - return gr::basic_block::message_subscribers(which_port); - } - - pmt::pmt_t block__message_ports_in() { return gr::basic_block::message_ports_in(); } - - pmt::pmt_t block__message_ports_out() { return gr::basic_block::message_ports_out(); } - - void set_msg_handler_feval(pmt::pmt_t which_port, gr::feval_p* msg_handler) - { - if (msg_queue.find(which_port) == msg_queue.end()) { - throw std::runtime_error( - "attempt to set_msg_handler_feval() on bad input message port!"); - } - d_msg_handlers_feval[which_port] = msg_handler; - } + virtual void set_msg_handler_pybind(pmt::pmt_t which_port, std::string& handler_name) = 0; protected: - typedef std::map<pmt::pmt_t, feval_p*, pmt::comparator> msg_handlers_feval_t; - msg_handlers_feval_t d_msg_handlers_feval; - - bool has_msg_handler(pmt::pmt_t which_port) - { - if (d_msg_handlers_feval.find(which_port) != d_msg_handlers_feval.end()) { - return true; - } else { - return gr::basic_block::has_msg_handler(which_port); - } - } + virtual bool has_msg_handler(pmt::pmt_t which_port) = 0; + virtual void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg) = 0; - void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg) - { - // Is there a handler? - if (d_msg_handlers_feval.find(which_port) != d_msg_handlers_feval.end()) { - d_msg_handlers_feval[which_port]->calleval(msg); // Yes, invoke it. - } else { - // Pass to generic dispatcher if not found - gr::basic_block::dispatch_msg(which_port, msg); - } - } }; } /* namespace gr */ diff --git a/gnuradio-runtime/include/gnuradio/feval.h b/gnuradio-runtime/include/gnuradio/feval.h deleted file mode 100644 index 0148aea89c..0000000000 --- a/gnuradio-runtime/include/gnuradio/feval.h +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef INCLUDED_GR_FEVAL_H -#define INCLUDED_GR_FEVAL_H - -#include <gnuradio/api.h> -#include <gnuradio/gr_complex.h> -#include <pmt/pmt.h> - -namespace gr { - -/*! - * \brief base class for evaluating a function: double -> double - * \ingroup misc - * - * This class is designed to be subclassed in Python or C++ and is - * callable from both places. It uses SWIG's "director" feature to - * implement the magic. - * - * It's slow. Don't use it in a performance critical path. - * - * Override eval to define the behavior. - * Use calleval to invoke eval (this kludge is required to allow a - * python specific "shim" to be inserted. - */ -class GR_RUNTIME_API feval_dd -{ -protected: - /*! - * \brief override this to define the function - */ - virtual double eval(double x); - -public: - feval_dd() {} - virtual ~feval_dd(); - - virtual double calleval(double x); // invoke "eval" -}; - -/*! - * \brief base class for evaluating a function: complex -> complex - * \ingroup misc - * - * This class is designed to be subclassed in Python or C++ and is - * callable from both places. It uses SWIG's "director" feature to - * implement the magic. - * - * It's slow. Don't use it in a performance critical path. - * - * Override eval to define the behavior. - * Use calleval to invoke eval (this kludge is required to allow a - * python specific "shim" to be inserted. - */ -class GR_RUNTIME_API feval_cc -{ -protected: - /*! - * \brief override this to define the function - */ - virtual gr_complex eval(gr_complex x); - -public: - feval_cc() {} - virtual ~feval_cc(); - - virtual gr_complex calleval(gr_complex x); // invoke "eval" -}; - -/*! - * \brief base class for evaluating a function: long -> long - * \ingroup misc - * - * This class is designed to be subclassed in Python or C++ and is - * callable from both places. It uses SWIG's "director" feature to - * implement the magic. - * - * It's slow. Don't use it in a performance critical path. - * - * Override eval to define the behavior. - * Use calleval to invoke eval (this kludge is required to allow a - * python specific "shim" to be inserted. - */ -class GR_RUNTIME_API feval_ll -{ -protected: - /*! - * \brief override this to define the function - */ - virtual long eval(long x); - -public: - feval_ll() {} - virtual ~feval_ll(); - - virtual long calleval(long x); // invoke "eval" -}; - -/*! - * \brief base class for evaluating a function: void -> void - * \ingroup misc - * - * This class is designed to be subclassed in Python or C++ and is - * callable from both places. It uses SWIG's "director" feature to - * implement the magic. - * - * It's slow. Don't use it in a performance critical path. - * - * Override eval to define the behavior. - * Use calleval to invoke eval (this kludge is required to allow a - * python specific "shim" to be inserted. - */ -class GR_RUNTIME_API feval -{ -protected: - /*! - * \brief override this to define the function - */ - virtual void eval(); - -public: - feval() {} - virtual ~feval(); - - virtual void calleval(); // invoke "eval" -}; - -/*! - * \brief base class for evaluating a function: pmt -> void - * \ingroup misc - * - * This class is designed to be subclassed in Python or C++ and is - * callable from both places. It uses SWIG's "director" feature to - * implement the magic. - * - * It's slow. Don't use it in a performance critical path. - * - * Override eval to define the behavior. - * Use calleval to invoke eval (this kludge is required to allow a - * python specific "shim" to be inserted. - */ -class GR_RUNTIME_API feval_p -{ -protected: - /*! - * \brief override this to define the function - */ - virtual void eval(pmt::pmt_t x); - -public: - feval_p() {} - virtual ~feval_p(); - - virtual void calleval(pmt::pmt_t x); // invoke "eval" -}; - -/*! - * \brief trivial examples / test cases showing C++ calling Python code - */ -GR_RUNTIME_API double feval_dd_example(feval_dd* f, double x); -GR_RUNTIME_API gr_complex feval_cc_example(feval_cc* f, gr_complex x); -GR_RUNTIME_API long feval_ll_example(feval_ll* f, long x); -GR_RUNTIME_API void feval_example(feval* f); - -} /* namespace gr */ - -#endif /* INCLUDED_GR_FEVAL_H */ diff --git a/gnuradio-runtime/include/gnuradio/py_feval.h b/gnuradio-runtime/include/gnuradio/py_feval.h deleted file mode 100644 index 50af37ec03..0000000000 --- a/gnuradio-runtime/include/gnuradio/py_feval.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef INCLUDED_GR_PY_FEVAL_H -#define INCLUDED_GR_PY_FEVAL_H - -#include <gnuradio/feval.h> -#include <Python.h> -#include <pmt/pmt.h> - -class ensure_py_gil_state -{ - PyGILState_STATE d_gstate; - -public: - ensure_py_gil_state() { d_gstate = PyGILState_Ensure(); } - ~ensure_py_gil_state() { PyGILState_Release(d_gstate); } -}; - -namespace gr { - -class GR_RUNTIME_API py_feval_dd : public feval_dd -{ -public: - double calleval(double x) - { - ensure_py_gil_state _lock; - return eval(x); - } - virtual ~py_feval_dd(){}; -}; - -class GR_RUNTIME_API py_feval_cc : public feval_cc -{ -public: - gr_complex calleval(gr_complex x) - { - ensure_py_gil_state _lock; - return eval(x); - } - virtual ~py_feval_cc(){}; -}; - -class GR_RUNTIME_API py_feval_ll : public feval_ll -{ -public: - long calleval(long x) - { - ensure_py_gil_state _lock; - return eval(x); - } - virtual ~py_feval_ll(){}; -}; - -class GR_RUNTIME_API py_feval : public feval -{ -public: - void calleval() - { - ensure_py_gil_state _lock; - eval(); - } - virtual ~py_feval(){}; -}; - -class GR_RUNTIME_API py_feval_p : public feval_p -{ -public: - void calleval(pmt::pmt_t x) - { - ensure_py_gil_state _lock; - eval(x); - } - virtual ~py_feval_p(){}; -}; - -} /* namespace gr */ - -#endif /* INCLUDED_GR_PY_FEVAL_H */ diff --git a/gnuradio-runtime/lib/CMakeLists.txt b/gnuradio-runtime/lib/CMakeLists.txt index ee89f363ce..65673ad699 100644 --- a/gnuradio-runtime/lib/CMakeLists.txt +++ b/gnuradio-runtime/lib/CMakeLists.txt @@ -47,7 +47,6 @@ add_library(gnuradio-runtime block_gateway_impl.cc block_registry.cc buffer.cc - feval.cc flat_flowgraph.cc flowgraph.cc hier_block2.cc @@ -196,10 +195,14 @@ target_link_libraries(gnuradio-runtime PUBLIC Boost::thread Log4Cpp::log4cpp MPLib::mplib + ${PYTHON_LIBRARIES} ) target_include_directories(gnuradio-runtime PUBLIC + ${PYTHON_INCLUDE_DIR} + ${PYTHON_NUMPY_INCLUDE_DIR} + ${pybind11_INCLUDE_DIR} $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/../include> diff --git a/gnuradio-runtime/lib/block_gateway_impl.cc b/gnuradio-runtime/lib/block_gateway_impl.cc index 4acb464511..ced8edd1f5 100644 --- a/gnuradio-runtime/lib/block_gateway_impl.cc +++ b/gnuradio-runtime/lib/block_gateway_impl.cc @@ -1,93 +1,45 @@ +/* -*- c++ -*- */ /* - * Copyright 2011-2013 Free Software Foundation, Inc. + * Copyright 2013,2020 Free Software Foundation, Inc. * * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later * */ - #include "block_gateway_impl.h" +#include <pybind11/embed.h> + #include <gnuradio/io_signature.h> -#include <boost/bind.hpp> #include <iostream> namespace gr { -/*********************************************************************** - * Helper routines - **********************************************************************/ -template <typename OutType, typename InType> -void copy_pointers(OutType& out, const InType& in) -{ - out.resize(in.size()); - for (size_t i = 0; i < in.size(); i++) { - out[i] = (void*)(in[i]); - } -} - - -block_gateway::sptr block_gateway::make(feval_ll* handler, +block_gateway::sptr block_gateway::make(const py::object& p, const std::string& name, gr::io_signature::sptr in_sig, - gr::io_signature::sptr out_sig, - const block_gw_work_type work_type, - const unsigned factor) + gr::io_signature::sptr out_sig) { return block_gateway::sptr( - new block_gateway_impl(handler, name, in_sig, out_sig, work_type, factor)); + new block_gateway_impl(p, name, in_sig, out_sig)); } -block_gateway_impl::block_gateway_impl(feval_ll* handler, +block_gateway_impl::block_gateway_impl(const py::handle& p, const std::string& name, gr::io_signature::sptr in_sig, - gr::io_signature::sptr out_sig, - const block_gw_work_type work_type, - const unsigned factor) - : block(name, in_sig, out_sig), _handler(handler), _work_type(work_type) + gr::io_signature::sptr out_sig) + : block(name, in_sig, out_sig) { - switch (_work_type) { - case GR_BLOCK_GW_WORK_GENERAL: - _decim = 1; // not relevant, but set anyway - _interp = 1; // not relevant, but set anyway - break; - - case GR_BLOCK_GW_WORK_SYNC: - _decim = 1; - _interp = 1; - this->set_fixed_rate(true); - break; - - case GR_BLOCK_GW_WORK_DECIM: - _decim = factor; - _interp = 1; - break; - - case GR_BLOCK_GW_WORK_INTERP: - _decim = 1; - _interp = factor; - this->set_output_multiple(_interp); - break; - } + _py_handle = p; } void block_gateway_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required) { - switch (_work_type) { - case GR_BLOCK_GW_WORK_GENERAL: - _message.action = block_gw_message_type::ACTION_FORECAST; - _message.forecast_args_noutput_items = noutput_items; - _message.forecast_args_ninput_items_required = ninput_items_required; - _handler->calleval(0); - ninput_items_required = _message.forecast_args_ninput_items_required; - return; + py::gil_scoped_acquire acquire; + + py::object ret_ninput_items_required = _py_handle.attr("handle_forecast")(noutput_items, ninput_items_required.size()); + ninput_items_required = ret_ninput_items_required.cast<std::vector<int>>(); - default: - unsigned ninputs = ninput_items_required.size(); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); - return; - } } int block_gateway_impl::general_work(int noutput_items, @@ -95,63 +47,28 @@ int block_gateway_impl::general_work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { - switch (_work_type) { - case GR_BLOCK_GW_WORK_GENERAL: - _message.action = block_gw_message_type::ACTION_GENERAL_WORK; - _message.general_work_args_noutput_items = noutput_items; - _message.general_work_args_ninput_items = ninput_items; - copy_pointers(_message.general_work_args_input_items, input_items); - _message.general_work_args_output_items = output_items; - _handler->calleval(0); - return _message.general_work_args_return_value; + py::gil_scoped_acquire acquire; - default: - int r = work(noutput_items, input_items, output_items); - if (r > 0) - consume_each(r * _decim / _interp); - return r; - } + py::object ret = _py_handle.attr("handle_general_work")(noutput_items, ninput_items, input_items, output_items); + + return ret.cast<int>();; } -int block_gateway_impl::work(int noutput_items, - gr_vector_const_void_star& input_items, - gr_vector_void_star& output_items) +bool block_gateway_impl::start(void) { - _message.action = block_gw_message_type::ACTION_WORK; - _message.work_args_ninput_items = fixed_rate_noutput_to_ninput(noutput_items); - if (_message.work_args_ninput_items == 0) - return -1; - _message.work_args_noutput_items = noutput_items; - copy_pointers(_message.work_args_input_items, input_items); - _message.work_args_output_items = output_items; - _handler->calleval(0); - return _message.work_args_return_value; -} + py::gil_scoped_acquire acquire; -int block_gateway_impl::fixed_rate_noutput_to_ninput(int noutput_items) -{ - return (noutput_items * _decim / _interp) + history() - 1; + py::object ret = _py_handle.attr("start")(); + return ret.cast<bool>(); } -int block_gateway_impl::fixed_rate_ninput_to_noutput(int ninput_items) +bool block_gateway_impl::stop(void) { - return std::max(0, ninput_items - (int)history() + 1) * _interp / _decim; -} + py::gil_scoped_acquire acquire; -bool block_gateway_impl::start(void) -{ - _message.action = block_gw_message_type::ACTION_START; - _handler->calleval(0); - return _message.start_args_return_value; -} + py::object ret = _py_handle.attr("stop")(); + return ret.cast<bool>(); -bool block_gateway_impl::stop(void) -{ - _message.action = block_gw_message_type::ACTION_STOP; - _handler->calleval(0); - return _message.stop_args_return_value; } -block_gw_message_type& block_gateway_impl::block_message(void) { return _message; } - } /* namespace gr */ diff --git a/gnuradio-runtime/lib/block_gateway_impl.h b/gnuradio-runtime/lib/block_gateway_impl.h index a87f0ec1e5..168a78650e 100644 --- a/gnuradio-runtime/lib/block_gateway_impl.h +++ b/gnuradio-runtime/lib/block_gateway_impl.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2013 Free Software Foundation, Inc. + * Copyright 2013,2020 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -21,12 +21,10 @@ namespace gr { class block_gateway_impl : public block_gateway { public: - block_gateway_impl(feval_ll* handler, + block_gateway_impl(const py::handle& p, const std::string& name, gr::io_signature::sptr in_sig, - gr::io_signature::sptr out_sig, - const block_gw_work_type work_type, - const unsigned factor); + gr::io_signature::sptr out_sig); /******************************************************************* * Overloads for various scheduler-called functions @@ -38,23 +36,47 @@ public: gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); - int work(int noutput_items, - gr_vector_const_void_star& input_items, - gr_vector_void_star& output_items); - - int fixed_rate_noutput_to_ninput(int noutput_items); - int fixed_rate_ninput_to_noutput(int ninput_items); - bool start(void); bool stop(void); + void set_msg_handler_pybind(pmt::pmt_t which_port, std::string& handler_name) + { + if (msg_queue.find(which_port) == msg_queue.end()) { + throw std::runtime_error( + "attempt to set_msg_handler_pybind() on invalid input message port!"); + } + d_msg_handlers_pybind[which_port] = handler_name; + } + +protected: + // Message handlers back into python using pybind API + typedef std::map<pmt::pmt_t, std::string, pmt::comparator> msg_handlers_pybind_t; + msg_handlers_pybind_t d_msg_handlers_pybind; + + bool has_msg_handler(pmt::pmt_t which_port) + { + if (d_msg_handlers_pybind.find(which_port) != d_msg_handlers_pybind.end()) { + return true; + } else { + return gr::basic_block::has_msg_handler(which_port); + } + } - block_gw_message_type& block_message(void); + void dispatch_msg(pmt::pmt_t which_port, pmt::pmt_t msg) + { + // Is there a handler? + if (d_msg_handlers_pybind.find(which_port) != d_msg_handlers_pybind.end()) { + // d_msg_handlers_pybind[which_port]->calleval(msg); // Yes, invoke it. + py::gil_scoped_acquire acquire; + // std::string handler_name(d_msg_handlers_pybind[which_port]); + py::object ret = _py_handle.attr(d_msg_handlers_pybind[which_port].c_str())(msg); + } else { + // Pass to generic dispatcher if not found + gr::basic_block::dispatch_msg(which_port, msg); + } + } private: - feval_ll* _handler; - block_gw_message_type _message; - const block_gw_work_type _work_type; - unsigned _decim, _interp; + py::handle _py_handle; }; } /* namespace gr */ diff --git a/gnuradio-runtime/lib/feval.cc b/gnuradio-runtime/lib/feval.cc deleted file mode 100644 index 63e3fa419d..0000000000 --- a/gnuradio-runtime/lib/feval.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gnuradio/feval.h> - -namespace gr { - -feval_dd::~feval_dd() {} - -double feval_dd::eval(double x) { return 0; } - -double feval_dd::calleval(double x) { return eval(x); } - -// ---------------------------------------------------------------- - -feval_cc::~feval_cc() {} - -gr_complex feval_cc::eval(gr_complex x) { return 0; } - -gr_complex feval_cc::calleval(gr_complex x) { return eval(x); } - -// ---------------------------------------------------------------- - -feval_ll::~feval_ll() {} - -long feval_ll::eval(long x) { return 0; } - -long feval_ll::calleval(long x) { return eval(x); } - -// ---------------------------------------------------------------- - -feval::~feval() {} - -void feval::eval(void) -{ - // nop -} - -void feval::calleval(void) { eval(); } - -// ---------------------------------------------------------------- - -feval_p::~feval_p() {} - -void feval_p::eval(pmt::pmt_t x) -{ - // nop -} - -void feval_p::calleval(pmt::pmt_t x) { eval(x); } - -/* - * Trivial examples showing C++ (transparently) calling Python - */ -double feval_dd_example(feval_dd* f, double x) { return f->calleval(x); } - -gr_complex feval_cc_example(feval_cc* f, gr_complex x) { return f->calleval(x); } - -long feval_ll_example(feval_ll* f, long x) { return f->calleval(x); } - -void feval_example(feval* f) { f->calleval(); } - -} /* namespace gr */ diff --git a/gnuradio-runtime/python/gnuradio/gr/qa_feval.py b/gnuradio-runtime/python/gnuradio/gr/qa_feval.py deleted file mode 100644 index 7018fd9f1a..0000000000 --- a/gnuradio-runtime/python/gnuradio/gr/qa_feval.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2006,2007,2010 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - - -from gnuradio import gr, gr_unittest - -class my_add2_dd(gr.feval_dd): - def eval(self, x): - return x + 2 - -class my_add2_ll(gr.feval_ll): - def eval(self, x): - return x + 2 - -class my_add2_cc(gr.feval_cc): - def eval(self, x): - return x + (2 - 2j) - -class my_feval(gr.feval): - def __init__(self): - gr.feval.__init__(self) - self.fired = False - def eval(self): - self.fired = True - -class test_feval(gr_unittest.TestCase): - - def test_dd_1(self): - f = my_add2_dd() - src_data = (0.0, 1.0, 2.0, 3.0, 4.0) - expected_result = (2.0, 3.0, 4.0, 5.0, 6.0) - # this is all in python... - actual_result = tuple([f.eval(x) for x in src_data]) - self.assertEqual(expected_result, actual_result) - - def test_dd_2(self): - f = my_add2_dd() - src_data = (0.0, 1.0, 2.0, 3.0, 4.0) - expected_result = (2.0, 3.0, 4.0, 5.0, 6.0) - # this is python -> C++ -> python and back again... - actual_result = tuple([gr.feval_dd_example(f, x) for x in src_data]) - self.assertEqual(expected_result, actual_result) - - - def test_ll_1(self): - f = my_add2_ll() - src_data = (0, 1, 2, 3, 4) - expected_result = (2, 3, 4, 5, 6) - # this is all in python... - actual_result = tuple([f.eval(x) for x in src_data]) - self.assertEqual(expected_result, actual_result) - - def test_ll_2(self): - f = my_add2_ll() - src_data = (0, 1, 2, 3, 4) - expected_result = (2, 3, 4, 5, 6) - # this is python -> C++ -> python and back again... - actual_result = tuple([gr.feval_ll_example(f, x) for x in src_data]) - self.assertEqual(expected_result, actual_result) - - - def test_cc_1(self): - f = my_add2_cc() - src_data = (0+1j, 2+3j, 4+5j, 6+7j) - expected_result = (2-1j, 4+1j, 6+3j, 8+5j) - # this is all in python... - actual_result = tuple([f.eval(x) for x in src_data]) - self.assertEqual(expected_result, actual_result) - - def test_cc_2(self): - f = my_add2_cc() - src_data = (0+1j, 2+3j, 4+5j, 6+7j) - expected_result = (2-1j, 4+1j, 6+3j, 8+5j) - # this is python -> C++ -> python and back again... - actual_result = tuple([gr.feval_cc_example(f, x) for x in src_data]) - self.assertEqual(expected_result, actual_result) - - def test_void_1(self): - # this is all in python - f = my_feval() - f.eval() - self.assertEqual(True, f.fired) - - def test_void_2(self): - # this is python -> C++ -> python and back again - f = my_feval() - gr.feval_example(f) - self.assertEqual(True, f.fired) - - -if __name__ == '__main__': - gr_unittest.run(test_feval, "test_feval.xml") |