From 932bab1eae69a96679eea7e20c2b602c4a9a52b9 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 9 Mar 2020 14:43:10 -0700 Subject: python: Arrange file in Python module into uhd/ subdirectory This adds the host/python/uhd subdirectory, which will add all files that go into the actual Python module once installed. Before, all Python files were directly in host/python and got sorted into their appropriate destination folders during configuration and installation. This change doesn't change anything (Python modules will look the same as they do now), except that it makes the source tree a tad neater, but more importantly, it creates a consistent directory structure when adding submodules to the uhd module. Apart from the PyBind11-generated shared object file (which gets generated during build time), the uhd/ subdirectory in host/python exactly resembles the Python module once installed, so it's more obvious where to add new submodules and files. --- host/python/CMakeLists.txt | 14 ++-- host/python/__init__.py | 13 ---- host/python/filters.py | 16 ----- host/python/rfnoc.py | 20 ------ host/python/types.py | 32 --------- host/python/uhd/__init__.py | 13 ++++ host/python/uhd/filters.py | 16 +++++ host/python/uhd/rfnoc.py | 20 ++++++ host/python/uhd/types.py | 32 +++++++++ host/python/uhd/usrp/__init__.py | 17 +++++ host/python/uhd/usrp/libtypes.py | 29 ++++++++ host/python/uhd/usrp/multi_usrp.py | 128 +++++++++++++++++++++++++++++++++ host/python/usrp.py | 141 ------------------------------------- 13 files changed, 262 insertions(+), 229 deletions(-) delete mode 100644 host/python/__init__.py delete mode 100644 host/python/filters.py delete mode 100644 host/python/rfnoc.py delete mode 100644 host/python/types.py create mode 100644 host/python/uhd/__init__.py create mode 100644 host/python/uhd/filters.py create mode 100644 host/python/uhd/rfnoc.py create mode 100644 host/python/uhd/types.py create mode 100644 host/python/uhd/usrp/__init__.py create mode 100644 host/python/uhd/usrp/libtypes.py create mode 100644 host/python/uhd/usrp/multi_usrp.py delete mode 100644 host/python/usrp.py diff --git a/host/python/CMakeLists.txt b/host/python/CMakeLists.txt index 9c5503881..a4929b977 100644 --- a/host/python/CMakeLists.txt +++ b/host/python/CMakeLists.txt @@ -65,12 +65,12 @@ endif(WIN32) add_custom_command(TARGET pyuhd POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR}/uhd/$) -set(PYUHD_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py - ${CMAKE_CURRENT_SOURCE_DIR}/types.py - ${CMAKE_CURRENT_SOURCE_DIR}/usrp.py - ${CMAKE_CURRENT_SOURCE_DIR}/filters.py - ${CMAKE_CURRENT_SOURCE_DIR}/rfnoc.py +# List of Python files that are part of the module but don't get +# generated during build time. +# Note: When adding Python files into uhd/, they don't get added to the +# dependency list until CMake is re-run. +file(GLOB_RECURSE PYUHD_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/uhd/*.py ) set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") @@ -81,7 +81,7 @@ file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR} NATIVE_CURRENT_BINARY_DIR) 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 ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/uhd ${CMAKE_CURRENT_BINARY_DIR}/uhd COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} -q build COMMAND ${CMAKE_COMMAND} -E touch ${TIMESTAMP_FILE} DEPENDS ${PYUHD_FILES}) diff --git a/host/python/__init__.py b/host/python/__init__.py deleted file mode 100644 index bf37f5215..000000000 --- a/host/python/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# -# Copyright 2017-2018 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -""" -UHD Python API module -""" - -from . import types -from . import usrp -from . import filters -from . import rfnoc diff --git a/host/python/filters.py b/host/python/filters.py deleted file mode 100644 index 8479b56e1..000000000 --- a/host/python/filters.py +++ /dev/null @@ -1,16 +0,0 @@ -# -# 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/rfnoc.py b/host/python/rfnoc.py deleted file mode 100644 index af8200998..000000000 --- a/host/python/rfnoc.py +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright 2019 Ettus Research, a National Instruments Brand -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -""" @package rfnoc -Python UHD module containing the RFNoC API. -""" - -from . import libpyuhd as lib - -BlockID = lib.rfnoc.block_id -Edge = lib.rfnoc.edge -GraphEdge = lib.rfnoc.graph_edge -Source = lib.rfnoc.source -ResSourceInfo = lib.rfnoc.res_source_info -RfnocGraph = lib.rfnoc.rfnoc_graph -MBController = lib.rfnoc.mb_controller -Timekeeper = lib.rfnoc.timekeeper -NocBlock = lib.rfnoc.noc_block_base diff --git a/host/python/types.py b/host/python/types.py deleted file mode 100644 index ad96076f3..000000000 --- a/host/python/types.py +++ /dev/null @@ -1,32 +0,0 @@ -# -# 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 -DeviceAddr = lib.types.device_addr -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 -MetaRange = lib.types.meta_range_t -GainRange = lib.types.meta_range_t -FreqRange = lib.types.meta_range_t -RXMetadata = lib.types.rx_metadata -TXMetadata = lib.types.tx_metadata -TXAsyncMetadata = lib.types.async_metadata -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/uhd/__init__.py b/host/python/uhd/__init__.py new file mode 100644 index 000000000..bf37f5215 --- /dev/null +++ b/host/python/uhd/__init__.py @@ -0,0 +1,13 @@ +# +# Copyright 2017-2018 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" +UHD Python API module +""" + +from . import types +from . import usrp +from . import filters +from . import rfnoc diff --git a/host/python/uhd/filters.py b/host/python/uhd/filters.py new file mode 100644 index 000000000..8479b56e1 --- /dev/null +++ b/host/python/uhd/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/uhd/rfnoc.py b/host/python/uhd/rfnoc.py new file mode 100644 index 000000000..af8200998 --- /dev/null +++ b/host/python/uhd/rfnoc.py @@ -0,0 +1,20 @@ +# +# Copyright 2019 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" @package rfnoc +Python UHD module containing the RFNoC API. +""" + +from . import libpyuhd as lib + +BlockID = lib.rfnoc.block_id +Edge = lib.rfnoc.edge +GraphEdge = lib.rfnoc.graph_edge +Source = lib.rfnoc.source +ResSourceInfo = lib.rfnoc.res_source_info +RfnocGraph = lib.rfnoc.rfnoc_graph +MBController = lib.rfnoc.mb_controller +Timekeeper = lib.rfnoc.timekeeper +NocBlock = lib.rfnoc.noc_block_base diff --git a/host/python/uhd/types.py b/host/python/uhd/types.py new file mode 100644 index 000000000..ad96076f3 --- /dev/null +++ b/host/python/uhd/types.py @@ -0,0 +1,32 @@ +# +# 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 +DeviceAddr = lib.types.device_addr +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 +MetaRange = lib.types.meta_range_t +GainRange = lib.types.meta_range_t +FreqRange = lib.types.meta_range_t +RXMetadata = lib.types.rx_metadata +TXMetadata = lib.types.tx_metadata +TXAsyncMetadata = lib.types.async_metadata +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/uhd/usrp/__init__.py b/host/python/uhd/usrp/__init__.py new file mode 100644 index 000000000..c7a630258 --- /dev/null +++ b/host/python/uhd/usrp/__init__.py @@ -0,0 +1,17 @@ +# +# Copyright 2020 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" @package usrp +Python UHD module containing the MultiUSRP and other objects +""" + +from .multi_usrp import MultiUSRP +# Disable PyLint because the entire libtypes modules is a list of renames. It is +# thus less redundant to do a wildcard import, even if generally discouraged. +# We could also paste the contents of libtypes.py into here, but by leaving it +# separate we avoid importing the lib module in this __init__ file. +# pylint: disable=wildcard-import +from .libtypes import * +# pylint: enable=wildcard-import diff --git a/host/python/uhd/usrp/libtypes.py b/host/python/uhd/usrp/libtypes.py new file mode 100644 index 000000000..2c3170387 --- /dev/null +++ b/host/python/uhd/usrp/libtypes.py @@ -0,0 +1,29 @@ +# +# 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 +""" + +from .. import libpyuhd as lib + +# Disable PyLint because we want to make it look like the following classes are +# defined in Python, but they're just renames of lib types. They therefore +# follow name conventions for Python classes, not for global constants. +# pylint: disable=invalid-name +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 +# pylint: enable=invalid-name diff --git a/host/python/uhd/usrp/multi_usrp.py b/host/python/uhd/usrp/multi_usrp.py new file mode 100644 index 000000000..adb03d436 --- /dev/null +++ b/host/python/uhd/usrp/multi_usrp.py @@ -0,0 +1,128 @@ +# +# 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 + """ + 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 + + 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 + + diff --git a/host/python/usrp.py b/host/python/usrp.py deleted file mode 100644 index ce141d683..000000000 --- a/host/python/usrp.py +++ /dev/null @@ -1,141 +0,0 @@ -# -# 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 - """ - 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 - - 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 -- cgit v1.2.3