aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul David <paul.david@ettus.com>2017-05-02 14:10:05 -0400
committerMartin Braun <martin.braun@ettus.com>2018-06-20 19:02:32 -0500
commite74cf7635ba3360b5b7002a2f7317941f65ffa16 (patch)
tree46b63039f31c5aedf26773b4b626b2a7932999db
parent22e24497a510c174e6de7718ad918a423d1973dd (diff)
downloaduhd-e74cf7635ba3360b5b7002a2f7317941f65ffa16.tar.gz
uhd-e74cf7635ba3360b5b7002a2f7317941f65ffa16.tar.bz2
uhd-e74cf7635ba3360b5b7002a2f7317941f65ffa16.zip
python: Separating exposed Python data structures
- Separating exposed Python data structures into logical sections - Exposes all of the multi_usrp API - Adds a layer of Python for documentation and adding helper methods - Adds improvements and fixes to the MultiUSRP object - Includes additional exposed data structures (like time_spec_t, etc.) - Add code to release the Python GIL during long C++ calls
-rw-r--r--host/CMakeLists.txt54
-rw-r--r--host/docs/CMakeLists.txt2
-rw-r--r--host/docs/Doxyfile.in2
-rw-r--r--host/examples/python/CMakeLists.txt21
-rwxr-xr-xhost/examples/python/rx_to_file.py (renamed from host/examples/python/pyuhd_rx_to_file.py)38
-rwxr-xr-xhost/examples/python/tx_waveforms.py (renamed from host/examples/python/pyuhd_tx_waveforms.py)34
-rw-r--r--host/lib/stream_python.hpp199
-rw-r--r--host/lib/types/filters_python.hpp60
-rw-r--r--host/lib/types/metadata_python.hpp111
-rw-r--r--host/lib/types/sensors_python.hpp46
-rw-r--r--host/lib/types/serial_python.hpp32
-rw-r--r--host/lib/types/time_spec_python.hpp35
-rw-r--r--host/lib/types/tune_python.hpp39
-rw-r--r--host/lib/types/types_python.hpp33
-rw-r--r--host/lib/usrp/dboard_iface_python.hpp95
-rw-r--r--host/lib/usrp/fe_connection_python.hpp39
-rw-r--r--host/lib/usrp/multi_usrp_python.hpp441
-rw-r--r--host/lib/usrp/subdev_spec_python.hpp37
-rw-r--r--host/lib/utils/gil_release_python.hpp31
-rw-r--r--host/python/CMakeLists.txt75
-rw-r--r--host/python/__init__.py22
-rw-r--r--host/python/filters.py16
-rw-r--r--host/python/pyuhd.cpp553
-rw-r--r--host/python/pyuhd.py120
-rwxr-xr-xhost/python/setup.py.in28
-rw-r--r--host/python/types.py30
-rw-r--r--host/python/usrp.py143
27 files changed, 1624 insertions, 712 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index 2fb78cb0d..5b19be476 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -1,6 +1,5 @@
#
-# Copyright 2010-2016 Ettus Research LLC
-# Copyright 2018 Ettus Research, a National Instruments Company
+# Copyright 2010-2018 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: GPL-3.0
#
@@ -281,9 +280,18 @@ ENDIF(CYGWIN)
IF(WIN32)
ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp
ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max
- ENDIF(WIN32)
-
+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)
+IF(${ENABLE_PYTHON3})
+ SET(BOOST_PYTHON_COMPONENT python3)
+ SET(BOOST_PYTHON_VERSION 3)
+ENDIF()
########################################################################
# Setup Boost
@@ -299,11 +307,9 @@ SET(BOOST_REQUIRED_COMPONENTS
system
unit_test_framework
serialization
- )
-
-SET(BOOST_OPTIONAL_COMPONENTS
- python
)
+
+SET(BOOST_OPTIONAL_COMPONENTS ${BOOST_PYTHON_COMPONENT})
IF(MINGW)
LIST(APPEND BOOST_REQUIRED_COMPONENTS thread_win32)
ELSE()
@@ -330,20 +336,27 @@ SET(Boost_ADDITIONAL_VERSIONS
)
#Python API requirements
-MESSAGE(STATUS "Looking for optional Boost copmponents...")
+MESSAGE(STATUS "Looking for optional Boost components...")
FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} OPTIONAL_COMPONENTS ${BOOST_OPTIONAL_COMPONENTS})
-MESSAGE(STATUS "Looking for required Boost copmponents...")
+MESSAGE(STATUS "Looking for required Boost components...")
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}")
-
########################################################################
# Additional settings for build environment
########################################################################
@@ -355,11 +368,18 @@ INCLUDE(UHDLog)
########################################################################
# Check Python Modules
########################################################################
+FIND_PACKAGE(PythonInterp ${BOOST_PYTHON_VERSION})
+FIND_PACKAGE(PythonLibs ${BOOST_PYTHON_VERSION})
INCLUDE(UHDPython)
+SET(PYTHON_VERSION "platform.python_version() >= '2.7' and platform.python_version() < '3.0'")
+IF(${ENABLE_PYTHON3})
+ SET(PYTHON_VERSION "platform.python_version() >= '3.0'")
+ENDIF()
+
PYTHON_CHECK_MODULE(
- "Python version 2.7 or greater"
- "platform" "platform.python_version() >= '2.7'"
+ "Python version ${BOOST_PYTHON_VERSION} or greater"
+ "platform" ${PYTHON_VERSION}
HAVE_PYTHON_PLAT_MIN_VERSION
)
@@ -373,16 +393,16 @@ PYTHON_CHECK_MODULE(
"requests 2.0 or greater"
"requests" "requests.__version__ >= '2.0'"
HAVE_PYTHON_MODULE_REQUESTS
- )
+)
PYTHON_CHECK_MODULE(
"numpy 1.7 or greater"
"numpy" "LooseVersion(numpy.__version__) >= LooseVersion('1.7')"
HAVE_PYTHON_MODULE_NUMPY
- )
+)
SET(PYTHON_ADDITIONAL_VERSIONS 2.7 3.4 3.5)
-FIND_PACKAGE(PythonLibs)
+
########################################################################
# Create Uninstall Target
########################################################################
@@ -410,7 +430,7 @@ 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)
-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 OFF "ENABLE_LIBUHD;BOOST_PYTHON_FOUND;HAVE_PYTHON_MODULE_NUMPY;PythonLibs_FOUND" OFF OFF)
LIBUHD_REGISTER_COMPONENT("Examples" ENABLE_EXAMPLES ON "ENABLE_LIBUHD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("Utils" ENABLE_UTILS ON "ENABLE_LIBUHD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("Tests" ENABLE_TESTS ON "ENABLE_LIBUHD" OFF OFF)
diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt
index 41f248557..a5f6751bf 100644
--- a/host/docs/CMakeLists.txt
+++ b/host/docs/CMakeLists.txt
@@ -74,7 +74,7 @@ IF(ENABLE_DOXYGEN)
LIST(APPEND header_files ${h_files})
SET(DOXYGEN_DEPENDENCIES ${DOXYGEN_DEPENDENCIES} ${header_files})
IF(ENABLE_DOXYGEN_FULL)
- SET(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib")
+ SET(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/python")
ELSE(ENABLE_DOXYGEN_FULL)
SET(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${CMAKE_SOURCE_DIR}/include")
ENDIF(ENABLE_DOXYGEN_FULL)
diff --git a/host/docs/Doxyfile.in b/host/docs/Doxyfile.in
index 009d02a3e..678ea6b8d 100644
--- a/host/docs/Doxyfile.in
+++ b/host/docs/Doxyfile.in
@@ -672,7 +672,7 @@ INPUT_ENCODING = UTF-8
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
-FILE_PATTERNS = *.hpp *.dox *.h *.ipp *.md
+FILE_PATTERNS = *.hpp *.dox *.h *.ipp *.md *.py
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
diff --git a/host/examples/python/CMakeLists.txt b/host/examples/python/CMakeLists.txt
index 628bf10a2..4b75f57bd 100644
--- a/host/examples/python/CMakeLists.txt
+++ b/host/examples/python/CMakeLists.txt
@@ -1,23 +1,12 @@
#
-# Copyright 2010-2012,2015 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
#
SET(python_examples
- pyuhd_rx_to_file.py
- pyuhd_tx_waveforms.py
+ rx_to_file.py
+ tx_waveforms.py
)
-UHD_INSTALL(PROGRAMS ${python_examples} DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples)
+UHD_INSTALL(PROGRAMS ${python_examples} DESTINATION ${PKG_LIB_DIR}/examples/python COMPONENT examples)
diff --git a/host/examples/python/pyuhd_rx_to_file.py b/host/examples/python/rx_to_file.py
index 0b4956b33..7017a08c2 100755
--- a/host/examples/python/pyuhd_rx_to_file.py
+++ b/host/examples/python/rx_to_file.py
@@ -1,27 +1,20 @@
-#! /usr/bin/env python
+#!/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.
-#
-# 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
#
+"""
+RX samples to file using Python API
+"""
-
+import argparse
import numpy as np
import uhd
-import argparse
+
def parse_args():
+ """Parse the command line arguments"""
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--args", default="", type=str)
parser.add_argument("-o", "--output-file", type=str, required=True)
@@ -30,17 +23,24 @@ def parse_args():
parser.add_argument("-d", "--duration", default=5.0, type=float)
parser.add_argument("-c", "--channels", default=0, nargs="+", type=int)
parser.add_argument("-g", "--gain", type=int, default=10)
+ parser.add_argument("-n", "--numpy", default=False, action="store_true",
+ help="Save output file in NumPy format (default: No)")
return parser.parse_args()
+
def main():
+ """RX samples and write to file"""
args = parse_args()
- usrp = uhd.multi_usrp(args.args)
+ usrp = uhd.usrp.MultiUSRP(args.args)
num_samps = int(np.ceil(args.duration*args.rate))
if not isinstance(args.channels, list):
args.channels = [args.channels]
samps = usrp.recv_num_samps(num_samps, args.freq, args.rate, args.channels, args.gain)
- with open(args.output_file, 'wb') as f:
- np.save(f, samps, allow_pickle=False, fix_imports=False)
+ with open(args.output_file, 'wb') as out_file:
+ if args.numpy:
+ np.save(out_file, samps, allow_pickle=False, fix_imports=False)
+ else:
+ samps.tofile(out_file)
if __name__ == "__main__":
main()
diff --git a/host/examples/python/pyuhd_tx_waveforms.py b/host/examples/python/tx_waveforms.py
index d7d431f44..6db50fa2b 100755
--- a/host/examples/python/pyuhd_tx_waveforms.py
+++ b/host/examples/python/tx_waveforms.py
@@ -1,35 +1,28 @@
-#! /usr/bin/env python
+#!/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.
-#
-# 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
#
+"""
+Generate and TX samples using a set of waveforms, and waveform characteristics
+"""
+import argparse
import numpy as np
import uhd
-import argparse
-
waveforms = {
"sine": lambda n, tone_offset, rate: np.exp(n * 2j * np.pi * tone_offset / rate),
"square": lambda n, tone_offset, rate: np.sign(waveforms["sine"](n, tone_offset, rate)),
"const": lambda n, tone_offset, rate: 1 + 1j,
- "ramp": lambda n, tone_offset, rate: 2*(n*(tone_offset/rate) - np.floor(float(0.5 + n*(tone_offset/rate))))
+ "ramp": lambda n, tone_offset, rate:
+ 2*(n*(tone_offset/rate) - np.floor(float(0.5 + n*(tone_offset/rate))))
}
def parse_args():
+ """Parse the command line arguments"""
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--args", default="", type=str)
parser.add_argument(
@@ -45,15 +38,16 @@ def parse_args():
def main():
+ """TX samples based on input arguments"""
args = parse_args()
- usrp = uhd.multi_usrp(args.args)
+ usrp = uhd.usrp.MultiUSRP(args.args)
if not isinstance(args.channels, list):
args.channels = [args.channels]
data = np.array(
- map(lambda n: args.wave_ampl * waveforms[args.waveform](n, args.wave_freq, args.rate),
+ list(map(lambda n: args.wave_ampl * waveforms[args.waveform](n, args.wave_freq, args.rate),
np.arange(
int(10 * np.floor(args.rate / args.wave_freq)),
- dtype=np.complex64)),
+ dtype=np.complex64))),
dtype=np.complex64) # One period
usrp.send_waveform(data, args.duration, args.freq, args.rate,
diff --git a/host/lib/stream_python.hpp b/host/lib/stream_python.hpp
new file mode 100644
index 000000000..c283d34a6
--- /dev/null
+++ b/host/lib/stream_python.hpp
@@ -0,0 +1,199 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#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)
+{
+ // Release the GIL
+ scoped_gil_release gil_release;
+
+ // 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);
+ 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 okay
+ if (((channels > 1) && (dims != 2))
+ or ((size_t) shape[0] < channels))
+ {
+ // Manually decrement the ref count
+ Py_DECREF(array_obj);
+ // If we don't have a 2D NumPy array, assume we have a 1D array
+ size_t input_channels = (dims != 2) ? 1 : shape[0];
+ throw uhd::runtime_error(str(boost::format(
+ "Number of RX channels (%d) does not match the dimensions of the data array (%d)")
+ % channels % input_channels));
+ }
+
+ // 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,
+ get_metadata()
+ );
+
+ // Manually decrement the ref count
+ Py_DECREF(array_obj);
+ return result;
+}
+
+static size_t wrap_send(uhd::tx_streamer *tx_stream,
+ bp::object &np_array,
+ bp::object &metadata)
+{
+ // Release the GIL
+ scoped_gil_release gil_release;
+
+ // 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
+ 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))
+ or ((size_t) shape[0] < channels))
+ {
+ // Manually decrement the ref count
+ Py_DECREF(array_obj);
+ // If we don't have a 2D NumPy array, assume we have a 1D array
+ size_t input_channels = (dims != 2) ? 1 : shape[0];
+ throw uhd::runtime_error(str(boost::format(
+ "Number of TX channels (%d) does not match the dimensions of the data array (%d)")
+ % channels % input_channels));
+ }
+
+ // 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 = (dims > 1) ? (size_t) shape[1] : PyArray_SIZE(array_type_obj);
+
+ // Call the real recv()
+ const size_t result = tx_stream->send(
+ channel_storage,
+ nsamps_per_buff,
+ get_metadata()
+ );
+
+ // Manually decrement the ref count
+ Py_DECREF(array_obj);
+ return result;
+}
+
+void export_stream()
+{
+ using stream_args_t = uhd::stream_args_t;
+ using rx_streamer = uhd::rx_streamer;
+ using tx_streamer = uhd::tx_streamer;
+ using async_metadata_t = uhd::async_metadata_t;
+
+ bp::class_<stream_args_t>
+ ("stream_args", bp::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)
+ .def_readwrite("args" , &stream_args_t::args )
+ .def_readwrite("channels" , &stream_args_t::channels )
+ ;
+
+ bp::class_<
+ rx_streamer,
+ boost::shared_ptr<rx_streamer>,
+ boost::noncopyable>("rx_streamer", "See: uhd::rx_streamer", bp::no_init)
+
+ // Methods
+ .def("recv" , &wrap_recv )
+ .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>,
+ boost::noncopyable>("tx_streamer", "See: uhd::tx_streamer", bp::no_init)
+
+ // Methods
+ .def("send" , &wrap_send )
+ .def("get_num_channels" , &tx_streamer::get_num_channels )
+ .def("get_max_num_samps", &tx_streamer::get_max_num_samps)
+ // FIXME: the timeout isn't actually an optional argument right now in Python
+ .def("recv_async_msg" , +[](tx_streamer& self, async_metadata_t& metadata, double timeout = 0.1) {
+ // Release the GIL
+ scoped_gil_release gil_release;
+
+ return self.recv_async_msg(metadata, timeout);
+ })
+ ;
+}
+
+#endif /* INCLUDED_UHD_STREAM_PYTHON_HPP */
diff --git a/host/lib/types/filters_python.hpp b/host/lib/types/filters_python.hpp
new file mode 100644
index 000000000..ff5785345
--- /dev/null
+++ b/host/lib/types/filters_python.hpp
@@ -0,0 +1,60 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_FILTERS_PYTHON_HPP
+#define INCLUDED_UHD_FILTERS_PYTHON_HPP
+
+#include <uhd/types/filters.hpp>
+
+void export_filters()
+{
+ 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")
+ .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>())
+
+ // Methods
+ .def("is_bypassed", &filter_info_base::is_bypassed )
+ .def("get_type" , &filter_info_base::get_type )
+ .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>())
+
+ // Methods
+ .def("get_analog_type", &analog_filter_base::get_analog_type, bp::return_value_policy<bp::copy_const_reference>())
+ ;
+
+ 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>())
+
+ // Methods
+ .def("get_cutoff" , &analog_filter_lp::get_cutoff )
+ .def("get_rolloff", &analog_filter_lp::get_rolloff)
+ .def("set_cutoff" , &analog_filter_lp::set_cutoff )
+ ;
+}
+
+#endif /* INCLUDED_UHD_FILTERS_PYTHON_HPP */
diff --git a/host/lib/types/metadata_python.hpp b/host/lib/types/metadata_python.hpp
new file mode 100644
index 000000000..876756d73
--- /dev/null
+++ b/host/lib/types/metadata_python.hpp
@@ -0,0 +1,111 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_METADATA_PYTHON_HPP
+#define INCLUDED_UHD_METADATA_PYTHON_HPP
+
+#include <uhd/types/ranges.hpp>
+
+void export_metadata()
+{
+ using range_t = uhd::range_t;
+ using meta_range_t = uhd::meta_range_t;
+ using rx_metadata_t = uhd::rx_metadata_t;
+ using error_code_t = rx_metadata_t::error_code_t;
+ using tx_metadata_t = uhd::tx_metadata_t;
+ 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")
+ .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)
+ .value("broken_chain", error_code_t::ERROR_CODE_BROKEN_CHAIN)
+ .value("overflow" , error_code_t::ERROR_CODE_OVERFLOW )
+ .value("alignment" , error_code_t::ERROR_CODE_ALIGNMENT )
+ .value("bad_packet" , error_code_t::ERROR_CODE_BAD_PACKET )
+ ;
+
+ bp::class_<range_t>
+ ("range", bp::init<double>())
+
+ // Constructors
+ .def(bp::init<double, double, double>())
+
+ // Methods
+ .def("start" , &range_t::start )
+ .def("stop" , &range_t::stop )
+ .def("step" , &range_t::step )
+ .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<>())
+
+ // Constructors
+ .def(bp::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("__str__", &meta_range_t::to_pp_string)
+ ;
+
+ bp::class_<rx_metadata_t>("rx_metadata", bp::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)
+
+ // Properties
+ .def_readonly("has_time_spec" , &rx_metadata_t::has_time_spec )
+ .def_readonly("time_spec" , &rx_metadata_t::time_spec )
+ .def_readonly("more_fragments" , &rx_metadata_t::more_fragments )
+ .def_readonly("start_of_burst" , &rx_metadata_t::start_of_burst )
+ .def_readonly("end_of_burst" , &rx_metadata_t::end_of_burst )
+ .def_readonly("error_code" , &rx_metadata_t::error_code )
+ .def_readonly("out_of_sequence", &rx_metadata_t::out_of_sequence)
+ ;
+
+ bp::class_<tx_metadata_t>("tx_metadata", bp::init<>())
+
+ // Properties
+ .def_readwrite("has_time_spec" , &tx_metadata_t::has_time_spec )
+ .def_readwrite("time_spec" , &tx_metadata_t::time_spec )
+ .def_readwrite("start_of_burst", &tx_metadata_t::start_of_burst)
+ .def_readwrite("end_of_burst" , &tx_metadata_t::end_of_burst )
+ ;
+
+ bp::enum_<event_code_t>("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 )
+ .value("time_error" , event_code_t::EVENT_CODE_TIME_ERROR )
+ .value("underflow_in_packet", event_code_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
+ .value("seq_error_in_packet", event_code_t::EVENT_CODE_SEQ_ERROR_IN_BURST )
+ .value("user_payload" , event_code_t::EVENT_CODE_USER_PAYLOAD )
+ ;
+
+ bp::class_<async_metadata_t>("async_metadata", bp::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 )
+ // TODO: Expose user payloads
+ //.def_readwrite("user_payload" , &async_metadata_t::user_payload )
+ ;
+}
+
+#endif /* INCLUDED_UHD_METADATA_PYTHON_HPP */
diff --git a/host/lib/types/sensors_python.hpp b/host/lib/types/sensors_python.hpp
new file mode 100644
index 000000000..8fd9da4e3
--- /dev/null
+++ b/host/lib/types/sensors_python.hpp
@@ -0,0 +1,46 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_SENSORS_PYTHON_HPP
+#define INCLUDED_UHD_SENSORS_PYTHON_HPP
+
+#include <uhd/types/sensors.hpp>
+
+void export_sensors()
+{
+ 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")
+ .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&>())
+
+ // 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&>())
+
+ // Methods
+ .def("to_bool", &sensor_value_t::to_bool )
+ .def("to_int", &sensor_value_t::to_int )
+ .def("to_real", &sensor_value_t::to_real )
+ .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 )
+ ;
+}
+
+#endif /* INCLUDED_UHD_SENSORS_PYTHON_HPP */
diff --git a/host/lib/types/serial_python.hpp b/host/lib/types/serial_python.hpp
new file mode 100644
index 000000000..441bcc4d7
--- /dev/null
+++ b/host/lib/types/serial_python.hpp
@@ -0,0 +1,32 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_SERIAL_PYTHON_HPP
+#define INCLUDED_UHD_SERIAL_PYTHON_HPP
+
+#include <uhd/types/serial.hpp>
+
+void export_spi_config()
+{
+ using spi_config_t = uhd::spi_config_t;
+ using spi_edge_t = spi_config_t::edge_t;
+
+ bp::enum_<spi_edge_t>("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>())
+
+ // 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 )
+ ;
+}
+
+#endif /* INCLUDED_UHD_SERIAL_PYTHON_HPP */
diff --git a/host/lib/types/time_spec_python.hpp b/host/lib/types/time_spec_python.hpp
new file mode 100644
index 000000000..f411af0b0
--- /dev/null
+++ b/host/lib/types/time_spec_python.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_TIME_SPEC_PYTHON_HPP
+#define INCLUDED_UHD_TIME_SPEC_PYTHON_HPP
+
+#include <uhd/types/time_spec.hpp>
+
+void export_time_spec()
+{
+ using time_spec_t = uhd::time_spec_t;
+
+ bp::class_<time_spec_t>("time_spec", bp::init<double>())
+
+ // Methods
+ .def("from_ticks" , &time_spec_t::from_ticks )
+ .staticmethod("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())
+ ;
+}
+
+#endif /* INCLUDED_UHD_TIME_SPEC_PYTHON_HPP */
diff --git a/host/lib/types/tune_python.hpp b/host/lib/types/tune_python.hpp
new file mode 100644
index 000000000..532cc2f8e
--- /dev/null
+++ b/host/lib/types/tune_python.hpp
@@ -0,0 +1,39 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_TUNE_PYTHON_HPP
+#define INCLUDED_UHD_TUNE_PYTHON_HPP
+
+#include <uhd/types/tune_result.hpp>
+#include <uhd/types/tune_request.hpp>
+
+void export_tune()
+{
+ 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")
+ .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>())
+ .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)
+ .def_readwrite("rf_freq" , &tune_request_t::rf_freq )
+ .def_readwrite("dsp_freq" , &tune_request_t::dsp_freq )
+ .def_readwrite("args" , &tune_request_t::args )
+ ;
+
+ bp::class_<tune_result_t>("tune_result", bp::init<>())
+ ;
+}
+
+#endif /* INCLUDED_UHD_TUNE_PYTHON_HPP */
diff --git a/host/lib/types/types_python.hpp b/host/lib/types/types_python.hpp
new file mode 100644
index 000000000..4cda00d0d
--- /dev/null
+++ b/host/lib/types/types_python.hpp
@@ -0,0 +1,33 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_TYPES_PYTHON_HPP
+#define INCLUDED_UHD_TYPES_PYTHON_HPP
+
+#include <uhd/types/stream_cmd.hpp>
+
+void export_types()
+{
+ using stream_cmd_t = uhd::stream_cmd_t;
+ using stream_mode_t = stream_cmd_t::stream_mode_t;
+
+ bp::enum_<stream_mode_t>("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>())
+
+ // 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)
+ ;
+}
+
+#endif /* INCLUDED_UHD_TYPES_PYTHON_HPP */
diff --git a/host/lib/usrp/dboard_iface_python.hpp b/host/lib/usrp/dboard_iface_python.hpp
new file mode 100644
index 000000000..df86fdcc8
--- /dev/null
+++ b/host/lib/usrp/dboard_iface_python.hpp
@@ -0,0 +1,95 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_USRP_DBOARD_IFACE_PYTHON_HPP
+#define INCLUDED_UHD_USRP_DBOARD_IFACE_PYTHON_HPP
+
+#include <uhd/usrp/dboard_iface.hpp>
+#include <uhd/usrp/gpio_defs.hpp>
+#include "../include/uhdlib/usrp/gpio_defs.hpp"
+
+void export_dboard_iface()
+{
+ using dboard_iface = uhd::usrp::dboard_iface;
+ using special_props_t = uhd::usrp::dboard_iface_special_props_t;
+ using unit_t = dboard_iface::unit_t;
+
+ using aux_dac_t = dboard_iface::aux_dac_t;
+ using aux_adc_t = dboard_iface::aux_adc_t;
+
+ 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")
+ .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")
+ .value("MODE_ATR" , gpio_atr_mode_t::MODE_ATR )
+ .value("MODE_GPIO", gpio_atr_mode_t::MODE_GPIO)
+ ;
+
+ bp::enum_<unit_t>("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")
+ .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")
+ .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")
+
+ // Properties
+ .add_property("soft_clock_divider", &special_props_t::soft_clock_divider)
+ .add_property("mangle_i2c_addrs" , &special_props_t::mangle_i2c_addrs )
+ ;
+
+ bp::class_<
+ dboard_iface,
+ boost::shared_ptr<dboard_iface>,
+ boost::noncopyable>("dboard_iface", bp::no_init)
+
+ // Methods
+ .def("get_special_props", &dboard_iface::get_special_props)
+ .def("write_aux_dac" , &dboard_iface::write_aux_dac )
+ .def("read_aux_adc" , &dboard_iface::read_aux_adc )
+ .def("set_pin_ctrl" , &dboard_iface::set_pin_ctrl )
+ .def("get_pin_ctrl" , &dboard_iface::get_pin_ctrl )
+ .def("set_atr_reg" , &dboard_iface::set_atr_reg )
+ .def("get_atr_reg" , &dboard_iface::get_atr_reg )
+ .def("set_gpio_ddr" , &dboard_iface::set_gpio_ddr )
+ .def("get_gpio_ddr" , &dboard_iface::get_gpio_ddr )
+ .def("get_gpio_out" , &dboard_iface::get_gpio_out )
+ .def("set_gpio_out" , &dboard_iface::set_gpio_out )
+ .def("read_gpio" , &dboard_iface::read_gpio )
+ .def("write_spi" , &dboard_iface::write_spi )
+ .def("read_write_spi" , &dboard_iface::read_write_spi )
+ .def("set_clock_rate" , &dboard_iface::set_clock_rate )
+ .def("get_clock_rate" , &dboard_iface::get_clock_rate )
+ .def("get_clock_rates" , &dboard_iface::get_clock_rates )
+ .def("set_clock_enabled", &dboard_iface::set_clock_enabled)
+ .def("get_codec_rate" , &dboard_iface::get_codec_rate )
+ .def("set_fe_connection", &dboard_iface::set_fe_connection)
+ .def("get_command_time" , &dboard_iface::get_command_time )
+ .def("set_command_time" , &dboard_iface::set_command_time )
+ .def("sleep" , &dboard_iface::sleep )
+ ;
+}
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_IFACE_PYTHON_HPP */
diff --git a/host/lib/usrp/fe_connection_python.hpp b/host/lib/usrp/fe_connection_python.hpp
new file mode 100644
index 000000000..29bba1746
--- /dev/null
+++ b/host/lib/usrp/fe_connection_python.hpp
@@ -0,0 +1,39 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_USRP_FE_CONNECTION_PYTHON_HPP
+#define INCLUDED_UHD_USRP_FE_CONNECTION_PYTHON_HPP
+
+#include <uhd/usrp/fe_connection.hpp>
+
+void export_fe_connection()
+{
+ using fe_connection_t = uhd::usrp::fe_connection_t;
+ using sampling_t = fe_connection_t::sampling_t;
+
+ bp::enum_<sampling_t>("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>())
+
+ // Constructors
+ .def(bp::init<const std::string&, double>())
+
+ // Methods
+ .def("get_sampling_mode", &fe_connection_t::get_sampling_mode)
+ .def("is_iq_swapped" , &fe_connection_t::is_iq_swapped )
+ .def("is_i_inverted" , &fe_connection_t::is_i_inverted )
+ .def("is_q_inverted" , &fe_connection_t::is_q_inverted )
+ .def("get_if_freq" , &fe_connection_t::get_if_freq )
+ .def("set_if_freq" , &fe_connection_t::set_if_freq )
+ ;
+}
+
+#endif /* INCLUDED_UHD_USRP_FE_CONNECTION_PYTHON_HPP */
diff --git a/host/lib/usrp/multi_usrp_python.hpp b/host/lib/usrp/multi_usrp_python.hpp
new file mode 100644
index 000000000..2c1bc6b59
--- /dev/null
+++ b/host/lib/usrp/multi_usrp_python.hpp
@@ -0,0 +1,441 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_USRP_MULTI_USRP_PYTHON_HPP
+#define INCLUDED_UHD_USRP_MULTI_USRP_PYTHON_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);
+
+//
+// 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_rx_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_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_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_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()
+{
+ 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", &register_info_t::bitwidth)
+ .add_property("readable", &register_info_t::readable)
+ .add_property("writable", &register_info_t::writable)
+ ;
+
+ bp::class_<
+ multi_usrp,
+ boost::shared_ptr<multi_usrp>,
+ boost::noncopyable>("multi_usrp", bp::no_init)
+
+ .def("__init__", bp::make_constructor(&multi_usrp::make))
+
+ // Methods
+ .def("make", &multi_usrp::make)
+ .staticmethod("make")
+
+ // General USRP methods
+ .def("get_rx_freq" , &multi_usrp::get_rx_freq, overload_get_rx_freq())
+ .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_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_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("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("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("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("get_clock_source" , &multi_usrp::get_clock_source)
+ .def("get_clock_sources" , &multi_usrp::get_clock_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("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())
+
+ // 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())
+
+ // 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("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())
+
+ // 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())
+
+ // Filter API methods
+ .def("get_filter_names" , &multi_usrp::get_filter_names, overload_get_filter_names())
+ .def("get_filter" , &multi_usrp::get_filter)
+ .def("set_filter" , &multi_usrp::set_filter)
+ ;
+}
+
+#endif /* INCLUDED_UHD_USRP_MULTI_USRP_PYTHON_HPP */
diff --git a/host/lib/usrp/subdev_spec_python.hpp b/host/lib/usrp/subdev_spec_python.hpp
new file mode 100644
index 000000000..ed91099f9
--- /dev/null
+++ b/host/lib/usrp/subdev_spec_python.hpp
@@ -0,0 +1,37 @@
+//
+// Copyright 2017-2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_UHD_USRP_SUBDEV_SPEC_PYTHON_HPP
+#define INCLUDED_UHD_USRP_SUBDEV_SPEC_PYTHON_HPP
+
+#include <uhd/usrp/subdev_spec.hpp>
+
+void export_subdev_spec()
+{
+ 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 &>())
+
+ // Properties
+ .add_property("db_name", &subdev_spec_pair_t::db_name)
+ .add_property("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 &>())
+
+ // Methods
+ .def("__str__", &subdev_spec_t::to_pp_string)
+ .def("to_string", &subdev_spec_t::to_string)
+ ;
+}
+
+#endif /* INCLUDED_UHD_USRP_SUBDEV_SPEC_PYTHON_HPP */
diff --git a/host/lib/utils/gil_release_python.hpp b/host/lib/utils/gil_release_python.hpp
new file mode 100644
index 000000000..287ba240e
--- /dev/null
+++ b/host/lib/utils/gil_release_python.hpp
@@ -0,0 +1,31 @@
+//
+// 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 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