diff options
Diffstat (limited to 'host/python')
| -rw-r--r-- | host/python/CMakeLists.txt | 75 | ||||
| -rw-r--r-- | host/python/__init__.py | 22 | ||||
| -rw-r--r-- | host/python/filters.py | 16 | ||||
| -rw-r--r-- | host/python/pyuhd.cpp | 553 | ||||
| -rw-r--r-- | host/python/pyuhd.py | 120 | ||||
| -rwxr-xr-x | host/python/setup.py.in | 28 | ||||
| -rw-r--r-- | host/python/types.py | 30 | ||||
| -rw-r--r-- | host/python/usrp.py | 143 | 
8 files changed, 349 insertions, 638 deletions
diff --git a/host/python/CMakeLists.txt b/host/python/CMakeLists.txt index f4effa1c4..a650529fa 100644 --- a/host/python/CMakeLists.txt +++ b/host/python/CMakeLists.txt @@ -1,30 +1,19 @@  # -# Copyright 2017 Ettus Research LLC +# Copyright 2017-2018 Ettus Research, a National Instruments Company  # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# SPDX-License-Identifier: GPL-3.0-or-later  #  ########################################################################  # This file included, use CMake directory variables  ######################################################################## -  PYTHON_CHECK_MODULE( -      "virtualenv" -      "sys" "hasattr(sys, 'real_prefix')" -      HAVE_PYTHON_VIRTUALENV -  ) +    "virtualenv" +    "sys" "hasattr(sys, 'real_prefix')" +    HAVE_PYTHON_VIRTUALENV +) +  # Get include dirs  INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS})  EXECUTE_PROCESS( @@ -32,7 +21,7 @@ EXECUTE_PROCESS(      "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"      OUTPUT_VARIABLE PYTHON_NUMPY_INCLUDE_DIR) -# Build libpyuhd.so +# Build pyuhd library  ADD_LIBRARY(pyuhd SHARED pyuhd.cpp)  TARGET_INCLUDE_DIRECTORIES(pyuhd PUBLIC      ${PYTHON_NUMPY_INCLUDE_DIR} @@ -42,7 +31,7 @@ TARGET_LINK_LIBRARIES(pyuhd ${BOOST_PYTHON_LIBRARY} ${Boost_LIBRARIES} ${PYTHON_  # Copy pyuhd library to the staging directory  SET(PYUHD_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}pyuhd${CMAKE_SHARED_LIBRARY_SUFFIX})  ADD_CUSTOM_COMMAND(TARGET pyuhd -    POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/libpyuhd.so ${CMAKE_CURRENT_BINARY_DIR}/uhd/libpyuhd.so) +    POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:pyuhd> ${CMAKE_CURRENT_BINARY_DIR}/uhd/${PYUHD_LIBRARY_NAME})  SET(PYUHD_FILES    ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py @@ -51,33 +40,27 @@ SET(PYUHD_FILES    ${CMAKE_CURRENT_SOURCE_DIR}/filters.py  ) -SET(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") -SET(SETUP_PY    "${CMAKE_CURRENT_BINARY_DIR}/setup.py") -SET(OUTPUT      "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") +SET(SETUP_PY_IN    "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") +SET(SETUP_PY       "${CMAKE_CURRENT_BINARY_DIR}/setup.py") +SET(TIMESTAMP_FILE "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") -    SET(PYUHD_FILES -      ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py -      ${CMAKE_CURRENT_SOURCE_DIR}/pyuhd.py -      ) -    SET(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") -    SET(SETUP_PY    "${CMAKE_CURRENT_BINARY_DIR}/setup.py") -    SET(OUTPUT      "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") +CONFIGURE_FILE(${SETUP_PY_IN} ${SETUP_PY}) -    CONFIGURE_FILE(${SETUP_PY_IN} ${SETUP_PY}) +ADD_CUSTOM_COMMAND(OUTPUT ${TIMESTAMP_FILE} +  COMMAND ${CMAKE_COMMAND} -E copy ${PYUHD_FILES} ${CMAKE_CURRENT_BINARY_DIR}/uhd +  COMMAND ${PYTHON} ${SETUP_PY} -q build +  COMMAND ${CMAKE_COMMAND} -E touch ${TIMESTAMP_FILE} +  DEPENDS ${PYUHD_FILES}) -    ADD_CUSTOM_COMMAND(OUTPUT ${OUTPUT} -      COMMAND ${CMAKE_COMMAND} -E copy ${PYUHD_FILES} ${CMAKE_CURRENT_BINARY_DIR}/uhd -      COMMAND ${PYTHON} ${SETUP_PY} -q build -      COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT} -      DEPENDS ${PYUHD_FILES}) -    ADD_CUSTOM_TARGET(target ALL DEPENDS ${OUTPUT} pyuhd) -    IF(HAVE_PYTHON_VIRTUALENV) -        INSTALL(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} -q install --force)") -    ELSE() -        EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c -          "from distutils import sysconfig; print sysconfig.get_python_lib(plat_specific=True, prefix='')" -          OUTPUT_VARIABLE UHD_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE -        ) -        INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/lib/uhd DESTINATION ${CMAKE_INSTALL_PREFIX}/${UHD_PYTHON_DIR}) -    ENDIF() +ADD_CUSTOM_TARGET(pyuhd_library ALL DEPENDS ${TIMESTAMP_FILE} pyuhd) +IF(HAVE_PYTHON_VIRTUALENV) +    INSTALL(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} -q install --force)") +ELSE() +    EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c +      "from distutils import sysconfig; print(sysconfig.get_python_lib(plat_specific=True, prefix=''))" +      OUTPUT_VARIABLE UHD_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE +    ) +    MESSAGE(STATUS "Utilizing the python install directory: ${CMAKE_INSTALL_PREFIX}/${UHD_PYTHON_DIR}") +    INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/uhd DESTINATION ${CMAKE_INSTALL_PREFIX}/${UHD_PYTHON_DIR}) +ENDIF() diff --git a/host/python/__init__.py b/host/python/__init__.py index 39b6b170d..501b599ef 100644 --- a/host/python/__init__.py +++ b/host/python/__init__.py @@ -1,18 +1,12 @@  # -# Copyright 2017 Ettus Research LLC +# Copyright 2017-2018 Ettus Research, a National Instruments Company  # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# SPDX-License-Identifier: GPL-3.0-or-later  # +""" +UHD Python API module +""" -from pyuhd import * +from . import types +from . import usrp +from . import filters diff --git a/host/python/filters.py b/host/python/filters.py new file mode 100644 index 000000000..8479b56e1 --- /dev/null +++ b/host/python/filters.py @@ -0,0 +1,16 @@ +# +#  Copyright 2017-2018 Ettus Research, a National Instruments Company +# +#  SPDX-License-Identifier: GPL-3.0-or-later +# +""" @package filters +Python UHD module containing the filter API +""" + + +from . import libpyuhd as lib + +FilterType = lib.filters.filter_type +FilterInfoBase = lib.filters.filter_info_base +AnalogFilterBase = lib.filters.analog_filter_base +AnalogFilterLP = lib.filters.analog_filter_lp diff --git a/host/python/pyuhd.cpp b/host/python/pyuhd.cpp index 5bb6271f3..fe8d6a790 100644 --- a/host/python/pyuhd.cpp +++ b/host/python/pyuhd.cpp @@ -1,181 +1,82 @@  // -// Copyright 2017 Ettus Research LLC +// Copyright 2017-2018 Ettus Research, a National Instruments Company  // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// SPDX-License-Identifier: GPL-3.0-or-later  // -#include <uhd/types/dict.hpp> -#include <uhd/types/ranges.hpp> -#include <uhd/types/stream_cmd.hpp> -#include <uhd/types/tune_result.hpp> -#include <uhd/types/tune_request.hpp> -#include <uhd/usrp/multi_usrp.hpp> -#include <uhd/stream.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/python.hpp>  #include <boost/python/stl_iterator.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp>  #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION  #include <numpy/arrayobject.h> -  namespace bp = boost::python; +#include "stream_python.hpp" -size_t Pyrecv(uhd::rx_streamer* rx_stream, bp::object& np_array, uhd::rx_metadata_t& rx_metadata){ -    // 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); -    PyArrayObject* array_type_obj = reinterpret_cast<PyArrayObject*>(array_obj); - -    // Get dimensions of the numpy array -    const size_t dims = PyArray_NDIM(array_type_obj); -    const npy_intp* shape = PyArray_SHAPE(array_type_obj); -    // How many bytes to jump to get to the next element of this stride (next row) -    const npy_intp* strides = PyArray_STRIDES(array_type_obj); -    const size_t channels = rx_stream->get_num_channels(); - - -    // Check if numpy array sizes are ok -    if ((channels > 1) && (dims != 2)){ -        return 0; -    }else if ((size_t)shape[0] < channels){ -        return 0; -    } - -    // Get a pointer to the storage -    std::vector<void*> channel_storage; -    char* data = PyArray_BYTES(array_type_obj); -    for (size_t i = 0; i<channels; ++i){ -        channel_storage.push_back((void*)(data+i*strides[0])); -    } - -    // Get data buffer and size of the array -    size_t nsamps_per_buff; -    if (dims > 1){ -        nsamps_per_buff = (size_t)shape[1]; -    }else{ -        nsamps_per_buff = PyArray_SIZE(array_type_obj); -    } - -    // Call the real recv() -    const size_t result =  rx_stream->recv( -        channel_storage, -        nsamps_per_buff, -        rx_metadata); -    return result; -}; - -size_t Pysend(uhd::tx_streamer* tx_stream, bp::object& np_array, uhd::tx_metadata_t& tx_metadata){ -    // 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); -    PyArrayObject* array_type_obj = reinterpret_cast<PyArrayObject*>(array_obj); - -    // Get dimensions of the numpy array -    const size_t dims = PyArray_NDIM(array_type_obj); -    const npy_intp* shape = PyArray_SHAPE(array_type_obj); -    // How many bytes to jump to get to the next element of the stride (next row) -    const npy_intp* strides = PyArray_STRIDES(array_type_obj); -    const size_t channels = tx_stream->get_num_channels(); - -    // Check if numpy array sizes are ok -    if ((channels > 1) && (dims != 2)){ -        return 0; -    }else if ((size_t)shape[0] < channels){ -        return 0; -    } +#include "types/types_python.hpp" +#include "types/serial_python.hpp" +#include "types/time_spec_python.hpp" +#include "types/metadata_python.hpp" +#include "types/sensors_python.hpp" +#include "types/filters_python.hpp" +#include "types/tune_python.hpp" -    // Get a pointer to the storage -    std::vector<void*> channel_storage; -    char* data = PyArray_BYTES(array_type_obj); -    for (size_t i = 0; i<channels; ++i){ -        channel_storage.push_back((void*)(data+i*strides[0])); -    } - -    // Get data buffer and size of the array -    size_t nsamps_per_buff; -    if (dims > 1){ -        nsamps_per_buff = (size_t)shape[1]; -    }else{ -        nsamps_per_buff = PyArray_SIZE(array_type_obj); -    } - -    // Call the real recv() -    const size_t result =  tx_stream->send( -        channel_storage, -        nsamps_per_buff, -        tx_metadata); -    return result; -}; - -// Manual wrapping because of non-standard overloading -void set_rx_gain_conv(uhd::usrp::multi_usrp* multi_usrp, double gain, size_t chan){ -    multi_usrp->set_rx_gain(gain, chan); -} - -void set_tx_gain_conv(uhd::usrp::multi_usrp* multi_usrp, double gain, size_t chan){ -    multi_usrp->set_tx_gain(gain, chan); -} +#include "usrp/fe_connection_python.hpp" +#include "usrp/dboard_iface_python.hpp" +#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; +    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; +    } -    typedef bp::stl_input_iterator<typename Container::value_type> -                                                                    iterator; +    static void* convertible(PyObject* object) +    { +        return PyObject_GetIter(object) ? object : NULL; +    } -    // 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 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  { @@ -203,280 +104,10 @@ struct iterable_to_python_list      }  }; - -void export_multi_usrp(void) -{ -    //Register submodule multi_usrp -    bp::object multi_usrp_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.multi_usrp")))); -    bp::scope().attr("multi_usrp") = multi_usrp_module; -    bp::scope io_scope = multi_usrp_module; - -    bp::class_<uhd::usrp::multi_usrp, boost::shared_ptr<uhd::usrp::multi_usrp>, boost::noncopyable>("multi_usrp", bp::no_init) -        .def("make", &uhd::usrp::multi_usrp::make) -        .staticmethod("make") -        .def("get_rx_freq", &uhd::usrp::multi_usrp::get_rx_freq) -        .def("get_rx_num_channels", &uhd::usrp::multi_usrp::get_rx_num_channels) -        .def("get_rx_rate", &uhd::usrp::multi_usrp::get_rx_rate) -        .def("get_rx_stream", &uhd::usrp::multi_usrp::get_rx_stream) -        .def("set_rx_freq", &uhd::usrp::multi_usrp::set_rx_freq) -        .def("set_rx_gain", &set_rx_gain_conv) -        .def("set_rx_rate", &uhd::usrp::multi_usrp::set_rx_rate) -        .def("get_tx_freq", &uhd::usrp::multi_usrp::get_tx_freq) -        .def("get_tx_num_channels", &uhd::usrp::multi_usrp::get_tx_num_channels) -        .def("get_tx_rate", &uhd::usrp::multi_usrp::get_tx_rate) -        .def("get_tx_stream", &uhd::usrp::multi_usrp::get_tx_stream) -        .def("set_tx_freq", &uhd::usrp::multi_usrp::set_tx_freq) -        .def("set_tx_gain", &set_tx_gain_conv) -        .def("set_tx_rate", &uhd::usrp::multi_usrp::set_tx_rate) -        .def("get_usrp_rx_info", &uhd::usrp::multi_usrp::get_usrp_rx_info) -        .def("get_usrp_tx_info", &uhd::usrp::multi_usrp::get_usrp_tx_info) -        .def("set_master_clock_rate", &uhd::usrp::multi_usrp::set_master_clock_rate) -        .def("get_master_clock_rate", &uhd::usrp::multi_usrp::get_master_clock_rate) -        .def("get_pp_string", &uhd::usrp::multi_usrp::get_pp_string) -        .def("get_mboard_name", &uhd::usrp::multi_usrp::get_mboard_name) -        .def("get_time_now", &uhd::usrp::multi_usrp::get_time_now) -        .def("get_time_last_pps", &uhd::usrp::multi_usrp::get_time_last_pps) -        .def("set_time_now", &uhd::usrp::multi_usrp::set_time_now) -        .def("set_time_next_pps", &uhd::usrp::multi_usrp::set_time_next_pps) -        .def("set_time_unknown_pps", &uhd::usrp::multi_usrp::set_time_unknown_pps) -        .def("get_time_synchronized", &uhd::usrp::multi_usrp::get_time_synchronized) -        .def("set_command_time", &uhd::usrp::multi_usrp::set_command_time) -        .def("clear_command_time", &uhd::usrp::multi_usrp::clear_command_time) -        .def("issue_stream_cmd", &uhd::usrp::multi_usrp::issue_stream_cmd) -        .def("set_clock_config", &uhd::usrp::multi_usrp::set_clock_config) -        .def("set_time_source", &uhd::usrp::multi_usrp::set_time_source) -        .def("get_time_source", &uhd::usrp::multi_usrp::get_time_source) -        .def("get_time_sources", &uhd::usrp::multi_usrp::get_time_sources) -        .def("set_clock_source", &uhd::usrp::multi_usrp::set_clock_source) -        .def("get_clock_source", &uhd::usrp::multi_usrp::get_clock_source) -        .def("get_clock_sources", &uhd::usrp::multi_usrp::get_clock_sources) -        .def("set_clock_source_out", &uhd::usrp::multi_usrp::set_clock_source_out) -        .def("set_time_source_out", &uhd::usrp::multi_usrp::set_time_source_out) -        .def("get_num_mboards", &uhd::usrp::multi_usrp::get_num_mboards) -        .def("get_mboard_sensor", &uhd::usrp::multi_usrp::get_mboard_sensor) // TODO sensor_value_t -        .def("get_mboard_sensor_names", &uhd::usrp::multi_usrp::get_mboard_sensor_names) -        .def("set_user_register", &uhd::usrp::multi_usrp::set_user_register) - -        // RX methods -        .def("set_rx_subdev_spec", &uhd::usrp::multi_usrp::set_rx_subdev_spec) // TODO subdev_spec_t -        .def("get_rx_subdev_spec", &uhd::usrp::multi_usrp::get_rx_subdev_spec) // TODO subdev_spec_t -        .def("get_rx_subdev_name", &uhd::usrp::multi_usrp::get_rx_subdev_name) -        .def("get_rx_rates", &uhd::usrp::multi_usrp::get_rx_rates) -        .def("get_rx_freq_range", &uhd::usrp::multi_usrp::get_rx_freq_range) -        .def("get_fe_rx_freq_range", &uhd::usrp::multi_usrp::get_fe_rx_freq_range) -        .def("get_rx_lo_names", &uhd::usrp::multi_usrp::get_rx_lo_names) -        .def("set_rx_lo_source", &uhd::usrp::multi_usrp::set_rx_lo_source) -        .def("get_rx_lo_source", &uhd::usrp::multi_usrp::get_rx_lo_source) -        .def("get_rx_lo_sources", &uhd::usrp::multi_usrp::get_rx_lo_sources) -        .def("set_rx_lo_export_enabled", &uhd::usrp::multi_usrp::set_rx_lo_export_enabled) -        .def("get_rx_lo_export_enabled", &uhd::usrp::multi_usrp::get_rx_lo_export_enabled) -        .def("set_rx_lo_freq", &uhd::usrp::multi_usrp::set_rx_lo_freq) -        .def("get_rx_lo_freq", &uhd::usrp::multi_usrp::get_rx_lo_freq) -        .def("get_rx_lo_freq_range", &uhd::usrp::multi_usrp::get_rx_lo_freq_range) -        .def("set_normalized_rx_gain", &uhd::usrp::multi_usrp::set_normalized_rx_gain) -        .def("get_normalized_rx_gain", &uhd::usrp::multi_usrp::get_normalized_rx_gain) -        .def("set_rx_agc", &uhd::usrp::multi_usrp::set_rx_agc) -        //get_rx_gain (special wrapper) -        //.def("get_rx_gain_range", &uhd::usrp::multi_usrp::get_rx_gain_range) // (special wrapper) -        .def("get_rx_gain_names", &uhd::usrp::multi_usrp::get_rx_gain_names) -        .def("set_rx_antenna", &uhd::usrp::multi_usrp::set_rx_antenna) -        .def("get_rx_antenna", &uhd::usrp::multi_usrp::get_rx_antenna) -        .def("get_rx_antennas", &uhd::usrp::multi_usrp::get_rx_antennas) -        .def("set_rx_bandwidth", &uhd::usrp::multi_usrp::set_rx_bandwidth) -        .def("get_rx_bandwidth", &uhd::usrp::multi_usrp::get_rx_bandwidth) -        .def("get_rx_bandwidth_range", &uhd::usrp::multi_usrp::get_rx_bandwidth_range)  -        .def("get_rx_dboard_iface", &uhd::usrp::multi_usrp::get_rx_dboard_iface) // TODO dboard_iface::sptr -        .def("get_rx_sensor", &uhd::usrp::multi_usrp::get_rx_sensor) // TODO sensor_value_t -        .def("get_rx_sensor_names", &uhd::usrp::multi_usrp::get_rx_sensor_names) -        //set_rx_dc_offset (special wrapper) -        //set_rx_iq_balance (special wrapper) - -        // TX methods -        .def("set_tx_subdev_spec", &uhd::usrp::multi_usrp::set_tx_subdev_spec) // TODO subdev_spec_t -        .def("get_tx_subdev_spec", &uhd::usrp::multi_usrp::get_tx_subdev_spec) // TODO subdev_spec_t -        .def("get_tx_subdev_name", &uhd::usrp::multi_usrp::get_tx_subdev_name) -        .def("get_tx_rates", &uhd::usrp::multi_usrp::get_tx_rates) -        .def("get_tx_freq_range", &uhd::usrp::multi_usrp::get_tx_freq_range) -        .def("get_fe_tx_freq_range", &uhd::usrp::multi_usrp::get_fe_tx_freq_range) -        .def("set_normalized_tx_gain", &uhd::usrp::multi_usrp::set_normalized_tx_gain) -        .def("get_normalized_tx_gain", &uhd::usrp::multi_usrp::get_normalized_tx_gain) -        //get_tx_gain (special wrapper) -        //.def("get_tx_gain_range", &uhd::usrp::multi_usrp::get_tx_gain_range) //(special wrapper) -        .def("get_tx_gain_names", &uhd::usrp::multi_usrp::get_tx_gain_names) -        .def("set_tx_antenna", &uhd::usrp::multi_usrp::set_tx_antenna) -        .def("get_tx_antenna", &uhd::usrp::multi_usrp::get_tx_antenna) -        .def("get_tx_antennas", &uhd::usrp::multi_usrp::get_tx_antennas) -        .def("set_tx_bandwidth", &uhd::usrp::multi_usrp::set_tx_bandwidth) -        .def("get_tx_bandwidth", &uhd::usrp::multi_usrp::get_tx_bandwidth) -        .def("get_tx_bandwidth_range", &uhd::usrp::multi_usrp::get_tx_bandwidth_range)  -        .def("get_tx_dboard_iface", &uhd::usrp::multi_usrp::get_tx_dboard_iface) // TODO dboard_iface::sptr -        .def("get_tx_sensor", &uhd::usrp::multi_usrp::get_tx_sensor) // TODO sensor_value_t -        .def("get_tx_sensor_names", &uhd::usrp::multi_usrp::get_tx_sensor_names) -        //set_tx_dc_offset (special wrapper) -        //set_tx_iq_balance (special wrapper) - -        // GPIO methods -        .def("get_gpio_banks", &uhd::usrp::multi_usrp::get_gpio_banks) -        .def("set_gpio_attr", &uhd::usrp::multi_usrp::set_gpio_attr) -        .def("get_gpio_attr", &uhd::usrp::multi_usrp::get_gpio_attr) -        .def("enumerate_registers", &uhd::usrp::multi_usrp::enumerate_registers) -        .def("get_register_info", &uhd::usrp::multi_usrp::get_register_info) // TODO register_info_t -        .def("write_register", &uhd::usrp::multi_usrp::write_register) -        .def("read_register", &uhd::usrp::multi_usrp::read_register) - -        //Filter API methods -        .def("get_filter_names", &uhd::usrp::multi_usrp::get_filter_names) -        .def("get_filter", &uhd::usrp::multi_usrp::get_filter) -        .def("set_filter", &uhd::usrp::multi_usrp::set_filter) -        ; - -    bp::class_<uhd::rx_streamer, boost::shared_ptr<uhd::rx_streamer>, boost::noncopyable>("rx_streamer", bp::no_init) -        .def("recv", &Pyrecv) -        .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_<uhd::tx_streamer, boost::shared_ptr<uhd::tx_streamer>, boost::noncopyable>("tx_streamer", bp::no_init) -        .def("send", &Pysend) -        .def("get_num_channels", &uhd::tx_streamer::get_num_channels) -        .def("get_max_num_samps", &uhd::tx_streamer::get_max_num_samps) -        ; - -} - -void export_types(void) -{ -    //Register submodule types -    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>(); - -    bp::enum_<uhd::stream_cmd_t::stream_mode_t>("stream_mode") -        .value("start_cont", uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS) -        .value("stop_cont", uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) -        .value("num_done", uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE) -        .value("num_more", uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE) -        ; - -    bp::enum_<uhd::rx_metadata_t::error_code_t>("rx_metadata_error_code") -        .value("none", uhd::rx_metadata_t::error_code_t::ERROR_CODE_NONE) -        .value("timeout", uhd::rx_metadata_t::error_code_t::ERROR_CODE_TIMEOUT) -        .value("late", uhd::rx_metadata_t::error_code_t::ERROR_CODE_LATE_COMMAND) -        .value("broken_chain", uhd::rx_metadata_t::error_code_t::ERROR_CODE_BROKEN_CHAIN) -        .value("overflow", uhd::rx_metadata_t::error_code_t::ERROR_CODE_OVERFLOW) -        .value("alignment", uhd::rx_metadata_t::error_code_t::ERROR_CODE_ALIGNMENT) -        .value("bad_packet", uhd::rx_metadata_t::error_code_t::ERROR_CODE_BAD_PACKET) -        ; - -    bp::enum_<uhd::tune_request_t::policy_t>("tune_request_policy") -        .value("none", uhd::tune_request_t::POLICY_NONE) -        .value("auto", uhd::tune_request_t::POLICY_AUTO) -        .value("manual", uhd::tune_request_t::POLICY_MANUAL) -        ; - - -    bp::class_<uhd::stream_args_t>("stream_args", bp::init<std::string,std::string>()) -        .def_readwrite("cpu_format", &uhd::stream_args_t::cpu_format) -        .def_readwrite("otw_format", &uhd::stream_args_t::otw_format) -        .def_readwrite("args", &uhd::stream_args_t::args) -        .def_readwrite("channels", &uhd::stream_args_t::channels) -        ; - -    bp::class_<uhd::stream_cmd_t>("stream_cmd", bp::init<uhd::stream_cmd_t::stream_mode_t>()) -        .def_readwrite("num_samps", &uhd::stream_cmd_t::num_samps) -        .def_readwrite("time_spec", &uhd::stream_cmd_t::time_spec) -        .def_readwrite("stream_now", &uhd::stream_cmd_t::stream_now) -        ; - -    bp::class_<uhd::rx_metadata_t>("rx_metadata", bp::init<>()) -        .def("reset", &uhd::rx_metadata_t::reset) -        .def("to_pp_string", &uhd::rx_metadata_t::to_pp_string) -        .def("strerror", &uhd::rx_metadata_t::strerror) -        .def("__str__", &uhd::rx_metadata_t::to_pp_string, bp::args("compact")=false) -        .def_readonly("has_time_spec", &uhd::rx_metadata_t::has_time_spec) -        .def_readonly("time_spec", &uhd::rx_metadata_t::time_spec) -        .def_readonly("more_fragments", &uhd::rx_metadata_t::more_fragments) -        .def_readonly("start_of_burst", &uhd::rx_metadata_t::start_of_burst) -        .def_readonly("end_of_burst", &uhd::rx_metadata_t::end_of_burst) -        .def_readonly("error_code", &uhd::rx_metadata_t::error_code) -        .def_readonly("out_of_sequence", &uhd::rx_metadata_t::out_of_sequence) -        ; - -    bp::class_<uhd::tx_metadata_t>("tx_metadata", bp::init<>()) -        .def_readwrite("has_time_spec", &uhd::tx_metadata_t::has_time_spec) -        .def_readwrite("time_spec", &uhd::tx_metadata_t::time_spec) -        .def_readwrite("start_of_burst", &uhd::tx_metadata_t::start_of_burst) -        .def_readwrite("end_of_burst", &uhd::tx_metadata_t::end_of_burst) -        ; - - -    bp::class_<uhd::tune_request_t>("tune_request", bp::init<double>()) -        .def_readwrite("target_freq", &uhd::tune_request_t::target_freq) -        .def_readwrite("rf_freq_policy", &uhd::tune_request_t::rf_freq_policy) -        .def_readwrite("dsp_freq_policy", &uhd::tune_request_t::dsp_freq_policy) -        .def_readwrite("rf_freq", &uhd::tune_request_t::rf_freq) -        .def_readwrite("dsp_freq", &uhd::tune_request_t::dsp_freq) -        .def_readwrite("args", &uhd::tune_request_t::args) -        ; - -    bp::class_<uhd::tune_result_t>("tune_result", bp::init<>()) -        ; - -    bp::class_<uhd::range_t>("range", bp::init<double>()) -        .def(bp::init<double, double, double>()) -        .def("start", &uhd::range_t::start) -        .def("stop", &uhd::range_t::stop) -        .def("step", &uhd::range_t::step) -        .def("__str__", &uhd::range_t::to_pp_string) -        ; - -    bp::class_<uhd::meta_range_t>("meta_range", bp::init<>()) -        .def(bp::init<double, double, double>()) -        .def("start", &uhd::meta_range_t::start) -        .def("stop", &uhd::meta_range_t::stop) -        .def("step", &uhd::meta_range_t::step) -        .def("clip", &uhd::meta_range_t::clip) -        .def("__str__", &uhd::meta_range_t::to_pp_string) -        ; -} - -void export_filter() -{ -    //Register submodule filter -    bp::object filter_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.filter")))); -    bp::scope().attr("filter") = filter_module; -    bp::scope io_scope = filter_module; - -    bp::enum_<uhd::filter_info_base::filter_type>("filter_type") -        .value("analog_low_pass", uhd::filter_info_base::ANALOG_LOW_PASS) -        .value("analog_band_pass", uhd::filter_info_base::ANALOG_BAND_PASS) -        .value("digital_i16", uhd::filter_info_base::DIGITAL_I16) -        .value("digital_fir_i16", uhd::filter_info_base::DIGITAL_FIR_I16) -        ; - -    bp::class_<uhd::filter_info_base, boost::shared_ptr<uhd::filter_info_base> >("filter_info_base", bp::init<uhd::filter_info_base::filter_type, bool, size_t>()) -    .def("is_bypassed", &uhd::filter_info_base::is_bypassed) -    .def("get_type", &uhd::filter_info_base::get_type) -    .def("__str__", &uhd::filter_info_base::to_pp_string) -    ; - -    bp::class_<uhd::analog_filter_base, boost::shared_ptr<uhd::analog_filter_base>, bp::bases<uhd::filter_info_base> >("analog_filter_base", bp::init< uhd::filter_info_base::filter_type, bool, size_t, std::string>()) -        .def("get_analog_type", &uhd::analog_filter_base::get_analog_type, bp::return_value_policy<bp::copy_const_reference>() ) -    ; - -    bp::class_<uhd::analog_filter_lp, boost::shared_ptr<uhd::analog_filter_lp>, bp::bases<uhd::analog_filter_base> >("analog_filter_lp", bp::init<uhd::filter_info_base::filter_type, bool, size_t, const std::string, double, double>()) -        .def("get_cutoff", &uhd::analog_filter_lp::get_cutoff) -        .def("get_rolloff", &uhd::analog_filter_lp::get_rolloff) -        .def("set_cutoff", &uhd::analog_filter_lp::set_cutoff) -        ; - -} - -// We need this hack because import_array() returns NULL for newer Python -// versions. +// 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 +// and removes a warning.  #if PY_MAJOR_VERSION >= 3  void* init_numpy()  { @@ -492,21 +123,69 @@ void init_numpy()  BOOST_PYTHON_MODULE(libpyuhd)  { +    // 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 >(); -    export_multi_usrp(); -    export_types(); -    export_filter(); -    init_numpy(); +    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(); +    } + +    // 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(); +    } + +    // 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(); +    }  } diff --git a/host/python/pyuhd.py b/host/python/pyuhd.py deleted file mode 100644 index 32279afb3..000000000 --- a/host/python/pyuhd.py +++ /dev/null @@ -1,120 +0,0 @@ -# -# Copyright 2017 Ettus Research LLC -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. -# - -import libpyuhd as lib -import numpy as np - - -class multi_usrp(object): -    def __init__(self, args=""): -        self.usrp = lib.multi_usrp.multi_usrp.make(args) - -    def __del__(self): -        # Help the garbage collection -        self.usrp = None - -    def set_rx_rate(self, rate, chan=None): -        if chan is None: -            for c in xrange(self.usrp.get_rx_num_channels()): -                self.usrp.set_rx_rate(rate, c) -        elif isinstance(chan, list): -            for c in chan: -                self.usrp.set_rx_rate(rate, c) -        else: -            self.usrp.set_rx_rate(rate, chan) - -    def set_tx_rate(self, rate, chan=None): -        if chan is None: -            for chan in xrange(self.usrp.get_tx_num_channels()): -                self.usrp.set_tx_rate(rate, chan) -        elif isinstance(chan, list): -            for c in chan: -                self.usrp.set_tx_rate(rate, c) -        else: -            self.usrp.set_tx_rate(rate, chan) - - -    def recv_num_samps(self, num_samps, freq, rate=1e6, channels=[0], gain=10): -        result = np.empty((len(channels), num_samps), dtype=np.complex64) -        for chan in channels: -            self.usrp.set_rx_rate(rate, chan) -            self.usrp.set_rx_freq(lib.types.tune_request(freq), chan) -            self.usrp.set_rx_gain(gain, chan) -        st_args = lib.types.stream_args("fc32", "sc16") -        st_args.channels = channels -        metadata = lib.types.rx_metadata() -        streamer = self.usrp.get_rx_stream(st_args) -        buffer_samps = streamer.get_max_num_samps() -        recv_buffer = np.zeros( -            (len(channels), buffer_samps), dtype=np.complex64) -        recv_samps = 0 -        stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.start_cont) -        stream_cmd.stream_now = True -        streamer.issue_stream_cmd(stream_cmd) -        while (recv_samps < num_samps): -            samps = streamer.recv(recv_buffer, metadata) -            if metadata.error_code != lib.types.rx_metadata_error_code.none: -                print(metadata.strerror()) -            if samps: -                real_samps = min(num_samps - recv_samps, samps) -                result[:, recv_samps:recv_samps + real_samps - -                       1] = recv_buffer[:, 0:real_samps - 1] -                recv_samps += real_samps -        stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.stop_cont) -        streamer.issue_stream_cmd(stream_cmd) -        while samps: -            samps = streamer.recv(recv_buffer, metadata) -        # Help the garbage collection -        streamer = None -        return result - -    def send_waveform(self, -                      waveform_proto, -                      duration, -                      freq, -                      rate=1e6, -                      channels=[0], -                      gain=10): -        self.set_tx_rate(rate) -        for chan in channels: -            self.usrp.set_tx_rate(rate, chan) -            self.usrp.set_tx_freq(lib.types.tune_request(freq), chan) -            self.usrp.set_tx_gain(gain, chan) -        st_args = lib.types.stream_args("fc32", "sc16") -        st_args.channels = channels -        metadata = lib.types.rx_metadata() -        streamer = self.usrp.get_tx_stream(st_args) -        buffer_samps = streamer.get_max_num_samps() -        proto_len = waveform_proto.shape[-1] -        if proto_len < buffer_samps: -            waveform_proto = np.tile(waveform_proto, (1, int(np.ceil(float(buffer_samps)/proto_len)))) -            proto_len = waveform_proto.shape[-1] -        metadata = lib.types.tx_metadata() -        send_samps = 0 -        max_samps = int(np.floor(duration * rate)) -        if waveform_proto.shape[0] < len(channels): -            waveform_proto = np.tile(waveform_proto[0], (len(channels), 1)) -        while send_samps < max_samps: -            real_samps = min(proto_len, max_samps-send_samps) -            if real_samps < proto_len: -                samples = streamer.send(waveform_proto[:real_samps], metadata) -            else: -                samples = streamer.send(waveform_proto, metadata) -            send_samps += samples -        # Help the garbage collection -        streamer = None -        return send_samps diff --git a/host/python/setup.py.in b/host/python/setup.py.in index 76044fe72..3c2176c0e 100755 --- a/host/python/setup.py.in +++ b/host/python/setup.py.in @@ -1,22 +1,10 @@  #!/usr/bin/env python  # -# Copyright 2017 Ettus Research LLC +#  Copyright 2017-2018 Ettus Research, a National Instruments Company  # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +#  SPDX-License-Identifier: GPL-3.0-or-later  # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. -# - - +"""Setup file for uhd module"""  from setuptools import setup @@ -30,15 +18,13 @@ setup(name='uhd',            'Programming Language :: Python',            'Topic :: System :: Hardware :: Hardware Drivers',        ], -      keywords='SDR UHD USRP SDR', +      keywords='SDR UHD USRP',        author='Ettus Research',        author_email='packages@ettus.com',        url='https://www.ettus.com/',        license='GPLv3', -      package_dir={ '': '${CMAKE_CURRENT_BINARY_DIR}' }, -      package_data={"uhd": ["*.so"]}, +      package_dir={'': '${CMAKE_CURRENT_BINARY_DIR}'}, +      package_data={'uhd': ['*.so']},        zip_safe=False,        packages=['uhd'], -      install_requires=[ -          'numpy' -      ]) +      install_requires=['numpy']) diff --git a/host/python/types.py b/host/python/types.py new file mode 100644 index 000000000..bcf6e1df2 --- /dev/null +++ b/host/python/types.py @@ -0,0 +1,30 @@ +# +# Copyright 2017-2018 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" @package types +Python UHD module containing types to be used with a MultiUSRP object +""" + +from . import libpyuhd as lib + + +StreamMode = lib.types.stream_mode +StreamCMD = lib.types.stream_cmd +TimeSpec = lib.types.time_spec +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 +RXMetadata = lib.types.rx_metadata +TXMetadata = lib.types.tx_metadata +TXAsyncMetadata = lib.types.async_metadata +TXMetadataEventCode = lib.types.tx_metadata_event_code +DataType = lib.types.data_type +SensorValue = lib.types.sensor_value +TuneRequestPolicy = lib.types.tune_request_policy +TuneRequest = lib.types.tune_request +TuneResult = lib.types.tune_result diff --git a/host/python/usrp.py b/host/python/usrp.py new file mode 100644 index 000000000..6179a3602 --- /dev/null +++ b/host/python/usrp.py @@ -0,0 +1,143 @@ +# +# Copyright 2017-2018 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" @package usrp +Python UHD module containing the MultiUSRP and other objects +""" + +import numpy as np +from . import libpyuhd as lib + + +class MultiUSRP(lib.usrp.multi_usrp): +    """ +    MultiUSRP object for controlling devices +    """ +    def __init__(self, args=""): +        """MultiUSRP constructor""" +        super(MultiUSRP, self).__init__(args) + +    def recv_num_samps(self, num_samps, freq, rate=1e6, channels=(0,), gain=10): +        """ +        RX a finite number of samples from the USRP +        :param num_samps: number of samples to RX +        :param freq: RX frequency (Hz) +        :param rate: RX sample rate (Hz) +        :param channels: list of channels to RX on +        :param gain: RX gain (dB) +        :return: numpy array of complex floating-point samples (fc32) +        """ +        result = np.empty((len(channels), num_samps), dtype=np.complex64) + +        for chan in channels: +            super(MultiUSRP, self).set_rx_rate(rate, chan) +            super(MultiUSRP, self).set_rx_freq(lib.types.tune_request(freq), chan) +            super(MultiUSRP, self).set_rx_gain(gain, chan) + +        st_args = lib.usrp.stream_args("fc32", "sc16") +        st_args.channels = channels +        metadata = lib.types.rx_metadata() +        streamer = super(MultiUSRP, self).get_rx_stream(st_args) +        buffer_samps = streamer.get_max_num_samps() +        recv_buffer = np.zeros( +            (len(channels), buffer_samps), dtype=np.complex64) + +        recv_samps = 0 +        stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.start_cont) +        stream_cmd.stream_now = True +        streamer.issue_stream_cmd(stream_cmd) + +        samps = np.array([], dtype=np.complex64) +        while recv_samps < num_samps: +            samps = streamer.recv(recv_buffer, metadata) + +            if metadata.error_code != lib.types.rx_metadata_error_code.none: +                print(metadata.strerror()) +            if samps: +                real_samps = min(num_samps - recv_samps, samps) +                result[:, recv_samps:recv_samps + real_samps] = recv_buffer[:, 0:real_samps] +                recv_samps += real_samps + +        stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.stop_cont) +        streamer.issue_stream_cmd(stream_cmd) + +        while samps: +            samps = streamer.recv(recv_buffer, metadata) + +        # Help the garbage collection +        streamer = None +        return result + +    def send_waveform(self, +                      waveform_proto, +                      duration, +                      freq, +                      rate=1e6, +                      channels=(0,), +                      gain=10): +        """ +        TX a finite number of samples from the USRP +        :param waveform_proto: numpy array of samples to TX +        :param duration: time in seconds to transmit at the supplied rate +        :param freq: TX frequency (Hz) +        :param rate: TX sample rate (Hz) +        :param channels: list of channels to TX on +        :param gain: TX gain (dB) +        :return: the number of transmitted samples +        """ +        super(MultiUSRP, self).set_tx_rate(rate) +        for chan in channels: +            super(MultiUSRP, self).set_tx_rate(rate, chan) +            super(MultiUSRP, self).set_tx_freq(lib.types.tune_request(freq), chan) +            super(MultiUSRP, self).set_tx_gain(gain, chan) + +        st_args = lib.usrp.stream_args("fc32", "sc16") +        st_args.channels = channels + +        metadata = lib.types.rx_metadata() +        streamer = super(MultiUSRP, self).get_tx_stream(st_args) +        buffer_samps = streamer.get_max_num_samps() +        proto_len = waveform_proto.shape[-1] + +        if proto_len < buffer_samps: +            waveform_proto = np.tile(waveform_proto, +                                     (1, int(np.ceil(float(buffer_samps)/proto_len)))) +            proto_len = waveform_proto.shape[-1] + +        metadata = lib.types.tx_metadata() +        send_samps = 0 +        max_samps = int(np.floor(duration * rate)) + +        if len(waveform_proto.shape) == 1: +            waveform_proto = waveform_proto.reshape(1, waveform_proto.size) +        if waveform_proto.shape[0] < len(channels): +            waveform_proto = np.tile(waveform_proto[0], (len(channels), 1)) + +        while send_samps < max_samps: +            real_samps = min(proto_len, max_samps-send_samps) +            if real_samps < proto_len: +                samples = streamer.send(waveform_proto[:real_samps], metadata) +            else: +                samples = streamer.send(waveform_proto, metadata) +            send_samps += samples + +        # Help the garbage collection +        streamer = None +        return send_samps + + +SubdevSpecPair = lib.usrp.subdev_spec_pair +SubdevSpec = lib.usrp.subdev_spec +GPIOAtrReg = lib.usrp.gpio_atr_reg +GPIOAtrMode = lib.usrp.gpio_atr_mode +Unit = lib.usrp.unit +AuxDAC = lib.usrp.aux_dac +AuxADC = lib.usrp.aux_adc +SpecialProps = lib.usrp.special_props +Sampling = lib.usrp.sampling +FEConnection = lib.usrp.fe_connection +StreamArgs = lib.usrp.stream_args +RXStreamer = lib.usrp.rx_streamer +TXStreamer = lib.usrp.tx_streamer  | 
