diff options
-rw-r--r-- | host/lib/usrp/x300/x300_radio_control.cpp | 66 |
1 files changed, 53 insertions, 13 deletions
diff --git a/host/lib/usrp/x300/x300_radio_control.cpp b/host/lib/usrp/x300/x300_radio_control.cpp index 3bbadf7d6..6a851bc8f 100644 --- a/host/lib/usrp/x300/x300_radio_control.cpp +++ b/host/lib/usrp/x300/x300_radio_control.cpp @@ -94,6 +94,14 @@ static constexpr uint32_t SR_LEDS = PERIPH_BASE + 176 * PERIPH_REG_OFFSET; static constexpr uint32_t SR_FP_GPIO = PERIPH_BASE + 184 * PERIPH_REG_OFFSET; static constexpr uint32_t SR_DB_GPIO = PERIPH_BASE + 192 * PERIPH_REG_OFFSET; +// LED bit positions +// Green LED on TX/RX port (left SMA) +static constexpr int SR_LED_TXRX_RX = (1 << 0); +// Red LED on TX/RX port (left SMA) +static constexpr int SR_LED_TXRX_TX = (1 << 1); +// Green LED on RX2 port (right SMA) +static constexpr int SR_LED_RX2_RX = (1 << 2); + static constexpr uint32_t RB_MISC_IO = PERIPH_BASE + 16 * PERIPH_REG_OFFSET; static constexpr uint32_t RB_SPI = PERIPH_BASE + 17 * PERIPH_REG_OFFSET; // static constexpr uint32_t RB_LEDS = PERIPH_BASE + 18 * PERIPH_REG_OFFSET; @@ -178,6 +186,17 @@ public: x300_regs::SR_LEDS, x300_regs::PERIPH_REG_OFFSET)); _leds->set_atr_mode( usrp::gpio_atr::MODE_ATR, usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL); + // Set LEDs to default setting: RX2 LED on RX, TX/RX red LED on TX. The + // actual setting depends on the antenna choice and is handled in + // _update_atr_leds(). + _leds->set_atr_reg(gpio_atr::ATR_REG_IDLE, 0); + _leds->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, x300_regs::SR_LED_RX2_RX); + _leds->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, x300_regs::SR_LED_TXRX_TX); + // We choose to light both LEDs on full duplex, regardless of the + // antenna selection, because the single multi-color LED on the TX/RX + // side does not provide useful visual feedback by itself. + _leds->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, + x300_regs::SR_LED_RX2_RX | x300_regs::SR_LED_TXRX_TX); // We always want to initialize at least one frontend core for both TX and RX // RX periphs for (size_t i = 0; i < std::max<size_t>(get_num_output_ports(), 1); i++) { @@ -1768,21 +1787,36 @@ private: _db_eeproms[addr] = db_eeprom; } + // A note on updating the LED ATR register: There is a single ATR register + // for the radio block, despite there being 2 channels. For most (1-channel) + // daughterboards, the rules are simple: When transmitting, the red LED turns + // on. When receiving, either the green LED under the RX2 or on the TX/RX + // port turn, depending on if the user has selected a TX/RX antenna or not. + // For TwinRX, we have additional rules. The board has two channels, but + // either of them can used with any SMA port. We therefore have to check + // which channels are active (0, 1, or both) and on the active channels, + // which set of antenna ports is used (RX1 aka TX/RX, RX2). All active RX + // ports shall then be added the the RX ATR register. void _update_atr_leds(const std::string& rx_ant, const size_t /*chan*/) { - // The "RX1" port is used by TwinRX and the "TX/RX" port is used by all - // other full-duplex dboards. We need to handle both here. - const bool is_txrx = (rx_ant == "TX/RX" or rx_ant == "RX1"); - // Green LED on TX/RX port (left SMA) - constexpr int TXRX_RX = (1 << 0); - // Red LED on TX/RX port (left SMA) - constexpr int TXRX_TX = (1 << 1); - // Green LED on RX2 port (right SMA) - constexpr int RX2_RX = (1 << 2); - _leds->set_atr_reg(gpio_atr::ATR_REG_IDLE, 0); - _leds->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, is_txrx ? TXRX_RX : RX2_RX); - _leds->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, TXRX_TX); - _leds->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, RX2_RX | TXRX_TX); + uint32_t rx_led_atr_state = 0; + if (_twinrx) { + for (size_t chan = 0; chan < get_num_output_ports(); chan++) { + const auto fe_enable_path = get_db_path("rx", chan) / "enabled"; + if (get_tree()->access<bool>(fe_enable_path).get()) { + if (get_rx_antenna(chan) == "RX1") { + rx_led_atr_state |= x300_regs::SR_LED_TXRX_RX; + } + if (get_rx_antenna(chan) == "RX2") { + rx_led_atr_state |= x300_regs::SR_LED_RX2_RX; + } + } + } + } else { + rx_led_atr_state = rx_ant == "TX/RX" ? x300_regs::SR_LED_TXRX_RX + : x300_regs::SR_LED_RX2_RX; + } + _leds->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, rx_led_atr_state); } void _set_rx_fe(const std::string& fe, const size_t chan) @@ -1888,6 +1922,12 @@ private: "Enabling RX chan " << chan << ": " << (chan_active ? "Yes" : "No")); get_tree()->access<bool>(fe_enable_path).set(chan_active); } + // Modifying the number of active channels can affect how the + // front-panel LEDs get configured for TwinRX boards. Worst case, + // this is a no-op since we call it with the same argument as it was + // called before. Note this must be called after the 'enable' + // property is set. + _update_atr_leds(get_rx_antenna(chan), chan); } return true; |