Clean build
authorJason Abele <jason@jasonabeleconsulting.com>
Fri, 21 Aug 2009 17:08:44 +0000 (10:08 -0700)
committerJohnathan Corgan <jcorgan@corganenterprises.com>
Mon, 5 Oct 2009 21:37:13 +0000 (14:37 -0700)
usrp/host/include/usrp/Makefile.am
usrp/host/include/usrp/db_wbxng.h
usrp/host/include/usrp/db_wbxng_adf4350.h [new file with mode: 0644]
usrp/host/include/usrp/db_wbxng_adf4350_regs.h [new file with mode: 0644]
usrp/host/lib/Makefile.am
usrp/host/lib/db_wbxng.cc
usrp/host/lib/db_wbxng_adf4350.cc [new file with mode: 0644]
usrp/host/lib/db_wbxng_adf4350_regs.cc [new file with mode: 0644]

index 83e86da7ed9b5bd107c3419f3faadb36ae3056b2..7c868e061564f16e5320df572b8f30c77a391878 100644 (file)
@@ -33,6 +33,8 @@ usrpinclude_HEADERS = \
        db_flexrf_mimo.h \
        db_tv_rx.h \
        db_tv_rx_mimo.h \
+       db_wbxng_adf4350.h \
+       db_wbxng_adf4350_regs.h \
        db_wbxng.h \
        db_xcvr2450.h \
        libusb_types.h \
index b255cf91c5a6ff85647a18d0ecb6bee3c4369f39..1ded1b5dc0aa66a6fde07c6f19ddd70b1d2e8271 100644 (file)
 #define DB_WBXNG_H
 
 #include <usrp/db_base.h>
-#include <boost/shared_ptr.hpp>
+#include <cmath>
 
-class wbxng;
-typedef boost::shared_ptr<wbxng> wbxng_sptr;
+//debug_using_gui = true                // Must be set to True or False
+#define debug_using_gui false           // Must be set to True or False
 
+class adf4350;
 
-/******************************************************************************/
-
-
-class db_wbxng_base: public db_base
+class wbxng_base : public db_base
 {
-  /*
-   * Abstract base class for all wbxng boards.
-   * 
-   * Derive board specific subclasses from db_wbxng_base_{tx,rx}
-   */
 public:
-  db_wbxng_base(usrp_basic_sptr usrp, int which);
-  ~db_wbxng_base();
-  struct freq_result_t set_freq(double target_freq);
-  bool is_quadrature();
+  wbxng_base(usrp_basic_sptr usrp, int which, int _power_on=0);
+  ~wbxng_base();
+
+  struct freq_result_t set_freq(double freq);
+
+  bool  is_quadrature();
   double freq_min();
   double freq_max();
 
 protected:
-  wbxng_sptr d_wbxng;
-  void shutdown_common();
+  void _write_all(int R, int control, int N);
+  void _write_control(int control);
+  void _write_R(int R);
+  void _write_N(int N);
+  void _write_it(int v);
+  bool _lock_detect();
+
+  virtual bool _compute_regs(double freq, int &retR, int &retcontrol, 
+                            int &retN, double &retfreq);
+  int  _compute_control_reg();
+  int _refclk_divisor();
+  double _refclk_freq();
+
+  bool _set_pga(float pga_gain);
+
+  int power_on() { return d_power_on; }
+  int power_off() { return 0; }
+
+  bool d_first;
+  int  d_spi_format;
+  int  d_spi_enable;
+  int  d_power_on;
+  int  d_PD;
+
+  adf4350 *d_common;
 };
 
+// ----------------------------------------------------------------
 
-/******************************************************************************/
-
-
-class db_wbxng_tx : public db_wbxng_base
+class wbxng_base_tx : public wbxng_base
 {
 protected:
   void shutdown();
 
 public:
-  db_wbxng_tx(usrp_basic_sptr usrp, int which);
-  ~db_wbxng_tx();
+  wbxng_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0);
+  ~wbxng_base_tx();
 
+  //*** TODO *** Fix comment
+  // All RFX tx d'boards have fixed gain
   float gain_min();
   float gain_max();
   float gain_db_per_step();
-  bool  set_gain(float gain);
-  bool  i_and_q_swapped();
+
+  bool set_auto_tr(bool on);
+  bool set_enable(bool on);
+  bool set_gain(float gain);
 };
 
-class db_wbxng_rx : public db_wbxng_base
+class wbxng_base_rx : public wbxng_base
 {
 protected:
   void shutdown();
 
+public:
+  wbxng_base_rx(usrp_basic_sptr usrp, int which, int _power_on=0);
+  ~wbxng_base_rx();
+    
+  bool set_auto_tr(bool on);
+  bool select_rx_antenna(int which_antenna);
+  bool select_rx_antenna(const std::string &which_antenna);
+  bool set_gain(float gain);
+
+};
+
+// ----------------------------------------------------------------
+
+class db_wbxng_tx : public wbxng_base_tx
+{
+ public:
+  db_wbxng_tx(usrp_basic_sptr usrp, int which);
+  ~db_wbxng_tx();
+
+  // Wrapper calls to d_common functions
+  bool _compute_regs(double freq, int &retR, int &retcontrol,
+                    int &retN, double &retfreq);
+};
+
+class db_wbxng_rx : public wbxng_base_rx
+{
 public:
   db_wbxng_rx(usrp_basic_sptr usrp, int which);
   ~db_wbxng_rx();
-
+  
   float gain_min();
   float gain_max();
   float gain_db_per_step();
-  bool  set_gain(float gain);
-};
+  bool i_and_q_swapped();
 
+  bool _compute_regs(double freq, int &retR, int &retcontrol,
+                    int &retN, double &retfreq);
+};
 
 
 #endif
