From 86c86ede9775824411262e36f104489bcd171e21 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 13 Aug 2010 13:40:13 -0700 Subject: usrp1: Add libusb-1.0 implementations of USB interfaces --- host/lib/transport/libusb1_control.cpp | 238 +++++++++ host/lib/transport/libusb1_zero_copy.cpp | 854 +++++++++++++++++++++++++++++++ 2 files changed, 1092 insertions(+) create mode 100644 host/lib/transport/libusb1_control.cpp create mode 100644 host/lib/transport/libusb1_zero_copy.cpp (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp new file mode 100644 index 000000000..2903d943d --- /dev/null +++ b/host/lib/transport/libusb1_control.cpp @@ -0,0 +1,238 @@ +// +// 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 . +// + +#include +#include +#include +#include +#include +#include + +using namespace uhd::transport; + +static int libusb_debug_level = 0; +static 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(); + + size_t submit(boost::uint8_t request_type, + boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + 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) +{ + if (libusb_init(&_ctx) < 0) + UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + + libusb_set_debug(_ctx, libusb_debug_level); + + if (!open_device()) + UHD_THROW_SITE_INFO("USB: failed to open device"); + + if (!open_interface()) + UHD_THROW_SITE_INFO("USB: failed to open device interface"); +} + + +libusb_control_impl::~libusb_control_impl() +{ + libusb_close(_dev_handle); + libusb_exit(_ctx); +} + + +uhd::usb_descriptor_t libusb_control_impl::create_descriptor(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) + UHD_THROW_SITE_INFO("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, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) +{ + return libusb_control_transfer(_dev_handle, + request_type, + request, + value, + index, + buff, + length, + libusb_timeout); +} + + +/*********************************************************************** + * USB control public make functions + **********************************************************************/ +usb_control::sptr usb_control::make(uhd::usb_descriptor_t descriptor) +{ + return sptr(new libusb_control_impl(descriptor)); +} + +uhd::usb_descriptors_t usb_control::get_device_list() +{ + libusb_device **list; + uhd::usb_descriptors_t descriptors; + + if (libusb_init(NULL) < 0) + UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + + ssize_t cnt = libusb_get_device_list(NULL, &list); + + if (cnt < 0) + UHD_THROW_SITE_INFO("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_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp new file mode 100644 index 000000000..39617e4dd --- /dev/null +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -0,0 +1,854 @@ +// +// 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 . +// + + +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd::transport; + +static int libusb_debug_level = 3; + +/*********************************************************************** + * Helper functions + * + * Print to stdout the values of a libusb_transfer struct + ***********************************************************************/ +void pp_transfer(libusb_transfer *lut) +{ + std::cout << "Libusb transfer" << std::endl; + std::cout << " flags: 0x" << std::hex << (unsigned int) lut->flags << std::endl; + std::cout << " endpoint: 0x" << std::hex << (unsigned int) lut->endpoint << std::endl; + std::cout << " type: 0x" << std::hex << (unsigned int) lut->type << std::endl; + std::cout << " timeout: " << std::dec << lut->timeout << std::endl; + std::cout << " status: 0x" << std::hex << lut->status << std::endl; + std::cout << " length: " << std::dec << lut->length << std::endl; + std::cout << " actual_length: " << std::dec << lut->actual_length << std::endl; +} + +/*********************************************************************** + * USB asynchronous phony zero_copy endpoint + * This endpoint implementation provides asynchronous I/O to libusb-1.0 + * devices. Each endpoint is directional and two can be combined to + * create a bidirectional interface. It is a zero copy implementation + * with respect to libusb, however, each send and recv requires a copy + * operation from kernel to userspace; this is due to the usbfs + * interface provided by the kernel. + **********************************************************************/ +class usb_endpoint { +private: + libusb_device_handle *_dev_handle; + libusb_context *_ctx; + int _endpoint; + bool _input; + + size_t _transfer_size; + size_t _num_transfers; + + /* + * Transfer state lists (free, pending, or completed) + */ + std::list _free_list; + std::list _pending_list; + std::list _completed_list; + + /* + * Calls for processing asynchronous I/O + */ + libusb_transfer *allocate_transfer(int buff_len); + bool cancel(libusb_transfer *lut); + bool cancel_all(); + bool reap_pending_list(); + bool reap_pending_list_timeout(); + bool reap_completed_list(); + + /* + * Transfer state manipulators + */ + void free_list_add(libusb_transfer *lut); + void pending_list_add(libusb_transfer *lut); + void completed_list_add(libusb_transfer *lut); + libusb_transfer *free_list_get(); + libusb_transfer *completed_list_get(); + bool pending_list_remove(libusb_transfer *lut); + + /* + * Misc + */ + void print_transfer_status(libusb_transfer *lut); + +public: + usb_endpoint(libusb_device_handle *dev_handle, + libusb_context *ctx, int endpoint, bool input, + size_t transfer_size, size_t num_transfers); + + ~usb_endpoint(); + + /* + * Accessors + */ + int get_endpoint() const { return _endpoint; } + bool get_direction() const { return _input; } + libusb_device_handle *get_dev_handle() const { return _dev_handle; } + libusb_context *get_ctx() const { return _ctx; } + + /* + * Exposed interface for submitting / retrieving transfer buffers + * used in zero-copy interface + */ + bool submit(libusb_transfer *lut); + libusb_transfer *get_completed_transfer(); + libusb_transfer *get_free_transfer(); + + /* + * Callback use only + */ + void callback_handle_transfer(libusb_transfer *lut); +}; + + +/* + * Callback function called when submitted transfers complete. + * The endpoint upon which the transfer is part of is recovered + * and the transfer moved from pending to completed state. + */ +static void callback(libusb_transfer *lut) +{ + usb_endpoint *endpoint = (usb_endpoint *) lut->user_data; + endpoint->callback_handle_transfer(lut); +} + + +/* + * Accessor call to allow list access from callback space + */ +void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) +{ + if (!pending_list_remove(lut)) { + std::cerr << "USB: pending remove failed" << std::endl; + return; + } + + completed_list_add(lut); +} + + +/* + * Constructor + * + * Allocate libusb transfers. For IN endpoints, submit the transfers + * so that they're ready to return when data is available. + */ +usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, + libusb_context *ctx, int endpoint, bool input, + size_t transfer_size, size_t num_transfers) + : _dev_handle(dev_handle), + _ctx(ctx), _endpoint(endpoint), _input(input), + _transfer_size(transfer_size), _num_transfers(num_transfers) +{ + unsigned int i; + for (i = 0; i < _num_transfers; i++) { + free_list_add(allocate_transfer(_transfer_size)); + + if (_input) + submit(free_list_get()); + } +} + + +/* + * Destructor + */ +usb_endpoint::~usb_endpoint() +{ + cancel_all(); + + while (!_pending_list.empty()) { + if (!reap_pending_list()) + std::cerr << "error: destructor failed to reap" << std::endl; + } + + while (!_completed_list.empty()) { + if (!reap_completed_list()) + std::cerr << "error: destructor failed to reap" << std::endl; + } + + while (!_free_list.empty()) { + libusb_free_transfer(free_list_get()); + } +} + + +/* + * Allocate a libusb transfer + * + * The allocated transfer is continuously reused and should be freed at + * shutdown. + */ +libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) +{ + libusb_transfer *lut = libusb_alloc_transfer(0); + + unsigned char *buff = new unsigned char[buff_len]; + + unsigned int endpoint = ((_endpoint & 0x7f) | (_input ? 0x80 : 0)); + + libusb_fill_bulk_transfer(lut, // transfer + _dev_handle, // dev_handle + endpoint, // endpoint + buff, // buffer + buff_len, // length + callback, // callback + this, // user_data + 0); // timeout + return lut; +} + + +/* + * Asynchonous transfer submission + * + * Submit and mark transfer as pending. + */ +bool usb_endpoint::submit(libusb_transfer *lut) +{ + int retval; + if ((retval = libusb_submit_transfer(lut)) < 0) { + std::cerr << "error: libusb_submit_transfer: " << retval << std::endl; + return false; + } + + pending_list_add(lut); + return true; +} + + +/* + * Cancel a pending transfer + * + * Search the pending list for the transfer and cancel if found. + * Returns true on success. False otherwise or on error. + * + * Note: success only indicates submission of cancelation request. + * Sucessful cancelation is not known until the callback occurs. + */ +bool usb_endpoint::cancel(libusb_transfer *lut) +{ + std::list::iterator iter; + for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { + if (*iter == lut) { + libusb_cancel_transfer(lut); + return true; + } + } + return false; +} + + +/* + * Cancel all pending transfers + * + * Note: success only indicates submission of cancelation request. + * Sucessful cancelation is not known until the callback occurs. + */ +bool usb_endpoint::cancel_all() +{ + std::list::iterator iter; + + for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { + if (libusb_cancel_transfer(*iter) < 0) { + std::cerr << "error: libusb_cancal_transfer() failed" << std::endl; + return false; + } + } + + return true; +} + + +/* + * Reap completed transfers + * + * return true if at least one transfer was reaped, false otherwise. + * + * Check completed transfers for errors and mark as free. This is a + * blocking call. + */ +bool usb_endpoint::reap_completed_list() +{ + libusb_transfer *lut; + + if (_completed_list.empty()) { + if (!reap_pending_list_timeout()) + return false; + } + + while (!_completed_list.empty()) { + lut = completed_list_get(); + print_transfer_status(lut); + free_list_add(lut); + } + + return true; +} + + +/* + * Print completed transfer status error(s) + * + * return true if at least one transfer was reaped, false otherwise. + * + * Check completed transfers for errors and mark as free. This is a + * blocking call. + */ +void usb_endpoint::print_transfer_status(libusb_transfer *lut) +{ + switch (lut->status) { + case LIBUSB_TRANSFER_COMPLETED: + if (lut->actual_length < lut->length) { + std::cerr << "USB: transfer completed with short write," + << " length = " << lut->length + << " actual = " << lut->actual_length << std::endl; + } + + if ((lut->actual_length < 0) || (lut->length < 0)) { + std::cerr << "USB: transfer completed with invalid response" + << std::endl; + } + break; + case LIBUSB_TRANSFER_CANCELLED: + break; + case LIBUSB_TRANSFER_NO_DEVICE: + std::cerr << "USB: device was disconnected" << std::endl; + break; + case LIBUSB_TRANSFER_OVERFLOW: + std::cerr << "USB: device sent more data than requested" << std::endl; + break; + case LIBUSB_TRANSFER_TIMED_OUT: + std::cerr << "USB: transfer timed out" << std::endl; + break; + case LIBUSB_TRANSFER_STALL: + std::cerr << "USB: halt condition detected (endpoint stalled)" << std::endl; + break; + case LIBUSB_TRANSFER_ERROR: + std::cerr << "USB: transfer failed" << std::endl; + break; + default: + std::cerr << "USB: received unknown transfer status" << std::endl; + } +} + + +/* + * Reap pending transfers + * + * Return true if at least one transfer was reaped, false otherwise. This is + * a blocking call. + * + * Reaping submitted transfers is handled by libusb and the assigned callback + * function. Block until at least one transfer is reaped. + */ +bool usb_endpoint::reap_pending_list() +{ + int retval; + + if ((retval = libusb_handle_events(_ctx)) < 0) { + std::cerr << "error: libusb_handle_events: " << retval << std::endl; + return false; + } + + return true; +} + + +/* + * Reap pending transfers with timeout + * + * Return true if at least one transfer was reaped, false otherwise. This call + * blocks until a transfer is reaped or timeout. + * + * Reaping submitted transfers is handled by libusb and the assigned callback + * function. Block until at least one transfer is reaped or timeout occurs. + */ +bool usb_endpoint::reap_pending_list_timeout() +{ + int retval; + timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 100000; //100ms + + size_t pending_list_size = _pending_list.size(); + + if ((retval = libusb_handle_events_timeout(_ctx, &tv)) < 0) { + std::cerr << "error: libusb_handle_events: " << retval << std::endl; + return false; + } + + if (_pending_list.size() < pending_list_size) { + return true; + } + else { + return false; + } +} + + +/* + * Returns a free transfer with empty data bufer for OUT requests + */ +libusb_transfer *usb_endpoint::get_free_transfer() +{ + if (_free_list.empty()) { + if (!reap_completed_list()) + return NULL; + } + + return free_list_get(); +} + + +/* + * Returns a transfer containing data for IN requests + */ +libusb_transfer *usb_endpoint::get_completed_transfer() +{ + if (_completed_list.empty()) { + if (!reap_pending_list_timeout()) + return NULL; + } + + return completed_list_get(); +} + +/* + * List operations + */ +void usb_endpoint::free_list_add(libusb_transfer *lut) +{ + _free_list.push_back(lut); +} + +void usb_endpoint::pending_list_add(libusb_transfer *lut) +{ + _pending_list.push_back(lut); +} + +void usb_endpoint::completed_list_add(libusb_transfer *lut) +{ + _completed_list.push_back(lut); +} + + +/* + * Free and completed lists don't have ordered content + * + * Pop transfers from the front as needed + */ +libusb_transfer *usb_endpoint::free_list_get() +{ + libusb_transfer *lut; + + if (_free_list.size() == 0) { + return NULL; + } + else { + lut = _free_list.front(); + _free_list.pop_front(); + return lut; + } +} + + +/* + * Free and completed lists don't have ordered content + * + * Pop transfers from the front as needed + */ +libusb_transfer *usb_endpoint::completed_list_get() +{ + libusb_transfer *lut; + + if (_completed_list.empty()) { + return NULL; + } + else { + lut = _completed_list.front(); + _completed_list.pop_front(); + return lut; + } +} + + +/* + * Search and remove transfer from pending list + * + * Assuming that the callbacks occur in order, the front element + * should yield the correct transfer. If not, then something else + * is going on. If no transfers match, then something went wrong. + */ +bool usb_endpoint::pending_list_remove(libusb_transfer *lut) +{ + std::list::iterator iter; + for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { + if (*iter == lut) { + _pending_list.erase(iter); + return true; + } + } + return false; +} + + +/*********************************************************************** + * Managed buffers + **********************************************************************/ +class libusb_managed_recv_buffer_impl : public managed_recv_buffer { +public: + libusb_managed_recv_buffer_impl(libusb_transfer *lut, + usb_endpoint *endpoint) + : _buff(lut->buffer, lut->length) + { + _lut = lut; + _endpoint = endpoint; + } + + ~libusb_managed_recv_buffer_impl() + { + if (!_endpoint->submit(_lut)) + std::cerr << "USB: failed to submit IN transfer" << std::endl; + } + +private: + const boost::asio::const_buffer &get() const + { + return _buff; + } + + libusb_transfer *_lut; + usb_endpoint *_endpoint; + const boost::asio::const_buffer _buff; +}; + + +class libusb_managed_send_buffer_impl : public managed_send_buffer { +public: + libusb_managed_send_buffer_impl(libusb_transfer *lut, + usb_endpoint *endpoint, + size_t buff_size) + : _buff(lut->buffer, buff_size) + { + _lut = lut; + _endpoint = endpoint; + } + + ~libusb_managed_send_buffer_impl() + { + /* NOP */ + } + + ssize_t commit(size_t num_bytes) + { + _lut->length = num_bytes; + _lut->actual_length = 0; + + if (_endpoint->submit(_lut)) + return num_bytes; + else + return 0; + } + +private: + const boost::asio::mutable_buffer &get() const + { + return _buff; + } + + libusb_transfer *_lut; + usb_endpoint *_endpoint; + const boost::asio::mutable_buffer _buff; +}; + + +/*********************************************************************** + * USB zero_copy device class + **********************************************************************/ +class libusb_zero_copy_impl : public usb_zero_copy +{ +private: + usb_endpoint *_rx_ep; + usb_endpoint *_tx_ep; + + /* + * Libusb handles + */ + libusb_context *_rx_ctx; + libusb_context *_tx_ctx; + 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 sptr; + + /* + * Structors + */ + libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t recv_buff_size, + size_t send_buff_size); + + ~libusb_zero_copy_impl(); + + managed_recv_buffer::sptr get_recv_buff(void); + managed_send_buffer::sptr get_send_buff(void); + + size_t get_num_recv_frames(void) const { return _num_frames; } + size_t get_num_send_frames(void) const { return _num_frames; } +}; + + +libusb_zero_copy_impl::libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t buff_size, + size_t block_size) + : _rx_ctx(NULL), _tx_ctx(NULL), _rx_dev_handle(NULL), _tx_dev_handle(NULL), + _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; + + if (libusb_init(&_tx_ctx) < 0) + std::cerr << "error: libusb_init" << std::endl; + + libusb_set_debug(_rx_ctx, libusb_debug_level); + libusb_set_debug(_tx_ctx, libusb_debug_level); + + open_device(descriptor); + + open_interface(_rx_dev_handle, 2); + open_interface(_tx_dev_handle, 1); + + _rx_ep = new usb_endpoint(_rx_dev_handle, + _rx_ctx, + rx_endpoint, + true, + _recv_buff_size, + _num_frames); + + _tx_ep = new usb_endpoint(_tx_dev_handle, + _tx_ctx, + tx_endpoint, + false, + _send_buff_size, + _num_frames); +} + + +libusb_zero_copy_impl::~libusb_zero_copy_impl() +{ + delete _rx_ep; + delete _tx_ep; + + libusb_close(_rx_dev_handle); + libusb_close(_tx_dev_handle); + + libusb_exit(_rx_ctx); + libusb_exit(_tx_ctx); +} + + +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(); + if (lut == NULL) { + return managed_recv_buffer::sptr(); + } + else { + return managed_recv_buffer::sptr( + new libusb_managed_recv_buffer_impl(lut, + _rx_ep)); + } +} + + +managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() +{ + libusb_transfer *lut = _tx_ep->get_free_transfer(); + if (lut == NULL) { + return managed_send_buffer::sptr(); + } + else { + return managed_send_buffer::sptr( + new libusb_managed_send_buffer_impl(lut, + _tx_ep, + _send_buff_size)); + } +} + + +/*********************************************************************** + * USB zero_copy make functions + **********************************************************************/ +usb_zero_copy::sptr usb_zero_copy::make(uhd::usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t buff_size, + size_t block_size) + +{ + return sptr(new libusb_zero_copy_impl(descriptor, + rx_endpoint, + tx_endpoint, + buff_size, + block_size)); +} + + + -- cgit v1.2.3 From d10de2f6a68ebf0611368e50d85709cbecf8fd0f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 13 Aug 2010 16:06:14 -0700 Subject: usrp1: Cmake changes to find libusb-1.0 FindUSB1.cmake file imported from the libFTDI project, http://www.intra2net.com/en/developer/libftdi --- host/lib/transport/CMakeLists.txt | 15 +++++++++++++++ host/lib/transport/FindUSB1.cmake | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 host/lib/transport/FindUSB1.cmake (limited to 'host/lib/transport') diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index bde2b72b9..d6e1ff7ba 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -17,6 +17,21 @@ #This file will be included by cmake, use absolute paths! +######################################################################## +# Setup libusb +######################################################################## +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/lib/transport) +FIND_PACKAGE(USB1 REQUIRED) + +IF(LIBUSB_FOUND) + INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIR}) + LIBUHD_APPEND_LIBS(${LIBUSB_LIBRARIES}) + LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp + ) +ENDIF(LIBUSB_FOUND) + ######################################################################## # Check for SIMD headers ######################################################################## diff --git a/host/lib/transport/FindUSB1.cmake b/host/lib/transport/FindUSB1.cmake new file mode 100644 index 000000000..ebcac99eb --- /dev/null +++ b/host/lib/transport/FindUSB1.cmake @@ -0,0 +1,38 @@ +# - Try to find the freetype library +# Once done this defines +# +# LIBUSB_FOUND - system has libusb +# LIBUSB_INCLUDE_DIR - the libusb include directory +# LIBUSB_LIBRARIES - Link these to use libusb + +# Copyright (c) 2006, 2008 Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) + + # in cache already + set(LIBUSB_FOUND TRUE) + +else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) + IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + pkg_check_modules(PC_LIBUSB libusb-1.0) + ENDIF(NOT WIN32) + + FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h + PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}) + + FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0 + PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) + + MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) + +endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) -- cgit v1.2.3 From 2e978d8835b8f954b7c34c42138b64d3a5767f81 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 15 Aug 2010 12:40:37 -0700 Subject: usrp1: compiling off next branch made usb checking changes implemented named_prop_t::extract change copied the remainder of the codec pga gain control --- host/lib/transport/CMakeLists.txt | 1 + host/lib/transport/libusb1_control.cpp | 14 ++++----- host/lib/usrp/usrp1/CMakeLists.txt | 56 ++++++++++++++++++++++------------ host/lib/usrp/usrp1/codec_ctrl.cpp | 8 ++--- host/lib/usrp/usrp1/codec_ctrl.hpp | 16 ++++++++++ host/lib/usrp/usrp1/codec_impl.cpp | 33 +++++++++----------- host/lib/usrp/usrp1/dboard_iface.cpp | 7 +++-- host/lib/usrp/usrp1/dboard_impl.cpp | 14 ++++----- host/lib/usrp/usrp1/mboard_impl.cpp | 12 +++----- host/lib/usrp/usrp1/usrp1_impl.cpp | 5 ++- 10 files changed, 98 insertions(+), 68 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index d6e1ff7ba..627d2d806 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -30,6 +30,7 @@ IF(LIBUSB_FOUND) ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp ) + SET(HAVE_USB_SUPPORT TRUE) ENDIF(LIBUSB_FOUND) ######################################################################## diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 2903d943d..c2f7060e8 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -16,10 +16,10 @@ // #include -#include #include #include #include +#include #include using namespace uhd::transport; @@ -61,15 +61,15 @@ libusb_control_impl::libusb_control_impl(uhd::usb_descriptor_t descriptor) : _descriptor(descriptor), _ctx(NULL), _dev_handle(NULL) { if (libusb_init(&_ctx) < 0) - UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + throw std::runtime_error("USB: failed to initialize libusb"); libusb_set_debug(_ctx, libusb_debug_level); if (!open_device()) - UHD_THROW_SITE_INFO("USB: failed to open device"); + throw std::runtime_error("USB: failed to open device"); if (!open_interface()) - UHD_THROW_SITE_INFO("USB: failed to open device interface"); + throw std::runtime_error("USB: failed to open device interface"); } @@ -85,7 +85,7 @@ uhd::usb_descriptor_t libusb_control_impl::create_descriptor(libusb_device *dev) libusb_device_descriptor desc; if (libusb_get_device_descriptor(dev, &desc) < 0) - UHD_THROW_SITE_INFO("USB: failed to get device descriptor"); + throw std::runtime_error("USB: failed to get device descriptor"); uhd::usb_descriptor_t descriptor; @@ -217,12 +217,12 @@ uhd::usb_descriptors_t usb_control::get_device_list() uhd::usb_descriptors_t descriptors; if (libusb_init(NULL) < 0) - UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + throw std::runtime_error("USB: failed to initialize libusb"); ssize_t cnt = libusb_get_device_list(NULL, &list); if (cnt < 0) - UHD_THROW_SITE_INFO("USB: failed to get device list"); + throw std::runtime_error("USB: failed to get device list"); ssize_t i = 0; for (i = 0; i < cnt; i++) { diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index eb7bd4b06..229a4ce63 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -17,23 +17,41 @@ #This file will be included by cmake, use absolute paths! -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) +######################################################################## +# Conditionally configure the USRP1 support +######################################################################## +MESSAGE(STATUS "Configuring usrp1 support...") -LIBUHD_APPEND_SOURCES( - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dsp_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/io_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/mboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.hpp -) +IF(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - found") +ELSE(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - not found") +ENDIF(HAVE_USB_SUPPORT) + +#TODO check for usrp1 enable/disable option flag + +IF(HAVE_USB_SUPPORT) + MESSAGE(STATUS " Building usrp1 support.") + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) + + LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dsp_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/io_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.hpp + ) +ELSE(HAVE_USB_SUPPORT) + MESSAGE(STATUS " Skipping usrp1 support.") +ENDIF(HAVE_USB_SUPPORT) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 866650c2c..d0576a769 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -25,12 +25,12 @@ #include #include #include +#include #include #include #include #include #include -#include using namespace uhd; @@ -335,9 +335,9 @@ unsigned int usrp1_codec_ctrl_impl::compute_freq_control_word_9862( 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; - fprintf(stdout, - "compute_freq_control_word_9862: target = %g actual = %g delta = %g v = %8d\n", - target_freq, *actual_freq, *actual_freq - target_freq, v); + 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; } diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 51e29345a..0605e3228 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 #include #include @@ -31,6 +32,9 @@ class usrp1_codec_ctrl : boost::noncopyable{ public: typedef boost::shared_ptr sptr; + static const uhd::gain_range_t tx_pga_gain_range; + static const uhd::gain_range_t rx_pga_gain_range; + /*! * Make a new clock control object. * \param iface the usrp1 iface object @@ -70,6 +74,18 @@ public: */ virtual void write_aux_dac(aux_dac_t which, float volts) = 0; + //! Set the TX PGA gain + virtual void set_tx_pga_gain(float gain) = 0; + + //! Get the TX PGA gain + virtual float get_tx_pga_gain(void) = 0; + + //! Set the RX PGA gain ('A' or 'B') + virtual void set_rx_pga_gain(float gain, char which) = 0; + + //! 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; }; diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp index 9253c06ba..7bf5631fb 100644 --- a/host/lib/usrp/usrp1/codec_impl.cpp +++ b/host/lib/usrp/usrp1/codec_impl.cpp @@ -16,6 +16,7 @@ // #include "usrp1_impl.hpp" +#include #include #include @@ -44,8 +45,7 @@ static const std::string ad9862_pga_gain_name = "ad9862 pga"; void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()) { @@ -62,17 +62,17 @@ void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) return; case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = usrp1_codec_ctrl::rx_pga_gain_range; return; case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = _codec_ctrl->get_rx_pga_gain('A'); return; case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = _codec_ctrl->get_rx_pga_gain('B'); return; @@ -80,20 +80,19 @@ void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) } } -void usrp1_impl::rx_codec_set(const wax::obj &, const wax::obj &) +void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the set request conditioned on the key switch(key.as()) { case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); _codec_ctrl->set_rx_pga_gain(val.as(), 'A'); return; case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); _codec_ctrl->set_rx_pga_gain(val.as(), 'B'); return; @@ -106,8 +105,7 @@ void usrp1_impl::rx_codec_set(const wax::obj &, const wax::obj &) **********************************************************************/ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()) { @@ -124,13 +122,13 @@ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) return; case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = usrp1_codec_ctrl::tx_pga_gain_range; return; case CODEC_PROP_GAIN_I: //only one gain for I and Q case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = _codec_ctrl->get_tx_pga_gain(); return; @@ -138,16 +136,15 @@ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) } } -void usrp1_impl::tx_codec_set(const wax::obj &, const wax::obj &) +void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the set request conditioned on the key switch(key.as()){ case CODEC_PROP_GAIN_I: //only one gain for I and Q case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); _codec_ctrl->set_tx_pga_gain(val.as()); return; diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 11ad3fe8a..ef6a1e67b 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -51,9 +51,12 @@ public: /* NOP */ } - std::string get_mboard_name() + special_props_t get_special_props() { - return "usrp1"; + special_props_t props; + props.soft_clock_divider = true; + props.mangle_i2c_addrs = false; //TODO true on side B + return props; } void write_aux_dac(unit_t, aux_dac_t, float); diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp index 4f2836ea9..9df87432d 100644 --- a/host/lib/usrp/usrp1/dboard_impl.cpp +++ b/host/lib/usrp/usrp1/dboard_impl.cpp @@ -82,8 +82,7 @@ void usrp1_impl::dboard_init(void) **********************************************************************/ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -92,7 +91,7 @@ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(name); + val = _dboard_manager->get_rx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: @@ -112,7 +111,7 @@ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_manager->get_rx_subdev(name), + val = make_gain_group(_dboard_manager->get_rx_subdev(key.name), _rx_codec_proxy->get_link()); return; @@ -142,8 +141,7 @@ void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val) **********************************************************************/ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -152,7 +150,7 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(name); + val = _dboard_manager->get_tx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: @@ -172,7 +170,7 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_manager->get_tx_subdev(name), + val = make_gain_group(_dboard_manager->get_tx_subdev(key.name), _tx_codec_proxy->get_link()); return; diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index ee1ba305b..2514072e0 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -111,9 +111,7 @@ void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) **********************************************************************/ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; - std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -126,7 +124,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _rx_dboard_proxy->get_link(); return; @@ -135,7 +133,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _tx_dboard_proxy->get_link(); return; @@ -144,7 +142,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_RX_DSP: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _rx_ddc_proxy->get_link(); return; @@ -153,7 +151,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_TX_DSP: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _tx_duc_proxy->get_link(); return; diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 4cb286354..1435b981c 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -165,8 +165,7 @@ usrp1_impl::~usrp1_impl(void){ **********************************************************************/ void usrp1_impl::get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -175,7 +174,7 @@ void usrp1_impl::get(const wax::obj &key_, wax::obj &val) return; case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _mboard_proxy->get_link(); return; -- cgit v1.2.3 From 8c872ffb2e4f24927b6ec9de825a31c5eda014b8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 24 Aug 2010 17:26:07 -0700 Subject: uhd: convert types corrected for little endian, created SSE2 float/short conversion for no-swap case --- host/lib/transport/convert_types_impl.hpp | 141 ++++++++++++++++++++++++------ host/test/convert_types_test.cpp | 139 ++++++++++++++++++----------- 2 files changed, 202 insertions(+), 78 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index 5958b08cb..641029795 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -28,6 +28,13 @@ #define USE_EMMINTRIN_H //use sse2 intrinsics #endif +#if defined(USE_EMMINTRIN_H) + #include +#endif + +//! shortcut for a byteswap16 with casting +#define BSWAP16_C(num) uhd::byteswap(boost::uint16_t(num)) + /*********************************************************************** * Typedefs **********************************************************************/ @@ -47,9 +54,10 @@ static UHD_INLINE void sc16_to_item32_nswap( static UHD_INLINE void sc16_to_item32_bswap( const sc16_t *input, item32_t *output, size_t nsamps ){ - const item32_t *item32_input = (const item32_t *)input; for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(item32_input[i]); + boost::uint16_t real = BSWAP16_C(input[i].real()); + boost::uint16_t imag = BSWAP16_C(input[i].imag()); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } @@ -65,34 +73,71 @@ static UHD_INLINE void item32_to_sc16_nswap( static UHD_INLINE void item32_to_sc16_bswap( const item32_t *input, sc16_t *output, size_t nsamps ){ - item32_t *item32_output = (item32_t *)output; for (size_t i = 0; i < nsamps; i++){ - item32_output[i] = uhd::byteswap(input[i]); + boost::int16_t real = BSWAP16_C(input[i] >> 0); + boost::int16_t imag = BSWAP16_C(input[i] >> 16); + output[i] = sc16_t(real, imag); } } /*********************************************************************** - * Convert complex float buffer to items32 + * Convert complex float buffer to items32 (no swap) **********************************************************************/ static const float shorts_per_float = float(32767); -static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ - boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); - boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); - return (item32_t(real) << 16) | (item32_t(imag) << 0); +#define FC32_TO_SC16_C(num) boost::int16_t(num*shorts_per_float) + +//////////////////////////////////// +// none-swap +//////////////////////////////////// +#if defined(USE_EMMINTRIN_H) +static UHD_INLINE void fc32_to_item32_nswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(shorts_per_float); + + //convert blocks of samples with intrinsics + size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ + //load from input + __m128 tmplo = _mm_loadu_ps(reinterpret_cast(input+i+0)); + __m128 tmphi = _mm_loadu_ps(reinterpret_cast(input+i+2)); + + //convert and scale + __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); + __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); + + //pack + __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); + + //store to output + _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); + } + + //convert remainder + for (; i < nsamps; i++){ + boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); + boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + } } +#else static UHD_INLINE void fc32_to_item32_nswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = fc32_to_item32(input[i]); + boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); + boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } -#if defined(USE_EMMINTRIN_H) -#include +#endif +//////////////////////////////////// +// byte-swap +//////////////////////////////////// +#if defined(USE_EMMINTRIN_H) static UHD_INLINE void fc32_to_item32_bswap( const fc32_t *input, item32_t *output, size_t nsamps ){ @@ -108,7 +153,7 @@ static UHD_INLINE void fc32_to_item32_bswap( __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - //pack + byteswap -> byteswap 32 bit words + //pack + byteswap -> byteswap 16 bit words __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); @@ -118,7 +163,9 @@ static UHD_INLINE void fc32_to_item32_bswap( //convert remainder for (; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); + boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); + boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } @@ -127,7 +174,9 @@ static UHD_INLINE void fc32_to_item32_bswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); + boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); + boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } @@ -138,24 +187,60 @@ static UHD_INLINE void fc32_to_item32_bswap( **********************************************************************/ static const float floats_per_short = float(1.0/shorts_per_float); -static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ - return fc32_t( - float(boost::int16_t(item >> 16)*floats_per_short), - float(boost::int16_t(item >> 0)*floats_per_short) - ); +#define I16_TO_FC32_C(num) (boost::int16_t(num)*floats_per_short) + +//////////////////////////////////// +// none-swap +//////////////////////////////////// +#if defined(USE_EMMINTRIN_H) +static UHD_INLINE void item32_to_fc32_nswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); + __m128i zeroi = _mm_setzero_si128(); + + //convert blocks of samples with intrinsics + size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ + //load from input + __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); + + //unpack + __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits + __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); + + //convert and scale + __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); + __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); + + //store to output + _mm_storeu_ps(reinterpret_cast(output+i+0), tmplo); + _mm_storeu_ps(reinterpret_cast(output+i+2), tmphi); + } + + //convert remainder + for (; i < nsamps; i++){ + float real = I16_TO_FC32_C(input[i] >> 0); + float imag = I16_TO_FC32_C(input[i] >> 16); + output[i] = fc32_t(real, imag); + } } +#else static UHD_INLINE void item32_to_fc32_nswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(input[i]); + float real = I16_TO_FC32_C(input[i] >> 0); + float imag = I16_TO_FC32_C(input[i] >> 16); + output[i] = fc32_t(real, imag); } } +#endif +//////////////////////////////////// +// byte-swap +//////////////////////////////////// #if defined(USE_EMMINTRIN_H) -#include - static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ @@ -167,7 +252,7 @@ static UHD_INLINE void item32_to_fc32_bswap( //load from input __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); - //byteswap + unpack -> byteswap 32 bit words + //byteswap + unpack -> byteswap 16 bit words tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); @@ -183,7 +268,9 @@ static UHD_INLINE void item32_to_fc32_bswap( //convert remainder for (; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); + float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); + float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); + output[i] = fc32_t(real, imag); } } @@ -192,7 +279,9 @@ static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); + float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); + float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); + output[i] = fc32_t(real, imag); } } diff --git a/host/test/convert_types_test.cpp b/host/test/convert_types_test.cpp index 1587be57f..d132a708b 100644 --- a/host/test/convert_types_test.cpp +++ b/host/test/convert_types_test.cpp @@ -17,109 +17,144 @@ #include #include +#include #include +#include #include +#include +#include using namespace uhd; -template -void loopback( +//typedefs for complex types +typedef std::complex sc16_t; +typedef std::complex fc32_t; + +//extract pointer to POD since using &vector.front() throws in MSVC +template void * pod2ptr(T &pod){ + return boost::asio::buffer_cast(boost::asio::buffer(pod)); +} +template const void * pod2ptr(const T &pod){ + return boost::asio::buffer_cast(boost::asio::buffer(pod)); +} + +/*********************************************************************** + * Loopback runner: + * convert input buffer into intermediate buffer + * convert intermediate buffer into output buffer + **********************************************************************/ +template static void loopback( + size_t nsamps, const io_type_t &io_type, const otw_type_t &otw_type, - const host_type *input, - host_type *output + const Range &input, + Range &output ){ - dev_type dev[nsamps]; + //item32 is largest device type + std::vector dev(nsamps); //convert to dev type transport::convert_io_type_to_otw_type( - input, io_type, - dev, otw_type, + pod2ptr(input), io_type, + pod2ptr(dev), otw_type, nsamps ); //convert back to host type transport::convert_otw_type_to_io_type( - dev, otw_type, - output, io_type, + pod2ptr(dev), otw_type, + pod2ptr(output), io_type, nsamps ); } -typedef std::complex sc16_t; +/*********************************************************************** + * Test short conversion + **********************************************************************/ +static void test_convert_types_sc16( + size_t nsamps, + const io_type_t &io_type, + const otw_type_t &otw_type +){ + //fill the input samples + std::vector input(nsamps), output(nsamps); + BOOST_FOREACH(sc16_t &in, input) in = sc16_t( + std::rand()-(RAND_MAX/2), + std::rand()-(RAND_MAX/2) + ); -BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16){ - sc16_t in_sc16[] = { - sc16_t(0, -1234), sc16_t(4321, 1234), - sc16_t(9876, -4567), sc16_t(8912, 0) - }, out_sc16[4]; + //run the loopback and test + loopback(nsamps, io_type, otw_type, input, output); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} +BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16){ io_type_t io_type(io_type_t::COMPLEX_INT16); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_sc16, out_sc16); - BOOST_CHECK_EQUAL_COLLECTIONS(in_sc16, in_sc16+4, out_sc16, out_sc16+4); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_sc16(nsamps, io_type, otw_type); + } } BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16){ - sc16_t in_sc16[] = { - sc16_t(0, -1234), sc16_t(4321, 1234), - sc16_t(9876, -4567), sc16_t(8912, 0) - }, out_sc16[4]; - io_type_t io_type(io_type_t::COMPLEX_INT16); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_sc16, out_sc16); - BOOST_CHECK_EQUAL_COLLECTIONS(in_sc16, in_sc16+4, out_sc16, out_sc16+4); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_sc16(nsamps, io_type, otw_type); + } } -typedef std::complex fc32_t; - -#define BOOST_CHECK_CLOSE_COMPLEX(a1, a2, p) \ - BOOST_CHECK_CLOSE(a1.real(), a2.real(), p); \ - BOOST_CHECK_CLOSE(a1.imag(), a2.imag(), p); +/*********************************************************************** + * Test float conversion + **********************************************************************/ +static void test_convert_types_fc32( + size_t nsamps, + const io_type_t &io_type, + const otw_type_t &otw_type +){ + //fill the input samples + std::vector input(nsamps), output(nsamps); + BOOST_FOREACH(fc32_t &in, input) in = fc32_t( + (std::rand()/float(RAND_MAX/2)) - 1, + (std::rand()/float(RAND_MAX/2)) - 1 + ); -static const float tolerance = float(0.1); + //run the loopback and test + loopback(nsamps, io_type, otw_type, input, output); + for (size_t i = 0; i < nsamps; i++){ + BOOST_CHECK_CLOSE_FRACTION(input[i].real(), output[i].real(), float(0.01)); + BOOST_CHECK_CLOSE_FRACTION(input[i].imag(), output[i].imag(), float(0.01)); + } +} BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32){ - fc32_t in_fc32[] = { - fc32_t(float(0), float(-0.2)), fc32_t(float(0.03), float(-0.16)), - fc32_t(float(1.0), float(.45)), fc32_t(float(0.09), float(0)) - }, out_fc32[4]; - io_type_t io_type(io_type_t::COMPLEX_FLOAT32); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_fc32, out_fc32); - - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[0], out_fc32[0], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[1], out_fc32[1], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[2], out_fc32[2], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[3], out_fc32[3], tolerance); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_fc32(nsamps, io_type, otw_type); + } } BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32){ - fc32_t in_fc32[] = { - fc32_t(float(0), float(-0.2)), fc32_t(float(0.03), float(-0.16)), - fc32_t(float(1.0), float(.45)), fc32_t(float(0.09), float(0)) - }, out_fc32[4]; - io_type_t io_type(io_type_t::COMPLEX_FLOAT32); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_fc32, out_fc32); - - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[0], out_fc32[0], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[1], out_fc32[1], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[2], out_fc32[2], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[3], out_fc32[3], tolerance); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_fc32(nsamps, io_type, otw_type); + } } -- cgit v1.2.3 From 738f4a86558aca8d2fdfecd480613766bfc82510 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 25 Aug 2010 21:15:17 -0700 Subject: uhd: switched the IQ order interpretation for convert types --- host/lib/transport/convert_types_impl.hpp | 66 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 37 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index 641029795..fdc859883 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -32,9 +32,6 @@ #include #endif -//! shortcut for a byteswap16 with casting -#define BSWAP16_C(num) uhd::byteswap(boost::uint16_t(num)) - /*********************************************************************** * Typedefs **********************************************************************/ @@ -54,10 +51,9 @@ static UHD_INLINE void sc16_to_item32_nswap( static UHD_INLINE void sc16_to_item32_bswap( const sc16_t *input, item32_t *output, size_t nsamps ){ + const item32_t *item32_input = (const item32_t *)input; for (size_t i = 0; i < nsamps; i++){ - boost::uint16_t real = BSWAP16_C(input[i].real()); - boost::uint16_t imag = BSWAP16_C(input[i].imag()); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = uhd::byteswap(item32_input[i]); } } @@ -73,10 +69,9 @@ static UHD_INLINE void item32_to_sc16_nswap( static UHD_INLINE void item32_to_sc16_bswap( const item32_t *input, sc16_t *output, size_t nsamps ){ + item32_t *item32_output = (item32_t *)output; for (size_t i = 0; i < nsamps; i++){ - boost::int16_t real = BSWAP16_C(input[i] >> 0); - boost::int16_t imag = BSWAP16_C(input[i] >> 16); - output[i] = sc16_t(real, imag); + item32_output[i] = uhd::byteswap(input[i]); } } @@ -85,7 +80,11 @@ static UHD_INLINE void item32_to_sc16_bswap( **********************************************************************/ static const float shorts_per_float = float(32767); -#define FC32_TO_SC16_C(num) boost::int16_t(num*shorts_per_float) +static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ + boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); + boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); + return (item32_t(real) << 16) | (item32_t(imag) << 0); +} //////////////////////////////////// // none-swap @@ -106,8 +105,10 @@ static UHD_INLINE void fc32_to_item32_nswap( __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - //pack + //pack + swap 16-bit pairs __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); + tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); + tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); //store to output _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); @@ -115,9 +116,7 @@ static UHD_INLINE void fc32_to_item32_nswap( //convert remainder for (; i < nsamps; i++){ - boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); - boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = fc32_to_item32(input[i]); } } @@ -126,9 +125,7 @@ static UHD_INLINE void fc32_to_item32_nswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); - boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = fc32_to_item32(input[i]); } } @@ -163,9 +160,7 @@ static UHD_INLINE void fc32_to_item32_bswap( //convert remainder for (; i < nsamps; i++){ - boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); - boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = uhd::byteswap(fc32_to_item32(input[i])); } } @@ -174,9 +169,7 @@ static UHD_INLINE void fc32_to_item32_bswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); - boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = uhd::byteswap(fc32_to_item32(input[i])); } } @@ -187,7 +180,12 @@ static UHD_INLINE void fc32_to_item32_bswap( **********************************************************************/ static const float floats_per_short = float(1.0/shorts_per_float); -#define I16_TO_FC32_C(num) (boost::int16_t(num)*floats_per_short) +static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ + return fc32_t( + float(boost::int16_t(item >> 16)*floats_per_short), + float(boost::int16_t(item >> 0)*floats_per_short) + ); +} //////////////////////////////////// // none-swap @@ -204,7 +202,9 @@ static UHD_INLINE void item32_to_fc32_nswap( //load from input __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); - //unpack + //unpack + swap 16-bit pairs + tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); + tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); @@ -219,9 +219,7 @@ static UHD_INLINE void item32_to_fc32_nswap( //convert remainder for (; i < nsamps; i++){ - float real = I16_TO_FC32_C(input[i] >> 0); - float imag = I16_TO_FC32_C(input[i] >> 16); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(input[i]); } } @@ -230,9 +228,7 @@ static UHD_INLINE void item32_to_fc32_nswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - float real = I16_TO_FC32_C(input[i] >> 0); - float imag = I16_TO_FC32_C(input[i] >> 16); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(input[i]); } } #endif @@ -268,9 +264,7 @@ static UHD_INLINE void item32_to_fc32_bswap( //convert remainder for (; i < nsamps; i++){ - float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); - float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(uhd::byteswap(input[i])); } } @@ -279,9 +273,7 @@ static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); - float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(uhd::byteswap(input[i])); } } -- cgit v1.2.3 From fe7df530e69834e974108d2c3e682f38b8a75524 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 12:21:50 -0700 Subject: usrp1: Modifiy USB transport implementations to use new interface Common libusb1 code is consolidated in the libusb base file. --- host/lib/transport/CMakeLists.txt | 2 + host/lib/transport/libusb1_base.cpp | 118 +++++++++++++++++++ host/lib/transport/libusb1_base.hpp | 42 +++++++ host/lib/transport/libusb1_control.cpp | 170 ++------------------------- host/lib/transport/libusb1_device_handle.cpp | 114 ++++++++++++++++++ host/lib/transport/libusb1_zero_copy.cpp | 153 +++--------------------- host/lib/usrp/usrp1/usrp1_impl.cpp | 37 +++--- 7 files changed, 322 insertions(+), 314 deletions(-) create mode 100644 host/lib/transport/libusb1_base.cpp create mode 100644 host/lib/transport/libusb1_base.hpp create mode 100644 host/lib/transport/libusb1_device_handle.cpp (limited to 'host/lib/transport') 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 . +// + +#include "libusb1_base.hpp" +#include + +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 . +// + +#ifndef INCLUDED_TRANSPORT_LIBUSB_HPP +#define INCLUDED_TRANSPORT_LIBUSB_HPP + +#include +#include +#include + +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 . // -#include +#include "libusb1_base.hpp" #include -#include -#include -#include -#include 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 . +// + +#include "libusb1_base.hpp" +#include + +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::get_device_list() +{ + libusb_context *ctx = NULL; + libusb_device **list; + std::vector 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 . // - +#include "libusb1_base.hpp" #include #include -#include #include #include #include @@ -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 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/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index ee6fe6e99..a4effb907 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -48,13 +48,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) if (hint.has_key("type") and hint["type"] != "usrp1") return usrp1_addrs; //see what we got on the USB bus - usb_descriptors_t usb_descriptors; - usb_descriptors = usb_control::get_device_list(); + std::vector 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(filename); } @@ -64,13 +66,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) sleep(1); //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); } } @@ -93,22 +97,23 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) std::cout << "Make usrp1 with " << filename << 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 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(filename); - 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 -- cgit v1.2.3 From 5e047eb5cb6f51b0c86ace7e5b4ea6c8089f0de9 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 19:00:05 -0700 Subject: usrp1: Only return a list of FSF devices --- host/lib/transport/libusb1_device_handle.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index f80090f15..5289f668f 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -88,6 +88,16 @@ usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) device_addr)); } +bool check_fsf_device(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + + return desc.idVendor == 0xfffe; +} std::vector usb_device_handle::get_device_list() { @@ -105,7 +115,8 @@ std::vector usb_device_handle::get_device_list() ssize_t i = 0; for (i = 0; i < cnt; i++) { libusb_device *dev = list[i]; - device_list.push_back(make_usb_device_handle(dev)); + if (check_fsf_device(dev)) + device_list.push_back(make_usb_device_handle(dev)); } libusb_free_device_list(list, 0); -- cgit v1.2.3 From b6099569e31705174920f44083f7f1bc22c445c7 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 13:27:32 -0700 Subject: usrp1: Cleanup libusb device handling This patch limits all libusb device enumeration operations to FSF (Vendor ID = 0xfffe) devices, which removes a lot of unncessary libusb output when debug mode is enabled. The reference counts held by the libusb device list are also reduced, which prevents holding references to unused devices. --- host/lib/transport/libusb1_base.cpp | 50 +++++++++++++++++++++++----- host/lib/transport/libusb1_base.hpp | 2 ++ host/lib/transport/libusb1_device_handle.cpp | 31 ++++------------- 3 files changed, 50 insertions(+), 33 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 6965de214..493d4eff3 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -16,10 +16,22 @@ // #include "libusb1_base.hpp" +#include #include using namespace uhd::transport; +bool check_fsf_device(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + + return desc.idVendor == 0xfffe; +} + void libusb::init(libusb_context **ctx, int debug_level) { if (libusb_init(ctx) < 0) @@ -28,27 +40,47 @@ void libusb::init(libusb_context **ctx, int debug_level) libusb_set_debug(*ctx, debug_level); } +std::vector libusb::get_fsf_device_list(libusb_context *ctx) +{ + libusb_device **libusb_dev_list; + std::vector fsf_dev_list; + + ssize_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list); + + //find the FSF devices + for (ssize_t i = 0; i < dev_cnt; i++) { + libusb_device *dev = libusb_dev_list[i]; + + if (check_fsf_device(dev)) + fsf_dev_list.push_back(dev); + else + libusb_unref_device(dev); + } + + libusb_free_device_list(libusb_dev_list, 0); + + return fsf_dev_list; +} libusb_device_handle *libusb::open_device(libusb_context *ctx, usb_device_handle::sptr handle) { - libusb_device **dev_list; - libusb_device_handle *dev_handle; + libusb_device_handle *dev_handle = NULL; + std::vector fsf_dev_list = get_fsf_device_list(ctx); - 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]; + //find and open the USB device + for (size_t i = 0; i < fsf_dev_list.size(); i++) { + libusb_device *dev = fsf_dev_list[i]; if (compare_device(dev, handle)) { libusb_open(dev, &dev_handle); + libusb_unref_device(dev); break; } + + libusb_unref_device(dev); } - libusb_free_device_list(dev_list, 0); - return dev_handle; } diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index ae560cd52..708a42c73 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -27,6 +27,8 @@ namespace uhd { namespace transport { namespace libusb { void init(libusb_context **ctx, int debug_level); + std::vector get_fsf_device_list(libusb_context *ctx); + libusb_device_handle *open_device(libusb_context *ctx, usb_device_handle::sptr handle); diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 5289f668f..4885099eb 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -88,38 +88,21 @@ usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) device_addr)); } -bool check_fsf_device(libusb_device *dev) -{ - libusb_device_descriptor desc; - - if (libusb_get_device_descriptor(dev, &desc) < 0) { - UHD_ASSERT_THROW("USB: failed to get device descriptor"); - } - - return desc.idVendor == 0xfffe; -} - std::vector usb_device_handle::get_device_list() { libusb_context *ctx = NULL; - libusb_device **list; - std::vector device_list; + std::vector libusb_device_list; + std::vector device_handle_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"); + libusb_device_list = libusb::get_fsf_device_list(ctx); - ssize_t i = 0; - for (i = 0; i < cnt; i++) { - libusb_device *dev = list[i]; - if (check_fsf_device(dev)) - device_list.push_back(make_usb_device_handle(dev)); + for (size_t i = 0; i < libusb_device_list.size(); i++) { + libusb_device *dev = libusb_device_list[i]; + device_handle_list.push_back(make_usb_device_handle(dev)); } - libusb_free_device_list(list, 0); libusb_exit(ctx); - return device_list; + return device_handle_list; } -- cgit v1.2.3 From 72fc20bc8ba4cb636a04de78210aac483f4ffaf3 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 13:46:22 -0700 Subject: usrp1: Disable default debug output for libusb implementations --- host/lib/transport/libusb1_control.cpp | 2 +- host/lib/transport/libusb1_device_handle.cpp | 2 +- host/lib/transport/libusb1_zero_copy.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 8bf271256..4b827c350 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -20,7 +20,7 @@ using namespace uhd::transport; -const int libusb_debug_level = 3; +const int libusb_debug_level = 0; const int libusb_timeout = 0; /*********************************************************************** diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 4885099eb..3476fdc4e 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -20,7 +20,7 @@ using namespace uhd::transport; -const int libusb_debug_level = 3; +const int libusb_debug_level = 0; class libusb1_device_handle_impl : public usb_device_handle { public: diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 55aa10cbb..2149625f9 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -25,7 +25,7 @@ using namespace uhd::transport; -const int libusb_debug_level = 3; +const int libusb_debug_level = 0; const int libusb_timeout = 0; /*********************************************************************** -- cgit v1.2.3 From 7f8c73faa22aaf2a381193d9f460857785e45023 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 15:59:05 -0700 Subject: usrp1: Handle degenerate managed send buffer cases Handle degenerate usage of send buffer commits. If the buffer is destroyed without ever being submitted, submit a zero byte transfer to return control to the underlying structure. If a committed buffer is re-committed, then report an error message and return 0 bytes back. --- host/lib/transport/libusb1_zero_copy.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 2149625f9..4469991b8 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -555,7 +555,7 @@ public: libusb_managed_send_buffer_impl(libusb_transfer *lut, usb_endpoint *endpoint, size_t buff_size) - : _buff(lut->buffer, buff_size) + : _buff(lut->buffer, buff_size), _committed(false) { _lut = lut; _endpoint = endpoint; @@ -563,18 +563,32 @@ public: ~libusb_managed_send_buffer_impl() { - /* NOP */ + if (!_committed) { + _lut->length = 0; + _lut->actual_length = 0; + _endpoint->submit(_lut); + } } ssize_t commit(size_t num_bytes) { + if (_committed) { + std::cerr << "UHD: send buffer already committed" << std::endl; + return 0; + } + + UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff)); + _lut->length = num_bytes; _lut->actual_length = 0; - if (_endpoint->submit(_lut)) + if (_endpoint->submit(_lut)) { + _committed = true; return num_bytes; - else + } + else { return 0; + } } private: @@ -586,6 +600,7 @@ private: libusb_transfer *_lut; usb_endpoint *_endpoint; const boost::asio::mutable_buffer _buff; + bool _committed; }; -- cgit v1.2.3 From 55da3154519639d84f4d008431461829646823bd Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 20:35:17 -0700 Subject: usrp1: Additional comments to libusb transport implementation --- host/lib/transport/libusb1_zero_copy.cpp | 183 ++++++++++++++++++------------- 1 file changed, 104 insertions(+), 79 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 4469991b8..edbeb5673 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -64,16 +64,12 @@ private: size_t _transfer_size; size_t _num_transfers; - /* - * Transfer state lists (free, pending, or completed) - */ + // Transfer state lists (transfers are free, pending, or completed) std::list _free_list; std::list _pending_list; std::list _completed_list; - /* - * Calls for processing asynchronous I/O - */ + // Calls for processing asynchronous I/O libusb_transfer *allocate_transfer(int buff_len); bool cancel(libusb_transfer *lut); bool cancel_all(); @@ -81,9 +77,7 @@ private: bool reap_pending_list_timeout(); bool reap_completed_list(); - /* - * Transfer state manipulators - */ + // Transfer state manipulators void free_list_add(libusb_transfer *lut); void pending_list_add(libusb_transfer *lut); void completed_list_add(libusb_transfer *lut); @@ -91,9 +85,7 @@ private: libusb_transfer *completed_list_get(); bool pending_list_remove(libusb_transfer *lut); - /* - * Misc - */ + // Debug use void print_transfer_status(libusb_transfer *lut); public: @@ -103,25 +95,18 @@ public: ~usb_endpoint(); - /* - * Accessors - */ + // Accessors int get_endpoint() const { return _endpoint; } bool get_direction() const { return _input; } libusb_device_handle *get_dev_handle() const { return _dev_handle; } libusb_context *get_ctx() const { return _ctx; } - /* - * Exposed interface for submitting / retrieving transfer buffers - * used in zero-copy interface - */ + // Exposed interface for submitting / retrieving transfer buffers bool submit(libusb_transfer *lut); libusb_transfer *get_completed_transfer(); libusb_transfer *get_free_transfer(); - /* - * Callback use only - */ + //Callback use only void callback_handle_transfer(libusb_transfer *lut); }; @@ -130,6 +115,10 @@ public: * Callback function called when submitted transfers complete. * The endpoint upon which the transfer is part of is recovered * and the transfer moved from pending to completed state. + * Callbacks occur during the reaping calls where libusb_handle_events() + * is used. The callback only modifies the transfer state by moving + * it from the pending to completed status list. + * \param lut pointer to libusb_transfer */ static void callback(libusb_transfer *lut) { @@ -140,6 +129,7 @@ static void callback(libusb_transfer *lut) /* * Accessor call to allow list access from callback space + * \param pointer to libusb_transfer */ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) { @@ -154,9 +144,9 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) /* * Constructor - * - * Allocate libusb transfers. For IN endpoints, submit the transfers - * so that they're ready to return when data is available. + * Allocate libusb transfers and mark as free. For IN endpoints, + * submit the transfers so that they're ready to return when + * data is available. */ usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, libusb_context *ctx, int endpoint, bool input, @@ -177,6 +167,10 @@ usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, /* * Destructor + * Make sure all the memory is freed. Cancel any pending transfers. + * When all completed transfers are moved to the free list, release + * the transfers. Libusb will deallocate the data buffer held by + * each transfer. */ usb_endpoint::~usb_endpoint() { @@ -200,9 +194,10 @@ usb_endpoint::~usb_endpoint() /* * Allocate a libusb transfer - * - * The allocated transfer is continuously reused and should be freed at - * shutdown. + * The allocated transfer - and buffer it contains - is repeatedly + * submitted, reaped, and reused and should not be freed until shutdown. + * \param buff_len size of the individual buffer held by each transfer + * \return pointer to an allocated libusb_transfer */ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) { @@ -226,8 +221,9 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) /* * Asynchonous transfer submission - * - * Submit and mark transfer as pending. + * Submit a libusb transfer to libusb add pending status + * \param lut pointer to libusb_transfer + * \return true on success or false on error */ bool usb_endpoint::submit(libusb_transfer *lut) { @@ -244,9 +240,9 @@ bool usb_endpoint::submit(libusb_transfer *lut) /* * Cancel a pending transfer - * * Search the pending list for the transfer and cancel if found. - * Returns true on success. False otherwise or on error. + * \param lut pointer to libusb_transfer to cancel + * \return true on success or false if transfer is not found * * Note: success only indicates submission of cancelation request. * Sucessful cancelation is not known until the callback occurs. @@ -266,6 +262,7 @@ bool usb_endpoint::cancel(libusb_transfer *lut) /* * Cancel all pending transfers + * \return bool true if cancelation request is submitted * * Note: success only indicates submission of cancelation request. * Sucessful cancelation is not known until the callback occurs. @@ -287,11 +284,10 @@ bool usb_endpoint::cancel_all() /* * Reap completed transfers - * * return true if at least one transfer was reaped, false otherwise. - * * Check completed transfers for errors and mark as free. This is a * blocking call. + * \return bool true if a libusb transfer is reaped, false otherwise */ bool usb_endpoint::reap_completed_list() { @@ -313,12 +309,8 @@ bool usb_endpoint::reap_completed_list() /* - * Print completed transfer status error(s) - * - * return true if at least one transfer was reaped, false otherwise. - * - * Check completed transfers for errors and mark as free. This is a - * blocking call. + * Print status errors of a completed transfer + * \param lut pointer to an libusb_transfer */ void usb_endpoint::print_transfer_status(libusb_transfer *lut) { @@ -359,13 +351,11 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut) /* - * Reap pending transfers - * - * Return true if at least one transfer was reaped, false otherwise. This is - * a blocking call. - * - * Reaping submitted transfers is handled by libusb and the assigned callback - * function. Block until at least one transfer is reaped. + * Reap pending transfers without timeout + * This is a blocking call. Reaping submitted transfers is + * handled by libusb and the assigned callback function. + * Block until at least one transfer is reaped. + * \return true true if a transfer was reaped or false otherwise */ bool usb_endpoint::reap_pending_list() { @@ -382,12 +372,11 @@ bool usb_endpoint::reap_pending_list() /* * Reap pending transfers with timeout - * - * Return true if at least one transfer was reaped, false otherwise. This call - * blocks until a transfer is reaped or timeout. - * - * Reaping submitted transfers is handled by libusb and the assigned callback - * function. Block until at least one transfer is reaped or timeout occurs. + * This call blocks until a transfer is reaped or timeout. + * Reaping submitted transfers is handled by libusb and the + * assigned callback function. Block until at least one + * transfer is reaped or timeout occurs. + * \return true if a transfer was reaped or false otherwise */ bool usb_endpoint::reap_pending_list_timeout() { @@ -414,7 +403,9 @@ bool usb_endpoint::reap_pending_list_timeout() /* - * Returns a free transfer with empty data bufer for OUT requests + * Get a free transfer + * The transfer has an empty data bufer for OUT requests + * \return pointer to a libusb_transfer */ libusb_transfer *usb_endpoint::get_free_transfer() { @@ -428,7 +419,9 @@ libusb_transfer *usb_endpoint::get_free_transfer() /* - * Returns a transfer containing data for IN requests + * Get a completed transfer + * The transfer has a full data buffer for IN requests + * \return pointer to libusb_transfer */ libusb_transfer *usb_endpoint::get_completed_transfer() { @@ -461,7 +454,6 @@ void usb_endpoint::completed_list_add(libusb_transfer *lut) /* * Free and completed lists don't have ordered content - * * Pop transfers from the front as needed */ libusb_transfer *usb_endpoint::free_list_get() @@ -481,7 +473,6 @@ libusb_transfer *usb_endpoint::free_list_get() /* * Free and completed lists don't have ordered content - * * Pop transfers from the front as needed */ libusb_transfer *usb_endpoint::completed_list_get() @@ -501,7 +492,6 @@ libusb_transfer *usb_endpoint::completed_list_get() /* * Search and remove transfer from pending list - * * Assuming that the callbacks occur in order, the front element * should yield the correct transfer. If not, then something else * is going on. If no transfers match, then something went wrong. @@ -522,6 +512,13 @@ bool usb_endpoint::pending_list_remove(libusb_transfer *lut) /*********************************************************************** * Managed buffers **********************************************************************/ +/* + * Libusb managed receive buffer + * Construct a recv buffer from a libusb transfer. The memory held by + * the libusb transfer is exposed through the managed buffer interface. + * Upon destruction, the transfer and buffer are resubmitted to the + * endpoint for further use. + */ class libusb_managed_recv_buffer_impl : public managed_recv_buffer { public: libusb_managed_recv_buffer_impl(libusb_transfer *lut, @@ -549,7 +546,15 @@ private: const boost::asio::const_buffer _buff; }; - +/* + * Libusb managed send buffer + * Construct a send buffer from a libusb transfer. The memory held by + * the libusb transfer is exposed through the managed buffer interface. + * Committing the buffer will set the data length and submit the buffer + * to the endpoint. Submitting a buffer multiple times or destroying + * the buffer before committing is an error. For the latter, the transfer + * is returned to the endpoint with no data for reuse. + */ class libusb_managed_send_buffer_impl : public managed_send_buffer { public: libusb_managed_send_buffer_impl(libusb_transfer *lut, @@ -613,9 +618,7 @@ private: usb_endpoint *_rx_ep; usb_endpoint *_tx_ep; - /* - * Libusb handles - */ + // Maintain libusb values libusb_context *_rx_ctx; libusb_context *_tx_ctx; libusb_device_handle *_rx_dev_handle; @@ -628,9 +631,6 @@ private: public: typedef boost::shared_ptr sptr; - /* - * Structors - */ libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, @@ -646,7 +646,11 @@ public: size_t get_num_send_frames(void) const { return _num_frames; } }; - +/* + * Constructor + * Initializes libusb, opens devices, and sets up interfaces for I/O. + * Finally, creates endpoints for asynchronous I/O. + */ libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, @@ -656,30 +660,39 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, _recv_buff_size(block_size), _send_buff_size(block_size), _num_frames(buff_size / block_size) { + // Initialize libusb with separate contexts to allow + // thread safe operation of transmit and receive libusb::init(&_rx_ctx, libusb_debug_level); libusb::init(&_tx_ctx, libusb_debug_level); UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL)); + // Find and open the libusb_device corresponding to the + // given handle and return the libusb_device_handle + // that can be used for I/O purposes. _rx_dev_handle = libusb::open_device(_rx_ctx, handle); _tx_dev_handle = libusb::open_device(_tx_ctx, handle); + // Open USB interfaces for tx/rx using magic values. + // IN interface: 2 + // OUT interface: 1 + // Control interface: 0 libusb::open_interface(_rx_dev_handle, 2); libusb::open_interface(_tx_dev_handle, 1); - _rx_ep = new usb_endpoint(_rx_dev_handle, - _rx_ctx, - rx_endpoint, - true, - _recv_buff_size, - _num_frames); - - _tx_ep = new usb_endpoint(_tx_dev_handle, - _tx_ctx, - tx_endpoint, - false, - _send_buff_size, - _num_frames); + _rx_ep = new usb_endpoint(_rx_dev_handle, // libusb device_handle + _rx_ctx, // libusb context + rx_endpoint, // USB endpoint number + true, // IN endpoint + _recv_buff_size, // buffer size per transfer + _num_frames); // number of libusb transfers + + _tx_ep = new usb_endpoint(_tx_dev_handle, // libusb device_handle + _tx_ctx, // libusb context + tx_endpoint, // USB endpoint number + false, // OUT endpoint + _send_buff_size, // buffer size per transfer + _num_frames); // number of libusb transfers } @@ -696,6 +709,12 @@ libusb_zero_copy_impl::~libusb_zero_copy_impl() } +/* + * Construct a managed receive buffer from a completed libusb transfer + * (happy with buffer full of data) obtained from the receive endpoint. + * Return empty pointer if no transfer is available (timeout or error). + * \return pointer to a managed receive buffer + */ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() { libusb_transfer *lut = _rx_ep->get_completed_transfer(); @@ -710,6 +729,12 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() } +/* + * Construct a managed send buffer from a free libusb transfer (with + * empty buffer). Return empty pointer of no transfer is available + * (timeout or error). + * \return pointer to a managed send buffer + */ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() { libusb_transfer *lut = _tx_ep->get_free_transfer(); -- cgit v1.2.3 From 76365acdbb22c5a4c6c2d9b6fbcc015ace6df09a Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 20:39:26 -0700 Subject: usrp1: Remove unused funtions libusb transport --- host/lib/transport/libusb1_zero_copy.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index edbeb5673..518b8baf0 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -95,12 +95,6 @@ public: ~usb_endpoint(); - // Accessors - int get_endpoint() const { return _endpoint; } - bool get_direction() const { return _input; } - libusb_device_handle *get_dev_handle() const { return _dev_handle; } - libusb_context *get_ctx() const { return _ctx; } - // Exposed interface for submitting / retrieving transfer buffers bool submit(libusb_transfer *lut); libusb_transfer *get_completed_transfer(); -- cgit v1.2.3 From ad55e25aeb273fb7278c6d5175cd0df01fc90924 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 23:46:16 -0700 Subject: usrp1: Additional comments on libusb transport implemenation --- host/lib/transport/libusb1_base.cpp | 12 ++++++ host/lib/transport/libusb1_base.hpp | 60 ++++++++++++++++++++++++++++ host/lib/transport/libusb1_control.cpp | 7 ++++ host/lib/transport/libusb1_device_handle.cpp | 3 ++ host/lib/transport/libusb1_zero_copy.cpp | 8 ++-- 5 files changed, 87 insertions(+), 3 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 493d4eff3..92dcd969f 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -21,6 +21,15 @@ using namespace uhd::transport; +/********************************************************** + * Helper Methods + **********************************************************/ +/* + * Check for FSF device + * Compare the device's descriptor Vendor ID + * \param dev pointer to libusb_device + * \return true if Vendor ID matches 0xfffe + */ bool check_fsf_device(libusb_device *dev) { libusb_device_descriptor desc; @@ -32,6 +41,9 @@ bool check_fsf_device(libusb_device *dev) return desc.idVendor == 0xfffe; } +/********************************************************** + * libusb namespace + **********************************************************/ void libusb::init(libusb_context **ctx, int debug_level) { if (libusb_init(ctx) < 0) diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index 708a42c73..442f89ded 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -25,17 +25,77 @@ namespace uhd { namespace transport { namespace libusb { + /* + * Initialize libusb and set debug level + * Takes a pointer to context pointer because that's + * how libusb rolls. Debug levels. + * + * Level 0: no messages ever printed by the library (default) + * Level 1: error messages are printed to stderr + * Level 2: warning and error messages are printed to stderr + * Level 3: informational messages are printed to stdout, warning + * and error messages are printed to stderr + * + * \param ctx pointer to context pointer + * \param debug_level + */ void init(libusb_context **ctx, int debug_level); + /* + * Get a list of Free Software Foundation devices (Vendor ID 0xfffe) + * As opposed to the public USB device handle interface, which returns + * generic identifiers, this call returns device pointers speficic + * to libusb. + * \param ctx the libusb context used for init + * \return a vector of libusb devices + */ std::vector get_fsf_device_list(libusb_context *ctx); + /* + * Open the device specified by a generic handle + * Find the libusb_device cooresponding to the generic handle + * and open it for I/O, which returns a libusb_device_handle + * ready for an interface + * \param ctx the libusb context used for init + * \return a libusb_device_handle ready for action + */ libusb_device_handle *open_device(libusb_context *ctx, usb_device_handle::sptr handle); + /* + * Compare a libusb device with a generic handle + * Check the descriptors and open the device to check the + * serial number string. Compare values against the given + * handle. The libusb context is already implied in the + * libusb_device. + * \param dev a libusb_device pointer + * \param handle a generic handle specifier + * \return true if handle and device match, false otherwise + */ bool compare_device(libusb_device *dev, usb_device_handle::sptr handle); + /* + * Open an interface to the device + * This is a logical operation for operating system housekeeping as + * nothing is sent over the bus. The interface much correspond + * to the USB device descriptors. + * \param dev_handle libusb handle to an opened device + * \param interface integer of the interface to use + * \return true on success, false on error + */ bool open_interface(libusb_device_handle *dev_handle, int interface); + /* + * Get serial number + * The standard USB device descriptor contains an index to an + * actual serial number string descriptor. The index is readily + * readble, but the string descriptor requires probing the device. + * Because this call attempts to open the device, it may not + * succeed because not all USB devices are readily opened. + * The default language is used for the request (English). + * \param dev a libusb_device pointer + * \return string serial number or 0 on error or unavailablity + */ std::string get_serial(libusb_device *dev); } diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 4b827c350..3531128b2 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -48,8 +48,15 @@ libusb_control_impl::libusb_control_impl(usb_device_handle::sptr handle) { libusb::init(&_ctx, libusb_debug_level); + // Find and open the libusb_device corresponding to the + // given handle and return the libusb_device_handle + // that can be used for I/O purposes. _dev_handle = libusb::open_device(_ctx, handle); + // Open USB interfaces for control using magic value + // IN interface: 2 + // OUT interface: 1 + // Control interface: 0 libusb::open_interface(_dev_handle, 0); } diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 3476fdc4e..5d9d8faf0 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -22,6 +22,9 @@ using namespace uhd::transport; const int libusb_debug_level = 0; +/**************************************************************** + * libusb USB device handle implementation class + ***************************************************************/ class libusb1_device_handle_impl : public usb_device_handle { public: libusb1_device_handle_impl(std::string serial, diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 518b8baf0..b890a87f9 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -30,9 +30,11 @@ const int libusb_timeout = 0; /*********************************************************************** * Helper functions - * - * Print to stdout the values of a libusb_transfer struct ***********************************************************************/ +/* + * Print the values of a libusb_transfer struct + * http://libusb.sourceforge.net/api-1.0/structlibusb__transfer.html + */ void pp_transfer(libusb_transfer *lut) { std::cout << "Libusb transfer" << std::endl; @@ -46,7 +48,7 @@ void pp_transfer(libusb_transfer *lut) } /*********************************************************************** - * USB asynchronous phony zero_copy endpoint + * USB asynchronous zero_copy endpoint * This endpoint implementation provides asynchronous I/O to libusb-1.0 * devices. Each endpoint is directional and two can be combined to * create a bidirectional interface. It is a zero copy implementation -- cgit v1.2.3 From 79ea83d6b352a7865ff6143ba77fcc0956c6452f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 12:33:13 -0700 Subject: uhd: fixed short conversion (IQ swap) and added test between short/float --- host/lib/transport/convert_types_impl.hpp | 27 +++++++--- host/lib/transport/gen_convert_types.py | 2 +- host/test/convert_types_test.cpp | 84 ++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 8 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index fdc859883..90618dec6 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -42,36 +42,51 @@ typedef boost::uint32_t item32_t; /*********************************************************************** * Convert complex short buffer to items32 **********************************************************************/ +static UHD_INLINE item32_t sc16_to_item32(sc16_t num){ + boost::uint16_t real = num.real(); + boost::uint16_t imag = num.imag(); + return (item32_t(real) << 16) | (item32_t(imag) << 0); +} + static UHD_INLINE void sc16_to_item32_nswap( const sc16_t *input, item32_t *output, size_t nsamps ){ - std::memcpy(output, input, nsamps*sizeof(item32_t)); + for (size_t i = 0; i < nsamps; i++){ + output[i] = sc16_to_item32(input[i]); + } } static UHD_INLINE void sc16_to_item32_bswap( const sc16_t *input, item32_t *output, size_t nsamps ){ - const item32_t *item32_input = (const item32_t *)input; for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(item32_input[i]); + output[i] = uhd::byteswap(sc16_to_item32(input[i])); } } /*********************************************************************** * Convert items32 buffer to complex short **********************************************************************/ +static UHD_INLINE sc16_t item32_to_sc16(item32_t item){ + return sc16_t( + boost::int16_t(item >> 16), + boost::int16_t(item >> 0) + ); +} + static UHD_INLINE void item32_to_sc16_nswap( const item32_t *input, sc16_t *output, size_t nsamps ){ - std::memcpy(output, input, nsamps*sizeof(item32_t)); + for (size_t i = 0; i < nsamps; i++){ + output[i] = item32_to_sc16(input[i]); + } } static UHD_INLINE void item32_to_sc16_bswap( const item32_t *input, sc16_t *output, size_t nsamps ){ - item32_t *item32_output = (item32_t *)output; for (size_t i = 0; i < nsamps; i++){ - item32_output[i] = uhd::byteswap(input[i]); + output[i] = item32_to_sc16(uhd::byteswap(input[i])); } } diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index 951b634d9..17d8ffde0 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -95,7 +95,7 @@ void transport::convert_otw_type_to_io_type( size_t num_samps ){ switch(get_pred(io_type, otw_type)){ - #for $pred in range(4) + #for $pred in range(2**$ph.nbits) case $pred: #set $out_type = $ph.get_host_type($pred) #set $in_type = $ph.get_dev_type($pred) diff --git a/host/test/convert_types_test.cpp b/host/test/convert_types_test.cpp index d132a708b..2148302b6 100644 --- a/host/test/convert_types_test.cpp +++ b/host/test/convert_types_test.cpp @@ -27,7 +27,7 @@ using namespace uhd; //typedefs for complex types -typedef std::complex sc16_t; +typedef std::complex sc16_t; typedef std::complex fc32_t; //extract pointer to POD since using &vector.front() throws in MSVC @@ -158,3 +158,85 @@ BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32){ test_convert_types_fc32(nsamps, io_type, otw_type); } } + +/*********************************************************************** + * Test float to short conversion loopback + **********************************************************************/ +BOOST_AUTO_TEST_CASE(test_convert_types_fc32_to_sc16){ + io_type_t io_type_in(io_type_t::COMPLEX_FLOAT32); + io_type_t io_type_out(io_type_t::COMPLEX_INT16); + + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_NATIVE; + otw_type.width = 16; + + const size_t nsamps = 13; + std::vector input(nsamps); + BOOST_FOREACH(fc32_t &in, input) in = fc32_t( + (std::rand()/float(RAND_MAX/2)) - 1, + (std::rand()/float(RAND_MAX/2)) - 1 + ); + + //convert float to dev + std::vector tmp(nsamps); + transport::convert_io_type_to_otw_type( + pod2ptr(input), io_type_in, + pod2ptr(tmp), otw_type, + nsamps + ); + + //convert dev to short + std::vector output(nsamps); + transport::convert_otw_type_to_io_type( + pod2ptr(tmp), otw_type, + pod2ptr(output), io_type_out, + nsamps + ); + + //test that the inputs and outputs match + for (size_t i = 0; i < nsamps; i++){ + BOOST_CHECK_CLOSE_FRACTION(input[i].real(), output[i].real()/float(32767), float(0.01)); + BOOST_CHECK_CLOSE_FRACTION(input[i].imag(), output[i].imag()/float(32767), float(0.01)); + } +} + +/*********************************************************************** + * Test short to float conversion loopback + **********************************************************************/ +BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32){ + io_type_t io_type_in(io_type_t::COMPLEX_INT16); + io_type_t io_type_out(io_type_t::COMPLEX_FLOAT32); + + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_NATIVE; + otw_type.width = 16; + + const size_t nsamps = 13; + std::vector input(nsamps); + BOOST_FOREACH(sc16_t &in, input) in = sc16_t( + std::rand()-(RAND_MAX/2), + std::rand()-(RAND_MAX/2) + ); + + //convert short to dev + std::vector tmp(nsamps); + transport::convert_io_type_to_otw_type( + pod2ptr(input), io_type_in, + pod2ptr(tmp), otw_type, + nsamps + ); + + //convert dev to float + std::vector output(nsamps); + transport::convert_otw_type_to_io_type( + pod2ptr(tmp), otw_type, + pod2ptr(output), io_type_out, + nsamps + ); + + //test that the inputs and outputs match + for (size_t i = 0; i < nsamps; i++){ + BOOST_CHECK_CLOSE_FRACTION(input[i].real()/float(32767), output[i].real(), float(0.01)); + BOOST_CHECK_CLOSE_FRACTION(input[i].imag()/float(32767), output[i].imag(), float(0.01)); + } +} -- cgit v1.2.3 From 99494305b35adf5c4f89b4888192c723f32d9da2 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 16:00:35 -0700 Subject: uhd: added interleave/de-interleave type conversion routines --- host/include/uhd/transport/CMakeLists.txt | 1 + host/include/uhd/transport/convert_types.hpp | 37 ++++++++++ host/include/uhd/transport/convert_types.ipp | 43 +++++++++++ host/lib/transport/gen_convert_types.py | 105 ++++++++++++++++++++++----- 4 files changed, 166 insertions(+), 20 deletions(-) create mode 100644 host/include/uhd/transport/convert_types.ipp (limited to 'host/lib/transport') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 93e9a6485..01856454f 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -22,6 +22,7 @@ INSTALL(FILES bounded_buffer.hpp bounded_buffer.ipp convert_types.hpp + convert_types.ipp if_addrs.hpp udp_simple.hpp udp_zero_copy.hpp diff --git a/host/include/uhd/transport/convert_types.hpp b/host/include/uhd/transport/convert_types.hpp index a4d999240..dc7fa6c1a 100644 --- a/host/include/uhd/transport/convert_types.hpp +++ b/host/include/uhd/transport/convert_types.hpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace uhd{ namespace transport{ @@ -39,6 +40,23 @@ UHD_API void convert_io_type_to_otw_type( size_t num_samps ); +/*! + * Convert IO samples to OWT samples + interleave. + * + * \param io_buffs buffers containing samples + * \param io_type the type of these samples + * \param otw_buff memory to write converted samples + * \param otw_type the type of these samples + * \param nsamps_per_io_buff samples per io_buff + */ +UHD_API void convert_io_type_to_otw_type( + const std::vector &io_buffs, + const io_type_t &io_type, + void *otw_buff, + const otw_type_t &otw_type, + size_t nsamps_per_io_buff +); + /*! * Convert OTW samples to IO samples. * @@ -54,6 +72,25 @@ UHD_API void convert_otw_type_to_io_type( size_t num_samps ); +/*! + * Convert OTW samples to IO samples + de-interleave. + * + * \param otw_buff memory containing samples + * \param otw_type the type of these samples + * \param io_buffs buffers to write converted samples + * \param io_type the type of these samples + * \param nsamps_per_io_buff samples per io_buff + */ +UHD_API void convert_otw_type_to_io_type( + const void *otw_buff, + const otw_type_t &otw_type, + std::vector &io_buffs, + const io_type_t &io_type, + size_t nsamps_per_io_buff +); + }} //namespace +#include + #endif /* INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP */ diff --git a/host/include/uhd/transport/convert_types.ipp b/host/include/uhd/transport/convert_types.ipp new file mode 100644 index 000000000..914ca6f17 --- /dev/null +++ b/host/include/uhd/transport/convert_types.ipp @@ -0,0 +1,43 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_IPP +#define INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_IPP + +UHD_INLINE void uhd::transport::convert_io_type_to_otw_type( + const void *io_buff, const io_type_t &io_type, + void *otw_buff, const otw_type_t &otw_type, + size_t num_samps +){ + std::vector buffs(1, io_buff); + return uhd::transport::convert_io_type_to_otw_type( + buffs, io_type, otw_buff, otw_type, num_samps + ); +} + +UHD_INLINE void uhd::transport::convert_otw_type_to_io_type( + const void *otw_buff, const otw_type_t &otw_type, + void *io_buff, const io_type_t &io_type, + size_t num_samps +){ + std::vector buffs(1, io_buff); + return uhd::transport::convert_otw_type_to_io_type( + otw_buff, otw_type, buffs, io_type, num_samps + ); +} + +#endif /* INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_IPP */ diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index 17d8ffde0..adbd22868 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -36,7 +36,8 @@ using namespace uhd; **********************************************************************/ UHD_INLINE boost::uint8_t get_pred( const io_type_t &io_type, - const otw_type_t &otw_type + const otw_type_t &otw_type, + size_t num_chans ){ boost::uint8_t pred = 0; @@ -63,6 +64,14 @@ UHD_INLINE boost::uint8_t get_pred( default: throw std::runtime_error("unhandled io type id"); } + switch(num_chans){ + case 1: pred |= $ph.chan1_p; break; + case 2: pred |= $ph.chan2_p; break; + case 3: pred |= $ph.chan3_p; break; + case 4: pred |= $ph.chan4_p; break; + default: throw std::runtime_error("unhandled number of channels"); + } + return pred; } @@ -70,17 +79,37 @@ UHD_INLINE boost::uint8_t get_pred( * Convert host type to device type **********************************************************************/ void transport::convert_io_type_to_otw_type( - const void *io_buff, const io_type_t &io_type, - void *otw_buff, const otw_type_t &otw_type, - size_t num_samps + const std::vector &io_buffs, + const io_type_t &io_type, + void *otw_buff, + const otw_type_t &otw_type, + size_t nsamps_per_io_buff ){ - switch(get_pred(io_type, otw_type)){ + switch(get_pred(io_type, otw_type, io_buffs.size())){ #for $pred in range(2**$ph.nbits) case $pred: #set $out_type = $ph.get_dev_type($pred) #set $in_type = $ph.get_host_type($pred) - #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)]) - $(converter)((const $(in_type)_t *)io_buff, ($(out_type)_t *)otw_buff, num_samps); + #set $num_chans = $ph.get_num_chans($pred) + #set $converter = '_'.join([$in_type, 'to', $out_type]) + #if $num_chans == 1 + $(converter)_$ph.get_swap_type($pred)( + reinterpret_cast(io_buffs.front()), + reinterpret_cast<$(out_type)_t *>(otw_buff), + nsamps_per_io_buff + ); + #else + for (size_t i = 0; i < nsamps_per_io_buff; i++){ + #for $j in range($num_chans) + reinterpret_cast<$(out_type)_t *>(otw_buff)[i*$num_chans + $j] = + #if $ph.get_swap_type($pred) == 'bswap' + uhd::byteswap($(converter)(reinterpret_cast(io_buffs[$j])[i])); + #else + $(converter)(reinterpret_cast(io_buffs[$j])[i]); + #end if + #end for + } + #end if break; #end for } @@ -90,17 +119,37 @@ void transport::convert_io_type_to_otw_type( * Convert device type to host type **********************************************************************/ void transport::convert_otw_type_to_io_type( - const void *otw_buff, const otw_type_t &otw_type, - void *io_buff, const io_type_t &io_type, - size_t num_samps + const void *otw_buff, + const otw_type_t &otw_type, + std::vector &io_buffs, + const io_type_t &io_type, + size_t nsamps_per_io_buff ){ - switch(get_pred(io_type, otw_type)){ + switch(get_pred(io_type, otw_type, io_buffs.size())){ #for $pred in range(2**$ph.nbits) case $pred: #set $out_type = $ph.get_host_type($pred) #set $in_type = $ph.get_dev_type($pred) - #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)]) - $(converter)((const $(in_type)_t *)otw_buff, ($(out_type)_t *)io_buff, num_samps); + #set $num_chans = $ph.get_num_chans($pred) + #set $converter = '_'.join([$in_type, 'to', $out_type]) + #if $num_chans == 1 + $(converter)_$ph.get_swap_type($pred)( + reinterpret_cast(otw_buff), + reinterpret_cast<$(out_type)_t *>(io_buffs.front()), + nsamps_per_io_buff + ); + #else + for (size_t i = 0; i < nsamps_per_io_buff; i++){ + #for $j in range($num_chans) + reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] = + #if $ph.get_swap_type($pred) == 'bswap' + $(converter)(uhd::byteswap(reinterpret_cast(otw_buff)[i*$num_chans + $j])); + #else + $(converter)(reinterpret_cast(otw_buff)[i*$num_chans + $j]); + #end if + #end for + } + #end if break; #end for } @@ -118,27 +167,43 @@ class ph: item32_p = 0b00000 sc16_p = 0b00010 fc32_p = 0b00000 + chan1_p = 0b00000 + chan2_p = 0b00100 + chan3_p = 0b01000 + chan4_p = 0b01100 - nbits = 2 #see above + nbits = 4 #see above @staticmethod - def has(pred, flag): return (pred & flag) == flag + def has(pred, mask, flag): return (pred & mask) == flag @staticmethod def get_swap_type(pred): - if ph.has(pred, ph.bswap_p): return 'bswap' - if ph.has(pred, ph.nswap_p): return 'nswap' + mask = 0b1 + if ph.has(pred, mask, ph.bswap_p): return 'bswap' + if ph.has(pred, mask, ph.nswap_p): return 'nswap' raise NotImplementedError @staticmethod def get_dev_type(pred): - if ph.has(pred, ph.item32_p): return 'item32' + mask = 0b0 + if ph.has(pred, mask, ph.item32_p): return 'item32' raise NotImplementedError @staticmethod def get_host_type(pred): - if ph.has(pred, ph.sc16_p): return 'sc16' - if ph.has(pred, ph.fc32_p): return 'fc32' + mask = 0b10 + if ph.has(pred, mask, ph.sc16_p): return 'sc16' + if ph.has(pred, mask, ph.fc32_p): return 'fc32' + raise NotImplementedError + + @staticmethod + def get_num_chans(pred): + mask = 0b1100 + if ph.has(pred, mask, ph.chan1_p): return 1 + if ph.has(pred, mask, ph.chan2_p): return 2 + if ph.has(pred, mask, ph.chan3_p): return 3 + if ph.has(pred, mask, ph.chan4_p): return 4 raise NotImplementedError if __name__ == '__main__': -- cgit v1.2.3 From b96088b692a5c44974919ee36e253b6ea8c51972 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 31 Aug 2010 16:44:30 -0700 Subject: EEPROM burning in UHD. Changed some USB device handle stuff. Added usrp_init_eeprom.cpp. Hacked up the firmware makefile to behave and to generate .bin EEPROM images instead of IHX. --- firmware/fx2/src/common/build_eeprom.py | 103 +++-------------------- firmware/fx2/src/usrp1/Makefile.am | 58 +++---------- host/include/uhd/transport/usb_device_handle.hpp | 4 +- host/lib/transport/libusb1_base.cpp | 52 ++---------- host/lib/transport/libusb1_base.hpp | 10 --- host/lib/transport/libusb1_device_handle.cpp | 18 ++-- host/lib/usrp/usrp1/mboard_impl.cpp | 11 +++ host/lib/usrp/usrp1/usrp1_ctrl.cpp | 63 +++++++++++++- host/lib/usrp/usrp1/usrp1_ctrl.hpp | 31 +++++++ host/lib/usrp/usrp1/usrp1_iface.cpp | 21 +++-- host/lib/usrp/usrp1/usrp1_impl.cpp | 34 ++++---- host/utils/CMakeLists.txt | 4 + host/utils/usrp_init_eeprom.cpp | 69 +++++++++++++++ 13 files changed, 255 insertions(+), 223 deletions(-) create mode 100644 host/utils/usrp_init_eeprom.cpp (limited to 'host/lib/transport') diff --git a/firmware/fx2/src/common/build_eeprom.py b/firmware/fx2/src/common/build_eeprom.py index 023c4b3f5..ae62587db 100755 --- a/firmware/fx2/src/common/build_eeprom.py +++ b/firmware/fx2/src/common/build_eeprom.py @@ -29,15 +29,6 @@ from optparse import OptionParser VID = 0xfffe # Free Software Folks PID = 0x0002 # Universal Software Radio Peripheral - - -def hex_to_bytes (s): - if len (s) & 0x1: - raise ValueError, "Length must be even" - r = [] - for i in range (0, len(s), 2): - r.append (int (s[i:i+2], 16)) - return r def msb (x): return (x >> 8) & 0xff @@ -45,56 +36,6 @@ def msb (x): def lsb (x): return x & 0xff -class ihx_rec (object): - def __init__ (self, addr, type, data): - self.addr = addr - self.type = type - self.data = data - -class ihx_file (object): - def __init__ (self): - self.pat = re.compile (r':[0-9A-F]{10,}') - def read (self, file): - r = [] - for line in file: - line = line.strip().upper () - if not self.pat.match (line): - raise ValueError, "Invalid hex record format" - bytes = hex_to_bytes (line[1:]) - sum = reduce (lambda x, y: x + y, bytes, 0) % 256 - if sum != 0: - raise ValueError, "Bad hex checksum" - lenx = bytes[0] - addr = (bytes[1] << 8) + bytes[2] - type = bytes[3] - data = bytes[4:-1] - if lenx != len (data): - raise ValueError, "Invalid hex record (bad length)" - if type != 0: - break; - r.append (ihx_rec (addr, type, data)) - - return r - -def get_code (filename): - """Read the intel hex format file FILENAME and return a tuple - of the code starting address and a list of bytes to load there. - """ - f = open (filename, 'r') - ifx = ihx_file () - r = ifx.read (f) - r.sort (lambda a,b: a.addr - b.addr) - code_start = r[0].addr - code_end = r[-1].addr + len (r[-1].data) - code_len = code_end - code_start - code = [0] * code_len - for x in r: - a = x.addr - l = len (x.data) - code[a-code_start:a-code_start+l] = x.data - return (code_start, code) - - def build_eeprom_image (filename, rev): """Build a ``C2 Load'' EEPROM image. @@ -102,9 +43,11 @@ def build_eeprom_image (filename, rev): the EZ-USB FX2 Technical Reference Manual """ # get the code we want to run - (start_addr, bytes) = get_code (filename) + f = open(filename, 'rb') + bytes = f.read() devid = rev + start_addr = 0 #prove me wrong rom_header = [ 0xC2, # boot from EEPROM @@ -135,41 +78,18 @@ def build_eeprom_image (filename, rev): 0x00 ] - image = rom_header + code_header + bytes + trailer + image = rom_header + code_header + [ord(c) for c in bytes] + trailer assert (len (image) <= 256) - return image - -def build_shell_script (out, ihx_filename, rev): - - image = build_eeprom_image (ihx_filename, rev) - - out.write ('#!/bin/sh\n') - out.write ('usrper -x load_firmware /usr/local/share/usrp/rev%d/std.ihx\n' % rev) - out.write ('sleep 1\n') - - # print "len(image) =", len(image) - - i2c_addr = 0x50 - rom_addr = 0x00 - - hex_image = map (lambda x : "%02x" % (x,), image) - - while (len (hex_image) > 0): - l = min (len (hex_image), 16) - out.write ('usrper i2c_write 0x%02x %02x%s\n' % - (i2c_addr, rom_addr, ''.join (hex_image[0:l]))) - hex_image = hex_image[l:] - rom_addr = rom_addr + l - out.write ('sleep 1\n') + return image if __name__ == '__main__': - usage = "usage: %prog -r REV [options] bootfile.ihx" + usage = "usage: %prog -r REV [options] bootfile.bin outfile.bin" parser = OptionParser (usage=usage) parser.add_option ("-r", "--rev", type="int", default=-1, help="Specify USRP revision number REV (2 or 4)") (options, args) = parser.parse_args () - if len (args) != 1: + if len (args) != 2: parser.print_help () sys.exit (1) if options.rev < 0: @@ -177,6 +97,11 @@ if __name__ == '__main__': "You must specify the USRP revision number (2 or 4) with -r REV\n") sys.exit (1) - ihx_filename = args[0] + infile = args[0] + outfile = args[1] + + image = "".join(chr(c) for c in build_eeprom_image(infile, options.rev)) - build_shell_script (sys.stdout, ihx_filename, options.rev) + f = open(outfile, 'wb') + f.write(str(image)) + f.close() diff --git a/firmware/fx2/src/usrp1/Makefile.am b/firmware/fx2/src/usrp1/Makefile.am index 5586e83a3..a964f9198 100644 --- a/firmware/fx2/src/usrp1/Makefile.am +++ b/firmware/fx2/src/usrp1/Makefile.am @@ -19,12 +19,12 @@ # Boston, MA 02110-1301, USA. # -firmware2dir = $(prefix)/share/usrp/rev2 -firmware2_DATA = std.ihx +#firmwaredir = $(prefix)/share/uhd/images +#firmware_DATA = usrp1_fw.ihx -# we put the same stuff in the rev4 directory -firmware4dir = $(prefix)/share/usrp/rev4 -firmware4_DATA = std.ihx +#eepromdir = $(firmwaredir) +#eepromfile = eeprom_boot.ihx +#eeprom_DATA = usrp1_eeprom.bin EXTRA_DIST = \ edit-gpif \ @@ -85,11 +85,6 @@ EXECUTABLES = \ STARTUP = _startup.rel -noinst_SCRIPTS = \ - burn-usrp2-eeprom \ - burn-usrp4-eeprom - - .c.rel: $(XCC) $(FW_INCLUDES) $(DEFINES) \ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< @@ -107,34 +102,11 @@ EEPROM_BOOT_OBJS = eeprom_boot.rel eeprom_init.rel $(STARTUP) eeprom_boot.ihx: $(EEPROM_BOOT_OBJS) $(LIBDEP) $(XCC) $(LINKOPTS) -o $@ $(EEPROM_BOOT_OBJS) -burn-usrp2-eeprom: eeprom_boot.ihx - $(PYTHON) $(srcdir)/../common/build_eeprom.py -r2 eeprom_boot.ihx > $@ - chmod +x $@ - -burn-usrp4-eeprom: eeprom_boot.ihx - $(PYTHON) $(srcdir)/../common/build_eeprom.py -r4 eeprom_boot.ihx > $@ - chmod +x $@ - - -BLINK_LEDS_OBJS = blink_leds.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) - -blink_leds.ihx: $(BLINK_LEDS_OBJS) $(LIBDEP) - $(XCC) $(LINKOPTS) -o $@ $(BLINK_LEDS_OBJS) - - -CHECK_MDELAY_OBJS = check_mdelay.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) - -check_mdelay.ihx: $(CHECK_MDELAY_OBJS) $(LIBDEP) - $(XCC) $(LINKOPTS) -o $@ $(CHECK_MDELAY_OBJS) - - - -CHECK_UDELAY_OBJS = check_udelay.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) - -check_udelay.ihx: $(CHECK_UDELAY_OBJS) $(LIBDEP) - $(XCC) $(LINKOPTS) -o $@ $(CHECK_UDELAY_OBJS) - +usrp1_eeprom.bin: eeprom_boot.bin + $(PYTHON) ../common/build_eeprom.py -r4 $< $@ +eeprom_boot.bin: eeprom_boot.ihx + objcopy -I ihex -O binary $< $@ USRP_OBJS = \ vectors.rel \ @@ -146,25 +118,23 @@ std.ihx: $(USRP_OBJS) $(LIBDEP) $(XCC) $(LINKOPTS) -o $@ $(USRP_OBJS) CLEANFILES = \ - *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib \ - usrp_gpif.c usrp_gpif_inline.h \ - burn-usrp2-eeprom \ - burn-usrp4-eeprom + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib *.bin \ + usrp_gpif.c usrp_gpif_inline.h DISTCLEANFILES = \ - *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib *.bin # build gpif stuff -all: usrp_gpif.c +all: usrp_gpif.c std.ihx usrp1_eeprom.bin usrp_gpif.c usrp_gpif_inline.h : gpif.c srcdir=$(srcdir) $(PYTHON) $(srcdir)/edit-gpif $(srcdir)/gpif.c usrp_gpif.c usrp_gpif_inline.h - # dependencies usrp_main.rel: usrp_gpif_inline.h + #usrp_main.rel: fpga.h usrp_common.h ../../include/usrp_commands.h usrp_gpif_inline.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h #usrp_common.rel: usrp_common.h ../../include/usrp_commands.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h #fpga.rel: usrp_common.h ../../include/usrp_commands.h fpga.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp index 78c78f6b5..c3eb72b00 100644 --- a/host/include/uhd/transport/usb_device_handle.hpp +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -68,9 +68,9 @@ public: /*! * Return a vector of USB devices on this host - * \return a vector of USB device handles + * \return a vector of USB device handles that match vid and pid */ - static UHD_API std::vector get_device_list(); + static UHD_API std::vector get_device_list(boost::uint16_t vid, boost::uint16_t pid); }; //namespace usb diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 92dcd969f..e21c39aa3 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -24,22 +24,6 @@ using namespace uhd::transport; /********************************************************** * Helper Methods **********************************************************/ -/* - * Check for FSF device - * Compare the device's descriptor Vendor ID - * \param dev pointer to libusb_device - * \return true if Vendor ID matches 0xfffe - */ -bool check_fsf_device(libusb_device *dev) -{ - libusb_device_descriptor desc; - - if (libusb_get_device_descriptor(dev, &desc) < 0) { - UHD_ASSERT_THROW("USB: failed to get device descriptor"); - } - - return desc.idVendor == 0xfffe; -} /********************************************************** * libusb namespace @@ -52,37 +36,16 @@ void libusb::init(libusb_context **ctx, int debug_level) libusb_set_debug(*ctx, debug_level); } -std::vector libusb::get_fsf_device_list(libusb_context *ctx) -{ - libusb_device **libusb_dev_list; - std::vector fsf_dev_list; - - ssize_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list); - - //find the FSF devices - for (ssize_t i = 0; i < dev_cnt; i++) { - libusb_device *dev = libusb_dev_list[i]; - - if (check_fsf_device(dev)) - fsf_dev_list.push_back(dev); - else - libusb_unref_device(dev); - } - - libusb_free_device_list(libusb_dev_list, 0); - - return fsf_dev_list; -} - libusb_device_handle *libusb::open_device(libusb_context *ctx, usb_device_handle::sptr handle) { libusb_device_handle *dev_handle = NULL; - std::vector fsf_dev_list = get_fsf_device_list(ctx); + libusb_device **libusb_dev_list; + size_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list); //find and open the USB device - for (size_t i = 0; i < fsf_dev_list.size(); i++) { - libusb_device *dev = fsf_dev_list[i]; + for (size_t i = 0; i < dev_cnt; i++) { + libusb_device *dev = libusb_dev_list[i]; if (compare_device(dev, handle)) { libusb_open(dev, &dev_handle); @@ -96,7 +59,8 @@ libusb_device_handle *libusb::open_device(libusb_context *ctx, return dev_handle; } - +//note: changed order of checks so it only tries to get_serial and get_device_address if vid and pid match +//doing this so it doesn't try to open the device if it's not ours bool libusb::compare_device(libusb_device *dev, usb_device_handle::sptr handle) { @@ -108,12 +72,12 @@ bool libusb::compare_device(libusb_device *dev, 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 (serial != get_serial(dev)) + return false; if (device_addr != libusb_get_device_address(dev)) return false; diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index 442f89ded..abe5e22a2 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -41,16 +41,6 @@ namespace libusb { */ void init(libusb_context **ctx, int debug_level); - /* - * Get a list of Free Software Foundation devices (Vendor ID 0xfffe) - * As opposed to the public USB device handle interface, which returns - * generic identifiers, this call returns device pointers speficic - * to libusb. - * \param ctx the libusb context used for init - * \return a vector of libusb devices - */ - std::vector get_fsf_device_list(libusb_context *ctx); - /* * Open the device specified by a generic handle * Find the libusb_device cooresponding to the generic handle diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 5d9d8faf0..43d0f0e26 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -17,6 +17,7 @@ #include "libusb1_base.hpp" #include +#include using namespace uhd::transport; @@ -91,19 +92,24 @@ usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) device_addr)); } -std::vector usb_device_handle::get_device_list() +std::vector usb_device_handle::get_device_list(boost::uint16_t vid, boost::uint16_t pid) { libusb_context *ctx = NULL; - std::vector libusb_device_list; + libusb_device** libusb_device_list; std::vector device_handle_list; + libusb_device_descriptor desc; libusb::init(&ctx, libusb_debug_level); - libusb_device_list = libusb::get_fsf_device_list(ctx); - - for (size_t i = 0; i < libusb_device_list.size(); i++) { + size_t dev_size = libusb_get_device_list(ctx, &libusb_device_list); + for (size_t i = 0; i < dev_size; i++) { libusb_device *dev = libusb_device_list[i]; - device_handle_list.push_back(make_usb_device_handle(dev)); + if(libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + if(desc.idVendor == vid && desc.idProduct == pid) { + device_handle_list.push_back(make_usb_device_handle(dev)); + } } libusb_exit(ctx); diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 75129c32f..1409855cb 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -318,6 +319,16 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) **********************************************************************/ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) { + if(key.type() == typeid(std::string)) { + if(key.as() == "load_eeprom") { + std::string usrp1_fpga_image = val.as(); + std::cout << "USRP1 EEPROM image: " << usrp1_fpga_image << std::endl; + _ctrl_transport->usrp_load_eeprom(val.as()); + } + + return; + } + //handle the get request conditioned on the key switch(key.as()){ diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 98226b738..451129ef5 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace uhd; @@ -203,7 +204,7 @@ public: return -1; } } - //type 0x00 is end + //type 0x01 is end else if (type == 0x01) { usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); @@ -283,6 +284,55 @@ public: return 0; } + int usrp_load_eeprom(std::string filestring) + { + const char *filename = filestring.c_str(); + const uint16_t i2c_addr = 0x50; + + //FIXME: verify types + int len; + unsigned int addr; + unsigned char data[256]; + unsigned char sendbuf[17]; + + int ret; + std::ifstream file; + file.open(filename, std::ifstream::in); + + if (!file.good()) { + std::cerr << "cannot open EEPROM input file" << std::endl; + return -1; + } + + file.read((char *)data, 256); + len = file.gcount(); + + if(len == 256) { + std::cerr << "error: image size too large" << std::endl; + file.close(); + return -1; + } + + const int pagesize = 16; + addr = 0; + while(len > 0) { + sendbuf[0] = addr; + memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : len); + ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : len)+1); + if (ret < 0) { + std::cerr << "error: usrp_i2c_write failed: "; + std::cerr << ret << std::endl; + file.close(); + return -1; + } + addr += pagesize; + len -= pagesize; + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + file.close(); + return 0; + } + int usrp_set_led(int led_num, bool on) { @@ -371,6 +421,17 @@ public: return usrp_control_write(request, value, index, 0, 0); } + int usrp_i2c_write(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len) + { + return usrp_control_write(VRQ_I2C_WRITE, i2c_addr, 0, buf, len); + } + + int usrp_i2c_read(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len) + { + return usrp_control_read(VRQ_I2C_READ, i2c_addr, 0, buf, len); + } + + private: uhd::transport::usb_control::sptr _ctrl_transport; diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.hpp b/host/lib/usrp/usrp1/usrp1_ctrl.hpp index deedec4e8..a02d9f96c 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.hpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.hpp @@ -49,6 +49,13 @@ public: */ virtual int usrp_load_fpga(std::string filename) = 0; + /*! + * Load USB descriptor file in Intel HEX format into EEPROM + * \param filename name of EEPROM image + * \return 0 on success, error code otherwise + */ + virtual int usrp_load_eeprom(std::string filestring) = 0; + /*! * Set led usrp * \param led_num which LED to control (0 or 1) @@ -127,6 +134,30 @@ public: unsigned char *buff, boost::uint16_t length) = 0; + /*! + * Perform an I2C write + * \param i2c_addr I2C device address + * \param buf data to be written + * \param len length of data in bytes + * \return number of bytes written or error + */ + + virtual int usrp_i2c_write(boost::uint16_t i2c_addr, + unsigned char *buf, + boost::uint16_t len) = 0; + + /*! + * Perform an I2C read + * \param i2c_addr I2C device address + * \param buf data to be read + * \param len length of data in bytes + * \return number of bytes read or error + */ + + virtual int usrp_i2c_read(boost::uint16_t i2c_addr, + unsigned char *buf, + boost::uint16_t len) = 0; + }; #endif /* INCLUDED_USRP_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 8756a21c9..4bc18dd16 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -109,18 +109,19 @@ public: ******************************************************************/ static const size_t max_i2c_data_bytes = 64; + //TODO: make this handle EEPROM page sizes. right now you can't write over a 16-byte boundary. + //to accomplish this you'll have to have addr offset as a separate parameter. + void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) { UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); unsigned char buff[max_i2c_data_bytes]; - std::copy(bytes.begin(), bytes.end(), buff); + std::copy(bytes.begin(), bytes.end(), buff); - int ret = _ctrl_transport->usrp_control_write(VRQ_I2C_WRITE, - addr & 0xff, - 0, - buff, - bytes.size()); + int ret = _ctrl_transport->usrp_i2c_write(addr & 0xff, + buff, + bytes.size()); // TODO throw and catch i2c failures during eeprom read if (iface_debug && (ret < 0)) @@ -132,11 +133,9 @@ public: UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); unsigned char buff[max_i2c_data_bytes]; - int ret = _ctrl_transport->usrp_control_read(VRQ_I2C_READ, - addr & 0xff, - 0, - buff, - num_bytes); + int ret = _ctrl_transport->usrp_i2c_read(addr & 0xff, + buff, + num_bytes); // TODO throw and catch i2c failures during eeprom read if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes))) { diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 3c3306525..8ad148274 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -34,6 +34,11 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; +const boost::uint16_t USRP1_VENDOR_ID = 0xfffe; +const boost::uint16_t USRP1_PRODUCT_ID = 0x0002; +const boost::uint16_t FX2_VENDOR_ID = 0x04b4; +const boost::uint16_t FX2_PRODUCT_ID = 0x8613; + const std::vector usrp1_impl::_dboard_slots = boost::assign::list_of (usrp1_impl::DBOARD_SLOT_A)(usrp1_impl::DBOARD_SLOT_B) ; @@ -54,33 +59,32 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) ); std::cout << "USRP1 firmware image: " << usrp1_fw_image << std::endl; + boost::uint16_t vid = hint.has_key("uninit") ? FX2_VENDOR_ID : USRP1_VENDOR_ID; + boost::uint16_t pid = hint.has_key("uninit") ? FX2_PRODUCT_ID : USRP1_PRODUCT_ID; + //see what we got on the USB bus std::vector device_list = - usb_device_handle::get_device_list(); + usb_device_handle::get_device_list(vid, pid); + + if(device_list.size() == 0) return usrp1_addrs; //return nothing if no USRPs found //find the usrps and load firmware 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); - } } - //get descriptors again with serial number - device_list = usb_device_handle::get_device_list(); + //get descriptors again with serial number, but using the initialized VID/PID now since we have firmware + vid = USRP1_VENDOR_ID; + pid = USRP1_PRODUCT_ID; + device_list = usb_device_handle::get_device_list(vid, pid); BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { - if (handle->get_vendor_id() == 0xfffe && - handle->get_product_id() == 0x0002) { - device_addr_t new_addr; new_addr["type"] = "usrp1"; new_addr["serial"] = handle->get_serial(); usrp1_addrs.push_back(new_addr); - } } return usrp1_addrs; @@ -99,17 +103,15 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) //try to match the given device address with something on the USB bus std::vector device_list = - usb_device_handle::get_device_list(); + usb_device_handle::get_device_list(USRP1_VENDOR_ID, USRP1_PRODUCT_ID); //create data and control transports usb_zero_copy::sptr data_transport; usrp_ctrl::sptr usrp_ctrl; - 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"]) { + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_serial() == device_addr["serial"]) { usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index c349a9018..9d788b06c 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -39,9 +39,13 @@ TARGET_LINK_LIBRARIES(usrp2_addr_burner uhd) ADD_EXECUTABLE(usrp_burn_db_eeprom usrp_burn_db_eeprom.cpp) TARGET_LINK_LIBRARIES(usrp_burn_db_eeprom uhd) +ADD_EXECUTABLE(usrp_init_eeprom usrp_init_eeprom.cpp) +TARGET_LINK_LIBRARIES(usrp_init_eeprom uhd) + INSTALL(TARGETS usrp2_addr_burner usrp_burn_db_eeprom + usrp_init_eeprom RUNTIME DESTINATION ${PKG_DATA_DIR}/utils ) diff --git a/host/utils/usrp_init_eeprom.cpp b/host/utils/usrp_init_eeprom.cpp new file mode 100644 index 000000000..28c7c5745 --- /dev/null +++ b/host/utils/usrp_init_eeprom.cpp @@ -0,0 +1,69 @@ +// +// 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 . +// + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("image", po::value(), "IHX image file") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("USRP EEPROM initialization %s") % desc << std::endl; + return ~0; + } + + //load the options into the address + uhd::device_addr_t device_addr; + device_addr["type"] = "usrp1"; + device_addr["uninit"] = "yeah"; //tell find to look for an uninitialized FX2 + + //find and create a control transport to do the writing. + + uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); + + if (found_addrs.size() == 0){ + std::cerr << "No uninitialized USRP devices found" << std::endl; + return ~0; + } + + for (size_t i = 0; i < found_addrs.size(); i++){ + std::cout << "Writing EEPROM data..." << std::endl; + //uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]); + uhd::device::sptr dev = uhd::device::make(found_addrs[i]); + wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; + mb[std::string("load_eeprom")] = vm["image"].as(); + } + + + std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; + return 0; +} -- cgit v1.2.3 From 72646d1960b0c979afec225e741d7d89a827c7d0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 9 Sep 2010 15:53:04 -0700 Subject: uhd: added enable flags for usrp1 and usrp2 --- host/lib/transport/CMakeLists.txt | 6 ++++ host/lib/usrp/usrp1/CMakeLists.txt | 32 +++++++++++++-------- host/lib/usrp/usrp2/CMakeLists.txt | 59 ++++++++++++++++++++++++++------------ 3 files changed, 66 insertions(+), 31 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 753fd5e85..71a3a1494 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -35,6 +35,12 @@ IF(LIBUSB_FOUND) SET(HAVE_USB_SUPPORT TRUE) ENDIF(LIBUSB_FOUND) +IF(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - found") +ELSE(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - not found") +ENDIF(HAVE_USB_SUPPORT) + ######################################################################## # Check for SIMD headers ######################################################################## diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index 229a4ce63..67487f99e 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -20,18 +20,26 @@ ######################################################################## # Conditionally configure the USRP1 support ######################################################################## -MESSAGE(STATUS "Configuring usrp1 support...") +MESSAGE(STATUS "Configuring USRP1 support...") -IF(HAVE_USB_SUPPORT) - MESSAGE(STATUS "Has USB support - found") -ELSE(HAVE_USB_SUPPORT) - MESSAGE(STATUS "Has USB support - not found") -ENDIF(HAVE_USB_SUPPORT) +IF(DEFINED ENABLE_USRP1) + IF(ENABLE_USRP1) + MESSAGE(STATUS "USRP1 support enabled by configure flag") + ELSE(ENABLE_USRP1) + MESSAGE(STATUS "USRP1 support disabled by configure flag") + ENDIF(ENABLE_USRP1) +ELSE(DEFINED ENABLE_USRP1) #not defined: automatic enabling of component + SET(ENABLE_USRP1 ${HAVE_USB_SUPPORT}) +ENDIF(DEFINED ENABLE_USRP1) +SET(ENABLE_USRP1 ${ENABLE_USRP1} CACHE BOOL "enable USRP1 support") -#TODO check for usrp1 enable/disable option flag +#sanity check when USRP1 support enabled +IF(ENABLE_USRP1 AND NOT HAVE_USB_SUPPORT) + MESSAGE(FATAL_ERROR "USRP1 support enabled without USB support") +ENDIF(ENABLE_USRP1 AND NOT HAVE_USB_SUPPORT) -IF(HAVE_USB_SUPPORT) - MESSAGE(STATUS " Building usrp1 support.") +IF(ENABLE_USRP1) + MESSAGE(STATUS " Building USRP1 support.") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) LIBUHD_APPEND_SOURCES( @@ -52,6 +60,6 @@ IF(HAVE_USB_SUPPORT) ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.hpp ) -ELSE(HAVE_USB_SUPPORT) - MESSAGE(STATUS " Skipping usrp1 support.") -ENDIF(HAVE_USB_SUPPORT) +ELSE(ENABLE_USRP1) + MESSAGE(STATUS " Skipping USRP1 support.") +ENDIF(ENABLE_USRP1) diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 796126d07..078485d6a 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -17,22 +17,43 @@ #This file will be included by cmake, use absolute paths! -LIBUHD_APPEND_SOURCES( - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp -) +######################################################################## +# Conditionally configure the USRP2 support +######################################################################## +MESSAGE(STATUS "Configuring USRP2 support...") + +IF(DEFINED ENABLE_USRP2) + IF(ENABLE_USRP2) + MESSAGE(STATUS "USRP2 support enabled by configure flag") + ELSE(ENABLE_USRP2) + MESSAGE(STATUS "USRP2 support disabled by configure flag") + ENDIF(ENABLE_USRP2) +ELSE(DEFINED ENABLE_USRP2) #not defined: automatic enabling of component + SET(ENABLE_USRP2 TRUE) +ENDIF(DEFINED ENABLE_USRP2) +SET(ENABLE_USRP2 ${ENABLE_USRP2} CACHE BOOL "enable USRP2 support") + +IF(ENABLE_USRP2) + MESSAGE(STATUS " Building USRP2 support.") + LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp + ) +ELSE(ENABLE_USRP2) + MESSAGE(STATUS " Skipping USRP2 support.") +ENDIF(ENABLE_USRP2) -- cgit v1.2.3