diff options
| author | Martin Braun <martin.braun@ettus.com> | 2019-02-04 16:00:16 +0100 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2019-02-22 16:56:52 -0800 | 
| commit | 692ddc71b17196487dcad982836e074cab9a0f25 (patch) | |
| tree | cf76abf577dde6128e03561c52d9c31dca302026 | |
| parent | 51bbf548c9b442d0b53b6c8de5f89403de274424 (diff) | |
| download | uhd-692ddc71b17196487dcad982836e074cab9a0f25.tar.gz uhd-692ddc71b17196487dcad982836e074cab9a0f25.tar.bz2 uhd-692ddc71b17196487dcad982836e074cab9a0f25.zip  | |
python: Replace Boost.Python with PyBind11
This does not change the Python API itself, but it is still
a significant change. Most importantly, it removes the dependency on
Boost.Python.
| -rw-r--r-- | host/CMakeLists.txt | 25 | ||||
| -rw-r--r-- | host/cmake/debian/control | 1 | ||||
| -rw-r--r-- | host/docs/pythonapi.dox | 32 | ||||
| -rw-r--r-- | host/lib/stream_python.hpp | 73 | ||||
| -rw-r--r-- | host/lib/types/filters_python.hpp | 27 | ||||
| -rw-r--r-- | host/lib/types/metadata_python.hpp | 49 | ||||
| -rw-r--r-- | host/lib/types/sensors_python.hpp | 24 | ||||
| -rw-r--r-- | host/lib/types/serial_python.hpp | 16 | ||||
| -rw-r--r-- | host/lib/types/time_spec_python.hpp | 24 | ||||
| -rw-r--r-- | host/lib/types/tune_python.hpp | 12 | ||||
| -rw-r--r-- | host/lib/types/types_python.hpp | 35 | ||||
| -rw-r--r-- | host/lib/usrp/dboard_iface_python.hpp | 26 | ||||
| -rw-r--r-- | host/lib/usrp/fe_connection_python.hpp | 11 | ||||
| -rw-r--r-- | host/lib/usrp/multi_usrp_python.hpp | 589 | ||||
| -rw-r--r-- | host/lib/usrp/subdev_spec_python.hpp | 19 | ||||
| -rw-r--r-- | host/lib/utils/gil_release_python.hpp | 31 | ||||
| -rw-r--r-- | host/python/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | host/python/pyuhd.cpp | 179 | ||||
| -rw-r--r-- | host/python/types.py | 5 | 
19 files changed, 337 insertions, 852 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 3ae6fbffb..092c2348f 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -284,11 +284,9 @@ endif(WIN32)  # Choose a version of Python  ########################################################################  option(ENABLE_PYTHON3 "Enable Python 3. Default is Python 2" OFF) -set(BOOST_PYTHON_COMPONENT python) -set(BOOST_PYTHON_VERSION 2.7) +set(PYBIND11_PYTHON_VERSION 2.7)  if(${ENABLE_PYTHON3}) -    set(BOOST_PYTHON_COMPONENT python3) -    set(BOOST_PYTHON_VERSION 3) +    set(PYBIND11_PYTHON_VERSION 3)  endif()  ######################################################################## @@ -307,7 +305,6 @@ set(BOOST_REQUIRED_COMPONENTS      serialization  ) -set(BOOST_OPTIONAL_COMPONENTS ${BOOST_PYTHON_COMPONENT})  if(MINGW)      list(APPEND BOOST_REQUIRED_COMPONENTS thread_win32)  else() @@ -344,14 +341,6 @@ find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_REQUIRED_COMPONENTS})  include_directories(${Boost_INCLUDE_DIRS})  link_directories(${Boost_LIBRARY_DIRS}) -#Check to see if the Python version we're looking for exists -set(BOOST_PYTHON_FOUND ${Boost_PYTHON_FOUND}) -set(BOOST_PYTHON_LIBRARY ${Boost_PYTHON_LIBRARY}) -if(${ENABLE_PYTHON3}) -    set(BOOST_PYTHON_FOUND ${Boost_PYTHON3_FOUND}) -    set(BOOST_PYTHON_LIBRARY ${Boost_PYTHON3_LIBRARY}) -endif() -  message(STATUS "Boost include directories: ${Boost_INCLUDE_DIRS}")  message(STATUS "Boost library directories: ${Boost_LIBRARY_DIRS}")  message(STATUS "Boost libraries: ${Boost_LIBRARIES}") @@ -367,8 +356,8 @@ include(UHDLog)  ########################################################################  # Check Python Modules  ######################################################################## -find_package(PythonInterp ${BOOST_PYTHON_VERSION}) -find_package(PythonLibs ${BOOST_PYTHON_VERSION}) +find_package(PythonInterp ${PYBIND11_PYTHON_VERSION}) +find_package(PythonLibs ${PYBIND11_PYTHON_VERSION})  include(UHDPython)  set(PYTHON_VERSION "platform.python_version() >= '2.7' and platform.python_version() < '3.0'") @@ -377,7 +366,7 @@ if(${ENABLE_PYTHON3})  endif()  PYTHON_CHECK_MODULE( -    "Python version ${BOOST_PYTHON_VERSION} or greater" +    "Python version ${PYBIND11_PYTHON_VERSION} or greater"      "platform" ${PYTHON_VERSION}      HAVE_PYTHON_PLAT_MIN_VERSION  ) @@ -430,9 +419,9 @@ UHD_INSTALL(FILES  LIBUHD_REGISTER_COMPONENT("LibUHD" ENABLE_LIBUHD ON "Boost_FOUND;HAVE_PYTHON_PLAT_MIN_VERSION;HAVE_PYTHON_MODULE_MAKO" OFF ON)  LIBUHD_REGISTER_COMPONENT("LibUHD - C API" ENABLE_C_API ON "ENABLE_LIBUHD" OFF OFF)  if(WIN32) -    LIBUHD_REGISTER_COMPONENT("LibUHD - Python API" ENABLE_PYTHON_API OFF "ENABLE_LIBUHD;BOOST_PYTHON_FOUND;HAVE_PYTHON_MODULE_NUMPY;PythonLibs_FOUND" OFF OFF) +    LIBUHD_REGISTER_COMPONENT("LibUHD - Python API" ENABLE_PYTHON_API OFF "ENABLE_LIBUHD;HAVE_PYTHON_MODULE_NUMPY;PythonLibs_FOUND" OFF OFF)  else() -    LIBUHD_REGISTER_COMPONENT("LibUHD - Python API" ENABLE_PYTHON_API ON "ENABLE_LIBUHD;BOOST_PYTHON_FOUND;HAVE_PYTHON_MODULE_NUMPY;PythonLibs_FOUND" OFF OFF) +    LIBUHD_REGISTER_COMPONENT("LibUHD - Python API" ENABLE_PYTHON_API ON "ENABLE_LIBUHD;HAVE_PYTHON_MODULE_NUMPY;PythonLibs_FOUND" OFF OFF)  endif(WIN32)  LIBUHD_REGISTER_COMPONENT("Examples" ENABLE_EXAMPLES ON "ENABLE_LIBUHD" OFF OFF)  LIBUHD_REGISTER_COMPONENT("Utils" ENABLE_UTILS ON "ENABLE_LIBUHD" OFF OFF) diff --git a/host/cmake/debian/control b/host/cmake/debian/control index fc53a929e..4a6bd19ee 100644 --- a/host/cmake/debian/control +++ b/host/cmake/debian/control @@ -10,7 +10,6 @@ Build-Depends:  cmake,                  libboost-dev,                  libboost-filesystem-dev,                  libboost-program-options-dev, -                libboost-python-dev,                  libboost-regex-dev,                  libboost-serialization-dev,                  libboost-system-dev, diff --git a/host/docs/pythonapi.dox b/host/docs/pythonapi.dox index e290f1ea5..3f73c3a74 100644 --- a/host/docs/pythonapi.dox +++ b/host/docs/pythonapi.dox @@ -5,10 +5,17 @@ for your application.  \section python_install Installing the Python API -In order to install the Python API when building UHD from source, make sure all -the dependencies are available (see also \ref page_build_guide, you need -Boost.Python from your Boost library). Make sure you have the CMake variable -`ENABLE_PYTHON_API` set to ON (e.g., by running `cmake -DENABLE_PYTHON_API=ON`). +In order to install the Python API when building UHD from source, make sure you +have the CMake variable `ENABLE_PYTHON_API` set to ON (e.g., by running +`cmake -DENABLE_PYTHON_API=ON`). +UHD requires Python header files in order to compile the Python API. On most +Linux systems, there are packages called "python3-dev" or "python3-devel" that +provide that functionality. On Windows, these headers always get installed when +using the binary installers provided on https://www.python.org/downloads/windows/. + +If CMake can't find the Python headers or library, specify +the `PYTHON_INCLUDE_DIRS` and/or `PYTHON_LIBRARY` CMake variables manually. +  \subsection python_install_2v3 Python 2 vs. 3 @@ -20,13 +27,18 @@ Python 3.  \subsection python_install_windows Installing on Windows -On Windows, only certain combinations of MSVC and Boost have proven functional. -The following combinations are known to work (others might also work): +Static linking on is unsupported on Windows. Otherwise, compiling the Python API +on Windows is no different from other operating systems. + +\subsection python_install_adv Advanced Usage Notes -- Visual Studio 2017 (version 15.7.3), Release X64 on Windows 10 with Boost -  1.65.1 and Boost 1.66, Python27 x64 bit. +UHD uses the PyBind11 library to generate its Python bindings. UHD ships its own +copy of PyBind11, in order to facilitate the access to that library, as it is +not packaged for many operating systems, but also to lock down its version. For +the purpose of experimentation, it is, however possible to replace the version +of PyBind11 shipped with UHD by overriding the `PYBIND11_INCLUDE_DIR` CMake +variable. -Static linking on is currently unsupported on Windows.  \section python_usage Using the Python API @@ -93,7 +105,7 @@ def recv_to_file():  This kind of API is particularly useful in combination with Jupyter Notebooks or  similar interactive environments. -\section python_usage_gil Python Global Interpreter Lock +\section python_usage_gil Thread Safety and the Python Global Interpreter Lock  From the <a href="https://wiki.python.org/moin/GlobalInterpreterLock">Python wiki page on the GIL:</a>  > In CPython, the global interpreter lock, or GIL, is a mutex that protects diff --git a/host/lib/stream_python.hpp b/host/lib/stream_python.hpp index 0760edf1b..1cb922b52 100644 --- a/host/lib/stream_python.hpp +++ b/host/lib/stream_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -7,24 +8,15 @@  #ifndef INCLUDED_UHD_STREAM_PYTHON_HPP  #define INCLUDED_UHD_STREAM_PYTHON_HPP -#include "utils/gil_release_python.hpp"  #include <uhd/stream.hpp>  #include <uhd/types/metadata.hpp> -  #include <boost/format.hpp>  static size_t wrap_recv(uhd::rx_streamer *rx_stream, -                        bp::object &np_array, -                        bp::object &metadata, +                        py::object &np_array, +                        uhd::rx_metadata_t &metadata,                          const double timeout = 0.1)  { -    // Extract the metadata -    bp::extract<uhd::rx_metadata_t&> get_metadata(metadata); -    if (not get_metadata.check()) -    { -        return 0; -    } -      // Get a numpy array object from given python object      // No sanity checking possible!      PyObject* array_obj = PyArray_FROM_OF(np_array.ptr(), NPY_ARRAY_CARRAY); @@ -70,12 +62,12 @@ static size_t wrap_recv(uhd::rx_streamer *rx_stream,      // Release the GIL only for the recv() call      const size_t result = [&]() { -        scoped_gil_release gil_release; +        py::gil_scoped_release release;          // Call the real recv()          return rx_stream->recv(              channel_storage,              nsamps_per_buff, -            get_metadata(), +            metadata,              timeout          );      }(); @@ -84,21 +76,12 @@ static size_t wrap_recv(uhd::rx_streamer *rx_stream,      Py_DECREF(array_obj);      return result;  } -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_wrap_recv, wrap_recv, 3, 4);  static size_t wrap_send(uhd::tx_streamer *tx_stream, -                        bp::object &np_array, -                        bp::object &metadata, +                        py::object &np_array, +                        uhd::tx_metadata_t& metadata,                          const double timeout = 0.1)  { -    // Extract the metadata -    bp::extract<uhd::tx_metadata_t&> get_metadata(metadata); -    // TODO: throw an error here? -    if (not get_metadata.check()) -    { -        return 0; -    } -      // Get a numpy array object from given python object      // No sanity checking possible!      // Note: this increases the ref count, which we'll need to manually decrease at the end @@ -140,12 +123,12 @@ static size_t wrap_send(uhd::tx_streamer *tx_stream,      // Release the GIL only for the send() call      const size_t result = [&]() { -        scoped_gil_release gil_release; +        py::gil_scoped_release release;          // Call the real send()          return tx_stream->send(              channel_storage,              nsamps_per_buff, -            get_metadata(), +            metadata,              timeout          );      }(); @@ -154,28 +137,25 @@ static size_t wrap_send(uhd::tx_streamer *tx_stream,      Py_DECREF(array_obj);      return result;  } -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_wrap_send, wrap_send, 3, 4);  static bool wrap_recv_async_msg(uhd::tx_streamer *tx_stream,                                  uhd::async_metadata_t &async_metadata,                                  double timeout = 0.1)  {      // Release the GIL -    scoped_gil_release gil_release; - +    py::gil_scoped_release release;      return tx_stream->recv_async_msg(async_metadata, timeout);  } -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_wrap_recv_async_msg, wrap_recv_async_msg, 2, 3); -void export_stream() +void export_stream(py::module& m)  {      using stream_args_t = uhd::stream_args_t;      using rx_streamer   = uhd::rx_streamer;      using tx_streamer   = uhd::tx_streamer; -    bp::class_<stream_args_t> -        ("stream_args", bp::init<const std::string&, const std::string&>()) - +    py::class_<stream_args_t> +        (m, "stream_args") +        .def(py::init<const std::string&, const std::string&>())          // Properties          .def_readwrite("cpu_format", &stream_args_t::cpu_format)          .def_readwrite("otw_format", &stream_args_t::otw_format) @@ -183,29 +163,28 @@ void export_stream()          .def_readwrite("channels"  , &stream_args_t::channels  )          ; -    bp::class_< -        rx_streamer, -        boost::shared_ptr<rx_streamer>, -        uhd::noncopyable>("rx_streamer", "See: uhd::rx_streamer", bp::no_init) - +    py::class_<rx_streamer, rx_streamer::sptr>(m, "rx_streamer", "See: uhd::rx_streamer")          // Methods -        .def("recv"             , &wrap_recv, overload_wrap_recv()    ) +        .def("recv"             , &wrap_recv, +                                    py::arg("np_array"), +                                    py::arg("metadata"), +                                    py::arg("timeout") = 0.1)          .def("get_num_channels" , &uhd::rx_streamer::get_num_channels )          .def("get_max_num_samps", &uhd::rx_streamer::get_max_num_samps)          .def("issue_stream_cmd" , &uhd::rx_streamer::issue_stream_cmd )          ; -    bp::class_< -        tx_streamer, -        boost::shared_ptr<tx_streamer>, -        uhd::noncopyable>("tx_streamer", "See: uhd::tx_streamer", bp::no_init) - +    py::class_<tx_streamer, tx_streamer::sptr>(m, "tx_streamer", "See: uhd::tx_streamer")          // Methods -        .def("send"             , &wrap_send, overload_wrap_send()) +        .def("send"             , &wrap_send, +                                    py::arg("np_array"), +                                    py::arg("metadata"), +                                    py::arg("timeout") = 0.1)          .def("get_num_channels" , &tx_streamer::get_num_channels  )          .def("get_max_num_samps", &tx_streamer::get_max_num_samps )          .def("recv_async_msg"   , &wrap_recv_async_msg, -                                  overload_wrap_recv_async_msg()  ) +                                  py::arg("async_metadata"), +                                  py::arg("timeout") = 0.1)          ;  } diff --git a/host/lib/types/filters_python.hpp b/host/lib/types/filters_python.hpp index ff5785345..ad13eed1e 100644 --- a/host/lib/types/filters_python.hpp +++ b/host/lib/types/filters_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -9,24 +10,22 @@  #include <uhd/types/filters.hpp> -void export_filters() +void export_filters(py::module& m)  {      using filter_info_base   = uhd::filter_info_base;      using filter_info_type   = filter_info_base::filter_type;      using analog_filter_base = uhd::analog_filter_base;      using analog_filter_lp   = uhd::analog_filter_lp; -    bp::enum_<filter_info_type>("filter_type") +    py::enum_<filter_info_type>(m, "filter_type")          .value("analog_low_pass" , filter_info_base::ANALOG_LOW_PASS )          .value("analog_band_pass", filter_info_base::ANALOG_BAND_PASS)          .value("digital_i16"     , filter_info_base::DIGITAL_I16     )          .value("digital_fir_i16" , filter_info_base::DIGITAL_FIR_I16 )          ; -    bp::class_< -        filter_info_base, -        boost::shared_ptr<filter_info_base> > -        ("filter_info_base", bp::init<filter_info_type, bool, size_t>()) +    py::class_<filter_info_base, filter_info_base::sptr>(m, "filter_info_base") +        .def(py::init<filter_info_type, bool, size_t>())          // Methods          .def("is_bypassed", &filter_info_base::is_bypassed ) @@ -34,21 +33,15 @@ void export_filters()          .def("__str__"    , &filter_info_base::to_pp_string)          ; -    bp::class_< -        analog_filter_base, -        boost::shared_ptr<analog_filter_base>, -        bp::bases<filter_info_base> > -        ("analog_filter_base", bp::init<filter_info_type, bool, size_t, std::string>()) +    py::class_<analog_filter_base, analog_filter_base::sptr>(m, "analog_filter_base") +        .def(py::init<filter_info_type, bool, size_t, std::string>())          // Methods -        .def("get_analog_type", &analog_filter_base::get_analog_type, bp::return_value_policy<bp::copy_const_reference>()) +        .def("get_analog_type", &analog_filter_base::get_analog_type)      ; -    bp::class_< -        analog_filter_lp, -        boost::shared_ptr<analog_filter_lp>, -        bp::bases<analog_filter_base> > -        ("analog_filter_lp", bp::init<filter_info_type, bool, size_t, const std::string, double, double>()) +    py::class_<analog_filter_lp, boost::shared_ptr<analog_filter_lp>>(m, "analog_filter_lp") +        .def(py::init<filter_info_type, bool, size_t, const std::string, double, double>())          // Methods          .def("get_cutoff" , &analog_filter_lp::get_cutoff ) diff --git a/host/lib/types/metadata_python.hpp b/host/lib/types/metadata_python.hpp index 876756d73..f57d82dc9 100644 --- a/host/lib/types/metadata_python.hpp +++ b/host/lib/types/metadata_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -9,7 +10,7 @@  #include <uhd/types/ranges.hpp> -void export_metadata() +void export_metadata(py::module& m)  {      using range_t       = uhd::range_t;      using meta_range_t  = uhd::meta_range_t; @@ -19,7 +20,7 @@ void export_metadata()      using async_metadata_t = uhd::async_metadata_t;      using event_code_t = async_metadata_t::event_code_t; -    bp::enum_<error_code_t>("rx_metadata_error_code") +    py::enum_<error_code_t>(m, "rx_metadata_error_code")          .value("none"        , error_code_t::ERROR_CODE_NONE        )          .value("timeout"     , error_code_t::ERROR_CODE_TIMEOUT     )          .value("late"        , error_code_t::ERROR_CODE_LATE_COMMAND) @@ -29,11 +30,11 @@ void export_metadata()          .value("bad_packet"  , error_code_t::ERROR_CODE_BAD_PACKET  )          ; -    bp::class_<range_t> -        ("range", bp::init<double>()) - +    py::class_<range_t>(m, "range")          // Constructors -        .def(bp::init<double, double, double>()) +        .def(py::init<double>()) +        .def(py::init<double, double>()) +        .def(py::init<double, double, double>())          // Methods          .def("start"  , &range_t::start       ) @@ -42,30 +43,28 @@ void export_metadata()          .def("__str__", &range_t::to_pp_string)          ; -    bp::class_<std::vector<range_t> >("range_vector") -        .def(bp::vector_indexing_suite<std::vector<range_t> >()); - -    bp::class_<meta_range_t, bp::bases<std::vector<range_t> > > -        ("meta_range", bp::init<>()) - +    py::class_<meta_range_t>(m, "meta_range_t")          // Constructors -        .def(bp::init<double, double, double>()) +        .def(py::init<>()) +        .def(py::init<double, double>()) +        .def(py::init<double, double, double>())          // Methods          .def("start"  , &meta_range_t::start       )          .def("stop"   , &meta_range_t::stop        )          .def("step"   , &meta_range_t::step        ) -        .def("clip"   , &meta_range_t::clip        ) +        .def("clip"   , &meta_range_t::clip, py::arg("value"), py::arg("clip_step") = false)          .def("__str__", &meta_range_t::to_pp_string)          ; -    bp::class_<rx_metadata_t>("rx_metadata", bp::init<>()) +    py::class_<rx_metadata_t>(m, "rx_metadata") +        .def(py::init<>())          // Methods          .def("reset"       , &rx_metadata_t::reset       )          .def("to_pp_string", &rx_metadata_t::to_pp_string)          .def("strerror"    , &rx_metadata_t::strerror    ) -        .def("__str__"     , &rx_metadata_t::to_pp_string, bp::args("compact") = false) +        .def("__str__"     , &rx_metadata_t::to_pp_string, py::arg("compact") = false)          // Properties          .def_readonly("has_time_spec"  , &rx_metadata_t::has_time_spec  ) @@ -77,7 +76,8 @@ void export_metadata()          .def_readonly("out_of_sequence", &rx_metadata_t::out_of_sequence)          ; -    bp::class_<tx_metadata_t>("tx_metadata", bp::init<>()) +    py::class_<tx_metadata_t>(m, "tx_metadata") +        .def(py::init<>())          // Properties          .def_readwrite("has_time_spec" , &tx_metadata_t::has_time_spec ) @@ -86,7 +86,7 @@ void export_metadata()          .def_readwrite("end_of_burst"  , &tx_metadata_t::end_of_burst  )          ; -    bp::enum_<event_code_t>("tx_metadata_event_code") +    py::enum_<event_code_t>(m, "tx_metadata_event_code")          .value("burst_ack"          , event_code_t::EVENT_CODE_BURST_ACK          )          .value("underflow"          , event_code_t::EVENT_CODE_UNDERFLOW          )          .value("seq_error"          , event_code_t::EVENT_CODE_SEQ_ERROR          ) @@ -96,15 +96,16 @@ void export_metadata()          .value("user_payload"       , event_code_t::EVENT_CODE_USER_PAYLOAD       )          ; -    bp::class_<async_metadata_t>("async_metadata", bp::init<>()) +    py::class_<async_metadata_t>(m, "async_metadata") +        .def(py::init<>())          // Properties -        .def_readwrite("channel"      , &async_metadata_t::channel      ) -        .def_readwrite("has_time_spec", &async_metadata_t::has_time_spec) -        .def_readwrite("time_spec"    , &async_metadata_t::time_spec    ) -        .def_readwrite("event_code"   , &async_metadata_t::event_code   ) +        .def_readonly("channel"      , &async_metadata_t::channel      ) +        .def_readonly("has_time_spec", &async_metadata_t::has_time_spec) +        .def_readonly("time_spec"    , &async_metadata_t::time_spec    ) +        .def_readonly("event_code"   , &async_metadata_t::event_code   )          // TODO: Expose user payloads -        //.def_readwrite("user_payload" , &async_metadata_t::user_payload ) +        //.def_readonly("user_payload" , &async_metadata_t::user_payload )          ;  } diff --git a/host/lib/types/sensors_python.hpp b/host/lib/types/sensors_python.hpp index 8fd9da4e3..e3937d117 100644 --- a/host/lib/types/sensors_python.hpp +++ b/host/lib/types/sensors_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -9,25 +10,24 @@  #include <uhd/types/sensors.hpp> -void export_sensors() +void export_sensors(py::module& m)  {      using sensor_value_t = uhd::sensor_value_t;      using data_type_t    = sensor_value_t::data_type_t; -    bp::enum_<data_type_t>("data_type") +    py::enum_<data_type_t>(m, "data_type")          .value("b", data_type_t::BOOLEAN)          .value("i", data_type_t::INTEGER)          .value("r", data_type_t::REALNUM)          .value("s", data_type_t::STRING )          ; -    bp::class_<sensor_value_t> -        ("sensor_value", bp::init<const std::string&, bool, const std::string&, const std::string&>()) - +    py::class_<sensor_value_t>(m, "sensor_value")          // Constructors -        .def(bp::init<const std::string&, signed, const std::string&, const std::string&>()) -        .def(bp::init<const std::string&, double, const std::string&, const std::string&>()) -        .def(bp::init<const std::string&, const std::string&        , const std::string&>()) +        .def(py::init<const std::string&, bool, const std::string&, const std::string&>()) +        .def(py::init<const std::string&, signed, const std::string&, const std::string&>()) +        .def(py::init<const std::string&, double, const std::string&, const std::string&>()) +        .def(py::init<const std::string&, const std::string&        , const std::string&>())          // Methods          .def("to_bool", &sensor_value_t::to_bool     ) @@ -36,10 +36,10 @@ void export_sensors()          .def("__str__", &sensor_value_t::to_pp_string)          // Properties -        .add_property("name",  &sensor_value_t::name ) -        .add_property("value", &sensor_value_t::value) -        .add_property("unit",  &sensor_value_t::unit ) -        .add_property("type",  &sensor_value_t::type ) +        .def_readwrite("name",  &sensor_value_t::name ) +        .def_readwrite("value", &sensor_value_t::value) +        .def_readwrite("unit",  &sensor_value_t::unit ) +        .def_readwrite("type",  &sensor_value_t::type )          ;  } diff --git a/host/lib/types/serial_python.hpp b/host/lib/types/serial_python.hpp index 441bcc4d7..eb52472a5 100644 --- a/host/lib/types/serial_python.hpp +++ b/host/lib/types/serial_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -9,23 +10,24 @@  #include <uhd/types/serial.hpp> -void export_spi_config() +void export_spi_config(py::module& m)  {      using spi_config_t = uhd::spi_config_t;      using spi_edge_t   = spi_config_t::edge_t; -    bp::enum_<spi_edge_t>("spi_edge") +    py::enum_<spi_edge_t>(m, "spi_edge")          .value("EDGE_RISE" , spi_edge_t::EDGE_RISE)          .value("EDGE_FALL",  spi_edge_t::EDGE_FALL)          ; -    bp::class_<spi_config_t>("spi_config", bp::init<spi_edge_t>()) +    py::class_<spi_config_t>(m, "spi_config") +        .def(py::init<spi_edge_t>())          // Properties -        .add_property("mosi_edge"         , &spi_config_t::mosi_edge         ) -        .add_property("miso_edge"         , &spi_config_t::miso_edge         ) -        .add_property("use_custom_divider", &spi_config_t::use_custom_divider) -        .add_property("divider"           , &spi_config_t::divider           ) +        .def_readwrite("mosi_edge"         , &spi_config_t::mosi_edge         ) +        .def_readwrite("miso_edge"         , &spi_config_t::miso_edge         ) +        .def_readwrite("use_custom_divider", &spi_config_t::use_custom_divider) +        .def_readwrite("divider"           , &spi_config_t::divider           )          ;  } diff --git a/host/lib/types/time_spec_python.hpp b/host/lib/types/time_spec_python.hpp index 219dd076b..12489fd44 100644 --- a/host/lib/types/time_spec_python.hpp +++ b/host/lib/types/time_spec_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -8,30 +9,31 @@  #define INCLUDED_UHD_TIME_SPEC_PYTHON_HPP  #include <uhd/types/time_spec.hpp> +#include <pybind11/operators.h> -void export_time_spec() +void export_time_spec(py::module& m)  {      using time_spec_t = uhd::time_spec_t; -    bp::class_<time_spec_t>("time_spec", bp::init<double>()) +    py::class_<time_spec_t>(m, "time_spec")          //Additional constructors -        .def(bp::init<int64_t, double>()) -        .def(bp::init<int64_t, long, double>()) +        .def(py::init<double>()) +        .def(py::init<int64_t, double>()) +        .def(py::init<int64_t, long, double>())          // Methods -        .def("from_ticks"     , &time_spec_t::from_ticks     ) -        .staticmethod("from_ticks"                           ) +        .def_static("from_ticks"     , &time_spec_t::from_ticks)          .def("get_tick_count" , &time_spec_t::get_tick_count )          .def("to_ticks"       , &time_spec_t::to_ticks       )          .def("get_real_secs"  , &time_spec_t::get_real_secs  )          .def("get_frac_secs"  , &time_spec_t::get_frac_secs  ) -        .def(bp::self += time_spec_t()) -        .def(bp::self += double()) -        .def(bp::self + double()) -        .def(bp::self + time_spec_t()) -        .def(bp::self -= time_spec_t()) +        .def(py::self += time_spec_t()) +        .def(py::self += double()) +        .def(py::self + double()) +        .def(py::self + time_spec_t()) +        .def(py::self -= time_spec_t())          ;  } diff --git a/host/lib/types/tune_python.hpp b/host/lib/types/tune_python.hpp index 587c8cbea..6c3607908 100644 --- a/host/lib/types/tune_python.hpp +++ b/host/lib/types/tune_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -10,20 +11,20 @@  #include <uhd/types/tune_result.hpp>  #include <uhd/types/tune_request.hpp> -void export_tune() +void export_tune(py::module& m)  {      using tune_request_t = uhd::tune_request_t;      using tune_result_t  = uhd::tune_result_t;      using policy_t       = tune_request_t::policy_t; -    bp::enum_<policy_t>("tune_request_policy") +    py::enum_<policy_t>(m, "tune_request_policy")          .value("none",   tune_request_t::POLICY_NONE  )          .value("auto",   tune_request_t::POLICY_AUTO  )          .value("manual", tune_request_t::POLICY_MANUAL)          ; -    bp::class_<tune_request_t>("tune_request", bp::init<double>()) -        .def(bp::init<double, double>()) +    py::class_<tune_request_t>(m, "tune_request") +        .def(py::init<double, double>())          .def_readwrite("target_freq"    , &tune_request_t::target_freq    )          .def_readwrite("rf_freq_policy" , &tune_request_t::rf_freq_policy )          .def_readwrite("dsp_freq_policy", &tune_request_t::dsp_freq_policy) @@ -32,7 +33,8 @@ void export_tune()          .def_readwrite("args"           , &tune_request_t::args           )          ; -    bp::class_<tune_result_t>("tune_result", bp::init<>()) +    py::class_<tune_result_t>(m, "tune_result") +        .def(py::init<>())          .def_readwrite("clipped_rf_freq", &tune_result_t::clipped_rf_freq)          .def_readwrite("target_rf_freq" , &tune_result_t::target_rf_freq )          .def_readwrite("actual_rf_freq" , &tune_result_t::actual_rf_freq ) diff --git a/host/lib/types/types_python.hpp b/host/lib/types/types_python.hpp index 434ae9171..b7003d7b0 100644 --- a/host/lib/types/types_python.hpp +++ b/host/lib/types/types_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -7,59 +8,49 @@  #ifndef INCLUDED_UHD_TYPES_PYTHON_HPP  #define INCLUDED_UHD_TYPES_PYTHON_HPP +#include <pybind11/stl.h>  #include <uhd/types/device_addr.hpp>  #include <uhd/types/stream_cmd.hpp> -#include <boost/python.hpp>  #include <string>  #include <map> -//! Make a device_addr_t from a Python dict of strings -static uhd::device_addr_t make_device_addr(bp::dict& info) { -    // Manually extract each key and each value, copy them to a map of strings, and return that. -    std::map<std::string,std::string> info_map; -    auto keys = info.keys(); -    for (int ii = 0; ii < bp::len(keys); ++ii) { -        std::string key = bp::extract<std::string>(keys[ii]); -        info_map[key] = bp::extract<std::string>(info[key]); -    } -    return uhd::device_addr_t(info_map); -} - -void export_types() +void export_types(py::module& m)  {      using stream_cmd_t  = uhd::stream_cmd_t;      using stream_mode_t = stream_cmd_t::stream_mode_t;      using str_map = std::map<std::string, std::string>; -    bp::enum_<stream_mode_t>("stream_mode") +    py::enum_<stream_mode_t>(m, "stream_mode")          .value("start_cont", stream_cmd_t::STREAM_MODE_START_CONTINUOUS  )          .value("stop_cont" , stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS   )          .value("num_done"  , stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE)          .value("num_more"  , stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE)          ; -    bp::class_<stream_cmd_t>("stream_cmd", bp::init<stream_cmd_t::stream_mode_t>()) - +    py::class_<stream_cmd_t>(m, "stream_cmd") +        .def(py::init<stream_cmd_t::stream_mode_t>())          // Properties          .def_readwrite("num_samps" , &stream_cmd_t::num_samps )          .def_readwrite("time_spec" , &stream_cmd_t::time_spec )          .def_readwrite("stream_now", &stream_cmd_t::stream_now)          ; -    bp::class_<uhd::device_addr_t>("device_addr", bp::init<bp::optional<std::string> >()) +    py::class_<uhd::device_addr_t>(m, "device_addr")          // Constructors -        /* TODO: This calls the correct C++ constructor, but Python -                 dictionaries != str_maps, so we get a signature error */ -        .def(bp::init<str_map>()) +        .def(py::init<>()) +        .def(py::init<std::string>()) +        .def(py::init<str_map>())          // Methods          .def("__str__", &uhd::device_addr_t::to_pp_string)          .def("to_string", &uhd::device_addr_t::to_string)          .def("to_pp_string", &uhd::device_addr_t::to_pp_string)          ; +    // This will allow functions in Python that take a device_addr to also take +    // a string: +    py::implicitly_convertible<std::string, uhd::device_addr_t>(); -    bp::def("make_device_addr", make_device_addr);  }  #endif /* INCLUDED_UHD_TYPES_PYTHON_HPP */ diff --git a/host/lib/usrp/dboard_iface_python.hpp b/host/lib/usrp/dboard_iface_python.hpp index f43490e7d..96fcc1702 100644 --- a/host/lib/usrp/dboard_iface_python.hpp +++ b/host/lib/usrp/dboard_iface_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -11,7 +12,7 @@  #include <uhd/usrp/gpio_defs.hpp>  #include "../include/uhdlib/usrp/gpio_defs.hpp" -void export_dboard_iface() +void export_dboard_iface(py::module& m)  {      using dboard_iface    = uhd::usrp::dboard_iface;      using special_props_t = uhd::usrp::dboard_iface_special_props_t; @@ -23,48 +24,43 @@ void export_dboard_iface()      using gpio_atr_reg_t  = uhd::usrp::gpio_atr::gpio_atr_reg_t;      using gpio_atr_mode_t = uhd::usrp::gpio_atr::gpio_atr_mode_t; -    bp::enum_<gpio_atr_reg_t>("gpio_atr_reg") +    py::enum_<gpio_atr_reg_t>(m, "gpio_atr_reg")          .value("ATR_REG_IDLE"       , gpio_atr_reg_t::ATR_REG_IDLE       )          .value("ATR_REG_TX_ONLY"    , gpio_atr_reg_t::ATR_REG_TX_ONLY    )          .value("ATR_REG_RX_ONLY"    , gpio_atr_reg_t::ATR_REG_RX_ONLY    )          .value("ATR_REG_FULL_DUPLEX", gpio_atr_reg_t::ATR_REG_FULL_DUPLEX)          ; -    bp::enum_<gpio_atr_mode_t>("gpio_atr_mode") +    py::enum_<gpio_atr_mode_t>(m, "gpio_atr_mode")          .value("MODE_ATR" , gpio_atr_mode_t::MODE_ATR )          .value("MODE_GPIO", gpio_atr_mode_t::MODE_GPIO)          ; -    bp::enum_<unit_t>("unit") +    py::enum_<unit_t>(m, "unit")          .value("UNIT_RX"  , unit_t::UNIT_RX  )          .value("UNIT_TX"  , unit_t::UNIT_TX  )          .value("UNIT_BOTH", unit_t::UNIT_BOTH)          ; -    bp::enum_<aux_dac_t>("aux_dac") +    py::enum_<aux_dac_t>(m, "aux_dac")          .value("AUX_DAC_A", aux_dac_t::AUX_DAC_A)          .value("AUX_DAC_B", aux_dac_t::AUX_DAC_B)          .value("AUX_DAC_C", aux_dac_t::AUX_DAC_C)          .value("AUX_DAC_D", aux_dac_t::AUX_DAC_D)          ; -    bp::enum_<aux_adc_t>("aux_adc") +    py::enum_<aux_adc_t>(m, "aux_adc")          .value("AUX_ADC_A", aux_adc_t::AUX_ADC_A)          .value("AUX_ADC_B", aux_adc_t::AUX_ADC_B)          ; -    bp::class_<special_props_t>("special_props") - +    py::class_<special_props_t>(m, "special_props")          // Properties -        .add_property("soft_clock_divider", &special_props_t::soft_clock_divider) -        .add_property("mangle_i2c_addrs"  , &special_props_t::mangle_i2c_addrs  ) +        .def_readwrite("soft_clock_divider", &special_props_t::soft_clock_divider) +        .def_readwrite("mangle_i2c_addrs"  , &special_props_t::mangle_i2c_addrs  )          ; -    bp::class_< -        dboard_iface, -        boost::shared_ptr<dboard_iface>, -        uhd::noncopyable>("dboard_iface", bp::no_init) - +    py::class_<dboard_iface, dboard_iface::sptr>(m, "dboard_iface")          // Methods          .def("get_special_props", &dboard_iface::get_special_props)          .def("write_aux_dac"    , &dboard_iface::write_aux_dac    ) diff --git a/host/lib/usrp/fe_connection_python.hpp b/host/lib/usrp/fe_connection_python.hpp index 29bba1746..d1304909e 100644 --- a/host/lib/usrp/fe_connection_python.hpp +++ b/host/lib/usrp/fe_connection_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -9,22 +10,22 @@  #include <uhd/usrp/fe_connection.hpp> -void export_fe_connection() +void export_fe_connection(py::module& m)  {      using fe_connection_t = uhd::usrp::fe_connection_t;      using sampling_t      = fe_connection_t::sampling_t; -    bp::enum_<sampling_t>("sampling") +    py::enum_<sampling_t>(m, "sampling")          .value("QUADRATURE", sampling_t::QUADRATURE)          .value("HETERODYNE", sampling_t::HETERODYNE)          .value("REAL"      , sampling_t::REAL      )          ; -    bp::class_<fe_connection_t> -        ("fe_connection", bp::init<sampling_t, bool, bool, bool, double>()) +    py::class_<fe_connection_t>(m, "fe_connection")          // Constructors -        .def(bp::init<const std::string&, double>()) +        .def(py::init<sampling_t, bool, bool, bool, double>()) +        .def(py::init<const std::string&, double>())          // Methods          .def("get_sampling_mode", &fe_connection_t::get_sampling_mode) diff --git a/host/lib/usrp/multi_usrp_python.hpp b/host/lib/usrp/multi_usrp_python.hpp index 6dc14f083..9bec4bb4f 100644 --- a/host/lib/usrp/multi_usrp_python.hpp +++ b/host/lib/usrp/multi_usrp_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -10,495 +11,167 @@  #include <uhd/types/device_addr.hpp>  #include <uhd/usrp/multi_usrp.hpp> -// -// Boost.Python needs overloaded API calls to be defined -// -static void set_rx_gain_0( -    uhd::usrp::multi_usrp *multi_usrp, double gain, const std::string &name, size_t chan = 0) -{ -    multi_usrp->set_rx_gain(gain, name, chan); -} - -static void set_rx_gain_1( -    uhd::usrp::multi_usrp *multi_usrp, double gain, size_t chan = 0) -{ -    multi_usrp->set_rx_gain(gain, chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_rx_gain_0, set_rx_gain_0, 3, 4); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_rx_gain_1, set_rx_gain_1, 2, 3); - -static void set_tx_gain_0( -    uhd::usrp::multi_usrp *multi_usrp, double gain, const std::string &name, size_t chan = 0) -{ -    multi_usrp->set_tx_gain(gain, name, chan); -} - -static void set_tx_gain_1( -    uhd::usrp::multi_usrp *multi_usrp, double gain, size_t chan = 0) -{ -    multi_usrp->set_tx_gain(gain, chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_tx_gain_0, set_tx_gain_0, 3, 4); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_tx_gain_1, set_tx_gain_1, 2, 3); - -static double get_rx_gain_0( -    uhd::usrp::multi_usrp *multi_usrp, const std::string &name, size_t chan = 0) -{ -    return multi_usrp->get_rx_gain(name, chan); -} - -static double get_rx_gain_1( -    uhd::usrp::multi_usrp *multi_usrp, size_t chan = 0) -{ -    return multi_usrp->get_rx_gain(chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_rx_gain_0, get_rx_gain_0, 2, 3); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_rx_gain_1, get_rx_gain_1, 1, 2); - -static double get_tx_gain_0( -    uhd::usrp::multi_usrp *multi_usrp, const std::string &name, size_t chan = 0) -{ -    return multi_usrp->get_tx_gain(name, chan); -} - -static double get_tx_gain_1( -    uhd::usrp::multi_usrp *multi_usrp, size_t chan = 0) -{ -    return multi_usrp->get_tx_gain(chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_tx_gain_0, get_tx_gain_0, 2, 3); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_tx_gain_1, get_tx_gain_1, 1, 2); - -static uhd::gain_range_t get_rx_gain_range_0( -    uhd::usrp::multi_usrp *multi_usrp, const std::string &name, size_t chan = 0) -{ -    return multi_usrp->get_rx_gain_range(name, chan); -} - -static uhd::gain_range_t get_rx_gain_range_1( -    uhd::usrp::multi_usrp *multi_usrp, size_t chan = 0) -{ -    return multi_usrp->get_rx_gain_range(chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_rx_gain_range_0, get_rx_gain_range_0, 2, 3); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_rx_gain_range_1, get_rx_gain_range_1, 1, 2); - -static uhd::gain_range_t get_tx_gain_range_0( -    uhd::usrp::multi_usrp *multi_usrp, const std::string &name, size_t chan = 0) -{ -    return multi_usrp->get_tx_gain_range(name, chan); -} - -static uhd::gain_range_t get_tx_gain_range_1( -    uhd::usrp::multi_usrp *multi_usrp, size_t chan = 0) -{ -    return multi_usrp->get_tx_gain_range(chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_tx_gain_range_0, get_tx_gain_range_0, 2, 3); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_get_tx_gain_range_1, get_tx_gain_range_1, 1, 2); - -static void set_rx_dc_offset_0( -    uhd::usrp::multi_usrp *multi_usrp, const bool enb, size_t chan = 0) -{ -    multi_usrp->set_rx_dc_offset(enb, chan); -} - -static void set_rx_dc_offset_1( -    uhd::usrp::multi_usrp *multi_usrp, const std::complex<double> &offset, size_t chan = 0) -{ -    multi_usrp->set_rx_dc_offset(offset, chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_rx_dc_offset_0, set_rx_dc_offset_0, 2, 3); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_rx_dc_offset_1, set_rx_dc_offset_1, 2, 3); - -static void set_tx_dc_offset_0( -    uhd::usrp::multi_usrp *multi_usrp, const bool enb, size_t chan = 0) -{ -    multi_usrp->set_tx_dc_offset(enb, chan); -} - -static void set_tx_dc_offset_1( -    uhd::usrp::multi_usrp *multi_usrp, const std::complex<double> &offset, size_t chan = 0) -{ -    multi_usrp->set_tx_dc_offset(offset, chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_tx_dc_offset_0, set_tx_dc_offset_0, 2, 3); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_tx_dc_offset_1, set_tx_dc_offset_1, 2, 3); - -static void set_rx_iq_balance_0( -    uhd::usrp::multi_usrp *multi_usrp, const bool enb, size_t chan = 0) -{ -    multi_usrp->set_rx_iq_balance(enb, chan); -} - -static void set_rx_iq_balance_1( -    uhd::usrp::multi_usrp *multi_usrp, const std::complex<double> &offset, size_t chan = 0) -{ -    multi_usrp->set_rx_iq_balance(offset, chan); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_rx_iq_balance_0, set_rx_iq_balance_0, 2, 3); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_rx_iq_balance_1, set_rx_iq_balance_1, 2, 3); - -static void set_gpio_attr_0(uhd::usrp::multi_usrp *multi_usrp, -                            const std::string &bank, -                            const std::string &attr, -                            const uint32_t value, -                            const uint32_t mask = 0xffffffff, -                            const size_t mboard = 0) -{ -    multi_usrp->set_gpio_attr(bank, attr, value, mask, mboard); -} - -static void set_gpio_attr_1(uhd::usrp::multi_usrp *multi_usrp, -                            const std::string &bank, -                            const std::string &attr, -                            const std::string &value, -                            const uint32_t mask = 0xffffffff, -                            const size_t mboard = 0) -{ -    multi_usrp->set_gpio_attr(bank, attr, value, mask, mboard); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_gpio_attr_0, set_gpio_attr_0, 4, 6); -BOOST_PYTHON_FUNCTION_OVERLOADS(overload_set_gpio_attr_1, set_gpio_attr_1, 4, 6); - -static void set_sync_source_0(uhd::usrp::multi_usrp *multi_usrp, -                              const std::string &clock_source, -                              const std::string &time_source) -{ -    multi_usrp->set_sync_source(clock_source, time_source); -} -static void set_sync_source_1(uhd::usrp::multi_usrp *multi_usrp, -                              const std::string &clock_source, -                              const std::string &time_source, -                              const size_t mboard) -{ -    multi_usrp->set_sync_source(clock_source, time_source, mboard); -} -static void set_sync_source_2(uhd::usrp::multi_usrp *multi_usrp, -                              const uhd::device_addr_t& sync_source) -{ -    multi_usrp->set_sync_source(sync_source); -} -static void set_sync_source_3(uhd::usrp::multi_usrp *multi_usrp, -                              const uhd::device_addr_t& sync_source, -                              const size_t mboard) -{ -    multi_usrp->set_sync_source(sync_source, mboard); -} - -// -// Boost.Python needs to know about default argument overloads -// - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_freq, get_rx_freq, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_rate, get_rx_rate, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_freq, set_rx_freq, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_rate, set_rx_rate, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_freq, get_tx_freq, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_rate, get_tx_rate, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_freq, set_tx_freq, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_rate, set_tx_rate, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_usrp_rx_info, get_usrp_rx_info, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_usrp_tx_info, get_usrp_tx_info, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_master_clock_rate, set_master_clock_rate, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_master_clock_rate, get_master_clock_rate, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_master_clock_rate_range, get_master_clock_rate_range, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_mboard_name, get_mboard_name, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_time_now, get_time_now, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_time_last_pps, get_time_last_pps, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_time_now, set_time_now, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_time_next_pps, set_time_next_pps, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_command_time, set_command_time, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_clear_command_time, clear_command_time, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_issue_stream_cmd, issue_stream_cmd, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_clock_config, set_clock_config, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_time_source, set_time_source, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_clock_source, set_clock_source, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_clock_source_out, set_clock_source_out, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_time_source_out, set_time_source_out, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_mboard_sensor, get_mboard_sensor, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_mboard_sensor_names, get_mboard_sensor_names, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_user_register, set_user_register, 2, 3); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_subdev_spec, set_rx_subdev_spec, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_subdev_spec, get_rx_subdev_spec, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_subdev_name, get_rx_subdev_name, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_rates, get_rx_rates, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_freq_range, get_rx_freq_range, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_fe_rx_freq_range, get_fe_rx_freq_range, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_lo_names, get_rx_lo_names, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_lo_source, get_rx_lo_source, 0, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_lo_source, set_rx_lo_source, 1, 3); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_lo_sources, get_rx_lo_sources, 0, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_lo_export_enabled, set_rx_lo_export_enabled, 1, 3); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_lo_export_enabled, get_rx_lo_export_enabled, 0, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_lo_freq, set_rx_lo_freq, 2, 3); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_lo_freq, get_rx_lo_freq, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_lo_freq_range, get_rx_lo_freq_range, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_normalized_rx_gain, set_normalized_rx_gain, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_normalized_rx_gain, get_normalized_rx_gain, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_agc, set_rx_agc, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_gain_names, get_rx_gain_names, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_antenna, set_rx_antenna, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_antenna, get_rx_antenna, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_antennas, get_rx_antennas, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_bandwidth, set_rx_bandwidth, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_bandwidth, get_rx_bandwidth, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_bandwidth_range, get_rx_bandwidth_range, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_dboard_iface, get_rx_dboard_iface, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_sensor, get_rx_sensor, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_sensor_names, get_rx_sensor_names, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_gain_profile, get_rx_gain_profile, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_rx_gain_profile, set_rx_gain_profile, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_rx_gain_profile_names, get_rx_gain_profile_names, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_subdev_spec, set_tx_subdev_spec, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_subdev_spec, get_tx_subdev_spec, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_subdev_name, get_tx_subdev_name, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_rates, get_tx_rates, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_freq_range, get_tx_freq_range, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_fe_tx_freq_range, get_fe_tx_freq_range, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_lo_names, get_tx_lo_names, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_lo_source, get_tx_lo_source, 0, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_lo_source, set_tx_lo_source, 1, 3); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_lo_sources, get_tx_lo_sources, 0, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_lo_export_enabled, set_tx_lo_export_enabled, 1, 3); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_lo_export_enabled, get_tx_lo_export_enabled, 0, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_lo_freq, set_tx_lo_freq, 2, 3); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_lo_freq, get_tx_lo_freq, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_lo_freq_range, get_tx_lo_freq_range, 1, 2); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_normalized_tx_gain, set_normalized_tx_gain, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_normalized_tx_gain, get_normalized_tx_gain, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_gain_names, get_tx_gain_names, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_antenna, set_tx_antenna, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_antenna, get_tx_antenna, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_antennas, get_tx_antennas, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_bandwidth, set_tx_bandwidth, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_bandwidth, get_tx_bandwidth, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_bandwidth_range, get_tx_bandwidth_range, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_dboard_iface, get_tx_dboard_iface, 0, 1); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_sensor, get_tx_sensor, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_sensor_names, get_tx_sensor_names, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_iq_balance, set_tx_iq_balance, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_gain_profile, get_tx_gain_profile, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_set_tx_gain_profile, set_tx_gain_profile, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_tx_gain_profile_names, get_tx_gain_profile_names, 0, 1); - - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_gpio_attr, get_gpio_attr, 2, 3); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_enumerate_registers, enumerate_registers, 0, 1); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_register_info, get_register_info, 1, 2); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_write_register, write_register, 3, 4); -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_read_register, read_register, 2, 3); - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(overload_get_filter_names, get_filter_names, 0, 1); - -void export_multi_usrp() +void export_multi_usrp(py::module& m)  {      using multi_usrp      = uhd::usrp::multi_usrp;      using register_info_t = multi_usrp::register_info_t; -    bp::class_<register_info_t>("register_info") -        .add_property("bitwidth", ®ister_info_t::bitwidth) -        .add_property("readable", ®ister_info_t::readable) -        .add_property("writable", ®ister_info_t::writable) -        ; +    const auto ALL_MBOARDS = multi_usrp::ALL_MBOARDS; +    const auto ALL_CHANS = multi_usrp::ALL_CHANS; +    const auto ALL_LOS = multi_usrp::ALL_LOS; -    bp::class_< -        multi_usrp, -        boost::shared_ptr<multi_usrp>, -        uhd::noncopyable>("multi_usrp", bp::no_init) +    py::class_<register_info_t>(m, "register_info") +        .def_readwrite("bitwidth", ®ister_info_t::bitwidth) +        .def_readwrite("readable", ®ister_info_t::readable) +        .def_readwrite("writable", ®ister_info_t::writable) +        ; -        .def("__init__", bp::make_constructor(&multi_usrp::make)) +    py::class_<multi_usrp, multi_usrp::sptr>(m, "multi_usrp") -        // Methods -        .def("make", &multi_usrp::make) -        .staticmethod("make") +        // Factory +        .def(py::init(&multi_usrp::make))          // General USRP methods -        .def("get_rx_freq"             , &multi_usrp::get_rx_freq, overload_get_rx_freq()) +        .def("get_rx_freq"             , &multi_usrp::get_rx_freq, py::arg("chan") = 0)          .def("get_rx_num_channels"     , &multi_usrp::get_rx_num_channels) -        .def("get_rx_rate"             , &multi_usrp::get_rx_rate, overload_get_rx_rate()) -        .def("get_rx_stream"           , &multi_usrp::get_rx_stream)  -        .def("set_rx_freq"             , &multi_usrp::set_rx_freq, overload_set_rx_freq()) -        .def("set_rx_gain"             , &set_rx_gain_0, overload_set_rx_gain_0()) -        .def("set_rx_gain"             , &set_rx_gain_1, overload_set_rx_gain_1()) -        .def("set_rx_rate"             , &multi_usrp::set_rx_rate, overload_set_rx_rate()) -        .def("get_tx_freq"             , &multi_usrp::get_tx_freq, overload_get_tx_freq()) +        .def("get_rx_rate"             , &multi_usrp::get_rx_rate, py::arg("chan") = 0) +        .def("get_rx_stream"           , &multi_usrp::get_rx_stream) +        .def("set_rx_freq"             , &multi_usrp::set_rx_freq, py::arg("tune_request"), py::arg("chan") = 0) +        .def("set_rx_gain"             , (void (multi_usrp::*)(double, const std::string&, size_t)) &multi_usrp::set_rx_gain, py::arg("gain"), py::arg("name"), py::arg("chan") = 0) +        .def("set_rx_gain"             , (void (multi_usrp::*)(double, size_t)) &multi_usrp::set_rx_gain, py::arg("gain"), py::arg("chan") = 0) +        .def("set_rx_rate"             , &multi_usrp::set_rx_rate, py::arg("rate"), py::arg("chan") = ALL_CHANS) +        .def("get_tx_freq"             , &multi_usrp::get_tx_freq, py::arg("chan") = 0)          .def("get_tx_num_channels"     , &multi_usrp::get_tx_num_channels) -        .def("get_tx_rate"             , &multi_usrp::get_tx_rate, overload_get_tx_rate()) +        .def("get_tx_rate"             , &multi_usrp::get_tx_rate, py::arg("chan") = 0)          .def("get_tx_stream"           , &multi_usrp::get_tx_stream) -        .def("set_tx_freq"             , &multi_usrp::set_tx_freq, overload_set_tx_freq()) -        .def("set_tx_gain"             , &set_tx_gain_0, overload_set_tx_gain_0()) -        .def("set_tx_gain"             , &set_tx_gain_1, overload_set_tx_gain_1()) -        .def("set_tx_rate"             , &multi_usrp::set_tx_rate, overload_set_tx_rate()) -        .def("get_usrp_rx_info"        , &multi_usrp::get_usrp_rx_info, overload_get_usrp_rx_info()) -        .def("get_usrp_tx_info"        , &multi_usrp::get_usrp_tx_info, overload_get_usrp_tx_info()) -        .def("set_master_clock_rate"   , &multi_usrp::set_master_clock_rate, overload_set_master_clock_rate()) -        .def("get_master_clock_rate"   , &multi_usrp::get_master_clock_rate, overload_get_master_clock_rate()) -        .def("get_master_clock_rate_range", &multi_usrp::get_master_clock_rate_range, overload_get_master_clock_rate_range()) +        .def("set_tx_freq"             , &multi_usrp::set_tx_freq, py::arg("tune_request"), py::arg("chan") = 0) +        .def("set_tx_gain"             , (void (multi_usrp::*)(double, const std::string&, size_t)) &multi_usrp::set_tx_gain, py::arg("gain"), py::arg("name"), py::arg("chan") = 0) +        .def("set_tx_gain"             , (void (multi_usrp::*)(double, size_t)) &multi_usrp::set_tx_gain, py::arg("gain"), py::arg("chan") = 0) +        .def("set_tx_rate"             , &multi_usrp::set_tx_rate, py::arg("rate"), py::arg("chan") = ALL_CHANS) +        .def("get_usrp_rx_info"        , &multi_usrp::get_usrp_rx_info, py::arg("chan") = 0) +        .def("get_usrp_tx_info"        , &multi_usrp::get_usrp_tx_info, py::arg("chan") = 0) +        .def("set_master_clock_rate"   , &multi_usrp::set_master_clock_rate, py::arg("rate"), py::arg("mboard") = ALL_MBOARDS) +        .def("get_master_clock_rate"   , &multi_usrp::get_master_clock_rate, py::arg("mboard") = 0) +        .def("get_master_clock_rate_range", &multi_usrp::get_master_clock_rate_range, py::arg("mboard") = ALL_MBOARDS)          .def("get_pp_string"           , &multi_usrp::get_pp_string) -        .def("get_mboard_name"         , &multi_usrp::get_mboard_name, overload_get_mboard_name()) -        .def("get_time_now"            , &multi_usrp::get_time_now, overload_get_time_now()) -        .def("get_time_last_pps"       , &multi_usrp::get_time_last_pps, overload_get_time_last_pps()) -        .def("set_time_now"            , &multi_usrp::set_time_now, overload_set_time_now()) -        .def("set_time_next_pps"       , &multi_usrp::set_time_next_pps, overload_set_time_next_pps()) +        .def("get_mboard_name"         , &multi_usrp::get_mboard_name, py::arg("mboard") = 0) +        .def("get_time_now"            , &multi_usrp::get_time_now, py::arg("mboard") = 0) +        .def("get_time_last_pps"       , &multi_usrp::get_time_last_pps, py::arg("mboard") = 0) +        .def("set_time_now"            , &multi_usrp::set_time_now, py::arg("time_spec"), py::arg("mboard") = ALL_MBOARDS) +        .def("set_time_next_pps"       , &multi_usrp::set_time_next_pps, py::arg("time_spec"), py::arg("mboard") = ALL_MBOARDS)          .def("set_time_unknown_pps"    , &multi_usrp::set_time_unknown_pps)          .def("get_time_synchronized"   , &multi_usrp::get_time_synchronized) -        .def("set_command_time"        , &multi_usrp::set_command_time, overload_set_command_time()) -        .def("clear_command_time"      , &multi_usrp::clear_command_time, overload_clear_command_time()) -        .def("issue_stream_cmd"        , &multi_usrp::issue_stream_cmd, overload_issue_stream_cmd()) -        .def("set_clock_config"        , &multi_usrp::set_clock_config, overload_set_clock_config()) -        .def("set_time_source"         , &multi_usrp::set_time_source, overload_set_time_source()) +        .def("set_command_time"        , &multi_usrp::set_command_time, py::arg("time_spec"), py::arg("mboard") = 0) +        .def("clear_command_time"      , &multi_usrp::clear_command_time, py::arg("mboard") = ALL_MBOARDS) +        .def("issue_stream_cmd"        , &multi_usrp::issue_stream_cmd, py::arg("rate"), py::arg("chan") = ALL_CHANS) +        .def("set_time_source"         , &multi_usrp::set_time_source, py::arg("source"), py::arg("mboard") = ALL_MBOARDS)          .def("get_time_source"         , &multi_usrp::get_time_source)          .def("get_time_sources"        , &multi_usrp::get_time_sources) -        .def("set_clock_source"        , &multi_usrp::set_clock_source, overload_set_clock_source()) +        .def("set_clock_source"        , &multi_usrp::set_clock_source, py::arg("source"), py::arg("mboard") = ALL_MBOARDS)          .def("get_clock_source"        , &multi_usrp::get_clock_source)          .def("get_clock_sources"       , &multi_usrp::get_clock_sources) -        .def("set_sync_source"         , &set_sync_source_0) -        .def("set_sync_source"         , &set_sync_source_1) -        .def("set_sync_source"         , &set_sync_source_2) -        .def("set_sync_source"         , &set_sync_source_3) +        .def("set_sync_source"         , (void (multi_usrp::*)(const std::string&, const std::string&, size_t)) &multi_usrp::set_sync_source, py::arg("clock_source"), py::arg("time_source"), py::arg("mboard") = ALL_MBOARDS) +        .def("set_sync_source"         , (void (multi_usrp::*)(const uhd::device_addr_t&, size_t)) &multi_usrp::set_sync_source, py::arg("sync_source"), py::arg("mboard") = ALL_MBOARDS)          .def("get_sync_source"         , &multi_usrp::get_sync_source)          .def("get_sync_sources"        , &multi_usrp::get_sync_sources) -        .def("set_clock_source_out"    , &multi_usrp::set_clock_source_out, overload_set_clock_source_out()) -        .def("set_time_source_out"     , &multi_usrp::set_time_source_out, overload_set_time_source_out()) +        .def("set_clock_source_out"    , &multi_usrp::set_clock_source_out, py::arg("enb"), py::arg("mboard") = ALL_MBOARDS) +        .def("set_time_source_out"     , &multi_usrp::set_time_source_out, py::arg("enb"), py::arg("mboard") = ALL_MBOARDS)          .def("get_num_mboards"         , &multi_usrp::get_num_mboards) -        .def("get_mboard_sensor"       , &multi_usrp::get_mboard_sensor, overload_get_mboard_sensor()) -        .def("get_mboard_sensor_names" , &multi_usrp::get_mboard_sensor_names, overload_get_mboard_sensor_names()) -        .def("set_user_register"       , &multi_usrp::set_user_register, overload_set_user_register()) +        .def("get_mboard_sensor"       , &multi_usrp::get_mboard_sensor, py::arg("name"), py::arg("mboard") = 0) +        .def("get_mboard_sensor_names" , &multi_usrp::get_mboard_sensor_names, py::arg("mboard") = 0) +        .def("set_user_register"       , &multi_usrp::set_user_register, py::arg("addr"), py::arg("data"), py::arg("mboard") = ALL_MBOARDS)          // RX methods -        .def("set_rx_subdev_spec"      , &multi_usrp::set_rx_subdev_spec, overload_set_rx_subdev_spec()) -        .def("get_rx_subdev_spec"      , &multi_usrp::get_rx_subdev_spec, overload_get_rx_subdev_spec()) -        .def("get_rx_subdev_name"      , &multi_usrp::get_rx_subdev_name, overload_get_rx_subdev_name()) -        .def("get_rx_rates"            , &multi_usrp::get_rx_rates, overload_get_rx_rates()) -        .def("get_rx_freq_range"       , &multi_usrp::get_rx_freq_range, overload_get_rx_freq_range()) -        .def("get_fe_rx_freq_range"    , &multi_usrp::get_fe_rx_freq_range, overload_get_fe_rx_freq_range()) -        .def("get_rx_lo_names"         , &multi_usrp::get_rx_lo_names, overload_get_rx_lo_names()) -        .def("set_rx_lo_source"        , &multi_usrp::set_rx_lo_source, overload_set_rx_lo_source()) -        .def("get_rx_lo_source"        , &multi_usrp::get_rx_lo_source, overload_get_rx_lo_source()) -        .def("get_rx_lo_sources"       , &multi_usrp::get_rx_lo_sources, overload_get_rx_lo_sources()) -        .def("set_rx_lo_export_enabled", &multi_usrp::set_rx_lo_export_enabled, overload_set_rx_lo_export_enabled()) -        .def("get_rx_lo_export_enabled", &multi_usrp::get_rx_lo_export_enabled, overload_get_rx_lo_export_enabled()) -        .def("set_rx_lo_freq"          , &multi_usrp::set_rx_lo_freq, overload_set_rx_lo_freq()) -        .def("get_rx_lo_freq"          , &multi_usrp::get_rx_lo_freq, overload_get_rx_lo_freq()) -        .def("get_rx_lo_freq_range"    , &multi_usrp::get_rx_lo_freq_range, overload_get_rx_lo_freq_range()) -        .def("set_normalized_rx_gain"  , &multi_usrp::set_normalized_rx_gain, overload_set_normalized_rx_gain()) -        .def("get_normalized_rx_gain"  , &multi_usrp::get_normalized_rx_gain, overload_get_normalized_rx_gain()) -        .def("set_rx_agc"              , &multi_usrp::set_rx_agc, overload_set_rx_agc()) -        .def("get_rx_gain"             , &get_rx_gain_0, overload_get_rx_gain_0()) -        .def("get_rx_gain"             , &get_rx_gain_1, overload_get_rx_gain_1()) -        .def("get_rx_gain_range"       , &get_rx_gain_range_0, overload_get_rx_gain_range_0()) -        .def("get_rx_gain_range"       , &get_rx_gain_range_1, overload_get_rx_gain_range_1()) -        .def("get_rx_gain_names"       , &multi_usrp::get_rx_gain_names, overload_get_rx_gain_names()) -        .def("set_rx_antenna"          , &multi_usrp::set_rx_antenna, overload_set_rx_antenna()) -        .def("get_rx_antenna"          , &multi_usrp::get_rx_antenna, overload_get_rx_antenna()) -        .def("get_rx_antennas"         , &multi_usrp::get_rx_antennas, overload_get_rx_antennas()) -        .def("set_rx_bandwidth"        , &multi_usrp::set_rx_bandwidth, overload_set_rx_bandwidth()) -        .def("get_rx_bandwidth"        , &multi_usrp::get_rx_bandwidth, overload_get_rx_bandwidth()) -        .def("get_rx_bandwidth_range"  , &multi_usrp::get_rx_bandwidth_range, overload_get_rx_bandwidth_range()) -        .def("get_rx_dboard_iface"     , &multi_usrp::get_rx_dboard_iface, overload_get_rx_dboard_iface()) -        .def("get_rx_sensor"           , &multi_usrp::get_rx_sensor, overload_get_rx_sensor()) -        .def("get_rx_sensor_names"     , &multi_usrp::get_rx_sensor_names, overload_get_rx_sensor_names()) -        .def("set_rx_dc_offset"        , &set_rx_dc_offset_0, overload_set_rx_dc_offset_0()) -        .def("set_rx_dc_offset"        , &set_rx_dc_offset_1, overload_set_rx_dc_offset_1()) -        .def("set_rx_iq_balance"       , &set_rx_iq_balance_0, overload_set_rx_iq_balance_0()) -        .def("set_rx_iq_balance"       , &set_rx_iq_balance_1, overload_set_rx_iq_balance_1()) -        .def("get_rx_gain_profile"     , &multi_usrp::get_rx_gain_profile, overload_get_rx_gain_profile()) -        .def("set_rx_gain_profile"     , &multi_usrp::set_rx_gain_profile, overload_set_rx_gain_profile()) -        .def("get_rx_gain_profile_names", &multi_usrp::get_rx_gain_profile_names, overload_get_rx_gain_profile_names()) +        .def("set_rx_subdev_spec"      , &multi_usrp::set_rx_subdev_spec, py::arg("spec"), py::arg("mboard") = ALL_MBOARDS) +        .def("get_rx_subdev_spec"      , &multi_usrp::get_rx_subdev_spec, py::arg("mboard") = 0) +        .def("get_rx_subdev_name"      , &multi_usrp::get_rx_subdev_name, py::arg("chan") = 0) +        .def("get_rx_rates"            , &multi_usrp::get_rx_rates, py::arg("chan") = 0) +        .def("get_rx_freq_range"       , &multi_usrp::get_rx_freq_range, py::arg("chan") = 0) +        .def("get_fe_rx_freq_range"    , &multi_usrp::get_fe_rx_freq_range, py::arg("chan") = 0) +        .def("get_rx_lo_names"         , &multi_usrp::get_rx_lo_names, py::arg("chan") = 0) +        .def("set_rx_lo_source"        , &multi_usrp::set_rx_lo_source, py::arg("src"), py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("get_rx_lo_source"        , &multi_usrp::get_rx_lo_source, py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("get_rx_lo_sources"       , &multi_usrp::get_rx_lo_sources, py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("set_rx_lo_export_enabled", &multi_usrp::set_rx_lo_export_enabled, py::arg("enb"), py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("get_rx_lo_export_enabled", &multi_usrp::get_rx_lo_export_enabled, py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("set_rx_lo_freq"          , &multi_usrp::set_rx_lo_freq, py::arg("freq"), py::arg("name"), py::arg("chan") = 0) +        .def("get_rx_lo_freq"          , &multi_usrp::get_rx_lo_freq, py::arg("name"), py::arg("chan") = 0) +        .def("get_rx_lo_freq_range"    , &multi_usrp::get_rx_lo_freq_range, py::arg("name"), py::arg("chan") = 0) +        .def("set_normalized_rx_gain"  , &multi_usrp::set_normalized_rx_gain, py::arg("gain"), py::arg("chan") = 0) +        .def("get_normalized_rx_gain"  , &multi_usrp::get_normalized_rx_gain, py::arg("chan") = 0) +        .def("set_rx_agc"              , &multi_usrp::set_rx_agc, py::arg("enable"), py::arg("chan") = 0) +        .def("get_rx_gain"             , (double (multi_usrp::*)(const std::string&, size_t)) &multi_usrp::get_rx_gain, py::arg("name"), py::arg("chan") = 0) +        .def("get_rx_gain"             , (double (multi_usrp::*)(size_t)) &multi_usrp::get_rx_gain, py::arg("chan") = 0) +        .def("get_rx_gain_range"       , (uhd::gain_range_t (multi_usrp::*)(const std::string&, size_t)) &multi_usrp::get_rx_gain_range, py::arg("name"), py::arg("chan") = 0) +        .def("get_rx_gain_range"       , (uhd::gain_range_t (multi_usrp::*)(size_t)) &multi_usrp::get_rx_gain_range, py::arg("chan") = 0) +        .def("get_rx_gain_names"       , &multi_usrp::get_rx_gain_names, py::arg("chan") = 0) +        .def("set_rx_antenna"          , &multi_usrp::set_rx_antenna, py::arg("ant"), py::arg("chan") = 0) +        .def("get_rx_antenna"          , &multi_usrp::get_rx_antenna, py::arg("chan") = 0) +        .def("get_rx_antennas"         , &multi_usrp::get_rx_antennas, py::arg("chan") = 0) +        .def("set_rx_bandwidth"        , &multi_usrp::set_rx_bandwidth, py::arg("bandwidth"), py::arg("chan") = 0) +        .def("get_rx_bandwidth"        , &multi_usrp::get_rx_bandwidth, py::arg("chan") = 0) +        .def("get_rx_bandwidth_range"  , &multi_usrp::get_rx_bandwidth_range, py::arg("chan") = 0) +        .def("get_rx_dboard_iface"     , &multi_usrp::get_rx_dboard_iface, py::arg("chan") = 0) +        .def("get_rx_sensor"           , &multi_usrp::get_rx_sensor, py::arg("name"), py::arg("chan") = 0) +        .def("get_rx_sensor_names"     , &multi_usrp::get_rx_sensor_names, py::arg("chan") = 0) +        .def("set_rx_dc_offset"        , (void (multi_usrp::*)(const std::complex<double>&, size_t)) &multi_usrp::set_rx_dc_offset, py::arg("offset"), py::arg("chan") = 0) +        .def("set_rx_dc_offset"        , (void (multi_usrp::*)(bool, size_t)) &multi_usrp::set_rx_dc_offset, py::arg("enb"), py::arg("chan") = 0) +        .def("set_rx_iq_balance"       , (void (multi_usrp::*)(const std::complex<double>&, size_t)) &multi_usrp::set_rx_iq_balance, py::arg("correction"), py::arg("chan") = 0) +        .def("set_rx_iq_balance"       , (void (multi_usrp::*)(bool, size_t)) &multi_usrp::set_rx_dc_offset, py::arg("enb"), py::arg("chan") = 0) +        .def("get_rx_gain_profile"     , &multi_usrp::get_rx_gain_profile, py::arg("chan") = 0) +        .def("set_rx_gain_profile"     , &multi_usrp::set_rx_gain_profile, py::arg("profile"), py::arg("chan") = 0) +        .def("get_rx_gain_profile_names", &multi_usrp::get_rx_gain_profile_names, py::arg("chan") = 0)          // TX methods -        .def("set_tx_subdev_spec"      , &multi_usrp::set_tx_subdev_spec, overload_set_tx_subdev_spec()) -        .def("get_tx_subdev_spec"      , &multi_usrp::get_tx_subdev_spec, overload_get_tx_subdev_spec()) -        .def("get_tx_subdev_name"      , &multi_usrp::get_tx_subdev_name, overload_get_tx_subdev_name()) -        .def("get_tx_rates"            , &multi_usrp::get_tx_rates, overload_get_rx_rates()) -        .def("get_tx_freq_range"       , &multi_usrp::get_tx_freq_range, overload_get_tx_freq_range()) -        .def("get_fe_tx_freq_range"    , &multi_usrp::get_fe_tx_freq_range, overload_get_fe_tx_freq_range()) -        .def("get_tx_lo_names"         , &multi_usrp::get_tx_lo_names, overload_get_tx_lo_names()) -        .def("set_tx_lo_source"        , &multi_usrp::set_tx_lo_source, overload_set_tx_lo_source()) -        .def("get_tx_lo_source"        , &multi_usrp::get_tx_lo_source, overload_get_tx_lo_source()) -        .def("get_tx_lo_sources"       , &multi_usrp::get_tx_lo_sources, overload_get_tx_lo_sources()) -        .def("set_tx_lo_export_enabled", &multi_usrp::set_tx_lo_export_enabled, overload_set_tx_lo_export_enabled()) -        .def("get_tx_lo_export_enabled", &multi_usrp::get_tx_lo_export_enabled, overload_get_tx_lo_export_enabled()) -        .def("set_tx_lo_freq"          , &multi_usrp::set_tx_lo_freq, overload_set_tx_lo_freq()) -        .def("get_tx_lo_freq"          , &multi_usrp::get_tx_lo_freq, overload_get_tx_lo_freq()) -        .def("get_tx_lo_freq_range"    , &multi_usrp::get_tx_lo_freq_range, overload_get_tx_lo_freq_range()) -        .def("set_normalized_tx_gain"  , &multi_usrp::set_normalized_tx_gain, overload_set_normalized_tx_gain()) -        .def("get_normalized_tx_gain"  , &multi_usrp::get_normalized_tx_gain, overload_get_normalized_tx_gain()) -        .def("get_tx_gain"             , &get_tx_gain_0, overload_get_tx_gain_0()) -        .def("get_tx_gain"             , &get_tx_gain_1, overload_get_tx_gain_1()) -        .def("get_tx_gain_range"       , &get_tx_gain_range_0, overload_get_tx_gain_range_0()) -        .def("get_tx_gain_range"       , &get_tx_gain_range_1, overload_get_tx_gain_range_1()) -        .def("get_tx_gain_names"       , &multi_usrp::get_tx_gain_names, overload_get_tx_gain_names()) -        .def("set_tx_antenna"          , &multi_usrp::set_tx_antenna, overload_set_tx_antenna()) -        .def("get_tx_antenna"          , &multi_usrp::get_tx_antenna, overload_get_tx_antenna()) -        .def("get_tx_antennas"         , &multi_usrp::get_tx_antennas, overload_get_tx_antennas()) -        .def("set_tx_bandwidth"        , &multi_usrp::set_tx_bandwidth, overload_set_tx_bandwidth()) -        .def("get_tx_bandwidth"        , &multi_usrp::get_tx_bandwidth, overload_get_tx_bandwidth()) -        .def("get_tx_bandwidth_range"  , &multi_usrp::get_tx_bandwidth_range, overload_get_tx_bandwidth_range()) -        .def("get_tx_dboard_iface"     , &multi_usrp::get_tx_dboard_iface, overload_get_tx_dboard_iface()) -        .def("get_tx_sensor"           , &multi_usrp::get_tx_sensor, overload_get_tx_sensor()) -        .def("get_tx_sensor_names"     , &multi_usrp::get_tx_sensor_names, overload_get_tx_sensor_names()) -        .def("set_tx_dc_offset"        , &set_tx_dc_offset_0, overload_set_tx_dc_offset_0()) -        .def("set_tx_dc_offset"        , &set_tx_dc_offset_1, overload_set_tx_dc_offset_1()) -        .def("set_tx_iq_balance"       , &multi_usrp::set_tx_iq_balance, overload_set_tx_iq_balance()) -        .def("get_tx_gain_profile"     , &multi_usrp::get_tx_gain_profile, overload_get_tx_gain_profile()) -        .def("set_tx_gain_profile"     , &multi_usrp::set_tx_gain_profile, overload_set_tx_gain_profile()) -        .def("get_tx_gain_profile_names", &multi_usrp::get_tx_gain_profile_names, overload_get_tx_gain_profile_names()) +        .def("set_tx_subdev_spec"      , &multi_usrp::set_tx_subdev_spec, py::arg("spec"), py::arg("mboard") = ALL_MBOARDS) +        .def("get_tx_subdev_spec"      , &multi_usrp::get_tx_subdev_spec, py::arg("mboard") = 0) +        .def("get_tx_subdev_name"      , &multi_usrp::get_tx_subdev_name, py::arg("chan") = 0) +        .def("get_tx_rates"            , &multi_usrp::get_tx_rates, py::arg("chan") = 0) +        .def("get_tx_freq_range"       , &multi_usrp::get_tx_freq_range, py::arg("chan") = 0) +        .def("get_fe_tx_freq_range"    , &multi_usrp::get_fe_tx_freq_range, py::arg("chan") = 0) +        .def("get_tx_lo_names"         , &multi_usrp::get_tx_lo_names, py::arg("chan") = 0) +        .def("set_tx_lo_source"        , &multi_usrp::set_tx_lo_source, py::arg("src"), py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("get_tx_lo_source"        , &multi_usrp::get_tx_lo_source, py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("get_tx_lo_sources"       , &multi_usrp::get_tx_lo_sources, py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("set_tx_lo_export_enabled", &multi_usrp::set_tx_lo_export_enabled, py::arg("enb"), py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("get_tx_lo_export_enabled", &multi_usrp::get_tx_lo_export_enabled, py::arg("name") = ALL_LOS, py::arg("chan") = 0) +        .def("set_tx_lo_freq"          , &multi_usrp::set_tx_lo_freq, py::arg("freq"), py::arg("name"), py::arg("chan") = 0) +        .def("get_tx_lo_freq"          , &multi_usrp::get_tx_lo_freq, py::arg("name"), py::arg("chan") = 0) +        .def("get_tx_lo_freq_range"    , &multi_usrp::get_tx_lo_freq_range, py::arg("name"), py::arg("chan") = 0) +        .def("set_normalized_tx_gain"  , &multi_usrp::set_normalized_tx_gain, py::arg("gain"), py::arg("chan") = 0) +        .def("get_normalized_tx_gain"  , &multi_usrp::get_normalized_tx_gain, py::arg("chan") = 0) +        .def("get_tx_gain"             , (double (multi_usrp::*)(const std::string&, size_t)) &multi_usrp::get_tx_gain, py::arg("name"), py::arg("chan") = 0) +        .def("get_tx_gain"             , (double (multi_usrp::*)(size_t)) &multi_usrp::get_tx_gain, py::arg("chan") = 0) +        .def("get_tx_gain_range"       , (uhd::gain_range_t (multi_usrp::*)(const std::string&, size_t)) &multi_usrp::get_tx_gain_range, py::arg("name"), py::arg("chan") = 0) +        .def("get_tx_gain_range"       , (uhd::gain_range_t (multi_usrp::*)(size_t)) &multi_usrp::get_tx_gain_range, py::arg("chan") = 0) +        .def("get_tx_gain_names"       , &multi_usrp::get_tx_gain_names, py::arg("chan") = 0) +        .def("set_tx_antenna"          , &multi_usrp::set_tx_antenna, py::arg("ant"), py::arg("chan") = 0) +        .def("get_tx_antenna"          , &multi_usrp::get_tx_antenna, py::arg("chan") = 0) +        .def("get_tx_antennas"         , &multi_usrp::get_tx_antennas, py::arg("chan") = 0) +        .def("set_tx_bandwidth"        , &multi_usrp::set_tx_bandwidth, py::arg("bandwidth"), py::arg("chan") = 0) +        .def("get_tx_bandwidth"        , &multi_usrp::get_tx_bandwidth, py::arg("chan") = 0) +        .def("get_tx_bandwidth_range"  , &multi_usrp::get_tx_bandwidth_range, py::arg("chan") = 0) +        .def("get_tx_dboard_iface"     , &multi_usrp::get_tx_dboard_iface, py::arg("chan") = 0) +        .def("get_tx_sensor"           , &multi_usrp::get_tx_sensor, py::arg("name"), py::arg("chan") = 0) +        .def("get_tx_sensor_names"     , &multi_usrp::get_tx_sensor_names, py::arg("chan") = 0) +        .def("set_tx_dc_offset"        , (void (multi_usrp::*)(const std::complex<double>&, size_t)) &multi_usrp::set_tx_dc_offset, py::arg("offset"), py::arg("chan") = 0) +        .def("set_tx_iq_balance"       , (void (multi_usrp::*)(const std::complex<double>&, size_t)) &multi_usrp::set_tx_iq_balance, py::arg("correction"), py::arg("chan") = 0) +        .def("get_tx_gain_profile"     , &multi_usrp::get_tx_gain_profile, py::arg("chan") = 0) +        .def("set_tx_gain_profile"     , &multi_usrp::set_tx_gain_profile, py::arg("profile"), py::arg("chan") = 0) +        .def("get_tx_gain_profile_names", &multi_usrp::get_tx_gain_profile_names, py::arg("chan") = 0)          // GPIO methods          .def("get_gpio_banks"          , &multi_usrp::get_gpio_banks) -        .def("set_gpio_attr"           , &set_gpio_attr_0, overload_set_gpio_attr_0()) -        .def("set_gpio_attr"           , &set_gpio_attr_1, overload_set_gpio_attr_1()) -        .def("get_gpio_attr"           , &multi_usrp::get_gpio_attr, overload_get_gpio_attr()) -        .def("enumerate_registers"     , &multi_usrp::enumerate_registers, overload_enumerate_registers()) -        .def("get_register_info"       , &multi_usrp::get_register_info, overload_get_register_info()) -        .def("write_register"          , &multi_usrp::write_register, overload_write_register()) -        .def("read_register"           , &multi_usrp::read_register, overload_read_register()) +        .def("set_gpio_attr"           , (void (multi_usrp::*)(const std::string&, const std::string&, const std::string&, const uint32_t, const size_t)) &multi_usrp::set_gpio_attr, py::arg("bank"), py::arg("attr"), py::arg("value"), py::arg("mask") = 0xffffffff, py::arg("mboard") = 0) +        .def("set_gpio_attr"           , (void (multi_usrp::*)(const std::string&, const std::string&, const uint32_t, const uint32_t, const size_t)) &multi_usrp::set_gpio_attr, py::arg("bank"), py::arg("attr"), py::arg("value"), py::arg("mask") = 0xffffffff, py::arg("mboard") = 0) +        .def("get_gpio_attr"           , &multi_usrp::get_gpio_attr, py::arg("bank"), py::arg("attr"), py::arg("mboard") = 0) +        .def("enumerate_registers"     , &multi_usrp::enumerate_registers, py::arg("mboard") = 0) +        .def("get_register_info"       , &multi_usrp::get_register_info, py::arg("path"), py::arg("mboard") = 0) +        .def("write_register"          , &multi_usrp::write_register, py::arg("path"), py::arg("field"), py::arg("value"), py::arg("mboard") = 0) +        .def("read_register"           , &multi_usrp::read_register, py::arg("path"), py::arg("field"), py::arg("mboard") = 0)          // Filter API methods -        .def("get_filter_names"        , &multi_usrp::get_filter_names, overload_get_filter_names()) +        .def("get_filter_names"        , &multi_usrp::get_filter_names, py::arg("search_mask") = "")          .def("get_filter"              , &multi_usrp::get_filter)          .def("set_filter"              , &multi_usrp::set_filter)          ; diff --git a/host/lib/usrp/subdev_spec_python.hpp b/host/lib/usrp/subdev_spec_python.hpp index ed91099f9..61a517a6f 100644 --- a/host/lib/usrp/subdev_spec_python.hpp +++ b/host/lib/usrp/subdev_spec_python.hpp @@ -1,5 +1,6 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // @@ -9,24 +10,20 @@  #include <uhd/usrp/subdev_spec.hpp> -void export_subdev_spec() +void export_subdev_spec(py::module& m)  {      using subdev_spec_pair_t = uhd::usrp::subdev_spec_pair_t;      using subdev_spec_t      = uhd::usrp::subdev_spec_t; -    bp::class_<subdev_spec_pair_t> -        ("subdev_spec_pair", bp::init<const std::string&, const std::string &>()) - +    py::class_<subdev_spec_pair_t> (m, "subdev_spec_pair") +        .def(py::init<const std::string&, const std::string &>())          // Properties -        .add_property("db_name", &subdev_spec_pair_t::db_name) -        .add_property("sd_name", &subdev_spec_pair_t::sd_name) +        .def_readwrite("db_name", &subdev_spec_pair_t::db_name) +        .def_readwrite("sd_name", &subdev_spec_pair_t::sd_name)          ; -    bp::class_<std::vector<subdev_spec_pair_t> >("subdev_spec_vector") -        .def(bp::vector_indexing_suite<std::vector<subdev_spec_pair_t> >()); - -    bp::class_<subdev_spec_t, bp::bases<std::vector<subdev_spec_pair_t> > > -        ("subdev_spec", bp::init<const std::string &>()) +    py::class_<subdev_spec_t>(m, "subdev_spec") +        .def(py::init<const std::string &>())          // Methods          .def("__str__",   &subdev_spec_t::to_pp_string) diff --git a/host/lib/utils/gil_release_python.hpp b/host/lib/utils/gil_release_python.hpp deleted file mode 100644 index 287ba240e..000000000 --- a/host/lib/utils/gil_release_python.hpp +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -//! RAII-style GIL release method -// -// To release the GIL using this method, simply instantiate this class in the -// scope that needs to release the GIL. -// -// Note that using this class assumes that threads have already been -// initialized. See also https://docs.python.org/3.5/c-api/init.html for more -// documentation on Python initialization and threads. -class scoped_gil_release -{ -public: -    inline scoped_gil_release() -    { -        _thread_state = PyEval_SaveThread(); -    } - -    inline ~scoped_gil_release() -    { -        PyEval_RestoreThread(_thread_state); -        _thread_state = nullptr; -    } - -private: -    PyThreadState* _thread_state; -}; diff --git a/host/python/CMakeLists.txt b/host/python/CMakeLists.txt index 07791de55..ec2c80fd4 100644 --- a/host/python/CMakeLists.txt +++ b/host/python/CMakeLists.txt @@ -16,6 +16,14 @@ PYTHON_CHECK_MODULE(  # Get include dirs  include_directories(${PYTHON_INCLUDE_DIRS}) +set(PYBIND11_INCLUDE_DIR +    "${CMAKE_SOURCE_DIR}/lib/deps/pybind11/include" +    CACHE +    STRING +    "Location of PyBind11 includes" +) +message(STATUS "${PYBIND11_INCLUDE_DIR}") +include_directories(${PYBIND11_INCLUDE_DIR})  execute_process(      COMMAND "${PYTHON_EXECUTABLE}" -c      "from __future__ import print_function\ntry:\n import numpy\n import os\n inc_path = numpy.get_include()\n if os.path.exists(os.path.join(inc_path, 'numpy', 'arrayobject.h')):\n  print(inc_path, end='')\nexcept:\n pass" @@ -26,9 +34,10 @@ add_library(pyuhd SHARED pyuhd.cpp)  target_include_directories(pyuhd PUBLIC      ${PYTHON_NUMPY_INCLUDE_DIR}      ${CMAKE_SOURCE_DIR}/lib +    ${PYBIND11_INCLUDE_DIR}  ) -target_link_libraries(pyuhd ${BOOST_PYTHON_LIBRARY} ${Boost_LIBRARIES} ${PYTHON_LIBRARY} uhd) +target_link_libraries(pyuhd ${Boost_LIBRARIES} ${PYTHON_LIBRARY} uhd)  # Copy pyuhd library to the staging directory  if(WIN32)      set(PYUHD_LIBRARY_NAME libpyuhd.pyd) diff --git a/host/python/pyuhd.cpp b/host/python/pyuhd.cpp index e0f35d929..16badbe8c 100644 --- a/host/python/pyuhd.cpp +++ b/host/python/pyuhd.cpp @@ -1,29 +1,21 @@  //  // Copyright 2017-2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  // -#include <boost/shared_ptr.hpp> -#include <boost/python.hpp> -#include <boost/python/stl_iterator.hpp> -#include <boost/python/suite/indexing/vector_indexing_suite.hpp> - -/* -This solution was adapted from an Issue posted to the Boost.Python Github. -https://github.com/boostorg/python/pull/159/files -*/ -#if (BOOST_VERSION >= 106400) && (BOOST_VERSION < 106600) -#warning overriding broken boost python implementation of BOOST_PYTHON_MODULE_INIT -#  define BOOST_PYTHON_MODULE_INIT(name)                       \ -  void BOOST_PP_CAT(init_module_,name)();                      \ -extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name) -#endif +#include <pybind11/pybind11.h>  #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION  #include <numpy/arrayobject.h> -namespace bp = boost::python; +namespace py = pybind11; + +// Allow boost::shared_ptr<T> to be a holder class of an object (PyBind11 +// supports std::shared_ptr and std::unique_ptr out of the box) +#include <boost/shared_ptr.hpp> +PYBIND11_DECLARE_HOLDER_TYPE(T, boost::shared_ptr<T>);  #include "stream_python.hpp" @@ -40,81 +32,6 @@ namespace bp = boost::python;  #include "usrp/subdev_spec_python.hpp"  #include "usrp/multi_usrp_python.hpp" -// Converter for std::vector / std::list arguments from python iterables -struct iterable_converter -{ -    template <typename Container> -    iterable_converter& from_python() -    { -        bp::converter::registry::push_back( -            &iterable_converter::convertible, -            &iterable_converter::construct<Container>, -            bp::type_id<Container>() -        ); -        return *this; -    } - -    static void* convertible(PyObject* object) -    { -        return PyObject_GetIter(object) ? object : NULL; -    } - -    template <typename Container> -    static void construct( -        PyObject* object, -        bp::converter::rvalue_from_python_stage1_data* data) -    { -        // Object is a borrowed reference, so create a handle indicting it is -        // borrowed for proper reference counting. -        bp::handle<> handle(bp::borrowed(object)); - -        // Obtain a handle to the memory block that the converter has -        // allocated for the C++ type. -        typedef bp::converter::rvalue_from_python_storage<Container> storage_type; - -        void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes; -        typedef bp::stl_input_iterator<typename Container::value_type> iterator; - -        // Allocate the C++ type into the converter's memory block, and assign -        // its handle to the converter's convertible variable.  The C++ -        // container is populated by passing the begin and end iterators of -        // the python object to the container's constructor. -        new (storage) Container( -          iterator(bp::object(handle)), // begin -          iterator()                    // end -        ); - -        data->convertible = storage; -    } -}; - -template<typename Dtype1, typename Dtype2> -struct uhd_to_python_dict -{ -    static PyObject* convert(uhd::dict<Dtype1, Dtype2> const& input_dict) -    { -        bp::dict py_dict; -        for (const auto& key: input_dict.keys()){ -            py_dict[key] = input_dict[key]; -        } -        return bp::incref(py_dict.ptr()); -    } - -}; - -template<typename Container> -struct iterable_to_python_list -{ -    static PyObject* convert(Container const& input) -    { -        bp::list py_list; -        for (const auto& element: input){ -            py_list.append(element); -        } -        return bp::incref(py_list.ptr()); -    } -}; -  // We need this hack because import_array() returns NULL  // for newer Python versions.  // This function is also necessary because it ensures access to the C API @@ -132,80 +49,32 @@ void init_numpy()  }  #endif -BOOST_PYTHON_MODULE(libpyuhd) +PYBIND11_MODULE(libpyuhd, m)  {      // Initialize the numpy C API      // (otherwise we will see segmentation faults)      init_numpy(); -    bp::object package = bp::scope(); -    package.attr("__path__") = "libpyuhd"; - -    // Declare converters -    iterable_converter() -        .from_python<std::vector<double> >() -        .from_python<std::vector<int> >() -        .from_python<std::vector<size_t> >() -        ; - -    bp::to_python_converter< -        uhd::dict<std::string, std::string>, -        uhd_to_python_dict<std::string, std::string>, false >(); -    bp::to_python_converter< -        std::vector<std::string>, -        iterable_to_python_list<std::vector<std::string> >, false >(); -      // Register types submodule -    { -        bp::object types_module( -            bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.types"))) -        ); -        bp::scope().attr("types") = types_module; -        bp::scope io_scope = types_module; - -        bp::implicitly_convertible<std::string, uhd::device_addr_t>(); - -        export_types(); -        export_time_spec(); -        export_spi_config(); -        export_metadata(); -        export_sensors(); -        export_tune(); +    auto types_module = m.def_submodule("types", "UHD Types"); -        // Declare some more converters -        iterable_converter() -            .from_python<std::vector<uhd::device_addr_t>>() -            ; - -        bp::to_python_converter< -            std::vector<uhd::device_addr_t>, -            iterable_to_python_list<std::vector<uhd::device_addr_t>>, false >(); -    } +    export_types(types_module); +    export_time_spec(types_module); +    export_spi_config(types_module); +    export_metadata(types_module); +    export_sensors(types_module); +    export_tune(types_module);      // Register usrp submodule -    { -        bp::object usrp_module( -            bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.usrp"))) -        ); -        bp::scope().attr("usrp") = usrp_module; -        bp::scope io_scope = usrp_module; - -        export_multi_usrp(); -        export_subdev_spec(); -        export_dboard_iface(); -        export_fe_connection(); -        export_stream(); -    } +    auto usrp_module = m.def_submodule("usrp", "USRP Objects"); +    export_multi_usrp(usrp_module); +    export_subdev_spec(usrp_module); +    export_dboard_iface(usrp_module); +    export_fe_connection(usrp_module); +    export_stream(usrp_module);      // Register filters submodule -    { -        bp::object filters_module( -            bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.filters"))) -        ); -        bp::scope().attr("filters") = filters_module; -        bp::scope io_scope = filters_module; - -        export_filters(); -    } +    auto filters_module = m.def_submodule("filters", "Filter Submodule"); +    export_filters(filters_module);  } diff --git a/host/python/types.py b/host/python/types.py index 6b4ceefce..ad96076f3 100644 --- a/host/python/types.py +++ b/host/python/types.py @@ -18,8 +18,9 @@ SPIEdge = lib.types.spi_edge  SPIConfig = lib.types.spi_config  RXMetadataErrorCode = lib.types.rx_metadata_error_code  Range = lib.types.range -RangeVector = lib.types.range_vector -MetaRange = lib.types.meta_range +MetaRange = lib.types.meta_range_t +GainRange = lib.types.meta_range_t +FreqRange = lib.types.meta_range_t  RXMetadata = lib.types.rx_metadata  TXMetadata = lib.types.tx_metadata  TXAsyncMetadata = lib.types.async_metadata  | 
