X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=usrp%2Fhost%2Flib%2Flimbo%2Fdb_wbx.cc;fp=usrp%2Fhost%2Flib%2Flimbo%2Fdb_wbx.cc;h=9f1d72939a24edaf853c9f65da8a588ecdfc18bd;hb=8a9ddbb0675f9bfcc6e03b457fba6c79474a3693;hp=0000000000000000000000000000000000000000;hpb=82d471b9b4a8b389b5da44b19c69c36420828382;p=debian%2Fgnuradio diff --git a/usrp/host/lib/limbo/db_wbx.cc b/usrp/host/lib/limbo/db_wbx.cc new file mode 100644 index 00000000..9f1d7293 --- /dev/null +++ b/usrp/host/lib/limbo/db_wbx.cc @@ -0,0 +1,953 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#include +#include +#include +#include +#include +#include +#include + +// d'board i/o pin defs + +// TX IO Pins +#define TX_POWER (1 << 0) // TX Side Power +#define RX_TXN (1 << 1) // T/R antenna switch for TX/RX port +#define TX_ENB_MIX (1 << 2) // Enable IQ mixer +#define TX_ENB_VGA (1 << 3) + +// RX IO Pins +#define RX2_RX1N (1 << 0) // antenna switch between RX2 and TX/RX port +#define RXENABLE (1 << 1) // enables mixer +#define PLL_LOCK_DETECT (1 << 2) // Muxout pin from PLL -- MUST BE INPUT +#define MReset (1 << 3) // NB6L239 Master Reset, asserted low +#define SELA0 (1 << 4) // NB6L239 SelA0 +#define SELA1 (1 << 5) // NB6L239 SelA1 +#define SELB0 (1 << 6) // NB6L239 SelB0 +#define SELB1 (1 << 7) // NB6L239 SelB1 +#define PLL_ENABLE (1 << 8) // CE Pin on PLL +#define AUX_SCLK (1 << 9) // ALT SPI SCLK +#define AUX_SDO (1 << 10) // ALT SPI SDO +#define AUX_SEN (1 << 11) // ALT SPI SEN + + +wbx_base::wbx_base(usrp_basic_sptr usrp, int which) + : db_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to side A or B respectively + * @type which: int + */ + + d_first = true; + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + // FIXME -- the write reg functions don't work with 0xffff for masks + _rx_write_oe(int(PLL_ENABLE|MReset|SELA0|SELA1|SELB0|SELB1|RX2_RX1N|RXENABLE), 0x7fff); + _rx_write_io((PLL_ENABLE|MReset|0|RXENABLE), (PLL_ENABLE|MReset|RX2_RX1N|RXENABLE)); + + _tx_write_oe((TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA), 0x7fff); + _tx_write_io((0|RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); // TX off, TR switch set to RX + + if(d_which == 0) { + d_spi_enable = SPI_ENABLE_RX_A; + } + else { + d_spi_enable = SPI_ENABLE_RX_B; + } + + set_auto_tr(false); + +} + +wbx_base::~wbx_base() +{ + shutdown(); +} + + +void +wbx_base::shutdown() +{ + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + write_io(d_which, d_power_off, POWER_UP); // turn off power to board + _write_oe(d_which, 0, 0xffff); // turn off all outputs + set_auto_tr(false); // disable auto transmit + } +} + +bool +wbx_base::_lock_detect() +{ + /* + * @returns: the value of the VCO/PLL lock detect bit. + * @rtype: 0 or 1 + */ + + if(_rx_read_io() & PLL_LOCK_DETECT) { + return true; + } + else { // Give it a second chance + if(_rx_read_io() & PLL_LOCK_DETECT) { + return true; + } + else { + return false; + } + } +} + +bool +wbx_base::_tx_write_oe(int value, int mask) +{ + int reg = (d_which == 0 ? FR_OE_0 : FR_OE_2); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_write_oe(int value, int mask) +{ + int reg = (d_which == 0 ? FR_OE_1 : FR_OE_3); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_tx_write_io(int value, int mask) +{ + int reg = (d_which == 0 ? FR_IO_0 : FR_IO_2); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_write_io(int value, int mask) +{ + int reg = (d_which == 0 ? FR_IO_1 : FR_IO_3); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_read_io() +{ + int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); + int t = d_usrp->_read_fpga_reg(reg); + return (t >> 16) & 0xffff; +} + +bool +wbx_base::_tx_read_io() +{ + int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); + int t = d_usrp->_read_fpga_reg(reg); + return (t & 0xffff); +} + +bool +wbx_base::_compute_regs(double freq) +{ + /* + * Determine values of registers, along with actual freq. + * + * @param freq: target frequency in Hz + * @type freq: double + * @returns: (R, N, func, init, actual_freq) + * @rtype: tuple(int, int, int, int, double) + * + * Override this in derived classes. + */ + throw std::runtime_error("_compute_regs called from base class\n"); +} + +double +wbx_base::_refclk_freq() +{ + return (double)(d_usrp->fpga_master_clock_freq())/_refclk_divisor(); +} + +int +wbx_base::_refclk_divisor() +{ + /* + * Return value to stick in REFCLK_DIVISOR register + */ + return 1; +} + +struct freq_result_t +wbx_base::set_freq(double freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + throw std::runtime_error("set_freq called from base class\n"); +} + +float +wbx_base::gain_min() +{ + throw std::runtime_error("gain_min called from base class\n"); +} + +float +wbx_base::gain_max() +{ + throw std::runtime_error("gain_max called from base class\n"); +} + +float +wbx_base::gain_db_per_step() +{ + throw std::runtime_error("gain_db_per_step called from base class\n"); +} + +bool +wbx_base::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + throw std::runtime_error("set_gain called from base class\n"); +} + +bool +wbx_base::_set_pga(float pga_gain) +{ + bool ok; + if(d_which == 0) { + ok = d_usrp->set_pga(0, pga_gain); + ok |= d_usrp->set_pga(1, pga_gain); + } + else { + ok = d_usrp->set_pga(2, pga_gain); + ok |= d_usrp->set_pga(3, pga_gain); + } + return ok; +} + +bool +wbx_base::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + return true; +} + + +/****************************************************************************/ + + +wbx_base_tx::wbx_base_tx(usrp_basic_sptr usrp, int which) + : wbx_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.sink_c + * @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. + */ + + // power up the transmit side, NO -- but set antenna to receive + d_usrp->write_io(d_which, (TX_POWER), (TX_POWER|RX_TXN)); + d_lo_offset = 0e6; + + // Gain is not set by the PGA, but the PGA must be set at max gain in the TX + _set_pga(d_usrp->pga_max()); +} + +wbx_base_tx::~wbx_base_tx() +{ + // Power down and leave the T/R switch in the R position + d_usrp->write_io(d_which, (RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); +} + +void +wbx_base_tx::set_auto_tr(bool on) +{ + if(on) { + set_atr_mask (RX_TXN); + set_atr_txval(0); + set_atr_rxval(RX_TXN); + } + else { + set_atr_mask (0); + set_atr_txval(0); + set_atr_rxval(0); + } +} + +void +wbx_base_tx::set_enable(bool on) +{ + /* + * Enable transmitter if on is True + */ + + int mask = RX_TXN|TX_ENB_MIX|TX_ENB_VGA; + //printf("HERE!!!!\n"); + if(on) { + d_usrp->write_io(d_which, TX_ENB_MIX|TX_ENB_VGA, mask); + } + else { + d_usrp->write_io(d_which, RX_TXN, mask); + } +} + +void +wbx_base_tx::set_lo_offset(double offset) +{ + /* + * Set amount by which LO is offset from requested tuning frequency. + * + * @param offset: offset in Hz + */ + + d_lo_offset = offset; +} + +double +wbx_base_tx::lo_offset() +{ + /* + * Get amount by which LO is offset from requested tuning frequency. + * + * @returns Offset in Hz + */ + + return d_lo_offset; +} + + +/****************************************************************************/ + + +wbx_base_rx::wbx_base_rx(usrp_basic_sptr usrp, int which) + : wbx_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.source_c + * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. + */ + + // set up for RX on TX/RX port + select_rx_antenna("TX/RX"); + + bypass_adc_buffers(true); + + d_lo_offset = 0.0; +} + +wbx_base_rx::~wbx_base_rx() +{ + // Power down + d_usrp->write_io(d_which, 0, (RXENABLE)); +} + +void +wbx_base_rx::set_auto_tr(bool on) +{ + if(on) { + // FIXME: where does ENABLE come from? + //set_atr_mask (ENABLE); + set_atr_txval( 0); + //set_atr_rxval(ENABLE); + } + else { + set_atr_mask (0); + set_atr_txval(0); + set_atr_rxval(0); + } +} + +void +wbx_base_rx::select_rx_antenna(int which_antenna) +{ + /* + * Specify which antenna port to use for reception. + * @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == 0) { + d_usrp->write_io(d_which, 0, RX2_RX1N); + } + else if(which_antenna == 1) { + d_usrp->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } +} + +void +wbx_base_rx::select_rx_antenna(const std::string &which_antenna) +{ + if(which_antenna == "TX/RX") { + select_rx_antenna(0); + } + else if(which_antenna == "RX2") { + select_rx_antenna(1); + } + else { + throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } +} + +bool +wbx_base_rx::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + + float pga_gain, agc_gain; + float maxgain = gain_max() - d_usrp->pga_max(); + float mingain = gain_min(); + if(gain > maxgain) { + pga_gain = gain-maxgain; + assert(pga_gain <= d_usrp->pga_max()); + agc_gain = maxgain; + } + else { + pga_gain = 0; + agc_gain = gain; + } + + float V_maxgain = .2; + float V_mingain = 1.2; + float V_fullscale = 3.3; + float dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + + return d_usrp->write_aux_dac(d_which, 0, (int)(dac_value)) && _set_pga((int)(pga_gain)); +} + +void +wbx_base_rx::set_lo_offset(double offset) +{ + /* + * Set amount by which LO is offset from requested tuning frequency. + * + * @param offset: offset in Hz + */ + d_lo_offset = offset; +} + +double +wbx_base_rx::lo_offset() +{ + /* + * Get amount by which LO is offset from requested tuning frequency. + * + * @returns Offset in Hz + */ + return d_lo_offset; +} + +bool +wbx_base_rx::i_and_q_swapped() +{ + /* + * Return True if this is a quadrature device and ADC 0 is Q. + */ + return false; +} + + +/****************************************************************************/ + +_ADF410X_common::_ADF410X_common() +{ + // R-Register Common Values + d_R_RSV = 0; // bits 23,22,21 + d_LDP = 1; // bit 20 Lock detect in 5 cycles + d_TEST = 0; // bit 19,18 Normal + d_ABP = 0; // bit 17,16 2.9ns + + // N-Register Common Values + d_N_RSV = 0; // 23,22 + d_CP_GAIN = 0; // 21 + + // Function Register Common Values + d_P = 0; // bits 23,22 0 = 8/9, 1 = 16/17, 2 = 32/33, 3 = 64/65 + d_PD2 = 0; // bit 21 Normal operation + d_CP2 = 4; // bits 20,19,18 CP Gain = 5mA + d_CP1 = 4; // bits 17,16,15 CP Gain = 5mA + d_TC = 0; // bits 14-11 PFD Timeout + d_FL = 0; // bit 10,9 Fastlock Disabled + d_CP3S = 0; // bit 8 CP Enabled + d_PDP = 0; // bit 7 Phase detector polarity, Positive=1 + d_MUXOUT = 1; // bits 6:4 Digital Lock Detect + d_PD1 = 0; // bit 3 Normal operation + d_CR = 0; // bit 2 Normal operation +} + +_ADF410X_common::~_ADF410X_common() +{ +} + +bool +_ADF410X_common::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + /* + * Determine values of R, control, and N registers, along with actual freq. + * + * @param freq: target frequency in Hz + * @type freq: double + * @returns: (R, N, control, actual_freq) + * @rtype: tuple(int, int, int, double) + */ + + // Band-specific N-Register Values + double phdet_freq = _refclk_freq()/d_R_DIV; + printf("phdet_freq = %f\n", phdet_freq); + + double desired_n = round(freq*d_freq_mult/phdet_freq); + printf("desired_n %f\n", desired_n); + + double actual_freq = desired_n * phdet_freq; + printf("actual freq %f\n", actual_freq); + + double B = floor(desired_n/_prescaler()); + double A = desired_n - _prescaler()*B; + printf("A %f B %f\n", A, B); + + d_B_DIV = int(B); // bits 20:8; + d_A_DIV = int(A); // bit 6:2; + + if(d_B_DIV < d_A_DIV) { + retR = 0; + retN = 0; + retcontrol = 0; + retfreq = 0; + return false; + } + + retR = (d_R_RSV<<21) | (d_LDP<<20) | (d_TEST<<18) | + (d_ABP<<16) | (d_R_DIV<<2); + + retN = (d_N_RSV<<22) | (d_CP_GAIN<<21) | (d_B_DIV<<8) | (d_A_DIV<<2); + + retcontrol = (d_P<<22) | (d_PD2<<21) | (d_CP2<<18) | (d_CP1<<15) | + (d_TC<<11) | (d_FL<<9) | (d_CP3S<<8) | (d_PDP<<7) | + (d_MUXOUT<<4) | (d_PD1<<3) | (d_CR<<2); + + retfreq = actual_freq/d_freq_mult; + + return true; +} + +void +_ADF410X_common::_write_all(int R, int N, int control) +{ + /* + * Write all PLL registers: + * R counter latch, + * N counter latch, + * Function latch, + * Initialization latch + * + * Adds 10ms delay between writing control and N if this is first call. + * This is the required power-up sequence. + * + * @param R: 24-bit R counter latch + * @type R: int + * @param N: 24-bit N counter latch + * @type N: int + * @param control: 24-bit control latch + * @type control: int + */ + static bool first = true; + + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + + _write_R(R); + _write_func(control); + _write_init(control); + if(first) { + //time.sleep(0.010); + nanosleep(&t, NULL); + first = false; + } + _write_N(N); +} + +void +_ADF410X_common::_write_R(int R) +{ + _write_it((R & ~0x3) | 0); +} + +void +_ADF410X_common::_write_N(int N) +{ + _write_it((N & ~0x3) | 1); +} + +void +_ADF410X_common::_write_func(int func) +{ + _write_it((func & ~0x3) | 2); +} + +void +_ADF410X_common::_write_init(int init) +{ + _write_it((init & ~0x3) | 3); +} + +void +_ADF410X_common::_write_it(int v) +{ + char c[3]; + c[0] = (char)((v >> 16) & 0xff); + c[1] = (char)((v >> 8) & 0xff); + c[2] = (char)((v & 0xff)); + std::string s(c, 3); + //d_usrp->_write_spi(0, d_spi_enable, d_spi_format, s); + usrp()->_write_spi(0, d_spi_enable, d_spi_format, s); +} + +int +_ADF410X_common::_prescaler() +{ + if(d_P == 0) { + return 8; + } + else if(d_P == 1) { + return 16; + } + else if(d_P == 2) { + return 32; + } + else if(d_P == 3) { + return 64; + } + else { + throw std::invalid_argument("Prescaler out of range\n"); + } +} + +double +_ADF410X_common::_refclk_freq() +{ + throw std::runtime_error("_refclk_freq called from base class."); +} + +bool +_ADF410X_common::_rx_write_io(int value, int mask) +{ + throw std::runtime_error("_rx_write_io called from base class."); +} + +bool +_ADF410X_common::_lock_detect() +{ + throw std::runtime_error("_lock_detect called from base class."); +} + +usrp_basic* +_ADF410X_common::usrp() +{ + throw std::runtime_error("usrp() called from base class."); +} + + +/****************************************************************************/ + + +_lo_common::_lo_common() + : _ADF410X_common() +{ + // Band-specific R-Register Values + d_R_DIV = 4; // bits 15:2 + + // Band-specific C-Register values + d_P = 0; // bits 23,22 0 = Div by 8/9 + d_CP2 = 4; // bits 19:17 + d_CP1 = 4; // bits 16:14 + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 0; // bit 22 + d_CPGAIN = 0; // bit 21 + d_freq_mult = 1; + + d_div = 1; + d_aux_div = 2; + d_main_div = 0; +} + +_lo_common::~_lo_common() +{ +} + +double +_lo_common::freq_min() +{ + return 50e6; +} + +double +_lo_common::freq_max() +{ + return 1000e6; +} + +void +_lo_common::set_divider(int main_or_aux, int divisor) +{ + if(main_or_aux == 0) { + if((divisor != 1) || (divisor != 2) || (divisor != 4) || (divisor != 8)) { + throw std::invalid_argument("Main Divider Must be 1, 2, 4, or 8\n"); + } + d_main_div = (int)(log10(divisor)/log10(2.0)); + } + else if(main_or_aux == 1) { + if((divisor != 2) || (divisor != 4) || (divisor != 8) || (divisor != 16)) { + throw std::invalid_argument("Aux Divider Must be 2, 4, 8 or 16\n"); + } + d_main_div = (int)(log10(divisor/2.0)/log10(2.0)); + } + else { + throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); + } + + int vala = d_main_div*SELA0; + int valb = d_aux_div*SELB0; + int mask = SELA0|SELA1|SELB0|SELB1; + + _rx_write_io((vala | valb), mask); +} + +void +_lo_common::set_divider(const std::string &main_or_aux, int divisor) +{ + if(main_or_aux == "main") { + set_divider(0, divisor); + } + else if(main_or_aux == "aux") { + set_divider(1, divisor); + } + else { + throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); + } +} + +struct freq_result_t +_lo_common::set_freq(double freq) +{ + struct freq_result_t ret; + + if(freq < 20e6 or freq > 1200e6) { + throw std::invalid_argument("Requested frequency out of range\n"); + } + + int div = 1; + double lo_freq = freq * 2; + while((lo_freq < 1e9) && (div < 8)) { + div = div * 2; + lo_freq = lo_freq * 2; + } + + printf("For RF freq of %f, we set DIV=%d and LO Freq=%f\n", freq, div, lo_freq); + + set_divider("main", div); + set_divider("aux", div*2); + + int R, N, control; + double actual_freq; + _compute_regs(lo_freq, R, N, control, actual_freq); + + printf("R %d N %d control %d actual freq %f\n", R, N, control, actual_freq); + if(R==0) { + ret.ok = false; + ret.baseband_freq = 0.0; + return ret; + } + _write_all(R, N, control); + + ret.ok = _lock_detect(); + ret.baseband_freq = actual_freq/div/2; + return ret; +} + + +/****************************************************************************/ + + +db_wbx_lo_tx::db_wbx_lo_tx(usrp_basic_sptr usrp, int which) + : _lo_common(), + wbx_base_tx(usrp, which) +{ +} + +db_wbx_lo_tx::~db_wbx_lo_tx() +{ +} + +float +db_wbx_lo_tx::gain_min() +{ + return -56.0; +} + +float +db_wbx_lo_tx::gain_max() +{ + return 0.0; +} + +float +db_wbx_lo_tx::gain_db_per_step() +{ + return 0.1; +} + +bool +db_wbx_lo_tx::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + + float txvga_gain; + float maxgain = gain_max(); + float mingain = gain_min(); + if(gain > maxgain) { + txvga_gain = maxgain; + } + else if(gain < mingain) { + txvga_gain = mingain; + } + else { + txvga_gain = gain; + } + + float V_maxgain = 1.4; + float V_mingain = 0.1; + float V_fullscale = 3.3; + float dac_value = ((txvga_gain-mingain)*(V_maxgain-V_mingain)/ + (maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + printf("DAC value %f\n", dac_value); + + return d_usrp->write_aux_dac(d_which, 1, (int)(dac_value)); +} + +double +db_wbx_lo_tx::_refclk_freq() +{ + return wbx_base::_refclk_freq(); +} + +bool +db_wbx_lo_tx::_rx_write_io(int value, int mask) +{ + return wbx_base::_rx_write_io(value, mask); +} + +bool +db_wbx_lo_tx::_lock_detect() +{ + return wbx_base::_lock_detect(); +} + +usrp_basic* +db_wbx_lo_tx::usrp() +{ + return d_usrp; +} + + +/****************************************************************************/ + + +db_wbx_lo_rx::db_wbx_lo_rx(usrp_basic_sptr usrp, int which) + : _lo_common(), + wbx_base_rx(usrp, which) +{ +} + +db_wbx_lo_rx::~db_wbx_lo_rx() +{ +} + +float +db_wbx_lo_rx::gain_min() +{ + return d_usrp->pga_min(); +} + +float +db_wbx_lo_rx::gain_max() +{ + return d_usrp->pga_max() + 45; +} + +float +db_wbx_lo_rx::gain_db_per_step() +{ + return 0.05; +} + +double +db_wbx_lo_rx::_refclk_freq() +{ + return wbx_base::_refclk_freq(); +} + +bool +db_wbx_lo_rx::_rx_write_io(int value, int mask) +{ + return wbx_base::_rx_write_io(value, mask); +} + +bool +db_wbx_lo_rx::_lock_detect() +{ + return wbx_base::_lock_detect(); +} + +usrp_basic* +db_wbx_lo_rx::usrp() +{ + return d_usrp; +}