diff --git a/adi/compat.py b/adi/compat.py new file mode 100644 index 000000000..88c641f93 --- /dev/null +++ b/adi/compat.py @@ -0,0 +1,91 @@ +# Copyright (C) 2023 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD +"""Compatibility module for libiio v1.X.""" + +from typing import Any + +import iio + + +class compat_libiio: + """Compatibility class for libiio v1.X.""" + + def __is_libiio_v1(self): + """Check is we are using >= v1.X.""" + v = iio.version + return v[0] >= 1 + + def _setup_v1_rx(self): + """Setup for libiio v1.X RX side.""" + self._rx_buffer_mask = None + self.__rx_stream = None + self._rx_buffer_num_blocks = 4 + + def _setup_v1_tx(self): + """Setup for libiio v1.X TX side.""" + self._tx_buffer_mask = None + self.__tx_stream = None + self._tx_buffer_num_blocks = 4 + + def __getattr__(self, __name: str) -> Any: + if __name in ["_rx_init_channels", "_tx_init_channels", "__tx_buffer_push"]: + if self.__is_libiio_v1(): + return getattr(self, f"_{__name}_v1") + else: + return getattr(self, f"_{__name}") + + def _rx_init_channels_v1(self): + if not self._rx_buffer_mask: + self._rx_buffer_mask = iio.ChannelsMask(self._rxadc) + + channels = [] + if self._complex_data: + for m in self.rx_enabled_channels: + v = self._rxadc.find_channel(self._rx_channel_names[m * 2]) + channels.append(v) + v = self._rxadc.find_channel(self._rx_channel_names[m * 2 + 1]) + channels.append(v) + else: + for m in self.rx_enabled_channels: + v = self._rxadc.find_channel(self._rx_channel_names[m]) + channels.append(v) + + self._rx_buffer_mask.channels = channels + + self.__rxbuf = iio.Buffer(self._rxadc, self._rx_buffer_mask) + self.__rx_stream = iio.Stream( + buffer=self.__rxbuf, + nb_blocks=self._rx_buffer_num_blocks, + samples_count=self.rx_buffer_size, + ) + + def _tx_init_channels_v1(self): + if not self._tx_buffer_mask: + self._tx_buffer_mask = iio.ChannelsMask(self._txdac) + + channels = [] + if self._complex_data: + for m in self.tx_enabled_channels: + v = self._txdac.find_channel(self._tx_channel_names[m * 2], True) + channels.append(v) + v = self._txdac.find_channel(self._tx_channel_names[m * 2 + 1], True) + channels.append(v) + else: + for m in self.tx_enabled_channels: + v = self._txdac.find_channel(self._tx_channel_names[m], True) + channels.append(v) + + self._tx_buffer_mask.channels = channels + + self.__txbuf = iio.Buffer(self._txdac, self._tx_buffer_mask) + self.__block_tx = iio.Block(self.__txbuf, self._tx_buffer_size) + + def __tx_buffer_push_v1(self, data): + """Push data to TX buffer. + + data: bytearray + """ + self.__block_tx.write(data) + self.__block_tx.enqueue(None, self.__tx_cyclic_buffer) + self.__txbuf.enabled = True diff --git a/adi/dds.py b/adi/dds.py index 33c99d544..22247c8a0 100644 --- a/adi/dds.py +++ b/adi/dds.py @@ -142,6 +142,8 @@ def dds_single_tone(self, frequency, scale, channel=0): + "_F1", True, ) + if not chan: + raise Exception(f"DDS Channel {channel} not found") chan.attrs["frequency"].value = str(frequency) chan.attrs["phase"].value = str(90000) chan.attrs["scale"].value = str(scale) diff --git a/adi/rx_tx.py b/adi/rx_tx.py index 05115d168..6ae03a663 100644 --- a/adi/rx_tx.py +++ b/adi/rx_tx.py @@ -9,6 +9,7 @@ import numpy as np from adi.attribute import attribute +from adi.compat import compat_libiio from adi.context_manager import context_manager from adi.dds import dds @@ -20,7 +21,7 @@ def __del__(self): self._ctrl = [] -class rx_tx_common(attribute): +class rx_tx_common(attribute, compat_libiio): """Common functions for RX and TX""" def _annotate(self, data, cnames: List[str], echans: List[int]): @@ -43,9 +44,6 @@ class rx(rx_tx_common): _rx_unbuffered_data = False _rx_annotated = False _rx_stack_interleaved = True # Convert from channel to sample interleaved - _rx_buffer_mask = None - __rx_stream = None - _rx_buffer_num_blocks = 4 def __init__(self, rx_buffer_size=1024): if self._complex_data: @@ -56,6 +54,8 @@ def __init__(self, rx_buffer_size=1024): self._num_rx_channels = len(self._rx_channel_names) self.rx_enabled_channels = rx_enabled_channels self.rx_buffer_size = rx_buffer_size + if self.__is_libiio_v1(): + self._setup_v1_rx() @property def rx_channel_names(self) -> List[str]: @@ -181,30 +181,23 @@ def __get_rx_channel_offsets(self): return rx_offset def _rx_init_channels(self): + for m in self._rx_channel_names: + v = self._rxadc.find_channel(m) + if not v: + raise Exception(f"Channel {m} not found") + v.enabled = False - if not self._rx_buffer_mask: - self._rx_buffer_mask = iio.ChannelsMask(self._rxadc) - - channels = [] if self._complex_data: for m in self.rx_enabled_channels: v = self._rxadc.find_channel(self._rx_channel_names[m * 2]) - channels.append(v) + v.enabled = True v = self._rxadc.find_channel(self._rx_channel_names[m * 2 + 1]) - channels.append(v) + v.enabled = True else: for m in self.rx_enabled_channels: v = self._rxadc.find_channel(self._rx_channel_names[m]) - channels.append(v) - - self._rx_buffer_mask.channels = channels - - self.__rxbuf = iio.Buffer(self._rxadc, self._rx_buffer_mask) - self.__rx_stream = iio.Stream( - buffer=self.__rxbuf, - nb_blocks=self._rx_buffer_num_blocks, - samples_count=self.rx_buffer_size, - ) + v.enabled = True + self.__rxbuf = iio.Buffer(self._rxadc, self.__rx_buffer_size, False) def __rx_unbuffered_data(self): x = [] @@ -242,7 +235,7 @@ def __rx_buffered_data(self) -> Union[List[np.ndarray], np.ndarray]: """ if not self.__rxbuf: self._rx_init_channels() - rx_block = next(self.__rx_stream) + self.__rxbuf.refill() data_channel_interleaved = [] ecn = [] @@ -256,7 +249,7 @@ def __rx_buffered_data(self) -> Union[List[np.ndarray], np.ndarray]: for name in ecn: chan = self._rxadc.find_channel(name) - bytearray_data = chan.read(rx_block) # Do local type conversion + bytearray_data = chan.read(self.__rxbuf) # Do local type conversion # create format strings df = chan.data_format fmt = ("i" if df.is_signed is True else "u") + str(df.length // 8) @@ -332,6 +325,8 @@ def __init__(self, tx_cyclic_buffer=False): self.tx_enabled_channels = tx_enabled_channels self.tx_cyclic_buffer = tx_cyclic_buffer dds.__init__(self) + if self.__is_libiio_v1(): + self._setup_v1_tx() def __del__(self): self.__txbuf = [] @@ -518,8 +513,11 @@ def tx(self, data_np=None): f.write(bytearray(data)) f.close() else: - self.__txbuf.write(bytearray(data)) - self.__txbuf.push() + self.__tx_buffer_push(data) + + def __tx_buffer_push(self, data): + self.__txbuf.write(bytearray(data)) + self.__txbuf.push() class rx_tx(rx, tx, phy): @@ -594,7 +592,6 @@ def __handle_init_args(self, args, kwargs): def __init__( self, *args: Union[str, iio.Context], **kwargs: Union[str, iio.Context] ) -> None: - # Handle Older API and Newer APIs uri_ctx = self.__handle_init_args(args, kwargs) @@ -653,7 +650,6 @@ def _rx_data_device_name(self) -> None: def __init__( self, *args: Union[str, iio.Context], **kwargs: Union[str, iio.Context] ) -> None: - shared_def.__init__(self, *args, **kwargs) if self._rx_data_device_name: @@ -701,7 +697,6 @@ def _tx_data_device_name(self) -> None: def __init__( self, *args: Union[str, iio.Context], **kwargs: Union[str, iio.Context] ) -> None: - shared_def.__init__(self, *args, **kwargs) if self._tx_data_device_name: