diff options
Diffstat (limited to 'usrp/host/lib')
31 files changed, 2906 insertions, 455 deletions
diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am index 8e40692a5..17d4b8014 100644 --- a/usrp/host/lib/Makefile.am +++ b/usrp/host/lib/Makefile.am @@ -20,7 +20,7 @@ include $(top_srcdir)/Makefile.common -common_INCLUDES = $(USRP_INCLUDES) +common_INCLUDES = $(USRP_INCLUDES) -I$(USB_INCLUDEDIR) lib_LTLIBRARIES = libusrp.la @@ -44,13 +44,12 @@ endif EXTRA_DIST = \ std_paths.h.in \ - usrp_dbid.dat + usrp_dbid.dat -BUILT_SOURCES = \ - $(abs_top_builddir)/usrp/host/include/usrp/usrp_dbid.h +BUILT_SOURCES = $(abs_top_builddir)/usrp/host/include/usrp/usrp_dbid.h BUILT_SOURCES += usrp_dbid.cc \ - usrp_dbid.py + usrp_dbid.py # ---------------------------------------------------------------- # FUSB_TECH is set at configure time by way of @@ -61,7 +60,9 @@ BUILT_SOURCES += usrp_dbid.cc \ generic_CODE = \ fusb_generic.cc \ - fusb_sysconfig_generic.cc + fusb_sysconfig_generic.cc \ + usrp_prims_libusb0.cc \ + usrp_basic_libusb0.cc darwin_CODE = \ fusb_darwin.cc \ @@ -70,20 +71,35 @@ darwin_CODE = \ circular_buffer.h \ circular_linked_list.h \ darwin_libusb.h \ - mld_threads.h + mld_threads.h \ + usrp_prims_libusb0.cc \ + usrp_basic_libusb0.cc + win32_CODE = \ fusb_win32.cc \ - fusb_sysconfig_win32.cc + fusb_sysconfig_win32.cc \ + usrp_prims_libusb0.cc \ + usrp_basic_libusb0.cc + linux_CODE = \ fusb_linux.cc \ - fusb_sysconfig_linux.cc + fusb_sysconfig_linux.cc \ + usrp_prims_libusb0.cc \ + usrp_basic_libusb0.cc ra_wb_CODE = \ fusb_ra_wb.cc \ - fusb_sysconfig_ra_wb.cc + fusb_sysconfig_ra_wb.cc \ + usrp_prims_libusb0.cc \ + usrp_basic_libusb0.cc +libusb1_CODE = \ + fusb_libusb1.cc \ + fusb_sysconfig_libusb1.cc \ + usrp_prims_libusb1.cc \ + usrp_basic_libusb1.cc # # include each <foo>_CODE entry here... @@ -93,24 +109,24 @@ EXTRA_libusrp_la_SOURCES = \ $(darwin_CODE) \ $(win32_CODE) \ $(linux_CODE) \ - $(ra_wb_CODE) - + $(ra_wb_CODE) \ + $(libusb1_CODE) # work around automake deficiency libusrp_la_common_SOURCES = \ fusb.cc \ md5.c \ - usrp_basic.cc \ + usrp_basic_common.cc \ usrp_config.cc \ usrp_dbid.cc \ usrp_local_sighandler.cc \ - usrp_prims.cc \ + usrp_prims_common.cc \ usrp_standard.cc \ db_boards.cc \ db_base.cc \ db_basic.cc \ db_tv_rx.cc \ - db_tv_rx_mimo.cc \ + db_tv_rx_mimo.cc \ db_flexrf.cc \ db_flexrf_mimo.cc \ db_dbs_rx.cc \ @@ -119,8 +135,6 @@ libusrp_la_common_SOURCES = \ db_dtt768.cc \ db_util.cc - - if FUSB_TECH_generic libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(generic_CODE) endif @@ -141,6 +155,11 @@ if FUSB_TECH_ra_wb libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE) endif +if FUSB_TECH_libusb1 +libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(libusb1_CODE) +endif + + noinst_HEADERS = \ ad9862.h \ db_base_impl.h \ @@ -150,11 +169,13 @@ noinst_HEADERS = \ fusb_darwin.h \ fusb_generic.h \ fusb_linux.h \ + fusb_libusb1.h \ fusb_ra_wb.h \ fusb_win32.h \ md5.h \ rate_to_regval.h \ - usrp_config.h + usrp_config.h \ + usrp_primsi.h if PYTHON usrppython_PYTHON = \ diff --git a/usrp/host/lib/db_base.cc b/usrp/host/lib/db_base.cc index 102166a86..1cb463429 100644 --- a/usrp/host/lib/db_base.cc +++ b/usrp/host/lib/db_base.cc @@ -19,6 +19,10 @@ // Boston, MA 02110-1301, USA. // +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_base.h> #include <db_base_impl.h> diff --git a/usrp/host/lib/db_basic.cc b/usrp/host/lib/db_basic.cc index 0c6bedec4..1694d6a3f 100644 --- a/usrp/host/lib/db_basic.cc +++ b/usrp/host/lib/db_basic.cc @@ -18,6 +18,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_basic.h> #include <db_base_impl.h> diff --git a/usrp/host/lib/db_boards.cc b/usrp/host/lib/db_boards.cc index d6c644704..8ef5bac8b 100644 --- a/usrp/host/lib/db_boards.cc +++ b/usrp/host/lib/db_boards.cc @@ -20,6 +20,10 @@ // Boston, MA 02110-1301, USA. // +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <db_boards.h> #include <usrp/usrp_dbid.h> #include <usrp/db_basic.h> diff --git a/usrp/host/lib/db_dbs_rx.cc b/usrp/host/lib/db_dbs_rx.cc index 99f66c785..7fe8c4951 100644 --- a/usrp/host/lib/db_dbs_rx.cc +++ b/usrp/host/lib/db_dbs_rx.cc @@ -1,5 +1,5 @@ // -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008,2009 Free Software Foundation, Inc. // // This file is part of GNU Radio // @@ -18,6 +18,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_dbs_rx.h> #include <db_base_impl.h> #include <cmath> diff --git a/usrp/host/lib/db_dtt754.cc b/usrp/host/lib/db_dtt754.cc index d78c5b328..9ced705e4 100644 --- a/usrp/host/lib/db_dtt754.cc +++ b/usrp/host/lib/db_dtt754.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ // -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008,2009 Free Software Foundation, Inc. // // This file is part of GNU Radio // @@ -19,6 +19,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_dtt754.h> #include <db_base_impl.h> diff --git a/usrp/host/lib/db_dtt768.cc b/usrp/host/lib/db_dtt768.cc index a520fdc60..0dfe1a8f3 100644 --- a/usrp/host/lib/db_dtt768.cc +++ b/usrp/host/lib/db_dtt768.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ // -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008,2009 Free Software Foundation, Inc. // // This file is part of GNU Radio // @@ -19,6 +19,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_dtt768.h> #include <db_base_impl.h> diff --git a/usrp/host/lib/db_flexrf.cc b/usrp/host/lib/db_flexrf.cc index 2d2bfabbb..85ef79bd3 100644 --- a/usrp/host/lib/db_flexrf.cc +++ b/usrp/host/lib/db_flexrf.cc @@ -1,5 +1,5 @@ // -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008,2009 Free Software Foundation, Inc. // // This file is part of GNU Radio // @@ -18,6 +18,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_flexrf.h> #include <db_base_impl.h> diff --git a/usrp/host/lib/db_flexrf_mimo.cc b/usrp/host/lib/db_flexrf_mimo.cc index e2db5cd10..29bbbd58f 100644 --- a/usrp/host/lib/db_flexrf_mimo.cc +++ b/usrp/host/lib/db_flexrf_mimo.cc @@ -19,6 +19,10 @@ * Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_flexrf_mimo.h> #include <fpga_regs_standard.h> #include <fpga_regs_common.h> diff --git a/usrp/host/lib/db_tv_rx.cc b/usrp/host/lib/db_tv_rx.cc index 494ee7a1a..1822479e1 100644 --- a/usrp/host/lib/db_tv_rx.cc +++ b/usrp/host/lib/db_tv_rx.cc @@ -1,5 +1,5 @@ // -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008,2009 Free Software Foundation, Inc. // // This file is part of GNU Radio // @@ -18,6 +18,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_tv_rx.h> #include <db_base_impl.h> diff --git a/usrp/host/lib/db_tv_rx_mimo.cc b/usrp/host/lib/db_tv_rx_mimo.cc index d0dcb52a9..0964c5d8b 100644 --- a/usrp/host/lib/db_tv_rx_mimo.cc +++ b/usrp/host/lib/db_tv_rx_mimo.cc @@ -1,5 +1,5 @@ // -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008,2009 Free Software Foundation, Inc. // // This file is part of GNU Radio // @@ -18,6 +18,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_tv_rx_mimo.h> db_tv_rx_mimo::db_tv_rx_mimo(usrp_basic_sptr usrp, int which, diff --git a/usrp/host/lib/db_xcvr2450.cc b/usrp/host/lib/db_xcvr2450.cc index 408a05587..72367286c 100644 --- a/usrp/host/lib/db_xcvr2450.cc +++ b/usrp/host/lib/db_xcvr2450.cc @@ -18,6 +18,10 @@ // the Free Software Foundation, Inc., 51 Franklin Street, // Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/db_xcvr2450.h> #include <db_base_impl.h> #include <cmath> diff --git a/usrp/host/lib/fusb.cc b/usrp/host/lib/fusb.cc index 6e4358f5f..2a597b67c 100644 --- a/usrp/host/lib/fusb.cc +++ b/usrp/host/lib/fusb.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. + * Copyright 2003,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,12 +26,11 @@ #include <fusb.h> - // ------------------------------------------------------------------------ // device handle // ------------------------------------------------------------------------ -fusb_devhandle::fusb_devhandle (usb_dev_handle *udh) +fusb_devhandle::fusb_devhandle (libusb_device_handle *udh) : d_udh (udh) { // that's it diff --git a/usrp/host/lib/fusb.h b/usrp/host/lib/fusb.h index 769e51cca..538ae1ae0 100644 --- a/usrp/host/lib/fusb.h +++ b/usrp/host/lib/fusb.h @@ -1,32 +1,31 @@ -/* -*- c++ -*- */ +/* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. - * + * Copyright 2005,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. */ -// Fast USB interface - #ifndef _FUSB_H_ #define _FUSB_H_ +#include <usrp/libusb_types.h> -struct usb_dev_handle; +struct libusb_context; class fusb_ephandle; /*! @@ -39,11 +38,11 @@ private: fusb_devhandle &operator= (const fusb_devhandle &rhs); // no assignment operator protected: - usb_dev_handle *d_udh; + libusb_device_handle *d_udh; public: // CREATORS - fusb_devhandle (usb_dev_handle *udh); + fusb_devhandle (libusb_device_handle *udh); virtual ~fusb_devhandle (); // MANIPULATORS @@ -55,7 +54,7 @@ public: int block_size = 0, int nblocks = 0) = 0; // ACCESSORS - usb_dev_handle *get_usb_dev_handle () const { return d_udh; } + libusb_device_handle *get_usb_dev_handle () const { return d_udh; } }; @@ -116,7 +115,8 @@ public: /*! * \brief returns fusb_devhandle or throws if trouble */ - static fusb_devhandle *make_devhandle (usb_dev_handle *udh); + static fusb_devhandle *make_devhandle (libusb_device_handle *udh, + libusb_context *ctx = 0); /*! * \brief Returns max block size in bytes (hard limit). diff --git a/usrp/host/lib/fusb_libusb1.cc b/usrp/host/lib/fusb_libusb1.cc new file mode 100644 index 000000000..4846f51a5 --- /dev/null +++ b/usrp/host/lib/fusb_libusb1.cc @@ -0,0 +1,694 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,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 <fusb_libusb1.h> +#include <fusb.h> +#include <libusb-1.0/libusb.h> +#include <stdexcept> +#include <cstdio> +#include <assert.h> +#include <string.h> +#include <algorithm> +#include <errno.h> +#include <string.h> + +#define MINIMIZE_TX_BUFFERING true + +static const int MAX_BLOCK_SIZE = fusb_sysconfig::max_block_size(); +static const int DEFAULT_BLOCK_SIZE = MAX_BLOCK_SIZE; +static const int DEFAULT_BUFFER_SIZE = 4 * (1L << 20); // 4 MB endpoint +static const int LIBUSB_TIMEOUT = 0; // no timeout + +inline static fusb_ephandle_libusb1 * +lut_get_ephandle (libusb_transfer *lut) +{ + return (fusb_ephandle_libusb1 *) lut->user_data; +} + +// ------------------------------------------------------------------------ +// libusb_transfer allocation, deallocation, and callback +// ------------------------------------------------------------------------ + +static void +free_lut (libusb_transfer *lut) +{ + + // if this was an input transfer, free the buffer + if (lut->endpoint & 0x80) + delete [] ((unsigned char *) lut->buffer); + + libusb_free_transfer(lut); + +} + +/* + * The callback means the libusb_transfer is completed whether sent, cancelled, + * or failed. Move the libusb_transfer from the pending list to the + * completed list. If the cancel is from the destructor then free the + * transfer instead; normally this won't happen since all endpoints should be + * destroyed first leaving the pending list empty. + */ + +static void +generic_callback(struct libusb_transfer *lut) +{ + + // Fish out devhandle from endpoint + fusb_devhandle_libusb1* dev_handle = + lut_get_ephandle(lut)->get_fusb_devhandle_libusb1(); + + dev_handle->pending_remove(lut); + + if (lut->status == LIBUSB_TRANSFER_CANCELLED && dev_handle->_teardown() == 1) + { + free_lut (lut); + return; + } + + lut_get_ephandle(lut)->completed_list_add(lut); + +} + +static libusb_transfer* +alloc_lut (fusb_ephandle_libusb1 *self, int buffer_length, int endpoint, + bool input_p, unsigned char *write_buffer, + fusb_devhandle_libusb1 *dh) +{ + + struct libusb_transfer* lut = libusb_alloc_transfer(0); + + endpoint = (endpoint & 0x7f) | (input_p ? 0x80 : 0); + + if (input_p) + write_buffer = new unsigned char [buffer_length]; + + // We need the base class libusb_device_handle + libusb_device_handle *dev_handle = dh->get_usb_dev_handle(); + + // Load the libusb_transfer for bulk transfer + libusb_fill_bulk_transfer (lut, // transfer + dev_handle, // dev_handle + endpoint, // endpoint + write_buffer, // buffer + buffer_length, // length + generic_callback, // callback + self, // user_data + LIBUSB_TIMEOUT); // timeout + + return lut; +} + +// ------------------------------------------------------------------------ +// device handle +// ------------------------------------------------------------------------ + +fusb_devhandle_libusb1::fusb_devhandle_libusb1 (libusb_device_handle *udh, + libusb_context *ctx) + : fusb_devhandle (udh), d_ctx (ctx), d_teardown (false) +{ + // that's it +} + +fusb_devhandle_libusb1::~fusb_devhandle_libusb1 () +{ + d_teardown = true; + + std::list<libusb_transfer*>::reverse_iterator it; + + // After cancellation the libusb_transfer is still active so delay freeing + // transfer until callback occurs. In most cases the pending list should + // already be empty by the time this destructor is called. + + for (it = d_pending_rqsts.rbegin (); it != d_pending_rqsts.rend (); it++) { + _cancel_lut (*it); + } + + // Wait for pending list to empty + _wait_for_completion (); + +} + +fusb_ephandle* +fusb_devhandle_libusb1::make_ephandle (int endpoint, bool input_p, + int block_size, int nblocks) +{ + return new fusb_ephandle_libusb1 (this, endpoint, input_p, + block_size, nblocks); +} + +/* + * devhandle list manipulators + */ + +void +fusb_devhandle_libusb1::pending_add (libusb_transfer *lut) +{ + d_pending_rqsts.push_back (lut); +} + + +/* + * Attempt to cancel all transations associated with eph + */ + +void +fusb_devhandle_libusb1::_cancel_pending_rqsts (fusb_ephandle_libusb1 *eph) +{ + std::list<libusb_transfer*>::reverse_iterator it; + + for (it = d_pending_rqsts.rbegin (); it != d_pending_rqsts.rend (); it++){ + if (lut_get_ephandle (*it) == eph) + _cancel_lut (*it); + } +} + +/* + * Pull from the pending list + */ + +libusb_transfer * +fusb_devhandle_libusb1::pending_get () +{ + if (d_pending_rqsts.empty ()) + return 0; + + libusb_transfer *lut = d_pending_rqsts.front (); + d_pending_rqsts.pop_front (); + return lut; +} + +/* + * Match libusb_tranfer with the pending list and erase + * Return true if found, false otherwise + */ + +bool +fusb_devhandle_libusb1::pending_remove (libusb_transfer *lut) +{ + std::list<libusb_transfer*>::iterator result; + result = find (d_pending_rqsts.begin (), d_pending_rqsts.end (), lut); + + if (result == d_pending_rqsts.end ()) { + fprintf (stderr, "fusb::pending_remove: failed to find lut in pending_rqsts: %p\n", lut); + + return false; + } + d_pending_rqsts.erase (result); + return true; +} + +/* + * Submit the libusb_transfer to libusb + * iff successful, the transfer will be placed on the devhandle pending list. + */ + +bool +fusb_devhandle_libusb1::_submit_lut (libusb_transfer *lut) +{ + + int ret = libusb_submit_transfer (lut); + if (ret < 0) { + fprintf(stderr, "fusb::_submit_lut %d", ret); + return false; + } + + pending_add(lut); + return true; + +} + +/* + * Attempt to cancel any pending libusb_transfer transactions. + * Return true in the absence of errors, which does not mean that the transfer + * is cancelled. Cancellation can be checked after the callback is fired off + * by libusb. + */ + +bool +fusb_devhandle_libusb1::_cancel_lut (libusb_transfer *lut) +{ + + int ret = libusb_cancel_transfer (lut); + if (ret < 0) { + fprintf (stderr, "fusb::_cancel_lut"); + return false; + } + return true; + +} + +/* + * Reimplementing _reap for context use and compatibiliy with libusb-0.12. + * + * Returns false on timeout or error, true if an event was handled + * + * If ok_to_block_p is false then handle already pending events and return + * immediately. + * + * If ok_to_block_p is true then call libusb_handle_events_timeout with default + * timeout value of 2 seconds, which waits and returns on event arrival or + * timeout. + */ + +bool +fusb_devhandle_libusb1::_reap (bool ok_to_block_p) +{ + int ret; + struct timeval tv; + + if (ok_to_block_p) { + tv.tv_sec = 2; + tv.tv_usec = 0; + } + else { + tv.tv_sec = 0; + tv.tv_usec = 0; + } + + if ((ret = libusb_handle_events_timeout(d_ctx, &tv)) < 0) { + fprintf (stderr, "fusb::_reap libusb_handle_events() %i\n", ret); + return false; + } + + return true; +} + +void +fusb_devhandle_libusb1::_wait_for_completion () +{ + + while (!d_pending_rqsts.empty ()) + if (!_reap(true)) + break; + +} + +// ------------------------------------------------------------------------ +// endpoint handle +// ------------------------------------------------------------------------ + +fusb_ephandle_libusb1::fusb_ephandle_libusb1 (fusb_devhandle_libusb1 *dh, + int endpoint, bool input_p, + int block_size, int nblocks) + : fusb_ephandle (endpoint, input_p, block_size, nblocks), + d_devhandle (dh), + d_write_work_in_progress (0), d_write_buffer (0), + d_read_work_in_progress (0), d_read_buffer (0), d_read_buffer_end (0) +{ + + if (d_block_size < 0 || d_block_size > MAX_BLOCK_SIZE) + throw std::out_of_range ("fusb_ephandle_libusb1: block_size"); + + if (d_nblocks < 0) + throw std::out_of_range ("fusb_ephandle_libusb1: nblocks"); + + if (d_block_size == 0) + d_block_size = DEFAULT_BLOCK_SIZE; + + if (d_nblocks == 0) + d_nblocks = std::max (1, DEFAULT_BUFFER_SIZE / d_block_size); + + if (!d_input_p) + if (!MINIMIZE_TX_BUFFERING) + d_write_buffer = new unsigned char [d_block_size]; + + if (0) + fprintf(stderr, "fusb_ephandle_libusb1::ctor: d_block_size = %d d_nblocks = %d\n", + d_block_size, d_nblocks); + + // allocate libusb_transfers + for (int i = 0; i < d_nblocks; i++) + d_free_list.push_back (alloc_lut (this, d_block_size, d_endpoint, + d_input_p, d_write_buffer, d_devhandle)); +} + +fusb_ephandle_libusb1::~fusb_ephandle_libusb1 () +{ + + stop (); + + libusb_transfer *lut; + + while ((lut = free_list_get ()) != 0) + free_lut (lut); + + while ((lut = completed_list_get ()) != 0) + free_lut (lut); + + if (d_write_work_in_progress) + free_lut (d_write_work_in_progress); + + delete [] d_write_buffer; + + if (d_read_work_in_progress) + free_lut (d_read_work_in_progress); + +} + +bool +fusb_ephandle_libusb1::start () +{ + if (d_started) + return true; + + d_started = true; + + if (d_input_p) { + libusb_transfer *lut; + + int nerrors = 0; + while ((lut = free_list_get ()) !=0 && nerrors < d_nblocks) { + if (!submit_lut (lut)) + nerrors++; + } + } + + return true; + +} + +/* + * Cancel all transfers in progress or pending and return to initial state + */ + +bool +fusb_ephandle_libusb1::stop () +{ + + if (!d_started) + return true; + + if (d_write_work_in_progress){ + free_list_add (d_write_work_in_progress); + d_write_work_in_progress = 0; + } + + if (d_read_work_in_progress){ + free_list_add (d_read_work_in_progress); + d_read_work_in_progress = 0; + d_read_buffer = 0; + d_read_buffer_end = 0; + } + + d_devhandle->_cancel_pending_rqsts (this); + d_devhandle->_reap (false); + + while (1) { + libusb_transfer *lut; + while ((lut = completed_list_get ()) != 0) + free_list_add (lut); + + if (d_free_list.size () == (unsigned) d_nblocks) + break; + + if (!d_devhandle->_reap(true)) + break; + } + + d_started = false; + + return true; +} + +// ------------------------------------------------------------------------ +// routines for writing +// ------------------------------------------------------------------------ + +#if (MINIMIZE_TX_BUFFERING) + +int +fusb_ephandle_libusb1::write (const void *buffer, int nbytes) +{ + if (!d_started) // doesn't matter here, but keeps semantics constant + return -1; + + if (d_input_p) + return -1; + + assert(nbytes % 512 == 0); + + unsigned char *src = (unsigned char *) buffer; + + int n = 0; + while (n < nbytes){ + + struct libusb_transfer *lut = get_write_work_in_progress(); + if (!lut) + return -1; + assert(lut->actual_length == 0); + int m = std::min(nbytes - n, MAX_BLOCK_SIZE); + lut->buffer = src; + lut->length = m; + + n += m; + src += m; + + if (!submit_lut(lut)) + return -1; + + d_write_work_in_progress = 0; + } + + return n; +} + +#else + +int +fusb_ephandle_libusb1::write (const void *buffer, int nbytes) +{ + if (!d_started) + return -1; + + if (d_input_p) + return -1; + + unsigned char *src = (unsigned char *) buffer; + + int n = 0; + while (n < nbytes){ + + libusb_transfer *lut = get_write_work_in_progress (); + if (!lut) + return -1; + unsigned char *dst = (unsigned char *) lut->buffer; + int m = std::min (nbytes - n, lut->length - lut->actual_length); + + memcpy (&dst[lut->actual_length], &src[n], m); + lut->actual_length += m; + n += m; + + if (lut->actual_length == lut->length){ + if (!submit_lut (lut)) + return -1; + d_write_work_in_progress = 0; + } + } + + return n; +} + +#endif + +struct libusb_transfer * +fusb_ephandle_libusb1::get_write_work_in_progress () +{ + if (d_write_work_in_progress) + return d_write_work_in_progress; + + while (1) { + + reap_complete_writes (); + + struct libusb_transfer *lut = free_list_get (); + + if (lut != 0){ + assert (lut->actual_length == 0); + d_write_work_in_progress = lut; + return lut; + } + + if (!d_devhandle->_reap (true)) + return 0; + } +} + +void +fusb_ephandle_libusb1::reap_complete_writes () +{ + // take a look at the completed list and xfer to free list after + // checking for errors. + + libusb_transfer *lut; + + while ((lut = completed_list_get ()) != 0) { + + // Check for any errors or short writes that were reporetd in the transfer. + // libusb1 sets status, actual_length. + + if (lut->status != LIBUSB_TRANSFER_COMPLETED) { + fprintf (stderr, "fusb: (status %d) \n", lut->status ); + } + else if (lut->actual_length != lut->length){ + fprintf (stderr, "fusb: short write xfer: %d != %d\n", + lut->actual_length, lut->length); + } + + free_list_add (lut); + } +} + +void +fusb_ephandle_libusb1::wait_for_completion () +{ + d_devhandle->_wait_for_completion (); +} + +// ------------------------------------------------------------------------ +// routines for reading +// ------------------------------------------------------------------------ + +int +fusb_ephandle_libusb1::read (void *buffer, int nbytes) +{ + if (!d_started) // doesn't matter here, but keeps semantics constant + return -1; + + if (!d_input_p) + return -1; + + unsigned char *dst = (unsigned char *) buffer; + + int n = 0; + while (n < nbytes) { + + if (d_read_buffer >= d_read_buffer_end) + if (!reload_read_buffer ()) + return -1; + + int m = std::min (nbytes - n, (int) (d_read_buffer_end - d_read_buffer)); + + memcpy (&dst[n], d_read_buffer, m); + d_read_buffer += m; + n += m; + } + + return n; + +} + +bool +fusb_ephandle_libusb1::reload_read_buffer () +{ + assert (d_read_buffer >= d_read_buffer_end); + + libusb_transfer *lut; + + if (d_read_work_in_progress) { + lut = d_read_work_in_progress; + d_read_work_in_progress = 0; + d_read_buffer = 0; + d_read_buffer_end = 0; + lut->actual_length = 0; + if (!submit_lut (lut)) + return false; + } + + while (1) { + + while ((lut = completed_list_get ()) == 0 ) + if (!d_devhandle->_reap(true)) + return false; + + if (lut->status != LIBUSB_TRANSFER_COMPLETED) { + fprintf (stderr, "fust: (rd status %d) %s\n", lut->status, + strerror (-lut->status)); + lut->actual_length = 0; + free_list_add (lut); + return false; + } + + d_read_work_in_progress = lut; + d_read_buffer = (unsigned char *) lut->buffer; + d_read_buffer_end = d_read_buffer + lut->actual_length; + + return true; + } +} + + +/* + * ephandle list manipulation + */ + + +void +fusb_ephandle_libusb1::free_list_add (libusb_transfer *lut) +{ + assert (lut_get_ephandle (lut) == this); + lut->actual_length = 0; + d_free_list.push_back (lut); +} + +libusb_transfer * +fusb_ephandle_libusb1::free_list_get () +{ + if (d_free_list.empty ()) + return 0; + + libusb_transfer *lut = d_free_list.front (); + d_free_list.pop_front (); + return lut; +} + +void +fusb_ephandle_libusb1::completed_list_add (libusb_transfer *lut) +{ + assert (lut_get_ephandle (lut) == this); + d_completed_list.push_back (lut); +} + +libusb_transfer * +fusb_ephandle_libusb1::completed_list_get () +{ + if (d_completed_list.empty ()) + return 0; + + libusb_transfer *lut = d_completed_list.front (); + d_completed_list.pop_front (); + return lut; +} + +bool +fusb_ephandle_libusb1::submit_lut (libusb_transfer *lut) +{ + if (!d_devhandle->_submit_lut (lut)) { + fprintf (stderr, "_submit_lut failed\n"); + free_list_add (lut); + return false; + } + return true; +} diff --git a/usrp/host/lib/fusb_libusb1.h b/usrp/host/lib/fusb_libusb1.h new file mode 100644 index 000000000..c0e3736bd --- /dev/null +++ b/usrp/host/lib/fusb_libusb1.h @@ -0,0 +1,131 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,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. + */ + +#ifndef _FUSB_LIBUSB1_H_ +#define _FUSB_LIBUSB1_H_ + +#include <fusb.h> +#include <list> + +struct libusb_transfer; +struct libusb_context; + +class fusb_ephandle_libusb1; + +/*! + * \brief libusb1 implementation of fusb_devhandle + */ +class fusb_devhandle_libusb1 : public fusb_devhandle +{ +private: + std::list<libusb_transfer*> d_pending_rqsts; + libusb_context *d_ctx; + + void pending_add (struct libusb_transfer *lut); + struct libusb_transfer * pending_get (); + + bool d_teardown; + +public: + // CREATORS + fusb_devhandle_libusb1 (libusb_device_handle *udh, libusb_context *ctx); + virtual ~fusb_devhandle_libusb1 (); + + // MANIPULATORS + virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); + // internal use only + bool _submit_lut (libusb_transfer *); + bool _cancel_lut (libusb_transfer *); + void _cancel_pending_rqsts (fusb_ephandle_libusb1 *eph); + bool _reap (bool ok_to_block_p); + void _wait_for_completion (); + + // accessors to work from callback context + bool pending_remove (struct libusb_transfer *lut); + inline bool _teardown() { return d_teardown; } + +}; + + +/*! + * \brief libusb1 implementation of fusb_ephandle + */ +class fusb_ephandle_libusb1 : public fusb_ephandle +{ +private: + fusb_devhandle_libusb1 *d_devhandle; + std::list<libusb_transfer*> d_free_list; + std::list<libusb_transfer*> d_completed_list; + libusb_transfer *d_write_work_in_progress; + unsigned char *d_write_buffer; + libusb_transfer *d_read_work_in_progress; + unsigned char *d_read_buffer; + unsigned char *d_read_buffer_end; + + libusb_transfer *get_write_work_in_progress (); + void reap_complete_writes (); + bool reload_read_buffer (); + bool submit_lut (libusb_transfer *lut); + +public: + // CREATORS + fusb_ephandle_libusb1 (fusb_devhandle_libusb1 *dh, int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); + virtual ~fusb_ephandle_libusb1 (); + + // MANIPULATORS + + virtual bool start (); //!< begin streaming i/o + virtual bool stop (); //!< stop streaming i/o + + /*! + * \returns \p nbytes if write was successfully enqueued, else -1. + * Will block if no free buffers available. + */ + virtual int write (const void *buffer, int nbytes); + + /*! + * \returns number of bytes read or -1 if error. + * number of bytes read will be <= nbytes. + * Will block if no input available. + */ + virtual int read (void *buffer, int nbytes); + + /* + * block until all outstanding writes have completed + */ + virtual void wait_for_completion (); + + void free_list_add (struct libusb_transfer *lut); + void completed_list_add (struct libusb_transfer *lut); + struct libusb_transfer *free_list_get (); + struct libusb_transfer *completed_list_get (); + + // accessor to work from callback context + fusb_devhandle_libusb1* get_fusb_devhandle_libusb1 () const { + return d_devhandle; + } +}; + +#endif /* _FUSB_LINUX1_H_ */ + diff --git a/usrp/host/lib/fusb_sysconfig_darwin.cc b/usrp/host/lib/fusb_sysconfig_darwin.cc index 4d19d1292..68dd64815 100644 --- a/usrp/host/lib/fusb_sysconfig_darwin.cc +++ b/usrp/host/lib/fusb_sysconfig_darwin.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. + * Copyright 2003,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -27,7 +27,7 @@ static const int MAX_BLOCK_SIZE = 32 * 1024; // hard limit static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB fusb_devhandle * -fusb_sysconfig::make_devhandle (usb_dev_handle *udh) +fusb_sysconfig::make_devhandle (usb_dev_handle *udh, libusb_context *ctx) { return new fusb_devhandle_darwin (udh); } diff --git a/usrp/host/lib/fusb_sysconfig_generic.cc b/usrp/host/lib/fusb_sysconfig_generic.cc index 58baba5a5..e0986510c 100644 --- a/usrp/host/lib/fusb_sysconfig_generic.cc +++ b/usrp/host/lib/fusb_sysconfig_generic.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. + * Copyright 2003,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -27,7 +27,7 @@ static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB fusb_devhandle * -fusb_sysconfig::make_devhandle (usb_dev_handle *udh) +fusb_sysconfig::make_devhandle (usb_dev_handle *udh, libusb_context *ctx) { return new fusb_devhandle_generic (udh); } diff --git a/usrp/host/lib/fusb_sysconfig_libusb1.cc b/usrp/host/lib/fusb_sysconfig_libusb1.cc new file mode 100644 index 000000000..46daf561a --- /dev/null +++ b/usrp/host/lib/fusb_sysconfig_libusb1.cc @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,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. + */ + +#include <fusb.h> +#include <fusb_libusb1.h> + +static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit +static const int DEFAULT_BLOCK_SIZE = 4 * 1024; +static const int FUSB_BUFFER_SIZE = 1 * (1L << 20); // 1 MB + +struct libusb_context; + +fusb_devhandle * +fusb_sysconfig::make_devhandle (libusb_device_handle *udh, libusb_context *ctx) +{ + return new fusb_devhandle_libusb1 (udh, ctx); +} + +int fusb_sysconfig::max_block_size () +{ + return MAX_BLOCK_SIZE; +} + +int fusb_sysconfig::default_block_size () +{ + return DEFAULT_BLOCK_SIZE; +} + +int fusb_sysconfig::default_buffer_size () +{ + return FUSB_BUFFER_SIZE; +} diff --git a/usrp/host/lib/fusb_sysconfig_linux.cc b/usrp/host/lib/fusb_sysconfig_linux.cc index 3c2f59375..e33b90ba4 100644 --- a/usrp/host/lib/fusb_sysconfig_linux.cc +++ b/usrp/host/lib/fusb_sysconfig_linux.cc @@ -1,19 +1,19 @@ /* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. - * + * Copyright 2003,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, @@ -28,7 +28,7 @@ static const int DEFAULT_BLOCK_SIZE = 4 * 1024; // fewer kernel memory problem static const int FUSB_BUFFER_SIZE = 1 * (1L << 20); // 1MB fusb_devhandle * -fusb_sysconfig::make_devhandle (usb_dev_handle *udh) +fusb_sysconfig::make_devhandle (usb_dev_handle *udh, libusb_context *ctx) { return new fusb_devhandle_linux (udh); } diff --git a/usrp/host/lib/fusb_sysconfig_ra_wb.cc b/usrp/host/lib/fusb_sysconfig_ra_wb.cc index 9da831fd5..c527e3099 100644 --- a/usrp/host/lib/fusb_sysconfig_ra_wb.cc +++ b/usrp/host/lib/fusb_sysconfig_ra_wb.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003,2006 Free Software Foundation, Inc. + * Copyright 2003,2006,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -31,7 +31,7 @@ static const int MAX_BLOCK_SIZE = 64 * 1024; static const int FUSB_BUFFER_SIZE = 256 * (1L << 10); // 256 kB fusb_devhandle * -fusb_sysconfig::make_devhandle (usb_dev_handle *udh) +fusb_sysconfig::make_devhandle (usb_dev_handle *udh, libusb_context *ctx) { return new fusb_devhandle_ra_wb (udh); } diff --git a/usrp/host/lib/fusb_sysconfig_win32.cc b/usrp/host/lib/fusb_sysconfig_win32.cc index 16eaaa645..fb4be8829 100644 --- a/usrp/host/lib/fusb_sysconfig_win32.cc +++ b/usrp/host/lib/fusb_sysconfig_win32.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003,2005 Free Software Foundation, Inc. + * Copyright 2003,2005,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -27,7 +27,7 @@ static const int MAX_BLOCK_SIZE = 64 * 1024; // Windows kernel hard limit static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB fusb_devhandle * -fusb_sysconfig::make_devhandle (usb_dev_handle *udh) +fusb_sysconfig::make_devhandle (usb_dev_handle *udh, libusb_context *ctx) { return new fusb_devhandle_win32 (udh); } diff --git a/usrp/host/lib/usrp_basic.h.in b/usrp/host/lib/usrp_basic.h.in new file mode 100644 index 000000000..3faa5304f --- /dev/null +++ b/usrp/host/lib/usrp_basic.h.in @@ -0,0 +1,960 @@ +class fusb_devhandle; +class fusb_ephandle; + +enum txrx_t { + C_RX = 0, + C_TX = 1 +}; + +/* + * ---------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------- + */ + + +/*! + * \brief abstract base class for usrp operations + * \ingroup usrp + */ +class usrp_basic : boost::noncopyable +{ +protected: + void shutdown_daughterboards(); + +protected: + libusb_device_handle *d_udh; + struct libusb_context *d_ctx; + int d_usb_data_rate; // bytes/sec + int d_bytes_per_poll; // how often to poll for overruns + bool d_verbose; + long d_fpga_master_clock_freq; + + static const int MAX_REGS = 128; + unsigned int d_fpga_shadows[MAX_REGS]; + + int d_dbid[2]; // daughterboard ID's (side A, side B) + + /*! + * Shared pointers to subclasses of db_base. + * + * The outer vector is of length 2 (0 = side A, 1 = side B). The + * inner vectors are of length 1, 2 or 3 depending on the number of + * subdevices implemented by the daugherboard. At this time, only + * the Basic Rx and LF Rx implement more than 1 subdevice. + */ + std::vector< std::vector<db_base_sptr> > d_db; + + //! One time call, made only only from usrp_standard_*::make after shared_ptr is created. + void init_db(usrp_basic_sptr u); + + + usrp_basic (int which_board, + libusb_device_handle *open_interface (libusb_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 (); + + + /*! + * Return a vector of vectors that contain shared pointers + * to the daughterboard instance(s) associated with the specified side. + * + * It is an error to use the returned objects after the usrp_basic + * object has been destroyed. + */ + std::vector<std::vector<db_base_sptr> > db() const { return d_db; } + + /*! + * Return a vector of size >= 1 that contains shared pointers + * to the daughterboard instance(s) associated with the specified side. + * + * \param which_side [0,1] which daughterboard + * + * It is an error to use the returned objects after the usrp_basic + * object has been destroyed. + */ + std::vector<db_base_sptr> db(int which_side); + + /*! + * \brief is the subdev_spec valid? + */ + bool is_valid(const usrp_subdev_spec &ss); + + /*! + * \brief given a subdev_spec, return the corresponding daughterboard object. + * \throws std::invalid_ argument if ss is invalid. + * + * \param ss specifies the side and subdevice + */ + db_base_sptr selected_subdev(const usrp_subdev_spec &ss); + + /*! + * \brief return frequency of master oscillator on USRP + */ + long fpga_master_clock_freq () const { return d_fpga_master_clock_freq; } + + /*! + * Tell API that the master oscillator on the USRP is operating at a non-standard + * fixed frequency. This is only needed for custom USRP hardware modified to + * operate at a different frequency from the default factory configuration. This + * function must be called prior to any other API function. + * \param master_clock USRP2 FPGA master clock frequency in Hz (10..64 MHz) + */ + void set_fpga_master_clock_freq (long master_clock) { d_fpga_master_clock_freq = master_clock; } + + /*! + * \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_adc 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_adc, int offset); + + /*! + * \brief Set DAC offset correction + * \param which_dac 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_dac, int offset, int offset_pin); + + /*! + * \brief Control ADC input buffer + * \param which_adc 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_adc, bool bypass); + + /*! + * \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); + + /*! + * \brief return the usrp's serial number. + * + * \returns non-zero length string iff successful. + */ + std::string serial_number(); + + /*! + * \brief Return daughterboard ID for given side [0,1]. + * + * \param which_side [0,1] which daughterboard + * + * \return daughterboard id >= 0 if successful + * \return -1 if no daugherboard + * \return -2 if invalid EEPROM on daughterboard + */ + virtual int daughterboard_id (int which_side) const = 0; + + /*! + * \brief Clock ticks to delay rising of T/R signal + * \sa write_atr_mask, write_atr_txval, write_atr_rxval + */ + bool write_atr_tx_delay(int value); + + /*! + * \brief Clock ticks to delay falling edge of T/R signal + * \sa write_atr_mask, write_atr_txval, write_atr_rxval + */ + bool write_atr_rx_delay(int value); + + + // ================================================================ + // Routines to access and control daughterboard specific i/o + // + // Those with a common_ prefix access either the Tx or Rx side depending + // on the txrx parameter. Those without the common_ prefix are virtual + // and are overriden in usrp_basic_rx and usrp_basic_tx to access the + // the Rx or Tx sides automatically. We provide the common_ versions + // for those daughterboards such as the WBX and XCVR2450 that share + // h/w resources (such as the LO) between the Tx and Rx sides. + + // ---------------------------------------------------------------- + // BEGIN common_ daughterboard control functions + + /*! + * \brief Set Programmable Gain Amplifier(PGA) + * + * \param txrx Tx or Rx? + * \param which_amp which amp [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 common_set_pga(txrx_t txrx, int which_amp, double gain_in_db); + + /*! + * \brief Return programmable gain amplifier gain setting in dB. + * + * \param txrx Tx or Rx? + * \param which_amp which amp [0,3] + */ + double common_pga(txrx_t txrx, int which_amp) const; + + /*! + * \brief Return minimum legal PGA gain in dB. + * \param txrx Tx or Rx? + */ + double common_pga_min(txrx_t txrx) const; + + /*! + * \brief Return maximum legal PGA gain in dB. + * \param txrx Tx or Rx? + */ + double common_pga_max(txrx_t txrx) const; + + /*! + * \brief Return hardware step size of PGA(linear in dB). + * \param txrx Tx or Rx? + */ + double common_pga_db_per_step(txrx_t txrx) const; + + /*! + * \brief Write direction register(output enables) for pins that go to daughterboard. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which size + * \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 txrx, int which_side, int value, int mask); + + /*! + * \brief Write daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [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 txrx, int which_side, int value, int mask); + + /*! + * \brief Read daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value output + */ + bool common_read_io(txrx_t txrx, int which_side, int *value); + + /*! + * \brief Read daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \returns register value if successful, else READ_FAILED + */ + int common_read_io(txrx_t txrx, int which_side); + + /*! + * \brief Write daughterboard refclk config register + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value value to write into register, see below + * + * <pre> + * Control whether a reference clock is sent to the daughterboards, + * and what frequency. The refclk is sent on d'board i/o pin 0. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------------------------------+-+------------+ + * | Reserved (Must be zero) |E| DIVISOR | + * +-----------------------------------------------+-+------------+ + * + * Bit 7 -- 1 turns on refclk, 0 allows IO use + * Bits 6:0 Divider value + * </pre> + */ + bool common_write_refclk(txrx_t txrx, int which_side, int value); + + /*! + * \brief Automatic Transmit/Receive switching + * <pre> + * + * If automatic transmit/receive (ATR) switching is enabled in the + * FR_ATR_CTL register, the presence or absence of data in the FPGA + * transmit fifo selects between two sets of values for each of the 4 + * banks of daughterboard i/o pins. + * + * Each daughterboard slot has 3 16-bit registers associated with it: + * FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_* + * + * FR_ATR_MASK_{0,1,2,3}: + * + * These registers determine which of the daugherboard i/o pins are + * affected by ATR switching. If a bit in the mask is set, the + * corresponding i/o bit is controlled by ATR, else it's output + * value comes from the normal i/o pin output register: + * FR_IO_{0,1,2,3}. + * + * FR_ATR_TXVAL_{0,1,2,3}: + * FR_ATR_RXVAL_{0,1,2,3}: + * + * If the Tx fifo contains data, then the bits from TXVAL that are + * selected by MASK are output. Otherwise, the bits from RXVAL that + * are selected by MASK are output. + * </pre> + */ + bool common_write_atr_mask(txrx_t txrx, int which_side, int value); + bool common_write_atr_txval(txrx_t txrx, int which_side, int value); + bool common_write_atr_rxval(txrx_t txrx, int which_side, int value); + + /*! + * \brief Write auxiliary digital to analog converter. + * + * \param txrx Tx or Rx? + * \param which_side [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 common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value); + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \param value return 12-bit value [0,4095] + * \returns true iff successful + */ + bool common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value); + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \returns value in the range [0,4095] if successful, else READ_FAILED. + */ + int common_read_aux_adc(txrx_t txrx, int which_side, int which_adc); + + // END common_ daughterboard control functions + // ---------------------------------------------------------------- + // BEGIN virtual daughterboard control functions + + /*! + * \brief Set Programmable Gain Amplifier (PGA) + * + * \param which_amp which amp [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() + */ + virtual bool set_pga (int which_amp, double gain_in_db) = 0; + + /*! + * \brief Return programmable gain amplifier gain setting in dB. + * + * \param which_amp which amp [0,3] + */ + virtual double pga (int which_amp) const = 0; + + /*! + * \brief Return minimum legal PGA gain in dB. + */ + virtual double pga_min () const = 0; + + /*! + * \brief Return maximum legal PGA gain in dB. + */ + virtual double pga_max () const = 0; + + /*! + * \brief Return hardware step size of PGA (linear in dB). + */ + virtual double pga_db_per_step () const = 0; + + /*! + * \brief Write direction register (output enables) for pins that go to daughterboard. + * + * \param which_side [0,1] which size + * \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. + */ + virtual bool _write_oe (int which_side, int value, int mask) = 0; + + /*! + * \brief Write daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \param value value to write into register + * \param mask which bits of value to write into reg + */ + virtual bool write_io (int which_side, int value, int mask) = 0; + + /*! + * \brief Read daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \param value output + */ + virtual bool read_io (int which_side, int *value) = 0; + + /*! + * \brief Read daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \returns register value if successful, else READ_FAILED + */ + virtual int read_io (int which_side) = 0; + + /*! + * \brief Write daughterboard refclk config register + * + * \param which_side [0,1] which d'board + * \param value value to write into register, see below + * + * <pre> + * Control whether a reference clock is sent to the daughterboards, + * and what frequency. The refclk is sent on d'board i/o pin 0. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------------------------------+-+------------+ + * | Reserved (Must be zero) |E| DIVISOR | + * +-----------------------------------------------+-+------------+ + * + * Bit 7 -- 1 turns on refclk, 0 allows IO use + * Bits 6:0 Divider value + * </pre> + */ + virtual bool write_refclk(int which_side, int value) = 0; + + virtual bool write_atr_mask(int which_side, int value) = 0; + virtual bool write_atr_txval(int which_side, int value) = 0; + virtual bool write_atr_rxval(int which_side, int value) = 0; + + /*! + * \brief Write auxiliary digital to analog converter. + * + * \param which_side [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 + */ + virtual bool write_aux_dac (int which_side, int which_dac, int value) = 0; + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \param value return 12-bit value [0,4095] + * \returns true iff successful + */ + virtual bool read_aux_adc (int which_side, int which_adc, int *value) = 0; + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \returns value in the range [0,4095] if successful, else READ_FAILED. + */ + virtual int read_aux_adc (int which_side, int which_adc) = 0; + + /*! + * \brief returns current fusb block size + */ + virtual int block_size() const = 0; + + /*! + * \brief returns A/D or D/A converter rate in Hz + */ + virtual long converter_rate() const = 0; + + // END virtual daughterboard control functions + + // ---------------------------------------------------------------- + // Low level implementation routines. + // You probably shouldn't be using these... + // + + bool _set_led (int which_led, 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 + * \ingroup 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. + * \param fpga_filename name of the rbf file to load + * \param firmware_filename name of ihx file to load + */ + 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 (); + + /*! + * \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. + * \param fpga_filename name of file that contains image to load into FPGA + * \param firmware_filename name of file that contains image to load into FX2 + */ + 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 = "" + ); + + /*! + * \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); + + + //! sampling rate of A/D converter + virtual long converter_rate() const { return fpga_master_clock_freq(); } // 64M + long adc_rate() const { return converter_rate(); } + int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; } + + bool set_pga (int which_amp, double gain_in_db); + double pga (int which_amp) const; + double pga_min () const; + double pga_max () const; + double pga_db_per_step () const; + + bool _write_oe (int which_side, int value, int mask); + bool write_io (int which_side, int value, int mask); + bool read_io (int which_side, int *value); + int read_io (int which_side); + bool write_refclk(int which_side, int value); + bool write_atr_mask(int which_side, int value); + bool write_atr_txval(int which_side, int value); + bool write_atr_rxval(int which_side, int value); + + bool write_aux_dac (int which_side, int which_dac, int value); + bool read_aux_adc (int which_side, int which_adc, int *value); + int read_aux_adc (int which_side, int which_adc); + + int block_size() const; + + // called in base class to derived class order + bool start (); + bool stop (); +}; + +/*! + * \brief class for accessing the transmit side of the USRP + * \ingroup 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. + * \param fpga_filename name of file that contains image to load into FPGA + * \param firmware_filename name of file that contains image to load into FX2 + */ + 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 (); + + /*! + * \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. + * \param fpga_filename name of file that contains image to load into FPGA + * \param firmware_filename name of file that contains image to load into FX2 + */ + 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 = "" + ); + + /*! + * \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 (); + + //! 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(); } + int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; } + + bool set_pga (int which_amp, double gain_in_db); + double pga (int which_amp) const; + double pga_min () const; + double pga_max () const; + double pga_db_per_step () const; + + bool _write_oe (int which_side, int value, int mask); + bool write_io (int which_side, int value, int mask); + bool read_io (int which_side, int *value); + int read_io (int which_side); + bool write_refclk(int which_side, int value); + bool write_atr_mask(int which_side, int value); + bool write_atr_txval(int which_side, int value); + bool write_atr_rxval(int which_side, int value); + + bool write_aux_dac (int which_side, int which_dac, int value); + bool read_aux_adc (int which_side, int which_adc, int *value); + int read_aux_adc (int which_side, int which_adc); + + int block_size() const; + + // called in base class to derived class order + bool start (); + bool stop (); +}; + +#endif diff --git a/usrp/host/lib/usrp_basic.cc b/usrp/host/lib/usrp_basic_common.cc index 4f3df5212..721301dec 100644 --- a/usrp/host/lib/usrp_basic.cc +++ b/usrp/host/lib/usrp_basic_common.cc @@ -1,19 +1,19 @@ /* -*- 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, @@ -24,14 +24,13 @@ #include "config.h" #endif -#include <usrp/usrp_basic.h> +#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 <usb.h> #include <stdexcept> #include <assert.h> #include <math.h> @@ -55,24 +54,22 @@ static const double POLLING_INTERVAL = 0.1; // seconds //////////////////////////////////////////////////////////////// -static struct usb_dev_handle * -open_rx_interface (struct usb_device *dev) +static libusb_device_handle * +open_rx_interface (libusb_device *dev) { - struct usb_dev_handle *udh = usrp_open_rx_interface (dev); + libusb_device_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) +static libusb_device_handle * +open_tx_interface (libusb_device *dev) { - struct usb_dev_handle *udh = usrp_open_tx_interface (dev); + libusb_device_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; } @@ -87,7 +84,7 @@ open_tx_interface (struct usb_device *dev) // Given: // CLKIN = 64 MHz -// CLKSEL pin = high +// CLKSEL pin = high // // These settings give us: // CLKOUT1 = CLKIN = 64 MHz @@ -104,80 +101,17 @@ static unsigned char common_regs[] = { 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 -} - 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++) + 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(); } -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); -} - void usrp_basic::init_db(usrp_basic_sptr u) { @@ -188,7 +122,7 @@ usrp_basic::init_db(usrp_basic_sptr u) d_db[1] = instantiate_dbs(d_dbid[1], u, 1); } -std::vector<db_base_sptr> +std::vector<db_base_sptr> usrp_basic::db(int which_side) { which_side &= 0x1; // clamp it to avoid any reporting any errors @@ -373,7 +307,7 @@ usrp_basic::set_adc_buffer_bypass (int which_adc, bool bypass) bool usrp_basic::set_dc_offset_cl_enable(int bits, int mask) { - return _write_fpga_reg(FR_DC_OFFSET_CL_EN, + return _write_fpga_reg(FR_DC_OFFSET_CL_EN, (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & mask)); } @@ -465,7 +399,7 @@ 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)) @@ -807,14 +741,14 @@ usrp_basic_rx::usrp_basic_rx (int which_board, int fusb_block_size, int fusb_nbl 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_devhandle = fusb_sysconfig::make_devhandle (d_udh, d_ctx); d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true, fusb_block_size, fusb_nblocks); @@ -834,7 +768,6 @@ 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 (); @@ -859,16 +792,14 @@ usrp_basic_rx::start () 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; } @@ -879,13 +810,11 @@ usrp_basic_rx::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; } @@ -898,7 +827,7 @@ usrp_basic_rx::make (int which_board, int fusb_block_size, int fusb_nblocks, 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); @@ -931,10 +860,10 @@ 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; @@ -959,10 +888,9 @@ usrp_basic_rx::read (void *buf, int len, bool *overrun) 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; } @@ -1012,21 +940,21 @@ usrp_basic_rx::probe_rx_slots (bool verbose) _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); @@ -1216,14 +1144,14 @@ usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int fusb_nbl 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_devhandle = fusb_sysconfig::make_devhandle (d_udh, d_ctx); d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false, fusb_block_size, fusb_nblocks); @@ -1264,13 +1192,11 @@ usrp_basic_tx::start () 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; } @@ -1284,13 +1210,11 @@ usrp_basic_tx::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; } @@ -1303,7 +1227,7 @@ usrp_basic_tx::make (int which_board, int fusb_block_size, int fusb_nblocks, 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); @@ -1336,10 +1260,10 @@ 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; @@ -1348,7 +1272,7 @@ usrp_basic_tx::write (const void *buf, int len, bool *underrun) 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 @@ -1364,7 +1288,6 @@ usrp_basic_tx::write (const void *buf, int len, bool *underrun) 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 (); } } @@ -1424,21 +1347,21 @@ usrp_basic_tx::probe_tx_slots (bool verbose) _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); diff --git a/usrp/host/lib/usrp_basic_libusb0.cc b/usrp/host/lib/usrp_basic_libusb0.cc new file mode 100644 index 000000000..217480580 --- /dev/null +++ b/usrp/host/lib/usrp_basic_libusb0.cc @@ -0,0 +1,137 @@ +/* -*- 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 <usb.h> +#include <stdexcept> +#include <assert.h> +#include <math.h> +#include <ad9862.h> +#include <string.h> +#include <cstdio> + +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 new file mode 100644 index 000000000..35009dc66 --- /dev/null +++ b/usrp/host/lib/usrp_basic_libusb1.cc @@ -0,0 +1,145 @@ +/* -*- 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 <libusb-1.0/libusb.h> +#include <stdexcept> +#include <assert.h> +#include <math.h> +#include <ad9862.h> +#include <string.h> +#include <cstdio> + + +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.cc b/usrp/host/lib/usrp_prims_common.cc index 3d87d2459..70e90d7fe 100644 --- a/usrp/host/lib/usrp_prims.cc +++ b/usrp/host/lib/usrp_prims_common.cc @@ -1,19 +1,19 @@ /* -*- c++ -*- */ /* * Copyright 2003,2004,2006,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, @@ -24,13 +24,12 @@ #include "config.h" #endif -#include "usrp/usrp_prims.h" +#include "usrp_primsi.h" #include "usrp_commands.h" #include "usrp_ids.h" #include "usrp_i2c_addr.h" #include "fpga_regs_common.h" #include "fpga_regs_standard.h" -#include <usb.h> #include <errno.h> #include <stdio.h> #include <unistd.h> @@ -41,6 +40,7 @@ #include <algorithm> #include <ad9862.h> #include <assert.h> +#include "std_paths.h" extern "C" { #include "md5.h" @@ -61,9 +61,6 @@ static const int hash_slot_addr[2] = { static const char *default_firmware_filename = "std.ihx"; static const char *default_fpga_filename = "std_2rxhb_2tx.rbf"; -#include "std_paths.h" -#include <stdio.h> - static char * find_file (const char *filename, int hw_rev) { @@ -101,218 +98,108 @@ get_proto_filename(const std::string user_filename, const char *env_var, const c } -static void power_down_9862s (struct usb_dev_handle *udh); - -void -usrp_one_time_init () -{ - static bool first = true; - - if (first){ - first = false; - usb_init (); // usb library init - usb_find_busses (); - usb_find_devices (); - } -} - -void -usrp_rescan () -{ - usb_find_busses (); - usb_find_devices (); -} +static void power_down_9862s (libusb_device_handle *udh); // ---------------------------------------------------------------- -// Danger, big, fragile KLUDGE. The problem is that we want to be -// able to get from a usb_dev_handle back to a usb_device, and the -// right way to do this is buried in a non-installed include file. - -static struct usb_device * -dev_handle_to_dev (usb_dev_handle *udh) -{ - struct usb_dev_handle_kludge { - int fd; - struct usb_bus *bus; - struct usb_device *device; - }; - - return ((struct usb_dev_handle_kludge *) udh)->device; -} - -// ---------------------------------------------------------------- /* * q must be a real USRP, not an FX2. Return its hardware rev number. */ + int -usrp_hw_rev (struct usb_device *q) +usrp_hw_rev (libusb_device *q) { - return q->descriptor.bcdDevice & 0x00FF; + libusb_device_descriptor desc = _get_usb_device_descriptor(q); + return desc.bcdDevice & 0x00FF; } /* * q must be a real USRP, not an FX2. Return true if it's configured. */ static bool -_usrp_configured_p (struct usb_device *q) +_usrp_configured_p (libusb_device *q) { - return (q->descriptor.bcdDevice & 0xFF00) != 0; + libusb_device_descriptor desc = _get_usb_device_descriptor(q); + return (desc.bcdDevice & 0xFF00) != 0; } bool -usrp_usrp_p (struct usb_device *q) +usrp_usrp_p (libusb_device *q) { - return (q->descriptor.idVendor == USB_VID_FSF - && q->descriptor.idProduct == USB_PID_FSF_USRP); + libusb_device_descriptor desc = _get_usb_device_descriptor(q); + return (desc.idVendor == USB_VID_FSF + && desc.idProduct == USB_PID_FSF_USRP); } bool -usrp_fx2_p (struct usb_device *q) +usrp_fx2_p (libusb_device *q) { - return (q->descriptor.idVendor == USB_VID_CYPRESS - && q->descriptor.idProduct == USB_PID_CYPRESS_FX2); + libusb_device_descriptor desc = _get_usb_device_descriptor(q); + return (desc.idVendor == USB_VID_CYPRESS + && desc.idProduct == USB_PID_CYPRESS_FX2); } bool -usrp_usrp0_p (struct usb_device *q) +usrp_usrp0_p (libusb_device *q) { return usrp_usrp_p (q) && usrp_hw_rev (q) == 0; } bool -usrp_usrp1_p (struct usb_device *q) +usrp_usrp1_p (libusb_device *q) { return usrp_usrp_p (q) && usrp_hw_rev (q) == 1; } bool -usrp_usrp2_p (struct usb_device *q) +usrp_usrp2_p (libusb_device *q) { return usrp_usrp_p (q) && usrp_hw_rev (q) == 2; } bool -usrp_unconfigured_usrp_p (struct usb_device *q) +usrp_unconfigured_usrp_p (libusb_device *q) { return usrp_usrp_p (q) && !_usrp_configured_p (q); } bool -usrp_configured_usrp_p (struct usb_device *q) +usrp_configured_usrp_p (libusb_device *q) { return usrp_usrp_p (q) && _usrp_configured_p (q); } -// ---------------------------------------------------------------- - -struct usb_device * -usrp_find_device (int nth, bool fx2_ok_p) -{ - struct usb_bus *p; - struct usb_device *q; - int n_found = 0; - - usrp_one_time_init (); - - p = usb_get_busses(); - while (p != NULL){ - q = p->devices; - while (q != NULL){ - if (usrp_usrp_p (q) || (fx2_ok_p && usrp_fx2_p (q))){ - if (n_found == nth) // return this one - return q; - n_found++; // keep looking - } - q = q->next; - } - p = p->next; - } - return 0; // not found -} - -static struct usb_dev_handle * -usrp_open_interface (struct usb_device *dev, int interface, int altinterface) -{ - struct usb_dev_handle *udh = usb_open (dev); - if (udh == 0) - return 0; - - if (dev != dev_handle_to_dev (udh)){ - fprintf (stderr, "%s:%d: internal error!\n", __FILE__, __LINE__); - abort (); - } - -#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) - // There's no get get_configuration function, and with some of the newer kernels - // setting the configuration, even if to the same value, hoses any other processes - // that have it open. Hence we opt to not set it at all (We've only - // got a single configuration anyway). This may hose the win32 stuff... - - // Appears to be required for libusb-win32 and Cygwin -- dew 09/20/06 - if (usb_set_configuration (udh, 1) < 0){ - /* - * Ignore this error. - * - * Seems that something changed in drivers/usb/core/devio.c:proc_setconfig such that - * it returns -EBUSY if _any_ of the interfaces of a device are open. - * We've only got a single configuration, so setting it doesn't even seem - * like it should be required. - */ - } -#endif - if (usb_claim_interface (udh, interface) < 0){ - fprintf (stderr, "%s:usb_claim_interface: failed interface %d\n", __FUNCTION__,interface); - fprintf (stderr, "%s\n", usb_strerror()); - usb_close (udh); - return 0; - } +// ---------------------------------------------------------------- - if (usb_set_altinterface (udh, altinterface) < 0){ - fprintf (stderr, "%s:usb_set_alt_interface: failed\n", __FUNCTION__); - fprintf (stderr, "%s\n", usb_strerror()); - usb_release_interface (udh, interface); - usb_close (udh); - return 0; - } - return udh; -} - -struct usb_dev_handle * -usrp_open_cmd_interface (struct usb_device *dev) +libusb_device_handle * +usrp_open_cmd_interface (libusb_device *dev) { return usrp_open_interface (dev, USRP_CMD_INTERFACE, USRP_CMD_ALTINTERFACE); } -struct usb_dev_handle * -usrp_open_rx_interface (struct usb_device *dev) +libusb_device_handle * +usrp_open_rx_interface (libusb_device *dev) { return usrp_open_interface (dev, USRP_RX_INTERFACE, USRP_RX_ALTINTERFACE); } -struct usb_dev_handle * -usrp_open_tx_interface (struct usb_device *dev) +libusb_device_handle * +usrp_open_tx_interface (libusb_device *dev) { return usrp_open_interface (dev, USRP_TX_INTERFACE, USRP_TX_ALTINTERFACE); } -bool -usrp_close_interface (struct usb_dev_handle *udh) -{ - // we're assuming that closing an interface automatically releases it. - return usb_close (udh) == 0; -} // ---------------------------------------------------------------- // write internal ram using Cypress vendor extension static bool -write_internal_ram (struct usb_dev_handle *udh, unsigned char *buf, - int start_addr, size_t len) +write_internal_ram (libusb_device_handle *udh, unsigned char *buf, + int start_addr, size_t len) { int addr; int n; @@ -324,22 +211,23 @@ write_internal_ram (struct usb_dev_handle *udh, unsigned char *buf, if (n > quanta) n = quanta; - a = usb_control_msg (udh, 0x40, 0xA0, - addr, 0, (char *)(buf + (addr - start_addr)), n, 1000); + a = _usb_control_transfer (udh, 0x40, 0xA0, addr, 0, + (unsigned char*)(buf + (addr - start_addr)), n, 1000); if (a < 0){ - fprintf(stderr,"write_internal_ram failed: %s\n", usb_strerror()); + fprintf(stderr,"write_internal_ram failed: %i\n", a); return false; } } return true; } + // ---------------------------------------------------------------- // whack the CPUCS register using the upload RAM vendor extension static bool -reset_cpu (struct usb_dev_handle *udh, bool reset_p) +reset_cpu (libusb_device_handle *udh, bool reset_p) { unsigned char v; @@ -355,7 +243,7 @@ reset_cpu (struct usb_dev_handle *udh, bool reset_p) // Load intel format file into cypress FX2 (8051) static bool -_usrp_load_firmware (struct usb_dev_handle *udh, const char *filename, +_usrp_load_firmware (libusb_device_handle *udh, const char *filename, unsigned char hash[USRP_HASH_SIZE]) { FILE *f = fopen (filename, "ra"); @@ -367,7 +255,7 @@ _usrp_load_firmware (struct usb_dev_handle *udh, const char *filename, if (!reset_cpu (udh, true)) // hold CPU in reset while loading firmware goto fail; - + char s[1024]; int length; int addr; @@ -434,31 +322,10 @@ _usrp_load_firmware (struct usb_dev_handle *udh, const char *filename, } // ---------------------------------------------------------------- -// write vendor extension command to USRP - -static int -write_cmd (struct usb_dev_handle *udh, - int request, int value, int index, - unsigned char *bytes, int len) -{ - int requesttype = (request & 0x80) ? VRT_VENDOR_IN : VRT_VENDOR_OUT; - - int r = usb_control_msg (udh, requesttype, request, value, index, - (char *) bytes, len, 1000); - if (r < 0){ - // we get EPIPE if the firmware stalls the endpoint. - if (errno != EPIPE) - fprintf (stderr, "usb_control_msg failed: %s\n", usb_strerror ()); - } - - return r; -} - -// ---------------------------------------------------------------- // load fpga static bool -_usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, +_usrp_load_fpga (libusb_device_handle *udh, const char *filename, unsigned char hash[USRP_HASH_SIZE]) { bool ok = true; @@ -480,7 +347,7 @@ _usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, if (write_cmd (udh, VRQ_FPGA_LOAD, 0, FL_BEGIN, 0, 0) != 0) goto fail; - + while ((n = fread (buf, 1, sizeof (buf), fp)) > 0){ if (write_cmd (udh, VRQ_FPGA_LOAD, 0, FL_XFER, buf, n) != n) goto fail; @@ -488,7 +355,7 @@ _usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, if (write_cmd (udh, VRQ_FPGA_LOAD, 0, FL_END, 0, 0) != 0) goto fail; - + fclose (fp); if (!usrp_set_hash (udh, FPGA_HASH_SLOT, hash)) @@ -501,7 +368,7 @@ _usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, usrp_set_fpga_reset (udh, 0); // fpga out of master reset // now these commands will work - + ok &= usrp_set_fpga_tx_enable (udh, 0); ok &= usrp_set_fpga_rx_enable (udh, 0); @@ -535,8 +402,8 @@ _usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, // ---------------------------------------------------------------- -bool -usrp_set_led (struct usb_dev_handle *udh, int which, bool on) +bool +usrp_set_led (libusb_device_handle *udh, int which, bool on) { int r = write_cmd (udh, VRQ_SET_LED, on, which, 0, 0); @@ -544,38 +411,39 @@ usrp_set_led (struct usb_dev_handle *udh, int which, bool on) } bool -usrp_set_hash (struct usb_dev_handle *udh, int which, - const unsigned char hash[USRP_HASH_SIZE]) +usrp_set_hash (libusb_device_handle *udh, int which, + const unsigned char hash[USRP_HASH_SIZE]) { which &= 1; - + // we use the Cypress firmware down load command to jam it in. - int r = usb_control_msg (udh, 0x40, 0xa0, hash_slot_addr[which], 0, - (char *) hash, USRP_HASH_SIZE, 1000); + int r = _usb_control_transfer (udh, 0x40, 0xa0, hash_slot_addr[which], 0, + (unsigned char *) hash, USRP_HASH_SIZE, 1000); return r == USRP_HASH_SIZE; } bool -usrp_get_hash (struct usb_dev_handle *udh, int which, - unsigned char hash[USRP_HASH_SIZE]) +usrp_get_hash (libusb_device_handle *udh, int which, + unsigned char hash[USRP_HASH_SIZE]) { which &= 1; - + // we use the Cypress firmware upload command to fetch it. - int r = usb_control_msg (udh, 0xc0, 0xa0, hash_slot_addr[which], 0, - (char *) hash, USRP_HASH_SIZE, 1000); + int r = _usb_control_transfer (udh, 0xc0, 0xa0, hash_slot_addr[which], 0, + (unsigned char *) hash, USRP_HASH_SIZE, 1000); return r == USRP_HASH_SIZE; } + + static bool -usrp_set_switch (struct usb_dev_handle *udh, int cmd_byte, bool on) +usrp_set_switch (libusb_device_handle *udh, int cmd_byte, bool on) { return write_cmd (udh, cmd_byte, on, 0, 0, 0) == 0; } - static bool -usrp1_fpga_write (struct usb_dev_handle *udh, +usrp1_fpga_write (libusb_device_handle *udh, int regno, int value) { // on the rev1 usrp, we use the generic spi_write interface @@ -586,7 +454,7 @@ usrp1_fpga_write (struct usb_dev_handle *udh, buf[1] = (value >> 16) & 0xff; buf[2] = (value >> 8) & 0xff; buf[3] = (value >> 0) & 0xff; - + return usrp_spi_write (udh, 0x00 | (regno & 0x7f), SPI_ENABLE_FPGA, SPI_FMT_MSB | SPI_FMT_HDR_1, @@ -594,7 +462,7 @@ usrp1_fpga_write (struct usb_dev_handle *udh, } static bool -usrp1_fpga_read (struct usb_dev_handle *udh, +usrp1_fpga_read (libusb_device_handle *udh, int regno, int *value) { *value = 0; @@ -611,13 +479,12 @@ usrp1_fpga_read (struct usb_dev_handle *udh, return ok; } - bool -usrp_write_fpga_reg (struct usb_dev_handle *udh, int reg, int value) +usrp_write_fpga_reg (libusb_device_handle *udh, int reg, int value) { - switch (usrp_hw_rev (dev_handle_to_dev (udh))){ - case 0: // not supported ;) - abort(); + switch (usrp_hw_rev (_get_usb_device (udh))){ + case 0: // not supported ;) + abort(); default: return usrp1_fpga_write (udh, reg, value); @@ -625,43 +492,43 @@ usrp_write_fpga_reg (struct usb_dev_handle *udh, int reg, int value) } bool -usrp_read_fpga_reg (struct usb_dev_handle *udh, int reg, int *value) +usrp_read_fpga_reg (libusb_device_handle *udh, int reg, int *value) { - switch (usrp_hw_rev (dev_handle_to_dev (udh))){ - case 0: // not supported ;) + switch (usrp_hw_rev (_get_usb_device (udh))){ + case 0: // not supported ;) abort(); - + default: return usrp1_fpga_read (udh, reg, value); } } -bool -usrp_set_fpga_reset (struct usb_dev_handle *udh, bool on) +bool +usrp_set_fpga_reset (libusb_device_handle *udh, bool on) { return usrp_set_switch (udh, VRQ_FPGA_SET_RESET, on); } -bool -usrp_set_fpga_tx_enable (struct usb_dev_handle *udh, bool on) +bool +usrp_set_fpga_tx_enable (libusb_device_handle *udh, bool on) { return usrp_set_switch (udh, VRQ_FPGA_SET_TX_ENABLE, on); } -bool -usrp_set_fpga_rx_enable (struct usb_dev_handle *udh, bool on) +bool +usrp_set_fpga_rx_enable (libusb_device_handle *udh, bool on) { return usrp_set_switch (udh, VRQ_FPGA_SET_RX_ENABLE, on); } -bool -usrp_set_fpga_tx_reset (struct usb_dev_handle *udh, bool on) +bool +usrp_set_fpga_tx_reset (libusb_device_handle *udh, bool on) { return usrp_set_switch (udh, VRQ_FPGA_SET_TX_RESET, on); } -bool -usrp_set_fpga_rx_reset (struct usb_dev_handle *udh, bool on) +bool +usrp_set_fpga_rx_reset (libusb_device_handle *udh, bool on) { return usrp_set_switch (udh, VRQ_FPGA_SET_RX_RESET, on); } @@ -683,22 +550,22 @@ compute_hash (const char *filename, unsigned char hash[USRP_HASH_SIZE]) } int r = md5_stream (fp, hash); fclose (fp); - + return r == 0; } static usrp_load_status_t -usrp_conditionally_load_something (struct usb_dev_handle *udh, +usrp_conditionally_load_something (libusb_device_handle *udh, const char *filename, bool force, int slot, - bool loader (struct usb_dev_handle *, + bool loader (libusb_device_handle *, const char *, unsigned char [USRP_HASH_SIZE])) { unsigned char file_hash[USRP_HASH_SIZE]; unsigned char usrp_hash[USRP_HASH_SIZE]; - + if (access (filename, R_OK) != 0){ perror (filename); return ULS_ERROR; @@ -721,7 +588,7 @@ usrp_conditionally_load_something (struct usb_dev_handle *udh, } usrp_load_status_t -usrp_load_firmware (struct usb_dev_handle *udh, +usrp_load_firmware (libusb_device_handle *udh, const char *filename, bool force) { @@ -731,7 +598,7 @@ usrp_load_firmware (struct usb_dev_handle *udh, } usrp_load_status_t -usrp_load_fpga (struct usb_dev_handle *udh, +usrp_load_fpga (libusb_device_handle *udh, const char *filename, bool force) { @@ -740,28 +607,28 @@ usrp_load_fpga (struct usb_dev_handle *udh, _usrp_load_fpga); } -static usb_dev_handle * -open_nth_cmd_interface (int nth) +static libusb_device_handle * +open_nth_cmd_interface (int nth, libusb_context *ctx) { - struct usb_device *udev = usrp_find_device (nth); + + libusb_device *udev = usrp_find_device (nth, false, ctx); if (udev == 0){ fprintf (stderr, "usrp: failed to find usrp[%d]\n", nth); return 0; } - struct usb_dev_handle *udh; + libusb_device_handle *udh; udh = usrp_open_cmd_interface (udev); if (udh == 0){ // FIXME this could be because somebody else has it open. // We should delay and retry... fprintf (stderr, "open_nth_cmd_interface: open_cmd_interface failed\n"); - usb_strerror (); return 0; } return udh; - } +} static bool our_nanosleep (const struct timespec *delay) @@ -791,9 +658,11 @@ mdelay (int millisecs) return our_nanosleep (&ts); } + usrp_load_status_t -usrp_load_firmware_nth (int nth, const char *filename, bool force){ - struct usb_dev_handle *udh = open_nth_cmd_interface (nth); +usrp_load_firmware_nth (int nth, const char *filename, bool force, libusb_context *ctx) +{ + libusb_device_handle *udh = open_nth_cmd_interface (nth, ctx); if (udh == 0) return ULS_ERROR; @@ -802,7 +671,7 @@ usrp_load_firmware_nth (int nth, const char *filename, bool force){ switch (s){ - case ULS_ALREADY_LOADED: // nothing changed... + case ULS_ALREADY_LOADED: // nothing changed... return ULS_ALREADY_LOADED; break; @@ -814,19 +683,16 @@ usrp_load_firmware_nth (int nth, const char *filename, bool force){ // handle. // FIXME. Turn this into a loop that rescans until we refind ourselves - - struct timespec t; // delay for 1 second + + struct timespec t; // delay for 1 second t.tv_sec = 2; t.tv_nsec = 0; our_nanosleep (&t); - usb_find_busses (); // rescan busses and devices - usb_find_devices (); - return ULS_OK; default: - case ULS_ERROR: // some kind of problem + case ULS_ERROR: // some kind of problem return ULS_ERROR; } } @@ -836,12 +702,12 @@ load_status_msg (usrp_load_status_t s, const char *type, const char *filename) { char *e = getenv("USRP_VERBOSE"); bool verbose = e != 0; - + switch (s){ case ULS_ERROR: fprintf (stderr, "usrp: failed to load %s %s.\n", type, filename); break; - + case ULS_ALREADY_LOADED: if (verbose) fprintf (stderr, "usrp: %s %s already loaded.\n", type, filename); @@ -857,7 +723,8 @@ load_status_msg (usrp_load_status_t s, const char *type, const char *filename) bool usrp_load_standard_bits (int nth, bool force, const std::string fpga_filename, - const std::string firmware_filename) + const std::string firmware_filename, + libusb_context *ctx) { usrp_load_status_t s; const char *filename; @@ -866,7 +733,7 @@ usrp_load_standard_bits (int nth, bool force, // first, figure out what hardware rev we're dealing with { - struct usb_device *udev = usrp_find_device (nth); + libusb_device *udev = usrp_find_device (nth, false, ctx); if (udev == 0){ fprintf (stderr, "usrp: failed to find usrp[%d]\n", nth); return false; @@ -883,8 +750,7 @@ usrp_load_standard_bits (int nth, bool force, fprintf (stderr, "Can't find firmware: %s\n", proto_filename); return false; } - - s = usrp_load_firmware_nth (nth, filename, force); + s = usrp_load_firmware_nth (nth, filename, force, ctx); load_status_msg (s, "firmware", filename); if (s == ULS_ERROR) @@ -903,11 +769,10 @@ usrp_load_standard_bits (int nth, bool force, fprintf (stderr, "Can't find fpga bitstream: %s\n", proto_filename); return false; } - - struct usb_dev_handle *udh = open_nth_cmd_interface (nth); + libusb_device_handle *udh = open_nth_cmd_interface (nth, ctx); if (udh == 0) return false; - + s = usrp_load_fpga (udh, filename, force); usrp_close_interface (udh); load_status_msg (s, "fpga bitstream", filename); @@ -918,12 +783,13 @@ usrp_load_standard_bits (int nth, bool force, return true; } + bool -_usrp_get_status (struct usb_dev_handle *udh, int which, bool *trouble) +_usrp_get_status (libusb_device_handle *udh, int which, bool *trouble) { unsigned char status; *trouble = true; - + if (write_cmd (udh, VRQ_GET_STATUS, 0, which, &status, sizeof (status)) != sizeof (status)) return false; @@ -933,20 +799,20 @@ _usrp_get_status (struct usb_dev_handle *udh, int which, bool *trouble) } bool -usrp_check_rx_overrun (struct usb_dev_handle *udh, bool *overrun_p) +usrp_check_rx_overrun (libusb_device_handle *udh, bool *overrun_p) { return _usrp_get_status (udh, GS_RX_OVERRUN, overrun_p); } bool -usrp_check_tx_underrun (struct usb_dev_handle *udh, bool *underrun_p) +usrp_check_tx_underrun (libusb_device_handle *udh, bool *underrun_p) { return _usrp_get_status (udh, GS_TX_UNDERRUN, underrun_p); } bool -usrp_i2c_write (struct usb_dev_handle *udh, int i2c_addr, +usrp_i2c_write (libusb_device_handle *udh, int i2c_addr, const void *buf, int len) { if (len < 1 || len > MAX_EP0_PKTSIZE) @@ -958,7 +824,7 @@ usrp_i2c_write (struct usb_dev_handle *udh, int i2c_addr, bool -usrp_i2c_read (struct usb_dev_handle *udh, int i2c_addr, +usrp_i2c_read (libusb_device_handle *udh, int i2c_addr, void *buf, int len) { if (len < 1 || len > MAX_EP0_PKTSIZE) @@ -969,7 +835,7 @@ usrp_i2c_read (struct usb_dev_handle *udh, int i2c_addr, } bool -usrp_spi_write (struct usb_dev_handle *udh, +usrp_spi_write (libusb_device_handle *udh, int optional_header, int enables, int format, const void *buf, int len) { @@ -984,7 +850,7 @@ usrp_spi_write (struct usb_dev_handle *udh, bool -usrp_spi_read (struct usb_dev_handle *udh, +usrp_spi_read (libusb_device_handle *udh, int optional_header, int enables, int format, void *buf, int len) { @@ -998,7 +864,7 @@ usrp_spi_read (struct usb_dev_handle *udh, } bool -usrp_9862_write (struct usb_dev_handle *udh, int which_codec, +usrp_9862_write (libusb_device_handle *udh, int which_codec, int regno, int value) { if (0) @@ -1008,7 +874,7 @@ usrp_9862_write (struct usb_dev_handle *udh, int which_codec, unsigned char buf[1]; buf[0] = value; - + return usrp_spi_write (udh, 0x00 | (regno & 0x3f), which_codec == 0 ? SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B, SPI_FMT_MSB | SPI_FMT_HDR_1, @@ -1016,7 +882,7 @@ usrp_9862_write (struct usb_dev_handle *udh, int which_codec, } bool -usrp_9862_read (struct usb_dev_handle *udh, int which_codec, +usrp_9862_read (libusb_device_handle *udh, int which_codec, int regno, unsigned char *value) { return usrp_spi_read (udh, 0x80 | (regno & 0x3f), @@ -1026,7 +892,7 @@ usrp_9862_read (struct usb_dev_handle *udh, int which_codec, } bool -usrp_9862_write_many (struct usb_dev_handle *udh, +usrp_9862_write_many (libusb_device_handle *udh, int which_codec, const unsigned char *buf, int len) @@ -1047,7 +913,7 @@ usrp_9862_write_many (struct usb_dev_handle *udh, bool -usrp_9862_write_many_all (struct usb_dev_handle *udh, +usrp_9862_write_many_all (libusb_device_handle *udh, const unsigned char *buf, int len) { // FIXME handle 2/2 and 4/4 versions @@ -1059,15 +925,15 @@ usrp_9862_write_many_all (struct usb_dev_handle *udh, } static void -power_down_9862s (struct usb_dev_handle *udh) +power_down_9862s (libusb_device_handle *udh) { static const unsigned char regs[] = { - REG_RX_PWR_DN, 0x01, // everything - REG_TX_PWR_DN, 0x0f, // pwr dn digital and analog_both - REG_TX_MODULATOR, 0x00 // coarse & fine modulators disabled + REG_RX_PWR_DN, 0x01, // everything + REG_TX_PWR_DN, 0x0f, // pwr dn digital and analog_both + REG_TX_MODULATOR, 0x00 // coarse & fine modulators disabled }; - switch (usrp_hw_rev (dev_handle_to_dev (udh))){ + switch (usrp_hw_rev (_get_usb_device (udh))){ case 0: break; @@ -1078,16 +944,15 @@ power_down_9862s (struct usb_dev_handle *udh) } - static const int EEPROM_PAGESIZE = 16; bool -usrp_eeprom_write (struct usb_dev_handle *udh, int i2c_addr, +usrp_eeprom_write (libusb_device_handle *udh, int i2c_addr, int eeprom_offset, const void *buf, int len) { unsigned char cmd[2]; const unsigned char *p = (unsigned char *) buf; - + // The simplest thing that could possibly work: // all writes are single byte writes. // @@ -1102,12 +967,12 @@ usrp_eeprom_write (struct usb_dev_handle *udh, int i2c_addr, if (!r) return false; } - + return true; } bool -usrp_eeprom_read (struct usb_dev_handle *udh, int i2c_addr, +usrp_eeprom_read (libusb_device_handle *udh, int i2c_addr, int eeprom_offset, void *buf, int len) { unsigned char *p = (unsigned char *) buf; @@ -1129,14 +994,14 @@ usrp_eeprom_read (struct usb_dev_handle *udh, int i2c_addr, } return true; } - + // ---------------------------------------------------------------- static bool slot_to_codec (int slot, int *which_codec) { *which_codec = 0; - + switch (slot){ case SLOT_TX_A: case SLOT_RX_A: @@ -1169,11 +1034,11 @@ tx_slot_p (int slot) } bool -usrp_write_aux_dac (struct usb_dev_handle *udh, int slot, +usrp_write_aux_dac (libusb_device_handle *udh, int slot, int which_dac, int value) { int which_codec; - + if (!slot_to_codec (slot, &which_codec)) return false; @@ -1183,7 +1048,7 @@ usrp_write_aux_dac (struct usb_dev_handle *udh, int slot, } value &= 0x0fff; // mask to 12-bits - + if (which_dac == 3){ // dac 3 is really 12-bits. Use value as is. bool r = true; @@ -1192,7 +1057,7 @@ usrp_write_aux_dac (struct usb_dev_handle *udh, int slot, return r; } else { - // dac 0, 1, and 2 are really 8 bits. + // dac 0, 1, and 2 are really 8 bits. value = value >> 4; // shift value appropriately return usrp_9862_write (udh, which_codec, 36 + which_dac, value); } @@ -1200,7 +1065,7 @@ usrp_write_aux_dac (struct usb_dev_handle *udh, int slot, bool -usrp_read_aux_adc (struct usb_dev_handle *udh, int slot, +usrp_read_aux_adc (libusb_device_handle *udh, int slot, int which_adc, int *value) { *value = 0; @@ -1219,7 +1084,7 @@ usrp_read_aux_adc (struct usb_dev_handle *udh, int slot, | AUX_ADC_CTRL_REFSEL_B; // on chip reference int rd_reg = 26; // base address of two regs to read for result - + // program the ADC mux bits if (tx_slot_p (slot)) aux_adc_control |= AUX_ADC_CTRL_SELECT_A2 | AUX_ADC_CTRL_SELECT_B2; @@ -1227,7 +1092,7 @@ usrp_read_aux_adc (struct usb_dev_handle *udh, int slot, rd_reg += 2; aux_adc_control |= AUX_ADC_CTRL_SELECT_A1 | AUX_ADC_CTRL_SELECT_B1; } - + // I'm not sure if we can set the mux and issue a start conversion // in the same cycle, so let's do them one at a time. @@ -1251,7 +1116,7 @@ usrp_read_aux_adc (struct usb_dev_handle *udh, int slot, if (r) *value = ((v_hi << 2) | ((v_lo >> 6) & 0x3)) << 2; // format as 12-bit - + return r; } @@ -1279,7 +1144,7 @@ set_chksum (unsigned char *buf) } static usrp_dbeeprom_status_t -read_dboard_eeprom (struct usb_dev_handle *udh, +read_dboard_eeprom (libusb_device_handle *udh, int slot_id, unsigned char *buf) { int i2c_addr = slot_to_i2c_addr (slot_id); @@ -1303,7 +1168,7 @@ read_dboard_eeprom (struct usb_dev_handle *udh, } usrp_dbeeprom_status_t -usrp_read_dboard_eeprom (struct usb_dev_handle *udh, +usrp_read_dboard_eeprom (libusb_device_handle *udh, int slot_id, usrp_dboard_eeprom *eeprom) { unsigned char buf[DB_EEPROM_CLEN]; @@ -1323,7 +1188,7 @@ usrp_read_dboard_eeprom (struct usb_dev_handle *udh, } bool -usrp_write_dboard_offsets (struct usb_dev_handle *udh, int slot_id, +usrp_write_dboard_offsets (libusb_device_handle *udh, int slot_id, short offset0, short offset1) { unsigned char buf[DB_EEPROM_CLEN]; @@ -1342,16 +1207,25 @@ usrp_write_dboard_offsets (struct usb_dev_handle *udh, int slot_id, 0, buf, sizeof (buf)); } +// ---------------------------------------------------------------- + std::string -usrp_serial_number(struct usb_dev_handle *udh) +usrp_serial_number(libusb_device_handle *udh) { - unsigned char iserial = usb_device(udh)->descriptor.iSerialNumber; + libusb_device_descriptor desc = + _get_usb_device_descriptor (_get_usb_device (udh)); + + unsigned char iserial = desc.iSerialNumber; if (iserial == 0) return ""; - char buf[1024]; - if (usb_get_string_simple(udh, iserial, buf, sizeof(buf)) < 0) + unsigned char buf[1024]; + if (_get_usb_string_descriptor (udh, iserial, buf, sizeof(buf)) < 0) return ""; - return buf; + return (char*) buf; } + + + + diff --git a/usrp/host/lib/usrp_prims_libusb0.cc b/usrp/host/lib/usrp_prims_libusb0.cc new file mode 100644 index 000000000..7a82eabfa --- /dev/null +++ b/usrp/host/lib/usrp_prims_libusb0.cc @@ -0,0 +1,207 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2004,2006,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_primsi.h" +#include "usrp_commands.h" +#include <usb.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <ad9862.h> +#include <assert.h> + +extern "C" { +#include "md5.h" +}; + +using namespace ad9862; + +/* + * libusb 0.12 / 1.0 compatibility + */ + +struct usb_device * +_get_usb_device (struct usb_dev_handle *udh) +{ + return usb_device (udh); +} + +struct usb_device_descriptor +_get_usb_device_descriptor (struct usb_device *q) +{ + return q->descriptor; +} +int +_get_usb_string_descriptor (struct usb_dev_handle *udh, int index, + unsigned char* data, int length) +{ + return usb_get_string_simple (udh, index, (char*) data, length); +} + +int +_usb_control_transfer (struct usb_dev_handle *udh, int request_type, + int request, int value, int index, + unsigned char *data, int length, unsigned int timeout) +{ + return usb_control_msg (udh, request_type,request, value, index, + (char*) data, length, (int) timeout); +} + + +// ---------------------------------------------------------------- + + +void +usrp_one_time_init (libusb_context **ctx) +{ + static bool first = true; + + if (first) { + first = false; + usb_init (); // usb library init + usb_find_busses (); + usb_find_devices (); + } +} + +void +usrp_rescan () +{ + usb_find_busses (); + usb_find_devices (); +} + + +// ---------------------------------------------------------------- + + +struct usb_device * +usrp_find_device (int nth, bool fx2_ok_p, libusb_context *ctx) +{ + struct usb_bus *p; + struct usb_device *q; + int n_found = 0; + + usrp_one_time_init (); + + p = usb_get_busses(); + while (p != NULL){ + q = p->devices; + while (q != NULL){ + if (usrp_usrp_p (q) || (fx2_ok_p && usrp_fx2_p (q))){ + if (n_found == nth) // return this one + return q; + n_found++; // keep looking + } + q = q->next; + } + p = p->next; + } + return 0; // not found +} + +struct usb_dev_handle * +usrp_open_interface (struct usb_device *dev, int interface, int altinterface) +{ + struct usb_dev_handle *udh = usb_open (dev); + if (udh == 0) + return 0; + + if (dev != usb_device (udh)){ + fprintf (stderr, "%s:%d: internal error!\n", __FILE__, __LINE__); + abort (); + } + +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + // There's no get get_configuration function, and with some of the newer kernels + // setting the configuration, even if to the same value, hoses any other processes + // that have it open. Hence we opt to not set it at all (We've only + // got a single configuration anyway). This may hose the win32 stuff... + + // Appears to be required for libusb-win32 and Cygwin -- dew 09/20/06 + if (usb_set_configuration (udh, 1) < 0){ + /* + * Ignore this error. + * + * Seems that something changed in drivers/usb/core/devio.c:proc_setconfig such that + * it returns -EBUSY if _any_ of the interfaces of a device are open. + * We've only got a single configuration, so setting it doesn't even seem + * like it should be required. + */ + } +#endif + + if (usb_claim_interface (udh, interface) < 0){ + fprintf (stderr, "%s:usb_claim_interface: failed interface %d\n", __FUNCTION__,interface); + fprintf (stderr, "%s\n", usb_strerror()); + usb_close (udh); + return 0; + } + + if (usb_set_altinterface (udh, altinterface) < 0){ + fprintf (stderr, "%s:usb_set_alt_interface: failed\n", __FUNCTION__); + fprintf (stderr, "%s\n", usb_strerror()); + usb_release_interface (udh, interface); + usb_close (udh); + return 0; + } + + return udh; +} + +bool +usrp_close_interface (struct usb_dev_handle *udh) +{ + // we're assuming that closing an interface automatically releases it. + return usb_close (udh) == 0; +} + + +// ---------------------------------------------------------------- +// write vendor extension command to USRP + + +int +write_cmd (struct usb_dev_handle *udh, + int request, int value, int index, + unsigned char *bytes, int len) +{ + int requesttype = (request & 0x80) ? VRT_VENDOR_IN : VRT_VENDOR_OUT; + + int r = usb_control_msg (udh, requesttype, request, value, index, + (char *) bytes, len, 1000); + if (r < 0){ + // we get EPIPE if the firmware stalls the endpoint. + if (errno != EPIPE) + fprintf (stderr, "usb_control_msg failed: %s\n", usb_strerror ()); + } + + return r; +} + diff --git a/usrp/host/lib/usrp_prims_libusb1.cc b/usrp/host/lib/usrp_prims_libusb1.cc new file mode 100644 index 000000000..cf1f8fe07 --- /dev/null +++ b/usrp/host/lib/usrp_prims_libusb1.cc @@ -0,0 +1,202 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2004,2006,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_primsi.h" +#include "usrp_commands.h" +#include <libusb-1.0/libusb.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <ad9862.h> +#include <assert.h> + +extern "C" { +#include "md5.h" +}; + +using namespace ad9862; + +/* + * libusb 0.12 / 1.0 compatibility + */ + +struct libusb_device * +_get_usb_device (struct libusb_device_handle *udh) +{ + return libusb_get_device (udh); +} + +struct libusb_device_descriptor +_get_usb_device_descriptor(struct libusb_device *q) +{ + int ret; + struct libusb_device_descriptor desc; + + if ((ret = libusb_get_device_descriptor(q, &desc)) < 0) + fprintf (stderr, "usrp: libusb_get_device_descriptor failed %d\n", ret); + + return desc; +} + +int +_get_usb_string_descriptor (struct libusb_device_handle *udh, int index, + unsigned char* data, int length) +{ + return libusb_get_string_descriptor_ascii (udh, (uint8_t) index, data, length); +} + +int +_usb_control_transfer (struct libusb_device_handle *udh, int request_type, + int request, int value, int index, + unsigned char *data, int length, unsigned int timeout) +{ + return libusb_control_transfer (udh, request_type, request, value, index, + data, length, timeout); +} + + +// ---------------------------------------------------------------- + + +void +usrp_one_time_init (libusb_context **ctx) +{ + int ret; + + if ((ret = libusb_init (ctx)) < 0) + fprintf (stderr, "usrp: libusb_init failed %i\n", ret); +} + +void +usrp_rescan () +{ + // nop +} + + +struct libusb_device * +usrp_find_device (int nth, bool fx2_ok_p, libusb_context *ctx) +{ + libusb_device **list; + + struct libusb_device *q; + int n_found = 0; + + // Make sure not operating on default context. There are cases where operating + // with a single global (NULL) context may be preferable, so this check can be + // skipped if you know what you're doing. + assert (ctx != NULL); + + size_t cnt = libusb_get_device_list(ctx, &list); + size_t i = 0; + + if (cnt < 0) + fprintf(stderr, "usrp: libusb_get_device_list failed %d\n", cnt); + + for (i = 0; i < cnt; i++) { + q = list[i]; + if (usrp_usrp_p (q) || (fx2_ok_p && usrp_fx2_p (q))) { + if (n_found == nth) // return this one + return q; + n_found++; // keep looking + } + } + + // The list needs to be freed. Right now just release it if nothing is found. + libusb_free_device_list(list, 1); + + return 0; // not found +} + +struct libusb_device_handle * +usrp_open_interface (libusb_device *dev, int interface, int altinterface) +{ + libusb_device_handle *udh; + int ret; + + if (libusb_open (dev, &udh) < 0) + return 0; + + if (dev != libusb_get_device (udh)){ + fprintf (stderr, "%s:%d: internal error!\n", __FILE__, __LINE__); + abort (); + } + + if ((ret = libusb_claim_interface (udh, interface)) < 0) { + fprintf (stderr, "%s:usb_claim_interface: failed interface %d\n", __FUNCTION__,interface); + fprintf (stderr, "%d\n", ret); + libusb_close (udh); + return 0; + } + + if ((ret = libusb_set_interface_alt_setting (udh, interface, + altinterface)) < 0) { + fprintf (stderr, "%s:usb_set_alt_interface: failed\n", __FUNCTION__); + fprintf (stderr, "%d\n", ret); + libusb_release_interface (udh, interface); + libusb_close (udh); + return 0; + } + + return udh; +} + +bool +usrp_close_interface (libusb_device_handle *udh) +{ + // returns void + libusb_close(udh); + return 0; +} + + +// ---------------------------------------------------------------- +// write vendor extension command to USRP + + +int +write_cmd (struct libusb_device_handle *udh, + int request, int value, int index, + unsigned char *bytes, int len) +{ + int requesttype = (request & 0x80) ? VRT_VENDOR_IN : VRT_VENDOR_OUT; + + int r = libusb_control_transfer(udh, requesttype, request, value, index, + (unsigned char *) bytes, len, 1000); + + if (r < 0){ + // we get EPIPE if the firmware stalls the endpoint. + if (r != LIBUSB_ERROR_PIPE) { + fprintf (stderr, "libusb_control_transfer failed: %i\n", r); + } + } + + return r; +} + diff --git a/usrp/host/lib/usrp_primsi.h b/usrp/host/lib/usrp_primsi.h new file mode 100644 index 000000000..b1cf7263a --- /dev/null +++ b/usrp/host/lib/usrp_primsi.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,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. + */ + +/* + * Internal usrp_prims header file + */ + +#ifndef _USRP_PRIMSI_H_ +#define _USRP_PRIMSI_H_ + +#include "usrp/usrp_prims.h" + +/* + * Internal functions + */ + +libusb_device_handle * +usrp_open_interface(libusb_device *dev, int interface, int altinterface); + +int write_cmd (libusb_device_handle *udh, int request, int value, int index, + unsigned char *bytes, int len); + +/* + * Compatibility functions + */ + +libusb_device *_get_usb_device (libusb_device_handle *udh); + +libusb_device_descriptor _get_usb_device_descriptor (libusb_device *q); + +int _get_usb_string_descriptor (libusb_device_handle *udh, int index, + unsigned char* data, int length); + +int _usb_control_transfer (libusb_device_handle *udh, int request_type, + int request, int value, int index, + unsigned char *data, int length, + unsigned int timeout); + +#endif /* _USRP_PRIMSI_H_ */ + diff --git a/usrp/host/lib/usrp_standard.cc b/usrp/host/lib/usrp_standard.cc index b112dbe0c..541dd3f57 100644 --- a/usrp/host/lib/usrp_standard.cc +++ b/usrp/host/lib/usrp_standard.cc @@ -20,6 +20,10 @@ * Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <usrp/usrp_standard.h> #include "usrp/usrp_prims.h" |