switch source package format to 3.0 quilt
[debian/gnuradio] / usrp / host / lib / db_wbxng.cc
index 8a03cfbac3af875e8dc1e31e4ac4777d1e0a1e92..bd836dfe331090724a18c8c9f414ec274dd66032 100644 (file)
@@ -1,25 +1,29 @@
 //
-// Copyright 2008 Free Software Foundation, Inc.
-// 
+// Copyright 2008,2009 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.
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <usrp/db_wbxng.h>
-#include <usrp/db_wbxng_adf4350.h>
+#include "db_wbxng_adf4350.h"
 #include <db_base_impl.h>
 #include <stdio.h>
 
 // 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 RX_TXN          (1 << 15)         // Tx only: T/R antenna switch for TX/RX port
+//#define RX2_RX1N        (1 << 15)         // Rx only: antenna switch between RX2 and TX/RX port
+#define RX_TXN          ((1 << 5)|(1 << 15))         // Tx only: T/R antenna switch for TX/RX port
+#define RX2_RX1N        ((1 << 5)|(1 << 15))         // Rx only: antenna switch between RX2 and TX/RX port
+#define RXBB_EN         (1 << 4)
 #define TXMOD_EN        (1 << 4)
 #define PLL_CE          (1 << 3)
 #define PLL_PDBRF       (1 << 2)
 #define PLL_MUXOUT      (1 << 1)
 #define PLL_LOCK_DETECT (1 << 0)
 
+// RX Attenuator constants
+#define ATTN_SHIFT     8
+#define ATTN_MASK      (63 << ATTN_SHIFT)
+
 wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
   : db_base(_usrp, which), d_power_on(_power_on)
 {
@@ -56,143 +67,8 @@ wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
 
 wbxng_base::~wbxng_base()
 {
-  delete d_common;
-}
-
-void
-wbxng_base::_write_all(int R, int control, int N)
-{
-  /*
-    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_base::_write_control(int control)
-{
-  //_write_it((control & ~0x3) | 0);
-}
-
-void
-wbxng_base::_write_R(int R)
-{
-  //_write_it((R & ~0x3) | 1);
-}
-
-void
-wbxng_base::_write_N(int N)
-{
-  //_write_it((N & ~0x3) | 2);
-}
-
-void
-wbxng_base::_write_it(int v)
-{
-  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);
-}
-        
-bool
-wbxng_base::_lock_detect()
-{
-  /*
-    @returns: the value of the VCO/PLL lock detect bit.
-    @rtype: 0 or 1
-  */
-  
-  if(d_common->_get_locked()){
-    return true;
-  }
-  else {      // Give it a second chance
-    return false;
-    /*
-    // 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");
-}
-
-/*
-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");
-}
-*/
-
-int
-wbxng_base::_compute_control_reg()
-{
-  throw std::runtime_error("_compute_control_reg called from wbxng_base\n");
-  //return d_common->_compute_control_reg();
-}
-
-int
-wbxng_base::_refclk_divisor()
-{
-  throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
-  //return d_common->_refclk_divisor();
-}
-
-double
-wbxng_base::_refclk_freq()
-{
-  throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
-  // *** TODO *** Magic Number 64e6?
-  //return 64e6/_refclk_divisor();
+  if (d_common)
+    delete d_common;
 }
 
 struct freq_result_t
@@ -204,7 +80,9 @@ wbxng_base::set_freq(double freq)
     actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
   */
 
-  freq_t int_freq = freq_t(freq);
+  // clamp freq
+  freq_t int_freq = freq_t(std::max(freq_min(), std::min(freq, freq_max())));
+
   bool ok = d_common->_set_freq(int_freq*2);
   double freq_result = (double) d_common->_get_freq()/2.0;
   struct freq_result_t args = {ok, freq_result};
@@ -215,34 +93,23 @@ wbxng_base::set_freq(double freq)
   t.tv_nsec = 10000000;
   nanosleep(&t, NULL);
 
-  fprintf(stderr,"Setting WBXNG frequency, requested %d, obtained %f, lock_detect %d\n", 
-          int_freq, freq_result, _lock_detect());
+  //fprintf(stderr,"Setting WBXNG frequency, requested %d, obtained %f, lock_detect %d\n",
+  //        int_freq, freq_result, d_common->_get_locked());
 
+  // FIXME
   // 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;
-  
-  //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_base::_set_pga(float pga_gain)
 {
-  /*
   if(d_which == 0) {
     usrp()->set_pga(0, pga_gain);
     usrp()->set_pga(1, pga_gain);
@@ -251,7 +118,6 @@ wbxng_base::_set_pga(float pga_gain)
     usrp()->set_pga(2, pga_gain);
     usrp()->set_pga(3, pga_gain);
   }
-  */
   return true;
 }
 
@@ -260,7 +126,7 @@ 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;
@@ -287,7 +153,7 @@ wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _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;
   }
@@ -296,14 +162,16 @@ wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
   }
 
   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,(RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5));