diff --git a/usrp/host/include/usrp/db_wbxng_adf4350.h b/usrp/host/include/usrp/db_wbxng_adf4350.h
new file mode 100644 (file)
index 0000000..a5ebe64
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Ettus Research LLC
+ */
+
+#ifndef ADF4350_H
+#define ADF4350_H
+
+#include <usrp/db_wbxng_adf4350_regs.h>
+#include <usrp/db_base.h>
+#include <stdint.h>
+
+typedef uint32_t freq_t;
+class adf4350_regs;
+
+class adf4350
+{
+public:
+    adf4350(usrp_basic_sptr _usrp, int _which, int _spi_enable);
+    ~adf4350();
+    void _update();
+    bool _get_locked();
+    void _enable(bool enable);
+    void _write(uint8_t addr, uint32_t data);
+    bool _set_freq(freq_t freq);
+    freq_t _get_freq();
+    freq_t _get_max_freq();
+    freq_t _get_min_freq();
+
+protected:
+    usrp_basic_sptr d_usrp;
+    int d_which;
+    int d_spi_enable;
+    int d_spi_format;
+    adf4350_regs *d_regs;
+};
+
+#endif /* ADF4350_H */
diff --git a/usrp/host/include/usrp/db_wbxng_adf4350_regs.h b/usrp/host/include/usrp/db_wbxng_adf4350_regs.h
new file mode 100644 (file)
index 0000000..ec78a9f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2009 Ettus Research LLC
+ */
+
+#ifndef ADF4350_REGS_H
+#define ADF4350_REGS_H
+
+#include <usrp/db_wbxng_adf4350.h>
+#include <usrp/db_base.h>
+#include <stdint.h>
+
+class adf4350;
+
+class adf4350_regs
+{
+public:
+    adf4350_regs(adf4350* _adf4350);
+    ~adf4350_regs();
+
+    adf4350* d_adf4350;
+
+    uint32_t _reg_shift(uint32_t data, uint32_t shift);
+    void _load_register(uint8_t addr);
+
+    /* reg 0 */
+    uint16_t _int;
+    uint16_t _frac;
+    /* reg 1 */
+    static uint8_t _prescaler;
+    static uint16_t _phase;
+    uint16_t _mod;
+    /* reg 2 */
+    static uint8_t _low_noise_and_low_spur_modes;
+    static uint8_t _muxout;
+    static uint8_t _reference_doubler;
+    static uint8_t _rdiv2;
+    uint16_t _10_bit_r_counter;
+    static uint8_t _double_buff;
+    static uint8_t _charge_pump_setting;
+    static uint8_t _ldf;
+    static uint8_t _ldp;
+    static uint8_t _pd_polarity;
+    static uint8_t _power_down;
+    static uint8_t _cp_three_state;
+    static uint8_t _counter_reset;
+    /* reg 3 */
+    static uint8_t _csr;
+    static uint8_t _clk_div_mode;
+    static uint16_t _12_bit_clock_divider_value;
+    /* reg 4 */
+    static uint8_t _feedback_select;
+    uint8_t _divider_select;
+    uint8_t _8_bit_band_select_clock_divider_value;
+    static uint8_t _vco_power_down;
+    static uint8_t _mtld;
+    static uint8_t _aux_output_select;
+    static uint8_t _aux_output_enable;
+    static uint8_t _aux_output_power;
+    static uint8_t _rf_output_enable;
+    static uint8_t _output_power;
+    /* reg 5 */
+    static uint8_t _ld_pin_mode;
+};
+
+#endif /* ADF4350_REGS_H */
index 4b889993b753ba14b49f27583a1dbbaa7edd0118..13f25d69be1b03da3c79a75a1e86f6316865bb5a 100644 (file)
@@ -122,6 +122,8 @@ libusrp_la_common_SOURCES =                 \
        usrp_local_sighandler.cc        \
        usrp_prims_common.cc            \
        usrp_standard.cc                \
+       db_wbxng_adf4350.cc                     \
+       db_wbxng_adf4350_regs.cc                        \
        db_boards.cc                    \
        db_base.cc                      \
        db_basic.cc                     \
index 53ec27afcad9239ce7a7fdf5402d10d2d69d8b13..e911c9d03459463bef58862930c596662e1aa082 100644 (file)
@@ -1,5 +1,5 @@
 //
-// Copyright 2008,2009 Free Software Foundation, Inc.
+// Copyright 2008 Free Software Foundation, Inc.
 // 
 // This file is part of GNU Radio
 // 
 // Boston, MA 02110-1301, USA.
 
 #include <usrp/db_wbxng.h>
+#include <usrp/db_wbxng_adf4350.h>
 #include <db_base_impl.h>
-#include <cmath>
-#include <boost/thread.hpp>
-#include <boost/weak_ptr.hpp>
-#include <cstdio>
-
-#if 0
-#define LO_OFFSET 4.25e6
-#else
-#define LO_OFFSET 0
-#define NO_LO_OFFSET
-#endif
-
-
-/* ------------------------------------------------------------------------
- *  **** TODO ****
- *    Fix the comment below to reflect WBX NG
- */
-
-/* ------------------------------------------------------------------------
- *  A few comments about the XCVR2450:
- *
- * It is half-duplex.  I.e., transmit and receive are mutually exclusive.
- * There is a single LO for both the Tx and Rx sides.
- * For our purposes the board is always either receiving or transmitting.
- *
- * Each board is uniquely identified by the *USRP hardware* instance and side
- * This dictionary holds a weak reference to existing board controller so it
- * can be created or retrieved as needed.
- */
-
-
-
-// TX IO Pins
-#define HB_PA_OFF      (1 << 15)    // 5GHz PA, 1 = off, 0 = on
-#define LB_PA_OFF      (1 << 14)    // 2.4GHz PA, 1 = off, 0 = on
-#define ANTSEL_TX1_RX2 (1 << 13)    // 1 = Ant 1 to TX, Ant 2 to RX
-#define ANTSEL_TX2_RX1 (1 << 12)    // 1 = Ant 2 to TX, Ant 1 to RX
-#define TX_EN          (1 << 11)    // 1 = TX on, 0 = TX off
-#define AD9515DIV      (1 << 4)     // 1 = Div  by 3, 0 = Div by 2
-
-#define TX_OE_MASK HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN|AD9515DIV
-#define TX_SAFE_IO HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|AD9515DIV
-
-// RX IO Pins
-#define LOCKDET (1 << 15)           // This is an INPUT!!!
-#define EN      (1 << 14)
-#define RX_EN   (1 << 13)           // 1 = RX on, 0 = RX off
-#define RX_HP   (1 << 12)
-#define RX_OE_MASK EN|RX_EN|RX_HP
-#define RX_SAFE_IO EN
-
-struct wbxng_key {
-  std::string serial_no;
-  int which;
-
-  bool operator==(const wbxng_key &x){
-    return x.serial_no ==serial_no && x.which == which;
-  }
-};
-
-class wbxng
-{
-private:
-  usrp_basic *d_raw_usrp;
-  int d_which;
-
-  bool d_is_shutdown;
-  int d_spi_format, d_spi_enable;
-  
-  int d_mimo, d_int_div, d_frac_div, d_highband, d_five_gig;
-  int d_cp_current, d_ref_div, d_rssi_hbw;
-  int d_txlpf_bw, d_rxlpf_bw, d_rxlpf_fine, d_rxvga_ser;
-  int d_rssi_range, d_rssi_mode, d_rssi_mux;
-  int d_rx_hp_pin, d_rx_hpf, d_rx_ant;
-  int d_tx_ant, d_txvga_ser, d_tx_driver_lin;
-  int d_tx_vga_lin, d_tx_upconv_lin, d_tx_bb_gain;
-  int d_pabias_delay, d_pabias, rx_rf_gain, rx_bb_gain, d_txgain;
-  int d_rx_rf_gain, d_rx_bb_gain;
-
-  int d_reg_standby, d_reg_int_divider, d_reg_frac_divider, d_reg_bandselpll;
-  int d_reg_cal, dsend_reg, d_reg_lpf, d_reg_rxrssi_ctrl, d_reg_txlin_gain;
-  int d_reg_pabias, d_reg_rxgain, d_reg_txgain;
-
-  int d_ad9515_div;
-
-  void _set_rfagc(float gain);
-  void _set_ifagc(float gain);
-  void _set_pga(float pga_gain);
-
-public:
-  usrp_basic *usrp(){
-    return d_raw_usrp;
-  }
-
-  wbxng(usrp_basic_sptr usrp, int which);
-  ~wbxng();
-  void shutdown();
-
-  void set_reg_standby();
-  
-  // Integer-Divider Ratio (3)
-  void set_reg_int_divider();
-  
-  // Fractional-Divider Ratio (4)
-  void set_reg_frac_divider();
-  
-  // Band Select and PLL (5)
-  void set_reg_bandselpll();
-  
-  // Calibration (6)
-  void set_reg_cal();
-
-  // Lowpass Filter (7)
-  void set_reg_lpf();
-  
-  // Rx Control/RSSI (8)
-  void set_reg_rxrssi_ctrl();
-  
-  // Tx Linearity/Baseband Gain (9)
-  void set_reg_txlin_gain();
-  
-  // PA Bias DAC (10)
-  void set_reg_pabias();
-  
-  // Rx Gain (11)
-  void set_reg_rxgain();
-  
-  // Tx Gain (12)
-  void set_reg_txgain();
-  
-  // Send register write to SPI
-  void send_reg(int v);
-
-  void set_gpio();
-  bool lock_detect();
-  bool set_rx_gain(float gain);
-  bool set_tx_gain(float gain);
-
-  struct freq_result_t set_freq(double target_freq);
-};
-
-
-/*****************************************************************************/
 
