commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r9742 - gnuradio/branches/developers/eb/cppdb-wip/usrp


From: eb
Subject: [Commit-gnuradio] r9742 - gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy
Date: Tue, 7 Oct 2008 21:53:43 -0600 (MDT)

Author: eb
Date: 2008-10-07 21:53:42 -0600 (Tue, 07 Oct 2008)
New Revision: 9742

Added:
   gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc
   
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc.prev
   gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h
   
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h.prev
Removed:
   gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc
   gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h
Log:
prepare to re-refactor usrp_basic

Deleted: 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc

Copied: 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc 
(from rev 9708, gnuradio/trunk/usrp/host/lib/legacy/usrp_basic.cc)
===================================================================
--- 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc    
                            (rev 0)
+++ 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc    
    2008-10-08 03:53:42 UTC (rev 9742)
@@ -0,0 +1,1243 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004 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 version 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_basic.h"
+#include "usrp_prims.h"
+#include "usrp_interfaces.h"
+#include "fpga_regs_common.h"
+#include "fusb.h"
+#include <usb.h>
+#include <stdexcept>
+#include <assert.h>
+#include <math.h>
+#include <ad9862.h>
+#include <string.h>
+
+using namespace ad9862;
+
+#define NELEM(x) (sizeof (x) / sizeof (x[0]))
+
+// These set the buffer size used for each end point using the fast
+// usb interface.  The kernel ends up locking down this much memory.
+
+static const int FUSB_BUFFER_SIZE = fusb_sysconfig::default_buffer_size();
+static const int FUSB_BLOCK_SIZE = fusb_sysconfig::max_block_size();
+static const int FUSB_NBLOCKS    = FUSB_BUFFER_SIZE / FUSB_BLOCK_SIZE;
+
+
+static const double POLLING_INTERVAL = 0.1;    // seconds
+
+////////////////////////////////////////////////////////////////
+
+static struct usb_dev_handle *
+open_rx_interface (struct usb_device *dev)
+{
+  struct usb_dev_handle *udh = usrp_open_rx_interface (dev);
+  if (udh == 0){
+    fprintf (stderr, "usrp_basic_rx: can't open rx interface\n");
+    usb_strerror ();
+  }
+  return udh;
+}
+
+static struct usb_dev_handle *
+open_tx_interface (struct usb_device *dev)
+{
+  struct usb_dev_handle *udh = usrp_open_tx_interface (dev);
+  if (udh == 0){
+    fprintf (stderr, "usrp_basic_tx: can't open tx interface\n");
+    usb_strerror ();
+  }
+  return udh;
+}
+
+
+//////////////////////////////////////////////////////////////////
+//
+//                     usrp_basic
+//
+////////////////////////////////////////////////////////////////
+
+
+// Given:
+//   CLKIN = 64 MHz
+//   CLKSEL pin = high 
+//
+// These settings give us:
+//   CLKOUT1 = CLKIN = 64 MHz
+//   CLKOUT2 = CLKIN = 64 MHz
+//   ADC is clocked at  64 MHz
+//   DAC is clocked at 128 MHz
+
+static unsigned char common_regs[] = {
+  REG_GENERAL,         0,
+  REG_DLL,             (DLL_DISABLE_INTERNAL_XTAL_OSC
+                        | DLL_MULT_2X
+                        | DLL_FAST),
+  REG_CLKOUT,          CLKOUT2_EQ_DLL_OVER_2,
+  REG_AUX_ADC_CLK,     AUX_ADC_CLK_CLK_OVER_4
+};
+
+
+usrp_basic::usrp_basic (int which_board, 
+                       struct usb_dev_handle *
+                       open_interface (struct usb_device *dev),
+                       const std::string fpga_filename,
+                       const std::string firmware_filename)
+  : d_udh (0),
+    d_usb_data_rate (16000000),        // SWAG, see below
+    d_bytes_per_poll ((int) (POLLING_INTERVAL * d_usb_data_rate)),
+    d_verbose (false)
+{
+  /*
+   * SWAG: Scientific Wild Ass Guess.
+   *
+   * d_usb_data_rate is used only to determine how often to poll for over- and 
under-runs.
+   * We defualt it to 1/2  of our best case.  Classes derived from usrp_basic 
(e.g., 
+   * usrp_standard_tx and usrp_standard_rx) call set_usb_data_rate() to tell 
us the
+   * actual rate.  This doesn't change our throughput, that's determined by 
the signal
+   * processing code in the FPGA (which we know nothing about), and the system 
limits
+   * determined by libusb, fusb_*, and the underlying drivers.
+   */
+  memset (d_fpga_shadows, 0, sizeof (d_fpga_shadows));
+
+  usrp_one_time_init ();
+
+  if (!usrp_load_standard_bits (which_board, false, fpga_filename, 
firmware_filename))
+    throw std::runtime_error ("usrp_basic/usrp_load_standard_bits");
+
+  struct usb_device *dev = usrp_find_device (which_board);
+  if (dev == 0){
+    fprintf (stderr, "usrp_basic: can't find usrp[%d]\n", which_board);
+    throw std::runtime_error ("usrp_basic/usrp_find_device");
+  }
+
+  if (!(usrp_usrp_p(dev) && usrp_hw_rev(dev) >= 1)){
+    fprintf (stderr, "usrp_basic: sorry, this code only works with USRP revs 
>= 1\n");
+    throw std::runtime_error ("usrp_basic/bad_rev");
+  }
+
+  if ((d_udh = open_interface (dev)) == 0)
+    throw std::runtime_error ("usrp_basic/open_interface");
+
+  // initialize registers that are common to rx and tx
+
+  if (!usrp_9862_write_many_all (d_udh, common_regs, sizeof (common_regs))){
+    fprintf (stderr, "usrp_basic: failed to init common AD9862 regs\n");
+    throw std::runtime_error ("usrp_basic/init_9862");
+  }
+
+  _write_fpga_reg (FR_MODE, 0);                // ensure we're in normal mode
+  _write_fpga_reg (FR_DEBUG_EN, 0);    // disable debug outputs
+}
+
+usrp_basic::~usrp_basic ()
+{
+  if (d_udh)
+    usb_close (d_udh);
+}
+
+bool
+usrp_basic::start ()
+{
+  return true;         // nop
+}
+
+bool
+usrp_basic::stop ()
+{
+  return true;         // nop
+}
+
+void
+usrp_basic::set_usb_data_rate (int usb_data_rate)
+{
+  d_usb_data_rate = usb_data_rate;
+  d_bytes_per_poll = (int) (usb_data_rate * POLLING_INTERVAL);
+}
+
+bool
+usrp_basic::write_aux_dac (int slot, int which_dac, int value)
+{
+  return usrp_write_aux_dac (d_udh, slot, which_dac, value);
+}
+
+bool
+usrp_basic::read_aux_adc (int slot, int which_adc, int *value)
+{
+  return usrp_read_aux_adc (d_udh, slot, which_adc, value);
+}
+
+int
+usrp_basic::read_aux_adc (int slot, int which_adc)
+{
+  int  value;
+  if (!read_aux_adc (slot, which_adc, &value))
+    return READ_FAILED;
+
+  return value;
+}
+
+bool
+usrp_basic::write_eeprom (int i2c_addr, int eeprom_offset, const std::string 
buf)
+{
+  return usrp_eeprom_write (d_udh, i2c_addr, eeprom_offset, buf.data (), 
buf.size ());
+}
+
+std::string
+usrp_basic::read_eeprom (int i2c_addr, int eeprom_offset, int len)
+{
+  if (len <= 0)
+    return "";
+
+  char buf[len];
+
+  if (!usrp_eeprom_read (d_udh, i2c_addr, eeprom_offset, buf, len))
+    return "";
+
+  return std::string (buf, len);
+}
+
+bool
+usrp_basic::write_i2c (int i2c_addr, const std::string buf)
+{
+  return usrp_i2c_write (d_udh, i2c_addr, buf.data (), buf.size ());
+}
+
+std::string
+usrp_basic::read_i2c (int i2c_addr, int len)
+{
+  if (len <= 0)
+    return "";
+
+  char buf[len];
+
+  if (!usrp_i2c_read (d_udh, i2c_addr, buf, len))
+    return "";
+
+  return std::string (buf, len);
+}
+
+std::string
+usrp_basic::serial_number()
+{
+  return usrp_serial_number(d_udh);
+}
+
+// ----------------------------------------------------------------
+
+bool
+usrp_basic::set_adc_offset (int which, int offset)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  return _write_fpga_reg (FR_ADC_OFFSET_0 + which, offset);
+}
+
+bool
+usrp_basic::set_dac_offset (int which, int offset, int offset_pin)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  int which_codec = which >> 1;
+  int tx_a = (which & 0x1) == 0;
+  int lo = ((offset & 0x3) << 6) | (offset_pin & 0x1);
+  int hi = (offset >> 2);
+  bool ok;
+
+  if (tx_a){
+    ok =  _write_9862 (which_codec, REG_TX_A_OFFSET_LO, lo);
+    ok &= _write_9862 (which_codec, REG_TX_A_OFFSET_HI, hi);
+  }
+  else {
+    ok =  _write_9862 (which_codec, REG_TX_B_OFFSET_LO, lo);
+    ok &= _write_9862 (which_codec, REG_TX_B_OFFSET_HI, hi);
+  }
+  return ok;
+}
+
+bool
+usrp_basic::set_adc_buffer_bypass (int which, bool bypass)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  int codec = which >> 1;
+  int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+  unsigned char cur_rx;
+  unsigned char cur_pwr_dn;
+
+  // If the input buffer is bypassed, we need to power it down too.
+
+  bool ok = _read_9862 (codec, reg, &cur_rx);
+  ok &= _read_9862 (codec, REG_RX_PWR_DN, &cur_pwr_dn);
+  if (!ok)
+    return false;
+
+  if (bypass){
+    cur_rx |= RX_X_BYPASS_INPUT_BUFFER;
+    cur_pwr_dn |= ((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B;
+  }
+  else {
+    cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER;
+    cur_pwr_dn &= ~(((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B);
+  }
+
+  ok &= _write_9862 (codec, reg, cur_rx);
+  ok &= _write_9862 (codec, REG_RX_PWR_DN, cur_pwr_dn);
+  return ok;
+}
+
+// ----------------------------------------------------------------
+
+bool
+usrp_basic::_write_fpga_reg (int regno, int value)
+{
+  if (d_verbose){
+    fprintf (stdout, "_write_fpga_reg(%3d, 0x%08x)\n", regno, value);
+    fflush (stdout);
+  }
+
+  if (regno >= 0 && regno < MAX_REGS)
+    d_fpga_shadows[regno] = value;
+
+  return usrp_write_fpga_reg (d_udh, regno, value);
+}
+
+bool
+usrp_basic::_write_fpga_reg_masked (int regno, int value, int mask)
+{
+  //Only use this for registers who actually use a mask in the verilog 
firmware, like FR_RX_MASTER_SLAVE
+  //value is a 16 bits value and mask is a 16 bits mask
+  if (d_verbose){
+    fprintf (stdout, "_write_fpga_reg_masked(%3d, 0x%04x,0x%04x)\n", regno, 
value, mask);
+    fflush (stdout);
+  }
+
+  if (regno >= 0 && regno < MAX_REGS)
+    d_fpga_shadows[regno] = value;
+
+  return usrp_write_fpga_reg (d_udh, regno, (value & 0xffff) | ((mask & 
0xffff)<<16));
+}
+
+
+bool
+usrp_basic::_read_fpga_reg (int regno, int *value)
+{
+  return usrp_read_fpga_reg (d_udh, regno, value);
+}
+
+int
+usrp_basic::_read_fpga_reg (int regno)
+{
+  int value;
+  if (!_read_fpga_reg (regno, &value))
+    return READ_FAILED;
+  return value;
+}
+
+bool
+usrp_basic::_write_9862 (int which_codec, int regno, unsigned char value)
+{
+  if (0 && d_verbose){
+    // FIXME really want to enable logging in usrp_prims:usrp_9862_write
+    fprintf(stdout, "_write_9862(codec = %d, regno = %2d, val = 0x%02x)\n", 
which_codec, regno, value);
+    fflush(stdout);
+  }
+
+  return usrp_9862_write (d_udh, which_codec, regno, value);
+}
+
+
+bool
+usrp_basic::_read_9862 (int which_codec, int regno, unsigned char *value) const
+{
+  return usrp_9862_read (d_udh, which_codec, regno, value);
+}
+
+int
+usrp_basic::_read_9862 (int which_codec, int regno) const
+{
+  unsigned char value;
+  if (!_read_9862 (which_codec, regno, &value))
+    return READ_FAILED;
+  return value;
+}
+
+bool
+usrp_basic::_write_spi (int optional_header, int enables, int format, 
std::string buf)
+{
+  return usrp_spi_write (d_udh, optional_header, enables, format,
+                        buf.data(), buf.size());
+}
+
+std::string
+usrp_basic::_read_spi (int optional_header, int enables, int format, int len)
+{
+  if (len <= 0)
+    return "";
+  
+  char buf[len];
+
+  if (!usrp_spi_read (d_udh, optional_header, enables, format, buf, len))
+    return "";
+
+  return std::string (buf, len);
+}
+
+
+bool
+usrp_basic::_set_led (int which, bool on)
+{
+  return usrp_set_led (d_udh, which, on);
+}
+
+////////////////////////////////////////////////////////////////
+//
+//                        usrp_basic_rx
+//
+////////////////////////////////////////////////////////////////
+
+static unsigned char rx_init_regs[] = {
+  REG_RX_PWR_DN,       0,
+  REG_RX_A,            0,      // minimum gain = 0x00 (max gain = 0x14)
+  REG_RX_B,            0,      // minimum gain = 0x00 (max gain = 0x14)
+  REG_RX_MISC,         (RX_MISC_HS_DUTY_CYCLE | RX_MISC_CLK_DUTY),
+  REG_RX_IF,           (RX_IF_USE_CLKOUT1
+                        | RX_IF_2S_COMP),
+  REG_RX_DIGITAL,      (RX_DIGITAL_2_CHAN)
+};
+
+
+usrp_basic_rx::usrp_basic_rx (int which_board, int fusb_block_size, int 
fusb_nblocks,
+                             const std::string fpga_filename,
+                             const std::string firmware_filename
+                             )
+  : usrp_basic (which_board, open_rx_interface, fpga_filename, 
firmware_filename),
+    d_devhandle (0), d_ephandle (0),
+    d_bytes_seen (0), d_first_read (true),
+    d_rx_enable (false)
+{
+  // initialize rx specific registers
+
+  if (!usrp_9862_write_many_all (d_udh, rx_init_regs, sizeof (rx_init_regs))){
+    fprintf (stderr, "usrp_basic_rx: failed to init AD9862 RX regs\n");
+    throw std::runtime_error ("usrp_basic_rx/init_9862");
+  }
+
+  if (0){
+    // FIXME power down 2nd codec rx path
+    usrp_9862_write (d_udh, 1, REG_RX_PWR_DN, 0x1);    // power down everything
+  }
+
+  // Reset the rx path and leave it disabled.
+  set_rx_enable (false);
+  usrp_set_fpga_rx_reset (d_udh, true);
+  usrp_set_fpga_rx_reset (d_udh, false);
+
+  set_fpga_rx_sample_rate_divisor (2); // usually correct
+
+  set_dc_offset_cl_enable(0xf, 0xf);   // enable DC offset removal control 
loops
+
+  probe_rx_slots (false);
+
+  // check fusb buffering parameters
+
+  if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_block_size");
+
+  if (fusb_nblocks < 0)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_nblocks");
+  
+  if (fusb_block_size == 0)
+    fusb_block_size = fusb_sysconfig::default_block_size();
+
+  if (fusb_nblocks == 0)
+    fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
+
+  d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+  d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true,
+                                          fusb_block_size, fusb_nblocks);
+
+  _write_fpga_reg(FR_ATR_MASK_1, 0);   // zero Rx side Auto Transmit/Receive 
regs
+  _write_fpga_reg(FR_ATR_TXVAL_1, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_1, 0);
+  _write_fpga_reg(FR_ATR_MASK_3, 0);
+  _write_fpga_reg(FR_ATR_TXVAL_3, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_3, 0);
+}
+
+static unsigned char rx_fini_regs[] = {
+  REG_RX_PWR_DN,       0x1                             // power down everything
+};
+
+usrp_basic_rx::~usrp_basic_rx ()
+{
+  if (!set_rx_enable (false)){
+    fprintf (stderr, "usrp_basic_rx: set_fpga_rx_enable failed\n");
+    usb_strerror ();
+  }
+
+  d_ephandle->stop ();
+  delete d_ephandle;
+  delete d_devhandle;
+
+  if (!usrp_9862_write_many_all (d_udh, rx_fini_regs, sizeof (rx_fini_regs))){
+    fprintf (stderr, "usrp_basic_rx: failed to fini AD9862 RX regs\n");
+  }
+}
+
+
+bool
+usrp_basic_rx::start ()
+{
+  if (!usrp_basic::start ())   // invoke parent's method
+    return false;
+
+  // fire off reads before asserting rx_enable
+
+  if (!d_ephandle->start ()){
+    fprintf (stderr, "usrp_basic_rx: failed to start end point streaming");
+    usb_strerror ();
+    return false;
+  }
+
+  if (!set_rx_enable (true)){
+    fprintf (stderr, "usrp_basic_rx: set_rx_enable failed\n");
+    usb_strerror ();
+    return false;
+  }
+  
+  return true;
+}
+
+bool
+usrp_basic_rx::stop ()
+{
+  bool ok = usrp_basic::stop();
+
+  if (!set_rx_enable(false)){
+    fprintf (stderr, "usrp_basic_rx: set_rx_enable(false) failed\n");
+    usb_strerror ();
+    ok = false;
+  }
+
+  if (!d_ephandle->stop()){
+    fprintf (stderr, "usrp_basic_rx: failed to stop end point streaming");
+    usb_strerror ();
+    ok = false;
+  }
+
+  return ok;
+}
+
+usrp_basic_rx *
+usrp_basic_rx::make (int which_board, int fusb_block_size, int fusb_nblocks,
+                    const std::string fpga_filename,
+                    const std::string firmware_filename)
+{
+  usrp_basic_rx *u = 0;
+  
+  try {
+    u = new usrp_basic_rx (which_board, fusb_block_size, fusb_nblocks,
+                          fpga_filename, firmware_filename);
+    return u;
+  }
+  catch (...){
+    delete u;
+    return 0;
+  }
+
+  return u;
+}
+
+bool
+usrp_basic_rx::set_fpga_rx_sample_rate_divisor (unsigned int div)
+{
+  return _write_fpga_reg (FR_RX_SAMPLE_RATE_DIV, div - 1);
+}
+
+
+/*
+ * \brief read data from the D/A's via the FPGA.
+ * \p len must be a multiple of 512 bytes.
+ *
+ * \returns the number of bytes read, or -1 on error.
+ *
+ * If overrun is non-NULL it will be set true iff an RX overrun is detected.
+ */
+int
+usrp_basic_rx::read (void *buf, int len, bool *overrun)
+{
+  int  r;
+  
+  if (overrun)
+    *overrun = false;
+  
+  if (len < 0 || (len % 512) != 0){
+    fprintf (stderr, "usrp_basic_rx::read: invalid length = %d\n", len);
+    return -1;
+  }
+
+  r = d_ephandle->read (buf, len);
+  if (r > 0)
+    d_bytes_seen += r;
+
+  /*
+   * In many cases, the FPGA reports an rx overrun right after we
+   * enable the Rx path.  If this is our first read, check for the
+   * overrun to clear the condition, then ignore the result.
+   */
+  if (0 && d_first_read){      // FIXME
+    d_first_read = false;
+    bool bogus_overrun;
+    usrp_check_rx_overrun (d_udh, &bogus_overrun);
+  }
+
+  if (overrun != 0 && d_bytes_seen >= d_bytes_per_poll){
+    d_bytes_seen = 0;
+    if (!usrp_check_rx_overrun (d_udh, overrun)){
+      fprintf (stderr, "usrp_basic_rx: usrp_check_rx_overrun failed\n");
+      usb_strerror ();
+    }
+  }
+    
+  return r;
+}
+
+bool
+usrp_basic_rx::set_rx_enable (bool on)
+{
+  d_rx_enable = on;
+  return usrp_set_fpga_rx_enable (d_udh, on);
+}
+
+// conditional disable, return prev state
+bool
+usrp_basic_rx::disable_rx ()
+{
+  bool enabled = rx_enable ();
+  if (enabled)
+    set_rx_enable (false);
+  return enabled;
+}
+
+// conditional set
+void
+usrp_basic_rx::restore_rx (bool on)
+{
+  if (on != rx_enable ())
+    set_rx_enable (on);
+}
+
+bool
+usrp_basic_rx::set_pga (int which, double gain)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  gain = std::max (pga_min (), gain);
+  gain = std::min (pga_max (), gain);
+
+  int codec = which >> 1;
+  int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+  // read current value to get input buffer bypass flag.
+  unsigned char cur_rx;
+  if (!_read_9862 (codec, reg, &cur_rx))
+    return false;
+
+  int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step());
+
+  cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f);
+  return _write_9862 (codec, reg, cur_rx);
+}
+
+double
+usrp_basic_rx::pga (int which) const
+{
+  if (which < 0 || which > 3)
+    return READ_FAILED;
+
+  int codec = which >> 1;
+  int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+  unsigned char v;
+  bool ok = _read_9862 (codec, reg, &v);
+  if (!ok)
+    return READ_FAILED;
+
+  return (pga_db_per_step() * (v & 0x1f)) + pga_min();
+}
+
+static int
+slot_id_to_oe_reg (int slot_id)
+{
+  static int reg[4]  = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 };
+  assert (0 <= slot_id && slot_id < 4);
+  return reg[slot_id];
+}
+
+static int
+slot_id_to_io_reg (int slot_id)
+{
+  static int reg[4]  = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 };
+  assert (0 <= slot_id && slot_id < 4);
+  return reg[slot_id];
+}
+
+void
+usrp_basic_rx::probe_rx_slots (bool verbose)
+{
+  struct usrp_dboard_eeprom    eeprom;
+  static int slot_id_map[2] = { SLOT_RX_A, SLOT_RX_B };
+  static const char *slot_name[2] = { "RX d'board A", "RX d'board B" };
+
+  for (int i = 0; i < 2; i++){
+    int slot_id = slot_id_map [i];
+    const char *msg = 0;
+    usrp_dbeeprom_status_t s = usrp_read_dboard_eeprom (d_udh, slot_id, 
&eeprom);
+
+    switch (s){
+    case UDBE_OK:
+      d_dbid[i] = eeprom.id;
+      msg = usrp_dbid_to_string (eeprom.id).c_str ();
+      set_adc_offset (2*i+0, eeprom.offset[0]);
+      set_adc_offset (2*i+1, eeprom.offset[1]);
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | eeprom.oe);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_NO_EEPROM:
+      d_dbid[i] = -1;
+      msg = "<none>";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_INVALID_EEPROM:
+      d_dbid[i] = -2;
+      msg = "Invalid EEPROM contents";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_BAD_SLOT:
+    default:
+      assert (0);
+    }
+
+    if (verbose){
+      fflush (stdout);
+      fprintf (stderr, "%s: %s\n", slot_name[i], msg);
+    }
+  }
+}
+
+bool
+usrp_basic_rx::_write_oe (int which_dboard, int value, int mask)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  return _write_fpga_reg (slot_id_to_oe_reg (dboard_to_slot (which_dboard)),
+                         (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_rx::write_io (int which_dboard, int value, int mask)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  return _write_fpga_reg (slot_id_to_io_reg (dboard_to_slot (which_dboard)),
+                         (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_rx::read_io (int which_dboard, int *value)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  int t;
+  int reg = which_dboard + 1;  // FIXME, *very* magic number (fix in 
serial_io.v)
+  bool ok = _read_fpga_reg (reg, &t);
+  if (!ok)
+    return false;
+
+  *value = (t >> 16) & 0xffff; // FIXME, more magic
+  return true;
+}
+
+int
+usrp_basic_rx::read_io (int which_dboard)
+{
+  int  value;
+  if (!read_io (which_dboard, &value))
+    return READ_FAILED;
+  return value;
+}
+
+bool
+usrp_basic_rx::write_aux_dac (int which_dboard, int which_dac, int value)
+{
+  return usrp_basic::write_aux_dac (dboard_to_slot (which_dboard),
+                                   which_dac, value);
+}
+
+bool
+usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc, int *value)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard),
+                                  which_adc, value);
+}
+
+int
+usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), which_adc);
+}
+
+int
+usrp_basic_rx::block_size () const { return d_ephandle->block_size(); }
+
+bool
+usrp_basic_rx::set_dc_offset_cl_enable(int bits, int mask)
+{
+  return _write_fpga_reg(FR_DC_OFFSET_CL_EN, 
+                        (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & 
mask));
+}
+
+////////////////////////////////////////////////////////////////
+//
+//                        usrp_basic_tx
+//
+////////////////////////////////////////////////////////////////
+
+
+//
+// DAC input rate 64 MHz interleaved for a total input rate of 128 MHz
+// DAC input is latched on rising edge of CLKOUT2
+// NCO is disabled
+// interpolate 2x
+// coarse modulator disabled
+//
+
+static unsigned char tx_init_regs[] = {
+  REG_TX_PWR_DN,       0,
+  REG_TX_A_OFFSET_LO,  0,
+  REG_TX_A_OFFSET_HI,  0,
+  REG_TX_B_OFFSET_LO,  0,
+  REG_TX_B_OFFSET_HI,  0,
+  REG_TX_A_GAIN,       (TX_X_GAIN_COARSE_FULL | 0),
+  REG_TX_B_GAIN,       (TX_X_GAIN_COARSE_FULL | 0),
+  REG_TX_PGA,          0xff,                   // maximum gain (0 dB)
+  REG_TX_MISC,         0,
+  REG_TX_IF,           (TX_IF_USE_CLKOUT1
+                        | TX_IF_I_FIRST
+                        | TX_IF_INV_TX_SYNC
+                        | TX_IF_2S_COMP
+                        | TX_IF_INTERLEAVED),
+  REG_TX_DIGITAL,      (TX_DIGITAL_2_DATA_PATHS
+                        | TX_DIGITAL_INTERPOLATE_4X),
+  REG_TX_MODULATOR,    (TX_MODULATOR_DISABLE_NCO
+                        | TX_MODULATOR_COARSE_MODULATION_NONE),
+  REG_TX_NCO_FTW_7_0,  0,
+  REG_TX_NCO_FTW_15_8, 0,
+  REG_TX_NCO_FTW_23_16,        0
+};
+
+usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int 
fusb_nblocks,
+                             const std::string fpga_filename,
+                             const std::string firmware_filename)
+  : usrp_basic (which_board, open_tx_interface, fpga_filename, 
firmware_filename),
+    d_devhandle (0), d_ephandle (0),
+    d_bytes_seen (0), d_first_write (true),
+    d_tx_enable (false)
+{
+  if (!usrp_9862_write_many_all (d_udh, tx_init_regs, sizeof (tx_init_regs))){
+    fprintf (stderr, "usrp_basic_tx: failed to init AD9862 TX regs\n");
+    throw std::runtime_error ("usrp_basic_tx/init_9862");
+  }
+
+  if (0){
+    // FIXME power down 2nd codec tx path
+    usrp_9862_write (d_udh, 1, REG_TX_PWR_DN,
+                    (TX_PWR_DN_TX_DIGITAL
+                     | TX_PWR_DN_TX_ANALOG_BOTH));
+  }
+
+  // Reset the tx path and leave it disabled.
+  set_tx_enable (false);
+  usrp_set_fpga_tx_reset (d_udh, true);
+  usrp_set_fpga_tx_reset (d_udh, false);
+
+  set_fpga_tx_sample_rate_divisor (4); // we're using interp x4
+
+  probe_tx_slots (false);
+
+  // check fusb buffering parameters
+
+  if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_block_size");
+
+  if (fusb_nblocks < 0)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_nblocks");
+  
+  if (fusb_block_size == 0)
+    fusb_block_size = FUSB_BLOCK_SIZE;
+
+  if (fusb_nblocks == 0)
+    fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
+
+  d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+  d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false,
+                                          fusb_block_size, fusb_nblocks);
+
+  _write_fpga_reg(FR_ATR_MASK_0, 0); // zero Tx side Auto Transmit/Receive regs
+  _write_fpga_reg(FR_ATR_TXVAL_0, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_0, 0);
+  _write_fpga_reg(FR_ATR_MASK_2, 0);
+  _write_fpga_reg(FR_ATR_TXVAL_2, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_2, 0);
+}
+
+
+static unsigned char tx_fini_regs[] = {
+  REG_TX_PWR_DN,       (TX_PWR_DN_TX_DIGITAL
+                        | TX_PWR_DN_TX_ANALOG_BOTH),
+  REG_TX_MODULATOR,    (TX_MODULATOR_DISABLE_NCO
+                        | TX_MODULATOR_COARSE_MODULATION_NONE)
+};
+
+usrp_basic_tx::~usrp_basic_tx ()
+{
+  d_ephandle->stop ();
+  delete d_ephandle;
+  delete d_devhandle;
+
+  if (!usrp_9862_write_many_all (d_udh, tx_fini_regs, sizeof (tx_fini_regs))){
+    fprintf (stderr, "usrp_basic_tx: failed to fini AD9862 TX regs\n");
+  }
+}
+
+bool
+usrp_basic_tx::start ()
+{
+  if (!usrp_basic::start ())
+    return false;
+
+  if (!set_tx_enable (true)){
+    fprintf (stderr, "usrp_basic_tx: set_tx_enable failed\n");
+    usb_strerror ();
+    return false;
+  }
+  
+  if (!d_ephandle->start ()){
+    fprintf (stderr, "usrp_basic_tx: failed to start end point streaming");
+    usb_strerror ();
+    return false;
+  }
+
+  return true;
+}
+
+bool
+usrp_basic_tx::stop ()
+{
+  bool ok = usrp_basic::stop ();
+
+  if (!d_ephandle->stop ()){
+    fprintf (stderr, "usrp_basic_tx: failed to stop end point streaming");
+    usb_strerror ();
+    ok = false;
+  }
+
+  if (!set_tx_enable (false)){
+    fprintf (stderr, "usrp_basic_tx: set_tx_enable(false) failed\n");
+    usb_strerror ();
+    ok = false;
+  }
+
+  return ok;
+}
+
+usrp_basic_tx *
+usrp_basic_tx::make (int which_board, int fusb_block_size, int fusb_nblocks,
+                    const std::string fpga_filename,
+                    const std::string firmware_filename)
+{
+  usrp_basic_tx *u = 0;
+  
+  try {
+    u = new usrp_basic_tx (which_board, fusb_block_size, fusb_nblocks,
+                          fpga_filename, firmware_filename);
+    return u;
+  }
+  catch (...){
+    delete u;
+    return 0;
+  }
+
+  return u;
+}
+
+bool
+usrp_basic_tx::set_fpga_tx_sample_rate_divisor (unsigned int div)
+{
+  return _write_fpga_reg (FR_TX_SAMPLE_RATE_DIV, div - 1);
+}
+
+/*!
+ * \brief Write data to the A/D's via the FPGA.
+ *
+ * \p len must be a multiple of 512 bytes.
+ * \returns number of bytes written or -1 on error.
+ *
+ * if \p underrun is non-NULL, it will be set to true iff
+ * a transmit underrun condition is detected.
+ */
+int
+usrp_basic_tx::write (const void *buf, int len, bool *underrun)
+{
+  int  r;
+  
+  if (underrun)
+    *underrun = false;
+  
+  if (len < 0 || (len % 512) != 0){
+    fprintf (stderr, "usrp_basic_tx::write: invalid length = %d\n", len);
+    return -1;
+  }
+
+  r = d_ephandle->write (buf, len);
+  if (r > 0)
+    d_bytes_seen += r;
+    
+  /*
+   * In many cases, the FPGA reports an tx underrun right after we
+   * enable the Tx path.  If this is our first write, check for the
+   * underrun to clear the condition, then ignore the result.
+   */
+  if (d_first_write && d_bytes_seen >= 4 * FUSB_BLOCK_SIZE){
+    d_first_write = false;
+    bool bogus_underrun;
+    usrp_check_tx_underrun (d_udh, &bogus_underrun);
+  }
+
+  if (underrun != 0 && d_bytes_seen >= d_bytes_per_poll){
+    d_bytes_seen = 0;
+    if (!usrp_check_tx_underrun (d_udh, underrun)){
+      fprintf (stderr, "usrp_basic_tx: usrp_check_tx_underrun failed\n");
+      usb_strerror ();
+    }
+  }
+
+  return r;
+}
+
+void
+usrp_basic_tx::wait_for_completion ()
+{
+  d_ephandle->wait_for_completion ();
+}
+
+bool
+usrp_basic_tx::set_tx_enable (bool on)
+{
+  d_tx_enable = on;
+  // fprintf (stderr, "set_tx_enable %d\n", on);
+  return usrp_set_fpga_tx_enable (d_udh, on);
+}
+
+// conditional disable, return prev state
+bool
+usrp_basic_tx::disable_tx ()
+{
+  bool enabled = tx_enable ();
+  if (enabled)
+    set_tx_enable (false);
+  return enabled;
+}
+
+// conditional set
+void
+usrp_basic_tx::restore_tx (bool on)
+{
+  if (on != tx_enable ())
+    set_tx_enable (on);
+}
+
+bool
+usrp_basic_tx::set_pga (int which, double gain)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  gain = std::max (pga_min (), gain);
+  gain = std::min (pga_max (), gain);
+
+  int codec = which >> 1;      // 0 and 1 are same, as are 2 and 3
+
+  int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step());
+
+  return _write_9862 (codec, REG_TX_PGA, int_gain);
+}
+
+double
+usrp_basic_tx::pga (int which) const
+{
+  if (which < 0 || which > 3)
+    return READ_FAILED;
+
+  int codec = which >> 1;
+  unsigned char v;
+  bool ok = _read_9862 (codec, REG_TX_PGA, &v);
+  if (!ok)
+    return READ_FAILED;
+
+  return (pga_db_per_step() * v) + pga_min();
+}
+
+void
+usrp_basic_tx::probe_tx_slots (bool verbose)
+{
+  struct usrp_dboard_eeprom    eeprom;
+  static int slot_id_map[2] = { SLOT_TX_A, SLOT_TX_B };
+  static const char *slot_name[2] = { "TX d'board A", "TX d'board B" };
+
+  for (int i = 0; i < 2; i++){
+    int slot_id = slot_id_map [i];
+    const char *msg = 0;
+    usrp_dbeeprom_status_t s = usrp_read_dboard_eeprom (d_udh, slot_id, 
&eeprom);
+
+    switch (s){
+    case UDBE_OK:
+      d_dbid[i] = eeprom.id;
+      msg = usrp_dbid_to_string (eeprom.id).c_str ();
+      // FIXME, figure out interpretation of dc offset for TX d'boards
+      // offset = (eeprom.offset[1] << 16) | (eeprom.offset[0] & 0xffff);
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | eeprom.oe);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_NO_EEPROM:
+      d_dbid[i] = -1;
+      msg = "<none>";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_INVALID_EEPROM:
+      d_dbid[i] = -2;
+      msg = "Invalid EEPROM contents";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_BAD_SLOT:
+    default:
+      assert (0);
+    }
+
+    if (verbose){
+      fflush (stdout);
+      fprintf (stderr, "%s: %s\n", slot_name[i], msg);
+    }
+  }
+}
+
+bool
+usrp_basic_tx::_write_oe (int which_dboard, int value, int mask)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  return _write_fpga_reg (slot_id_to_oe_reg (dboard_to_slot (which_dboard)),
+                         (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_tx::write_io (int which_dboard, int value, int mask)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  return _write_fpga_reg (slot_id_to_io_reg (dboard_to_slot (which_dboard)),
+                         (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_tx::read_io (int which_dboard, int *value)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  int t;
+  int reg = which_dboard + 1;  // FIXME, *very* magic number (fix in 
serial_io.v)
+  bool ok = _read_fpga_reg (reg, &t);
+  if (!ok)
+    return false;
+
+  *value = t & 0xffff;         // FIXME, more magic
+  return true;
+}
+
+int
+usrp_basic_tx::read_io (int which_dboard)
+{
+  int  value;
+  if (!read_io (which_dboard, &value))
+    return READ_FAILED;
+  return value;
+}
+
+bool
+usrp_basic_tx::write_aux_dac (int which_dboard, int which_dac, int value)
+{
+  return usrp_basic::write_aux_dac (dboard_to_slot (which_dboard),
+                                   which_dac, value);
+}
+
+bool
+usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc, int *value)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard),
+                                  which_adc, value);
+}
+
+int
+usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), which_adc);
+}
+
+int
+usrp_basic_tx::block_size () const { return d_ephandle->block_size(); }
+

