From: Thomas Tsou Date: Sun, 18 Oct 2009 02:28:43 +0000 (-0400) Subject: usrp: Cleanup of usrp_basic X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=f9c3bfb83af1048db54de941df1898f2ec7fb1fc;p=debian%2Fgnuradio usrp: Cleanup of usrp_basic Version specific libusb calls are pushed out of usrp_basic into usrp_prims where they belong. This leads to a single usrp_basic file. A new function in usrp_prims, usrp_deinit(), handles shutdown specific to version 1.0. --- diff --git a/usrp/host/include/usrp/usrp_prims.h b/usrp/host/include/usrp/usrp_prims.h index 323287d0..4780d000 100644 --- a/usrp/host/include/usrp/usrp_prims.h +++ b/usrp/host/include/usrp/usrp_prims.h @@ -53,6 +53,15 @@ enum usrp_load_status_t { ULS_ERROR = 0, ULS_OK, ULS_ALREADY_LOADED }; void usrp_one_time_init (libusb_context **ctx = NULL); +/*! + * \brief deinitialize libusb + * + * libusb-0.1: No effect + * + * libusb-1.0: Deinitialize context ctx + */ +void usrp_deinit (libusb_context *ctx); + /* * force a rescan of the buses and devices */ diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am index 72312ebb..e80f2711 100644 --- a/usrp/host/lib/Makefile.am +++ b/usrp/host/lib/Makefile.am @@ -61,8 +61,7 @@ BUILT_SOURCES += usrp_dbid.cc \ generic_CODE = \ fusb_generic.cc \ fusb_sysconfig_generic.cc \ - usrp_prims_libusb0.cc \ - usrp_basic_libusb0.cc + usrp_prims_libusb0.cc darwin_CODE = \ fusb_darwin.cc \ @@ -72,34 +71,29 @@ darwin_CODE = \ circular_linked_list.h \ darwin_libusb.h \ mld_threads.h \ - usrp_prims_libusb0.cc \ - usrp_basic_libusb0.cc + usrp_prims_libusb0.cc win32_CODE = \ fusb_win32.cc \ fusb_sysconfig_win32.cc \ - usrp_prims_libusb0.cc \ - usrp_basic_libusb0.cc + usrp_prims_libusb0.cc linux_CODE = \ fusb_linux.cc \ fusb_sysconfig_linux.cc \ - usrp_prims_libusb0.cc \ - usrp_basic_libusb0.cc + usrp_prims_libusb0.cc ra_wb_CODE = \ fusb_ra_wb.cc \ fusb_sysconfig_ra_wb.cc \ - usrp_prims_libusb0.cc \ - usrp_basic_libusb0.cc + usrp_prims_libusb0.cc libusb1_CODE = \ fusb_libusb1.cc \ fusb_sysconfig_libusb1.cc \ - usrp_prims_libusb1.cc \ - usrp_basic_libusb1.cc + usrp_prims_libusb1.cc # # include each _CODE entry here... @@ -116,14 +110,14 @@ EXTRA_libusrp_la_SOURCES = \ libusrp_la_common_SOURCES = \ fusb.cc \ md5.c \ - usrp_basic_common.cc \ + usrp_basic.cc \ usrp_config.cc \ usrp_dbid.cc \ usrp_local_sighandler.cc \ usrp_prims_common.cc \ usrp_standard.cc \ - db_wbxng_adf4350.cc \ - db_wbxng_adf4350_regs.cc \ + db_wbxng_adf4350.cc \ + db_wbxng_adf4350_regs.cc \ db_boards.cc \ db_base.cc \ db_basic.cc \ diff --git a/usrp/host/lib/usrp_basic.cc b/usrp/host/lib/usrp_basic.cc new file mode 100644 index 00000000..5b2f7ff7 --- /dev/null +++ b/usrp/host/lib/usrp_basic.cc @@ -0,0 +1,1538 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either 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/usrp_basic.h" +#include "usrp/usrp_prims.h" +#include "usrp_interfaces.h" +#include "fpga_regs_common.h" +#include "fpga_regs_standard.h" +#include "fusb.h" +#include "db_boards.h" +#include +#include +#include +#include +#include +#include + +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 libusb_device_handle * +open_rx_interface (libusb_device *dev) +{ + libusb_device_handle *udh = usrp_open_rx_interface (dev); + if (udh == 0){ + fprintf (stderr, "usrp_basic_rx: can't open rx interface\n"); + } + return udh; +} + +static libusb_device_handle * +open_tx_interface (libusb_device *dev) +{ + libusb_device_handle *udh = usrp_open_tx_interface (dev); + if (udh == 0){ + fprintf (stderr, "usrp_basic_tx: can't open tx interface\n"); + } + 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, + libusb_device_handle * + open_interface (libusb_device *dev), + const std::string fpga_filename, + const std::string firmware_filename) + : d_udh (0), d_ctx (0), + d_usb_data_rate (16000000), // SWAG, see below + d_bytes_per_poll ((int) (POLLING_INTERVAL * d_usb_data_rate)), + d_verbose (false), d_fpga_master_clock_freq(64000000), d_db(2) +{ + /* + * 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 (&d_ctx); + + if (!usrp_load_standard_bits (which_board, false, fpga_filename, + firmware_filename, d_ctx)) + throw std::runtime_error ("usrp_basic/usrp_load_standard_bits"); + + libusb_device *dev = usrp_find_device (which_board, false, d_ctx); + 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); // forget db shared ptrs + + if (d_udh) + usrp_close_interface (d_udh); + + usrp_deinit (d_ctx); +} + +void +usrp_basic::shutdown_daughterboards() +{ + // nuke d'boards before we close down USB in ~usrp_basic + // shutdown() will do any board shutdown while the USRP can still + // be talked to + for(size_t i = 0; i < d_db.size(); i++) + for(size_t j = 0; j < d_db[i].size(); j++) + d_db[i][j]->shutdown(); +} + +void +usrp_basic::init_db(usrp_basic_sptr u) +{ + if (u.get() != this) + throw std::invalid_argument("u is not this"); + + d_db[0] = instantiate_dbs(d_dbid[0], u, 0); + d_db[1] = instantiate_dbs(d_dbid[1], u, 1); +} + +std::vector +usrp_basic::db(int which_side) +{ + which_side &= 0x1; // clamp it to avoid any reporting any errors + return d_db[which_side]; +} + +bool +usrp_basic::is_valid(const usrp_subdev_spec &ss) +{ + if (ss.side < 0 || ss.side > 1) + return false; + + if (ss.subdev < 0 || ss.subdev >= d_db[ss.side].size()) + return false; + + return true; +} + +db_base_sptr +usrp_basic::selected_subdev(const usrp_subdev_spec &ss) +{ + if (!is_valid(ss)) + throw std::invalid_argument("invalid subdev_spec"); + + return d_db[ss.side][ss.subdev]; +} + +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_adc, int offset) +{ + if (which_adc < 0 || which_adc > 3) + return false; + + return _write_fpga_reg (FR_ADC_OFFSET_0 + which_adc, offset); +} + +bool +usrp_basic::set_dac_offset (int which_dac, int offset, int offset_pin) +{ + if (which_dac < 0 || which_dac > 3) + return false; + + int which_codec = which_dac >> 1; + int tx_a = (which_dac & 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_adc, bool bypass) +{ + if (which_adc < 0 || which_adc > 3) + return false; + + int codec = which_adc >> 1; + int reg = (which_adc & 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_adc & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B; + } + else { + cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER; + cur_pwr_dn &= ~(((which_adc & 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::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)); +} + +// ---------------------------------------------------------------- + +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_led, bool on) +{ + return usrp_set_led (d_udh, which_led, on); +} + +bool +usrp_basic::write_atr_tx_delay(int value) +{ + return _write_fpga_reg(FR_ATR_TX_DELAY, value); +} + +bool +usrp_basic::write_atr_rx_delay(int value) +{ + return _write_fpga_reg(FR_ATR_RX_DELAY, value); +} + +/* + * ---------------------------------------------------------------- + * Routines to access and control daughterboard specific i/o + * ---------------------------------------------------------------- + */ +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]; +} + +static int +slot_id_to_refclk_reg(int slot_id) +{ + static int reg[4] = { FR_TX_A_REFCLK, FR_RX_A_REFCLK, FR_TX_B_REFCLK, FR_RX_B_REFCLK }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_atr_mask_reg(int slot_id) +{ + static int reg[4] = { FR_ATR_MASK_0, FR_ATR_MASK_1, FR_ATR_MASK_2, FR_ATR_MASK_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_atr_txval_reg(int slot_id) +{ + static int reg[4] = { FR_ATR_TXVAL_0, FR_ATR_TXVAL_1, FR_ATR_TXVAL_2, FR_ATR_TXVAL_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_atr_rxval_reg(int slot_id) +{ + static int reg[4] = { FR_ATR_RXVAL_0, FR_ATR_RXVAL_1, FR_ATR_RXVAL_2, FR_ATR_RXVAL_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +to_slot(txrx_t txrx, int which_side) +{ + // TX_A = 0 + // RX_A = 1 + // TX_B = 2 + // RX_B = 3 + return ((which_side & 0x1) << 1) | ((txrx & 0x1) == C_RX); +} + +bool +usrp_basic::common_set_pga(txrx_t txrx, int which_amp, double gain) +{ + if (which_amp < 0 || which_amp > 3) + return false; + + gain = std::min(common_pga_max(txrx), + std::max(common_pga_min(txrx), gain)); + + int codec = which_amp >> 1; + int int_gain = (int) rint((gain - common_pga_min(txrx)) / common_pga_db_per_step(txrx)); + + if (txrx == C_TX){ // 0 and 1 are same, as are 2 and 3 + return _write_9862(codec, REG_TX_PGA, int_gain); + } + else { + int reg = (which_amp & 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; + + cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f); + return _write_9862(codec, reg, cur_rx); + } +} + +double +usrp_basic::common_pga(txrx_t txrx, int which_amp) const +{ + if (which_amp < 0 || which_amp > 3) + return READ_FAILED; + + if (txrx == C_TX){ + int codec = which_amp >> 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(); + } + else { + int codec = which_amp >> 1; + int reg = (which_amp & 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::common_pga_min(txrx_t txrx) const +{ + if (txrx == C_TX) + return -20.0; + else + return 0.0; +} + +double +usrp_basic::common_pga_max(txrx_t txrx) const +{ + if (txrx == C_TX) + return 0.0; + else + return 20.0; +} + +double +usrp_basic::common_pga_db_per_step(txrx_t txrx) const +{ + if (txrx == C_TX) + return 20.0 / 255; + else + return 20.0 / 20; +} + +bool +usrp_basic::_common_write_oe(txrx_t txrx, int which_side, int value, int mask) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_oe_reg(to_slot(txrx, which_side)), + (mask << 16) | (value & 0xffff)); +} + +bool +usrp_basic::common_write_io(txrx_t txrx, int which_side, int value, int mask) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_io_reg(to_slot(txrx, which_side)), + (mask << 16) | (value & 0xffff)); +} + +bool +usrp_basic::common_read_io(txrx_t txrx, int which_side, int *value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + int t; + int reg = which_side + 1; // FIXME, *very* magic number (fix in serial_io.v) + bool ok = _read_fpga_reg(reg, &t); + if (!ok) + return false; + + if (txrx == C_TX){ + *value = t & 0xffff; // FIXME, more magic + return true; + } + else { + *value = (t >> 16) & 0xffff; // FIXME, more magic + return true; + } +} + +int +usrp_basic::common_read_io(txrx_t txrx, int which_side) +{ + int value; + if (!common_read_io(txrx, which_side, &value)) + return READ_FAILED; + return value; +} + +bool +usrp_basic::common_write_refclk(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_refclk_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_atr_mask(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_atr_mask_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_atr_txval(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_atr_txval_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_atr_rxval(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_atr_rxval_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value) +{ + return _write_aux_dac(to_slot(txrx, which_side), which_dac, value); +} + +bool +usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value) +{ + return _read_aux_adc(to_slot(txrx, which_side), which_adc, value); +} + +int +usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc) +{ + return _read_aux_adc(to_slot(txrx, which_side), which_adc); +} + + +//////////////////////////////////////////////////////////////// +// +// 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); + + //d_db[0] = instantiate_dbs(d_dbid[0], this, 0); + //d_db[1] = instantiate_dbs(d_dbid[1], 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_ctx); + d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true, + fusb_block_size, fusb_nblocks); + + write_atr_mask(0, 0); // zero Rx A Auto Transmit/Receive regs + write_atr_txval(0, 0); + write_atr_rxval(0, 0); + write_atr_mask(1, 0); // zero Rx B Auto Transmit/Receive regs + write_atr_txval(1, 0); + write_atr_rxval(1, 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"); + } + + 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"); + } + + shutdown_daughterboards(); +} + + +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"); + return false; + } + + if (!set_rx_enable (true)){ + fprintf (stderr, "usrp_basic_rx: set_rx_enable failed\n"); + 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"); + ok = false; + } + + if (!d_ephandle->stop()){ + fprintf (stderr, "usrp_basic_rx: failed to stop end point streaming"); + 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"); + } + } + + 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); +} + +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 = ""; + _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::set_pga (int which_amp, double gain) +{ + return common_set_pga(C_RX, which_amp, gain); +} + +double +usrp_basic_rx::pga(int which_amp) const +{ + return common_pga(C_RX, which_amp); +} + +double +usrp_basic_rx::pga_min() const +{ + return common_pga_min(C_RX); +} + +double +usrp_basic_rx::pga_max() const +{ + return common_pga_max(C_RX); +} + +double +usrp_basic_rx::pga_db_per_step() const +{ + return common_pga_db_per_step(C_RX); +} + +bool +usrp_basic_rx::_write_oe (int which_side, int value, int mask) +{ + return _common_write_oe(C_RX, which_side, value, mask); +} + +bool +usrp_basic_rx::write_io (int which_side, int value, int mask) +{ + return common_write_io(C_RX, which_side, value, mask); +} + +bool +usrp_basic_rx::read_io (int which_side, int *value) +{ + return common_read_io(C_RX, which_side, value); +} + +int +usrp_basic_rx::read_io (int which_side) +{ + return common_read_io(C_RX, which_side); +} + +bool +usrp_basic_rx::write_refclk(int which_side, int value) +{ + return common_write_refclk(C_RX, which_side, value); +} + +bool +usrp_basic_rx::write_atr_mask(int which_side, int value) +{ + return common_write_atr_mask(C_RX, which_side, value); +} + +bool +usrp_basic_rx::write_atr_txval(int which_side, int value) +{ + return common_write_atr_txval(C_RX, which_side, value); +} + +bool +usrp_basic_rx::write_atr_rxval(int which_side, int value) +{ + return common_write_atr_rxval(C_RX, which_side, value); +} + +bool +usrp_basic_rx::write_aux_dac (int which_side, int which_dac, int value) +{ + return common_write_aux_dac(C_RX, which_side, which_dac, value); +} + +bool +usrp_basic_rx::read_aux_adc (int which_side, int which_adc, int *value) +{ + return common_read_aux_adc(C_RX, which_side, which_adc, value); +} + +int +usrp_basic_rx::read_aux_adc (int which_side, int which_adc) +{ + return common_read_aux_adc(C_RX, which_side, which_adc); +} + +int +usrp_basic_rx::block_size () const { return d_ephandle->block_size(); } + +//////////////////////////////////////////////////////////////// +// +// 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); + + //d_db[0] = instantiate_dbs(d_dbid[0], this, 0); + //d_db[1] = instantiate_dbs(d_dbid[1], 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_ctx); + d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false, + fusb_block_size, fusb_nblocks); + + write_atr_mask(0, 0); // zero Tx A Auto Transmit/Receive regs + write_atr_txval(0, 0); + write_atr_rxval(0, 0); + write_atr_mask(1, 0); // zero Tx B Auto Transmit/Receive regs + write_atr_txval(1, 0); + write_atr_rxval(1, 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"); + } + + shutdown_daughterboards(); +} + +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"); + return false; + } + + if (!d_ephandle->start ()){ + fprintf (stderr, "usrp_basic_tx: failed to start end point streaming"); + 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"); + ok = false; + } + + if (!set_tx_enable (false)){ + fprintf (stderr, "usrp_basic_tx: set_tx_enable(false) failed\n"); + 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"); + } + } + + 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); +} + +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 = ""; + _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::set_pga (int which_amp, double gain) +{ + return common_set_pga(C_TX, which_amp, gain); +} + +double +usrp_basic_tx::pga (int which_amp) const +{ + return common_pga(C_TX, which_amp); +} + +double +usrp_basic_tx::pga_min() const +{ + return common_pga_min(C_TX); +} + +double +usrp_basic_tx::pga_max() const +{ + return common_pga_max(C_TX); +} + +double +usrp_basic_tx::pga_db_per_step() const +{ + return common_pga_db_per_step(C_TX); +} + +bool +usrp_basic_tx::_write_oe (int which_side, int value, int mask) +{ + return _common_write_oe(C_TX, which_side, value, mask); +} + +bool +usrp_basic_tx::write_io (int which_side, int value, int mask) +{ + return common_write_io(C_TX, which_side, value, mask); +} + +bool +usrp_basic_tx::read_io (int which_side, int *value) +{ + return common_read_io(C_TX, which_side, value); +} + +int +usrp_basic_tx::read_io (int which_side) +{ + return common_read_io(C_TX, which_side); +} + +bool +usrp_basic_tx::write_refclk(int which_side, int value) +{ + return common_write_refclk(C_TX, which_side, value); +} + +bool +usrp_basic_tx::write_atr_mask(int which_side, int value) +{ + return common_write_atr_mask(C_TX, which_side, value); +} + +bool +usrp_basic_tx::write_atr_txval(int which_side, int value) +{ + return common_write_atr_txval(C_TX, which_side, value); +} + +bool +usrp_basic_tx::write_atr_rxval(int which_side, int value) +{ + return common_write_atr_rxval(C_TX, which_side, value); +} + +bool +usrp_basic_tx::write_aux_dac (int which_side, int which_dac, int value) +{ + return common_write_aux_dac(C_TX, which_side, which_dac, value); +} + +bool +usrp_basic_tx::read_aux_adc (int which_side, int which_adc, int *value) +{ + return common_read_aux_adc(C_TX, which_side, which_adc, value); +} + +int +usrp_basic_tx::read_aux_adc (int which_side, int which_adc) +{ + return common_read_aux_adc(C_TX, which_side, which_adc); +} + +int +usrp_basic_tx::block_size () const { return d_ephandle->block_size(); } + diff --git a/usrp/host/lib/usrp_basic_common.cc b/usrp/host/lib/usrp_basic_common.cc deleted file mode 100644 index 721301de..00000000 --- a/usrp/host/lib/usrp_basic_common.cc +++ /dev/null @@ -1,1475 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either 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/usrp_basic.h" -#include "usrp/usrp_prims.h" -#include "usrp_interfaces.h" -#include "fpga_regs_common.h" -#include "fpga_regs_standard.h" -#include "fusb.h" -#include "db_boards.h" -#include -#include -#include -#include -#include -#include - -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 libusb_device_handle * -open_rx_interface (libusb_device *dev) -{ - libusb_device_handle *udh = usrp_open_rx_interface (dev); - if (udh == 0){ - fprintf (stderr, "usrp_basic_rx: can't open rx interface\n"); - } - return udh; -} - -static libusb_device_handle * -open_tx_interface (libusb_device *dev) -{ - libusb_device_handle *udh = usrp_open_tx_interface (dev); - if (udh == 0){ - fprintf (stderr, "usrp_basic_tx: can't open tx interface\n"); - } - 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 -}; - -void -usrp_basic::shutdown_daughterboards() -{ - // nuke d'boards before we close down USB in ~usrp_basic - // shutdown() will do any board shutdown while the USRP can still - // be talked to - for(size_t i = 0; i < d_db.size(); i++) - for(size_t j = 0; j < d_db[i].size(); j++) - d_db[i][j]->shutdown(); -} - -void -usrp_basic::init_db(usrp_basic_sptr u) -{ - if (u.get() != this) - throw std::invalid_argument("u is not this"); - - d_db[0] = instantiate_dbs(d_dbid[0], u, 0); - d_db[1] = instantiate_dbs(d_dbid[1], u, 1); -} - -std::vector -usrp_basic::db(int which_side) -{ - which_side &= 0x1; // clamp it to avoid any reporting any errors - return d_db[which_side]; -} - -bool -usrp_basic::is_valid(const usrp_subdev_spec &ss) -{ - if (ss.side < 0 || ss.side > 1) - return false; - - if (ss.subdev < 0 || ss.subdev >= d_db[ss.side].size()) - return false; - - return true; -} - -db_base_sptr -usrp_basic::selected_subdev(const usrp_subdev_spec &ss) -{ - if (!is_valid(ss)) - throw std::invalid_argument("invalid subdev_spec"); - - return d_db[ss.side][ss.subdev]; -} - -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_adc, int offset) -{ - if (which_adc < 0 || which_adc > 3) - return false; - - return _write_fpga_reg (FR_ADC_OFFSET_0 + which_adc, offset); -} - -bool -usrp_basic::set_dac_offset (int which_dac, int offset, int offset_pin) -{ - if (which_dac < 0 || which_dac > 3) - return false; - - int which_codec = which_dac >> 1; - int tx_a = (which_dac & 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_adc, bool bypass) -{ - if (which_adc < 0 || which_adc > 3) - return false; - - int codec = which_adc >> 1; - int reg = (which_adc & 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_adc & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B; - } - else { - cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER; - cur_pwr_dn &= ~(((which_adc & 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::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)); -} - -// ---------------------------------------------------------------- - -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_led, bool on) -{ - return usrp_set_led (d_udh, which_led, on); -} - -bool -usrp_basic::write_atr_tx_delay(int value) -{ - return _write_fpga_reg(FR_ATR_TX_DELAY, value); -} - -bool -usrp_basic::write_atr_rx_delay(int value) -{ - return _write_fpga_reg(FR_ATR_RX_DELAY, value); -} - -/* - * ---------------------------------------------------------------- - * Routines to access and control daughterboard specific i/o - * ---------------------------------------------------------------- - */ -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]; -} - -static int -slot_id_to_refclk_reg(int slot_id) -{ - static int reg[4] = { FR_TX_A_REFCLK, FR_RX_A_REFCLK, FR_TX_B_REFCLK, FR_RX_B_REFCLK }; - assert (0 <= slot_id && slot_id < 4); - return reg[slot_id]; -} - -static int -slot_id_to_atr_mask_reg(int slot_id) -{ - static int reg[4] = { FR_ATR_MASK_0, FR_ATR_MASK_1, FR_ATR_MASK_2, FR_ATR_MASK_3 }; - assert (0 <= slot_id && slot_id < 4); - return reg[slot_id]; -} - -static int -slot_id_to_atr_txval_reg(int slot_id) -{ - static int reg[4] = { FR_ATR_TXVAL_0, FR_ATR_TXVAL_1, FR_ATR_TXVAL_2, FR_ATR_TXVAL_3 }; - assert (0 <= slot_id && slot_id < 4); - return reg[slot_id]; -} - -static int -slot_id_to_atr_rxval_reg(int slot_id) -{ - static int reg[4] = { FR_ATR_RXVAL_0, FR_ATR_RXVAL_1, FR_ATR_RXVAL_2, FR_ATR_RXVAL_3 }; - assert (0 <= slot_id && slot_id < 4); - return reg[slot_id]; -} - -static int -to_slot(txrx_t txrx, int which_side) -{ - // TX_A = 0 - // RX_A = 1 - // TX_B = 2 - // RX_B = 3 - return ((which_side & 0x1) << 1) | ((txrx & 0x1) == C_RX); -} - -bool -usrp_basic::common_set_pga(txrx_t txrx, int which_amp, double gain) -{ - if (which_amp < 0 || which_amp > 3) - return false; - - gain = std::min(common_pga_max(txrx), - std::max(common_pga_min(txrx), gain)); - - int codec = which_amp >> 1; - int int_gain = (int) rint((gain - common_pga_min(txrx)) / common_pga_db_per_step(txrx)); - - if (txrx == C_TX){ // 0 and 1 are same, as are 2 and 3 - return _write_9862(codec, REG_TX_PGA, int_gain); - } - else { - int reg = (which_amp & 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; - - cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f); - return _write_9862(codec, reg, cur_rx); - } -} - -double -usrp_basic::common_pga(txrx_t txrx, int which_amp) const -{ - if (which_amp < 0 || which_amp > 3) - return READ_FAILED; - - if (txrx == C_TX){ - int codec = which_amp >> 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(); - } - else { - int codec = which_amp >> 1; - int reg = (which_amp & 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::common_pga_min(txrx_t txrx) const -{ - if (txrx == C_TX) - return -20.0; - else - return 0.0; -} - -double -usrp_basic::common_pga_max(txrx_t txrx) const -{ - if (txrx == C_TX) - return 0.0; - else - return 20.0; -} - -double -usrp_basic::common_pga_db_per_step(txrx_t txrx) const -{ - if (txrx == C_TX) - return 20.0 / 255; - else - return 20.0 / 20; -} - -bool -usrp_basic::_common_write_oe(txrx_t txrx, int which_side, int value, int mask) -{ - if (! (0 <= which_side && which_side <= 1)) - return false; - - return _write_fpga_reg(slot_id_to_oe_reg(to_slot(txrx, which_side)), - (mask << 16) | (value & 0xffff)); -} - -bool -usrp_basic::common_write_io(txrx_t txrx, int which_side, int value, int mask) -{ - if (! (0 <= which_side && which_side <= 1)) - return false; - - return _write_fpga_reg(slot_id_to_io_reg(to_slot(txrx, which_side)), - (mask << 16) | (value & 0xffff)); -} - -bool -usrp_basic::common_read_io(txrx_t txrx, int which_side, int *value) -{ - if (! (0 <= which_side && which_side <= 1)) - return false; - - int t; - int reg = which_side + 1; // FIXME, *very* magic number (fix in serial_io.v) - bool ok = _read_fpga_reg(reg, &t); - if (!ok) - return false; - - if (txrx == C_TX){ - *value = t & 0xffff; // FIXME, more magic - return true; - } - else { - *value = (t >> 16) & 0xffff; // FIXME, more magic - return true; - } -} - -int -usrp_basic::common_read_io(txrx_t txrx, int which_side) -{ - int value; - if (!common_read_io(txrx, which_side, &value)) - return READ_FAILED; - return value; -} - -bool -usrp_basic::common_write_refclk(txrx_t txrx, int which_side, int value) -{ - if (! (0 <= which_side && which_side <= 1)) - return false; - - return _write_fpga_reg(slot_id_to_refclk_reg(to_slot(txrx, which_side)), - value); -} - -bool -usrp_basic::common_write_atr_mask(txrx_t txrx, int which_side, int value) -{ - if (! (0 <= which_side && which_side <= 1)) - return false; - - return _write_fpga_reg(slot_id_to_atr_mask_reg(to_slot(txrx, which_side)), - value); -} - -bool -usrp_basic::common_write_atr_txval(txrx_t txrx, int which_side, int value) -{ - if (! (0 <= which_side && which_side <= 1)) - return false; - - return _write_fpga_reg(slot_id_to_atr_txval_reg(to_slot(txrx, which_side)), - value); -} - -bool -usrp_basic::common_write_atr_rxval(txrx_t txrx, int which_side, int value) -{ - if (! (0 <= which_side && which_side <= 1)) - return false; - - return _write_fpga_reg(slot_id_to_atr_rxval_reg(to_slot(txrx, which_side)), - value); -} - -bool -usrp_basic::common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value) -{ - return _write_aux_dac(to_slot(txrx, which_side), which_dac, value); -} - -bool -usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value) -{ - return _read_aux_adc(to_slot(txrx, which_side), which_adc, value); -} - -int -usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc) -{ - return _read_aux_adc(to_slot(txrx, which_side), which_adc); -} - - -//////////////////////////////////////////////////////////////// -// -// 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); - - //d_db[0] = instantiate_dbs(d_dbid[0], this, 0); - //d_db[1] = instantiate_dbs(d_dbid[1], 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_ctx); - d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true, - fusb_block_size, fusb_nblocks); - - write_atr_mask(0, 0); // zero Rx A Auto Transmit/Receive regs - write_atr_txval(0, 0); - write_atr_rxval(0, 0); - write_atr_mask(1, 0); // zero Rx B Auto Transmit/Receive regs - write_atr_txval(1, 0); - write_atr_rxval(1, 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"); - } - - 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"); - } - - shutdown_daughterboards(); -} - - -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"); - return false; - } - - if (!set_rx_enable (true)){ - fprintf (stderr, "usrp_basic_rx: set_rx_enable failed\n"); - 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"); - ok = false; - } - - if (!d_ephandle->stop()){ - fprintf (stderr, "usrp_basic_rx: failed to stop end point streaming"); - 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"); - } - } - - 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); -} - -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 = ""; - _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::set_pga (int which_amp, double gain) -{ - return common_set_pga(C_RX, which_amp, gain); -} - -double -usrp_basic_rx::pga(int which_amp) const -{ - return common_pga(C_RX, which_amp); -} - -double -usrp_basic_rx::pga_min() const -{ - return common_pga_min(C_RX); -} - -double -usrp_basic_rx::pga_max() const -{ - return common_pga_max(C_RX); -} - -double -usrp_basic_rx::pga_db_per_step() const -{ - return common_pga_db_per_step(C_RX); -} - -bool -usrp_basic_rx::_write_oe (int which_side, int value, int mask) -{ - return _common_write_oe(C_RX, which_side, value, mask); -} - -bool -usrp_basic_rx::write_io (int which_side, int value, int mask) -{ - return common_write_io(C_RX, which_side, value, mask); -} - -bool -usrp_basic_rx::read_io (int which_side, int *value) -{ - return common_read_io(C_RX, which_side, value); -} - -int -usrp_basic_rx::read_io (int which_side) -{ - return common_read_io(C_RX, which_side); -} - -bool -usrp_basic_rx::write_refclk(int which_side, int value) -{ - return common_write_refclk(C_RX, which_side, value); -} - -bool -usrp_basic_rx::write_atr_mask(int which_side, int value) -{ - return common_write_atr_mask(C_RX, which_side, value); -} - -bool -usrp_basic_rx::write_atr_txval(int which_side, int value) -{ - return common_write_atr_txval(C_RX, which_side, value); -} - -bool -usrp_basic_rx::write_atr_rxval(int which_side, int value) -{ - return common_write_atr_rxval(C_RX, which_side, value); -} - -bool -usrp_basic_rx::write_aux_dac (int which_side, int which_dac, int value) -{ - return common_write_aux_dac(C_RX, which_side, which_dac, value); -} - -bool -usrp_basic_rx::read_aux_adc (int which_side, int which_adc, int *value) -{ - return common_read_aux_adc(C_RX, which_side, which_adc, value); -} - -int -usrp_basic_rx::read_aux_adc (int which_side, int which_adc) -{ - return common_read_aux_adc(C_RX, which_side, which_adc); -} - -int -usrp_basic_rx::block_size () const { return d_ephandle->block_size(); } - -//////////////////////////////////////////////////////////////// -// -// 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); - - //d_db[0] = instantiate_dbs(d_dbid[0], this, 0); - //d_db[1] = instantiate_dbs(d_dbid[1], 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_ctx); - d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false, - fusb_block_size, fusb_nblocks); - - write_atr_mask(0, 0); // zero Tx A Auto Transmit/Receive regs - write_atr_txval(0, 0); - write_atr_rxval(0, 0); - write_atr_mask(1, 0); // zero Tx B Auto Transmit/Receive regs - write_atr_txval(1, 0); - write_atr_rxval(1, 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"); - } - - shutdown_daughterboards(); -} - -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"); - return false; - } - - if (!d_ephandle->start ()){ - fprintf (stderr, "usrp_basic_tx: failed to start end point streaming"); - 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"); - ok = false; - } - - if (!set_tx_enable (false)){ - fprintf (stderr, "usrp_basic_tx: set_tx_enable(false) failed\n"); - 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"); - } - } - - 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); -} - -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 = ""; - _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::set_pga (int which_amp, double gain) -{ - return common_set_pga(C_TX, which_amp, gain); -} - -double -usrp_basic_tx::pga (int which_amp) const -{ - return common_pga(C_TX, which_amp); -} - -double -usrp_basic_tx::pga_min() const -{ - return common_pga_min(C_TX); -} - -double -usrp_basic_tx::pga_max() const -{ - return common_pga_max(C_TX); -} - -double -usrp_basic_tx::pga_db_per_step() const -{ - return common_pga_db_per_step(C_TX); -} - -bool -usrp_basic_tx::_write_oe (int which_side, int value, int mask) -{ - return _common_write_oe(C_TX, which_side, value, mask); -} - -bool -usrp_basic_tx::write_io (int which_side, int value, int mask) -{ - return common_write_io(C_TX, which_side, value, mask); -} - -bool -usrp_basic_tx::read_io (int which_side, int *value) -{ - return common_read_io(C_TX, which_side, value); -} - -int -usrp_basic_tx::read_io (int which_side) -{ - return common_read_io(C_TX, which_side); -} - -bool -usrp_basic_tx::write_refclk(int which_side, int value) -{ - return common_write_refclk(C_TX, which_side, value); -} - -bool -usrp_basic_tx::write_atr_mask(int which_side, int value) -{ - return common_write_atr_mask(C_TX, which_side, value); -} - -bool -usrp_basic_tx::write_atr_txval(int which_side, int value) -{ - return common_write_atr_txval(C_TX, which_side, value); -} - -bool -usrp_basic_tx::write_atr_rxval(int which_side, int value) -{ - return common_write_atr_rxval(C_TX, which_side, value); -} - -bool -usrp_basic_tx::write_aux_dac (int which_side, int which_dac, int value) -{ - return common_write_aux_dac(C_TX, which_side, which_dac, value); -} - -bool -usrp_basic_tx::read_aux_adc (int which_side, int which_adc, int *value) -{ - return common_read_aux_adc(C_TX, which_side, which_adc, value); -} - -int -usrp_basic_tx::read_aux_adc (int which_side, int which_adc) -{ - return common_read_aux_adc(C_TX, which_side, which_adc); -} - -int -usrp_basic_tx::block_size () const { return d_ephandle->block_size(); } - diff --git a/usrp/host/lib/usrp_basic_libusb0.cc b/usrp/host/lib/usrp_basic_libusb0.cc deleted file mode 100644 index 21748058..00000000 --- a/usrp/host/lib/usrp_basic_libusb0.cc +++ /dev/null @@ -1,137 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either 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 -#include "usrp/usrp_prims.h" -#include "usrp_interfaces.h" -#include "fpga_regs_common.h" -#include "fpga_regs_standard.h" -#include "fusb.h" -#include "db_boards.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace ad9862; - -#define NELEM(x) (sizeof (x) / sizeof (x[0])) - - -static const double POLLING_INTERVAL = 0.1; // seconds - - -////////////////////////////////////////////////////////////////// -// -// usrp_basic -// -//////////////////////////////////////////////////////////////// - - -// Given: -// CLKIN = 64 MHz -// CLKSEL pin = high -// -// 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), d_fpga_master_clock_freq(64000000), d_db(2) -{ - /* - * 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 () -{ - // shutdown_daughterboards(); // call from ~usrp_basic_{tx,rx} - - d_db.resize(0); // forget db shared ptrs - - if (d_udh) - usb_close (d_udh); -} - diff --git a/usrp/host/lib/usrp_basic_libusb1.cc b/usrp/host/lib/usrp_basic_libusb1.cc deleted file mode 100644 index 35009dc6..00000000 --- a/usrp/host/lib/usrp_basic_libusb1.cc +++ /dev/null @@ -1,145 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either 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 -#include "usrp/usrp_prims.h" -#include "usrp_interfaces.h" -#include "fpga_regs_common.h" -#include "fpga_regs_standard.h" -#include "fusb.h" -#include "db_boards.h" -#include -#include -#include -#include -#include -#include -#include - - -using namespace ad9862; - -#define NELEM(x) (sizeof (x) / sizeof (x[0])) - - -static const double POLLING_INTERVAL = 0.1; // seconds - - -////////////////////////////////////////////////////////////////// -// -// 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 libusb_device_handle * - open_interface (struct libusb_device *dev), - const std::string fpga_filename, - const std::string firmware_filename) - : d_udh (0), d_ctx (0), - d_usb_data_rate (16000000), // SWAG, see below - d_bytes_per_poll ((int) (POLLING_INTERVAL * d_usb_data_rate)), - d_verbose (false), d_fpga_master_clock_freq(64000000), d_db(2) -{ - /* - * 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 (&d_ctx); - - if (!usrp_load_standard_bits (which_board, false, fpga_filename, firmware_filename, d_ctx)) - throw std::runtime_error ("usrp_basic/usrp_load_standard_bits"); - - struct libusb_device *dev = usrp_find_device (which_board, false, d_ctx); - 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 () -{ - // shutdown_daughterboards(); // call from ~usrp_basic_{tx,rx} - - d_db.resize(0); // forget db shared ptrs - - if (d_udh) - libusb_close (d_udh); - - // Each object _should_ be running in its own context. If running in default - // context then leave the instance open as it may be shared. - - if (d_ctx != NULL) - libusb_exit (d_ctx); -} - diff --git a/usrp/host/lib/usrp_prims_libusb0.cc b/usrp/host/lib/usrp_prims_libusb0.cc index 7053786d..4d1fd78c 100644 --- a/usrp/host/lib/usrp_prims_libusb0.cc +++ b/usrp/host/lib/usrp_prims_libusb0.cc @@ -105,6 +105,12 @@ usrp_one_time_init (libusb_context **ctx) } } +void +usrp_deinit (libusb_context *ctx) +{ + // nop +} + void usrp_rescan () { diff --git a/usrp/host/lib/usrp_prims_libusb1.cc b/usrp/host/lib/usrp_prims_libusb1.cc index fdd497ab..5dfe416e 100644 --- a/usrp/host/lib/usrp_prims_libusb1.cc +++ b/usrp/host/lib/usrp_prims_libusb1.cc @@ -135,6 +135,7 @@ _usb_control_transfer (struct libusb_device_handle *udh, int request_type, return ret; } + // ---------------------------------------------------------------- @@ -154,13 +155,21 @@ usrp_one_time_init (libusb_context **ctx) libusb_set_debug(*ctx, 3); } +void +usrp_deinit (struct libusb_context *ctx) +{ + // Each object _should_ be running in its own context. If running in default + // context then leave the instance open as it may be shared. + if (ctx != NULL) + libusb_exit (ctx); +} + void usrp_rescan () { // nop } - struct libusb_device * usrp_find_device (int nth, bool fx2_ok_p, libusb_context *ctx) {