-  usrp()->write_io(d_which, (power_on()|RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5));
-  fprintf(stderr,"Setting WBXNG TXMOD on"); 
+  usrp()->write_io(d_which, (power_on()|RX_TXN|ENABLE_33|ENABLE_5), (RX_TXN|ENABLE_33|ENABLE_5));
   //set_lo_offset(4e6);
+  
+  // Disable VCO/PLL
+  d_common->_enable(true);
 
-  //set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
+  set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
 }
 
 wbxng_base_tx::~wbxng_base_tx()
@@ -321,12 +189,13 @@ wbxng_base_tx::shutdown()
     d_is_shutdown = true;
     // do whatever there is to do to shutdown
 
+    // Disable VCO/PLL
+    d_common->_enable(false);
+
     // Power down and leave the T/R switch in the R position
     usrp()->write_io(d_which, (power_off()|RX_TXN), (RX_TXN|ENABLE_33|ENABLE_5));
 
-    // Power down VCO/PLL
-    d_common->_enable(false);
-  
+
     /*
     _write_control(_compute_control_reg());
     */
@@ -340,9 +209,9 @@ wbxng_base_tx::set_auto_tr(bool on)
 {
   bool ok = true;
   if(on) {
-    ok &= set_atr_mask (RX_TXN | ENABLE_33 | ENABLE_5);
-    ok &= set_atr_txval(0      | ENABLE_33 | ENABLE_5);
-    ok &= set_atr_rxval(RX_TXN | 0);
+    ok &= set_atr_mask (RX_TXN | TXMOD_EN);
+    ok &= set_atr_txval(0      | TXMOD_EN);
+    ok &= set_atr_rxval(RX_TXN);
   }
   else {
     ok &= set_atr_mask (0);
@@ -360,12 +229,16 @@ wbxng_base_tx::set_enable(bool on)
   */
 
   int v;
-  int mask = RX_TXN | ENABLE_5 | ENABLE_33;
+  int mask = RX_TXN | TXMOD_EN;
   if(on) {
-    v = ENABLE_5 | ENABLE_33;
+    v = TXMOD_EN;
+    // Enable VCO/PLL
+    //d_common->_enable(true);
   }
   else {
     v = RX_TXN;
+    // Disable VCO/PLL
+    //d_common->_enable(false);
   }
   return usrp()->write_io(d_which, v, mask);
 }
@@ -373,19 +246,19 @@ wbxng_base_tx::set_enable(bool on)
 float
 wbxng_base_tx::gain_min()
 {
-  return usrp()->pga_max();
+  return 0.0;
 }
 
 float
 wbxng_base_tx::gain_max()
 {
-  return usrp()->pga_max();
+  return 25.0;
 }
 
 float
 wbxng_base_tx::gain_db_per_step()
 {
-  return 1;
+  return gain_max()/(1+(1.4-0.5)*4096/3.3);
 }
 
 bool
@@ -393,11 +266,33 @@ wbxng_base_tx::set_gain(float gain)
 {
   /*
     Set the gain.
-    
+
     @param gain:  gain in decibels
     @returns True/False
   */
-  return _set_pga(usrp()->pga_max());
+
+  // 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();
+  float mingain = gain_min();
+  pga_gain = 0;
+  agc_gain = gain;
+
+  V_maxgain = 0.5;
+  V_mingain = 1.4;
+  V_fullscale = 3.3;
+  dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
+
+  //fprintf(stderr, "TXGAIN: %f dB, Dac Code: %d, Voltage: %f\n", gain, int(dac_value), float((dac_value/4096.0)*V_fullscale));
+  assert(dac_value>=0 && dac_value<4096);
+
+  return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
+     && _set_pga(usrp()->pga_max()));
+
 }
 
 
@@ -420,16 +315,20 @@ wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
   }
 
   d_common = new adf4350(_usrp, d_which, d_spi_enable);
-
-  usrp()->_write_oe(d_which, (RX2_RX1N|ENABLE_33|ENABLE_5), (RX2_RX1N|ENABLE_33|ENABLE_5));
-  usrp()->write_io(d_which,  (power_on()|RX2_RX1N|ENABLE_33|ENABLE_5), (RX2_RX1N|ENABLE_33|ENABLE_5));
   