-
-wbxng::wbxng(usrp_basic_sptr _usrp, int which)
-  : d_raw_usrp(_usrp.get()), d_which(which), d_is_shutdown(false)
+// d'board i/o pin defs
+// Tx and Rx have shared defs, but different i/o regs
+#define ENABLE_5        (1 << 7)         // enables 5.0V power supply
+#define ENABLE_33       (1 << 6)         // enables 3.3V supply
+#define RX_TXN          (1 << 5)         // Tx only: T/R antenna switch for TX/RX port
+#define RX2_RX1N        (1 << 5)         // Rx only: antenna switch between RX2 and TX/RX port
+#define BBAMP_EN        (1 << 4)
+#define PLL_CE          (1 << 3)
+#define PLL_PDBRF       (1 << 2)
+#define PLL_MUXOUT      (1 << 1)
+#define PLL_LOCK_DETECT (1 << 0)
+
+wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
+  : db_base(_usrp, which), d_power_on(_power_on)
 {
-  // Handler for WBX NG daughterboards.
-  // 
-  // @param usrp: instance of usrp.source_c
-  // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
+  /*
+    @param usrp: instance of usrp.source_c
+    @param which: which side: 0 or 1 corresponding to side A or B respectively
+    @type which: int
+  */
 
-  // Use MSB with no header
+  d_first = true;
   d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
 
-  if(which == 0) {
-    d_spi_enable = SPI_ENABLE_RX_A;
-  }
-  else {
-    d_spi_enable = SPI_ENABLE_RX_B;
-  }
-
-  // Sane defaults
-  d_mimo = 1;          // 0 = OFF, 1 = ON
-  d_int_div = 192;     // 128 = min, 255 = max
-  d_frac_div = 0;      // 0 = min, 65535 = max
-  d_highband = 0;      // 0 = freq <= 5.4e9, 1 = freq > 5.4e9
-  d_five_gig = 0;      // 0 = freq <= 3.e9, 1 = freq > 3e9
-  d_cp_current = 1;    // 0 = 2mA, 1 = 4mA
-  d_ref_div = 1;       // 1 to 7
-  d_rssi_hbw = 0;      // 0 = 2 MHz, 1 = 6 MHz
-  d_txlpf_bw = 1;      // 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz
-  d_rxlpf_bw = 1;      // 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz
-  d_rxlpf_fine = 2;    // 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110%
-  d_rxvga_ser = 1;     // 0 = RXVGA controlled by B7:1, 1=controlled serially
-  d_rssi_range = 1;    // 0 = low range (datasheet typo), 1=high range (0.5V - 2.0V) 
-  d_rssi_mode = 1;     // 0 = enable follows RXHP, 1 = enabled
-  d_rssi_mux = 0;      // 0 = RSSI, 1 = TEMP
-  d_rx_hp_pin = 0;     // 0 = Fc set by rx_hpf, 1 = 600 KHz
-  d_rx_hpf = 0;        // 0 = 100Hz, 1 = 30KHz
-  d_rx_ant = 0;        // 0 = Ant. #1, 1 = Ant. #2
-  d_tx_ant = 0;        // 0 = Ant. #1, 1 = Ant. #2
-  d_txvga_ser = 1;     // 0 = TXVGA controlled by B6:1, 1=controlled serially
-  d_tx_driver_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
-  d_tx_vga_lin = 2;    // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
-  d_tx_upconv_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
-  d_tx_bb_gain = 3;    // 0=maxgain-5dB, 1=max-3dB, 2=max-1.5dB, 3=max
-  d_pabias_delay = 15; // 0 = 0, 15 = 7uS
-  d_pabias = 0;        // 0 = 0 uA, 63 = 315uA
-  d_rx_rf_gain = 0;    // 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB
-  d_rx_bb_gain = 16;   // 0 = min, 31 = max (0 - 62 dB)
-
-  d_txgain = 63;       // 0 = min, 63 = max
+  usrp()->_write_oe(d_which, 0, 0xffff);   // turn off all outputs
+  _enable_refclk(false);                // disable refclk
 
-  /*
-  // Initialize GPIO and ATR  
-  usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK);
-  usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff);
-  usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO);
-  usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO);
-  usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK);
-
-  usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK);
-  usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff);
-  usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO);
-  usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO);
-  usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK);
-
-  // Initialize chipset
-  // TODO: perform reset sequence to ensure power up defaults
-  set_reg_standby();
-  set_reg_bandselpll();
-  set_reg_cal();
-  set_reg_lpf();
-  set_reg_rxrssi_ctrl();
-  set_reg_txlin_gain();
-  set_reg_pabias();
-  set_reg_rxgain();
-  set_reg_txgain();
-  //FIXME: set_freq(2.45e9);
-  */
+  set_auto_tr(false);
 }
 
-wbxng::~wbxng()
+wbxng_base::~wbxng_base()
 {
-  //printf("wbxng::destructor\n");
-  shutdown();
+  delete d_common;
 }
 
 void