Copied: 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc.prev
 (from rev 9736, 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc)
===================================================================
--- 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc.prev
                           (rev 0)
+++ 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.cc.prev
   2008-10-08 03:53:42 UTC (rev 9742)
@@ -0,0 +1,1512 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,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 version 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_basic.h"
+#include "usrp_prims.h"
+#include "usrp_interfaces.h"
+#include "fpga_regs_common.h"
+#include "fusb.h"
+#include <usb.h>
+#include <stdexcept>
+#include <assert.h>
+#include <math.h>
+#include <ad9862.h>
+#include <string.h>
+#include <db_boards.h>
+
+using namespace ad9862;
+
+#define NELEM(x) (sizeof (x) / sizeof (x[0]))
+
+// These set the buffer size used for each end point using the fast
+// usb interface.  The kernel ends up locking down this much memory.
+
+static const int FUSB_BUFFER_SIZE = fusb_sysconfig::default_buffer_size();
+static const int FUSB_BLOCK_SIZE = fusb_sysconfig::max_block_size();
+static const int FUSB_NBLOCKS    = FUSB_BUFFER_SIZE / FUSB_BLOCK_SIZE;
+
+
+static const double POLLING_INTERVAL = 0.1;    // seconds
+
+////////////////////////////////////////////////////////////////
+
+static struct usb_dev_handle *
+open_rx_interface (struct usb_device *dev)
+{
+  struct usb_dev_handle *udh = usrp_open_rx_interface (dev);
+  if (udh == 0){
+    fprintf (stderr, "usrp_basic_rx: can't open rx interface\n");
+    usb_strerror ();
+  }
+  return udh;
+}
+
+static struct usb_dev_handle *
+open_tx_interface (struct usb_device *dev)
+{
+  struct usb_dev_handle *udh = usrp_open_tx_interface (dev);
+  if (udh == 0){
+    fprintf (stderr, "usrp_basic_tx: can't open tx interface\n");
+    usb_strerror ();
+  }
+  return udh;
+}
+
+
+static int
+slot_id_to_oe_reg (int slot_id)
+{
+  static int reg[4]  = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 };
+  assert (0 <= slot_id && slot_id < 4);
+  return reg[slot_id];
+}
+
+static int
+slot_id_to_io_reg (int slot_id)
+{
+  static int reg[4]  = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 };
+  assert (0 <= slot_id && slot_id < 4);
+  return reg[slot_id];
+}
+
+struct dxc_freq_t
+calc_dxc_freq(float target_freq, float baseband_freq, long fs)
+{
+  /*
+    Calculate the frequency to use for setting the digital up or down 
converter.
+    
+    @param target_freq: desired RF frequency (Hz)
+    @type  target_freq: number
+    @param baseband_freq: the RF frequency that corresponds to DC in the IF.
+    @type  baseband_freq: number
+    @param fs: converter sample rate
+    @type  fs: number
+    
+    @returns: 2-tuple (ddc_freq, inverted) where ddc_freq is the value
+      for the ddc and inverted is True if we're operating in an inverted
+      Nyquist zone.
+  */
+
+  struct dxc_freq_t ret;
+  float delta = target_freq - baseband_freq;
+    
+  if(delta >= 0) {
+    while(delta > fs) {
+      delta -= fs;
+    }
+    if(delta <= fs/2) {
+      ret.inverted = false;
+      ret.ddc_freq = -delta;       // non-inverted region
+      return ret;
+    }
+    else {
+      ret.inverted = true;
+      ret.ddc_freq = delta - fs;   // inverted region
+      return ret;
+    }
+  }
+  else {
+    while(delta < -fs) {
+      delta += fs;
+    }
+    if(delta >= -fs/2) {
+      ret.inverted = false;
+      ret.ddc_freq = -delta;       // non-inverted region
+      return ret;
+    }
+    else {
+      ret.inverted = true;
+      ret.ddc_freq = delta+fs;     // inverted region
+      return ret;
+    }
+  }
+}
+
+
+//////////////////////////////////////////////////////////////////
+//
+//                     usrp_basic
+//
+////////////////////////////////////////////////////////////////
+
+
+// Given:
+//   CLKIN = 64 MHz
+//   CLKSEL pin = high 
+//
+// These settings give us:
+//   CLKOUT1 = CLKIN = 64 MHz
+//   CLKOUT2 = CLKIN = 64 MHz
+//   ADC is clocked at  64 MHz
+//   DAC is clocked at 128 MHz
+
+static unsigned char common_regs[] = {
+  REG_GENERAL,         0,
+  REG_DLL,             (DLL_DISABLE_INTERNAL_XTAL_OSC
+                        | DLL_MULT_2X
+                        | DLL_FAST),
+  REG_CLKOUT,          CLKOUT2_EQ_DLL_OVER_2,
+  REG_AUX_ADC_CLK,     AUX_ADC_CLK_CLK_OVER_4
+};
+
+
+usrp_basic::usrp_basic (int which_board, 
+                       struct usb_dev_handle *
+                       open_interface (struct usb_device *dev),
+                       const std::string fpga_filename,
+                       const std::string firmware_filename,
+                       bool tx)
+  : d_udh (0),
+    d_usb_data_rate (16000000),        // SWAG, see below
+    d_bytes_per_poll ((int) (POLLING_INTERVAL * d_usb_data_rate)),
+    d_verbose (false),
+    d_tx(tx)
+{
+  /*
+   * SWAG: Scientific Wild Ass Guess.
+   *
+   * d_usb_data_rate is used only to determine how often to poll for over- and 
under-runs.
+   * We defualt it to 1/2  of our best case.  Classes derived from usrp_basic 
(e.g., 
+   * usrp_standard_tx and usrp_standard_rx) call set_usb_data_rate() to tell 
us the
+   * actual rate.  This doesn't change our throughput, that's determined by 
the signal
+   * processing code in the FPGA (which we know nothing about), and the system 
limits
+   * determined by libusb, fusb_*, and the underlying drivers.
+   */
+  memset (d_fpga_shadows, 0, sizeof (d_fpga_shadows));
+
+  d_db.resize(4);
+
+  usrp_one_time_init ();
+
+  if (!usrp_load_standard_bits (which_board, false, fpga_filename, 
firmware_filename))
+    throw std::runtime_error ("usrp_basic/usrp_load_standard_bits");
+
+  struct usb_device *dev = usrp_find_device (which_board);
+  if (dev == 0){
+    fprintf (stderr, "usrp_basic: can't find usrp[%d]\n", which_board);
+    throw std::runtime_error ("usrp_basic/usrp_find_device");
+  }
+
+  if (!(usrp_usrp_p(dev) && usrp_hw_rev(dev) >= 1)){
+    fprintf (stderr, "usrp_basic: sorry, this code only works with USRP revs 
>= 1\n");
+    throw std::runtime_error ("usrp_basic/bad_rev");
+  }
+
+  if ((d_udh = open_interface (dev)) == 0)
+    throw std::runtime_error ("usrp_basic/open_interface");
+
+  // initialize registers that are common to rx and tx
+
+  if (!usrp_9862_write_many_all (d_udh, common_regs, sizeof (common_regs))){
+    fprintf (stderr, "usrp_basic: failed to init common AD9862 regs\n");
+    throw std::runtime_error ("usrp_basic/init_9862");
+  }
+
+  _write_fpga_reg (FR_MODE, 0);                // ensure we're in normal mode
+  _write_fpga_reg (FR_DEBUG_EN, 0);    // disable debug outputs
+}
+
+usrp_basic::~usrp_basic ()
+{
+  d_db.resize(0);  // kill refs to daughterboards before closing USB
+  if (d_udh)
+    usb_close (d_udh);
+}
+
+int
+usrp_basic::dboard_to_slot (txrx_t tx, int dboard)
+{
+  // tx=(0,2) rx=(1,3)
+  return (dboard << 1) | (tx^1); 
+}
+
+std::vector< std::vector<db_base_sptr> >
+usrp_basic::db()
+{
+  return d_db;
+}
+
+std::vector<db_base_sptr> 
+usrp_basic::db(int which)
+{
+  if(which > 3) {
+    throw std::invalid_argument("usrp_basic::db which must be 0, 1, 2, or 3");
+  }
+  return d_db[which];
+}
+
+int
+usrp_basic::common_daughterboard_id (txrx_t tx, int which_dboard) const 
+{ 
+  return d_dbid[(which_dboard << 1) | (tx^1)];
+}
+
+int
+usrp_basic::daughterboard_id (int which_dboard) const 
+{ 
+  throw std::runtime_error("daughterboard_id called from usrp_basic.\n");
+}
+
+/********************************************
+  PGA functions
+********************************************/
+
+bool
+usrp_basic::set_pga(int which, double gain)
+{
+  if(d_tx) {
+    return set_tx_pga(which, gain);
+  }
+  else {
+    return set_rx_pga(which, gain);
+  }
+}
+
+bool
+usrp_basic::set_tx_pga (int which, double gain)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  gain = std::max (pga_min (), gain);
+  gain = std::min (pga_max (), gain);
+
+  int codec = which >> 1;      // 0 and 1 are same, as are 2 and 3
+
+  int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step());
+
+  return _write_9862 (codec, REG_TX_PGA, int_gain);
+}
+
+bool
+usrp_basic::set_rx_pga (int which, double gain)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  gain = std::max (pga_min (), gain);
+  gain = std::min (pga_max (), gain);
+
+  int codec = which >> 1;
+  int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+  // read current value to get input buffer bypass flag.
+  unsigned char cur_rx;
+  if (!_read_9862 (codec, reg, &cur_rx))
+    return false;
+
+  int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step());
+
+  cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f);
+  return _write_9862 (codec, reg, cur_rx);
+}
+
+double 
+usrp_basic::pga_min () const
+{
+  if(d_tx) {
+    return pga_tx_min();
+  }
+  else {
+    return pga_rx_min();
+  }
+}
+
+double 
+usrp_basic::pga_max () const
+{
+  if(d_tx) {
+    return pga_tx_max();
+  }
+  else {
+    return pga_rx_max();
+  }
+}
+
+double 
+usrp_basic::pga (int which) const
+{
+  if(d_tx) {
+    return pga_tx(which);
+  }
+  else {
+    return pga_rx(which);
+  }
+}
+
+double
+usrp_basic::pga_rx (int which) const
+{
+  if (which < 0 || which > 3)
+    return READ_FAILED;
+
+  int codec = which >> 1;
+  int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+  unsigned char v;
+  bool ok = _read_9862 (codec, reg, &v);
+  if (!ok)
+    return READ_FAILED;
+
+  return (pga_db_per_step() * (v & 0x1f)) + pga_min();
+}
+
+double
+usrp_basic::pga_tx (int which) const
+{
+  if (which < 0 || which > 3)
+    return READ_FAILED;
+
+  int codec = which >> 1;
+  unsigned char v;
+  bool ok = _read_9862 (codec, REG_TX_PGA, &v);
+  if (!ok)
+    return READ_FAILED;
+
+  return (pga_db_per_step() * v) + pga_min();
+}
+
+double
+usrp_basic::pga_db_per_step () const
+{
+  if(d_tx) {
+    return pga_tx_db_per_step();
+  }
+  else {
+    return pga_rx_db_per_step();
+  }  
+}
+
+/*****************************************************/
+
+
+bool
+usrp_basic::start ()
+{
+  return true;         // nop
+}
+
+bool
+usrp_basic::stop ()
+{
+  return true;         // nop
+}
+
+void
+usrp_basic::set_usb_data_rate (int usb_data_rate)
+{
+  d_usb_data_rate = usb_data_rate;
+  d_bytes_per_poll = (int) (usb_data_rate * POLLING_INTERVAL);
+}
+
+bool
+usrp_basic::write_aux_dac (int slot, int which_dac, int value)
+{
+  return usrp_write_aux_dac (d_udh, slot, which_dac, value);
+}
+
+bool
+usrp_basic::read_aux_adc (int slot, int which_adc, int *value)
+{
+  return usrp_read_aux_adc (d_udh, slot, which_adc, value);
+}
+
+int
+usrp_basic::read_aux_adc (int slot, int which_adc)
+{
+  int  value;
+  if (!read_aux_adc (slot, which_adc, &value))
+    return READ_FAILED;
+
+  return value;
+}
+
+bool
+usrp_basic::write_eeprom (int i2c_addr, int eeprom_offset, const std::string 
buf)
+{
+  return usrp_eeprom_write (d_udh, i2c_addr, eeprom_offset, buf.data (), 
buf.size ());
+}
+
+std::string
+usrp_basic::read_eeprom (int i2c_addr, int eeprom_offset, int len)
+{
+  if (len <= 0)
+    return "";
+
+  char buf[len];
+
+  if (!usrp_eeprom_read (d_udh, i2c_addr, eeprom_offset, buf, len))
+    return "";
+
+  return std::string (buf, len);
+}
+
+bool
+usrp_basic::write_i2c (int i2c_addr, const std::string buf)
+{
+  return usrp_i2c_write (d_udh, i2c_addr, buf.data (), buf.size ());
+}
+
+std::string
+usrp_basic::read_i2c (int i2c_addr, int len)
+{
+  if (len <= 0)
+    return "";
+
+  char buf[len];
+
+  if (!usrp_i2c_read (d_udh, i2c_addr, buf, len))
+    return "";
+
+  return std::string (buf, len);
+}
+
+std::string
+usrp_basic::serial_number()
+{
+  return usrp_serial_number(d_udh);
+}
+
+// ----------------------------------------------------------------
+
+bool
+usrp_basic::set_adc_offset (int which, int offset)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  return _write_fpga_reg (FR_ADC_OFFSET_0 + which, offset);
+}
+
+bool
+usrp_basic::set_dac_offset (int which, int offset, int offset_pin)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  int which_codec = which >> 1;
+  int tx_a = (which & 0x1) == 0;
+  int lo = ((offset & 0x3) << 6) | (offset_pin & 0x1);
+  int hi = (offset >> 2);
+  bool ok;
+
+  if (tx_a){
+    ok =  _write_9862 (which_codec, REG_TX_A_OFFSET_LO, lo);
+    ok &= _write_9862 (which_codec, REG_TX_A_OFFSET_HI, hi);
+  }
+  else {
+    ok =  _write_9862 (which_codec, REG_TX_B_OFFSET_LO, lo);
+    ok &= _write_9862 (which_codec, REG_TX_B_OFFSET_HI, hi);
+  }
+  return ok;
+}
+
+bool
+usrp_basic::set_adc_buffer_bypass (int which, bool bypass)
+{
+  if (which < 0 || which > 3)
+    return false;
+
+  int codec = which >> 1;
+  int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+  unsigned char cur_rx;
+  unsigned char cur_pwr_dn;
+
+  // If the input buffer is bypassed, we need to power it down too.
+
+  bool ok = _read_9862 (codec, reg, &cur_rx);
+  ok &= _read_9862 (codec, REG_RX_PWR_DN, &cur_pwr_dn);
+  if (!ok)
+    return false;
+
+  if (bypass){
+    cur_rx |= RX_X_BYPASS_INPUT_BUFFER;
+    cur_pwr_dn |= ((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B;
+  }
+  else {
+    cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER;
+    cur_pwr_dn &= ~(((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B);
+  }
+
+  ok &= _write_9862 (codec, reg, cur_rx);
+  ok &= _write_9862 (codec, REG_RX_PWR_DN, cur_pwr_dn);
+  return ok;
+}
+
+// ----------------------------------------------------------------
+
+bool
+usrp_basic::_write_fpga_reg (int regno, int value)
+{
+  if (d_verbose){
+    fprintf (stdout, "_write_fpga_reg(%3d, 0x%08x)\n", regno, value);
+    fflush (stdout);
+  }
+
+  if (regno >= 0 && regno < MAX_REGS)
+    d_fpga_shadows[regno] = value;
+
+  return usrp_write_fpga_reg (d_udh, regno, value);
+}
+
+bool
+usrp_basic::_write_fpga_reg_masked (int regno, int value, int mask)
+{
+  //Only use this for registers who actually use a mask in the verilog 
firmware, like FR_RX_MASTER_SLAVE
+  //value is a 16 bits value and mask is a 16 bits mask
+  if (d_verbose){
+    fprintf (stdout, "_write_fpga_reg_masked(%3d, 0x%04x,0x%04x)\n", regno, 
value, mask);
+    fflush (stdout);
+  }
+
+  if (regno >= 0 && regno < MAX_REGS)
+    d_fpga_shadows[regno] = value;
+
+  return usrp_write_fpga_reg (d_udh, regno, (value & 0xffff) | ((mask & 
0xffff)<<16));
+}
+
+
+bool
+usrp_basic::_read_fpga_reg (int regno, int *value)
+{
+  return usrp_read_fpga_reg (d_udh, regno, value);
+}
+
+int
+usrp_basic::_read_fpga_reg (int regno)
+{
+  int value;
+  if (!_read_fpga_reg (regno, &value))
+    return READ_FAILED;
+  return value;
+}
+
+bool
+usrp_basic::_write_9862 (int which_codec, int regno, unsigned char value)
+{
+  if (0 && d_verbose){
+    // FIXME really want to enable logging in usrp_prims:usrp_9862_write
+    fprintf(stdout, "_write_9862(codec = %d, regno = %2d, val = 0x%02x)\n", 
which_codec, regno, value);
+    fflush(stdout);
+  }
+
+  return usrp_9862_write (d_udh, which_codec, regno, value);
+}
+
+
+bool
+usrp_basic::_read_9862 (int which_codec, int regno, unsigned char *value) const
+{
+  return usrp_9862_read (d_udh, which_codec, regno, value);
+}
+
+int
+usrp_basic::_read_9862 (int which_codec, int regno) const
+{
+  unsigned char value;
+  if (!_read_9862 (which_codec, regno, &value))
+    return READ_FAILED;
+  return value;
+}
+
+bool
+usrp_basic::_write_spi (int optional_header, int enables, int format, 
std::string buf)
+{
+  return usrp_spi_write (d_udh, optional_header, enables, format,
+                        buf.data(), buf.size());
+}
+
+std::string
+usrp_basic::_read_spi (int optional_header, int enables, int format, int len)
+{
+  if (len <= 0)
+    return "";
+  
+  char buf[len];
+
+  if (!usrp_spi_read (d_udh, optional_header, enables, format, buf, len))
+    return "";
+
+  return std::string (buf, len);
+}
+
+bool
+usrp_basic::_common_write_oe (txrx_t tx, int which_dboard, int value, int mask)
+{
+
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  return _write_fpga_reg (slot_id_to_oe_reg (dboard_to_slot (tx, 
which_dboard)),
+                         (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic::_write_oe (int which_dboard, int value, int mask)
+{
+  throw std::runtime_error("_write_oe called from usrp_basic.\n");
+}
+
+bool
+usrp_basic::common_write_io (txrx_t tx, int which_dboard, int value, int mask)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  return _write_fpga_reg (slot_id_to_io_reg (dboard_to_slot (tx, 
which_dboard)),
+                         (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic::write_io (int which_dboard, int value, int mask)
+{
+  throw std::runtime_error("write_io called from usrp_basic.\n");
+}
+
+bool
+usrp_basic::common_read_io (txrx_t tx, int which_dboard, int *value)
+{
+  if (! (0 <= which_dboard && which_dboard <= 1))
+    return false;
+
+  int t;
+  int reg = which_dboard + 1;  // FIXME, *very* magic number (fix in 
serial_io.v)
+  bool ok = _read_fpga_reg (reg, &t);
+  if (!ok)
+    return false;
+
+  // FIXME, more magic
+  if(tx) {
+    *value = t & 0xffff;       
+  }
+  else {
+    *value = (t >> 16) & 0xffff;
+  }
+  return true;
+}
+
+bool
+usrp_basic::read_io (int which_dboard, int *value)
+{
+  throw std::runtime_error("read_io called from usrp_basic.\n");
+}
+
+int
+usrp_basic::read_io (int which_dboard)
+{
+  throw std::runtime_error("read_io called from usrp_basic.\n");
+}
+
+bool
+usrp_basic::_set_led (int which, bool on)
+{
+  return usrp_set_led (d_udh, which, on);
+}
+
+////////////////////////////////////////////////////////////////
+//
+//                        usrp_basic_rx
+//
+////////////////////////////////////////////////////////////////
+
+static unsigned char rx_init_regs[] = {
+  REG_RX_PWR_DN,       0,
+  REG_RX_A,            0,      // minimum gain = 0x00 (max gain = 0x14)
+  REG_RX_B,            0,      // minimum gain = 0x00 (max gain = 0x14)
+  REG_RX_MISC,         (RX_MISC_HS_DUTY_CYCLE | RX_MISC_CLK_DUTY),
+  REG_RX_IF,           (RX_IF_USE_CLKOUT1
+                        | RX_IF_2S_COMP),
+  REG_RX_DIGITAL,      (RX_DIGITAL_2_CHAN)
+};
+
+
+usrp_basic_rx::usrp_basic_rx (int which_board, int fusb_block_size, int 
fusb_nblocks,
+                             const std::string fpga_filename,
+                             const std::string firmware_filename
+                             )
+  : usrp_basic (which_board, open_rx_interface, fpga_filename, 
firmware_filename, false),
+    d_devhandle (0), d_ephandle (0),
+    d_bytes_seen (0), d_first_read (true),
+    d_rx_enable (false)
+{
+  // initialize rx specific registers
+
+  if (!usrp_9862_write_many_all (d_udh, rx_init_regs, sizeof (rx_init_regs))){
+    fprintf (stderr, "usrp_basic_rx: failed to init AD9862 RX regs\n");
+    throw std::runtime_error ("usrp_basic_rx/init_9862");
+  }
+
+  if (0){
+    // FIXME power down 2nd codec rx path
+    usrp_9862_write (d_udh, 1, REG_RX_PWR_DN, 0x1);    // power down everything
+  }
+
+  // Reset the rx path and leave it disabled.
+  set_rx_enable (false);
+  usrp_set_fpga_rx_reset (d_udh, true);
+  usrp_set_fpga_rx_reset (d_udh, false);
+
+  set_fpga_rx_sample_rate_divisor (2); // usually correct
+
+  set_dc_offset_cl_enable(0xf, 0xf);   // enable DC offset removal control 
loops
+
+  probe_rx_slots (false);
+  d_db[SLOT_RX_A] = instantiate_dbs(d_dbid[SLOT_RX_A], this, 0);
+  d_db[SLOT_RX_B] = instantiate_dbs(d_dbid[SLOT_RX_B], this, 1);
+
+  // check fusb buffering parameters
+
+  if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_block_size");
+
+  if (fusb_nblocks < 0)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_nblocks");
+  
+  if (fusb_block_size == 0)
+    fusb_block_size = fusb_sysconfig::default_block_size();
+
+  if (fusb_nblocks == 0)
+    fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
+
+  d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+  d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true,
+                                          fusb_block_size, fusb_nblocks);
+
+  _write_fpga_reg(FR_ATR_MASK_1, 0);   // zero Rx side Auto Transmit/Receive 
regs
+  _write_fpga_reg(FR_ATR_TXVAL_1, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_1, 0);
+  _write_fpga_reg(FR_ATR_MASK_3, 0);
+  _write_fpga_reg(FR_ATR_TXVAL_3, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_3, 0);
+}
+
+static unsigned char rx_fini_regs[] = {
+  REG_RX_PWR_DN,       0x1                             // power down everything
+};
+
+usrp_basic_rx::~usrp_basic_rx ()
+{
+  if (!set_rx_enable (false)){
+    fprintf (stderr, "usrp_basic_rx: set_fpga_rx_enable failed\n");
+    usb_strerror ();
+  }
+
+  d_ephandle->stop ();
+  delete d_ephandle;
+  delete d_devhandle;
+
+  if (!usrp_9862_write_many_all (d_udh, rx_fini_regs, sizeof (rx_fini_regs))){
+    fprintf (stderr, "usrp_basic_rx: failed to fini AD9862 RX regs\n");
+  }
+}
+
+int
+usrp_basic_rx::daughterboard_id (int which_dboard) const 
+{ 
+  return common_daughterboard_id(C_RX, which_dboard);
+}
+
+
+std::vector< std::vector<db_base_sptr> >
+usrp_basic_rx::db()
+{
+  // When called from here, only return if the RX side
+  std::vector< std::vector<db_base_sptr> > ret;
+  ret.push_back(d_db[SLOT_RX_A]);
+  ret.push_back(d_db[SLOT_RX_B]);
+  return ret;
+}
+
+std::vector<db_base_sptr> 
+usrp_basic_rx::db(int which)
+{
+  // When called from here, only return if the RX side
+  if(which == 0) {
+    return d_db[SLOT_RX_A];
+  }
+  else {
+    return d_db[SLOT_RX_B];
+  }
+}
+
+bool 
+usrp_basic_rx::_write_oe (int which_dboard, int value, int mask)
+{
+  return _common_write_oe(C_RX, which_dboard, value, mask);
+}
+
+bool
+usrp_basic_rx::write_io (int which_dboard, int value, int mask)
+{
+  return common_write_io(C_RX, which_dboard, value, mask);
+}
+
+bool
+usrp_basic_rx::read_io (int which_dboard, int *value)
+{
+  return common_read_io(C_RX, which_dboard, value);
+}
+
+int
+usrp_basic_rx::read_io (int which_dboard)
+{
+  int value;
+  common_read_io(C_RX, which_dboard, &value);
+  return value;
+}
+
+
+bool
+usrp_basic_rx::start ()
+{
+  if (!usrp_basic::start ())   // invoke parent's method
+    return false;
+
+  // fire off reads before asserting rx_enable
+
+  if (!d_ephandle->start ()){
+    fprintf (stderr, "usrp_basic_rx: failed to start end point streaming");
+    usb_strerror ();
+    return false;
+  }
+
+  if (!set_rx_enable (true)){
+    fprintf (stderr, "usrp_basic_rx: set_rx_enable failed\n");
+    usb_strerror ();
+    return false;
+  }
+  
+  return true;
+}
+
+bool
+usrp_basic_rx::stop ()
+{
+  bool ok = usrp_basic::stop();
+
+  if (!set_rx_enable(false)){
+    fprintf (stderr, "usrp_basic_rx: set_rx_enable(false) failed\n");
+    usb_strerror ();
+    ok = false;
+  }
+
+  if (!d_ephandle->stop()){
+    fprintf (stderr, "usrp_basic_rx: failed to stop end point streaming");
+    usb_strerror ();
+    ok = false;
+  }
+
+  return ok;
+}
+
+usrp_basic_rx *
+usrp_basic_rx::make (int which_board, int fusb_block_size, int fusb_nblocks,
+                    const std::string fpga_filename,
+                    const std::string firmware_filename)
+{
+  usrp_basic_rx *u = 0;
+  
+  try {
+    u = new usrp_basic_rx (which_board, fusb_block_size, fusb_nblocks,
+                          fpga_filename, firmware_filename);
+    return u;
+  }
+  catch (...){
+    delete u;
+    return 0;
+  }
+
+  return u;
+}
+
+bool
+usrp_basic_rx::set_fpga_rx_sample_rate_divisor (unsigned int div)
+{
+  return _write_fpga_reg (FR_RX_SAMPLE_RATE_DIV, div - 1);
+}
+
+
+/*
+ * \brief read data from the D/A's via the FPGA.
+ * \p len must be a multiple of 512 bytes.
+ *
+ * \returns the number of bytes read, or -1 on error.
+ *
+ * If overrun is non-NULL it will be set true iff an RX overrun is detected.
+ */
+int
+usrp_basic_rx::read (void *buf, int len, bool *overrun)
+{
+  int  r;
+  
+  if (overrun)
+    *overrun = false;
+  
+  if (len < 0 || (len % 512) != 0){
+    fprintf (stderr, "usrp_basic_rx::read: invalid length = %d\n", len);
+    return -1;
+  }
+
+  r = d_ephandle->read (buf, len);
+  if (r > 0)
+    d_bytes_seen += r;
+
+  /*
+   * In many cases, the FPGA reports an rx overrun right after we
+   * enable the Rx path.  If this is our first read, check for the
+   * overrun to clear the condition, then ignore the result.
+   */
+  if (0 && d_first_read){      // FIXME
+    d_first_read = false;
+    bool bogus_overrun;
+    usrp_check_rx_overrun (d_udh, &bogus_overrun);
+  }
+
+  if (overrun != 0 && d_bytes_seen >= d_bytes_per_poll){
+    d_bytes_seen = 0;
+    if (!usrp_check_rx_overrun (d_udh, overrun)){
+      fprintf (stderr, "usrp_basic_rx: usrp_check_rx_overrun failed\n");
+      usb_strerror ();
+    }
+  }
+    
+  return r;
+}
+
+bool
+usrp_basic_rx::set_rx_enable (bool on)
+{
+  d_rx_enable = on;
+  return usrp_set_fpga_rx_enable (d_udh, on);
+}
+
+// conditional disable, return prev state
+bool
+usrp_basic_rx::disable_rx ()
+{
+  bool enabled = rx_enable ();
+  if (enabled)
+    set_rx_enable (false);
+  return enabled;
+}
+
+// conditional set
+void
+usrp_basic_rx::restore_rx (bool on)
+{
+  if (on != rx_enable ())
+    set_rx_enable (on);
+}
+
+bool
+usrp_basic_rx::set_pga (int which, double gain)
+{
+  return usrp_basic::set_pga(which, gain);
+}
+
+double
+usrp_basic_rx::pga (int which) const
+{
+  return usrp_basic::pga(which);
+}
+
+void
+usrp_basic_rx::probe_rx_slots (bool verbose)
+{
+  struct usrp_dboard_eeprom    eeprom;
+  static int slot_id_map[2] = { SLOT_RX_A, SLOT_RX_B };
+  static const char *slot_name[2] = { "RX d'board A", "RX d'board B" };
+
+  for (int i = 0; i < 2; i++){
+    int slot_id = slot_id_map [i];
+    const char *msg = 0;
+    usrp_dbeeprom_status_t s = usrp_read_dboard_eeprom (d_udh, slot_id, 
&eeprom);
+
+    switch (s){
+    case UDBE_OK:
+      d_dbid[slot_id] = eeprom.id;
+      msg = usrp_dbid_to_string (eeprom.id).c_str ();
+      set_adc_offset (2*i+0, eeprom.offset[0]);
+      set_adc_offset (2*i+1, eeprom.offset[1]);
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | eeprom.oe);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_NO_EEPROM:
+      d_dbid[slot_id] = -1;
+      msg = "<none>";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_INVALID_EEPROM:
+      d_dbid[slot_id] = -2;
+      msg = "Invalid EEPROM contents";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_BAD_SLOT:
+    default:
+      assert (0);
+    }
+
+    if (verbose){
+      fflush (stdout);
+      fprintf (stderr, "%s: %s\n", slot_name[i], msg);
+    }
+  }
+}
+
+bool
+usrp_basic_rx::write_aux_dac (int which_dboard, int which_dac, int value)
+{
+  return usrp_basic::write_aux_dac (dboard_to_slot (C_RX, which_dboard),
+                                   which_dac, value);
+}
+
+bool
+usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc, int *value)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (C_RX, which_dboard),
+                                  which_adc, value);
+}
+
+int
+usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (C_RX, which_dboard), 
which_adc);
+}
+
+int
+usrp_basic_rx::block_size () const { return d_ephandle->block_size(); }
+
+bool
+usrp_basic_rx::set_dc_offset_cl_enable(int bits, int mask)
+{
+  return _write_fpga_reg(FR_DC_OFFSET_CL_EN, 
+                        (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & 
mask));
+}
+
+////////////////////////////////////////////////////////////////
+//
+//                        usrp_basic_tx
+//
+////////////////////////////////////////////////////////////////
+
+
+//
+// DAC input rate 64 MHz interleaved for a total input rate of 128 MHz
+// DAC input is latched on rising edge of CLKOUT2
+// NCO is disabled
+// interpolate 2x
+// coarse modulator disabled
+//
+
+static unsigned char tx_init_regs[] = {
+  REG_TX_PWR_DN,       0,
+  REG_TX_A_OFFSET_LO,  0,
+  REG_TX_A_OFFSET_HI,  0,
+  REG_TX_B_OFFSET_LO,  0,
+  REG_TX_B_OFFSET_HI,  0,
+  REG_TX_A_GAIN,       (TX_X_GAIN_COARSE_FULL | 0),
+  REG_TX_B_GAIN,       (TX_X_GAIN_COARSE_FULL | 0),
+  REG_TX_PGA,          0xff,                   // maximum gain (0 dB)
+  REG_TX_MISC,         0,
+  REG_TX_IF,           (TX_IF_USE_CLKOUT1
+                        | TX_IF_I_FIRST
+                        | TX_IF_INV_TX_SYNC
+                        | TX_IF_2S_COMP
+                        | TX_IF_INTERLEAVED),
+  REG_TX_DIGITAL,      (TX_DIGITAL_2_DATA_PATHS
+                        | TX_DIGITAL_INTERPOLATE_4X),
+  REG_TX_MODULATOR,    (TX_MODULATOR_DISABLE_NCO
+                        | TX_MODULATOR_COARSE_MODULATION_NONE),
+  REG_TX_NCO_FTW_7_0,  0,
+  REG_TX_NCO_FTW_15_8, 0,
+  REG_TX_NCO_FTW_23_16,        0
+};
+
+usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int 
fusb_nblocks,
+                             const std::string fpga_filename,
+                             const std::string firmware_filename)
+  : usrp_basic (which_board, open_tx_interface, fpga_filename, 
firmware_filename, true),
+    d_devhandle (0), d_ephandle (0),
+    d_bytes_seen (0), d_first_write (true),
+    d_tx_enable (false)
+{
+  if (!usrp_9862_write_many_all (d_udh, tx_init_regs, sizeof (tx_init_regs))){
+    fprintf (stderr, "usrp_basic_tx: failed to init AD9862 TX regs\n");
+    throw std::runtime_error ("usrp_basic_tx/init_9862");
+  }
+
+  if (0){
+    // FIXME power down 2nd codec tx path
+    usrp_9862_write (d_udh, 1, REG_TX_PWR_DN,
+                    (TX_PWR_DN_TX_DIGITAL
+                     | TX_PWR_DN_TX_ANALOG_BOTH));
+  }
+
+  // Reset the tx path and leave it disabled.
+  set_tx_enable (false);
+  usrp_set_fpga_tx_reset (d_udh, true);
+  usrp_set_fpga_tx_reset (d_udh, false);
+
+  set_fpga_tx_sample_rate_divisor (4); // we're using interp x4
+
+  probe_tx_slots (false);
+  d_db[SLOT_TX_A] = instantiate_dbs(d_dbid[SLOT_TX_A], this, 0);
+  d_db[SLOT_TX_B] = instantiate_dbs(d_dbid[SLOT_TX_B], this, 1);
+  
+  // check fusb buffering parameters
+
+  if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_block_size");
+
+  if (fusb_nblocks < 0)
+    throw std::out_of_range ("usrp_basic_rx: invalid fusb_nblocks");
+  
+  if (fusb_block_size == 0)
+    fusb_block_size = FUSB_BLOCK_SIZE;
+
+  if (fusb_nblocks == 0)
+    fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
+
+  d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+  d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false,
+                                          fusb_block_size, fusb_nblocks);
+
+  _write_fpga_reg(FR_ATR_MASK_0, 0); // zero Tx side Auto Transmit/Receive regs
+  _write_fpga_reg(FR_ATR_TXVAL_0, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_0, 0);
+  _write_fpga_reg(FR_ATR_MASK_2, 0);
+  _write_fpga_reg(FR_ATR_TXVAL_2, 0);
+  _write_fpga_reg(FR_ATR_RXVAL_2, 0);
+}
+
+
+static unsigned char tx_fini_regs[] = {
+  REG_TX_PWR_DN,       (TX_PWR_DN_TX_DIGITAL
+                        | TX_PWR_DN_TX_ANALOG_BOTH),
+  REG_TX_MODULATOR,    (TX_MODULATOR_DISABLE_NCO
+                        | TX_MODULATOR_COARSE_MODULATION_NONE)
+};
+
+usrp_basic_tx::~usrp_basic_tx ()
+{
+  d_ephandle->stop ();
+  delete d_ephandle;
+  delete d_devhandle;
+
+  if (!usrp_9862_write_many_all (d_udh, tx_fini_regs, sizeof (tx_fini_regs))){
+    fprintf (stderr, "usrp_basic_tx: failed to fini AD9862 TX regs\n");
+  }
+}
+
+int
+usrp_basic_tx::daughterboard_id (int which_dboard) const 
+{
+  return common_daughterboard_id(C_TX, which_dboard);
+}
+
+std::vector< std::vector<db_base_sptr> >
+usrp_basic_tx::db()
+{
+  // When called from here, only return if the RX side
+  std::vector< std::vector<db_base_sptr> > ret;
+  ret.push_back(d_db[SLOT_TX_A]);
+  ret.push_back(d_db[SLOT_TX_B]);
+  return ret;
+}
+
+std::vector<db_base_sptr> 
+usrp_basic_tx::db(int which)
+{
+  // When called from here, only return if the TX side
+  if(which == 0) {
+    return d_db[SLOT_TX_A];
+  }
+  else {
+    return d_db[SLOT_TX_B];
+  }
+}
+
+bool 
+usrp_basic_tx::_write_oe (int which_dboard, int value, int mask)
+{
+  return _common_write_oe(C_TX, which_dboard, value, mask);
+}
+
+bool
+usrp_basic_tx::write_io (int which_dboard, int value, int mask)
+{
+  return common_write_io(C_TX, which_dboard, value, mask);
+}
+
+bool
+usrp_basic_tx::read_io (int which_dboard, int *value)
+{
+  return common_read_io(C_TX, which_dboard, value);
+}
+
+int
+usrp_basic_tx::read_io (int which_dboard)
+{
+  int value;
+  common_read_io(C_TX, which_dboard, &value);
+  return value;
+}
+
+bool
+usrp_basic_tx::start ()
+{
+  if (!usrp_basic::start ())
+    return false;
+
+  if (!set_tx_enable (true)){
+    fprintf (stderr, "usrp_basic_tx: set_tx_enable failed\n");
+    usb_strerror ();
+    return false;
+  }
+  
+  if (!d_ephandle->start ()){
+    fprintf (stderr, "usrp_basic_tx: failed to start end point streaming");
+    usb_strerror ();
+    return false;
+  }
+
+  return true;
+}
+
+bool
+usrp_basic_tx::stop ()
+{
+  bool ok = usrp_basic::stop ();
+
+  if (!d_ephandle->stop ()){
+    fprintf (stderr, "usrp_basic_tx: failed to stop end point streaming");
+    usb_strerror ();
+    ok = false;
+  }
+
+  if (!set_tx_enable (false)){
+    fprintf (stderr, "usrp_basic_tx: set_tx_enable(false) failed\n");
+    usb_strerror ();
+    ok = false;
+  }
+
+  return ok;
+}
+
+usrp_basic_tx *
+usrp_basic_tx::make (int which_board, int fusb_block_size, int fusb_nblocks,
+                    const std::string fpga_filename,
+                    const std::string firmware_filename)
+{
+  usrp_basic_tx *u = 0;
+  
+  try {
+    u = new usrp_basic_tx (which_board, fusb_block_size, fusb_nblocks,
+                          fpga_filename, firmware_filename);
+    return u;
+  }
+  catch (...){
+    delete u;
+    return 0;
+  }
+
+  return u;
+}
+
+bool
+usrp_basic_tx::set_fpga_tx_sample_rate_divisor (unsigned int div)
+{
+  return _write_fpga_reg (FR_TX_SAMPLE_RATE_DIV, div - 1);
+}
+
+/*!
+ * \brief Write data to the A/D's via the FPGA.
+ *
+ * \p len must be a multiple of 512 bytes.
+ * \returns number of bytes written or -1 on error.
+ *
+ * if \p underrun is non-NULL, it will be set to true iff
+ * a transmit underrun condition is detected.
+ */
+int
+usrp_basic_tx::write (const void *buf, int len, bool *underrun)
+{
+  int  r;
+  
+  if (underrun)
+    *underrun = false;
+  
+  if (len < 0 || (len % 512) != 0){
+    fprintf (stderr, "usrp_basic_tx::write: invalid length = %d\n", len);
+    return -1;
+  }
+
+  r = d_ephandle->write (buf, len);
+  if (r > 0)
+    d_bytes_seen += r;
+    
+  /*
+   * In many cases, the FPGA reports an tx underrun right after we
+   * enable the Tx path.  If this is our first write, check for the
+   * underrun to clear the condition, then ignore the result.
+   */
+  if (d_first_write && d_bytes_seen >= 4 * FUSB_BLOCK_SIZE){
+    d_first_write = false;
+    bool bogus_underrun;
+    usrp_check_tx_underrun (d_udh, &bogus_underrun);
+  }
+
+  if (underrun != 0 && d_bytes_seen >= d_bytes_per_poll){
+    d_bytes_seen = 0;
+    if (!usrp_check_tx_underrun (d_udh, underrun)){
+      fprintf (stderr, "usrp_basic_tx: usrp_check_tx_underrun failed\n");
+      usb_strerror ();
+    }
+  }
+
+  return r;
+}
+
+void
+usrp_basic_tx::wait_for_completion ()
+{
+  d_ephandle->wait_for_completion ();
+}
+
+bool
+usrp_basic_tx::set_tx_enable (bool on)
+{
+  d_tx_enable = on;
+  // fprintf (stderr, "set_tx_enable %d\n", on);
+  return usrp_set_fpga_tx_enable (d_udh, on);
+}
+
+// conditional disable, return prev state
+bool
+usrp_basic_tx::disable_tx ()
+{
+  bool enabled = tx_enable ();
+  if (enabled)
+    set_tx_enable (false);
+  return enabled;
+}
+
+// conditional set
+void
+usrp_basic_tx::restore_tx (bool on)
+{
+  if (on != tx_enable ())
+    set_tx_enable (on);
+}
+
+bool
+usrp_basic_tx::set_pga (int which, double gain)
+{
+  return usrp_basic::set_pga(which, gain);
+}
+
+double
+usrp_basic_tx::pga (int which) const
+{
+  return usrp_basic::pga(which);
+}
+
+void
+usrp_basic_tx::probe_tx_slots (bool verbose)
+{
+  struct usrp_dboard_eeprom    eeprom;
+  static int slot_id_map[2] = { SLOT_TX_A, SLOT_TX_B };
+  static const char *slot_name[2] = { "TX d'board A", "TX d'board B" };
+
+  for (int i = 0; i < 2; i++){
+    int slot_id = slot_id_map [i];
+    const char *msg = 0;
+    usrp_dbeeprom_status_t s = usrp_read_dboard_eeprom (d_udh, slot_id, 
&eeprom);
+
+    switch (s){
+    case UDBE_OK:
+      d_dbid[slot_id] = eeprom.id;
+      msg = usrp_dbid_to_string (eeprom.id).c_str ();
+      // FIXME, figure out interpretation of dc offset for TX d'boards
+      // offset = (eeprom.offset[1] << 16) | (eeprom.offset[0] & 0xffff);
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | eeprom.oe);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_NO_EEPROM:
+      d_dbid[slot_id] = -1;
+      msg = "<none>";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_INVALID_EEPROM:
+      d_dbid[slot_id] = -2;
+      msg = "Invalid EEPROM contents";
+      _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+      _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+      break;
+      
+    case UDBE_BAD_SLOT:
+    default:
+      assert (0);
+    }
+
+    if (verbose){
+      fflush (stdout);
+      fprintf (stderr, "%s: %s\n", slot_name[i], msg);
+    }
+  }
+}
+
+bool
+usrp_basic_tx::write_aux_dac (int which_dboard, int which_dac, int value)
+{
+  return usrp_basic::write_aux_dac (dboard_to_slot (C_TX, which_dboard),
+                                   which_dac, value);
+}
+
+bool
+usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc, int *value)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (C_TX, which_dboard),
+                                  which_adc, value);
+}
+
+int
+usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc)
+{
+  return usrp_basic::read_aux_adc (dboard_to_slot (C_TX, which_dboard), 
which_adc);
+}
+
+int
+usrp_basic_tx::block_size () const { return d_ephandle->block_size(); }
+