+  // Disable VCO/PLL
+  d_common->_enable(true);
+
+  usrp()->_write_oe(d_which, (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5), (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5));
+  usrp()->write_io(d_which,  (power_on()|RX2_RX1N|RXBB_EN|ENABLE_33|ENABLE_5), (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5));
+  //fprintf(stderr,"Setting WBXNG RXBB on");
+
   // set up for RX on TX/RX port
   select_rx_antenna("TX/RX");
-  
+
   bypass_adc_buffers(true);
 
-  /*  
+  /*
   set_lo_offset(-4e6);
   */
 }
@@ -448,9 +347,6 @@ wbxng_base_rx::shutdown()
     d_is_shutdown = true;
     // do whatever there is to do to shutdown
 
-    // Power down
-    usrp()->common_write_io(C_RX, d_which, power_off(), (ENABLE_33|ENABLE_5));
-
     // Power down VCO/PLL
     d_common->_enable(false);
 
@@ -463,6 +359,9 @@ wbxng_base_rx::shutdown()
     // fprintf(stderr, "wbxng_base_rx::shutdown  before set_auto_tr\n");
     set_auto_tr(false);
 
+    // Power down
+    usrp()->write_io(d_which, power_off(), (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5));
+
     // fprintf(stderr, "wbxng_base_rx::shutdown  after set_auto_tr\n");
   }
 }
@@ -472,9 +371,9 @@ wbxng_base_rx::set_auto_tr(bool on)
 {
   bool ok = true;
   if(on) {
-    ok &= set_atr_mask (ENABLE_33|ENABLE_5);
-    ok &= set_atr_txval(     0);
-    ok &= set_atr_rxval(ENABLE_33|ENABLE_5);
+    ok &= set_atr_mask (RXBB_EN|RX2_RX1N);
+    ok &= set_atr_txval(      0|RX2_RX1N);
+    ok &= set_atr_rxval(RXBB_EN|       0);
   }
   else {
     ok &= set_atr_mask (0);
@@ -500,7 +399,6 @@ wbxng_base_rx::select_rx_antenna(int which_antenna)
   }
   else {
     return false;
-    // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
   }
   return true;
 }
@@ -513,7 +411,7 @@ wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
     @param which_antenna: either 'TX/RX' or 'RX2'
   */
 
-  
+
   if(which_antenna == "TX/RX") {
     usrp()->write_io(d_which, 0, RX2_RX1N);
   }
@@ -521,10 +419,9 @@ wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
     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;
 }
 
@@ -533,17 +430,15 @@ wbxng_base_rx::set_gain(float gain)
 {
   /*
     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();
@@ -556,18 +451,17 @@ wbxng_base_rx::set_gain(float gain)
     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 _set_attn(maxgain-agc_gain) && _set_pga(int(pga_gain));
+}
 
-  return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
-         && _set_pga(int(pga_gain)));
-  */
-  return false;
+bool
+wbxng_base_rx::_set_attn(float attn)
+{
+  int attn_code = int(floor(attn/0.5));
+  unsigned int iobits = (~attn_code) << ATTN_SHIFT;
+  //fprintf(stderr, "Attenuation: %f dB, Code: %d, IO Bits %x, Mask: %x \n", attn, attn_code, iobits & ATTN_MASK, ATTN_MASK);
+  return usrp()->write_io(d_which, iobits, ATTN_MASK);
 }
 
 // ----------------------------------------------------------------
@@ -581,17 +475,6 @@ db_wbxng_tx::~db_wbxng_tx()
 {
 }
 
-/*
-bool
-db_wbxng_tx::_compute_regs(double freq, int &retR, int &retcontrol,
-                                int &retN, double &retfreq)
-{
-  return d_common->_compute_regs(_refclk_freq(), freq, retR,
-                                retcontrol, retN, retfreq);
-}
-*/
-
-
 db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
   : wbxng_base_rx(usrp, which)
 {
@@ -611,7 +494,7 @@ db_wbxng_rx::gain_min()
 float
 db_wbxng_rx::gain_max()
 {
-  return usrp()->pga_max()+70;
+  return usrp()->pga_max()+30.5;
 }
 
 float
@@ -624,16 +507,5 @@ db_wbxng_rx::gain_db_per_step()
 bool
 db_wbxng_rx::i_and_q_swapped()
 {
-  return true;
-}
-
-/*
-bool
-db_wbxng_rx::_compute_regs(double freq, int &retR, int &retcontrol,
-                                int &retN, double &retfreq)
-{
-  return d_common->_compute_regs(_refclk_freq(), freq, retR,
-                                retcontrol, retN, retfreq);
+  return false;
 }
-*/
-