// // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #pragma once #include #include #include #include #include #include #include #include #include namespace uhd { namespace usrp { namespace zbx { //! Which LO to address when peeking/poking // This must match the LO_SELECT values in gen_zbx_cpld_regs.py enum class zbx_lo_t { TX0_LO1 = 0, TX0_LO2 = 1, TX1_LO1 = 2, TX1_LO2 = 3, RX0_LO1 = 4, RX0_LO2 = 5, RX1_LO1 = 6, RX1_LO2 = 7 }; static const std::map ZBX_LO_LOG_ID = { {zbx_lo_t::TX0_LO1, "ZBX TX0 LO1"}, {zbx_lo_t::TX0_LO2, "ZBX TX0 LO2"}, {zbx_lo_t::TX1_LO1, "ZBX TX1 LO1"}, {zbx_lo_t::TX1_LO2, "ZBX TX1 LO2"}, {zbx_lo_t::RX0_LO1, "ZBX RX0 LO1"}, {zbx_lo_t::RX0_LO2, "ZBX RX0 LO2"}, {zbx_lo_t::RX1_LO1, "ZBX RX1 LO1"}, {zbx_lo_t::RX1_LO2, "ZBX RX1 LO2"}}; static constexpr std::array ZBX_ALL_LO = {zbx_lo_t::TX0_LO1, zbx_lo_t::TX0_LO2, zbx_lo_t::TX1_LO1, zbx_lo_t::TX1_LO2, zbx_lo_t::RX0_LO1, zbx_lo_t::RX0_LO2, zbx_lo_t::RX1_LO1, zbx_lo_t::RX1_LO2}; /****************************************************************************** * Important: When changing values here, check if that also requires updating * the manual (host/docs/zbx.dox). If it also requires changing the website or * other sales/marketing material, make sure to let the appropriate people know! *****************************************************************************/ enum class zbx_lo_source_t { internal, external }; static constexpr zbx_lo_source_t ZBX_DEFAULT_LO_SOURCE = zbx_lo_source_t::internal; // The ZBX has a non-configurable analog bandwidth of 400 MHz. At lower frequency, // the usable bandwidth may be smaller though. For those smaller bandwidths, see // the tune maps. static constexpr double ZBX_DEFAULT_BANDWIDTH = 400e6; // Hz static constexpr double LMX2572_MAX_FREQ = 6.4e9; // Hz // LMX2572 can go lower, but on the ZBX, the analog paths limit frequencies down // to 3.2 GHz static constexpr double LMX2572_MIN_FREQ = 3.2e9; // Hz static constexpr double LMX2572_DEFAULT_FREQ = 4e9; // Hz static constexpr uint32_t ZBX_LO_LOCK_TIMEOUT_MS = 20; // milliseconds // This is the step size for the LO tuning relative to the PRC rate: static constexpr int ZBX_RELATIVE_LO_STEP_SIZE = 6; static constexpr double ZBX_MIN_FREQ = 1e6; // Hz static constexpr double ZBX_MAX_FREQ = 8e9; // Hz static constexpr double ZBX_DEFAULT_FREQ = 1e9; // Hz static const uhd::freq_range_t ZBX_FREQ_RANGE(ZBX_MIN_FREQ, ZBX_MAX_FREQ); static constexpr double ZBX_LOWBAND_FREQ = 3e9; // Hz constexpr char HW_GAIN_STAGE[] = "hw"; static constexpr double RX_MIN_GAIN = 0; static constexpr double RX_MAX_GAIN = 60; static constexpr double RX_GAIN_STEP = 1; static constexpr double ZBX_DEFAULT_RX_GAIN = RX_MIN_GAIN; static const uhd::gain_range_t ZBX_RX_GAIN_RANGE(RX_MIN_GAIN, RX_MAX_GAIN, RX_GAIN_STEP); // Rx gain is limited to [0, 38] for frequency <= 500 MHz static constexpr double RX_LOW_FREQ_MAX_GAIN = 38; static constexpr double RX_LOW_FREQ_MAX_GAIN_CUTOFF = 500e6; // Hz static const uhd::gain_range_t ZBX_RX_LOW_FREQ_GAIN_RANGE( RX_MIN_GAIN, RX_LOW_FREQ_MAX_GAIN, RX_GAIN_STEP); static constexpr double TX_MIN_GAIN = 0; static constexpr double TX_MAX_GAIN = 60; static constexpr double TX_GAIN_STEP = 1; static constexpr double ZBX_DEFAULT_TX_GAIN = TX_MIN_GAIN; static const uhd::gain_range_t ZBX_TX_GAIN_RANGE(TX_MIN_GAIN, TX_MAX_GAIN, TX_GAIN_STEP); static constexpr char ZBX_GAIN_PROFILE_DEFAULT[] = "default"; static constexpr char ZBX_GAIN_PROFILE_MANUAL[] = "manual"; static constexpr char ZBX_GAIN_PROFILE_CPLD[] = "table"; static constexpr char ZBX_GAIN_PROFILE_CPLD_NOATR[] = "table_noatr"; static const std::vector ZBX_GAIN_PROFILES = {ZBX_GAIN_PROFILE_DEFAULT, ZBX_GAIN_PROFILE_MANUAL, ZBX_GAIN_PROFILE_CPLD, ZBX_GAIN_PROFILE_CPLD_NOATR}; // Maximum attenuation of the TX DSAs static constexpr uint8_t ZBX_TX_DSA_MAX_ATT = 31; // Maximum attenuation of the RX DSAs static constexpr uint8_t ZBX_RX_DSA_MAX_ATT = 15; static constexpr char ZBX_GAIN_STAGE_DSA1[] = "DSA1"; static constexpr char ZBX_GAIN_STAGE_DSA2[] = "DSA2"; static constexpr char ZBX_GAIN_STAGE_DSA3A[] = "DSA3A"; static constexpr char ZBX_GAIN_STAGE_DSA3B[] = "DSA3B"; static constexpr char ZBX_GAIN_STAGE_AMP[] = "AMP"; static constexpr char ZBX_GAIN_STAGE_ALL[] = "all"; // Not technically a gain stage, but we'll keep it static constexpr char ZBX_GAIN_STAGE_TABLE[] = "TABLE"; static const std::vector ZBX_RX_GAIN_STAGES = { ZBX_GAIN_STAGE_DSA1, ZBX_GAIN_STAGE_DSA2, ZBX_GAIN_STAGE_DSA3A, ZBX_GAIN_STAGE_DSA3B}; static const std::vector ZBX_TX_GAIN_STAGES = { ZBX_GAIN_STAGE_DSA1, ZBX_GAIN_STAGE_DSA2, ZBX_GAIN_STAGE_AMP}; enum class tx_amp { BYPASS = 0, LOWBAND = 1, HIGHBAND = 2 }; static constexpr double ZBX_TX_BYPASS_GAIN = 0.0; static constexpr double ZBX_TX_LOWBAND_GAIN = 14.0; static constexpr double ZBX_TX_HIGHBAND_GAIN = 21.0; // The amplifier gain varies wildly across frequency, temperature.... but we // need some kind of mapping for querying/setting individual gain stages by // dB value. static const std::map ZBX_TX_AMP_GAIN_MAP = { {tx_amp::BYPASS, ZBX_TX_BYPASS_GAIN}, {tx_amp::LOWBAND, ZBX_TX_LOWBAND_GAIN}, {tx_amp::HIGHBAND, ZBX_TX_HIGHBAND_GAIN}}; static const std::map ZBX_TX_GAIN_AMP_MAP = { {ZBX_TX_BYPASS_GAIN, tx_amp::BYPASS}, {ZBX_TX_LOWBAND_GAIN, tx_amp::LOWBAND}, {ZBX_TX_HIGHBAND_GAIN, tx_amp::HIGHBAND}}; /*** Antenna-related constants ***********************************************/ // TX and RX SMA connectors on the front panel constexpr char ANTENNA_TXRX[] = "TX/RX0"; constexpr char ANTENNA_RX[] = "RX1"; // Internal "antenna" ports constexpr char ANTENNA_CAL_LOOPBACK[] = "CAL_LOOPBACK"; constexpr char ANTENNA_TERMINATION[] = "TERMINATION"; // Only RX path // Default antennas (which are selected at init) constexpr auto DEFAULT_TX_ANTENNA = ANTENNA_TXRX; constexpr auto DEFAULT_RX_ANTENNA = ANTENNA_RX; // Helper lists static const std::vector RX_ANTENNAS = { ANTENNA_TXRX, ANTENNA_RX, ANTENNA_CAL_LOOPBACK, ANTENNA_TERMINATION}; static const std::vector TX_ANTENNAS = {ANTENNA_TXRX, ANTENNA_CAL_LOOPBACK}; // For branding purposes, ZBX changed the antenna names around. For existing // software, we still accept the old antenna names, but map them to the new ones static const std::unordered_map TX_ANTENNA_NAME_COMPAT_MAP{ {"TX/RX", ANTENNA_TXRX}}; static const std::unordered_map RX_ANTENNA_NAME_COMPAT_MAP{ {"TX/RX", ANTENNA_TXRX}, {"RX2", ANTENNA_RX}}; /*** LO-related constants ****************************************************/ //! Low-band LO static constexpr char ZBX_LO1[] = "LO1"; //! LO at 2nd mixer static constexpr char ZBX_LO2[] = "LO2"; static constexpr char RFDC_NCO[] = "rfdc"; static const std::vector ZBX_LOS = {ZBX_LO1, ZBX_LO2, RFDC_NCO}; static constexpr size_t ZBX_NUM_CHANS = 2; static constexpr std::array ZBX_CHANNELS{0, 1}; static constexpr double ZBX_MIX1_MN_THRESHOLD = 4e9; // Struct for holding band information, used by zbx_radio_control_impl. // This information should be selected base on requested tune frequency, and should not be // changed once initialized. struct tune_map_item_t { double min_band_freq; double max_band_freq; uint8_t rf_fir; uint8_t if1_fir; uint8_t if2_fir; int mix1_m; int mix1_n; int mix2_m; int mix2_n; double if1_freq_min; double if1_freq_max; double if2_freq_min; double if2_freq_max; }; // These are addresses for the various table-based registers static constexpr uint32_t ATR_ADDR_0X = 0; static constexpr uint32_t ATR_ADDR_RX = 1; static constexpr uint32_t ATR_ADDR_TX = 2; static constexpr uint32_t ATR_ADDR_XX = 3; // Full-duplex // Helper for looping static constexpr std::array ATR_ADDRS{0, 1, 2, 3}; // Turn clang-formatting off so it doesn't compress these tables into a mess. // clang-format off static const std::vector rx_tune_map = { // | min_band_freq | max_band_freq | rf_fir | if1_fir | if2_fir | mix1 m, n | mix2 m, n | if1_freq_min | if1_freq_max | if2_freq_min | if2_freq_max | { 1e6, 200e6, 1, 1, 2, -1, 1, -1, 1, 4100e6, 4100e6, 1850e6, 1850e6 }, { 200e6, 400e6, 1, 1, 2, -1, 1, -1, 1, 4100e6, 4100e6, 1850e6, 1850e6 }, { 400e6, 500e6, 1, 1, 2, -1, 1, -1, 1, 4100e6, 4100e6, 1850e6, 1850e6 }, { 500e6, 900e6, 1, 1, 2, -1, 1, -1, 1, 4100e6, 4100e6, 1850e6, 1850e6 }, { 900e6, 1800e6, 1, 1, 2, -1, 1, -1, 1, 4100e6, 4100e6, 2150e6, 2150e6 }, { 1800e6, 2300e6, 2, 1, 1, -1, 1, -1, 1, 4100e6, 4100e6, 1060e6, 1060e6 }, { 2300e6, 2700e6, 3, 1, 1, -1, 1, -1, 1, 4100e6, 3700e6, 1060e6, 1060e6 }, { 2700e6, 3000e6, 3, 4, 2, 1, -1, 1, -1, 7000e6, 7100e6, 2050e6, 2080e6 }, { 3000e6, 4200e6, 0, 1, 2, 0, 0, -1, 1, 0, 0, 1850e6, 1850e6 }, { 4200e6, 4500e6, 0, 2, 2, 0, 0, -1, 1, 0, 0, 1850e6, 1850e6 }, { 4500e6, 4700e6, 0, 2, 1, 0, 0, -1, 1, 0, 0, 1060e6, 1060e6 }, { 4700e6, 5300e6, 0, 2, 1, 0, 0, -1, 1, 0, 0, 1060e6, 1060e6 }, { 5300e6, 5600e6, 0, 2, 1, 0, 0, 1, -1, 0, 0, 1060e6, 1060e6 }, { 5600e6, 6800e6, 0, 3, 1, 0, 0, 1, -1, 0, 0, 1060e6, 1060e6 }, { 6800e6, 7400e6, 0, 4, 1, 0, 0, 1, -1, 0, 0, 1060e6, 1060e6 }, { 7400e6, 8000e6, 0, 4, 2, 0, 0, 1, -1, 0, 0, 1850e6, 1850e6 }, }; static const std::vector tx_tune_map = { // | min_band_freq | max_band_freq | rf_fir | if1_fir | if2_fir | mix1 m, n | mix2 m, n | if1_freq_min | if1_freq_max | if2_freq_min | if2_freq_max | { 1e6, 200e6, 1, 2, 1, -1, 1, 1, -1, 4600e6, 4600e6, 1060e6, 1060e6 }, { 200e6, 300e6, 1, 2, 1, -1, 1, 1, -1, 4600e6, 4600e6, 1060e6, 1060e6 }, { 300e6, 400e6, 1, 2, 1, -1, 1, 1, -1, 4600e6, 4600e6, 1060e6, 1060e6 }, { 400e6, 600e6, 1, 2, 1, -1, 1, 1, -1, 4600e6, 4600e6, 1060e6, 1060e6 }, { 600e6, 800e6, 1, 2, 1, -1, 1, 1, -1, 4600e6, 4600e6, 1060e6, 1060e6 }, { 800e6, 1300e6, 1, 2, 1, -1, 1, 1, -1, 4600e6, 4600e6, 1060e6, 1060e6 }, { 1300e6, 1800e6, 1, 2, 1, -1, 1, 1, -1, 4600e6, 4600e6, 1060e6, 1060e6 }, { 1800e6, 2300e6, 2, 1, 1, -1, 1, -1, 1, 4100e6, 4100e6, 1060e6, 1060e6 }, { 2300e6, 2700e6, 3, 1, 2, -1, 1, -1, 1, 3700e6, 3700e6, 2070e6, 2200e6 }, { 2700e6, 3000e6, 3, 5, 2, 1, -1, 1, -1, 6800e6, 7100e6, 2000e6, 2000e6 }, { 3000e6, 4030e6, 0, 1, 2, 0, 0, -1, 1, 0, 0, 2050e6, 2370e6 }, { 4030e6, 4500e6, 0, 1, 1, 0, 0, -1, 1, 0, 0, 1060e6, 1060e6 }, { 4500e6, 4900e6, 0, 2, 1, 0, 0, 1, -1, 0, 0, 1060e6, 1060e6 }, { 4900e6, 5100e6, 0, 2, 1, 0, 0, 1, -1, 0, 0, 1060e6, 1060e6 }, { 5100e6, 5700e6, 0, 3, 2, 0, 0, 1, -1, 0, 0, 1900e6, 2300e6 }, { 5700e6, 6100e6, 0, 4, 2, 0, 0, 1, -1, 0, 0, 2300e6, 2500e6 }, { 6100e6, 6400e6, 0, 4, 2, 0, 0, 1, -1, 0, 0, 2400e6, 2500e6 }, { 6400e6, 7000e6, 0, 5, 2, 0, 0, 1, -1, 0, 0, 1900e6, 1950e6 }, { 7000e6, 7400e6, 0, 6, 1, 0, 0, 1, -1, 0, 0, 1060e6, 1060e6 }, { 7400e6, 8000e6, 0, 6, 2, 0, 0, 1, -1, 0, 0, 1950e6, 2050e6 }, }; // Turn clang-format back on just for posterity // clang-format on }}} // namespace uhd::usrp::zbx namespace uhd { namespace usrp { namespace zbx { // << Operator overload for expert's node printing (zbx_lo_source_t property) // Any added expert nodes of type enum class will have to define this std::ostream& operator<<( std::ostream& os, const ::uhd::usrp::zbx::zbx_lo_source_t& lo_source); }}} // namespace uhd::usrp::zbx