Deleted: 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h

Copied: 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h 
(from rev 9708, gnuradio/trunk/usrp/host/lib/legacy/usrp_basic.h)
===================================================================
--- gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h 
                        (rev 0)
+++ gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h 
2008-10-08 03:53:42 UTC (rev 9742)
@@ -0,0 +1,776 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004 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 version 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.
+ */
+
+/*
+ * ----------------------------------------------------------------------
+ * Mid level interface to the Universal Software Radio Peripheral (Rev 1)
+ *
+ * These classes implement the basic functionality for talking to the
+ * USRP.  They try to be as independent of the signal processing code
+ * in FPGA as possible.  They implement access to the low level
+ * peripherals on the board, provide a common way for reading and
+ * writing registers in the FPGA, and provide the high speed interface
+ * to streaming data across the USB.
+ *
+ * It is expected that subclasses will be derived that provide
+ * access to the functionality to a particular FPGA configuration.
+ * ----------------------------------------------------------------------
+ */
+
+#ifndef INCLUDED_USRP_BASIC_H
+#define INCLUDED_USRP_BASIC_H
+
+#include <usrp_slots.h>
+#include <string>
+
+struct usb_dev_handle;
+class  fusb_devhandle;
+class  fusb_ephandle;
+
+/*!
+ * \brief base class for usrp operations
+ */
+class usrp_basic
+{
+private:
+  // NOT IMPLEMENTED
+  usrp_basic (const usrp_basic &rhs);                  // no copy constructor
+  usrp_basic &operator= (const usrp_basic &rhs);       // no assignment 
operator
+
+  
+protected:
+  struct usb_dev_handle        *d_udh;
+  int                   d_usb_data_rate;       // bytes/sec
+  int                   d_bytes_per_poll;      // how often to poll for 
overruns
+  bool                  d_verbose;
+
+  static const int      MAX_REGS = 128;
+  unsigned int          d_fpga_shadows[MAX_REGS];
+
+  usrp_basic (int which_board,
+             struct usb_dev_handle *open_interface (struct usb_device *dev),
+             const std::string fpga_filename = "",
+             const std::string firmware_filename = "");
+
+  /*!
+   * \brief advise usrp_basic of usb data rate (bytes/sec)
+   *
+   * N.B., this doesn't tweak any hardware.  Derived classes
+   * should call this to inform us of the data rate whenever it's
+   * first set or if it changes.
+   *
+   * \param usb_data_rate      bytes/sec
+   */
+  void set_usb_data_rate (int usb_data_rate);
+  
+  /*!
+   * \brief Write auxiliary digital to analog converter.
+   *
+   * \param slot       Which Tx or Rx slot to write.
+   *                   N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
+   *                   SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
+   * \param which_dac  [0,3] RX slots must use only 0 and 1.  TX slots must 
use only 2 and 3.
+   * \param value      [0,4095]
+   * \returns true iff successful
+   */
+  bool write_aux_dac (int slot, int which_dac, int value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param slot       2-bit slot number. E.g., SLOT_TX_A
+   * \param which_adc  [0,1]
+   * \param value      return 12-bit value [0,4095]
+   * \returns true iff successful
+   */
+  bool read_aux_adc (int slot, int which_adc, int *value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param slot       2-bit slot number. E.g., SLOT_TX_A
+   * \param which_adc  [0,1]
+   * \returns value in the range [0,4095] if successful, else READ_FAILED.
+   */
+  int read_aux_adc (int slot, int which_adc);
+
+public:
+  virtual ~usrp_basic ();
+
+  /*!
+   * \brief return frequency of master oscillator on USRP
+   */
+  long  fpga_master_clock_freq () const { return 64000000; }
+
+  /*!
+   * \returns usb data rate in bytes/sec
+   */
+  int usb_data_rate () const { return d_usb_data_rate; }
+
+  void set_verbose (bool on) { d_verbose = on; }
+
+  //! magic value used on alternate register read interfaces
+  static const int READ_FAILED = -99999;
+
+  /*!
+   * \brief Write EEPROM on motherboard or any daughterboard.
+   * \param i2c_addr           I2C bus address of EEPROM
+   * \param eeprom_offset      byte offset in EEPROM to begin writing
+   * \param buf                        the data to write
+   * \returns true iff sucessful
+   */
+  bool write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf);
+
+  /*!
+   * \brief Read EEPROM on motherboard or any daughterboard.
+   * \param i2c_addr           I2C bus address of EEPROM
+   * \param eeprom_offset      byte offset in EEPROM to begin reading
+   * \param len                        number of bytes to read
+   * \returns the data read if successful, else a zero length string.
+   */
+  std::string read_eeprom (int i2c_addr, int eeprom_offset, int len);
+
+  /*!
+   * \brief Write to I2C peripheral
+   * \param i2c_addr           I2C bus address (7-bits)
+   * \param buf                        the data to write
+   * \returns true iff successful
+   * Writes are limited to a maximum of of 64 bytes.
+   */
+  bool write_i2c (int i2c_addr, const std::string buf);
+
+  /*!
+   * \brief Read from I2C peripheral
+   * \param i2c_addr           I2C bus address (7-bits)
+   * \param len                        number of bytes to read
+   * \returns the data read if successful, else a zero length string.
+   * Reads are limited to a maximum of 64 bytes.
+   */
+  std::string read_i2c (int i2c_addr, int len);
+
+  /*!
+   * \brief Set ADC offset correction
+   * \param which      which ADC[0,3]: 0 = RX_A I, 1 = RX_A Q...
+   * \param offset     16-bit value to subtract from raw ADC input.
+   */
+  bool set_adc_offset (int which, int offset);
+
+  /*!
+   * \brief Set DAC offset correction
+   * \param which      which DAC[0,3]: 0 = TX_A I, 1 = TX_A Q...
+   * \param offset     10-bit offset value (ambiguous format:  See AD9862 
datasheet).
+   * \param offset_pin 1-bit value.  If 0 offset applied to -ve differential 
pin;
+   *                                  If 1 offset applied to +ve differential 
pin.
+   */
+  bool set_dac_offset (int which, int offset, int offset_pin);
+
+  /*!
+   * \brief Control ADC input buffer
+   * \param which      which ADC[0,3]
+   * \param bypass     if non-zero, bypass input buffer and connect input
+   *                   directly to switched cap SHA input of RxPGA.
+   */
+  bool set_adc_buffer_bypass (int which, bool bypass);
+
+
+  /*!
+   * \brief return the usrp's serial number.
+   *
+   * \returns non-zero length string iff successful.
+   */
+  std::string serial_number();
+
+  // ----------------------------------------------------------------
+  // Low level implementation routines.
+  // You probably shouldn't be using these...
+  //
+
+  bool _set_led (int which, bool on);
+
+  /*!
+   * \brief Write FPGA register.
+   * \param regno      7-bit register number
+   * \param value      32-bit value
+   * \returns true iff successful
+   */
+  bool _write_fpga_reg (int regno, int value); //< 7-bit regno, 32-bit value
+
+  /*!
+   * \brief Read FPGA register.
+   * \param regno      7-bit register number
+   * \param value      32-bit value
+   * \returns true iff successful
+   */
+  bool _read_fpga_reg (int regno, int *value); //< 7-bit regno, 32-bit value
+
+  /*!
+   * \brief Read FPGA register.
+   * \param regno      7-bit register number
+   * \returns register value if successful, else READ_FAILED
+   */
+  int  _read_fpga_reg (int regno);
+
+
+  /*!
+   * \brief Write FPGA register with mask.
+   * \param regno      7-bit register number
+   * \param value      16-bit value
+   * \param mask       16-bit value
+   * \returns true if successful
+   * Only use this for registers who actually implement a mask in the verilog 
firmware, like FR_RX_MASTER_SLAVE
+   */
+  bool _write_fpga_reg_masked (int regno, int value, int mask);
+
+  /*!
+   * \brief Write AD9862 register.
+   * \param which_codec 0 or 1
+   * \param regno      6-bit register number
+   * \param value      8-bit value
+   * \returns true iff successful
+   */
+  bool _write_9862 (int which_codec, int regno, unsigned char value);
+
+  /*!
+   * \brief Read AD9862 register.
+   * \param which_codec 0 or 1
+   * \param regno      6-bit register number
+   * \param value      8-bit value
+   * \returns true iff successful
+   */
+  bool _read_9862 (int which_codec, int regno, unsigned char *value) const;
+
+  /*!
+   * \brief Read AD9862 register.
+   * \param which_codec 0 or 1
+   * \param regno      6-bit register number
+   * \returns register value if successful, else READ_FAILED
+   */
+  int  _read_9862 (int which_codec, int regno) const;
+
+  /*!
+   * \brief Write data to SPI bus peripheral.
+   *
+   * \param optional_header    0,1 or 2 bytes to write before buf.
+   * \param enables            bitmask of peripherals to write. See 
usrp_spi_defs.h
+   * \param format             transaction format.  See usrp_spi_defs.h 
SPI_FMT_*
+   * \param buf                        the data to write
+   * \returns true iff successful
+   * Writes are limited to a maximum of 64 bytes.
+   *
+   * If \p format specifies that optional_header bytes are present, they are
+   * written to the peripheral immediately prior to writing \p buf.
+   */
+  bool _write_spi (int optional_header, int enables, int format, std::string 
buf);
+
+  /*
+   * \brief Read data from SPI bus peripheral.
+   *
+   * \param optional_header    0,1 or 2 bytes to write before buf.
+   * \param enables            bitmask of peripheral to read. See 
usrp_spi_defs.h
+   * \param format             transaction format.  See usrp_spi_defs.h 
SPI_FMT_*
+   * \param len                        number of bytes to read.  Must be in 
[0,64].
+   * \returns the data read if sucessful, else a zero length string.
+   *
+   * Reads are limited to a maximum of 64 bytes.
+   *
+   * If \p format specifies that optional_header bytes are present, they
+   * are written to the peripheral first.  Then \p len bytes are read from
+   * the peripheral and returned.
+   */
+  std::string _read_spi (int optional_header, int enables, int format, int 
len);
+
+  /*!
+   * \brief Start data transfers.
+   * Called in base class to derived class order.
+   */
+  bool start ();
+
+  /*!
+   * \brief Stop data transfers.
+   * Called in base class to derived class order.
+   */
+  bool stop ();
+};
+
+/*!
+ * \brief class for accessing the receive side of the USRP
+ */
+class usrp_basic_rx : public usrp_basic 
+{
+private:
+  fusb_devhandle       *d_devhandle;
+  fusb_ephandle                *d_ephandle;
+  int                   d_bytes_seen;          // how many bytes we've seen
+  bool                  d_first_read;
+  bool                  d_rx_enable;
+
+protected:
+  int                   d_dbid[2];             // Rx daughterboard ID's
+
+  /*!
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512. 
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default. 
+   */
+  usrp_basic_rx (int which_board,
+                int fusb_block_size=0,
+                int fusb_nblocks=0,
+                const std::string fpga_filename = "",
+                const std::string firmware_filename = ""
+                );  // throws if trouble
+
+  bool set_rx_enable (bool on);
+  bool rx_enable () const { return d_rx_enable; }
+
+  bool disable_rx ();          // conditional disable, return prev state
+  void restore_rx (bool on);   // conditional set
+
+  void probe_rx_slots (bool verbose);
+  int  dboard_to_slot (int dboard) { return (dboard << 1) | 1; }
+
+public:
+  ~usrp_basic_rx ();
+
+  /*!
+   * \brief invokes constructor, returns instance or 0 if trouble
+   *
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512. 
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default. 
+   */
+  static usrp_basic_rx *make (int which_board,
+                             int fusb_block_size=0,
+                             int fusb_nblocks=0,
+                             const std::string fpga_filename = "",
+                             const std::string firmware_filename = ""
+                             );
+
+  // MANIPULATORS
+
+  /*!
+   * \brief tell the fpga the rate rx samples are coming from the A/D's
+   *
+   * div = fpga_master_clock_freq () / sample_rate
+   *
+   * sample_rate is determined by a myriad of registers
+   * in the 9862.  That's why you have to tell us, so
+   * we can tell the fpga.
+   */
+  bool set_fpga_rx_sample_rate_divisor (unsigned int div);
+
+  /*!
+   * \brief read data from the D/A's via the FPGA.
+   * \p len must be a multiple of 512 bytes.
+   *
+   * \returns the number of bytes read, or -1 on error.
+   *
+   * If overrun is non-NULL it will be set true iff an RX overrun is detected.
+   */
+  int read (void *buf, int len, bool *overrun);
+
+  // ACCESSORS
+
+  //! sampling rate of A/D converter
+  virtual long converter_rate() const { return fpga_master_clock_freq(); } // 
64M
+  long adc_rate() const { return converter_rate(); }
+  long adc_freq() const { return converter_rate(); }   //!< deprecated method 
name
+
+  /*!
+   * \brief Return daughterboard ID for given Rx daughterboard slot [0,1].
+   *
+   * \param which_dboard       [0,1] which Rx daughterboard
+   *
+   * \return daughterboard id >= 0 if successful
+   * \return -1 if no daugherboard
+   * \return -2 if invalid EEPROM on daughterboard
+   */
+  int daughterboard_id (int which_dboard) const { return d_dbid[which_dboard & 
0x1]; }
+
+  // ----------------------------------------------------------------
+  // routines for controlling the Programmable Gain Amplifier
+  /*!
+   * \brief Set Programmable Gain Amplifier (PGA)
+   *
+   * \param which      which A/D [0,3]
+   * \param gain_in_db gain value (linear in dB)
+   *
+   * gain is rounded to closest setting supported by hardware.
+   *
+   * \returns true iff sucessful.
+   *
+   * \sa pga_min(), pga_max(), pga_db_per_step()
+   */
+  bool set_pga (int which, double gain_in_db);
+
+  /*!
+   * \brief Return programmable gain amplifier gain setting in dB.
+   *
+   * \param which      which A/D [0,3]
+   */
+  double pga (int which) const;
+
+  /*!
+   * \brief Return minimum legal PGA gain in dB.
+   */
+  double pga_min () const { return 0.0; }
+
+  /*!
+   * \brief Return maximum legal PGA gain in dB.
+   */
+  double pga_max () const { return 20.0; }
+
+  /*!
+   * \brief Return hardware step size of PGA (linear in dB).
+   */
+  double pga_db_per_step () const { return 20.0 / 20; }
+
+  /*!
+   * \brief Write direction register (output enables) for pins that go to 
daughterboard.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param value              value to write into register
+   * \param mask               which bits of value to write into reg
+   *
+   * Each d'board has 16-bits of general purpose i/o.
+   * Setting the bit makes it an output from the FPGA to the d'board.
+   *
+   * This register is initialized based on a value stored in the
+   * d'board EEPROM.  In general, you shouldn't be using this routine
+   * without a very good reason.  Using this method incorrectly will
+   * kill your USRP motherboard and/or daughterboard.
+   */
+  bool _write_oe (int which_dboard, int value, int mask);
+
+  /*!
+   * \brief Write daughterboard i/o pin value
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param value              value to write into register
+   * \param mask               which bits of value to write into reg
+   */
+  bool write_io (int which_dboard, int value, int mask);
+
+  /*!
+   * \brief Read daughterboard i/o pin value
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param value              output
+   */
+  bool read_io (int which_dboard, int *value);
+
+  /*!
+   * \brief Read daughterboard i/o pin value
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \returns register value if successful, else READ_FAILED
+   */
+  int read_io (int which_dboard);
+
+  /*!
+   * \brief Write auxiliary digital to analog converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   *                           N.B., SLOT_TX_A and SLOT_RX_A share the same 
AUX DAC's.
+   *                           SLOT_TX_B and SLOT_RX_B share the same AUX 
DAC's.
+   * \param which_dac          [2,3] TX slots must use only 2 and 3.
+   * \param value              [0,4095]
+   * \returns true iff successful
+   */
+  bool write_aux_dac (int which_board, int which_dac, int value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \param value              return 12-bit value [0,4095]
+   * \returns true iff successful
+   */
+  bool read_aux_adc (int which_dboard, int which_adc, int *value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \returns value in the range [0,4095] if successful, else READ_FAILED.
+   */
+  int read_aux_adc (int which_dboard, int which_adc);
+
+  /*!
+   * \brief returns current fusb block size
+   */
+  int block_size() const;
+
+  /*!
+   * \brief Enable/disable automatic DC offset removal control loop in FPGA
+   *
+   * \param bits  which control loops to enable
+   * \param mask  which \p bits to pay attention to
+   *
+   * If the corresponding bit is set, enable the automatic DC
+   * offset correction control loop.
+   *
+   * <pre>
+   * The 4 low bits are significant:
+   *
+   *   ADC0 = (1 << 0)
+   *   ADC1 = (1 << 1)
+   *   ADC2 = (1 << 2)
+   *   ADC3 = (1 << 3)
+   * </pre>
+   *
+   * By default the control loop is enabled on all ADC's.
+   */
+  bool set_dc_offset_cl_enable(int bits, int mask);
+
+  // called in base class to derived class order
+  bool start ();
+  bool stop ();
+};
+
+/*!
+ * \brief class for accessing the transmit side of the USRP
+ */
+class usrp_basic_tx : public usrp_basic 
+{
+private:
+  fusb_devhandle       *d_devhandle;
+  fusb_ephandle                *d_ephandle;
+  int                   d_bytes_seen;          // how many bytes we've seen
+  bool                  d_first_write;
+  bool                  d_tx_enable;
+
+ protected:
+  int                   d_dbid[2];             // Tx daughterboard ID's
+
+  /*!
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512.
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default.
+   */
+  usrp_basic_tx (int which_board,
+                int fusb_block_size=0,
+                int fusb_nblocks=0,
+                const std::string fpga_filename = "",
+                const std::string firmware_filename = ""
+                );             // throws if trouble
+
+  bool set_tx_enable (bool on);
+  bool tx_enable () const { return d_tx_enable; }
+
+  bool disable_tx ();          // conditional disable, return prev state
+  void restore_tx (bool on);   // conditional set
+
+  void probe_tx_slots (bool verbose);
+  int  dboard_to_slot (int dboard) { return (dboard << 1) | 0; }
+
+public:
+
+  ~usrp_basic_tx ();
+
+  /*!
+   * \brief invokes constructor, returns instance or 0 if trouble
+   *
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512. 
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default. 
+   */
+  static usrp_basic_tx *make (int which_board, int fusb_block_size=0, int 
fusb_nblocks=0,
+                             const std::string fpga_filename = "",
+                             const std::string firmware_filename = ""
+                             );
+
+  // MANIPULATORS
+
+  /*!
+   * \brief tell the fpga the rate tx samples are going to the D/A's
+   *
+   * div = fpga_master_clock_freq () * 2
+   *
+   * sample_rate is determined by a myriad of registers
+   * in the 9862.  That's why you have to tell us, so
+   * we can tell the fpga.
+   */
+  bool set_fpga_tx_sample_rate_divisor (unsigned int div);
+
+  /*!
+   * \brief Write data to the A/D's via the FPGA.
+   *
+   * \p len must be a multiple of 512 bytes.
+   * \returns number of bytes written or -1 on error.
+   *
+   * if \p underrun is non-NULL, it will be set to true iff
+   * a transmit underrun condition is detected.
+   */
+  int write (const void *buf, int len, bool *underrun);
+
+  /*
+   * Block until all outstanding writes have completed.
+   * This is typically used to assist with benchmarking
+   */
+  void wait_for_completion ();
+
+  // ACCESSORS
+
+  //! sampling rate of D/A converter
+  virtual long converter_rate() const { return fpga_master_clock_freq () * 2; 
} // 128M
+  long dac_rate() const { return converter_rate(); }
+  long dac_freq() const { return converter_rate(); }   //!< deprecated method 
name
+
+  /*!
+   * \brief Return daughterboard ID for given Tx daughterboard slot [0,1].
+   *
+   * \return daughterboard id >= 0 if successful
+   * \return -1 if no daugherboard
+   * \return -2 if invalid EEPROM on daughterboard
+   */
+  int daughterboard_id (int which_dboard) const { return d_dbid[which_dboard & 
0x1]; }
+
+  // ----------------------------------------------------------------
+  // routines for controlling the Programmable Gain Amplifier
+  /*!
+   * \brief Set Programmable Gain Amplifier (PGA)
+   *
+   * \param which      which D/A [0,3]
+   * \param gain_in_db gain value (linear in dB)
+   *
+   * gain is rounded to closest setting supported by hardware.
+   * Note that DAC 0 and DAC 1 share a gain setting as do DAC 2 and DAC 3.
+   * Setting DAC 0 affects DAC 1 and vice versa.  Same with DAC 2 and DAC 3.
+   *
+   * \returns true iff sucessful.
+   *
+   * \sa pga_min(), pga_max(), pga_db_per_step()
+   */
+  bool set_pga (int which, double gain_in_db);
+
+  /*!
+   * \brief Return programmable gain amplifier gain in dB.
+   *
+   * \param which      which D/A [0,3]
+   */
+  double pga (int which) const;
+
+  /*!
+   * \brief Return minimum legal PGA gain in dB.
+   */
+  double pga_min () const { return -20.0; }
+
+  /*!
+   * \brief Return maximum legal PGA gain in dB.
+   */
+  double pga_max () const { return 0.0; }
+
+  /*!
+   * \brief Return hardware step size of PGA (linear in dB).
+   */
+  double pga_db_per_step () const { return 20.0/255; }
+
+  /*!
+   * \brief Write direction register (output enables) for pins that go to 
daughterboard.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param value              value to write into register
+   * \param mask               which bits of value to write into reg
+   *
+   * Each d'board has 16-bits of general purpose i/o.
+   * Setting the bit makes it an output from the FPGA to the d'board.
+   *
+   * This register is initialized based on a value stored in the
+   * d'board EEPROM.  In general, you shouldn't be using this routine
+   * without a very good reason.  Using this method incorrectly will
+   * kill your USRP motherboard and/or daughterboard.
+   */
+  bool _write_oe (int which_dboard, int value, int mask);
+
+  /*!
+   * \brief Write daughterboard i/o pin value
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param value              value to write into register
+   * \param mask               which bits of value to write into reg
+   */
+  bool write_io (int which_dboard, int value, int mask);
+
+  /*!
+   * \brief Read daughterboard i/o pin value
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param value              return value
+   */
+  bool read_io (int which_dboard, int *value);
+
+  /*!
+   * \brief Read daughterboard i/o pin value
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \returns register value if successful, else READ_FAILED
+   */
+  int read_io (int which_dboard);
+
+  /*!
+   * \brief Write auxiliary digital to analog converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   *                           N.B., SLOT_TX_A and SLOT_RX_A share the same 
AUX DAC's.
+   *                           SLOT_TX_B and SLOT_RX_B share the same AUX 
DAC's.
+   * \param which_dac          [2,3] TX slots must use only 2 and 3.
+   * \param value              [0,4095]
+   * \returns true iff successful
+   */
+  bool write_aux_dac (int which_board, int which_dac, int value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \param value              return 12-bit value [0,4095]
+   * \returns true iff successful
+   */
+  bool read_aux_adc (int which_dboard, int which_adc, int *value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \returns value in the range [0,4095] if successful, else READ_FAILED.
+   */
+  int read_aux_adc (int which_dboard, int which_adc);
+
+  /*!
+   * \brief returns current fusb block size
+   */
+  int block_size() const;
+
+  // called in base class to derived class order
+  bool start ();
+  bool stop ();
+};
+
+#endif

Copied: 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h.prev
 (from rev 9738, 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h)
===================================================================
--- 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h.prev
                            (rev 0)
+++ 
gnuradio/branches/developers/eb/cppdb-wip/usrp/host/lib/legacy/usrp_basic.h.prev
    2008-10-08 03:53:42 UTC (rev 9742)
@@ -0,0 +1,833 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,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 version 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.
+ */
+
+/*
+ * ----------------------------------------------------------------------
+ * Mid level interface to the Universal Software Radio Peripheral (Rev 1)
+ *
+ * These classes implement the basic functionality for talking to the
+ * USRP.  They try to be as independent of the signal processing code
+ * in FPGA as possible.  They implement access to the low level
+ * peripherals on the board, provide a common way for reading and
+ * writing registers in the FPGA, and provide the high speed interface
+ * to streaming data across the USB.
+ *
+ * It is expected that subclasses will be derived that provide
+ * access to the functionality to a particular FPGA configuration.
+ * ----------------------------------------------------------------------
+ */
+
+#ifndef INCLUDED_USRP_BASIC_H
+#define INCLUDED_USRP_BASIC_H
+
+#include <usrp_slots.h>
+#include <string>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+enum txrx_t {
+  C_RX = 0,
+  C_TX = 1
+};
+
+class db_base;
+typedef boost::shared_ptr<db_base> db_base_sptr;
+
+struct dxc_freq_t
+{
+  float ddc_freq;
+  bool inverted;
+};
+
+struct dxc_freq_t calc_dxc_freq(float target_freq, float baseband_freq, long 
fs);
+
+struct usb_dev_handle;
+class  fusb_devhandle;
+class  fusb_ephandle;
+
+/*!
+ * \brief base class for usrp operations
+ */
+class usrp_basic
+{
+private:
+  // NOT IMPLEMENTED
+  //usrp_basic (const usrp_basic &rhs);                        // no copy 
constructor
+  //usrp_basic &operator= (const usrp_basic &rhs);     // no assignment 
operator
+
+  
+protected:
+  struct usb_dev_handle        *d_udh;
+  int                   d_usb_data_rate;       // bytes/sec
+  int                   d_bytes_per_poll;      // how often to poll for 
overruns
+  bool                  d_verbose;
+  bool                   d_tx;                  // is this for RX or TX?
+  int                   d_dbid[4];             // daughterboard ID's; 0,1 for 
Rx, 2,3 for Tx
+
+
+  std::vector< std::vector<db_base_sptr> > d_db;
+
+  static const int      MAX_REGS = 128;
+  unsigned int          d_fpga_shadows[MAX_REGS];
+
+  usrp_basic (int which_board,
+             struct usb_dev_handle *open_interface (struct usb_device *dev),
+             const std::string fpga_filename = "",
+             const std::string firmware_filename = "",
+             bool tx=false);
+
+  /*!
+   * \brief advise usrp_basic of usb data rate (bytes/sec)
+   *
+   * N.B., this doesn't tweak any hardware.  Derived classes
+   * should call this to inform us of the data rate whenever it's
+   * first set or if it changes.
+   *
+   * \param usb_data_rate      bytes/sec
+   */
+  void set_usb_data_rate (int usb_data_rate);
+
+
+  int  dboard_to_slot (txrx_t tx, int dboard);
+
+public:
+  virtual ~usrp_basic ();
+
+  /*!
+   * \brief Returns a pointer to the daughterboard on the side specified
+   *        by 'which'. The basic daughterboards have two ports and so
+   *        return a vector of two objects while other boards return just 1.
+   * \param which side: 0=A, 1=B
+   *
+   * \return list of shared pointers to daughterboard objects
+   */
+  virtual std::vector< std::vector<db_base_sptr> > db();
+  virtual std::vector<db_base_sptr> db(int which);
+  
+  /*!
+   * \brief Returns true if this is a transmitter and false if it a receiver
+   * \return bool true=tx, false=rx
+   */
+  bool istx() { return d_tx; }
+
+  /*!
+   * \brief Return daughterboard ID for given daughterboard slot [0,1].
+   *
+   * \param tx                  [0,1] if tx (1) or rx (0)
+   * \param which_dboard       [0,1] which daughterboard
+   *                            based on TX value, maps to:
+   *                                SLOT_TX_A = 0
+   *                                SLOT_RX_A = 1
+   *                                SLOT_TX_B = 2
+   *                                SLOT_RX_B = 3
+   *
+   * \return daughterboard id >= 0 if successful
+   * \return -1 if no daugherboard
+   * \return -2 if invalid EEPROM on daughterboard
+   */
+  int common_daughterboard_id (txrx_t tx, int which_dboard) const;
+  virtual int daughterboard_id (int which_dboard) const;
+
+  virtual long converter_rate() const = 0;
+
+  virtual bool set_pga (int which, double gain);
+  bool set_rx_pga(int which, double gain);
+  bool set_tx_pga(int which, double gain);
+
+  /*!
+   * \brief Return programmable gain amplifier gain setting in dB.
+   *
+   * \param which      which A/D [0,3]
+   */
+  virtual double pga (int which) const;
+  double pga_rx (int which) const;
+  double pga_tx (int which) const;
+
+
+  /*!
+   * \brief Return minimum legal PGA gain in dB.
+   */
+  virtual double pga_min () const;
+  double pga_tx_min () const { return -20.0; }
+  double pga_rx_min () const { return 0.0; }
+
+  /*!
+   * \brief Return maximum legal PGA gain in dB.
+   */
+  virtual double pga_max () const;
+  double pga_tx_max () const { return 0.0; }
+  double pga_rx_max () const { return 20.0; }
+
+  /*!
+   * \brief Return hardware step size of PGA (linear in dB).
+   */
+  virtual double pga_db_per_step () const;
+  double pga_tx_db_per_step () const { return 20.0 / 255; }
+  double pga_rx_db_per_step () const { return 20.0 /  20; }
+  
+  /*!
+   * \brief return frequency of master oscillator on USRP
+   */
+  long  fpga_master_clock_freq () const { return 64000000; }
+
+  /*!
+   * \returns usb data rate in bytes/sec
+   */
+  int usb_data_rate () const { return d_usb_data_rate; }
+
+  void set_verbose (bool on) { d_verbose = on; }
+
+  //! magic value used on alternate register read interfaces
+  static const int READ_FAILED = -99999;
+
+  
+  /*!
+   * \brief Write auxiliary digital to analog converter.
+   *
+   * \param slot       Which Tx or Rx slot to write.
+   *                   N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
+   *                   SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
+   * \param which_dac  [0,3] RX slots must use only 0 and 1.  TX slots must 
use only 2 and 3.
+   * \param value      [0,4095]
+   * \returns true iff successful
+   */
+  bool write_aux_dac (int slot, int which_dac, int value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param slot       2-bit slot number. E.g., SLOT_TX_A
+   * \param which_adc  [0,1]
+   * \param value      return 12-bit value [0,4095]
+   * \returns true iff successful
+   */
+  bool read_aux_adc (int slot, int which_adc, int *value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param slot       2-bit slot number. E.g., SLOT_TX_A
+   * \param which_adc  [0,1]
+   * \returns value in the range [0,4095] if successful, else READ_FAILED.
+   */
+  int read_aux_adc (int slot, int which_adc);
+
+  /*!
+   * \brief Write EEPROM on motherboard or any daughterboard.
+   * \param i2c_addr           I2C bus address of EEPROM
+   * \param eeprom_offset      byte offset in EEPROM to begin writing
+   * \param buf                        the data to write
+   * \returns true iff sucessful
+   */
+  bool write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf);
+
+  /*!
+   * \brief Read EEPROM on motherboard or any daughterboard.
+   * \param i2c_addr           I2C bus address of EEPROM
+   * \param eeprom_offset      byte offset in EEPROM to begin reading
+   * \param len                        number of bytes to read
+   * \returns the data read if successful, else a zero length string.
+   */
+  std::string read_eeprom (int i2c_addr, int eeprom_offset, int len);
+
+  /*!
+   * \brief Write to I2C peripheral
+   * \param i2c_addr           I2C bus address (7-bits)
+   * \param buf                        the data to write
+   * \returns true iff successful
+   * Writes are limited to a maximum of of 64 bytes.
+   */
+  bool write_i2c (int i2c_addr, const std::string buf);
+
+  /*!
+   * \brief Read from I2C peripheral
+   * \param i2c_addr           I2C bus address (7-bits)
+   * \param len                        number of bytes to read
+   * \returns the data read if successful, else a zero length string.
+   * Reads are limited to a maximum of 64 bytes.
+   */
+  std::string read_i2c (int i2c_addr, int len);
+
+  /*!
+   * \brief Set ADC offset correction
+   * \param which      which ADC[0,3]: 0 = RX_A I, 1 = RX_A Q...
+   * \param offset     16-bit value to subtract from raw ADC input.
+   */
+  bool set_adc_offset (int which, int offset);
+
+  /*!
+   * \brief Set DAC offset correction
+   * \param which      which DAC[0,3]: 0 = TX_A I, 1 = TX_A Q...
+   * \param offset     10-bit offset value (ambiguous format:  See AD9862 
datasheet).
+   * \param offset_pin 1-bit value.  If 0 offset applied to -ve differential 
pin;
+   *                                  If 1 offset applied to +ve differential 
pin.
+   */
+  bool set_dac_offset (int which, int offset, int offset_pin);
+
+  /*!
+   * \brief Control ADC input buffer
+   * \param which      which ADC[0,3]
+   * \param bypass     if non-zero, bypass input buffer and connect input
+   *                   directly to switched cap SHA input of RxPGA.
+   */
+  bool set_adc_buffer_bypass (int which, bool bypass);
+
+
+  /*!
+   * \brief return the usrp's serial number.
+   *
+   * \returns non-zero length string iff successful.
+   */
+  std::string serial_number();
+
+  // ----------------------------------------------------------------
+  // Low level implementation routines.
+  // You probably shouldn't be using these...
+  //
+
+  bool _set_led (int which, bool on);
+
+  /*!
+   * \brief Write FPGA register.
+   * \param regno      7-bit register number
+   * \param value      32-bit value
+   * \returns true iff successful
+   */
+  bool _write_fpga_reg (int regno, int value); //< 7-bit regno, 32-bit value
+
+  /*!
+   * \brief Read FPGA register.
+   * \param regno      7-bit register number
+   * \param value      32-bit value
+   * \returns true iff successful
+   */
+  bool _read_fpga_reg (int regno, int *value); //< 7-bit regno, 32-bit value
+
+  /*!
+   * \brief Read FPGA register.
+   * \param regno      7-bit register number
+   * \returns register value if successful, else READ_FAILED
+   */
+  int  _read_fpga_reg (int regno);
+
+
+  /*!
+   * \brief Write FPGA register with mask.
+   * \param regno      7-bit register number
+   * \param value      16-bit value
+   * \param mask       16-bit value
+   * \returns true if successful
+   * Only use this for registers who actually implement a mask in the verilog 
firmware, like FR_RX_MASTER_SLAVE
+   */
+  bool _write_fpga_reg_masked (int regno, int value, int mask);
+
+  /*!
+   * \brief Write AD9862 register.
+   * \param which_codec 0 or 1
+   * \param regno      6-bit register number
+   * \param value      8-bit value
+   * \returns true iff successful
+   */
+  bool _write_9862 (int which_codec, int regno, unsigned char value);
+
+  /*!
+   * \brief Read AD9862 register.
+   * \param which_codec 0 or 1
+   * \param regno      6-bit register number
+   * \param value      8-bit value
+   * \returns true iff successful
+   */
+  bool _read_9862 (int which_codec, int regno, unsigned char *value) const;
+
+  /*!
+   * \brief Read AD9862 register.
+   * \param which_codec 0 or 1
+   * \param regno      6-bit register number
+   * \returns register value if successful, else READ_FAILED
+   */
+  int  _read_9862 (int which_codec, int regno) const;
+
+  /*!
+   * \brief Write data to SPI bus peripheral.
+   *
+   * \param optional_header    0,1 or 2 bytes to write before buf.
+   * \param enables            bitmask of peripherals to write. See 
usrp_spi_defs.h
+   * \param format             transaction format.  See usrp_spi_defs.h 
SPI_FMT_*
+   * \param buf                        the data to write
+   * \returns true iff successful
+   * Writes are limited to a maximum of 64 bytes.
+   *
+   * If \p format specifies that optional_header bytes are present, they are
+   * written to the peripheral immediately prior to writing \p buf.
+   */
+  bool _write_spi (int optional_header, int enables, int format, std::string 
buf);
+
+  /*
+   * \brief Read data from SPI bus peripheral.
+   *
+   * \param optional_header    0,1 or 2 bytes to write before buf.
+   * \param enables            bitmask of peripheral to read. See 
usrp_spi_defs.h
+   * \param format             transaction format.  See usrp_spi_defs.h 
SPI_FMT_*
+   * \param len                        number of bytes to read.  Must be in 
[0,64].
+   * \returns the data read if sucessful, else a zero length string.
+   *
+   * Reads are limited to a maximum of 64 bytes.
+   *
+   * If \p format specifies that optional_header bytes are present, they
+   * are written to the peripheral first.  Then \p len bytes are read from
+   * the peripheral and returned.
+   */
+  std::string _read_spi (int optional_header, int enables, int format, int 
len);
+
+
+  /*!
+   * \brief Write direction register (output enables) for pins that go to 
daughterboard.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param value              value to write into register
+   * \param mask               which bits of value to write into reg
+   *
+   * Each d'board has 16-bits of general purpose i/o.
+   * Setting the bit makes it an output from the FPGA to the d'board.
+   *
+   * This register is initialized based on a value stored in the
+   * d'board EEPROM.  In general, you shouldn't be using this routine
+   * without a very good reason.  Using this method incorrectly will
+   * kill your USRP motherboard and/or daughterboard.
+   */
+  bool _common_write_oe (txrx_t tx, int which_dboard, int value, int mask);
+  virtual bool _write_oe (int which_dboard, int value, int mask);
+
+  /*!
+   * \brief Write daughterboard i/o pin value
+   *
+   * \param tx                  [0, 1] if transmit (1) or receive (0)
+   * \param which_dboard       [0,1] which d'board
+   * \param value              value to write into register
+   * \param mask               which bits of value to write into reg
+   */
+  bool common_write_io (txrx_t tx, int which_dboard, int value, int mask);
+  virtual bool write_io (int which_dboard, int value, int mask);
+
+  /*!
+   * \brief Read daughterboard i/o pin value
+   *
+   * \param tx                 [0,1] if transmit (1) or receive (0)
+   * \param which_dboard       [0,1] which d'board
+   * \param value              output
+   */
+  bool common_read_io (txrx_t tx, int which_dboard, int *value);
+  virtual bool read_io (int which_dboard, int *value);
+  virtual int  read_io (int which_dboard);
+
+  /*!
+   * \brief Start data transfers.
+   * Called in base class to derived class order.
+   */
+  bool start ();
+
+  /*!
+   * \brief Stop data transfers.
+   * Called in base class to derived class order.
+   */
+  bool stop ();
+};
+
+
+
+
+/*!
+ * \brief class for accessing the receive side of the USRP
+ */
+class usrp_basic_rx : public usrp_basic 
+{
+private:
+  fusb_devhandle       *d_devhandle;
+  fusb_ephandle                *d_ephandle;
+  int                   d_bytes_seen;          // how many bytes we've seen
+  bool                  d_first_read;
+  bool                  d_rx_enable;
+
+protected:
+
+  /*!
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512. 
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default. 
+   */
+  usrp_basic_rx (int which_board,
+                int fusb_block_size=0,
+                int fusb_nblocks=0,
+                const std::string fpga_filename = "",
+                const std::string firmware_filename = ""
+                );  // throws if trouble
+
+  bool set_rx_enable (bool on);
+  bool rx_enable () const { return d_rx_enable; }
+
+  bool disable_rx ();          // conditional disable, return prev state
+  void restore_rx (bool on);   // conditional set
+
+  void probe_rx_slots (bool verbose);
+
+public:
+  ~usrp_basic_rx ();
+
+  std::vector< std::vector<db_base_sptr> > db();
+  std::vector<db_base_sptr> db(int which);
+  
+  int daughterboard_id (int which_dboard) const;
+  bool _write_oe (int which_dboard, int value, int mask);
+  bool write_io (int which_dboard, int value, int mask);
+  bool read_io (int which_dboard, int *value);
+  int  read_io (int which_dboard);
+
+  /*!
+   * \brief invokes constructor, returns instance or 0 if trouble
+   *
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512. 
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default. 
+   */
+  static usrp_basic_rx *make (int which_board,
+                             int fusb_block_size=0,
+                             int fusb_nblocks=0,
+                             const std::string fpga_filename = "",
+                             const std::string firmware_filename = ""
+                             );
+
+  // MANIPULATORS
+
+  /*!
+   * \brief tell the fpga the rate rx samples are coming from the A/D's
+   *
+   * div = fpga_master_clock_freq () / sample_rate
+   *
+   * sample_rate is determined by a myriad of registers
+   * in the 9862.  That's why you have to tell us, so
+   * we can tell the fpga.
+   */
+  bool set_fpga_rx_sample_rate_divisor (unsigned int div);
+
+  /*!
+   * \brief read data from the D/A's via the FPGA.
+   * \p len must be a multiple of 512 bytes.
+   *
+   * \returns the number of bytes read, or -1 on error.
+   *
+   * If overrun is non-NULL it will be set true iff an RX overrun is detected.
+   */
+  int read (void *buf, int len, bool *overrun);
+
+  // ACCESSORS
+
+  //! sampling rate of A/D converter
+  long converter_rate() const { return fpga_master_clock_freq(); } // 64M
+  long adc_rate() const { return converter_rate(); }
+  long adc_freq() const { return converter_rate(); }   //!< deprecated method 
name
+
+
+  // ----------------------------------------------------------------
+  // routines for controlling the Programmable Gain Amplifier
+  /*!
+   * \brief Set Programmable Gain Amplifier (PGA)
+   *
+   * \param which      which A/D [0,3]
+   * \param gain_in_db gain value (linear in dB)
+   *
+   * gain is rounded to closest setting supported by hardware.
+   *
+   * \returns true iff sucessful.
+   *
+   * \sa pga_min(), pga_max(), pga_db_per_step()
+   */
+  bool set_pga (int which, double gain_in_db);
+
+  /*!
+   * \brief Return programmable gain amplifier gain setting in dB.
+   *
+   * \param which      which A/D [0,3]
+   */
+  double pga (int which) const;
+
+  /*!
+   * \brief Return minimum legal PGA gain in dB.
+   */
+  double pga_min () const { return usrp_basic::pga_min(); }
+
+  /*!
+   * \brief Return maximum legal PGA gain in dB.
+   */
+  double pga_max () const { return usrp_basic::pga_max(); }
+
+  /*!
+   * \brief Return hardware step size of PGA (linear in dB).
+   */
+  double pga_db_per_step () const { return usrp_basic::pga_db_per_step(); }
+
+  /*!
+   * \brief Write auxiliary digital to analog converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   *                           N.B., SLOT_TX_A and SLOT_RX_A share the same 
AUX DAC's.
+   *                           SLOT_TX_B and SLOT_RX_B share the same AUX 
DAC's.
+   * \param which_dac          [2,3] TX slots must use only 2 and 3.
+   * \param value              [0,4095]
+   * \returns true iff successful
+   */
+  bool write_aux_dac (int which_board, int which_dac, int value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \param value              return 12-bit value [0,4095]
+   * \returns true iff successful
+   */
+  bool read_aux_adc (int which_dboard, int which_adc, int *value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \returns value in the range [0,4095] if successful, else READ_FAILED.
+   */
+  int read_aux_adc (int which_dboard, int which_adc);
+
+  /*!
+   * \brief returns current fusb block size
+   */
+  int block_size() const;
+
+  /*!
+   * \brief Enable/disable automatic DC offset removal control loop in FPGA
+   *
+   * \param bits  which control loops to enable
+   * \param mask  which \p bits to pay attention to
+   *
+   * If the corresponding bit is set, enable the automatic DC
+   * offset correction control loop.
+   *
+   * <pre>
+   * The 4 low bits are significant:
+   *
+   *   ADC0 = (1 << 0)
+   *   ADC1 = (1 << 1)
+   *   ADC2 = (1 << 2)
+   *   ADC3 = (1 << 3)
+   * </pre>
+   *
+   * By default the control loop is enabled on all ADC's.
+   */
+  bool set_dc_offset_cl_enable(int bits, int mask);
+
+  // called in base class to derived class order
+  bool start ();
+  bool stop ();
+};
+
+/*!
+ * \brief class for accessing the transmit side of the USRP
+ */
+class usrp_basic_tx : public usrp_basic 
+{
+private:
+  fusb_devhandle       *d_devhandle;
+  fusb_ephandle                *d_ephandle;
+  int                   d_bytes_seen;          // how many bytes we've seen
+  bool                  d_first_write;
+  bool                  d_tx_enable;
+
+ protected:
+
+  /*!
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512.
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default.
+   */
+  usrp_basic_tx (int which_board,
+                int fusb_block_size=0,
+                int fusb_nblocks=0,
+                const std::string fpga_filename = "",
+                const std::string firmware_filename = ""
+                );             // throws if trouble
+
+  bool set_tx_enable (bool on);
+  bool tx_enable () const { return d_tx_enable; }
+
+  bool disable_tx ();          // conditional disable, return prev state
+  void restore_tx (bool on);   // conditional set
+
+  void probe_tx_slots (bool verbose);
+
+public:
+
+  ~usrp_basic_tx ();
+
+  std::vector< std::vector<db_base_sptr> > db();
+  std::vector<db_base_sptr> db(int which);
+
+  int daughterboard_id (int which_dboard) const;
+  bool _write_oe (int which_dboard, int value, int mask);
+  bool write_io (int which_dboard, int value, int mask);
+  bool read_io (int which_dboard, int *value);
+  int  read_io (int which_dboard);
+
+  /*!
+   * \brief invokes constructor, returns instance or 0 if trouble
+   *
+   * \param which_board             Which USRP board on usb (not particularly 
useful; use 0)
+   * \param fusb_block_size  fast usb xfer block size.  Must be a multiple of 
512. 
+   *                         Use zero for a reasonable default.
+   * \param fusb_nblocks     number of fast usb URBs to allocate.  Use zero 
for a reasonable default. 
+   */
+  static usrp_basic_tx *make (int which_board, int fusb_block_size=0, int 
fusb_nblocks=0,
+                             const std::string fpga_filename = "",
+                             const std::string firmware_filename = ""
+                             );
+
+  // MANIPULATORS
+
+  /*!
+   * \brief tell the fpga the rate tx samples are going to the D/A's
+   *
+   * div = fpga_master_clock_freq () * 2
+   *
+   * sample_rate is determined by a myriad of registers
+   * in the 9862.  That's why you have to tell us, so
+   * we can tell the fpga.
+   */
+  bool set_fpga_tx_sample_rate_divisor (unsigned int div);
+
+  /*!
+   * \brief Write data to the A/D's via the FPGA.
+   *
+   * \p len must be a multiple of 512 bytes.
+   * \returns number of bytes written or -1 on error.
+   *
+   * if \p underrun is non-NULL, it will be set to true iff
+   * a transmit underrun condition is detected.
+   */
+  int write (const void *buf, int len, bool *underrun);
+
+  /*
+   * Block until all outstanding writes have completed.
+   * This is typically used to assist with benchmarking
+   */
+  void wait_for_completion ();
+
+
+  // ACCESSORS
+
+  //! sampling rate of D/A converter
+  long converter_rate() const { return fpga_master_clock_freq () * 2; } // 128M
+  long dac_rate() const { return converter_rate(); }
+  long dac_freq() const { return converter_rate(); }   //!< deprecated method 
name
+
+  // ----------------------------------------------------------------
+  // routines for controlling the Programmable Gain Amplifier
+  /*!
+   * \brief Set Programmable Gain Amplifier (PGA)
+   *
+   * \param which      which D/A [0,3]
+   * \param gain_in_db gain value (linear in dB)
+   *
+   * gain is rounded to closest setting supported by hardware.
+   * Note that DAC 0 and DAC 1 share a gain setting as do DAC 2 and DAC 3.
+   * Setting DAC 0 affects DAC 1 and vice versa.  Same with DAC 2 and DAC 3.
+   *
+   * \returns true iff sucessful.
+   *
+   * \sa pga_min(), pga_max(), pga_db_per_step()
+   */
+  bool set_pga (int which, double gain_in_db);
+
+  /*!
+   * \brief Return programmable gain amplifier gain in dB.
+   *
+   * \param which      which D/A [0,3]
+   */
+  double pga (int which) const;
+
+  /*!
+   * \brief Return minimum legal PGA gain in dB.
+   */
+  double pga_min () const { return usrp_basic::pga_min(); }
+
+  /*!
+   * \brief Return maximum legal PGA gain in dB.
+   */
+  double pga_max () const { return usrp_basic::pga_max(); }
+
+  /*!
+   * \brief Return hardware step size of PGA (linear in dB).
+   */
+  double pga_db_per_step () const { return usrp_basic::pga_db_per_step(); }
+
+  /*!
+   * \brief Write auxiliary digital to analog converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   *                           N.B., SLOT_TX_A and SLOT_RX_A share the same 
AUX DAC's.
+   *                           SLOT_TX_B and SLOT_RX_B share the same AUX 
DAC's.
+   * \param which_dac          [2,3] TX slots must use only 2 and 3.
+   * \param value              [0,4095]
+   * \returns true iff successful
+   */
+  bool write_aux_dac (int which_board, int which_dac, int value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \param value              return 12-bit value [0,4095]
+   * \returns true iff successful
+   */
+  bool read_aux_adc (int which_dboard, int which_adc, int *value);
+
+  /*!
+   * \brief Read auxiliary analog to digital converter.
+   *
+   * \param which_dboard       [0,1] which d'board
+   * \param which_adc          [0,1]
+   * \returns value in the range [0,4095] if successful, else READ_FAILED.
+   */
+  int read_aux_adc (int which_dboard, int which_adc);
+
+  /*!
+   * \brief returns current fusb block size
+   */
+  int block_size() const;
+
+  // called in base class to derived class order
+  bool start ();
+  bool stop ();
+};
+
+#endif





reply via email to

[Prev in Thread] Current Thread [Next in Thread]