From 322c9edbde2e6b2efdf115e2f27a91380f82a9e5 Mon Sep 17 00:00:00 2001 From: Trisha De Vera Date: Sun, 3 Sep 2023 23:42:00 +0800 Subject: [PATCH 1/7] Add ad9375 support --- adi/__init__.py | 2 +- adi/ad9371.py | 325 ------- adi/ad937x.py | 826 ++++++++++++++++++ .../{adi.ad9371.rst => adi.ad937x.rst} | 4 +- doc/source/devices/index.rst | 2 +- examples/ad9375.py | 121 +++ test/attr_tests.py | 59 ++ test/common.py | 12 +- test/conftest.py | 10 + test/emu/hardware_map.yml | 8 + test/test_ad9375.py | 494 +++++++++++ 11 files changed, 1531 insertions(+), 332 deletions(-) delete mode 100644 adi/ad9371.py create mode 100644 adi/ad937x.py rename doc/source/devices/{adi.ad9371.rst => adi.ad937x.rst} (68%) create mode 100644 examples/ad9375.py create mode 100644 test/test_ad9375.py diff --git a/adi/__init__.py b/adi/__init__.py index 5f49b8de8..fc6e920f7 100644 --- a/adi/__init__.py +++ b/adi/__init__.py @@ -9,6 +9,7 @@ from adi.ad719x import ad719x from adi.ad777x import ad777x from adi.ad936x import Pluto, ad9361, ad9363, ad9364 +from adi.ad937x import ad9371, ad9375 from adi.ad4020 import ad4020 from adi.ad4110 import ad4110 from adi.ad4130 import ad4130 @@ -40,7 +41,6 @@ from adi.ad9172 import ad9172 from adi.ad9250 import ad9250 from adi.ad9265 import ad9265 -from adi.ad9371 import ad9371 from adi.ad9434 import ad9434 from adi.ad9467 import ad9467 from adi.ad9625 import ad9625 diff --git a/adi/ad9371.py b/adi/ad9371.py deleted file mode 100644 index cb20fb3d5..000000000 --- a/adi/ad9371.py +++ /dev/null @@ -1,325 +0,0 @@ -# Copyright (C) 2019-2023 Analog Devices, Inc. -# -# SPDX short identifier: ADIBSD - -from adi.context_manager import context_manager -from adi.jesd import jesd -from adi.obs import obs -from adi.rx_tx import rx_tx -from adi.sync_start import sync_start - - -class ad9371(rx_tx, context_manager, sync_start): - """ AD9371 Transceiver """ - - _complex_data = True - _rx_channel_names = ["voltage0_i", "voltage0_q", "voltage1_i", "voltage1_q"] - _tx_channel_names = ["voltage0", "voltage1", "voltage2", "voltage3"] - _obs_channel_names = ["voltage0_i", "voltage0_q"] - _device_name = "" - - def __init__( - self, uri="", username="root", password="analog", disable_jesd_control=False - ): - """Initialize AD9371 interface class. - Args: - uri (str): URI of target platform with AD9371 - username (str): SSH username for target board. Required for JESD monitoring - password (str): SSH password for target board. Required for JESD monitoring - disable_jesd_control (bool): Disable JESD status monitoring over SSH - """ - context_manager.__init__(self, uri, self._device_name) - - self._ctrl = self._ctx.find_device("ad9371-phy") - self._rxadc = self._ctx.find_device("axi-ad9371-rx-hpc") - self._rxobs = self._ctx.find_device("axi-ad9371-rx-obs-hpc") - self._txdac = self._ctx.find_device("axi-ad9371-tx-hpc") - - if not disable_jesd_control and jesd: - self._jesd = jesd(uri, username=username, password=password) - - rx_tx.__init__(self) - - self.obs = obs(self._ctx, self._rxobs, self._obs_channel_names) - - @property - def ensm_mode(self): - """ensm_mode: Enable State Machine State Allows real time control over - the current state of the device. Options are: radio_on, radio_off""" - return self._get_iio_dev_attr_str("ensm_mode") - - @ensm_mode.setter - def ensm_mode(self, value): - self._set_iio_dev_attr_str("ensm_mode", value) - - @property - def gain_control_mode(self): - """gain_control_mode: Mode of receive path AGC. Options are: - automatic, hybrid, manual""" - return self._get_iio_attr_str("voltage0", "gain_control_mode", False) - - @gain_control_mode.setter - def gain_control_mode(self, value): - self._set_iio_attr("voltage0", "gain_control_mode", False, value) - - @property - def rx_quadrature_tracking_en_chan0(self): - """Enable Quadrature tracking calibration for RX1""" - return self._get_iio_attr("voltage0", "quadrature_tracking_en", False) - - @rx_quadrature_tracking_en_chan0.setter - def rx_quadrature_tracking_en_chan0(self, value): - self._set_iio_attr("voltage0", "quadrature_tracking_en", False, value) - - @property - def rx_quadrature_tracking_en_chan1(self): - """Enable Quadrature tracking calibration for RX2""" - return self._get_iio_attr("voltage1", "quadrature_tracking_en", False) - - @rx_quadrature_tracking_en_chan1.setter - def rx_quadrature_tracking_en_chan1(self, value): - self._set_iio_attr("voltage1", "quadrature_tracking_en", False, value) - - @property - def rx_hardwaregain_chan0(self): - """rx_hardwaregain: Gain applied to RX path channel 0. Only applicable when - gain_control_mode is set to 'manual'""" - return self._get_iio_attr("voltage0", "hardwaregain", False) - - @rx_hardwaregain_chan0.setter - def rx_hardwaregain_chan0(self, value): - if self.gain_control_mode == "manual": - self._set_iio_attr("voltage0", "hardwaregain", False, value) - - @property - def rx_hardwaregain_chan1(self): - """rx_hardwaregain: Gain applied to RX path channel 1. Only applicable when - gain_control_mode is set to 'manual'""" - return self._get_iio_attr("voltage1", "hardwaregain", False) - - @rx_hardwaregain_chan1.setter - def rx_hardwaregain_chan1(self, value): - if self.gain_control_mode == "manual": - self._set_iio_attr("voltage1", "hardwaregain", False, value) - - @property - def rx_temp_comp_gain_chan0(self): - """rx_temp_comp_gain_chan0: """ - return self._get_iio_attr("voltage0", "temp_comp_gain", False) - - @rx_temp_comp_gain_chan0.setter - def rx_temp_comp_gain_chan0(self, value): - self._set_iio_attr("voltage0", "temp_comp_gain", False, value) - - @property - def rx_temp_comp_gain_chan1(self): - """rx_temp_comp_gain_chan1: """ - return self._get_iio_attr("voltage1", "temp_comp_gain", False) - - @rx_temp_comp_gain_chan1.setter - def rx_temp_comp_gain_chan1(self, value): - self._set_iio_attr("voltage1", "temp_comp_gain", False, value) - - @property - def tx_quadrature_tracking_en_chan0(self): - """Enable Quadrature tracking calibration for TX1""" - return self._get_iio_attr("voltage0", "quadrature_tracking_en", True) - - @tx_quadrature_tracking_en_chan0.setter - def tx_quadrature_tracking_en_chan0(self, value): - self._set_iio_attr("voltage0", "quadrature_tracking_en", True, value) - - @property - def tx_quadrature_tracking_en_chan1(self): - """Enable Quadrature tracking calibration for TX2""" - return self._get_iio_attr("voltage1", "quadrature_tracking_en", True) - - @tx_quadrature_tracking_en_chan1.setter - def tx_quadrature_tracking_en_chan1(self, value): - self._set_iio_attr("voltage1", "quadrature_tracking_en", True, value) - - @property - def tx_hardwaregain_chan0(self): - """tx_hardwaregain: Attenuation applied to TX path channel 0""" - return self._get_iio_attr("voltage0", "hardwaregain", True) - - @tx_hardwaregain_chan0.setter - def tx_hardwaregain_chan0(self, value): - self._set_iio_attr("voltage0", "hardwaregain", True, value) - - @property - def tx_hardwaregain_chan1(self): - """tx_hardwaregain: Attenuation applied to TX path channel 1""" - return self._get_iio_attr("voltage1", "hardwaregain", True) - - @tx_hardwaregain_chan1.setter - def tx_hardwaregain_chan1(self, value): - self._set_iio_attr("voltage1", "hardwaregain", True, value) - - @property - def rx_rf_bandwidth(self): - """rx_rf_bandwidth: Bandwidth of front-end analog filter of RX path""" - return self._get_iio_attr("voltage0", "rf_bandwidth", False) - - @property - def tx_rf_bandwidth(self): - """tx_rf_bandwidth: Bandwidth of front-end analog filter of TX path""" - return self._get_iio_attr("voltage0", "rf_bandwidth", True) - - @property - def rx_enable_dec8(self): - """rx_enable_dec8: Enable x8 decimation filter in RX path""" - avail = self._get_iio_attr_str( - "voltage0_i", "sampling_frequency_available", False, self._rxadc - ) - avail = avail.strip().split(" ") - val = self._get_iio_attr_str( - "voltage0_i", "sampling_frequency", False, self._rxadc - ) - return val == avail[1] - - @rx_enable_dec8.setter - def rx_enable_dec8(self, value): - avail = self._get_iio_attr_str( - "voltage0_i", "sampling_frequency_available", False, self._rxadc - ) - avail = sorted(avail.strip().split(" ")) - val = int(avail[1] if value else avail[0]) - self._set_iio_attr("voltage0_i", "sampling_frequency", False, val, self._rxadc) - - @property - def tx_enable_int8(self): - """tx_enable_int8: Enable x8 interpolation filter in TX path""" - avail = self._get_iio_attr_str( - "voltage0", "sampling_frequency_available", True, self._txdac - ) - avail = avail.strip().split(" ") - val = self._get_iio_attr_str( - "voltage0", "sampling_frequency", True, self._txdac - ) - return val == avail[1] - - @tx_enable_int8.setter - def tx_enable_int8(self, value): - avail = self._get_iio_attr_str( - "voltage0", "sampling_frequency_available", True, self._txdac - ) - avail = sorted(avail.strip().split(" ")) - val = int(avail[1] if value else avail[0]) - self._set_iio_attr("voltage0", "sampling_frequency", True, val, self._txdac) - - @property - def rx_sample_rate(self): - """rx_sample_rate: Sample rate RX path in samples per second - This value will reflect the correct value when 8x decimator is enabled - """ - dec = 8 if self.rx_enable_dec8 else 1 - return self._get_iio_attr("voltage0", "sampling_frequency", False) / dec - - @property - def orx_sample_rate(self): - """orx_sample_rate: Sample rate ORX path in samples per second - This value will reflect the correct value when 8x decimator is enabled - """ - dec = 8 if self.rx_enable_dec8 else 1 - return self._get_iio_attr("voltage2", "sampling_frequency", False) / dec - - @property - def tx_sample_rate(self): - """tx_sample_rate: Sample rate TX path in samples per second - This value will reflect the correct value when 8x interpolator is enabled - """ - dec = 8 if self.tx_enable_int8 else 1 - return self._get_iio_attr("voltage0", "sampling_frequency", True) / dec - - @property - def rx_lo(self): - """rx_lo: Carrier frequency of RX path""" - return self._get_iio_attr("altvoltage0", "frequency", True) - - @rx_lo.setter - def rx_lo(self, value): - self._set_iio_attr("altvoltage0", "frequency", True, value) - - @property - def tx_lo(self): - """tx_lo: Carrier frequency of TX path""" - return self._get_iio_attr("altvoltage1", "frequency", True) - - @tx_lo.setter - def tx_lo(self, value): - self._set_iio_attr("altvoltage1", "frequency", True, value) - - @property - def sn_lo(self): - """sn_lo: Carrier frequency of Sniffer/ORx path""" - return self._get_iio_attr("altvoltage2", "frequency", True) - - @sn_lo.setter - def sn_lo(self, value): - self._set_iio_attr("altvoltage2", "frequency", True, value) - - @property - def obs_gain_control_mode(self): - """obs_gain_control_mode: Mode of Obs/Sniffer receive path AGC. Options are: - automatic, hybrid, manual""" - return self._get_iio_attr_str("voltage2", "gain_control_mode", False) - - @obs_gain_control_mode.setter - def obs_gain_control_mode(self, value): - self._set_iio_attr("voltage2", "gain_control_mode", False, value) - - @property - def obs_hardwaregain(self): - """obs_hardwaregain: Gain applied to Obs/Sniffer receive path chan0. Only applicable when - obs_gain_control_mode is set to 'manual'""" - return self._get_iio_attr("voltage2", "hardwaregain", False) - - @obs_hardwaregain.setter - def obs_hardwaregain(self, value): - if self.obs_gain_control_mode == "manual": - self._set_iio_attr("voltage2", "hardwaregain", False, value) - - @property - def obs_temp_comp_gain(self): - """obs_temp_comp_gain: """ - return self._get_iio_attr("voltage2", "temp_comp_gain", False) - - @obs_temp_comp_gain.setter - def obs_temp_comp_gain(self, value): - self._set_iio_attr("voltage2", "temp_comp_gain", False, value) - - @property - def obs_quadrature_tracking_en(self): - """Enable Quadrature tracking calibration for OBS chan0""" - return self._get_iio_attr("voltage2", "quadrature_tracking_en", False) - - @obs_quadrature_tracking_en.setter - def obs_quadrature_tracking_en(self, value): - self._set_iio_attr("voltage2", "quadrature_tracking_en", False, value) - - @property - def obs_rf_port_select(self): - """obs_rf_port_select: Observation path source. Options are: - - - OFF - SnRx path is disabled - - ORX1_TX_LO – SnRx operates in observation mode on ORx1 with Tx LO synthesizer - - ORX2_TX_LO – SnRx operates in observation mode on ORx2 with Tx LO synthesizer - - INTERNALCALS – enables scheduled Tx calibrations while using SnRx path. The enableTrackingCals function needs to be called in RADIO_OFF state. It sets the calibration mask, which the scheduler will later use to schedule the desired calibrations. This command is issued in RADIO_OFF. Once the AD9371 moves to RADIO_ON state, the internal scheduler will use the enabled calibration mask to schedule calibrations whenever possible, based on the state of the transceiver. The Tx calibrations will not be scheduled until INTERNALCALS is selected and the Tx calibrations are enabled in the cal mask. - - OBS_SNIFFER – SnRx operates in sniffer mode with latest selected Sniffer Input – for hardware pin control operation. In pin mode, the GPIO pins designated for ORX_MODE would select SNIFFER mode. Then MYKONOS_setSnifferChannel function would choose the channel. - - ORX1_SN_LO – SnRx operates in observation mode on ORx1 with SNIFFER LO synthesizer - - ORX2_SN_LO – SnRx operates in observation mode on ORx2 with SNIFFER LO synthesizer - - SN_A – SnRx operates in sniffer mode on SnRxA with SNIFFER LO synthesizer - - SN_B – SnRx operates in sniffer mode on SnRxB with SNIFFER LO synthesizer - - SN_C – SnRx operates in sniffer mode on SnRxC with SNIFFER LO synthesizer - - """ - return self._get_iio_attr_str("voltage2", "rf_port_select", False) - - @obs_rf_port_select.setter - def obs_rf_port_select(self, value): - self._set_iio_attr("voltage2", "rf_port_select", False, value) - - @property - def jesd204_statuses(self): - return self._jesd.get_all_statuses() diff --git a/adi/ad937x.py b/adi/ad937x.py new file mode 100644 index 000000000..d811a321d --- /dev/null +++ b/adi/ad937x.py @@ -0,0 +1,826 @@ +# Copyright (C) 2019-2023 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD + +from adi.context_manager import context_manager +from adi.jesd import jesd +from adi.obs import obs +from adi.rx_tx import rx_tx +from adi.sync_start import sync_start + + +class ad9371(rx_tx, context_manager, sync_start): + """ AD9371 Transceiver """ + + _complex_data = True + _rx_channel_names = ["voltage0_i", "voltage0_q", "voltage1_i", "voltage1_q"] + _tx_channel_names = ["voltage0", "voltage1", "voltage2", "voltage3"] + _obs_channel_names = ["voltage0_i", "voltage0_q"] + _device_name = "" + + def __init__( + self, uri="", username="root", password="analog", disable_jesd_control=False + ): + """Initialize AD9371 interface class. + Args: + uri (str): URI of target platform with AD9371 + username (str): SSH username for target board. Required for JESD monitoring + password (str): SSH password for target board. Required for JESD monitoring + disable_jesd_control (bool): Disable JESD status monitoring over SSH + """ + context_manager.__init__(self, uri, self._device_name) + + self._ctrl = self._ctx.find_device("ad9371-phy") + self._rxadc = self._ctx.find_device("axi-ad9371-rx-hpc") + self._rxobs = self._ctx.find_device("axi-ad9371-rx-obs-hpc") + self._txdac = self._ctx.find_device("axi-ad9371-tx-hpc") + + if not disable_jesd_control and jesd: + self._jesd = jesd(uri, username=username, password=password) + + rx_tx.__init__(self) + + self.obs = obs(self._ctx, self._rxobs, self._obs_channel_names) + + @property + def ensm_mode(self): + """ensm_mode: Enable State Machine State Allows real time control over + the current state of the device. Options are: radio_on, radio_off""" + return self._get_iio_dev_attr_str("ensm_mode") + + @ensm_mode.setter + def ensm_mode(self, value): + self._set_iio_dev_attr_str("ensm_mode", value) + + @property + def gain_control_mode(self): + """gain_control_mode: Mode of receive path AGC. Options are: + automatic, hybrid, manual""" + return self._get_iio_attr_str("voltage0", "gain_control_mode", False) + + @gain_control_mode.setter + def gain_control_mode(self, value): + self._set_iio_attr("voltage0", "gain_control_mode", False, value) + + @property + def rx_quadrature_tracking_en_chan0(self): + """Enable Quadrature tracking calibration for RX1""" + return self._get_iio_attr("voltage0", "quadrature_tracking_en", False) + + @rx_quadrature_tracking_en_chan0.setter + def rx_quadrature_tracking_en_chan0(self, value): + self._set_iio_attr("voltage0", "quadrature_tracking_en", False, value) + + @property + def rx_quadrature_tracking_en_chan1(self): + """Enable Quadrature tracking calibration for RX2""" + return self._get_iio_attr("voltage1", "quadrature_tracking_en", False) + + @rx_quadrature_tracking_en_chan1.setter + def rx_quadrature_tracking_en_chan1(self, value): + self._set_iio_attr("voltage1", "quadrature_tracking_en", False, value) + + @property + def rx_hardwaregain_chan0(self): + """rx_hardwaregain: Gain applied to RX path channel 0. Only applicable when + gain_control_mode is set to 'manual'""" + return self._get_iio_attr("voltage0", "hardwaregain", False) + + @rx_hardwaregain_chan0.setter + def rx_hardwaregain_chan0(self, value): + if self.gain_control_mode == "manual": + self._set_iio_attr("voltage0", "hardwaregain", False, value) + + @property + def rx_hardwaregain_chan1(self): + """rx_hardwaregain: Gain applied to RX path channel 1. Only applicable when + gain_control_mode is set to 'manual'""" + return self._get_iio_attr("voltage1", "hardwaregain", False) + + @rx_hardwaregain_chan1.setter + def rx_hardwaregain_chan1(self, value): + if self.gain_control_mode == "manual": + self._set_iio_attr("voltage1", "hardwaregain", False, value) + + @property + def rx_temp_comp_gain_chan0(self): + """rx_temp_comp_gain_chan0: """ + return self._get_iio_attr("voltage0", "temp_comp_gain", False) + + @rx_temp_comp_gain_chan0.setter + def rx_temp_comp_gain_chan0(self, value): + self._set_iio_attr("voltage0", "temp_comp_gain", False, value) + + @property + def rx_temp_comp_gain_chan1(self): + """rx_temp_comp_gain_chan1: """ + return self._get_iio_attr("voltage1", "temp_comp_gain", False) + + @rx_temp_comp_gain_chan1.setter + def rx_temp_comp_gain_chan1(self, value): + self._set_iio_attr("voltage1", "temp_comp_gain", False, value) + + @property + def tx_quadrature_tracking_en_chan0(self): + """Enable Quadrature tracking calibration for TX1""" + return self._get_iio_attr("voltage0", "quadrature_tracking_en", True) + + @tx_quadrature_tracking_en_chan0.setter + def tx_quadrature_tracking_en_chan0(self, value): + self._set_iio_attr("voltage0", "quadrature_tracking_en", True, value) + + @property + def tx_quadrature_tracking_en_chan1(self): + """Enable Quadrature tracking calibration for TX2""" + return self._get_iio_attr("voltage1", "quadrature_tracking_en", True) + + @tx_quadrature_tracking_en_chan1.setter + def tx_quadrature_tracking_en_chan1(self, value): + self._set_iio_attr("voltage1", "quadrature_tracking_en", True, value) + + @property + def tx_hardwaregain_chan0(self): + """tx_hardwaregain: Attenuation applied to TX path channel 0""" + return self._get_iio_attr("voltage0", "hardwaregain", True) + + @tx_hardwaregain_chan0.setter + def tx_hardwaregain_chan0(self, value): + self._set_iio_attr("voltage0", "hardwaregain", True, value) + + @property + def tx_hardwaregain_chan1(self): + """tx_hardwaregain: Attenuation applied to TX path channel 1""" + return self._get_iio_attr("voltage1", "hardwaregain", True) + + @tx_hardwaregain_chan1.setter + def tx_hardwaregain_chan1(self, value): + self._set_iio_attr("voltage1", "hardwaregain", True, value) + + @property + def rx_rf_bandwidth(self): + """rx_rf_bandwidth: Bandwidth of front-end analog filter of RX path""" + return self._get_iio_attr("voltage0", "rf_bandwidth", False) + + @property + def tx_rf_bandwidth(self): + """tx_rf_bandwidth: Bandwidth of front-end analog filter of TX path""" + return self._get_iio_attr("voltage0", "rf_bandwidth", True) + + @property + def rx_enable_dec8(self): + """rx_enable_dec8: Enable x8 decimation filter in RX path""" + avail = self._get_iio_attr_str( + "voltage0_i", "sampling_frequency_available", False, self._rxadc + ) + avail = avail.strip().split(" ") + val = self._get_iio_attr_str( + "voltage0_i", "sampling_frequency", False, self._rxadc + ) + return val == avail[1] + + @rx_enable_dec8.setter + def rx_enable_dec8(self, value): + avail = self._get_iio_attr_str( + "voltage0_i", "sampling_frequency_available", False, self._rxadc + ) + avail = sorted(avail.strip().split(" ")) + val = int(avail[1] if value else avail[0]) + self._set_iio_attr("voltage0_i", "sampling_frequency", False, val, self._rxadc) + + @property + def tx_enable_int8(self): + """tx_enable_int8: Enable x8 interpolation filter in TX path""" + avail = self._get_iio_attr_str( + "voltage0", "sampling_frequency_available", True, self._txdac + ) + avail = avail.strip().split(" ") + val = self._get_iio_attr_str( + "voltage0", "sampling_frequency", True, self._txdac + ) + return val == avail[1] + + @tx_enable_int8.setter + def tx_enable_int8(self, value): + avail = self._get_iio_attr_str( + "voltage0", "sampling_frequency_available", True, self._txdac + ) + avail = sorted(avail.strip().split(" ")) + val = int(avail[1] if value else avail[0]) + self._set_iio_attr("voltage0", "sampling_frequency", True, val, self._txdac) + + @property + def rx_sample_rate(self): + """rx_sample_rate: Sample rate RX path in samples per second + This value will reflect the correct value when 8x decimator is enabled + """ + dec = 8 if self.rx_enable_dec8 else 1 + return self._get_iio_attr("voltage0", "sampling_frequency", False) / dec + + @property + def orx_sample_rate(self): + """orx_sample_rate: Sample rate ORX path in samples per second + This value will reflect the correct value when 8x decimator is enabled + """ + dec = 8 if self.rx_enable_dec8 else 1 + return self._get_iio_attr("voltage2", "sampling_frequency", False) / dec + + @property + def tx_sample_rate(self): + """tx_sample_rate: Sample rate TX path in samples per second + This value will reflect the correct value when 8x interpolator is enabled + """ + dec = 8 if self.tx_enable_int8 else 1 + return self._get_iio_attr("voltage0", "sampling_frequency", True) / dec + + @property + def rx_lo(self): + """rx_lo: Carrier frequency of RX path""" + return self._get_iio_attr("altvoltage0", "frequency", True) + + @rx_lo.setter + def rx_lo(self, value): + self._set_iio_attr("altvoltage0", "frequency", True, value) + + @property + def tx_lo(self): + """tx_lo: Carrier frequency of TX path""" + return self._get_iio_attr("altvoltage1", "frequency", True) + + @tx_lo.setter + def tx_lo(self, value): + self._set_iio_attr("altvoltage1", "frequency", True, value) + + @property + def sn_lo(self): + """sn_lo: Carrier frequency of Sniffer/ORx path""" + return self._get_iio_attr("altvoltage2", "frequency", True) + + @sn_lo.setter + def sn_lo(self, value): + self._set_iio_attr("altvoltage2", "frequency", True, value) + + @property + def obs_gain_control_mode(self): + """obs_gain_control_mode: Mode of Obs/Sniffer receive path AGC. Options are: + automatic, hybrid, manual""" + return self._get_iio_attr_str("voltage2", "gain_control_mode", False) + + @obs_gain_control_mode.setter + def obs_gain_control_mode(self, value): + self._set_iio_attr("voltage2", "gain_control_mode", False, value) + + @property + def obs_hardwaregain(self): + """obs_hardwaregain: Gain applied to Obs/Sniffer receive path chan0. Only applicable when + obs_gain_control_mode is set to 'manual'""" + return self._get_iio_attr("voltage2", "hardwaregain", False) + + @obs_hardwaregain.setter + def obs_hardwaregain(self, value): + if self.obs_gain_control_mode == "manual": + self._set_iio_attr("voltage2", "hardwaregain", False, value) + + @property + def obs_temp_comp_gain(self): + """obs_temp_comp_gain: """ + return self._get_iio_attr("voltage2", "temp_comp_gain", False) + + @obs_temp_comp_gain.setter + def obs_temp_comp_gain(self, value): + self._set_iio_attr("voltage2", "temp_comp_gain", False, value) + + @property + def obs_quadrature_tracking_en(self): + """Enable Quadrature tracking calibration for OBS chan0""" + return self._get_iio_attr("voltage2", "quadrature_tracking_en", False) + + @obs_quadrature_tracking_en.setter + def obs_quadrature_tracking_en(self, value): + self._set_iio_attr("voltage2", "quadrature_tracking_en", False, value) + + @property + def obs_rf_port_select(self): + """obs_rf_port_select: Observation path source. Options are: + + - OFF - SnRx path is disabled + - ORX1_TX_LO – SnRx operates in observation mode on ORx1 with Tx LO synthesizer + - ORX2_TX_LO – SnRx operates in observation mode on ORx2 with Tx LO synthesizer + - INTERNALCALS – enables scheduled Tx calibrations while using SnRx path. The enableTrackingCals function needs to be called in RADIO_OFF state. It sets the calibration mask, which the scheduler will later use to schedule the desired calibrations. This command is issued in RADIO_OFF. Once the AD9371 moves to RADIO_ON state, the internal scheduler will use the enabled calibration mask to schedule calibrations whenever possible, based on the state of the transceiver. The Tx calibrations will not be scheduled until INTERNALCALS is selected and the Tx calibrations are enabled in the cal mask. + - OBS_SNIFFER – SnRx operates in sniffer mode with latest selected Sniffer Input – for hardware pin control operation. In pin mode, the GPIO pins designated for ORX_MODE would select SNIFFER mode. Then MYKONOS_setSnifferChannel function would choose the channel. + - ORX1_SN_LO – SnRx operates in observation mode on ORx1 with SNIFFER LO synthesizer + - ORX2_SN_LO – SnRx operates in observation mode on ORx2 with SNIFFER LO synthesizer + - SN_A – SnRx operates in sniffer mode on SnRxA with SNIFFER LO synthesizer + - SN_B – SnRx operates in sniffer mode on SnRxB with SNIFFER LO synthesizer + - SN_C – SnRx operates in sniffer mode on SnRxC with SNIFFER LO synthesizer + + """ + return self._get_iio_attr_str("voltage2", "rf_port_select", False) + + @obs_rf_port_select.setter + def obs_rf_port_select(self, value): + self._set_iio_attr("voltage2", "rf_port_select", False, value) + + @property + def jesd204_statuses(self): + return self._jesd.get_all_statuses() + + +class ad9375(ad9371): + """ AD9375 Transceiver """ + + @property + def tx_clgc_tracking_en_chan0(self): + """Enable CLGC tracking for channel 0""" + if self._get_iio_attr("voltage0", "clgc_tracking_en", True) == 1: + return True + elif self._get_iio_attr("voltage0", "clgc_tracking_en", True) == 0: + return False + return + + @tx_clgc_tracking_en_chan0.setter + def tx_clgc_tracking_en_chan0(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage0", "clgc_tracking_en", True, value) + + @property + def tx_clgc_tracking_en_chan1(self): + """Enable CLGC tracking for channel 1""" + if self._get_iio_attr("voltage1", "clgc_tracking_en", True) == 1: + return True + elif self._get_iio_attr("voltage1", "clgc_tracking_en", True) == 0: + return False + return + + @tx_clgc_tracking_en_chan1.setter + def tx_clgc_tracking_en_chan1(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage1", "clgc_tracking_en", True, value) + + @property + def tx_clgc_current_gain_chan0(self): + if self.tx_clgc_tracking_en_chan0 == 1: + """tx_clgc_current_gain: Current measured gain in 1/100ths dB scale in channel 0. + Current GaindB = currentGain/100""" + return self._get_iio_attr("voltage0", "clgc_current_gain", True) + return + + @property + def tx_clgc_current_gain_chan1(self): + """tx_clgc_current_gain: Current measured gain in 1/100ths dB scale in channel 1. + Current GaindB = currentGain/100""" + if self.tx_clgc_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "clgc_current_gain", True) + return + + @property + def tx_clgc_desired_gain_chan0(self): + """tx_clgc_desired_gain: Desired gain from channel 0 output to orx input. + Desired_gain (dB) = Desired_gain/100""" + if self.tx_clgc_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "clgc_desired_gain", True) / 100 + return + + @tx_clgc_desired_gain_chan0.setter + def tx_clgc_desired_gain_chan0(self, value): + value *= 100 + self._set_iio_attr("voltage0", "clgc_desired_gain", True, value) + + @property + def tx_clgc_desired_gain_chan1(self): + """tx_clgc_desired_gain: Desired gain from channel 1 output to orx input. + Desired_gain (dB) = Desired_gain/100""" + if self.tx_clgc_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "clgc_desired_gain", True) / 100 + return + + @tx_clgc_desired_gain_chan1.setter + def tx_clgc_desired_gain_chan1(self, value): + value *= 100 + self._set_iio_attr("voltage1", "clgc_desired_gain", True, value) + + @property + def tx_clgc_orx_rms_chan0(self): + """tx_clgc_orx_rms: RMS orx digital sample power measured in the DPD block on the orx side is returned + with measurement resolution of 0.01 dB for channel 0. Prms dBFs = orxRMS/100""" + if self.tx_clgc_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "clgc_orx_rms", True) / 100 + return + + @property + def tx_clgc_track_count_chan0(self): + """tx_clgc_track_count: The control reads back the number of times the CLGC has successfully run since + CLGC initialization calibration for channel 0""" + if self.tx_clgc_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "clgc_track_count", True) + return + + @property + def tx_clgc_track_count_chan1(self): + """tx_clgc_track_count: The control reads back the number of times the CLGC has successfully run since + CLGC initialization calibration for channel 1""" + if self.tx_clgc_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "clgc_track_count", True) + return + + @property + def tx_clgc_tx_gain_chan0(self): + """tx_clgc_tx_gain: It controls the current channel 0 attenuation for a channel in 0.05 dB resolution. + Tx_Attenuation(dB) = Tx_gain/200""" + if self.tx_clgc_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "clgc_tx_gain", True) * 0.05 + return + + @property + def tx_clgc_tx_gain_chan1(self): + """tx_clgc_tx_gain: It controls the current channel 1 attenuation for a channel in 0.05 dB resolution. Tx_Attenuation(dB) = Tx_gain/200""" + if self.tx_clgc_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "clgc_tx_gain", True) * 0.05 + return + + @property + def tx_clgc_tx_rms_chan0(self): + """tx_clgc_tx_rms: The controls returns the RMS channel 0 digital sample power measured at DPD actuator output + with measurement resolution of 0.01 dB. Prms dBFs = txRMS/100""" + if self.tx_clgc_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "clgc_tx_rms", True) / 100 + return + + @property + def tx_clgc_tx_rms_chan1(self): + """tx_clgc_tx_rms: The controls returns the RMS channel 1 digital sample power measured at DPD actuator output + with measurement resolution of 0.01 dB. Prms dBFs = txRMS/100""" + if self.tx_clgc_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "clgc_tx_rms", True) / 100 + return + + @property + def tx_dpd_actuator_en_chan0(self): + """Enable DPD actuator for channel 0""" + if self._get_iio_attr("voltage0", "dpd_actuator_en", True) == 1: + return True + elif self._get_iio_attr("voltage0", "dpd_actuator_en", True) == 0: + return False + return + + @tx_dpd_actuator_en_chan0.setter + def tx_dpd_actuator_en_chan0(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage0", "dpd_actuator_en", True, value) + + @property + def tx_dpd_actuator_en_chan1(self): + """Enable DPD actuator for channel 1""" + if self._get_iio_attr("voltage1", "dpd_actuator_en", True) == 1: + return True + elif self._get_iio_attr("voltage1", "dpd_actuator_en", True) == 0: + return False + return + + @tx_dpd_actuator_en_chan1.setter + def tx_dpd_actuator_en_chan1(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage1", "dpd_actuator_en", True, value) + + @property + def tx_dpd_tracking_en_chan0(self): + """Enable DPD tracking for channel 0""" + if self._get_iio_attr("voltage0", "dpd_tracking_en", True) == 1: + return True + elif self._get_iio_attr("voltage0", "dpd_tracking_en", True) == 0: + return False + return + + @tx_dpd_tracking_en_chan0.setter + def tx_dpd_tracking_en_chan0(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage0", "dpd_tracking_en", True, value) + + @property + def tx_dpd_tracking_en_chan1(self): + """Enable DPD tracking for channel 1""" + if self._get_iio_attr("voltage1", "dpd_tracking_en", True) == 1: + return True + elif self._get_iio_attr("voltage1", "dpd_tracking_en", True) == 0: + return False + return + + @tx_dpd_tracking_en_chan1.setter + def tx_dpd_tracking_en_chan1(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage1", "dpd_tracking_en", True, value) + + @property + def tx_dpd_external_path_delay_chan0(self): + """tx_dpd_external_path_delay: The control reads back the external path delay + from channel 0 output to orx input at 1/16 sample resolution of the ORx sample rate""" + if self.tx_dpd_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "dpd_external_path_delay", True) / 16 + return + + @property + def tx_dpd_external_path_delay_chan1(self): + """tx_dpd_external_path_delay: The control reads back the external path delay + from channel 1 output to orx input at 1/16 sample resolution of the ORx sample rate""" + if self.tx_dpd_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "dpd_external_path_delay", True) / 16 + return + + @property + def tx_dpd_model_error_chan0(self): + """tx_dpd_model_error: The control reads back the percent error of the PA model ×10 to include 1 decimal place for channel 0""" + if self.tx_dpd_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "dpd_model_error", True) / 10 + return + + @property + def tx_dpd_model_error_chan1(self): + """tx_dpd_model_error: The control reads back the percent error of the PA model ×10 to include 1 decimal place for channel 1""" + if self.tx_dpd_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "dpd_model_error", True) / 10 + return + + def tx_dpd_reset_en_chan0(self, value): + """Enable DPD reset for channel 0""" + if value == True: + value = 1 + self._set_iio_attr("voltage0", "dpd_reset_en", True, value) + + def tx_dpd_reset_en_chan1(self, value): + """Enable DPD reset for channel 1""" + if value == True: + value = 1 + self._set_iio_attr("voltage1", "dpd_reset_en", True, value) + + @property + def tx_dpd_status_chan0(self): + """tx_dpd_status: It reads back the DPD calibration status from the ARM processor for channel 0""" + # DPD status lookup + dpdstat_lookup = { + 0 : "No Error", + 1 : "Error: ORx disabled", + 2 : "Error: Tx disabled", + 3 : "Error: DPD initialization not run", + 4 : "Error: Path delay not setup", + 5 : "Error: ORx signal too low", + 6 : "Error: ORx signal saturated", + 7 : "Error: Tx signal too low", + 8 : "Error: Tx signal saturated", + 9 : "Error: Model error high", + 10 : "Error: AM AM outliers", + 11 : "Error: Invalid Tx profile", + 12 : "Error: ORx QEC Disabled" + } + if self.tx_dpd_tracking_en_chan0 == 1: + dpdstat_val = self._get_iio_attr("voltage0", "dpd_status", True) + if(dpdstat_val in dpdstat_lookup.keys()): + return dpdstat_lookup[dpdstat_val] + return + + @property + def tx_dpd_status_chan1(self): + """tx_dpd_status: It reads back the DPD calibration status from the ARM processor for channel 1""" + # DPD status lookup + dpdstat_lookup = { + 0 : "No Error", + 1 : "Error: ORx disabled", + 2 : "Error: Tx disabled", + 3 : "Error: DPD initialization not run", + 4 : "Error: Path delay not setup", + 5 : "Error: ORx signal too low", + 6 : "Error: ORx signal saturated", + 7 : "Error: Tx signal too low", + 8 : "Error: Tx signal saturated", + 9 : "Error: Model error high", + 10 : "Error: AM AM outliers", + 11 : "Error: Invalid Tx profile", + 12 : "Error: ORx QEC Disabled" + } + if self.tx_dpd_tracking_en_chan1 == 1: + dpdstat_val = self._get_iio_attr("voltage1", "dpd_status", True) + if(dpdstat_val in dpdstat_lookup.keys()): + return dpdstat_lookup[dpdstat_val] + return + + @property + def tx_dpd_track_count_chan0(self): + """tx_dpd_track_count: It reads back the number of times the DPD has successfully run since + DPD initialization calibration for channel 0""" + if self.tx_dpd_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "dpd_track_count", True) + return + + @property + def tx_dpd_track_count_chan1(self): + """tx_dpd_track_count: It reads back the number of times the DPD has successfully run since + DPD initialization calibration for channel 1""" + if self.tx_dpd_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "dpd_track_count", True) + return + + @property + def tx_vswr_tracking_en_chan0(self): + """Enable VSWR tracking for channel 0""" + if self._get_iio_attr("voltage0", "vswr_tracking_en", True) == 1: + return True + elif self._get_iio_attr("voltage0", "vswr_tracking_en", True) == 0: + return False + return + + @tx_vswr_tracking_en_chan0.setter + def tx_vswr_tracking_en_chan0(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage0", "vswr_tracking_en", True, value) + + @property + def tx_vswr_tracking_en_chan1(self): + """Enable VSWR tracking for channel 1""" + if self._get_iio_attr("voltage1", "vswr_tracking_en", True) == 1: + return True + elif self._get_iio_attr("voltage1", "vswr_tracking_en", True) == 0: + return False + return + + @tx_vswr_tracking_en_chan1.setter + def tx_vswr_tracking_en_chan1(self, value): + if value == True or value == False: + if value == True: + value = 1 + elif value == False: + value = 0 + self._set_iio_attr("voltage1", "vswr_tracking_en", True, value) + + @property + def tx_vswr_forward_gain_chan0(self): + """tx_vswr_forward: Forward rms gain measured from channel 0 to orx path. 0.01 dB = 1""" + if self.tx_vswr_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "vswr_forward_gain", True) * 0.01 + return + + @property + def tx_vswr_forward_gain_chan1(self): + """tx_vswr_forward: Forward rms gain measured from channel 1 to orx path. 0.01 dB = 1""" + if self.tx_vswr_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "vswr_forward_gain", True) * 0.01 + return + + @property + def tx_vswr_forward_gain_imag_chan0(self): + """tx_vswr_forward_gain_imag: Imaginary part of the forward path complex gain for channel 0 (1 = 0.01 linear gain)""" + if self.tx_vswr_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "vswr_forward_gain_imag", True) * 0.01 + return + + @property + def tx_vswr_forward_gain_imag_chan1(self): + if self.tx_vswr_tracking_en_chan1 == 1: + """tx_vswr_forward_gain_imag: Imaginary part of the forward path complex gain for channel 1 (1 = 0.01 linear gain)""" + return self._get_iio_attr("voltage1", "vswr_forward_gain_imag", True) * 0.01 + return + + @property + def tx_vswr_forward_gain_real_chan0(self): + """tx_vswr_forward_gain_real: Real part of the forward path complex gain for channel 0 (1 = 0.01 linear gain)""" + if self.tx_vswr_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "vswr_forward_gain_real", True) * 0.01 + return + + @property + def tx_vswr_forward_gain_real_chan1(self): + """tx_vswr_forward_gain_real: Real part of the forward path complex gain for channel 1 (1 = 0.01 linear gain)""" + if self.tx_vswr_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "vswr_forward_gain_real", True) * 0.01 + return + + @property + def tx_vswr_forward_orx_chan0(self): + """tx_vswr_forward_orx: RMS Orx digital sample power measured at DPD block for ORx data in the forward measurement mode + with measurement resolution of 0.01 dB and 21 dB offset for channel 0. Prms dBFS = txRms/100 + 21 dB""" + if self.tx_vswr_tracking_en_chan0 == 1: + return (self._get_iio_attr("voltage0", "vswr_forward_orx", True) / 100) + 21 + return + + @property + def tx_vswr_forward_tx_chan0(self): + """tx_vswr_forward_tx: RMS Tx digital sample power measured at DPD block for ORx data in the forward measurement mode + with measurement resolution of 0.01 dB and 21 dB offset for channel 0. Prms dBFS = txRms/100 + 21 dB""" + if self.tx_vswr_tracking_en_chan0 == 1: + return (self._get_iio_attr("voltage0", "vswr_forward_tx", True) / 100) + 21 + return + + @property + def tx_vswr_forward_tx_chan1(self): + """tx_vswr_forward_tx: RMS Tx digital sample power measured at DPD block for ORx data in the forward measurement mode + with measurement resolution of 0.01 dB and 21 dB offset for channel 1. Prms dBFS = txRms/100 + 21 dB""" + if self.tx_vswr_tracking_en_chan1 == 1: + return (self._get_iio_attr("voltage1", "vswr_forward_tx", True) / 100) + 21 + return + + @property + def tx_vswr_reflected_gain_chan0(self): + """tx_vswr_reflected_gain: Reflected path gain in RMS for channel 0. 1 = 0.01 dB gain""" + if self.tx_vswr_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "vswr_reflected_gain", True) * 0.01 + return + + @property + def tx_vswr_reflected_gain_chan1(self): + """tx_vswr_reflected_gain: Reflected path gain in RMS for channel 1. 1 = 0.01 dB gain""" + if self.tx_vswr_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "vswr_reflected_gain", True) * 0.01 + return + + @property + def tx_vswr_reflected_gain_imag_chan0(self): + """tx_vswr_reflected_gain_imag: Imaginary part of the reflected path complex gain for channel 0. 1 = 0.01 linear gain""" + if self.tx_vswr_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "vswr_reflected_gain_imag", True) * 0.01 + return + + @property + def tx_vswr_reflected_gain_imag_chan1(self): + """tx_vswr_reflected_gain_imag: Imaginary part of the reflected path complex gain for channel 1. 1 = 0.01 linear gain""" + if self.tx_vswr_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "vswr_reflected_gain_imag", True) * 0.01 + return + + @property + def tx_vswr_reflected_gain_real_chan0(self): + """tx_vswr_reflected_gain_real: Real part of the reflected path complex gain for channel 0. 1 = 0.01 linear gain""" + if self.tx_vswr_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "vswr_reflected_gain_real", True) * 0.01 + return + + @property + def tx_vswr_reflected_gain_real_chan1(self): + """tx_vswr_reflected_gain_real: Real part of the reflected path complex gain for channel 1. 1 = 0.01 linear gain""" + if self.tx_vswr_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "vswr_reflected_gain_real", True) * 0.01 + return + + @property + def tx_vswr_reflected_orx_chan0(self): + """tx_vswr_reflected_orx: RMS ORx digital sample power measured at DPD block for the ORx data in the reverse measurement mode + with measurement resolution of 0.01 dB and 21 dB offset for channel 0. Prms dBFS = orxRms/100 + 21 dB""" + if self.tx_vswr_tracking_en_chan0 == 1: + return (self._get_iio_attr("voltage0", "vswr_reflected_orx", True) / 100) + 21 + return + + @property + def tx_vswr_reflected_tx_chan0(self): + """tx_vswr_reflected_tx: RMS Tx digital sample power measured at DPD actuator for the reverse measurement + with measurement resolution of 0.01 dB and 21 dB offset for channel 0. Prms dBFS = txRms/100 + 21 dB""" + if self.tx_vswr_tracking_en_chan0 == 1: + return (self._get_iio_attr("voltage0", "vswr_reflected_tx", True) / 100) + 21 + return + + @property + def tx_vswr_reflected_tx_chan1(self): + """tx_vswr_reflected_tx: RMS Tx digital sample power measured at DPD actuator for the reverse measurement + with measurement resolution of 0.01 dB and 21 dB offset for channel 1. Prms dBFS = txRms/100 + 21 dB""" + if self.tx_vswr_tracking_en_chan1 == 1: + return (self._get_iio_attr("voltage1", "vswr_reflected_tx", True) / 100) + 21 + return + + @property + def tx_vswr_track_count_chan0(self): + """tx_vswr_track_count: The control reads back the number of times the VSWR has successfully run + since VSWR initialization calibration for channel 0""" + if self.tx_vswr_tracking_en_chan0 == 1: + return self._get_iio_attr("voltage0", "vswr_track_count", True) + return + + @property + def tx_vswr_track_count_chan1(self): + """tx_vswr_track_count: The control reads back the number of times the VSWR has successfully run since + VSWR initialization calibration for channel 1""" + if self.tx_vswr_tracking_en_chan1 == 1: + return self._get_iio_attr("voltage1", "vswr_track_count", True) + return diff --git a/doc/source/devices/adi.ad9371.rst b/doc/source/devices/adi.ad937x.rst similarity index 68% rename from doc/source/devices/adi.ad9371.rst rename to doc/source/devices/adi.ad937x.rst index 372789577..2ff836b53 100644 --- a/doc/source/devices/adi.ad9371.rst +++ b/doc/source/devices/adi.ad937x.rst @@ -1,7 +1,7 @@ -ad9371 +ad937x ================= -.. automodule:: adi.ad9371 +.. automodule:: adi.ad937x :members: :undoc-members: :show-inheritance: diff --git a/doc/source/devices/index.rst b/doc/source/devices/index.rst index ddfe0e240..3cd2dc02c 100644 --- a/doc/source/devices/index.rst +++ b/doc/source/devices/index.rst @@ -46,7 +46,7 @@ Supported Devices adi.ad9250 adi.ad9265 adi.ad936x - adi.ad9371 + adi.ad937x adi.ad9434 adi.ad9467 adi.ad9625 diff --git a/examples/ad9375.py b/examples/ad9375.py new file mode 100644 index 000000000..7c3396ad2 --- /dev/null +++ b/examples/ad9375.py @@ -0,0 +1,121 @@ +# Copyright (C) 2019 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD + +import time + +import adi +import matplotlib.pyplot as plt +import numpy as np +from scipy import signal + +# Create radio +sdr = adi.ad9375(uri="ip:192.168.10.231") + +# Configure properties +sdr.rx_enabled_channels = [0, 1] +sdr.tx_enabled_channels = [0, 1] +sdr.rx_lo = 2000000000 +sdr.tx_lo = 2000000000 +sdr.tx_cyclic_buffer = True +sdr.tx_hardwaregain_chan0 = -30 +sdr.tx_hardwaregain_chan1 = -30 +sdr.gain_control_mode = "automatic" + +# Enable int8 filter in FPGA +sdr.tx_enable_int8 = False +print("TX FS Pre int8:", sdr.tx_sample_rate) +sdr.tx_enable_int8 = True +print("TX FS Post int8:", sdr.tx_sample_rate) +fs = int(sdr.tx_sample_rate) + +# Read properties +print("RX LO %s" % (sdr.rx_lo)) + +# Create a sinewave waveform +N = 2 ** 15 +fc = 6000000 +ts = 1 / float(fs) +t = np.arange(0, N * ts, ts) +i = np.cos(2 * np.pi * t * fc) * 2 ** 14 +q = np.sin(2 * np.pi * t * fc) * 2 ** 14 +iq = i + 1j * q + +fc = -3000000 +i = np.cos(2 * np.pi * t * fc) * 2 ** 14 +q = np.sin(2 * np.pi * t * fc) * 2 ** 14 +iq2 = i + 1j * q + +# Send data +sdr.tx([iq, iq2]) + +# Collect data +fsr = int(sdr.rx_sample_rate) +for r in range(20): + x = sdr.rx() + f, Pxx_den = signal.periodogram(x[0], fsr) + f2, Pxx_den2 = signal.periodogram(x[1], fsr) + plt.clf() + plt.semilogy(f, Pxx_den) + plt.semilogy(f2, Pxx_den2) + plt.ylim([1e-7, 1e4]) + plt.xlabel("frequency [Hz]") + plt.ylabel("PSD [V**2/Hz]") + plt.draw() + plt.pause(0.05) + time.sleep(0.1) + +# plt.show() + +# ad9375 ONLY +# Enable CLGC tracking +sdr.tx_clgc_tracking_en_chan0 = True +sdr.tx_clgc_tracking_en_chan1 = True + +# Configure and read CLGC desired gain property +sdr.tx_clgc_desired_gain_chan0 = -3 +time.sleep(0.3) +print("CLGC desired gain channel 1:", sdr.tx_clgc_desired_gain_chan0) +sdr.tx_clgc_desired_gain_chan1 = -3 +time.sleep(0.3) +print("CLGC desired gain channel 2:", sdr.tx_clgc_desired_gain_chan1) + +# Read CLGC properties +print("CLGC tx rms channel 1", sdr.tx_clgc_tx_rms_chan0) +print("CLGC tx rms channel 2", sdr.tx_clgc_tx_rms_chan1) + +# Disable CLGC tracking +sdr.tx_clgc_tracking_en_chan0 = False +sdr.tx_clgc_tracking_en_chan1 = False + +# Enable DPD tracking +sdr.tx_dpd_tracking_en_chan0 = True +sdr.tx_dpd_tracking_en_chan1 = True + +# Enable DPD actuator +sdr.tx_dpd_actuator_en_chan0 = True +sdr.tx_dpd_actuator_en_chan1 = True + +# Read DPD properties +print("DPD status channel 1:", sdr.tx_dpd_status_chan0) +print("DPD status channel 2:", sdr.tx_dpd_status_chan1) + +# Enable DPD reset +sdr.tx_dpd_reset_en_chan0 = True +sdr.tx_dpd_reset_en_chan1 = True + +# Disable DPD tracking +sdr.tx_dpd_tracking_en_chan0 = False +sdr.tx_dpd_tracking_en_chan1 = False + +# Enable VSWR tracking +sdr.tx_vswr_tracking_en_chan0 = True +sdr.tx_vswr_tracking_en_chan1 = True + +# Read VSWR properties +print("VSWR forward gain channel 1:", sdr.tx_vswr_forward_gain_chan0) +print("VSWR forward gain channel 2:", sdr.tx_vswr_forward_gain_chan1) + +# Disable VSWR tracking +sdr.tx_vswr_tracking_en_chan0 = False +sdr.tx_vswr_tracking_en_chan1 = False \ No newline at end of file diff --git a/test/attr_tests.py b/test/attr_tests.py index b7f6dc08d..64a38b5ae 100644 --- a/test/attr_tests.py +++ b/test/attr_tests.py @@ -258,6 +258,33 @@ def attribute_multiple_values_with_depends( assert dev_interface(uri, classname, val, attr, tol) +def attribute_readonly_with_depends(uri, classname, attr, depends): + """attribute_readonly_with_depends: Read only class + property with dependent write properties + + parameters: + uri: type=string + URI of IIO context of target board/system + classname: type=string + Name of pyadi interface class which contain attribute + attr: type=string + Attribute name to be written. Must be property of classname + depends: type=dict + Dictionary of properties to write before value is written. Keys + are properties and values are values to be written + """ + sdr = eval(classname + "(uri='" + uri + "')") + for p in depends: + setattr(sdr, p, depends[p]) + try: + rval = getattr(sdr, attr) + assert type(rval) != None + del sdr + except Exception as e: + del sdr + raise Exception(e) + + def attribute_write_only_str(uri, classname, attr, value): """attribute_write_only_str: Write only string class property @@ -318,3 +345,35 @@ def attribute_write_only_str_with_depends(uri, classname, attr, value, depends): except Exception as e: del sdr raise Exception(e) + + +def attribute_check_range_readonly_with_depends(uri, classname, attr, depends, start, stop): + """attribute_check_range_readonly_with_depends: Read only integer class + property with dependent write properties + + parameters: + uri: type=string + URI of IIO context of target board/system + classname: type=string + Name of pyadi interface class which contain attribute + attr: type=string + Attribute name to be written. Must be property of classname + depends: type=dict + Dictionary of properties to write before value is written. Keys + are properties and values are values to be written + start: type=integer + Lower bound of possible values attribute can be + stop: type=integer + Upper bound of possible values attribute can be + """ + sdr = eval(classname + "(uri='" + uri + "')") + for p in depends: + setattr(sdr, p, depends[p]) + try: + rval = getattr(sdr, attr) + end = stop + 1 + assert rval in range(start, end) + del sdr + except Exception as e: + del sdr + raise Exception(e) \ No newline at end of file diff --git a/test/common.py b/test/common.py index 1c41c24e0..9678af06a 100644 --- a/test/common.py +++ b/test/common.py @@ -97,7 +97,7 @@ def pytest_generate_tests(metafunc): ################################################# -def dev_interface(uri, classname, val, attr, tol, sub_channel=None, sleep=0): +def dev_interface(uri, classname, val, attr, tol, sub_channel=None, sleep=0, readonly=False): sdr = eval(classname + "(uri='" + uri + "')") # Check hardware if not hasattr(sdr, attr): @@ -114,10 +114,16 @@ def dev_interface(uri, classname, val, attr, tol, sub_channel=None, sleep=0): time.sleep(sleep) rval = getattr(sdr, attr) - del sdr - if not isinstance(rval, str) and not is_list: rval = float(rval) + for _ in range(5): + setattr(sdr, attr, val) + time.sleep(0.3) + rval = float(getattr(sdr, attr)) + if rval == val: + break + + del sdr if is_list and isinstance(rval[0], str): return val == rval diff --git a/test/conftest.py b/test/conftest.py index fc6ead0b4..6e56b2e2d 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -164,6 +164,11 @@ def test_attribute_multiple_values_with_depends(request): yield attribute_multiple_values_with_depends +@pytest.fixture() +def test_attribute_readonly_with_depends(request): + yield attribute_readonly_with_depends + + @pytest.fixture() def test_attribute_write_only_str_with_depends(request): yield attribute_write_only_str_with_depends @@ -174,6 +179,11 @@ def test_attribute_write_only_str(request): yield attribute_write_only_str +@pytest.fixture +def test_attribute_check_range_readonly_with_depends(request): + yield attribute_check_range_readonly_with_depends + + @pytest.fixture() def test_dma_dac_zeros(request): yield dma_dac_zeros diff --git a/test/emu/hardware_map.yml b/test/emu/hardware_map.yml index a49b5d79c..3e9efa2ec 100644 --- a/test/emu/hardware_map.yml +++ b/test/emu/hardware_map.yml @@ -277,6 +277,14 @@ adrv9371: - data_devices: - iio:device4 - iio:device6 +adrv9375: + - ad9371-phy + - emulate: + - filename: ad9375.xml + - data_devices: + - iio:device4 + - iio:device5 + - iio:device6 adxl355: - adxl355 - emulate: diff --git a/test/test_ad9375.py b/test/test_ad9375.py new file mode 100644 index 000000000..5dccb8076 --- /dev/null +++ b/test/test_ad9375.py @@ -0,0 +1,494 @@ +from os import listdir +from os.path import dirname, join, realpath + +import pytest + +hardware = "ad9375" +classname = "adi.ad9375" + +profile_path = dirname(realpath(__file__)) + "/ad9371_5_profiles/" +test_profiles = [join(profile_path, f) for f in listdir(profile_path)] + + +clgc_tracking_en_0 = { + "tx_clgc_tracking_en_chan0" : True, +} + +dpd_tracking_en_0 = { + "tx_dpd_tracking_en_chan0" : True, +} + +vswr_tracking_en_0 = { + "tx_vswr_tracking_en_chan0" : True, +} + +clgc_tracking_en_1 = { + "tx_clgc_tracking_en_chan1" : True, +} + +dpd_tracking_en_1 = { + "tx_dpd_tracking_en_chan1" : True, +} + +vswr_tracking_en_1 = { + "tx_vswr_tracking_en_chan1" : True, +} + + +desired_gain_values = [-5, -4] + + +params = dict( + one_cw_tone_manual=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="manual", + rx_hardwaregain_chan0=10, + rx_hardwaregain_chan1=10, + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=0, + tx_hardwaregain_chan1=0, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + one_cw_tone_auto=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="automatic", + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=-10, + tx_hardwaregain_chan1=-10, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_attenuation_5dB_manual=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="manual", + rx_hardwaregain_chan0=10, + rx_hardwaregain_chan1=10, + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=-5, + tx_hardwaregain_chan1=-5, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_attenuation_10dB_manual=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="manual", + rx_hardwaregain_chan0=10, + rx_hardwaregain_chan1=10, + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=-10, + tx_hardwaregain_chan1=-10, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_attenuation_0dB_auto=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="automatic", + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=0, + tx_hardwaregain_chan1=0, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_attenuation_20dB_auto=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="automatic", + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=-20, + tx_hardwaregain_chan1=-20, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_rf_gain_0dB_manual=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="manual", + rx_hardwaregain_chan0=0, + rx_hardwaregain_chan1=0, + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=0, + tx_hardwaregain_chan1=0, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_rf_gain_20dB_manual=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="manual", + rx_hardwaregain_chan0=20, + rx_hardwaregain_chan1=20, + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=0, + rx_temp_comp_gain_chan1=0, + tx_hardwaregain_chan0=0, + tx_hardwaregain_chan1=0, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_temp_gain_up=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="manual", + rx_hardwaregain_chan0=10, + rx_hardwaregain_chan1=10, + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=3, + rx_temp_comp_gain_chan1=3, + tx_hardwaregain_chan0=0, + tx_hardwaregain_chan1=0, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), + change_temp_gain_down=dict( + ensm_mode="radio_on", + tx_lo=2500000000, + rx_lo=2500000000, + gain_control_mode="manual", + rx_hardwaregain_chan0=10, + rx_hardwaregain_chan1=10, + rx_quadrature_tracking_en_chan0=1, + rx_quadrature_tracking_en_chan1=1, + rx_temp_comp_gain_chan0=-3, + rx_temp_comp_gain_chan1=-3, + tx_hardwaregain_chan0=0, + tx_hardwaregain_chan1=0, + tx_quadrature_tracking_en_chan0=1, + tx_quadrature_tracking_en_chan1=1, + ), +) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize( + "attr, start, stop, step, tol", + [ + ("tx_hardwaregain_chan0", -41.95, 0.0, 0.05, 0.05), + ("tx_hardwaregain_chan1", -41.95, 0.0, 0.05, 0.05), + ("tx_lo", 70000000, 6000000000, 1000, 0), + ("rx_lo", 70000000, 6000000000, 1000, 0), + ], +) +def test_ad9375_attr( + test_attribute_single_value, iio_uri, classname, attr, start, stop, step, tol +): + test_attribute_single_value(iio_uri, classname, attr, start, stop, step, tol) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("channel", range(2)) +def test_ad9375_rx_data(test_dma_rx, iio_uri, classname, channel): + test_dma_rx(iio_uri, classname, channel) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("channel", [0, 1]) +@pytest.mark.parametrize( + "param_set, frequency, scale, peak_min", + [ + (params["one_cw_tone_manual"], 2000000, 0.5, -13), + (params["one_cw_tone_manual"], 2000000, 0.12, -25), + (params["one_cw_tone_manual"], 2000000, 0.25, -19), + (params["one_cw_tone_auto"], 1000000, 0.12, -14.7), + (params["one_cw_tone_auto"], 2000000, 0.12, -14.7), + (params["one_cw_tone_auto"], 500000, 0.12, -14.7), + (params["change_attenuation_5dB_manual"], 2000000, 0.25, -23.8), + (params["change_attenuation_10dB_manual"], 2000000, 0.25, -28.75), + (params["change_attenuation_0dB_auto"], 1000000, 0.12, -9), + (params["change_attenuation_20dB_auto"], 1000000, 0.12, -24.7), + (params["change_rf_gain_0dB_manual"], 2000000, 0.25, -29), + (params["change_rf_gain_20dB_manual"], 2000000, 0.25, -9), + (params["change_temp_gain_up"], 2000000, 0.25, -16), + (params["change_temp_gain_down"], 2000000, 0.25, -22), + ], +) +def test_ad9375_dds_loopback( + test_dds_loopback, + iio_uri, + classname, + param_set, + channel, + frequency, + scale, + peak_min, +): + test_dds_loopback( + iio_uri, classname, param_set, channel, frequency, scale, peak_min + ) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("channel", [0, 1]) +@pytest.mark.parametrize( + "param_set, frequency1, scale1, peak_min1, frequency2, scale2, peak_min2", + [(params["one_cw_tone_auto"], 1000000, 0.06, -21, 2000000, 0.12, -15)], +) +def test_ad9375_two_tone_loopback( + test_dds_two_tone, + iio_uri, + classname, + channel, + param_set, + frequency1, + scale1, + peak_min1, + frequency2, + scale2, + peak_min2, +): + test_dds_two_tone( + iio_uri, + classname, + channel, + param_set, + frequency1, + scale1, + peak_min1, + frequency2, + scale2, + peak_min2, + ) + + +######################################## +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("channel", [0, 1]) +@pytest.mark.parametrize( + "param_set, dds_scale, min_rssi, max_rssi", + [ + (params["one_cw_tone_manual"], 0.5, 8.5, 10.5), + (params["one_cw_tone_manual"], 0.12, 20.5, 23), + (params["one_cw_tone_manual"], 0.25, 14.5, 16.5), + (params["one_cw_tone_auto"], 0.12, 10.5, 13), + (params["change_attenuation_5dB_manual"], 0.25, 19.5, 21.25), + (params["change_attenuation_10dB_manual"], 0.25, 24.25, 26.25), + (params["change_attenuation_0dB_auto"], 0.12, 2.25, 5.25), + (params["change_attenuation_20dB_auto"], 0.12, 20.75, 22.75), + (params["change_rf_gain_0dB_manual"], 0.25, 24.75, 26.75), + (params["change_rf_gain_20dB_manual"], 0.25, 5, 6.5), + (params["change_temp_gain_up"], 0.25, 14.5, 16.75), + (params["change_temp_gain_down"], 0.25, 14.5, 16.75), + ], +) +def test_ad9375_dds_gain_check_vary_power( + test_gain_check, + iio_uri, + classname, + channel, + param_set, + dds_scale, + min_rssi, + max_rssi, +): + test_gain_check( + iio_uri, classname, channel, param_set, dds_scale, min_rssi, max_rssi + ) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("channel", [0, 1]) +@pytest.mark.parametrize( + "param_set", + [ + params["one_cw_tone_manual"], + params["one_cw_tone_auto"], + params["change_attenuation_5dB_manual"], + params["change_attenuation_10dB_manual"], + params["change_attenuation_0dB_auto"], + params["change_attenuation_20dB_auto"], + params["change_rf_gain_0dB_manual"], + params["change_rf_gain_20dB_manual"], + params["change_temp_gain_up"], + params["change_temp_gain_down"], + ], +) +@pytest.mark.parametrize("sfdr_min", [45]) +def test_ad9375_sfdr(test_sfdr, iio_uri, classname, channel, param_set, sfdr_min): + test_sfdr(iio_uri, classname, channel, param_set, sfdr_min) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("attr", ["profile"]) +@pytest.mark.parametrize( + "files", test_profiles, +) +def test_ad9375_profile_write( + test_attribute_write_only_str, iio_uri, classname, attr, files +): + test_attribute_write_only_str(iio_uri, classname, attr, files) + + +# AD9375 ONLY +######################################## +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize( + "attr, depends, values, tol, repeats", + [ + ("tx_clgc_desired_gain_chan0", clgc_tracking_en_0, desired_gain_values, 0.5, 1), + ("tx_clgc_desired_gain_chan1", clgc_tracking_en_1, desired_gain_values, 0.5, 5), + ], +) +def test_ad9375_attr_with_depends( + test_attribute_multipe_values_with_depends, iio_uri, classname, attr, depends, values, tol, repeats +): + test_attribute_multipe_values_with_depends(iio_uri, classname, attr, depends, values, tol, repeats) + + +######################################## +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize( + "attr, depends", + [ + ("tx_clgc_current_gain_chan0", clgc_tracking_en_0), + ("tx_clgc_current_gain_chan1", clgc_tracking_en_1), + ("tx_clgc_orx_rms_chan0", clgc_tracking_en_0), + ("tx_clgc_track_count_chan0", clgc_tracking_en_0), + ("tx_clgc_track_count_chan1", clgc_tracking_en_1), + ("tx_clgc_tx_gain_chan0", clgc_tracking_en_0), + ("tx_clgc_tx_gain_chan1", clgc_tracking_en_1), + ("tx_clgc_tx_rms_chan0", clgc_tracking_en_0), + ("tx_clgc_tx_rms_chan1", clgc_tracking_en_1), + ("tx_dpd_track_count_chan0", dpd_tracking_en_0), + ("tx_dpd_track_count_chan1", dpd_tracking_en_1), + ("tx_dpd_status_chan0", dpd_tracking_en_0), + ("tx_dpd_status_chan1", dpd_tracking_en_1), + ("tx_vswr_forward_gain_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_gain_chan1", vswr_tracking_en_1), + ("tx_vswr_forward_gain_imag_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_gain_imag_chan1", vswr_tracking_en_1), + ("tx_vswr_forward_gain_real_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_gain_real_chan1", vswr_tracking_en_1), + ("tx_vswr_forward_orx_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_tx_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_tx_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_gain_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_gain_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_gain_imag_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_gain_imag_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_gain_real_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_gain_real_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_orx_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_tx_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_tx_chan1", vswr_tracking_en_1), + ("tx_vswr_track_count_chan0", vswr_tracking_en_0), + ("tx_vswr_track_count_chan1", vswr_tracking_en_1), + ], +) +def test_ad9375_attr_readonly_with_depends( + test_attribute_readonly_with_depends, iio_uri, classname, attr, depends +): + test_attribute_readonly_with_depends(iio_uri, classname, attr, depends) + + +######################################## +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize( + "attr, depends, start, stop", + [ + ("tx_dpd_model_error_chan0", dpd_tracking_en_0, 0, 100), + ("tx_dpd_model_error_chan1", dpd_tracking_en_1, 0, 100), + ], +) +def test_ad9375_attr_range_readonly( + test_attribute_check_range_readonly_with_depends, iio_uri, classname, attr, depends, start, stop +): + test_attribute_check_range_readonly_with_depends(iio_uri, classname, attr, depends, start, stop) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize( + "attr, value", + [ + ("tx_clgc_tracking_en_chan0", True), + ("tx_clgc_tracking_en_chan0", False), + ("tx_clgc_tracking_en_chan1", True), + ("tx_clgc_tracking_en_chan1", False), + ("tx_dpd_actuator_en_chan0", True), + ("tx_dpd_actuator_en_chan0", False), + ("tx_dpd_actuator_en_chan1", True), + ("tx_dpd_actuator_en_chan1", False), + ("tx_vswr_tracking_en_chan0", True), + ("tx_vswr_tracking_en_chan0", False), + ("tx_vswr_tracking_en_chan1", True), + ("tx_vswr_tracking_en_chan1", False), + ("tx_dpd_tracking_en_chan0", True), + ("tx_dpd_tracking_en_chan0", False), + ("tx_dpd_tracking_en_chan1", True), + ("tx_dpd_tracking_en_chan1", False), + ], +) +def test_ad9375_attr_boolean( + test_attribute_single_value_boolean, iio_uri, classname, attr, value +): + test_attribute_single_value_boolean(iio_uri, classname, attr, value) + + +######################################## +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize( + "attr, value", + [ + ("tx_dpd_reset_en_chan0", 1), + ("tx_dpd_reset_en_chan1", 1), + ], +) +def test_ad9375_attr_write_only( + test_attribute_write_only_str, iio_uri, classname, attr, value +): + test_attribute_write_only_str(iio_uri, classname, attr, value) From fc45cc1d38105c1577e1348e57e6dbfbc8e8b6e3 Mon Sep 17 00:00:00 2001 From: Trisha De Vera Date: Thu, 5 Oct 2023 12:05:21 +0800 Subject: [PATCH 2/7] Add ad9375.xml --- test/emu/devices/ad9375.xml | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/emu/devices/ad9375.xml diff --git a/test/emu/devices/ad9375.xml b/test/emu/devices/ad9375.xml new file mode 100644 index 000000000..0fcf00083 --- /dev/null +++ b/test/emu/devices/ad9375.xml @@ -0,0 +1 @@ +]> \ No newline at end of file From 1be638141da35e15e57812b6cbca2033fe96138e Mon Sep 17 00:00:00 2001 From: Trisha De Vera Date: Thu, 5 Oct 2023 14:04:48 +0800 Subject: [PATCH 3/7] Fix lint Signed-off-by: Trisha De Vera --- adi/ad937x.py | 242 +++++++++++++++++--------------------------- examples/ad9375.py | 34 +++---- test/attr_tests.py | 6 +- test/common.py | 6 +- test/test_ad9375.py | 145 ++++++++++++++------------ 5 files changed, 195 insertions(+), 238 deletions(-) diff --git a/adi/ad937x.py b/adi/ad937x.py index d811a321d..651ee5c56 100644 --- a/adi/ad937x.py +++ b/adi/ad937x.py @@ -331,50 +331,32 @@ class ad9375(ad9371): @property def tx_clgc_tracking_en_chan0(self): """Enable CLGC tracking for channel 0""" - if self._get_iio_attr("voltage0", "clgc_tracking_en", True) == 1: - return True - elif self._get_iio_attr("voltage0", "clgc_tracking_en", True) == 0: - return False - return + return self._get_iio_attr("voltage0", "clgc_tracking_en", True) @tx_clgc_tracking_en_chan0.setter def tx_clgc_tracking_en_chan0(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage0", "clgc_tracking_en", True, value) + self._set_iio_attr("voltage0", "clgc_tracking_en", True, value) @property def tx_clgc_tracking_en_chan1(self): """Enable CLGC tracking for channel 1""" - if self._get_iio_attr("voltage1", "clgc_tracking_en", True) == 1: - return True - elif self._get_iio_attr("voltage1", "clgc_tracking_en", True) == 0: - return False - return + return self._get_iio_attr("voltage1", "clgc_tracking_en", True) @tx_clgc_tracking_en_chan1.setter def tx_clgc_tracking_en_chan1(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage1", "clgc_tracking_en", True, value) + self._set_iio_attr("voltage1", "clgc_tracking_en", True, value) @property def tx_clgc_current_gain_chan0(self): if self.tx_clgc_tracking_en_chan0 == 1: - """tx_clgc_current_gain: Current measured gain in 1/100ths dB scale in channel 0. + """tx_clgc_current_gain: Current measured gain in 1/100ths dB scale in channel 0. Current GaindB = currentGain/100""" return self._get_iio_attr("voltage0", "clgc_current_gain", True) return @property def tx_clgc_current_gain_chan1(self): - """tx_clgc_current_gain: Current measured gain in 1/100ths dB scale in channel 1. + """tx_clgc_current_gain: Current measured gain in 1/100ths dB scale in channel 1. Current GaindB = currentGain/100""" if self.tx_clgc_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "clgc_current_gain", True) @@ -382,7 +364,7 @@ def tx_clgc_current_gain_chan1(self): @property def tx_clgc_desired_gain_chan0(self): - """tx_clgc_desired_gain: Desired gain from channel 0 output to orx input. + """tx_clgc_desired_gain: Desired gain from channel 0 output to orx input. Desired_gain (dB) = Desired_gain/100""" if self.tx_clgc_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "clgc_desired_gain", True) / 100 @@ -395,7 +377,7 @@ def tx_clgc_desired_gain_chan0(self, value): @property def tx_clgc_desired_gain_chan1(self): - """tx_clgc_desired_gain: Desired gain from channel 1 output to orx input. + """tx_clgc_desired_gain: Desired gain from channel 1 output to orx input. Desired_gain (dB) = Desired_gain/100""" if self.tx_clgc_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "clgc_desired_gain", True) / 100 @@ -408,7 +390,7 @@ def tx_clgc_desired_gain_chan1(self, value): @property def tx_clgc_orx_rms_chan0(self): - """tx_clgc_orx_rms: RMS orx digital sample power measured in the DPD block on the orx side is returned + """tx_clgc_orx_rms: RMS orx digital sample power measured in the DPD block on the orx side is returned with measurement resolution of 0.01 dB for channel 0. Prms dBFs = orxRMS/100""" if self.tx_clgc_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "clgc_orx_rms", True) / 100 @@ -416,7 +398,7 @@ def tx_clgc_orx_rms_chan0(self): @property def tx_clgc_track_count_chan0(self): - """tx_clgc_track_count: The control reads back the number of times the CLGC has successfully run since + """tx_clgc_track_count: The control reads back the number of times the CLGC has successfully run since CLGC initialization calibration for channel 0""" if self.tx_clgc_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "clgc_track_count", True) @@ -424,7 +406,7 @@ def tx_clgc_track_count_chan0(self): @property def tx_clgc_track_count_chan1(self): - """tx_clgc_track_count: The control reads back the number of times the CLGC has successfully run since + """tx_clgc_track_count: The control reads back the number of times the CLGC has successfully run since CLGC initialization calibration for channel 1""" if self.tx_clgc_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "clgc_track_count", True) @@ -432,7 +414,7 @@ def tx_clgc_track_count_chan1(self): @property def tx_clgc_tx_gain_chan0(self): - """tx_clgc_tx_gain: It controls the current channel 0 attenuation for a channel in 0.05 dB resolution. + """tx_clgc_tx_gain: It controls the current channel 0 attenuation for a channel in 0.05 dB resolution. Tx_Attenuation(dB) = Tx_gain/200""" if self.tx_clgc_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "clgc_tx_gain", True) * 0.05 @@ -447,7 +429,7 @@ def tx_clgc_tx_gain_chan1(self): @property def tx_clgc_tx_rms_chan0(self): - """tx_clgc_tx_rms: The controls returns the RMS channel 0 digital sample power measured at DPD actuator output + """tx_clgc_tx_rms: The controls returns the RMS channel 0 digital sample power measured at DPD actuator output with measurement resolution of 0.01 dB. Prms dBFs = txRMS/100""" if self.tx_clgc_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "clgc_tx_rms", True) / 100 @@ -455,7 +437,7 @@ def tx_clgc_tx_rms_chan0(self): @property def tx_clgc_tx_rms_chan1(self): - """tx_clgc_tx_rms: The controls returns the RMS channel 1 digital sample power measured at DPD actuator output + """tx_clgc_tx_rms: The controls returns the RMS channel 1 digital sample power measured at DPD actuator output with measurement resolution of 0.01 dB. Prms dBFs = txRMS/100""" if self.tx_clgc_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "clgc_tx_rms", True) / 100 @@ -464,78 +446,42 @@ def tx_clgc_tx_rms_chan1(self): @property def tx_dpd_actuator_en_chan0(self): """Enable DPD actuator for channel 0""" - if self._get_iio_attr("voltage0", "dpd_actuator_en", True) == 1: - return True - elif self._get_iio_attr("voltage0", "dpd_actuator_en", True) == 0: - return False - return + return self._get_iio_attr("voltage0", "dpd_actuator_en", True) @tx_dpd_actuator_en_chan0.setter def tx_dpd_actuator_en_chan0(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage0", "dpd_actuator_en", True, value) + self._set_iio_attr("voltage0", "dpd_actuator_en", True, value) @property def tx_dpd_actuator_en_chan1(self): """Enable DPD actuator for channel 1""" - if self._get_iio_attr("voltage1", "dpd_actuator_en", True) == 1: - return True - elif self._get_iio_attr("voltage1", "dpd_actuator_en", True) == 0: - return False - return + return self._get_iio_attr("voltage1", "dpd_actuator_en", True) @tx_dpd_actuator_en_chan1.setter def tx_dpd_actuator_en_chan1(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage1", "dpd_actuator_en", True, value) + self._set_iio_attr("voltage1", "dpd_actuator_en", True, value) @property def tx_dpd_tracking_en_chan0(self): """Enable DPD tracking for channel 0""" - if self._get_iio_attr("voltage0", "dpd_tracking_en", True) == 1: - return True - elif self._get_iio_attr("voltage0", "dpd_tracking_en", True) == 0: - return False - return + return self._get_iio_attr("voltage0", "dpd_tracking_en", True) @tx_dpd_tracking_en_chan0.setter def tx_dpd_tracking_en_chan0(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage0", "dpd_tracking_en", True, value) + self._set_iio_attr("voltage0", "dpd_tracking_en", True, value) @property def tx_dpd_tracking_en_chan1(self): """Enable DPD tracking for channel 1""" - if self._get_iio_attr("voltage1", "dpd_tracking_en", True) == 1: - return True - elif self._get_iio_attr("voltage1", "dpd_tracking_en", True) == 0: - return False - return + return self._get_iio_attr("voltage1", "dpd_tracking_en", True) @tx_dpd_tracking_en_chan1.setter def tx_dpd_tracking_en_chan1(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage1", "dpd_tracking_en", True, value) + self._set_iio_attr("voltage1", "dpd_tracking_en", True, value) @property def tx_dpd_external_path_delay_chan0(self): - """tx_dpd_external_path_delay: The control reads back the external path delay + """tx_dpd_external_path_delay: The control reads back the external path delay from channel 0 output to orx input at 1/16 sample resolution of the ORx sample rate""" if self.tx_dpd_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "dpd_external_path_delay", True) / 16 @@ -543,7 +489,7 @@ def tx_dpd_external_path_delay_chan0(self): @property def tx_dpd_external_path_delay_chan1(self): - """tx_dpd_external_path_delay: The control reads back the external path delay + """tx_dpd_external_path_delay: The control reads back the external path delay from channel 1 output to orx input at 1/16 sample resolution of the ORx sample rate""" if self.tx_dpd_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "dpd_external_path_delay", True) / 16 @@ -562,17 +508,15 @@ def tx_dpd_model_error_chan1(self): if self.tx_dpd_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "dpd_model_error", True) / 10 return - + def tx_dpd_reset_en_chan0(self, value): """Enable DPD reset for channel 0""" - if value == True: - value = 1 - self._set_iio_attr("voltage0", "dpd_reset_en", True, value) + if value == 1: + self._set_iio_attr("voltage0", "dpd_reset_en", True, value) def tx_dpd_reset_en_chan1(self, value): """Enable DPD reset for channel 1""" - if value == True: - value = 1 + if value == 1: self._set_iio_attr("voltage1", "dpd_reset_en", True, value) @property @@ -580,24 +524,24 @@ def tx_dpd_status_chan0(self): """tx_dpd_status: It reads back the DPD calibration status from the ARM processor for channel 0""" # DPD status lookup dpdstat_lookup = { - 0 : "No Error", - 1 : "Error: ORx disabled", - 2 : "Error: Tx disabled", - 3 : "Error: DPD initialization not run", - 4 : "Error: Path delay not setup", - 5 : "Error: ORx signal too low", - 6 : "Error: ORx signal saturated", - 7 : "Error: Tx signal too low", - 8 : "Error: Tx signal saturated", - 9 : "Error: Model error high", - 10 : "Error: AM AM outliers", - 11 : "Error: Invalid Tx profile", - 12 : "Error: ORx QEC Disabled" - } + 0: "No Error", + 1: "Error: ORx disabled", + 2: "Error: Tx disabled", + 3: "Error: DPD initialization not run", + 4: "Error: Path delay not setup", + 5: "Error: ORx signal too low", + 6: "Error: ORx signal saturated", + 7: "Error: Tx signal too low", + 8: "Error: Tx signal saturated", + 9: "Error: Model error high", + 10: "Error: AM AM outliers", + 11: "Error: Invalid Tx profile", + 12: "Error: ORx QEC Disabled", + } if self.tx_dpd_tracking_en_chan0 == 1: - dpdstat_val = self._get_iio_attr("voltage0", "dpd_status", True) - if(dpdstat_val in dpdstat_lookup.keys()): - return dpdstat_lookup[dpdstat_val] + dpdstat_val = self._get_iio_attr("voltage0", "dpd_status", True) + if dpdstat_val in dpdstat_lookup.keys(): + return dpdstat_lookup[dpdstat_val] return @property @@ -605,29 +549,29 @@ def tx_dpd_status_chan1(self): """tx_dpd_status: It reads back the DPD calibration status from the ARM processor for channel 1""" # DPD status lookup dpdstat_lookup = { - 0 : "No Error", - 1 : "Error: ORx disabled", - 2 : "Error: Tx disabled", - 3 : "Error: DPD initialization not run", - 4 : "Error: Path delay not setup", - 5 : "Error: ORx signal too low", - 6 : "Error: ORx signal saturated", - 7 : "Error: Tx signal too low", - 8 : "Error: Tx signal saturated", - 9 : "Error: Model error high", - 10 : "Error: AM AM outliers", - 11 : "Error: Invalid Tx profile", - 12 : "Error: ORx QEC Disabled" - } + 0: "No Error", + 1: "Error: ORx disabled", + 2: "Error: Tx disabled", + 3: "Error: DPD initialization not run", + 4: "Error: Path delay not setup", + 5: "Error: ORx signal too low", + 6: "Error: ORx signal saturated", + 7: "Error: Tx signal too low", + 8: "Error: Tx signal saturated", + 9: "Error: Model error high", + 10: "Error: AM AM outliers", + 11: "Error: Invalid Tx profile", + 12: "Error: ORx QEC Disabled", + } if self.tx_dpd_tracking_en_chan1 == 1: - dpdstat_val = self._get_iio_attr("voltage1", "dpd_status", True) - if(dpdstat_val in dpdstat_lookup.keys()): + dpdstat_val = self._get_iio_attr("voltage1", "dpd_status", True) + if dpdstat_val in dpdstat_lookup.keys(): return dpdstat_lookup[dpdstat_val] return @property def tx_dpd_track_count_chan0(self): - """tx_dpd_track_count: It reads back the number of times the DPD has successfully run since + """tx_dpd_track_count: It reads back the number of times the DPD has successfully run since DPD initialization calibration for channel 0""" if self.tx_dpd_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "dpd_track_count", True) @@ -635,7 +579,7 @@ def tx_dpd_track_count_chan0(self): @property def tx_dpd_track_count_chan1(self): - """tx_dpd_track_count: It reads back the number of times the DPD has successfully run since + """tx_dpd_track_count: It reads back the number of times the DPD has successfully run since DPD initialization calibration for channel 1""" if self.tx_dpd_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "dpd_track_count", True) @@ -644,38 +588,20 @@ def tx_dpd_track_count_chan1(self): @property def tx_vswr_tracking_en_chan0(self): """Enable VSWR tracking for channel 0""" - if self._get_iio_attr("voltage0", "vswr_tracking_en", True) == 1: - return True - elif self._get_iio_attr("voltage0", "vswr_tracking_en", True) == 0: - return False - return + return self._get_iio_attr("voltage0", "vswr_tracking_en", True) @tx_vswr_tracking_en_chan0.setter def tx_vswr_tracking_en_chan0(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage0", "vswr_tracking_en", True, value) + self._set_iio_attr("voltage0", "vswr_tracking_en", True, value) @property def tx_vswr_tracking_en_chan1(self): """Enable VSWR tracking for channel 1""" - if self._get_iio_attr("voltage1", "vswr_tracking_en", True) == 1: - return True - elif self._get_iio_attr("voltage1", "vswr_tracking_en", True) == 0: - return False - return + return self._get_iio_attr("voltage1", "vswr_tracking_en", True) @tx_vswr_tracking_en_chan1.setter def tx_vswr_tracking_en_chan1(self, value): - if value == True or value == False: - if value == True: - value = 1 - elif value == False: - value = 0 - self._set_iio_attr("voltage1", "vswr_tracking_en", True, value) + self._set_iio_attr("voltage1", "vswr_tracking_en", True, value) @property def tx_vswr_forward_gain_chan0(self): @@ -721,7 +647,7 @@ def tx_vswr_forward_gain_real_chan1(self): @property def tx_vswr_forward_orx_chan0(self): - """tx_vswr_forward_orx: RMS Orx digital sample power measured at DPD block for ORx data in the forward measurement mode + """tx_vswr_forward_orx: RMS Orx digital sample power measured at DPD block for ORx data in the forward measurement mode with measurement resolution of 0.01 dB and 21 dB offset for channel 0. Prms dBFS = txRms/100 + 21 dB""" if self.tx_vswr_tracking_en_chan0 == 1: return (self._get_iio_attr("voltage0", "vswr_forward_orx", True) / 100) + 21 @@ -761,28 +687,36 @@ def tx_vswr_reflected_gain_chan1(self): def tx_vswr_reflected_gain_imag_chan0(self): """tx_vswr_reflected_gain_imag: Imaginary part of the reflected path complex gain for channel 0. 1 = 0.01 linear gain""" if self.tx_vswr_tracking_en_chan0 == 1: - return self._get_iio_attr("voltage0", "vswr_reflected_gain_imag", True) * 0.01 + return ( + self._get_iio_attr("voltage0", "vswr_reflected_gain_imag", True) * 0.01 + ) return @property def tx_vswr_reflected_gain_imag_chan1(self): """tx_vswr_reflected_gain_imag: Imaginary part of the reflected path complex gain for channel 1. 1 = 0.01 linear gain""" if self.tx_vswr_tracking_en_chan1 == 1: - return self._get_iio_attr("voltage1", "vswr_reflected_gain_imag", True) * 0.01 + return ( + self._get_iio_attr("voltage1", "vswr_reflected_gain_imag", True) * 0.01 + ) return @property def tx_vswr_reflected_gain_real_chan0(self): """tx_vswr_reflected_gain_real: Real part of the reflected path complex gain for channel 0. 1 = 0.01 linear gain""" if self.tx_vswr_tracking_en_chan0 == 1: - return self._get_iio_attr("voltage0", "vswr_reflected_gain_real", True) * 0.01 + return ( + self._get_iio_attr("voltage0", "vswr_reflected_gain_real", True) * 0.01 + ) return @property def tx_vswr_reflected_gain_real_chan1(self): """tx_vswr_reflected_gain_real: Real part of the reflected path complex gain for channel 1. 1 = 0.01 linear gain""" if self.tx_vswr_tracking_en_chan1 == 1: - return self._get_iio_attr("voltage1", "vswr_reflected_gain_real", True) * 0.01 + return ( + self._get_iio_attr("voltage1", "vswr_reflected_gain_real", True) * 0.01 + ) return @property @@ -790,7 +724,9 @@ def tx_vswr_reflected_orx_chan0(self): """tx_vswr_reflected_orx: RMS ORx digital sample power measured at DPD block for the ORx data in the reverse measurement mode with measurement resolution of 0.01 dB and 21 dB offset for channel 0. Prms dBFS = orxRms/100 + 21 dB""" if self.tx_vswr_tracking_en_chan0 == 1: - return (self._get_iio_attr("voltage0", "vswr_reflected_orx", True) / 100) + 21 + return ( + self._get_iio_attr("voltage0", "vswr_reflected_orx", True) / 100 + ) + 21 return @property @@ -798,7 +734,9 @@ def tx_vswr_reflected_tx_chan0(self): """tx_vswr_reflected_tx: RMS Tx digital sample power measured at DPD actuator for the reverse measurement with measurement resolution of 0.01 dB and 21 dB offset for channel 0. Prms dBFS = txRms/100 + 21 dB""" if self.tx_vswr_tracking_en_chan0 == 1: - return (self._get_iio_attr("voltage0", "vswr_reflected_tx", True) / 100) + 21 + return ( + self._get_iio_attr("voltage0", "vswr_reflected_tx", True) / 100 + ) + 21 return @property @@ -806,12 +744,14 @@ def tx_vswr_reflected_tx_chan1(self): """tx_vswr_reflected_tx: RMS Tx digital sample power measured at DPD actuator for the reverse measurement with measurement resolution of 0.01 dB and 21 dB offset for channel 1. Prms dBFS = txRms/100 + 21 dB""" if self.tx_vswr_tracking_en_chan1 == 1: - return (self._get_iio_attr("voltage1", "vswr_reflected_tx", True) / 100) + 21 + return ( + self._get_iio_attr("voltage1", "vswr_reflected_tx", True) / 100 + ) + 21 return @property def tx_vswr_track_count_chan0(self): - """tx_vswr_track_count: The control reads back the number of times the VSWR has successfully run + """tx_vswr_track_count: The control reads back the number of times the VSWR has successfully run since VSWR initialization calibration for channel 0""" if self.tx_vswr_tracking_en_chan0 == 1: return self._get_iio_attr("voltage0", "vswr_track_count", True) @@ -819,7 +759,7 @@ def tx_vswr_track_count_chan0(self): @property def tx_vswr_track_count_chan1(self): - """tx_vswr_track_count: The control reads back the number of times the VSWR has successfully run since + """tx_vswr_track_count: The control reads back the number of times the VSWR has successfully run since VSWR initialization calibration for channel 1""" if self.tx_vswr_tracking_en_chan1 == 1: return self._get_iio_attr("voltage1", "vswr_track_count", True) diff --git a/examples/ad9375.py b/examples/ad9375.py index 7c3396ad2..7d07f576e 100644 --- a/examples/ad9375.py +++ b/examples/ad9375.py @@ -69,8 +69,8 @@ # ad9375 ONLY # Enable CLGC tracking -sdr.tx_clgc_tracking_en_chan0 = True -sdr.tx_clgc_tracking_en_chan1 = True +sdr.tx_clgc_tracking_en_chan0 = 1 +sdr.tx_clgc_tracking_en_chan1 = 1 # Configure and read CLGC desired gain property sdr.tx_clgc_desired_gain_chan0 = -3 @@ -85,37 +85,37 @@ print("CLGC tx rms channel 2", sdr.tx_clgc_tx_rms_chan1) # Disable CLGC tracking -sdr.tx_clgc_tracking_en_chan0 = False -sdr.tx_clgc_tracking_en_chan1 = False +sdr.tx_clgc_tracking_en_chan0 = 0 +sdr.tx_clgc_tracking_en_chan1 = 0 # Enable DPD tracking -sdr.tx_dpd_tracking_en_chan0 = True -sdr.tx_dpd_tracking_en_chan1 = True +sdr.tx_dpd_tracking_en_chan0 = 1 +sdr.tx_dpd_tracking_en_chan1 = 1 # Enable DPD actuator -sdr.tx_dpd_actuator_en_chan0 = True -sdr.tx_dpd_actuator_en_chan1 = True +sdr.tx_dpd_actuator_en_chan0 = 1 +sdr.tx_dpd_actuator_en_chan1 = 1 # Read DPD properties print("DPD status channel 1:", sdr.tx_dpd_status_chan0) print("DPD status channel 2:", sdr.tx_dpd_status_chan1) -# Enable DPD reset -sdr.tx_dpd_reset_en_chan0 = True -sdr.tx_dpd_reset_en_chan1 = True +# Enable DPD reset +sdr.tx_dpd_reset_en_chan0 = 1 +sdr.tx_dpd_reset_en_chan1 = 1 # Disable DPD tracking -sdr.tx_dpd_tracking_en_chan0 = False -sdr.tx_dpd_tracking_en_chan1 = False +sdr.tx_dpd_tracking_en_chan0 = 0 +sdr.tx_dpd_tracking_en_chan1 = 0 # Enable VSWR tracking -sdr.tx_vswr_tracking_en_chan0 = True -sdr.tx_vswr_tracking_en_chan1 = True +sdr.tx_vswr_tracking_en_chan0 = 1 +sdr.tx_vswr_tracking_en_chan1 = 1 # Read VSWR properties print("VSWR forward gain channel 1:", sdr.tx_vswr_forward_gain_chan0) print("VSWR forward gain channel 2:", sdr.tx_vswr_forward_gain_chan1) # Disable VSWR tracking -sdr.tx_vswr_tracking_en_chan0 = False -sdr.tx_vswr_tracking_en_chan1 = False \ No newline at end of file +sdr.tx_vswr_tracking_en_chan0 = 0 +sdr.tx_vswr_tracking_en_chan1 = 0 diff --git a/test/attr_tests.py b/test/attr_tests.py index 64a38b5ae..45ea0737a 100644 --- a/test/attr_tests.py +++ b/test/attr_tests.py @@ -347,7 +347,9 @@ def attribute_write_only_str_with_depends(uri, classname, attr, value, depends): raise Exception(e) -def attribute_check_range_readonly_with_depends(uri, classname, attr, depends, start, stop): +def attribute_check_range_readonly_with_depends( + uri, classname, attr, depends, start, stop +): """attribute_check_range_readonly_with_depends: Read only integer class property with dependent write properties @@ -376,4 +378,4 @@ def attribute_check_range_readonly_with_depends(uri, classname, attr, depends, s del sdr except Exception as e: del sdr - raise Exception(e) \ No newline at end of file + raise Exception(e) diff --git a/test/common.py b/test/common.py index 9678af06a..0839dcb07 100644 --- a/test/common.py +++ b/test/common.py @@ -97,7 +97,9 @@ def pytest_generate_tests(metafunc): ################################################# -def dev_interface(uri, classname, val, attr, tol, sub_channel=None, sleep=0, readonly=False): +def dev_interface( + uri, classname, val, attr, tol, sub_channel=None, sleep=0, readonly=False +): sdr = eval(classname + "(uri='" + uri + "')") # Check hardware if not hasattr(sdr, attr): @@ -122,7 +124,7 @@ def dev_interface(uri, classname, val, attr, tol, sub_channel=None, sleep=0, rea rval = float(getattr(sdr, attr)) if rval == val: break - + del sdr if is_list and isinstance(rval[0], str): diff --git a/test/test_ad9375.py b/test/test_ad9375.py index 5dccb8076..7718fb752 100644 --- a/test/test_ad9375.py +++ b/test/test_ad9375.py @@ -11,27 +11,27 @@ clgc_tracking_en_0 = { - "tx_clgc_tracking_en_chan0" : True, + "tx_clgc_tracking_en_chan0": 1, } dpd_tracking_en_0 = { - "tx_dpd_tracking_en_chan0" : True, + "tx_dpd_tracking_en_chan0": 1, } vswr_tracking_en_0 = { - "tx_vswr_tracking_en_chan0" : True, + "tx_vswr_tracking_en_chan0": 1, } clgc_tracking_en_1 = { - "tx_clgc_tracking_en_chan1" : True, + "tx_clgc_tracking_en_chan1": 1, } dpd_tracking_en_1 = { - "tx_dpd_tracking_en_chan1" : True, + "tx_dpd_tracking_en_chan1": 1, } vswr_tracking_en_1 = { - "tx_vswr_tracking_en_chan1" : True, + "tx_vswr_tracking_en_chan1": 1, } @@ -375,14 +375,23 @@ def test_ad9375_profile_write( @pytest.mark.parametrize( "attr, depends, values, tol, repeats", [ - ("tx_clgc_desired_gain_chan0", clgc_tracking_en_0, desired_gain_values, 0.5, 1), - ("tx_clgc_desired_gain_chan1", clgc_tracking_en_1, desired_gain_values, 0.5, 5), + ("tx_clgc_desired_gain_chan0", clgc_tracking_en_0, desired_gain_values, 0.5, 2), + ("tx_clgc_desired_gain_chan1", clgc_tracking_en_1, desired_gain_values, 0.5, 2), ], ) def test_ad9375_attr_with_depends( - test_attribute_multipe_values_with_depends, iio_uri, classname, attr, depends, values, tol, repeats + test_attribute_multiple_values_with_depends, + iio_uri, + classname, + attr, + depends, + values, + tol, + repeats, ): - test_attribute_multipe_values_with_depends(iio_uri, classname, attr, depends, values, tol, repeats) + test_attribute_multiple_values_with_depends( + iio_uri, classname, attr, depends, values, tol, repeats + ) ######################################## @@ -391,39 +400,39 @@ def test_ad9375_attr_with_depends( @pytest.mark.parametrize( "attr, depends", [ - ("tx_clgc_current_gain_chan0", clgc_tracking_en_0), - ("tx_clgc_current_gain_chan1", clgc_tracking_en_1), - ("tx_clgc_orx_rms_chan0", clgc_tracking_en_0), - ("tx_clgc_track_count_chan0", clgc_tracking_en_0), - ("tx_clgc_track_count_chan1", clgc_tracking_en_1), - ("tx_clgc_tx_gain_chan0", clgc_tracking_en_0), - ("tx_clgc_tx_gain_chan1", clgc_tracking_en_1), - ("tx_clgc_tx_rms_chan0", clgc_tracking_en_0), - ("tx_clgc_tx_rms_chan1", clgc_tracking_en_1), - ("tx_dpd_track_count_chan0", dpd_tracking_en_0), - ("tx_dpd_track_count_chan1", dpd_tracking_en_1), - ("tx_dpd_status_chan0", dpd_tracking_en_0), - ("tx_dpd_status_chan1", dpd_tracking_en_1), - ("tx_vswr_forward_gain_chan0", vswr_tracking_en_0), - ("tx_vswr_forward_gain_chan1", vswr_tracking_en_1), - ("tx_vswr_forward_gain_imag_chan0", vswr_tracking_en_0), - ("tx_vswr_forward_gain_imag_chan1", vswr_tracking_en_1), - ("tx_vswr_forward_gain_real_chan0", vswr_tracking_en_0), - ("tx_vswr_forward_gain_real_chan1", vswr_tracking_en_1), - ("tx_vswr_forward_orx_chan0", vswr_tracking_en_0), - ("tx_vswr_forward_tx_chan0", vswr_tracking_en_0), - ("tx_vswr_forward_tx_chan1", vswr_tracking_en_1), - ("tx_vswr_reflected_gain_chan0", vswr_tracking_en_0), - ("tx_vswr_reflected_gain_chan1", vswr_tracking_en_1), - ("tx_vswr_reflected_gain_imag_chan0", vswr_tracking_en_0), - ("tx_vswr_reflected_gain_imag_chan1", vswr_tracking_en_1), - ("tx_vswr_reflected_gain_real_chan0", vswr_tracking_en_0), - ("tx_vswr_reflected_gain_real_chan1", vswr_tracking_en_1), - ("tx_vswr_reflected_orx_chan0", vswr_tracking_en_0), - ("tx_vswr_reflected_tx_chan0", vswr_tracking_en_0), - ("tx_vswr_reflected_tx_chan1", vswr_tracking_en_1), - ("tx_vswr_track_count_chan0", vswr_tracking_en_0), - ("tx_vswr_track_count_chan1", vswr_tracking_en_1), + ("tx_clgc_current_gain_chan0", clgc_tracking_en_0), + ("tx_clgc_current_gain_chan1", clgc_tracking_en_1), + ("tx_clgc_orx_rms_chan0", clgc_tracking_en_0), + ("tx_clgc_track_count_chan0", clgc_tracking_en_0), + ("tx_clgc_track_count_chan1", clgc_tracking_en_1), + ("tx_clgc_tx_gain_chan0", clgc_tracking_en_0), + ("tx_clgc_tx_gain_chan1", clgc_tracking_en_1), + ("tx_clgc_tx_rms_chan0", clgc_tracking_en_0), + ("tx_clgc_tx_rms_chan1", clgc_tracking_en_1), + ("tx_dpd_track_count_chan0", dpd_tracking_en_0), + ("tx_dpd_track_count_chan1", dpd_tracking_en_1), + ("tx_dpd_status_chan0", dpd_tracking_en_0), + ("tx_dpd_status_chan1", dpd_tracking_en_1), + ("tx_vswr_forward_gain_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_gain_chan1", vswr_tracking_en_1), + ("tx_vswr_forward_gain_imag_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_gain_imag_chan1", vswr_tracking_en_1), + ("tx_vswr_forward_gain_real_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_gain_real_chan1", vswr_tracking_en_1), + ("tx_vswr_forward_orx_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_tx_chan0", vswr_tracking_en_0), + ("tx_vswr_forward_tx_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_gain_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_gain_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_gain_imag_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_gain_imag_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_gain_real_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_gain_real_chan1", vswr_tracking_en_1), + ("tx_vswr_reflected_orx_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_tx_chan0", vswr_tracking_en_0), + ("tx_vswr_reflected_tx_chan1", vswr_tracking_en_1), + ("tx_vswr_track_count_chan0", vswr_tracking_en_0), + ("tx_vswr_track_count_chan1", vswr_tracking_en_1), ], ) def test_ad9375_attr_readonly_with_depends( @@ -443,9 +452,17 @@ def test_ad9375_attr_readonly_with_depends( ], ) def test_ad9375_attr_range_readonly( - test_attribute_check_range_readonly_with_depends, iio_uri, classname, attr, depends, start, stop + test_attribute_check_range_readonly_with_depends, + iio_uri, + classname, + attr, + depends, + start, + stop, ): - test_attribute_check_range_readonly_with_depends(iio_uri, classname, attr, depends, start, stop) + test_attribute_check_range_readonly_with_depends( + iio_uri, classname, attr, depends, start, stop + ) ######################################### @@ -454,22 +471,22 @@ def test_ad9375_attr_range_readonly( @pytest.mark.parametrize( "attr, value", [ - ("tx_clgc_tracking_en_chan0", True), - ("tx_clgc_tracking_en_chan0", False), - ("tx_clgc_tracking_en_chan1", True), - ("tx_clgc_tracking_en_chan1", False), - ("tx_dpd_actuator_en_chan0", True), - ("tx_dpd_actuator_en_chan0", False), - ("tx_dpd_actuator_en_chan1", True), - ("tx_dpd_actuator_en_chan1", False), - ("tx_vswr_tracking_en_chan0", True), - ("tx_vswr_tracking_en_chan0", False), - ("tx_vswr_tracking_en_chan1", True), - ("tx_vswr_tracking_en_chan1", False), - ("tx_dpd_tracking_en_chan0", True), - ("tx_dpd_tracking_en_chan0", False), - ("tx_dpd_tracking_en_chan1", True), - ("tx_dpd_tracking_en_chan1", False), + ("tx_clgc_tracking_en_chan0", 1), + ("tx_clgc_tracking_en_chan0", 0), + ("tx_clgc_tracking_en_chan1", 1), + ("tx_clgc_tracking_en_chan1", 0), + ("tx_dpd_actuator_en_chan0", 1), + ("tx_dpd_actuator_en_chan0", 0), + ("tx_dpd_actuator_en_chan1", 1), + ("tx_dpd_actuator_en_chan1", 0), + ("tx_vswr_tracking_en_chan0", 1), + ("tx_vswr_tracking_en_chan0", 0), + ("tx_vswr_tracking_en_chan1", 1), + ("tx_vswr_tracking_en_chan1", 0), + ("tx_dpd_tracking_en_chan0", 1), + ("tx_dpd_tracking_en_chan0", 0), + ("tx_dpd_tracking_en_chan1", 1), + ("tx_dpd_tracking_en_chan1", 0), ], ) def test_ad9375_attr_boolean( @@ -482,11 +499,7 @@ def test_ad9375_attr_boolean( @pytest.mark.iio_hardware(hardware) @pytest.mark.parametrize("classname", [(classname)]) @pytest.mark.parametrize( - "attr, value", - [ - ("tx_dpd_reset_en_chan0", 1), - ("tx_dpd_reset_en_chan1", 1), - ], + "attr, value", [("tx_dpd_reset_en_chan0", 1), ("tx_dpd_reset_en_chan1", 1),], ) def test_ad9375_attr_write_only( test_attribute_write_only_str, iio_uri, classname, attr, value From aa41fcd5c596b19c8538cb52ecadfc367dae6c7b Mon Sep 17 00:00:00 2001 From: Trisha De Vera Date: Thu, 12 Oct 2023 09:34:24 +0800 Subject: [PATCH 4/7] Modify test_map.py --- test/test_map.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_map.py b/test/test_map.py index da9b4366b..50a3a22bd 100644 --- a/test/test_map.py +++ b/test/test_map.py @@ -91,6 +91,10 @@ def get_test_map(): "zynq-zc706-adv7511-adrv9375", "zynqmp-zcu102-rev10-adrv9375", ] + test_map["adrv9375"] = [ + "zynq-zc706-adv7511-adrv9375", + "zynqmp-zcu102-rev10-adrv9375", + ] test_map["adrv9009"] = [ "socfpga_arria10_socdk_adrv9009", "zynqmp-zcu102-rev10-adrv9008-1", From d0ac3d941f13869be622190f0fbc2741a78b5f60 Mon Sep 17 00:00:00 2001 From: Trisha De Vera Date: Mon, 23 Oct 2023 09:37:10 +0800 Subject: [PATCH 5/7] Add profile property Signed-off-by: Trisha De Vera --- adi/ad937x.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/adi/ad937x.py b/adi/ad937x.py index 651ee5c56..5c8e0a802 100644 --- a/adi/ad937x.py +++ b/adi/ad937x.py @@ -34,6 +34,7 @@ def __init__( self._rxadc = self._ctx.find_device("axi-ad9371-rx-hpc") self._rxobs = self._ctx.find_device("axi-ad9371-rx-obs-hpc") self._txdac = self._ctx.find_device("axi-ad9371-tx-hpc") + self._ctx.set_timeout(30000) # Needed for loading profiles if not disable_jesd_control and jesd: self._jesd = jesd(uri, username=username, password=password) @@ -324,6 +325,17 @@ def obs_rf_port_select(self, value): def jesd204_statuses(self): return self._jesd.get_all_statuses() + @property + def profile(self): + """Load profile file. Provide path to profile file to attribute""" + return self._get_iio_dev_attr("profile_config") + + @profile.setter + def profile(self, value): + with open(value, "r") as file: + data = file.read() + self._set_iio_dev_attr_str("profile_config", data) + class ad9375(ad9371): """ AD9375 Transceiver """ From b1b81602c9c6d54abc80f7084acddbcb774c3813 Mon Sep 17 00:00:00 2001 From: Trisha De Vera Date: Wed, 8 Nov 2023 08:44:54 +0800 Subject: [PATCH 6/7] Add ad937x in supported_parts.md Signed-off-by: Trisha De Vera --- supported_parts.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/supported_parts.md b/supported_parts.md index c612e0846..ff33e0bc5 100644 --- a/supported_parts.md +++ b/supported_parts.md @@ -96,8 +96,7 @@ - AD9250 - AD9265 - AD936X (Pluto, FMComms2/3/4/5, ADRV936X) -- AD9371 -- AD9375 +- AD937X (AD9371, AD9375, ADRV937X) - AD9434 - AD9467 - AD9625 From 51433cd6b26860de4e16426e047429c99db49f57 Mon Sep 17 00:00:00 2001 From: Trisha De Vera Date: Fri, 17 Nov 2023 09:22:49 +0800 Subject: [PATCH 7/7] Modify supported_parts.md Signed-off-by: Trisha De Vera --- supported_parts.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/supported_parts.md b/supported_parts.md index ff33e0bc5..c612e0846 100644 --- a/supported_parts.md +++ b/supported_parts.md @@ -96,7 +96,8 @@ - AD9250 - AD9265 - AD936X (Pluto, FMComms2/3/4/5, ADRV936X) -- AD937X (AD9371, AD9375, ADRV937X) +- AD9371 +- AD9375 - AD9434 - AD9467 - AD9625