diff options
author | Thomas Tsou <ttsou@vt.edu> | 2010-08-26 12:33:06 -0700 |
---|---|---|
committer | Thomas Tsou <ttsou@vt.edu> | 2010-08-26 12:33:06 -0700 |
commit | 4434e8233fadc4eec81d345a6c4e63922d8c01ab (patch) | |
tree | 392a85fc9f11f230eeb0cc8d0a17fdaa819b74bd | |
parent | 2f3269f359043290fcaa7659e90292919306a8bc (diff) | |
parent | fe7df530e69834e974108d2c3e682f38b8a75524 (diff) | |
download | uhd-4434e8233fadc4eec81d345a6c4e63922d8c01ab.tar.gz uhd-4434e8233fadc4eec81d345a6c4e63922d8c01ab.tar.bz2 uhd-4434e8233fadc4eec81d345a6c4e63922d8c01ab.zip |
Merge branch 'usrp1_next' into usrp1
21 files changed, 741 insertions, 635 deletions
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index dd1a20eed..0f1cbf2a2 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -27,6 +27,7 @@ INSTALL(FILES udp_zero_copy.hpp usb_control.hpp usb_zero_copy.hpp + usb_device_handle.hpp vrt_if_packet.hpp zero_copy.hpp DESTINATION ${INCLUDE_DIR}/uhd/transport diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index 6b5591a21..6137ecf84 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -18,11 +18,7 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP #define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP -#include <uhd/config.hpp> -#include <uhd/types/usb_descriptor.hpp> -#include <boost/utility.hpp> -#include <boost/shared_ptr.hpp> -#include <vector> +#include "usb_device_handle.hpp" namespace uhd { namespace transport { @@ -35,9 +31,9 @@ public: * This transport is for sending and receiving control information from * the host to device using the Default Control Pipe. * - * \param descriptor a descriptor that identifies a USB device + * \param handle a device handle that uniquely identifies a USB device */ - static sptr make(usb_descriptor_t descriptor); + static sptr make(usb_device_handle::sptr handle); /*! * Submit a USB device request: @@ -62,13 +58,6 @@ public: boost::uint16_t index, unsigned char *buff, boost::uint16_t length) = 0; - - /*! - * Get a vector of USB device descriptors - * - * \return a vector of usb_descriptors - */ - static usb_descriptors_t get_device_list(); }; }} //namespace diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp new file mode 100644 index 000000000..78c78f6b5 --- /dev/null +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -0,0 +1,79 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP +#define INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP + +#include <uhd/config.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/cstdint.hpp> +#include <vector> + +namespace uhd { namespace transport { + +/*! + * Device handle class that represents a USB device + * Used for identifying devices on the USB bus and selecting which device is + * used when creating a USB transport. A minimal subset of USB descriptor + * fields are used. Fields can be found in the USB 2.0 specification Table + * 9-8 (Standard Device Descriptor). In addition to fields of the device + * descriptor, the interface returns the device's USB device address. + * + * Note: The USB 2.0 Standard Device Descriptor contains an index rather then + * a true descriptor serial number string. This interface returns the + * actual string descriptor. + */ +class UHD_API usb_device_handle : boost::noncopyable { +public: + typedef boost::shared_ptr<usb_device_handle> sptr; + + /*! + * Return the device's serial number + * \return a string describing the device's serial number + */ + virtual UHD_API std::string get_serial() const = 0; + + /*! + * Return the device's Vendor ID (usually assigned by the USB-IF) + * \return a Vendor ID + */ + virtual UHD_API boost::uint16_t get_vendor_id() const = 0; + + /*! + * Return the device's Product ID (usually assigned by manufacturer) + * \return a Product ID + */ + virtual UHD_API boost::uint16_t get_product_id() const = 0; + + /*! + * Return the device's USB address + * \return a Product ID + */ + virtual UHD_API boost::uint16_t get_device_addr() const = 0; + + /*! + * Return a vector of USB devices on this host + * \return a vector of USB device handles + */ + static UHD_API std::vector<usb_device_handle::sptr> get_device_list(); + +}; //namespace usb + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP */ diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 7b9692fa5..2edd6d91d 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -18,10 +18,8 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP #define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP -#include <uhd/config.hpp> -#include <uhd/types/usb_descriptor.hpp> +#include "usb_device_handle.hpp" #include <uhd/transport/zero_copy.hpp> -#include <boost/shared_ptr.hpp> namespace uhd { namespace transport { @@ -46,13 +44,13 @@ public: * The primary usage for this transport is data transactions. * The underlying implementation may be platform specific. * - * \param descriptor a USB descriptor identifying the device + * \param handle a device handle that uniquely identifying the device * \param rx_endpoint an integer specifiying an IN endpoint number * \param tx_endpoint an integer specifiying an OUT endpoint number * \param buff_size total number of bytes of buffer space to allocate * \param block_size number of bytes allocated for each I/O transaction */ - static sptr make(usb_descriptor_t descriptor, + static sptr make(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t buff_size = 0, diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 8e302eed2..dbce21c98 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -29,6 +29,5 @@ INSTALL(FILES stream_cmd.hpp time_spec.hpp tune_result.hpp - usb_descriptor.hpp DESTINATION ${INCLUDE_DIR}/uhd/types ) diff --git a/host/include/uhd/types/usb_descriptor.hpp b/host/include/uhd/types/usb_descriptor.hpp deleted file mode 100644 index 0e4c8c369..000000000 --- a/host/include/uhd/types/usb_descriptor.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program 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 of the License, or -// (at your option) any later version. -// -// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP -#define INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP - -#include <uhd/config.hpp> -#include <boost/cstdint.hpp> -#include <vector> -#include <string> - -namespace uhd{ - - /*! - * The USB descriptor struct holds identity information for a USB device - */ - struct UHD_API usb_descriptor_t{ - std::string serial; - boost::uint16_t vendor_id; - boost::uint16_t product_id; - boost::uint16_t device_addr; - - /*! - * Create a pretty print string for this USB descriptor struct. - * \return the printable string - */ - std::string to_pp_string(void) const; - }; - - //handy typde for a vector of usb descriptors - typedef std::vector<usb_descriptor_t> usb_descriptors_t; - -} //namespace uhd - -#endif /* INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP */ diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 627d2d806..753fd5e85 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -29,6 +29,8 @@ IF(LIBUSB_FOUND) LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_base.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_device_handle.cpp ) SET(HAVE_USB_SUPPORT TRUE) ENDIF(LIBUSB_FOUND) diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp new file mode 100644 index 000000000..6965de214 --- /dev/null +++ b/host/lib/transport/libusb1_base.cpp @@ -0,0 +1,118 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "libusb1_base.hpp" +#include <iostream> + +using namespace uhd::transport; + +void libusb::init(libusb_context **ctx, int debug_level) +{ + if (libusb_init(ctx) < 0) + std::cerr << "error: libusb_init" << std::endl; + + libusb_set_debug(*ctx, debug_level); +} + + +libusb_device_handle *libusb::open_device(libusb_context *ctx, + usb_device_handle::sptr handle) +{ + libusb_device **dev_list; + libusb_device_handle *dev_handle; + + ssize_t dev_cnt = libusb_get_device_list(ctx, &dev_list); + + //find and open the receive device + for (ssize_t i = 0; i < dev_cnt; i++) { + libusb_device *dev = dev_list[i]; + + if (compare_device(dev, handle)) { + libusb_open(dev, &dev_handle); + break; + } + } + + libusb_free_device_list(dev_list, 0); + + return dev_handle; +} + + +bool libusb::compare_device(libusb_device *dev, + usb_device_handle::sptr handle) +{ + std::string serial = handle->get_serial(); + boost::uint16_t vendor_id = handle->get_vendor_id(); + boost::uint16_t product_id = handle->get_product_id(); + boost::uint8_t device_addr = handle->get_device_addr(); + + libusb_device_descriptor libusb_desc; + if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) + return false; + if (serial != get_serial(dev)) + return false; + if (vendor_id != libusb_desc.idVendor) + return false; + if (product_id != libusb_desc.idProduct) + return false; + if (device_addr != libusb_get_device_address(dev)) + return false; + + return true; +} + + +bool libusb::open_interface(libusb_device_handle *dev_handle, + int interface) +{ + int ret = libusb_claim_interface(dev_handle, interface); + if (ret < 0) { + std::cerr << "error: libusb_claim_interface() " << ret << std::endl; + return false; + } + else { + return true; + } +} + + +std::string libusb::get_serial(libusb_device *dev) +{ + unsigned char buff[32]; + + libusb_device_descriptor desc; + if (libusb_get_device_descriptor(dev, &desc) < 0) + return ""; + + if (desc.iSerialNumber == 0) + return ""; + + //open the device because we have to + libusb_device_handle *dev_handle; + if (libusb_open(dev, &dev_handle) < 0) + return ""; + + if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, + buff, sizeof(buff)) < 0) { + return ""; + } + + libusb_close(dev_handle); + + return (char*) buff; +} diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp new file mode 100644 index 000000000..ae560cd52 --- /dev/null +++ b/host/lib/transport/libusb1_base.hpp @@ -0,0 +1,42 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_TRANSPORT_LIBUSB_HPP +#define INCLUDED_TRANSPORT_LIBUSB_HPP + +#include <uhd/config.hpp> +#include <uhd/transport/usb_device_handle.hpp> +#include <libusb-1.0/libusb.h> + +namespace uhd { namespace transport { + +namespace libusb { + void init(libusb_context **ctx, int debug_level); + + libusb_device_handle *open_device(libusb_context *ctx, + usb_device_handle::sptr handle); + + bool compare_device(libusb_device *dev, usb_device_handle::sptr handle); + + bool open_interface(libusb_device_handle *dev_handle, int interface); + + std::string get_serial(libusb_device *dev); +} + +}} //namespace + +#endif /* INCLUDED_TRANSPORT_LIBUSB_HPP */ diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index c2f7060e8..8bf271256 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -15,24 +15,20 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/types/usb_descriptor.hpp> +#include "libusb1_base.hpp" #include <uhd/transport/usb_control.hpp> -#include <libusb-1.0/libusb.h> -#include <boost/asio.hpp> -#include <stdexcept> -#include <iostream> using namespace uhd::transport; -static int libusb_debug_level = 0; -static int libusb_timeout = 0; +const int libusb_debug_level = 3; +const int libusb_timeout = 0; /*********************************************************************** * libusb-1.0 implementation of USB control transport **********************************************************************/ class libusb_control_impl : public usb_control { public: - libusb_control_impl(uhd::usb_descriptor_t descriptor); + libusb_control_impl(usb_device_handle::sptr handle); ~libusb_control_impl(); size_t submit(boost::uint8_t request_type, @@ -42,34 +38,19 @@ public: unsigned char *buff, boost::uint16_t length); - static uhd::usb_descriptor_t create_descriptor(libusb_device *dev); - static std::string get_serial(libusb_device *dev); - private: - uhd::usb_descriptor_t _descriptor; - libusb_context *_ctx; libusb_device_handle *_dev_handle; - - bool open_device(); - bool open_interface(); - bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor); }; -libusb_control_impl::libusb_control_impl(uhd::usb_descriptor_t descriptor) - : _descriptor(descriptor), _ctx(NULL), _dev_handle(NULL) +libusb_control_impl::libusb_control_impl(usb_device_handle::sptr handle) { - if (libusb_init(&_ctx) < 0) - throw std::runtime_error("USB: failed to initialize libusb"); + libusb::init(&_ctx, libusb_debug_level); - libusb_set_debug(_ctx, libusb_debug_level); + _dev_handle = libusb::open_device(_ctx, handle); - if (!open_device()) - throw std::runtime_error("USB: failed to open device"); - - if (!open_interface()) - throw std::runtime_error("USB: failed to open device interface"); + libusb::open_interface(_dev_handle, 0); } @@ -80,111 +61,6 @@ libusb_control_impl::~libusb_control_impl() } -uhd::usb_descriptor_t libusb_control_impl::create_descriptor(libusb_device *dev) -{ - libusb_device_descriptor desc; - - if (libusb_get_device_descriptor(dev, &desc) < 0) - throw std::runtime_error("USB: failed to get device descriptor"); - - uhd::usb_descriptor_t descriptor; - - descriptor.serial = get_serial(dev); - descriptor.product_id = desc.idProduct; - descriptor.vendor_id = desc.idVendor; - descriptor.device_addr = libusb_get_device_address(dev); - - return descriptor; -} - - -std::string libusb_control_impl::get_serial(libusb_device *dev) -{ - unsigned char buff[32]; - - libusb_device_descriptor desc; - if (libusb_get_device_descriptor(dev, &desc) < 0) - return ""; - - if (desc.iSerialNumber == 0) - return ""; - - //open the device because we have to - libusb_device_handle *dev_handle; - if (libusb_open(dev, &dev_handle) < 0) - return ""; - - if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, - buff, sizeof(buff)) < 0) { - return ""; - } - - libusb_close(dev_handle); - - return (char*) buff; -} - - -bool libusb_control_impl::open_device() -{ - libusb_device **list; - libusb_device *dev; - - ssize_t cnt = libusb_get_device_list(_ctx, &list); - - if (cnt < 0) - return cnt; - - ssize_t i = 0; - for (i = 0; i < cnt; i++) { - dev = list[i]; - if (compare_device(dev, _descriptor)) - goto found; - } - return false; - -found: - int ret; - if ((ret = libusb_open(dev, &_dev_handle)) < 0) - return false; - else - return true; -} - - -bool libusb_control_impl::compare_device(libusb_device *dev, - uhd::usb_descriptor_t descriptor) -{ - std::string serial = descriptor.serial; - boost::uint16_t vendor_id = descriptor.vendor_id; - boost::uint16_t product_id = descriptor.product_id; - boost::uint8_t device_addr = descriptor.device_addr; - - libusb_device_descriptor libusb_desc; - if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) - return false; - if (serial != get_serial(dev)) - return false; - if (vendor_id != libusb_desc.idVendor) - return false; - if (product_id != libusb_desc.idProduct) - return false; - if (device_addr != libusb_get_device_address(dev)) - return false; - - return true; -} - - -bool libusb_control_impl::open_interface() -{ - if (libusb_claim_interface(_dev_handle, 0) < 0) - return false; - else - return true; -} - - size_t libusb_control_impl::submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, @@ -206,33 +82,7 @@ size_t libusb_control_impl::submit(boost::uint8_t request_type, /*********************************************************************** * USB control public make functions **********************************************************************/ -usb_control::sptr usb_control::make(uhd::usb_descriptor_t descriptor) +usb_control::sptr usb_control::make(usb_device_handle::sptr handle) { - return sptr(new libusb_control_impl(descriptor)); + return sptr(new libusb_control_impl(handle)); } - -uhd::usb_descriptors_t usb_control::get_device_list() -{ - libusb_device **list; - uhd::usb_descriptors_t descriptors; - - if (libusb_init(NULL) < 0) - throw std::runtime_error("USB: failed to initialize libusb"); - - ssize_t cnt = libusb_get_device_list(NULL, &list); - - if (cnt < 0) - throw std::runtime_error("USB: failed to get device list"); - - ssize_t i = 0; - for (i = 0; i < cnt; i++) { - libusb_device *dev = list[i]; - descriptors.push_back(libusb_control_impl::create_descriptor(dev)); - } - - libusb_free_device_list(list, 0); - libusb_exit(NULL); - return descriptors; -} - - diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp new file mode 100644 index 000000000..f80090f15 --- /dev/null +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -0,0 +1,114 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "libusb1_base.hpp" +#include <uhd/utils/assert.hpp> + +using namespace uhd::transport; + +const int libusb_debug_level = 3; + +class libusb1_device_handle_impl : public usb_device_handle { +public: + libusb1_device_handle_impl(std::string serial, + boost::uint32_t product_id, + boost::uint32_t vendor_id, + boost::uint32_t device_addr) + : _serial(serial), _product_id(product_id), + _vendor_id(vendor_id), _device_addr(device_addr) + { + /* NOP */ + } + + ~libusb1_device_handle_impl() + { + /* NOP */ + } + + std::string get_serial() const + { + return _serial; + } + + boost::uint16_t get_vendor_id() const + { + return _vendor_id; + } + + + boost::uint16_t get_product_id() const + { + return _product_id; + } + + boost::uint16_t get_device_addr() const + { + return _device_addr; + } + +private: + std::string _serial; + boost::uint32_t _product_id; + boost::uint32_t _vendor_id; + boost::uint32_t _device_addr; +}; + + +usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + + std::string serial = libusb::get_serial(dev); + boost::uint32_t product_id = desc.idProduct; + boost::uint32_t vendor_id = desc.idVendor; + boost::uint32_t device_addr = libusb_get_device_address(dev); + + return usb_device_handle::sptr(new libusb1_device_handle_impl( + serial, + product_id, + vendor_id, + device_addr)); +} + + +std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list() +{ + libusb_context *ctx = NULL; + libusb_device **list; + std::vector<usb_device_handle::sptr> device_list; + + libusb::init(&ctx, libusb_debug_level); + + ssize_t cnt = libusb_get_device_list(ctx, &list); + + if (cnt < 0) + throw std::runtime_error("USB: enumeration failed"); + + ssize_t i = 0; + for (i = 0; i < cnt; i++) { + libusb_device *dev = list[i]; + device_list.push_back(make_usb_device_handle(dev)); + } + + libusb_free_device_list(list, 0); + libusb_exit(ctx); + return device_list; +} diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 39617e4dd..55aa10cbb 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -15,10 +15,9 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // - +#include "libusb1_base.hpp" #include <uhd/transport/usb_zero_copy.hpp> #include <uhd/utils/assert.hpp> -#include <libusb-1.0/libusb.h> #include <boost/asio.hpp> #include <boost/format.hpp> #include <iostream> @@ -26,7 +25,8 @@ using namespace uhd::transport; -static int libusb_debug_level = 3; +const int libusb_debug_level = 3; +const int libusb_timeout = 0; /*********************************************************************** * Helper functions @@ -347,7 +347,7 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut) std::cerr << "USB: transfer timed out" << std::endl; break; case LIBUSB_TRANSFER_STALL: - std::cerr << "USB: halt condition detected (endpoint stalled)" << std::endl; + std::cerr << "USB: halt condition detected (stalled)" << std::endl; break; case LIBUSB_TRANSFER_ERROR: std::cerr << "USB: transfer failed" << std::endl; @@ -606,26 +606,17 @@ private: libusb_device_handle *_rx_dev_handle; libusb_device_handle *_tx_dev_handle; - int _rx_endpoint; - int _tx_endpoint; - size_t _recv_buff_size; size_t _send_buff_size; size_t _num_frames; - bool open_device(uhd::usb_descriptor_t descriptor); - bool open_interface(libusb_device_handle *dev_handle, int interface); - bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor); - - std::string get_serial(libusb_device *dev); - public: typedef boost::shared_ptr<libusb_zero_copy_impl> sptr; /* * Structors */ - libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, + libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t recv_buff_size, @@ -641,7 +632,7 @@ public: }; -libusb_zero_copy_impl::libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, +libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t buff_size, @@ -650,19 +641,16 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, _recv_buff_size(block_size), _send_buff_size(block_size), _num_frames(buff_size / block_size) { - if (libusb_init(&_rx_ctx) < 0) - std::cerr << "error: libusb_init" << std::endl; + libusb::init(&_rx_ctx, libusb_debug_level); + libusb::init(&_tx_ctx, libusb_debug_level); - if (libusb_init(&_tx_ctx) < 0) - std::cerr << "error: libusb_init" << std::endl; + UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL)); - libusb_set_debug(_rx_ctx, libusb_debug_level); - libusb_set_debug(_tx_ctx, libusb_debug_level); + _rx_dev_handle = libusb::open_device(_rx_ctx, handle); + _tx_dev_handle = libusb::open_device(_tx_ctx, handle); - open_device(descriptor); - - open_interface(_rx_dev_handle, 2); - open_interface(_tx_dev_handle, 1); + libusb::open_interface(_rx_dev_handle, 2); + libusb::open_interface(_tx_dev_handle, 1); _rx_ep = new usb_endpoint(_rx_dev_handle, _rx_ctx, @@ -693,117 +681,6 @@ libusb_zero_copy_impl::~libusb_zero_copy_impl() } -bool libusb_zero_copy_impl::open_device(uhd::usb_descriptor_t descriptor) -{ - libusb_device **rx_list; - libusb_device **tx_list; - - bool rx_found = false; - bool tx_found = false; - - ssize_t rx_cnt = libusb_get_device_list(_rx_ctx, &rx_list); - ssize_t tx_cnt = libusb_get_device_list(_tx_ctx, &tx_list); - - if ((rx_cnt < 0) | (tx_cnt < 0) | (rx_cnt != tx_cnt)) - return false; - - //find and open the receive device - for (ssize_t i = 0; i < rx_cnt; i++) { - libusb_device *dev = rx_list[i]; - - if (compare_device(dev, descriptor)) { - libusb_open(dev, &_rx_dev_handle); - rx_found = true; - break; - } - } - - //find and open the transmit device - for (ssize_t i = 0; i < tx_cnt; i++) { - libusb_device *dev = tx_list[i]; - - if (compare_device(dev, descriptor)) { - libusb_open(dev, &_tx_dev_handle); - tx_found = true; - } - } - - libusb_free_device_list(rx_list, 0); - libusb_free_device_list(tx_list, 0); - - if (tx_found && rx_found) - return true; - else - return false; -} - -bool libusb_zero_copy_impl::compare_device(libusb_device *dev, - uhd::usb_descriptor_t descriptor) -{ - std::string serial = descriptor.serial; - boost::uint16_t vendor_id = descriptor.vendor_id; - boost::uint16_t product_id = descriptor.product_id; - boost::uint8_t device_addr = descriptor.device_addr; - - libusb_device_descriptor desc; - libusb_get_device_descriptor(dev, &desc); - - if (serial.compare(get_serial(dev))) - return false; - if (vendor_id != desc.idVendor) - return false; - if (product_id != desc.idProduct) - return false; - if (device_addr != libusb_get_device_address(dev)) - return false; - - return true; -} - -bool libusb_zero_copy_impl::open_interface(libusb_device_handle *dev_handle, - int interface) -{ - int ret = libusb_claim_interface(dev_handle, interface); - if (ret < 0) { - std::cerr << "error: libusb_claim_interface() " << ret << std::endl; - return false; - } - else { - return true; - } -} - -std::string libusb_zero_copy_impl::get_serial(libusb_device *dev) -{ - unsigned char buff[32]; - - libusb_device_descriptor desc; - if (libusb_get_device_descriptor(dev, &desc) < 0) { - std::cerr << "error: libusb_get_device_descriptor()" << std::endl; - return ""; - } - - if (desc.iSerialNumber == 0) - return ""; - - //open the device because we have to - libusb_device_handle *dev_handle; - if (libusb_open(dev, &dev_handle) < 0) { - return ""; - } - - if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, - buff, sizeof(buff)) < 0) { - std::cerr << "error: libusb_get_string_descriptor_ascii()" << std::endl; - return ""; - } - - libusb_close(dev_handle); - - return (char*) buff; -} - - managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() { libusb_transfer *lut = _rx_ep->get_completed_transfer(); @@ -836,14 +713,14 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() /*********************************************************************** * USB zero_copy make functions **********************************************************************/ -usb_zero_copy::sptr usb_zero_copy::make(uhd::usb_descriptor_t descriptor, +usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t buff_size, size_t block_size) { - return sptr(new libusb_zero_copy_impl(descriptor, + return sptr(new libusb_zero_copy_impl(handle, rx_endpoint, tx_endpoint, buff_size, diff --git a/host/lib/usrp/usrp1/clock_ctrl.cpp b/host/lib/usrp/usrp1/clock_ctrl.cpp index c83ad4c68..54f7b0b98 100644 --- a/host/lib/usrp/usrp1/clock_ctrl.cpp +++ b/host/lib/usrp/usrp1/clock_ctrl.cpp @@ -64,7 +64,7 @@ public: rates.push_back(master_clock_rate / div); return rates; #else - return std::vector<double>(1, 64e6); + return std::vector<double>(1, master_clock_rate); #endif } diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 01617de94..6751b9b7e 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -17,6 +17,7 @@ #include "codec_ctrl.hpp" #include "usrp_commands.h" +#include "clock_ctrl.hpp" #include "ad9862_regs.hpp" #include <uhd/types/dict.hpp> #include <uhd/utils/assert.hpp> @@ -43,7 +44,9 @@ const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1); class usrp1_codec_ctrl_impl : public usrp1_codec_ctrl { public: //structors - usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, int spi_slave); + usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + int spi_slave); ~usrp1_codec_ctrl_impl(void); //aux adc and dac control @@ -51,7 +54,7 @@ public: void write_aux_dac(aux_dac_t which, float volts); //duc control - bool set_duc_freq(double freq); + void set_duc_freq(double freq); //pga gain control void set_tx_pga_gain(float); @@ -61,25 +64,26 @@ public: private: usrp1_iface::sptr _iface; + usrp1_clock_ctrl::sptr _clock_ctrl; int _spi_slave; ad9862_regs_t _ad9862_regs; aux_adc_t _last_aux_adc_a, _last_aux_adc_b; void send_reg(boost::uint8_t addr); void recv_reg(boost::uint8_t addr); - //FIXME: poison - double _tx_freq[4]; - unsigned int compute_freq_control_word_9862 (double master_freq, - double target_freq, - double *actual_freq); + double coarse_tune(double codec_rate, double freq); + double fine_tune(double codec_rate, double freq); }; /*********************************************************************** * Codec Control Structors **********************************************************************/ -usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, int spi_slave) +usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + int spi_slave) { _iface = iface; + _clock_ctrl = clock; _spi_slave = spi_slave; //soft reset @@ -96,15 +100,15 @@ usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, int spi_sl _ad9862_regs.byp_buffer_b = 1; _ad9862_regs.buffer_a_pd = 1; _ad9862_regs.buffer_b_pd = 1; - _ad9862_regs.rx_pga_a = 0;//0x1f; //TODO bring under api control - _ad9862_regs.rx_pga_b = 0;//0x1f; //TODO bring under api control + _ad9862_regs.rx_pga_a = 0; + _ad9862_regs.rx_pga_b = 0; _ad9862_regs.rx_twos_comp = 1; _ad9862_regs.rx_hilbert = ad9862_regs_t::RX_HILBERT_DIS; //setup tx side of codec _ad9862_regs.two_data_paths = ad9862_regs_t::TWO_DATA_PATHS_BOTH; _ad9862_regs.interleaved = ad9862_regs_t::INTERLEAVED_INTERLEAVED; - _ad9862_regs.tx_pga_gain = 199; //TODO bring under api control + _ad9862_regs.tx_pga_gain = 199; _ad9862_regs.tx_hilbert = ad9862_regs_t::TX_HILBERT_DIS; _ad9862_regs.interp = ad9862_regs_t::INTERP_4; _ad9862_regs.tx_twos_comp = 1; @@ -152,8 +156,8 @@ usrp1_codec_ctrl_impl::~usrp1_codec_ctrl_impl(void) **********************************************************************/ void usrp1_codec_ctrl_impl::set_tx_pga_gain(float gain) { - int gain_word = int(63*(gain - tx_pga_gain_range.min)/(tx_pga_gain_range.max - tx_pga_gain_range.min)); - _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, 63); + int gain_word = int(255*(gain - tx_pga_gain_range.min)/(tx_pga_gain_range.max - tx_pga_gain_range.min)); + _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, 255); this->send_reg(16); } @@ -324,118 +328,102 @@ void usrp1_codec_ctrl_impl::recv_reg(boost::uint8_t addr) /*********************************************************************** * DUC tuning **********************************************************************/ -unsigned int usrp1_codec_ctrl_impl::compute_freq_control_word_9862( - double master_freq, double target_freq, double *actual_freq) +double usrp1_codec_ctrl_impl::coarse_tune(double codec_rate, double freq) { - double sign = 1.0; - - if (target_freq < 0) - sign = -1.0; - - int v = (int) rint (fabs (target_freq) / master_freq * pow (2.0, 24.0)); - *actual_freq = v * master_freq / pow (2.0, 24.0) * sign; - - std::cout << boost::format( - "compute_freq_control_word_9862: target = %g actual = %g delta = %g v = %8d\n" - ) % target_freq % *actual_freq % (*actual_freq - target_freq) % v; - - return (unsigned int) v; -} + double coarse_freq; -bool usrp1_codec_ctrl_impl::set_duc_freq(double freq) -{ - int channel = 0; - float dac_rate = 128e6; - - double coarse; - - std::cout << "duc_freq: " << freq << std::endl; - - // First coarse frequency - double coarse_freq_1 = dac_rate / 8; - // Second coarse frequency - double coarse_freq_2 = dac_rate / 4; - // Midpoint of [0 , freq1] range + double coarse_freq_1 = codec_rate / 8; + double coarse_freq_2 = codec_rate / 4; double coarse_limit_1 = coarse_freq_1 / 2; - // Midpoint of [freq1 , freq2] range double coarse_limit_2 = (coarse_freq_1 + coarse_freq_2) / 2; - // Highest meaningful frequency - double high_limit = (double) 44e6 / 128e6 * dac_rate; + double max_freq = coarse_freq_2 + .09375 * codec_rate; - if (freq < -high_limit) { // too low + if (freq < -max_freq) { return false; } - else if (freq < -coarse_limit_2) { // For 64MHz: [-44, -24) + else if (freq < -coarse_limit_2) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_NEG_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_4; - coarse = -coarse_freq_2; + coarse_freq = -coarse_freq_2; } - else if (freq < -coarse_limit_1) { // For 64MHz: [-24, -8) + else if (freq < -coarse_limit_1) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_NEG_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_8; - coarse = -coarse_freq_1; + coarse_freq = -coarse_freq_1; } - else if (freq < coarse_limit_1) { // For 64MHz: [-8, 8) + else if (freq < coarse_limit_1) { _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_BYPASS; - coarse = 0; + coarse_freq = 0; } - else if (freq < coarse_limit_2) { // For 64MHz: [8, 24) + else if (freq < coarse_limit_2) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_POS_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_8; - coarse = coarse_freq_1; + coarse_freq = coarse_freq_1; } - else if (freq <= high_limit) { // For 64MHz: [24, 44] + else if (freq <= max_freq) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_POS_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_4; - coarse = coarse_freq_2; + coarse_freq = coarse_freq_2; } - else { // too high - return false; + else { + return 0; } - - double fine = freq - coarse; - - // Compute fine tuning word... - // This assumes we're running the 4x on-chip interpolator. - // (This is required to use the fine modulator.) - - unsigned int v = compute_freq_control_word_9862 (dac_rate / 4, fine, - &_tx_freq[channel]); - - _tx_freq[channel] += coarse; // adjust actual - - boost::uint8_t high; - boost::uint8_t mid; - boost::uint8_t low; - - high = (v >> 16) & 0xff; - mid = (v >> 8) & 0xff; - low = (v >> 0) & 0xff; - - // write the fine tuning word - _ad9862_regs.ftw_23_16 = high; - _ad9862_regs.ftw_15_8 = mid; - _ad9862_regs.ftw_7_0 = low; - - _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_NCO; - - if (fine < 0) + + return coarse_freq; +} + +double usrp1_codec_ctrl_impl::fine_tune(double codec_rate, double target_freq) +{ + static const double scale_factor = std::pow(2.0, 24); + + boost::uint32_t freq_word = boost::uint32_t( + boost::math::round(abs((target_freq / codec_rate) * scale_factor))); + + double actual_freq = freq_word * codec_rate / scale_factor; + + if (target_freq < 0) { _ad9862_regs.neg_fine_tune = ad9862_regs_t::NEG_FINE_TUNE_NEG_SHIFT; - else + actual_freq = -actual_freq; + } + else { _ad9862_regs.neg_fine_tune = ad9862_regs_t::NEG_FINE_TUNE_POS_SHIFT; - + } + + _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_NCO; + _ad9862_regs.ftw_23_16 = (freq_word >> 16) & 0xff; + _ad9862_regs.ftw_15_8 = (freq_word >> 8) & 0xff; + _ad9862_regs.ftw_7_0 = (freq_word >> 0) & 0xff; + + return actual_freq; +} + +void usrp1_codec_ctrl_impl::set_duc_freq(double freq) +{ + double codec_rate = _clock_ctrl->get_master_clock_freq() * 2; + double coarse_freq = coarse_tune(codec_rate, freq); + double fine_freq = fine_tune(codec_rate / 4, freq - coarse_freq); + + if (codec_debug) { + std::cout << "ad9862 tuning result:" << std::endl; + std::cout << " requested: " << freq << std::endl; + std::cout << " actual: " << coarse_freq + fine_freq << std::endl; + std::cout << " coarse freq: " << coarse_freq << std::endl; + std::cout << " fine freq: " << fine_freq << std::endl; + std::cout << " codec rate: " << codec_rate << std::endl; + } + this->send_reg(20); this->send_reg(21); this->send_reg(22); this->send_reg(23); - - return true; } /*********************************************************************** * Codec Control Make **********************************************************************/ -usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface, int spi_slave) +usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + int spi_slave) { - return sptr(new usrp1_codec_ctrl_impl(iface, spi_slave)); + return sptr(new usrp1_codec_ctrl_impl(iface, clock, spi_slave)); } diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 6440f97d1..259d10ef4 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -19,6 +19,7 @@ #define INCLUDED_USRP1_CODEC_CTRL_HPP #include "usrp1_iface.hpp" +#include "clock_ctrl.hpp" #include <uhd/types/ranges.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> @@ -41,7 +42,9 @@ public: * \param spi_slave which spi device * \return the clock control object */ - static sptr make(usrp1_iface::sptr iface, int spi_slave); + static sptr make(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, int spi_slave + ); //! aux adc identifier constants enum aux_adc_t{ @@ -87,7 +90,8 @@ public: //! Get the RX PGA gain ('A' or 'B') virtual float get_rx_pga_gain(char which) = 0; - virtual bool set_duc_freq(double freq) = 0; + //! Set the TX modulator frequency + virtual void set_duc_freq(double freq) = 0; }; #endif /* INCLUDED_USRP1_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index 0db3cb473..ddd1e811b 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -73,31 +73,13 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) /*********************************************************************** * RX DDC Set **********************************************************************/ -unsigned int compute_freq_word(double master, double target) -{ - static const int NBITS = 14; - int v = (int) rint (target / master * pow(2.0, 32.0)); - - if (0) - v = (v >> (32 - NBITS)) << (32 - NBITS); // keep only top NBITS - - double actual_freq = v * master / pow(2.0, 32.0); - - if (0) std::cerr << boost::format( - "compute_freq_control_word_fpga: target = %g actual = %g delta = %g\n" - ) % target % actual_freq % (actual_freq - target); - - return (unsigned int) v; -} - void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) { switch(key.as<dsp_prop_t>()) { case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as<double>(); - boost::uint32_t hw_freq_word = compute_freq_word( - _clock_ctrl->get_master_clock_freq(), new_freq); - _iface->poke32(FR_RX_FREQ_0, hw_freq_word); + _iface->poke32(FR_RX_FREQ_0, + -dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_master_clock_freq())); _tx_dsp_freq = new_freq; return; } @@ -113,6 +95,8 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) } _rx_dsp_decim = rate; + _rx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() / rate; + _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1); } return; @@ -173,15 +157,15 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) { switch(key.as<dsp_prop_t>()) { + // TODO: Set both codec frequencies until we have duality properties case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as<double>(); _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); + _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); _tx_dsp_freq = new_freq; return; } - //TODO freq prop secondary: DBOARD_SLOT_B codec... - case DSP_PROP_HOST_RATE: { unsigned int rate = _clock_ctrl->get_master_clock_freq() * 2 / val.as<double>(); @@ -193,6 +177,8 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) } _tx_dsp_interp = rate; + _tx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate; + _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1); return; } diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 3f3e74b80..5e206b3d5 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,37 +33,67 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; -/* - * The FX2 firmware bursts data to the FPGA in 512 byte chunks so - * maintain send state to make sure that happens. - */ struct usrp1_send_state { uhd::transport::managed_send_buffer::sptr send_buff; - size_t bytes_used; - size_t bytes_free; + size_t bytes_written; + size_t underrun_poll_samp_count; + + size_t bytes_free() + { + if (send_buff != NULL) + return send_buff->size() - bytes_written; + else + return 0; + } +}; + +struct usrp1_recv_state { + uhd::transport::managed_recv_buffer::sptr recv_buff; + size_t bytes_read; + size_t overrun_poll_samp_count; + + size_t bytes_avail() + { + if (recv_buff != NULL) + return recv_buff->size() - bytes_read; + else + return 0; + } }; /*********************************************************************** * IO Implementation Details **********************************************************************/ struct usrp1_impl::io_impl { - io_impl(zero_copy_if::sptr zc_if); + io_impl(); ~io_impl(void); - bool get_recv_buff(managed_recv_buffer::sptr buff); - - //state management for the vrt packet handler code - vrt_packet_handler::recv_state packet_handler_recv_state; + //state handling for buffer management + usrp1_recv_state recv_state; usrp1_send_state send_state; - zero_copy_if::sptr data_transport; - unsigned int count; + //send transport management + bool get_send_buffer(zero_copy_if::sptr zc_if); + size_t copy_convert_send_samps(const void *buff, size_t num_samps, + size_t sample_offset, const io_type_t io_type, + otw_type_t otw_type); + bool conditional_buff_commit(bool force); + bool check_underrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, bool force); + + //recv transport management + bool get_recv_buffer(zero_copy_if::sptr zc_if); + size_t copy_convert_recv_samps(void *buff, size_t num_samps, + size_t sample_offset, const io_type_t io_type, + otw_type_t otw_type); + bool check_overrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, bool force); }; -usrp1_impl::io_impl::io_impl(zero_copy_if::sptr zc_if) - : packet_handler_recv_state(1), data_transport(zc_if), count(0) +usrp1_impl::io_impl::io_impl() { - /* NOP */ + send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); + recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr(); } usrp1_impl::io_impl::~io_impl(void) @@ -81,12 +111,92 @@ void usrp1_impl::io_init(void) _tx_otw_type.shift = 0; _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); + _io_impl = UHD_PIMPL_MAKE(io_impl, ()); } /*********************************************************************** * Data Send **********************************************************************/ +bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if) +{ + if (send_state.send_buff == NULL) { + + send_state.send_buff = zc_if->get_send_buff(); + if (send_state.send_buff == NULL) + return false; + + send_state.bytes_written = 0; + } + + return true; +} + +size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff, + size_t num_samps, + size_t sample_offset, + const io_type_t io_type, + otw_type_t otw_type) +{ + UHD_ASSERT_THROW(send_state.bytes_free() % otw_type.get_sample_size() == 0); + + size_t samps_free = send_state.bytes_free() / otw_type.get_sample_size(); + size_t copy_samps = std::min(num_samps - sample_offset, samps_free); + + const boost::uint8_t *io_mem = + reinterpret_cast<const boost::uint8_t *>(buff); + + boost::uint8_t *otw_mem = send_state.send_buff->cast<boost::uint8_t *>(); + + convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size, + io_type, + otw_mem + send_state.bytes_written, + otw_type, + copy_samps); + + send_state.bytes_written += copy_samps * otw_type.get_sample_size(); + send_state.underrun_poll_samp_count += copy_samps; + + return copy_samps; +} + +bool usrp1_impl::io_impl::conditional_buff_commit(bool force) +{ + if (send_state.bytes_written % 512) + return false; + + if (force || send_state.bytes_free() == 0) { + send_state.send_buff->commit(send_state.bytes_written); + send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); + return true; + } + + return false; +} + +bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, + bool force) +{ + unsigned char underrun = 0; + + bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval; + + if (force || ready_to_poll) { + int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, + 0, + GS_TX_UNDERRUN, + &underrun, sizeof(char)); + if (ret < 0) + std::cerr << "USRP: underrun check failed" << std::endl; + if (underrun) + std::cerr << "U" << std::endl; + + send_state.underrun_poll_samp_count = 0; + } + + return (bool) underrun; +} + size_t usrp1_impl::send(const std::vector<const void *> &buffs, size_t num_samps, const tx_metadata_t &, @@ -98,54 +208,21 @@ size_t usrp1_impl::send(const std::vector<const void *> &buffs, size_t total_samps_sent = 0; while (total_samps_sent < num_samps) { - - if (_io_impl->send_state.send_buff == NULL) { - _io_impl->send_state.send_buff = _data_transport->get_send_buff(); - if (_io_impl->send_state.send_buff == NULL) { - return 0; - } - _io_impl->send_state.bytes_used = 0; - _io_impl->send_state.bytes_free = _io_impl->send_state.send_buff->size(); - } - - size_t copy_samps = - std::min(num_samps - total_samps_sent, _io_impl->send_state.bytes_free / _tx_otw_type.get_sample_size()); - - const boost::uint8_t *io_mem = - reinterpret_cast<const boost::uint8_t *>(buffs[0]); - - boost::uint8_t *otw_mem = _io_impl->send_state.send_buff->cast<boost::uint8_t *>(); - - // Type conversion and copy - convert_io_type_to_otw_type( - io_mem + total_samps_sent * io_type.size, - io_type, - otw_mem + _io_impl->send_state.bytes_used, - _tx_otw_type, - copy_samps); - - _io_impl->send_state.bytes_used += copy_samps * _tx_otw_type.get_sample_size(); - _io_impl->send_state.bytes_free -= copy_samps * _tx_otw_type.get_sample_size(); - - if (_io_impl->send_state.bytes_free == 0) { - _io_impl->send_state.send_buff->commit(_io_impl->send_state.bytes_used); - _io_impl->send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); - } - - total_samps_sent += copy_samps; - - //check for underruns - if (!(_io_impl->count++ % 1000)) { - unsigned char underrun; - int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS, - 0, - GS_TX_UNDERRUN, - &underrun, sizeof(char)); - if (ret < 0) - std::cerr << "error: underrun check failed" << std::endl; - if (underrun) - std::cerr << "U" << std::endl; - } + if (!_io_impl->get_send_buffer(_data_transport)) + return 0; + + total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0], + num_samps, + total_samps_sent, + io_type, + _tx_otw_type); + if (total_samps_sent == num_samps) + _io_impl->conditional_buff_commit(true); + else + _io_impl->conditional_buff_commit(false); + + _io_impl->check_underrun(_ctrl_transport, + _tx_samps_per_poll_interval, false); } return total_samps_sent; @@ -154,17 +231,70 @@ size_t usrp1_impl::send(const std::vector<const void *> &buffs, /*********************************************************************** * Data Recv **********************************************************************/ -void _recv_helper(vrt_packet_handler::recv_state &state) +bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if) { - size_t num_packet_words32 = - state.managed_buffs[0]->size() / sizeof(boost::uint32_t); + if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail() == 0)) { - const boost::uint32_t *data = - state.managed_buffs[0]->cast<const boost::uint32_t *>(); + recv_state.recv_buff = zc_if->get_recv_buff(); + if (recv_state.recv_buff == NULL) + return false; + + recv_state.bytes_read = 0; + } - state.copy_buffs[0] = reinterpret_cast<const boost::uint8_t *>(data); - size_t num_payload_bytes = num_packet_words32 * sizeof(boost::uint32_t); - state.size_of_copy_buffs = num_payload_bytes; + return true; +} + +size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff, + size_t num_samps, + size_t sample_offset, + const io_type_t io_type, + otw_type_t otw_type) +{ + UHD_ASSERT_THROW(recv_state.bytes_avail() % otw_type.get_sample_size() == 0); + + size_t samps_avail = recv_state.bytes_avail() / otw_type.get_sample_size(); + size_t copy_samps = std::min(num_samps - sample_offset, samps_avail); + + const boost::uint8_t *otw_mem = + recv_state.recv_buff->cast<const boost::uint8_t *>(); + + boost::uint8_t *io_mem = reinterpret_cast<boost::uint8_t *>(buff); + + convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read, + otw_type, + io_mem + sample_offset * io_type.size, + io_type, + copy_samps); + + recv_state.bytes_read += copy_samps * otw_type.get_sample_size(); + recv_state.overrun_poll_samp_count += copy_samps; + + return copy_samps; +} + +bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, + bool force) +{ + unsigned char overrun = 0; + + bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval; + + if (force || ready_to_poll) { + int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, + 0, + GS_RX_OVERRUN, + &overrun, sizeof(char)); + if (ret < 0) + std::cerr << "USRP: overrrun check failed" << std::endl; + if (overrun) + std::cerr << "O" << std::endl; + + recv_state.overrun_poll_samp_count = 0; + } + + return (bool) overrun; } size_t usrp1_impl::recv(const std::vector<void *> &buffs, @@ -174,56 +304,23 @@ size_t usrp1_impl::recv(const std::vector<void *> &buffs, recv_mode_t, size_t) { - UHD_ASSERT_THROW(_io_impl->packet_handler_recv_state.width == 1); UHD_ASSERT_THROW(buffs.size() == 1); - size_t sent_samps = 0; - size_t nsamps_to_copy = 0;; - - while (sent_samps < num_samps) { - if (_io_impl->packet_handler_recv_state.size_of_copy_buffs == 0) { - _io_impl->packet_handler_recv_state.fragment_offset_in_samps = 0; - _io_impl->packet_handler_recv_state.managed_buffs[0] = - _io_impl->data_transport->get_recv_buff(); - - //timeout or something bad returns zero - if (!_io_impl->packet_handler_recv_state.managed_buffs[0].get()) - return 0; - - _recv_helper(_io_impl->packet_handler_recv_state); - } - - size_t bytes_per_item = _rx_otw_type.get_sample_size(); - size_t nsamps_available = - _io_impl->packet_handler_recv_state.size_of_copy_buffs / bytes_per_item; - nsamps_to_copy = std::min(num_samps, nsamps_available); - size_t bytes_to_copy = nsamps_to_copy * bytes_per_item; - - convert_otw_type_to_io_type( - _io_impl->packet_handler_recv_state.copy_buffs[0], - _rx_otw_type, - reinterpret_cast<boost::uint8_t *>(buffs[0]) + sent_samps * io_type.size, - io_type, - nsamps_to_copy); - - _io_impl->packet_handler_recv_state.copy_buffs[0] += bytes_to_copy; - _io_impl->packet_handler_recv_state.size_of_copy_buffs -= bytes_to_copy; - - sent_samps += nsamps_to_copy; - - //check for overruns - if (!(_io_impl->count++ % 10000)) { - unsigned char overrun; - int ret = _ctrl_transport->usrp_control_read( - VRQ_GET_STATUS, - 0, - GS_RX_OVERRUN, - &overrun, sizeof(char)); - if (ret < 0) - std::cerr << "error: overrun check failed" << std::endl; - if (overrun) - std::cerr << "O" << std::endl; - } + size_t total_samps_recv = 0; + + while (total_samps_recv < num_samps) { + + if (!_io_impl->get_recv_buffer(_data_transport)) + return 0; + + total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0], + num_samps, + total_samps_recv, + io_type, + _rx_otw_type); + _io_impl->check_overrun(_ctrl_transport, + _rx_samps_per_poll_interval, false); } - return sent_samps; + + return total_samps_recv; } diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index c3343f1f8..74ec514ff 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -114,7 +114,7 @@ static boost::uint32_t calc_tx_mux( //calculate the channel flags int channel_flags = 0, chan = 0; BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ - wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)]; + wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)]; wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>(); @@ -298,7 +298,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) case MBOARD_PROP_RX_SUBDEV_SPEC: _rx_subdev_spec = val.as<subdev_spec_t>(); - verify_rx_subdev_spec(_rx_subdev_spec, this->get_link()); + verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); //sanity check UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2); //set the mux and set the number of rx channels @@ -307,7 +307,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) case MBOARD_PROP_TX_SUBDEV_SPEC: _tx_subdev_spec = val.as<subdev_spec_t>(); - verify_tx_subdev_spec(_tx_subdev_spec, this->get_link()); + verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); //sanity check UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2); //set the mux and set the number of tx channels diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index b175ba21f..9d326d6bd 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -53,7 +53,8 @@ public: if (iface_debug) { std::cout.fill('0'); - std::cout << "poke32(" << std::dec << addr << ", 0x"; + std::cout << "poke32("; + std::cout << std::dec << std::setw(2) << addr << ", 0x"; std::cout << std::hex << std::setw(8) << value << ")" << std::endl; } @@ -129,11 +130,7 @@ public: { UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); - byte_vector_t out_bytes; - byte_vector_t::iterator it = out_bytes.begin(); - unsigned char buff[max_i2c_data_bytes]; - int ret = _ctrl_transport->usrp_control_read(VRQ_I2C_READ, addr & 0xff, 0, @@ -142,9 +139,10 @@ public: if ((ret < 0) || (unsigned)ret < (num_bytes)) { std::cerr << "USRP: failed i2c read: " << ret << std::endl; - return out_bytes; + return byte_vector_t(num_bytes, 0xff); } + byte_vector_t out_bytes; for (size_t i = 0; i < num_bytes; i++) out_bytes.push_back(buff[i]); @@ -168,7 +166,7 @@ public: size_t num_bits, bool readback) { - UHD_ASSERT_THROW((num_bits < 32) && !(num_bits % 8)); + UHD_ASSERT_THROW((num_bits <= 32) && !(num_bits % 8)); size_t num_bytes = num_bits / 8; // Byteswap on num_bytes diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 33a069bc6..a15d0a244 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -55,13 +55,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) std::cout << "USRP1 firmware image: " << usrp1_fw_image << std::endl; //see what we got on the USB bus - usb_descriptors_t usb_descriptors; - usb_descriptors = usb_control::get_device_list(); + std::vector<usb_device_handle::sptr> device_list = + usb_device_handle::get_device_list(); //find the usrps and load firmware - BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { - if (desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { - usb_control::sptr ctrl_transport = usb_control::make(desc); + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_vendor_id() == 0xfffe && + handle->get_product_id() == 0x0002) { + + usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_firmware(usrp1_fw_image); } @@ -71,13 +73,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) boost::this_thread::sleep(boost::posix_time::milliseconds(500)); //get descriptors again with serial number - usb_descriptors = usb_control::get_device_list(); + device_list = usb_device_handle::get_device_list(); + + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_vendor_id() == 0xfffe && + handle->get_product_id() == 0x0002) { - BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { - if (desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { device_addr_t new_addr; new_addr["type"] = "usrp1"; - new_addr["serial"] = desc.serial; + new_addr["serial"] = handle->get_serial(); usrp1_addrs.push_back(new_addr); } } @@ -97,22 +101,23 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) std::cout << "USRP1 FPGA image: " << usrp1_fpga_image << std::endl; //try to match the given device address with something on the USB bus - usb_descriptors_t usb_descriptors; - usb_descriptors = usb_control::get_device_list(); + std::vector<usb_device_handle::sptr> device_list = + usb_device_handle::get_device_list(); //create data and control transports usb_zero_copy::sptr data_transport; usrp_ctrl::sptr usrp_ctrl; - BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { - if (desc.serial == device_addr["serial"] - && desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_vendor_id() == 0xfffe && + handle->get_product_id() == 0x0002 && + handle->get_serial() == device_addr["serial"]) { - usb_control::sptr ctrl_transport = usb_control::make(desc); + usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - data_transport = usb_zero_copy::make(desc, // identifier + data_transport = usb_zero_copy::make(handle, // identifier 6, // IN endpoint 2, // OUT endpoint 2 * (1 << 20), // buffer size @@ -142,8 +147,12 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, _clock_ctrl = usrp1_clock_ctrl::make(_iface); //create codec interface - _codec_ctrls[DBOARD_SLOT_A] = usrp1_codec_ctrl::make(_iface, SPI_ENABLE_CODEC_A); - _codec_ctrls[DBOARD_SLOT_B] = usrp1_codec_ctrl::make(_iface, SPI_ENABLE_CODEC_B); + _codec_ctrls[DBOARD_SLOT_A] = usrp1_codec_ctrl::make( + _iface, _clock_ctrl, SPI_ENABLE_CODEC_A + ); + _codec_ctrls[DBOARD_SLOT_B] = usrp1_codec_ctrl::make( + _iface, _clock_ctrl, SPI_ENABLE_CODEC_B + ); //initialize the codecs codec_init(); diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index cbd3d5315..4b4ac51dd 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -120,6 +120,10 @@ private: void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd); void handle_overrun(size_t); + //underrun and overrun poll intervals + size_t _rx_samps_per_poll_interval; + size_t _tx_samps_per_poll_interval; + //otw types uhd::otw_type_t _rx_otw_type; uhd::otw_type_t _tx_otw_type; |