From 38746242eab47845c1b1b6cb264c3e3041977488 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 13 Aug 2010 12:59:32 -0700 Subject: usrp1: Add USB transport interfaces This patch adds generic interfaces for control and zero-copy transport of data between the host and a slave device. The interfaces are separate and generic to accommodate multiple implementations that may include cross platform libraries such as libusb or a platform specific implementation such as Linux usbfs. --- host/include/uhd/transport/CMakeLists.txt | 2 + host/include/uhd/transport/usb_control.hpp | 76 ++++++++++++++++++++++++++++ host/include/uhd/transport/usb_zero_copy.hpp | 64 +++++++++++++++++++++++ host/include/uhd/types/CMakeLists.txt | 1 + host/include/uhd/types/usb_descriptor.hpp | 49 ++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 host/include/uhd/transport/usb_control.hpp create mode 100644 host/include/uhd/transport/usb_zero_copy.hpp create mode 100644 host/include/uhd/types/usb_descriptor.hpp (limited to 'host/include') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 93e9a6485..dd1a20eed 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -25,6 +25,8 @@ INSTALL(FILES if_addrs.hpp udp_simple.hpp udp_zero_copy.hpp + usb_control.hpp + usb_zero_copy.hpp vrt_if_packet.hpp zero_copy.hpp DESTINATION ${INCLUDE_DIR}/uhd/transport diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp new file mode 100644 index 000000000..6b5591a21 --- /dev/null +++ b/host/include/uhd/transport/usb_control.hpp @@ -0,0 +1,76 @@ +// +// 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_USB_CONTROL_HPP +#define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP + +#include +#include +#include +#include +#include + +namespace uhd { namespace transport { + +class UHD_API usb_control : boost::noncopyable { +public: + typedef boost::shared_ptr sptr; + + /*! + * Create a new usb control transport: + * This transport is for sending and receiving control information from + * the host to device using the Default Control Pipe. + * + * \param descriptor a descriptor that identifies a USB device + */ + static sptr make(usb_descriptor_t descriptor); + + /*! + * Submit a USB device request: + * Blocks until the request returns + * + * For format and corresponding USB request fields + * see USB Specification Revision 2.0 - 9.3 USB Device Requests + * + * Usage is device specific + * + * \param request_type 1-byte bitmask (bmRequestType) + * \param request 1-byte (bRequest) + * \param value 2-byte (wValue) + * \param index 2-byte (wIndex) + * \param buff buffer to hold send or receive data + * \param length 2-byte (wLength) + * \return number of bytes submitted + */ + virtual 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) = 0; + + /*! + * Get a vector of USB device descriptors + * + * \return a vector of usb_descriptors + */ + static usb_descriptors_t get_device_list(); +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP */ diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp new file mode 100644 index 000000000..7b9692fa5 --- /dev/null +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -0,0 +1,64 @@ +// +// 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_USB_ZERO_COPY_HPP +#define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP + +#include +#include +#include +#include + +namespace uhd { namespace transport { + +/*! + * A zero copy usb transport provides an efficient way to handle data. + * by avoiding the extra copy when recv() or send() is called on the handle. + * Rather, the zero copy transport gives the caller memory references. + * The caller informs the transport when it is finished with the reference. + * + * On linux systems, the zero copy transport can use a kernel packet ring. + * If no platform specific solution is available, make returns a boost asio + * implementation that wraps functionality around standard send/recv calls. + */ +class UHD_API usb_zero_copy : public virtual zero_copy_if { +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new zero copy usb transport: + * This transport is for sending and receiving between the host + * and a pair of USB bulk transfer endpoints. + * The primary usage for this transport is data transactions. + * The underlying implementation may be platform specific. + * + * \param descriptor a USB descriptor identifying the device + * \param rx_endpoint an integer specifiying an IN endpoint number + * \param tx_endpoint an integer specifiying an OUT endpoint number + * \param buff_size total number of bytes of buffer space to allocate + * \param block_size number of bytes allocated for each I/O transaction + */ + static sptr make(usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t buff_size = 0, + size_t block_size = 0); +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP */ diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index dbce21c98..8e302eed2 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -29,5 +29,6 @@ INSTALL(FILES stream_cmd.hpp time_spec.hpp tune_result.hpp + usb_descriptor.hpp DESTINATION ${INCLUDE_DIR}/uhd/types ) diff --git a/host/include/uhd/types/usb_descriptor.hpp b/host/include/uhd/types/usb_descriptor.hpp new file mode 100644 index 000000000..0e4c8c369 --- /dev/null +++ b/host/include/uhd/types/usb_descriptor.hpp @@ -0,0 +1,49 @@ +// +// 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_TYPES_USB_DESCRIPTOR_HPP +#define INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP + +#include +#include +#include +#include + +namespace uhd{ + + /*! + * The USB descriptor struct holds identity information for a USB device + */ + struct UHD_API usb_descriptor_t{ + std::string serial; + boost::uint16_t vendor_id; + boost::uint16_t product_id; + boost::uint16_t device_addr; + + /*! + * Create a pretty print string for this USB descriptor struct. + * \return the printable string + */ + std::string to_pp_string(void) const; + }; + + //handy typde for a vector of usb descriptors + typedef std::vector usb_descriptors_t; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP */ -- cgit v1.2.3 From 687e118eefd7e35e3a094152a51927bd82ac030d Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 11:16:46 -0700 Subject: usrp1: Modifiy USB interfaces to use new device handle The interface previously defined a descriptor type, which is now replaced with a generalized handle. This change provides more flexibility in implementations that may pass internal representations of device handles or identifier objects. --- host/include/uhd/transport/CMakeLists.txt | 1 + host/include/uhd/transport/usb_control.hpp | 17 +---- host/include/uhd/transport/usb_device_handle.hpp | 79 ++++++++++++++++++++++++ host/include/uhd/transport/usb_zero_copy.hpp | 8 +-- host/include/uhd/types/CMakeLists.txt | 1 - host/include/uhd/types/usb_descriptor.hpp | 49 --------------- 6 files changed, 86 insertions(+), 69 deletions(-) create mode 100644 host/include/uhd/transport/usb_device_handle.hpp delete mode 100644 host/include/uhd/types/usb_descriptor.hpp (limited to 'host/include') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index dd1a20eed..0f1cbf2a2 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -27,6 +27,7 @@ INSTALL(FILES udp_zero_copy.hpp usb_control.hpp usb_zero_copy.hpp + usb_device_handle.hpp vrt_if_packet.hpp zero_copy.hpp DESTINATION ${INCLUDE_DIR}/uhd/transport diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index 6b5591a21..6137ecf84 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -18,11 +18,7 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP #define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP -#include -#include -#include -#include -#include +#include "usb_device_handle.hpp" namespace uhd { namespace transport { @@ -35,9 +31,9 @@ public: * This transport is for sending and receiving control information from * the host to device using the Default Control Pipe. * - * \param descriptor a descriptor that identifies a USB device + * \param handle a device handle that uniquely identifies a USB device */ - static sptr make(usb_descriptor_t descriptor); + static sptr make(usb_device_handle::sptr handle); /*! * Submit a USB device request: @@ -62,13 +58,6 @@ public: boost::uint16_t index, unsigned char *buff, boost::uint16_t length) = 0; - - /*! - * Get a vector of USB device descriptors - * - * \return a vector of usb_descriptors - */ - static usb_descriptors_t get_device_list(); }; }} //namespace diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp new file mode 100644 index 000000000..78c78f6b5 --- /dev/null +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -0,0 +1,79 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP +#define INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP + +#include +#include +#include +#include +#include + +namespace uhd { namespace transport { + +/*! + * Device handle class that represents a USB device + * Used for identifying devices on the USB bus and selecting which device is + * used when creating a USB transport. A minimal subset of USB descriptor + * fields are used. Fields can be found in the USB 2.0 specification Table + * 9-8 (Standard Device Descriptor). In addition to fields of the device + * descriptor, the interface returns the device's USB device address. + * + * Note: The USB 2.0 Standard Device Descriptor contains an index rather then + * a true descriptor serial number string. This interface returns the + * actual string descriptor. + */ +class UHD_API usb_device_handle : boost::noncopyable { +public: + typedef boost::shared_ptr sptr; + + /*! + * Return the device's serial number + * \return a string describing the device's serial number + */ + virtual UHD_API std::string get_serial() const = 0; + + /*! + * Return the device's Vendor ID (usually assigned by the USB-IF) + * \return a Vendor ID + */ + virtual UHD_API boost::uint16_t get_vendor_id() const = 0; + + /*! + * Return the device's Product ID (usually assigned by manufacturer) + * \return a Product ID + */ + virtual UHD_API boost::uint16_t get_product_id() const = 0; + + /*! + * Return the device's USB address + * \return a Product ID + */ + virtual UHD_API boost::uint16_t get_device_addr() const = 0; + + /*! + * Return a vector of USB devices on this host + * \return a vector of USB device handles + */ + static UHD_API std::vector get_device_list(); + +}; //namespace usb + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP */ diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 7b9692fa5..2edd6d91d 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -18,10 +18,8 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP #define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP -#include -#include +#include "usb_device_handle.hpp" #include -#include namespace uhd { namespace transport { @@ -46,13 +44,13 @@ public: * The primary usage for this transport is data transactions. * The underlying implementation may be platform specific. * - * \param descriptor a USB descriptor identifying the device + * \param handle a device handle that uniquely identifying the device * \param rx_endpoint an integer specifiying an IN endpoint number * \param tx_endpoint an integer specifiying an OUT endpoint number * \param buff_size total number of bytes of buffer space to allocate * \param block_size number of bytes allocated for each I/O transaction */ - static sptr make(usb_descriptor_t descriptor, + static sptr make(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t buff_size = 0, diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 8e302eed2..dbce21c98 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -29,6 +29,5 @@ INSTALL(FILES stream_cmd.hpp time_spec.hpp tune_result.hpp - usb_descriptor.hpp DESTINATION ${INCLUDE_DIR}/uhd/types ) diff --git a/host/include/uhd/types/usb_descriptor.hpp b/host/include/uhd/types/usb_descriptor.hpp deleted file mode 100644 index 0e4c8c369..000000000 --- a/host/include/uhd/types/usb_descriptor.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP -#define INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP - -#include -#include -#include -#include - -namespace uhd{ - - /*! - * The USB descriptor struct holds identity information for a USB device - */ - struct UHD_API usb_descriptor_t{ - std::string serial; - boost::uint16_t vendor_id; - boost::uint16_t product_id; - boost::uint16_t device_addr; - - /*! - * Create a pretty print string for this USB descriptor struct. - * \return the printable string - */ - std::string to_pp_string(void) const; - }; - - //handy typde for a vector of usb descriptors - typedef std::vector usb_descriptors_t; - -} //namespace uhd - -#endif /* INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP */ -- 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/include') 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 f5c62a46cbc44e254c0214b463d51f06675c17ab Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 16:54:18 -0700 Subject: usrp1: subdev spec tweaks and docs --- host/docs/usrp1.rst | 35 +++++++++++++++++++++++++++++++++++ host/include/uhd/usrp/subdev_spec.hpp | 9 --------- host/lib/usrp/misc_utils.cpp | 13 +++++++++++-- 3 files changed, 46 insertions(+), 11 deletions(-) (limited to 'host/include') diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index ebc33cbfa..c960b928b 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -21,6 +21,41 @@ Change the USRP1's serial number ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO +------------------------------------------------------------------------ +Specifying the subdevice to use +------------------------------------------------------------------------ +The USRP1 has multiple daughterboard slots, known as slot A and slot B. +The subdevice specification can be used to select +the daughterboard and subdevice for each channel. +For daughterboards with one one subdevice, +the subdevice name may be left blank for automatic selection. + +Ex: The subdev spec markup string to select a WBX on slot B. +Notice the use of the blank subdevice name for automatic selection. + +:: + + B: + + -- OR -- + + B:0 + +Ex: The subdev spec markup string to select a BasicRX on slot B. +Notice that the subdevice name is always specified in the 3 possible cases. + +:: + + B:AB + + -- OR -- + + B:A + + -- OR -- + + B:B + ------------------------------------------------------------------------ OS Specific Notes ------------------------------------------------------------------------ diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp index 56aa0df20..2f32509b9 100644 --- a/host/include/uhd/usrp/subdev_spec.hpp +++ b/host/include/uhd/usrp/subdev_spec.hpp @@ -56,17 +56,8 @@ namespace uhd{ namespace usrp{ * * The subdevice specification can be represented as a markup-string. * The markup-string is a whitespace separated list of dboard:subdev pairs. - * The "dboard:" part is optional on boards with only one daughterboard slot. * The first pair represents the subdevice for channel zero, * the second pair represents the subdevice for channel one, and so on. - * - * Examples: - * - Use subdevice AB on daughterboard A (USRP1): "A:AB" - * - Use subdevice A on daughterboard A for channel zero and subdevice A on daughterboard B for channel one (USRP1): "A:A B:A" - * - Use subdevice AB (USRP2): "AB" or ":AB" - * - * An empty subdevice specification can be used to automatically - * select the first subdevice on the first present daughterboard. */ class UHD_API subdev_spec_t : public std::vector{ public: diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp index a1664d810..5cfcdc8d3 100644 --- a/host/lib/usrp/misc_utils.cpp +++ b/host/lib/usrp/misc_utils.cpp @@ -164,13 +164,22 @@ static void verify_xx_subdev_spec( //empty db name means select dboard automatically if (pair.db_name.empty()){ if (dboard_names.size() != 1) throw std::runtime_error( - "A daughterboard name must be provided for multi-slot boards: " + subdev_spec.to_string() + "A daughterboard name must be provided for multi-slot motherboards: " + subdev_spec.to_string() ); pair.db_name == dboard_names.front(); } uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name"); wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)]; - uhd::assert_has(dboard[DBOARD_PROP_SUBDEV_NAMES].as(), pair.sd_name, xx_type + " subdev name"); + prop_names_t subdev_names = dboard[DBOARD_PROP_SUBDEV_NAMES].as(); + + //empty sd name means select the subdev automatically + if (pair.sd_name.empty()){ + if (subdev_names.size() != 1) throw std::runtime_error( + "A subdevice name must be provided for multi-subdev daughterboards: " + subdev_spec.to_string() + ); + pair.sd_name == subdev_names.front(); + } + uhd::assert_has(subdev_names, pair.sd_name, xx_type + " subdev name"); } }catch(const std::exception &e){ throw std::runtime_error(str(boost::format( -- 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/include') 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