-wbxng::shutdown()
+wbxng_base::_write_all(int R, int control, int N)
 {
-  if (!d_is_shutdown){
-    d_is_shutdown = true;
-    /*
-    usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO);
-    usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO);
-    usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO);
-    usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO);
-    */
+  /*
+    Write R counter latch, control latch and N counter latch to VCO.
+    
+    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 control: 24-bit control latch
+    @type control: int
+    @param N: 24-bit N counter latch
+    @type N: int
+  */
+  timespec t;
+  t.tv_sec = 0;
+  t.tv_nsec = 10000000;
+
+  /*
+  _write_R(R);
+  _write_control(control);
+  if(d_first) {
+    //time.sleep(0.010);
+    nanosleep(&t, NULL);
+    d_first = false;
   }
+  _write_N(N);
+  */
 }
 
-
 void
-wbxng::set_reg_standby()
+wbxng_base::_write_control(int control)
 {
-  d_reg_standby = ((d_mimo<<17) | 
-                  (1<<16)      | 
-                  (1<<6)       | 
-                  (1<<5)       | 
-                  (1<<4)       | 2);
-  //send_reg(d_reg_standby);
+  //_write_it((control & ~0x3) | 0);
 }
 
 void
-wbxng::set_reg_int_divider()
+wbxng_base::_write_R(int R)
 {
-  d_reg_int_divider = (((d_frac_div & 0x03)<<16) | 
-                      (d_int_div<<4)            | 3);
-  //send_reg(d_reg_int_divider);
+  //_write_it((R & ~0x3) | 1);
 }
 
 void
-wbxng::set_reg_frac_divider()
-{
-  d_reg_frac_divider = ((d_frac_div & 0xfffc)<<2) | 4;
-  //send_reg(d_reg_frac_divider);
-}
-        
-void
-wbxng::set_reg_bandselpll()
-{
-  d_reg_bandselpll = ((d_mimo<<17)      |
-                     (1<<16)           |
-                     (1<<15)           |
-                     (0<<11)           |
-                     (d_highband<<10)  |
-                     (d_cp_current<<9) |
-                     (d_ref_div<<5)    |
-                     (d_five_gig<<4)   | 5);
-  //send_reg(d_reg_bandselpll);
-  d_reg_bandselpll = ((d_mimo<<17)      |
-                     (1<<16)           |
-                     (1<<15)           |
-                     (1<<11)           |
-                     (d_highband<<10)  |
-                     (d_cp_current<<9) |
-                     (d_ref_div<<5)    |
-                     (d_five_gig<<4)   | 5);
-  //send_reg(d_reg_bandselpll);
-}
-     
-void
-wbxng::set_reg_cal()
+wbxng_base::_write_N(int N)
 {
-  // FIXME do calibration
-  d_reg_cal = (1<<14)|6;
-  //send_reg(d_reg_cal);
+  //_write_it((N & ~0x3) | 2);
 }
 
 void
-wbxng::set_reg_lpf()
+wbxng_base::_write_it(int v)
 {
-  d_reg_lpf = (
-            (d_rssi_hbw<<15)  |
-            (d_txlpf_bw<<10)  |
-            (d_rxlpf_bw<<9)   |
-            (d_rxlpf_fine<<4) | 7);
-  //send_reg(d_reg_lpf);
+  char s[3];
+  s[0] = (char)((v >> 16) & 0xff);
+  s[1] = (char)((v >>  8) & 0xff);
+  s[2] = (char)(v & 0xff);
+  std::string str(s, 3);
+  //usrp()->_write_spi(0, d_spi_enable, d_spi_format, str);
 }
-
-void
-wbxng::set_reg_rxrssi_ctrl()
+        
+bool
+wbxng_base::_lock_detect()
 {
-  d_reg_rxrssi_ctrl = ((d_rxvga_ser<<16)  |
-                      (d_rssi_range<<15) |
-                      (d_rssi_mode<<14)  |
-                      (d_rssi_mux<<12)   |
-                      (1<<9)             |
-                      (d_rx_hpf<<6)      |
-                      (1<<4)             | 8);
-  //send_reg(d_reg_rxrssi_ctrl);
+  /*
+    @returns: the value of the VCO/PLL lock detect bit.
+    @rtype: 0 or 1
+  */
+  /*
+  if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
+    return true;
+  }
+  else {      // Give it a second chance
+    // FIXME: make portable sleep
+    timespec t;
+    t.tv_sec = 0;
+    t.tv_nsec = 100000000;
+    nanosleep(&t, NULL);
+    
+    if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+  */
+  throw std::runtime_error("_lock_detect called from wbxng_base\n");
 }
 
-void
-wbxng::set_reg_txlin_gain()
-{
-  d_reg_txlin_gain = ((d_txvga_ser<<14)     |
-                     (d_tx_driver_lin<<12) |
-                     (d_tx_vga_lin<<10)    |
-                     (d_tx_upconv_lin<<6)  |
-                     (d_tx_bb_gain<<4)     | 9);
-  //send_reg(d_reg_txlin_gain);
+/*
+bool
+wbxng_base::_compute_regs(double freq, int &retR, int &retcontrol,
+                          int &retN, double &retfreq)
+{
+  **COMMENT**
+    Determine values of R, control, and N registers, along with actual freq.
+    
+    @param freq: target frequency in Hz
+    @type freq: float
+    @returns: (R, control, N, actual_freq)
+    @rtype: tuple(int, int, int, float)
+    
+    Override this in derived classes.
+  **COMMENT**
+  
+  //raise NotImplementedError;
+  throw std::runtime_error("_compute_regs called from wbxng_base\n");
 }
+*/
 
-void
-wbxng::set_reg_pabias()
+int
+wbxng_base::_compute_control_reg()
 {
-  d_reg_pabias = (
-                 (d_pabias_delay<<10) |
-                 (d_pabias<<4)        | 10);
-  //send_reg(d_reg_pabias);
+  throw std::runtime_error("_compute_control_reg called from wbxng_base\n");
+  //return d_common->_compute_control_reg();
 }
 
-void
-wbxng::set_reg_rxgain()
+int
+wbxng_base::_refclk_divisor()
 {
-  d_reg_rxgain = (
-                 (d_rx_rf_gain<<9) |
-                 (d_rx_bb_gain<<4) | 11);
-  //send_reg(d_reg_rxgain);
+  throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
+  //return d_common->_refclk_divisor();
 }
 
-void
-wbxng::set_reg_txgain()
+double
+wbxng_base::_refclk_freq()
 {
-  d_reg_txgain = (d_txgain<<4) | 12;
-  //send_reg(d_reg_txgain);
-}
-
-void
-wbxng::send_reg(int v)
-{
-  // Send 24 bits, it keeps last 18 clocked in
-  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);
-  
-  //usrp()->_write_spi(0, d_spi_enable, d_spi_format, s);
-  //printf("wbxng: Setting reg %d to %X\n", (v&15), v);
+  throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
+  // *** TODO *** Magic Number 64e6?
+  //return 64e6/_refclk_divisor();
 }
 
-// ----------------------------------------------------------------
-
-void
-wbxng::set_gpio()
-{
-  // We calculate four values:
-  //
-  // io_rx_while_rx: what to drive onto io_rx_* when receiving
-  // io_rx_while_tx: what to drive onto io_rx_* when transmitting
-  // io_tx_while_rx: what to drive onto io_tx_* when receiving
-  // io_tx_while_tx: what to drive onto io_tx_* when transmitting
-  //
-  // B1-B7 is ignored as gain is set serially for now.
-  
-  int rx_hp, tx_antsel, rx_antsel, tx_pa_sel;
-  if(d_rx_hp_pin)
-    rx_hp = RX_HP;
-  else
-    rx_hp = 0;
-  
-  if(d_tx_ant)
-    tx_antsel = ANTSEL_TX2_RX1;
-  else
-    tx_antsel = ANTSEL_TX1_RX2;
-
-  if(d_rx_ant)
-    rx_antsel = ANTSEL_TX2_RX1;
-  else
-    rx_antsel = ANTSEL_TX1_RX2;
-
-  if(d_five_gig)
-    tx_pa_sel = LB_PA_OFF;
-  else
-    tx_pa_sel = HB_PA_OFF;
+struct freq_result_t
+wbxng_base::set_freq(double freq)
+{
   /*
-  // Reset GPIO and ATR
-  // FIXME: dont set io, oe, atr mask once basic code stops overriding our settings
-  usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK);
-  usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff);
-  usrp()->common_write_atr_txval(C_TX, d_which, tx_pa_sel|tx_antsel|TX_EN|AD9515DIV);
-  usrp()->common_write_atr_rxval(C_TX, d_which, HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV);
-  usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK);
-
-  usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK);
-  usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff);
-  usrp()->common_write_atr_txval(C_RX, d_which, EN|rx_hp);
-  usrp()->common_write_atr_rxval(C_RX, d_which, EN|rx_hp|RX_EN);
-  usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK);
+    @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.
   */
 
-  //printf("GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X\n",
-  //       io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx);
-}
-  
-
-struct freq_result_t
-wbxng::set_freq(double target_freq)
-{
   struct freq_result_t args = {false, 0};
 
-  double scaler;
-
-  if(target_freq > 3e9) {
-    d_five_gig = 1;
-    d_ad9515_div = 3;
-    scaler = 4.0/5.0;
-  }
-  else {
-    d_five_gig = 0;
-    d_ad9515_div = 3;
-    scaler = 4.0/3.0;
-  }
-
-  if(target_freq > 5.408e9) {
-    d_highband = 1;
-  }
-  else {
-    d_highband = 0;
-  }
-
-  double vco_freq = target_freq*scaler;
-  double sys_clk = usrp()->fpga_master_clock_freq();  // Usually 64e6 
-  double ref_clk = sys_clk / d_ad9515_div;
-        
-  double phdet_freq = ref_clk/d_ref_div;
-  double div = vco_freq/phdet_freq;
-  d_int_div = int(floor(div));
-  d_frac_div = int((div-d_int_div)*65536.0);
-  // double actual_freq = phdet_freq*(d_int_div+(d_frac_div/65536.0))/scaler;
+  // Offsetting the LO helps get the Tx carrier leakage out of the way.
+  // This also ensures that on Rx, we're not getting hosed by the
+  // FPGA's DC removal loop's time constant.  We were seeing a
+  // problem when running with discontinuous transmission.
+  // Offsetting the LO made the problem go away.
+  freq += d_lo_offset;
   
-  //printf("RF=%f VCO=%f R=%d PHD=%f DIV=%3.5f I=%3d F=%5d ACT=%f\n",
-  //    target_freq, vco_freq, d_ref_div, phdet_freq,
-  //    div, d_int_div, d_frac_div, actual_freq);
-
-  args.ok = lock_detect();
-
-  /*
-  set_gpio();
-  set_reg_int_divider();
-  set_reg_frac_divider();
-  set_reg_bandselpll();
-
-  args.ok = lock_detect();
-#ifdef NO_LO_OFFSET
-  args.baseband_freq = target_freq;
-#else
-  args.baseband_freq = actual_freq;
-#endif
-  */
-
-  if(!args.ok){
-    printf("Fail %f\n", target_freq);
-  }
+  //int R, control, N;
+  //double actual_freq;
+  //_compute_regs(freq, R, control, N, actual_freq);
+
+  //if(R==0) {
+  //  return args;
+  //}
+   
+  //_write_all(R, control, N);
+  //args.ok = _lock_detect();
+  //args.baseband_freq = actual_freq;
   return args;
 }
 
 bool
-wbxng::lock_detect()
+wbxng_base::_set_pga(float pga_gain)
 {
   /*
-    @returns: the value of the VCO/PLL lock detect bit.
-    @rtype: 0 or 1
-  */
-  /*
-  if(usrp()->common_read_io(C_RX, d_which) & LOCKDET) {
-    return true;
+  if(d_which == 0) {
+    usrp()->set_pga(0, pga_gain);
+    usrp()->set_pga(1, pga_gain);
   }
-  else {      // Give it a second chance
-    if(usrp()->common_read_io(C_RX, d_which) & LOCKDET)
-      return true;
-    else
-      return false;
+  else {
+    usrp()->set_pga(2, pga_gain);
+    usrp()->set_pga(3, pga_gain);
   }
   */
   return true;
 }
 
 bool
-wbxng::set_rx_gain(float gain)
-{
-  if(gain < 0.0) 
-    gain = 0.0;
-  if(gain > 92.0)
-    gain = 92.0;
-
-  // Split the gain between RF and baseband
-  // This is experimental, not prescribed
-  if(gain < 31.0) {
-    d_rx_rf_gain = 0;                     // 0 dB RF gain
-    rx_bb_gain = int(gain/2.0);
-  }
-  
-  if(gain >= 30.0 and gain < 60.5) {
-    d_rx_rf_gain = 2;                    // 15 dB RF gain
-    d_rx_bb_gain = int((gain-15.0)/2.0);
-  }
-  
-  if(gain >= 60.5) {
-    d_rx_rf_gain = 3;                     // 30.5 dB RF gain
-    d_rx_bb_gain = int((gain-30.5)/2.0);
-  }
-  
-  //set_reg_rxgain();
-  
+wbxng_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;
 }
 
-bool
-wbxng::set_tx_gain(float gain)
+double
+wbxng_base::freq_min()
 {
-  if(gain < 0.0) {
-    gain = 0.0;
-  }
-  if(gain > 30.0) {
-    gain = 30.0;
-  }
-  
-  d_txgain = int((gain/30.0)*63);
-  //set_reg_txgain();
-
-  return true;
+  throw std::runtime_error("freq_min called from wbxng_base\n");
+  //return d_common->freq_min();
 }
 
-
-/*****************************************************************************/
-
-
-struct wbxng_table_entry {
-  wbxng_key                    key;
-  boost::weak_ptr<wbxng>       value;
-
-  wbxng_table_entry(const wbxng_key &_key, boost::weak_ptr<wbxng> _value)
-    : key(_key), value(_value) {}
-};
-
-typedef std::vector<wbxng_table_entry> wbxng_table;
-
-static boost::mutex s_table_mutex;
-static wbxng_table s_table;
-
-static wbxng_sptr
-_get_or_make_wbxng(usrp_basic_sptr usrp, int which)
+double
+wbxng_base::freq_max()
 {
-  wbxng_key key = {usrp->serial_number(), which};
+  throw std::runtime_error("freq_max called from wbxng_base\n");
+  //return d_common->freq_max();
+}
 
-  boost::mutex::scoped_lock    guard(s_table_mutex);
+// ----------------------------------------------------------------
 
-  for (wbxng_table::iterator p = s_table.begin(); p != s_table.end();){
-    if (p->value.expired())    // weak pointer is now dead
-      p = s_table.erase(p);    // erase it
-    else {
-      if (key == p->key){      // found it
-       return wbxng_sptr(p->value);
-      }
-      else                     
-       ++p;                    // keep looking
-    }
+wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
+  : wbxng_base(_usrp, which, _power_on)
+{
+  /*
+    @param usrp: instance of usrp.sink_c
+    @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
+  */
+  
+  if(which == 0) {
+    d_spi_enable = SPI_ENABLE_TX_A;
+  }
+  else {
+    d_spi_enable = SPI_ENABLE_TX_B;
   }
 
-  // We don't have the wbxng we're looking for
+  d_common = new adf4350(_usrp, d_which, d_spi_enable);
+  
+  // power up the transmit side, but don't enable the mixer
+  /*
+  usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff);
+  usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
+  set_lo_offset(4e6);
 
-  // create a new one and stick it in the table.
-  wbxng_sptr r(new wbxng(usrp, which));
-  wbxng_table_entry t(key, r);
-  s_table.push_back(t);
+  set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
+  */
+}
 
-  return r;
+wbxng_base_tx::~wbxng_base_tx()
+{
+  shutdown();
 }
 
 
-/*****************************************************************************/
+void
+wbxng_base_tx::shutdown()
+{
+  // fprintf(stderr, "wbxng_base_tx::shutdown  d_is_shutdown = %d\n", d_is_shutdown);
 
+  if (!d_is_shutdown){
+    d_is_shutdown = true;
+    // do whatever there is to do to shutdown
 
-db_wbxng_base::db_wbxng_base(usrp_basic_sptr usrp, int which)
-  : db_base(usrp, which)
-{
-  /*
-   * Abstract base class for all wbxng boards.
-   * 
-   * Derive board specific subclasses from db_wbxng_base_{tx,rx}
-   *
-   * @param usrp: instance of usrp.source_c
-   * @param which: which side: 0 or 1 corresponding to side A or B respectively
-   * @type which: int
-   */
+    // Power down and leave the T/R switch in the R position
+    //usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
+
+    // Power down VCO/PLL
+    d_PD = 3;
   
-  d_wbxng = _get_or_make_wbxng(usrp, which);
+    _write_control(_compute_control_reg());
+    _enable_refclk(false);                       // turn off refclk
+    set_auto_tr(false);
+  }
 }
 
-db_wbxng_base::~db_wbxng_base()
+bool
+wbxng_base_tx::set_auto_tr(bool on)
 {
+  bool ok = true;
+  /*
+  if(on) {
+    ok &= set_atr_mask (RX_TXN | ENABLE);
+    ok &= set_atr_txval(0      | ENABLE);
+    ok &= set_atr_rxval(RX_TXN | 0);
+  }
+  else {
+    ok &= set_atr_mask (0);
+    ok &= set_atr_txval(0);
+    ok &= set_atr_rxval(0);
+  }
+  */
+  return ok;
 }
 
-void
-db_wbxng_base::shutdown_common()
+bool
+wbxng_base_tx::set_enable(bool on)
 {
-  // If the usrp_basic in the wbxng is the same as the usrp_basic
-  // in the daughterboard, shutdown the wbxng now (when only one of Tx
-  // and Rx is open, this is always true).
+  /*
+    Enable transmitter if on is true
+  */
 
-  if (d_wbxng->usrp() == usrp()){
-    //std::cerr << "db_wbxng_base::shutdown_common: same -> shutting down\n";
-    d_wbxng->shutdown();
+  int v;
+  //int mask = RX_TXN | ENABLE_5 | ENABLE_33;
+  if(on) {
+    v = ENABLE_5 | ENABLE_33;
   }
   else {
-    //std::cerr << "db_wbxng_base::shutdown_common: different -> ignoring\n";
+    v = RX_TXN;
   }
+  throw std::runtime_error("set_enable called from wbxng_base_tx\n");
+  //return usrp()->write_io(d_which, v, mask);
 }
 
-struct freq_result_t
-db_wbxng_base::set_freq(double target_freq)
+float
+wbxng_base_tx::gain_min()
 {
-  /*
-   * @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.
-   */
-  return d_wbxng->set_freq(target_freq+d_lo_offset);
+  return usrp()->pga_max();
 }
 
-bool
-db_wbxng_base::is_quadrature()
+float
+wbxng_base_tx::gain_max()
 {
-  /*
-   * 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;
+  return usrp()->pga_max();
 }
 
-double
-db_wbxng_base::freq_min()
+float
+wbxng_base_tx::gain_db_per_step()
 {
-  return 2.4e9;
+  return 1;
 }
 
-double
-db_wbxng_base::freq_max()
+bool
+wbxng_base_tx::set_gain(float gain)
 {
-  return 6.0e9;
+  /*
+    Set the gain.
+    
+    @param gain:  gain in decibels
+    @returns True/False
+  */
+  return _set_pga(usrp()->pga_max());
 }
 
 
-/******************************************************************************/
+/**************************************************************************/
 
 
-db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which)
-  : db_wbxng_base(usrp, which)
+wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
+  : wbxng_base(_usrp, which, _power_on)
 {
-  set_lo_offset(LO_OFFSET);
-  //printf("db_wbxng_tx::db_wbxng_tx\n");
+  /*
+    @param usrp: instance of usrp.source_c
+    @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
+  */
+
+  if(which == 0) {
+    d_spi_enable = SPI_ENABLE_RX_A;
+  }
+  else {
+    d_spi_enable = SPI_ENABLE_RX_B;
+  }
+
+  d_common = new adf4350(_usrp, d_which, d_spi_enable);
+
+  /*  
+  usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff);
+  usrp()->write_io(d_which,  (power_on()|RX2_RX1N|ENABLE), 
+                  (POWER_UP|RX2_RX1N|ENABLE));
+  
+  // set up for RX on TX/RX port
+  select_rx_antenna("TX/RX");
+  
+  bypass_adc_buffers(true);
+
+  set_lo_offset(-4e6);
+  */
 }
 
-db_wbxng_tx::~db_wbxng_tx()
+wbxng_base_rx::~wbxng_base_rx()
 {
   shutdown();
 }
 
 void
-db_wbxng_tx::shutdown()
+wbxng_base_rx::shutdown()
 {
+  // fprintf(stderr, "wbxng_base_rx::shutdown  d_is_shutdown = %d\n", d_is_shutdown);
+
   if (!d_is_shutdown){
     d_is_shutdown = true;
-    shutdown_common();
+    // do whatever there is to do to shutdown
+
+    // Power down
+    //usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE));
+
+    // Power down VCO/PLL
+    d_PD = 3;
+  
+
+    // fprintf(stderr, "wbxng_base_rx::shutdown  before _write_control\n");
+    //_write_control(_compute_control_reg());
+
+    // fprintf(stderr, "wbxng_base_rx::shutdown  before _enable_refclk\n");
+    //_enable_refclk(false);                       // turn off refclk
+
+    // fprintf(stderr, "wbxng_base_rx::shutdown  before set_auto_tr\n");
+    //set_auto_tr(false);
+
+    // fprintf(stderr, "wbxng_base_rx::shutdown  after set_auto_tr\n");
   }
 }
 
-float
-db_wbxng_tx::gain_min()
+bool
+wbxng_base_rx::set_auto_tr(bool on)
 {
-  return 0;
+  //bool ok = true;
+  /*
+  if(on) {
+    ok &= set_atr_mask (ENABLE);
+    ok &= set_atr_txval(     0);
+    ok &= set_atr_rxval(ENABLE);
+  }
+  else {
+    ok &= set_atr_mask (0);
+    ok &= set_atr_txval(0);
+    ok &= set_atr_rxval(0);
+  }
+  */
+  return true;
 }
 
-float
-db_wbxng_tx::gain_max()
+/* *** TODO *** Defined select_rx_antenna twice?
+bool
+wbxng_base_rx::select_rx_antenna(int which_antenna)
 {
-  return 30;
-}
+  **COMMENT**
+    Specify which antenna port to use for reception.
+    @param which_antenna: either 'TX/RX' or 'RX2'
+  **COMMENT**
 
-float
-db_wbxng_tx::gain_db_per_step()
-{
-  return (30.0/63.0);
+  if(which_antenna == 0) {
+    usrp()->write_io(d_which, 0,RX2_RX1N);
+  }
+  else if(which_antenna == 1) {
+    usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
+  }
+  else {
+    return false;
+    // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
+  }
+  return true;
 }
+*/
 
 bool
-db_wbxng_tx::set_gain(float gain)
+wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
 {
-  return d_wbxng->set_tx_gain(gain);
+  /*
+    Specify which antenna port to use for reception.
+    @param which_antenna: either 'TX/RX' or 'RX2'
+  */
+
+  /*
+  if(which_antenna == "TX/RX") {
+    usrp()->write_io(d_which, 0, RX2_RX1N);
+  }
+  else if(which_antenna == "RX2") {
+    usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
+  }
+  else {
+    // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
+    return false;
+  }
+  */
+  return true;
 }
 
 bool
-db_wbxng_tx::i_and_q_swapped()
+wbxng_base_rx::set_gain(float gain)
 {
-  return true;
+  /*
+    Set the gain.
+    
+    @param gain:  gain in decibels
+    @returns True/False
+  */
+  
+  /*
+  // clamp gain
+  gain = std::max(gain_min(), std::min(gain, gain_max()));
+
+  float pga_gain, agc_gain;
+  float V_maxgain, V_mingain, V_fullscale, dac_value;
+
+  float maxgain = gain_max() - usrp()->pga_max();
+  float mingain = gain_min();
+  if(gain > maxgain) {
+    pga_gain = gain-maxgain;
+    assert(pga_gain <= usrp()->pga_max());
+    agc_gain = maxgain;
+  }
+  else {
+    pga_gain = 0;
+    agc_gain = gain;
+  }
+  
+  V_maxgain = .2;
+  V_mingain = 1.2;
+  V_fullscale = 3.3;
+  dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
+
+  assert(dac_value>=0 && dac_value<4096);
+
+  return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
+         && _set_pga(int(pga_gain)));
+  */
+  return false;
 }
 
+// ----------------------------------------------------------------
 
-/******************************************************************************/
+db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which)
+  : wbxng_base_tx(usrp, which)
+{
+}
 
+db_wbxng_tx::~db_wbxng_tx()
+{
+}
 
-db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
-  : db_wbxng_base(usrp, which)
+/*
+bool
+db_wbxng_tx::_compute_regs(double freq, int &retR, int &retcontrol,
+                                int &retN, double &retfreq)
 {
-  /*
-   * @param usrp: instance of usrp.source_c
-   * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
-   */
-  set_lo_offset(LO_OFFSET);
-  //printf("db_wbxng_rx:d_wbxng_rx\n");
+  return d_common->_compute_regs(_refclk_freq(), freq, retR,
+                                retcontrol, retN, retfreq);
 }
+*/
 
-db_wbxng_rx::~db_wbxng_rx()
+
+db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
+  : wbxng_base_rx(usrp, which)
 {
-  shutdown();
+  set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
 }
 
-void
-db_wbxng_rx::shutdown()
+db_wbxng_rx::~db_wbxng_rx()
 {
-  if (!d_is_shutdown){
-    d_is_shutdown = true;
-    shutdown_common();
-  }
 }
 
 float
 db_wbxng_rx::gain_min()
 {
-  return 0.0;
+  return usrp()->pga_min();
 }
 
 float
 db_wbxng_rx::gain_max()
 {
-  return 92.0;
+  return usrp()->pga_max()+70;
 }
 
 float
 db_wbxng_rx::gain_db_per_step()
 {
-  return 1;
+  return 0.05;
+}
+
+
+bool
+db_wbxng_rx::i_and_q_swapped()
+{
+  return true;
 }
 
+/*
 bool
-db_wbxng_rx::set_gain(float gain)
+db_wbxng_rx::_compute_regs(double freq, int &retR, int &retcontrol,
+                                int &retN, double &retfreq)
 {
-  return d_wbxng->set_rx_gain(gain);
+  return d_common->_compute_regs(_refclk_freq(), freq, retR,
+                                retcontrol, retN, retfreq);
 }
+*/
+
diff --git a/usrp/host/lib/db_wbxng_adf4350.cc b/usrp/host/lib/db_wbxng_adf4350.cc
new file mode 100644 (file)
index 0000000..22262be
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2009 Ettus Research LLC
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp/db_wbxng_adf4350.h>
+#include <usrp/db_wbxng_adf4350_regs.h>
+#include <db_base_impl.h>
+#include <stdio.h>
+//#include "io.h"
+//#include "spi.h"
+
+#define INPUT_REF_FREQ FREQ_C(10e6)
+#define DIV_ROUND(num, denom) (((num) + ((denom)/2))/(denom))
+#define FREQ_C(freq) ((uint32_t)DIV_ROUND(freq, (uint32_t)1000))
+#define INPUT_REF_FREQ_2X (2*INPUT_REF_FREQ)                            /* input ref freq with doubler turned on */
+#define MIN_INT_DIV uint16_t(23)                                        /* minimum int divider, prescaler 4/5 only */
+#define MAX_RF_DIV uint8_t(16)                                          /* max rf divider, divides rf output */
+#define MIN_VCO_FREQ FREQ_C(2.2e9)                                      /* minimum vco freq */
+#define MAX_VCO_FREQ FREQ_C(4.4e9)                                      /* minimum vco freq */
+#define MAX_FREQ MAX_VCO_FREQ                                           /* upper bound freq (rf div = 1) */
+#define MIN_FREQ DIV_ROUND(MIN_VCO_FREQ, MAX_RF_DIV)                    /* calculated lower bound freq */
+
+#define CE_PIN        (1 << 3)
+#define PDB_RF_PIN    (1 << 2)
+#define MUX_PIN       (1 << 1)
+#define LD_PIN        (1 << 0)
+
+adf4350::adf4350(usrp_basic_sptr _usrp, int _which, int _spi_enable){
+       /* Initialize the pin directions. */
+
+    d_usrp = _usrp;
+    d_which = _which;
+    d_spi_enable = _spi_enable;
+    d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
+
+    d_regs = new adf4350_regs(this);
+
+    /* Outputs */
+    d_usrp->_write_oe(d_which, (CE_PIN | PDB_RF_PIN), 0xffff);
+
+       /* Initialize the pin levels. */
+       _enable(true);
+       /* Initialize the registers. */
+       d_regs->_load_register(5);
+       d_regs->_load_register(4);
+       d_regs->_load_register(3);
+       d_regs->_load_register(2);
+       d_regs->_load_register(1);
+       d_regs->_load_register(0);
+}
+
+adf4350::~adf4350(){
+    delete d_regs;
+}
+
+freq_t 
+adf4350::_get_max_freq(void){
+       return MAX_FREQ;
+}
+
+freq_t 
+adf4350::_get_min_freq(void){
+       return MIN_FREQ;
+}
+
+bool 
+adf4350::_get_locked(void){
+    return d_usrp->read_io(d_which) & LD_PIN;
+}
+
+void 
+adf4350::_enable(bool enable){
+       if (enable){ /* chip enable */
+        d_usrp->write_io(d_which, 1, CE_PIN);
+       }else{
+        d_usrp->write_io(d_which, 0, CE_PIN);
+       }
+}
+
+void 
+adf4350::_write(uint8_t addr, uint32_t data){
+       data |= addr;
+
+    // create str from data here
+    char s[4];
+    s[0] = (char)((data >> 24) & 0xff);
+    s[1] = (char)((data >> 16) & 0xff);
+    s[2] = (char)((data >>  8) & 0xff);
+    s[3] = (char)(data & 0xff);
+    std::string str(s, 3);
+
+    d_usrp->_write_spi(0, d_spi_enable, d_spi_format, str);
+       /* pulse latch */
+    //d_usrp->write_io(d_which, 1, LE_PIN);
+    //d_usrp->write_io(d_which, 0, LE_PIN);
+}
+
+bool 
+adf4350::_set_freq(freq_t freq){
+       /* Set the frequency by setting int, frac, mod, r, div */
+       if (freq > MAX_FREQ || freq < MIN_FREQ) return false;
+       /* Ramp up the RF divider until the VCO is within range. */
+       d_regs->_divider_select = 0;
+       while (freq < MIN_VCO_FREQ){
+               freq <<= 1; //double the freq
+               d_regs->_divider_select++; //double the divider
+       }
+       /* Ramp up the R divider until the N divider is at least the minimum. */
+       d_regs->_10_bit_r_counter = INPUT_REF_FREQ_2X*MIN_INT_DIV/freq;
+       uint64_t n_mod;
+       do{
+               d_regs->_10_bit_r_counter++;
+               n_mod = freq;
+               n_mod *= d_regs->_10_bit_r_counter;
+               n_mod *= d_regs->_mod;
+               n_mod /= INPUT_REF_FREQ_2X;
+               /* calculate int and frac */
+               d_regs->_int = n_mod/d_regs->_mod;
+               d_regs->_frac = (n_mod - (freq_t)d_regs->_int*d_regs->_mod) & uint16_t(0xfff);
+               /*printf(
+                       "VCO %lu KHz, Int %u, Frac %u, Mod %u, R %u, Div %u\n",
+                       freq, d_regs->_int, d_regs->_frac,
+                       d_regs->_mod, d_regs->_10_bit_r_counter, (1 << d_regs->_divider_select)
+               );*/
+       }while(d_regs->_int < MIN_INT_DIV);
+       /* calculate the band select so PFD is under 125 KHz */
+       d_regs->_8_bit_band_select_clock_divider_value = \
+               INPUT_REF_FREQ_2X/(FREQ_C(125e3)*d_regs->_10_bit_r_counter) + 1;
+       /* load involved registers */
+       d_regs->_load_register(2);
+       d_regs->_load_register(4);
+       d_regs->_load_register(0); /* register 0 must be last */
+       return true;
+}
+
+freq_t 
+adf4350::_get_freq(void){
+       /* Calculate the freq from int, frac, mod, ref, r, div:
+        *  freq = (int + frac/mod) * (ref/r)
+        * Keep precision by doing multiplies first:
+        *  freq = (((((((int)*mod) + frac)*ref)/mod)/r)/div)
+        */
+       uint64_t temp;
+       temp = d_regs->_int;
+       temp *= d_regs->_mod;
+       temp += d_regs->_frac;
+       temp *= INPUT_REF_FREQ_2X;
+       temp /= d_regs->_mod;
+       temp /= d_regs->_10_bit_r_counter;
+       temp /= (1 << d_regs->_divider_select);
+       return temp;
+}
diff --git a/usrp/host/lib/db_wbxng_adf4350_regs.cc b/usrp/host/lib/db_wbxng_adf4350_regs.cc
new file mode 100644 (file)
index 0000000..b320e8b
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009 Ettus Research LLC
+ */
+
+#include <usrp/db_wbxng_adf4350_regs.h>
+#include <usrp/db_wbxng_adf4350.h>
+//#include "cal_div.h"
+
+adf4350_regs::adf4350_regs(adf4350* _adf4350){
+    d_adf4350 = _adf4350;
+
+    /* reg 0 */
+    _int = uint16_t(100);
+    _frac = 0;
+    /* reg 1 */
+    _prescaler = 1;                        /* 8/9 */
+    _phase = 0;                           /* 0 */
+    _mod = uint16_t(0xfff);                      /* max fractional accuracy */
+    /* reg 2 */
+    _low_noise_and_low_spur_modes = 0;     /* low noise mode */
+    _muxout = 6;                           /* digital lock detect */
+    _reference_doubler = 1;                /* enabled */
+    _rdiv2 = 0;                            /* disabled */
+    _10_bit_r_counter = uint16_t(1);
+    _double_buff = 0;                      /* disabled */
+    _charge_pump_setting = 7;              /* 2.50 mA */
+    _ldf = 0;                              /* frac-n */
+    _ldp = 0;                              /* 10 ns */
+    _pd_polarity = 1;                      /* positive */
+    _power_down = 0;                       /* disabled */
+    _cp_three_state = 0;                   /* disabled */
+    _counter_reset = 0;                    /* disabled */
+    /* reg 3 */
+    _csr = 0;                              /* disabled */
+    _clk_div_mode = 0;                     /* clock divider off */
+    _12_bit_clock_divider_value = 0;      /* 0 */
+    /* reg 4 */
+    _feedback_select = 1;                  /* fundamental */
+    _divider_select = 0;
+    _8_bit_band_select_clock_divider_value = 0;
+    _vco_power_down = 0;                   /* vco powered up */
+    _mtld = 0;                             /* mute disabled */
+    _aux_output_select = 0;                /* divided output */
+    _aux_output_enable = 0;                /* disabled */
+    _aux_output_power = 0;                 /* -4 */
+    _rf_output_enable = 1;                 /* enabled */
+    _output_power = 1;                     /* -1 */
+    /* reg 5 */
+    _ld_pin_mode = 1;                      /* digital lock detect */
+}
+
+adf4350_regs::~adf4350_regs(void){
+}
+
+uint32_t 
+adf4350_regs::_reg_shift(uint32_t data, uint32_t shift){
+        return data << shift;
+    }
+
+void 
+adf4350_regs::_load_register(uint8_t addr){
+       uint32_t data;
+       switch (addr){
+               case 0: data = (
+                       _reg_shift(_int, 15)                           |
+                       _reg_shift(_frac, 3)); break;
+               case 1: data = (
+                       _reg_shift(_prescaler, 27)                     |
+                       _reg_shift(_phase, 15)                         |
+                       _reg_shift(_mod, 3)); break;
+               case 2: data = (
+                       _reg_shift(_low_noise_and_low_spur_modes, 29)  |
+                       _reg_shift(_muxout, 26)                        |
+                       _reg_shift(_reference_doubler, 25)             |
+                       _reg_shift(_rdiv2, 24)                         |
+                       _reg_shift(_10_bit_r_counter, 14)              |
+                       _reg_shift(_double_buff, 13)                   |
+                       _reg_shift(_charge_pump_setting, 9)            |
+                       _reg_shift(_ldf, 8)                            |
+                       _reg_shift(_ldp, 7)                            |
+                       _reg_shift(_pd_polarity, 6)                    |
+                       _reg_shift(_power_down, 5)                     |
+                       _reg_shift(_cp_three_state, 4)                 |
+                       _reg_shift(_counter_reset, 3)); break;
+               case 3: data = (
+                       _reg_shift(_csr, 18)                           |
+                       _reg_shift(_clk_div_mode, 15)                  |
+                       _reg_shift(_12_bit_clock_divider_value, 3)); break;
+               case 4: data = (
+                       _reg_shift(_feedback_select, 23)               |
+                       _reg_shift(_divider_select, 20)                |
+                       _reg_shift(_8_bit_band_select_clock_divider_value, 12) |
+                       _reg_shift(_vco_power_down, 11)                |
+                       _reg_shift(_mtld, 10)                          |
+                       _reg_shift(_aux_output_select, 9)              |
+                       _reg_shift(_aux_output_enable, 8)              |
+                       _reg_shift(_aux_output_power, 6)               |
+                       _reg_shift(_rf_output_enable, 5)               |
+                       _reg_shift(_output_power, 3)); break;
+               case 5: data = (
+                       _reg_shift(_ld_pin_mode, 22)); break;
+               default: return;
+       }
+       /* write the data out to spi */
+       d_adf4350->_write(addr, data);
+}