diff options
| -rw-r--r-- | host/include/uhd/transport/usb_device_handle.hpp | 6 | ||||
| -rw-r--r-- | host/lib/transport/libusb1_base.cpp | 4 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_iface.cpp | 4 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_iface.hpp | 10 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 17 | ||||
| -rw-r--r-- | host/utils/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | host/utils/b2xx_fx3_utils.cpp | 858 | 
7 files changed, 358 insertions, 551 deletions
| diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp index 2951d7fbb..fdea9e2be 100644 --- a/host/include/uhd/transport/usb_device_handle.hpp +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -73,6 +73,12 @@ public:      virtual boost::uint16_t get_product_id() const = 0;      /*! +     * Test whether the firmware is loaded on the device. +     * \return true if firmware is loaded +     */ +    virtual bool firmware_loaded() = 0; + +    /*!       * Return a vector of USB devices on this host       * \return a vector of USB device handles that match vid and pid       */ diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 0ef53db0a..157edc199 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -274,6 +274,10 @@ public:          return libusb::device_descriptor::make(this->get_device())->get().idProduct;      } +    bool firmware_loaded() { +        return (get_manufacturer() == "Ettus Research LLC"); +    } +  private:      libusb::device::sptr _dev; //always keep a reference to device  }; diff --git a/host/lib/usrp/b200/b200_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp index 1d05e159c..b87df2977 100644 --- a/host/lib/usrp/b200/b200_iface.cpp +++ b/host/lib/usrp/b200/b200_iface.cpp @@ -240,10 +240,12 @@ public:          size_t num_bytes      ){          byte_vector_t recv_bytes(num_bytes); -        fx3_control_read(B200_VREQ_EEPROM_READ, +        int bytes_read = fx3_control_read(B200_VREQ_EEPROM_READ,                           0, offset | (boost::uint16_t(addr) << 8),                           (unsigned char*) &recv_bytes[0],                           num_bytes); +        if (bytes_read != num_bytes) +            throw uhd::io_error("Failed to read data from EEPROM.");          return recv_bytes;      } diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp index 1247d1f86..6ba77f0ff 100644 --- a/host/lib/usrp/b200/b200_iface.hpp +++ b/host/lib/usrp/b200/b200_iface.hpp @@ -25,6 +25,12 @@  #include <boost/utility.hpp>  #include "ad9361_ctrl.hpp" +const static boost::uint16_t B200_VENDOR_ID  = 0x2500; +const static boost::uint16_t B200_PRODUCT_ID = 0x0020; +const static boost::uint16_t FX3_VID = 0x04b4; +const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3; +const static boost::uint16_t FX3_REENUM_PID = 0x00f0; +  class b200_iface: boost::noncopyable, public virtual uhd::i2c_iface,                    public ad9361_ctrl_iface_type {  public: @@ -64,6 +70,10 @@ public:      //! send SPI through the FX3      virtual void transact_spi( unsigned char *tx_data, size_t num_tx_bits, \              unsigned char *rx_data, size_t num_rx_bits) = 0; + +    virtual void write_eeprom(boost::uint16_t addr, boost::uint16_t offset, const uhd::byte_vector_t &bytes) = 0; + +    virtual uhd::byte_vector_t read_eeprom(boost::uint16_t addr, boost::uint16_t offset, size_t num_bytes) = 0;  }; diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 0da388b93..30fdc7354 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -37,10 +37,6 @@ using namespace uhd;  using namespace uhd::usrp;  using namespace uhd::transport; -const boost::uint16_t B200_VENDOR_ID  = 0x2500; -const boost::uint16_t B200_PRODUCT_ID = 0x0020; -const boost::uint16_t INIT_PRODUCT_ID = 0x00f0; -  static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000);  //! mapping of frontend to radio perif index @@ -99,7 +95,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)          catch(const uhd::exception &){continue;} //ignore claimed          //check if fw was already loaded -        if (handle->get_manufacturer() != "Ettus Research LLC") +        if (!(handle->firmware_loaded()))          {              b200_iface::make(control)->load_firmware(b200_fw_image);          } @@ -160,8 +156,15 @@ b200_impl::b200_impl(const device_addr_t &device_addr)      const fs_path mb_path = "/mboards/0";      //try to match the given device address with something on the USB bus +    uint16_t vid = B200_VENDOR_ID; +    uint16_t pid = B200_PRODUCT_ID; +    if (device_addr.has_key("vid")) +            sscanf(device_addr.get("vid").c_str(), "%x", &vid); +    if (device_addr.has_key("pid")) +            sscanf(device_addr.get("pid").c_str(), "%x", &pid); +      std::vector<usb_device_handle::sptr> device_list = -        usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID); +        usb_device_handle::get_device_list(vid, pid);      //locate the matching handle in the device list      usb_device_handle::sptr handle; @@ -612,7 +615,7 @@ void b200_impl::setup_radio(const size_t dspno)  /***********************************************************************   * loopback tests   **********************************************************************/ -  +  void b200_impl::register_loopback_self_test(wb_iface::sptr iface)  {      bool test_fail = false; diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 92df0b7cf..1135ad031 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -47,7 +47,6 @@ SET(util_share_sources  IF(ENABLE_USB)      LIST(APPEND util_share_sources          fx2_init_eeprom.cpp -        b2xx_fx3_utils.cpp      )      INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS})  ENDIF(ENABLE_USB) @@ -68,6 +67,15 @@ FOREACH(util_source ${util_share_sources})      UHD_INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)  ENDFOREACH(util_source) +IF(ENABLE_USB) +    # build b2xx_fx3_utils +    INCLUDE_DIRECTORIES(../lib/usrp/b200) +    INCLUDE_DIRECTORIES(../lib/usrp/common) +    ADD_EXECUTABLE(b2xx_fx3_utils ../lib/transport/libusb1_base.cpp ../lib/usrp/b200/b200_iface.cpp b2xx_fx3_utils.cpp) +    TARGET_LINK_LIBRARIES(b2xx_fx3_utils uhd ${Boost_LIBRARIES}) +    UHD_INSTALL(TARGETS b2xx_fx3_utils RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities) +ENDIF(ENABLE_USB) +  UHD_INSTALL(TARGETS usrp_n2xx_simple_net_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)  #UHD images downloader configuration diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp index 36688c6c7..e910ffc6c 100644 --- a/host/utils/b2xx_fx3_utils.cpp +++ b/host/utils/b2xx_fx3_utils.cpp @@ -34,39 +34,10 @@  #include <boost/thread/thread.hpp>  #include <boost/functional/hash.hpp> -#include <uhd/config.hpp> -#include <uhd/utils/msg.hpp> - -const static boost::uint16_t FX3_VID = 0x04b4; -const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3; -const static boost::uint16_t FX3_REENUM_PID = 0x00f0; -const static boost::uint16_t B2XX_VID = 0x2500; -const static boost::uint16_t B2XX_PID = 0x0020; - -const static boost::uint8_t VRT_VENDOR_OUT = (LIBUSB_REQUEST_TYPE_VENDOR -                                              | LIBUSB_ENDPOINT_OUT); -const static boost::uint8_t VRT_VENDOR_IN = (LIBUSB_REQUEST_TYPE_VENDOR -                                             | LIBUSB_ENDPOINT_IN); -const static boost::uint8_t FX3_FIRMWARE_LOAD = 0xA0; - -const static boost::uint8_t B2XX_VREQ_FPGA_START = 0x02; -const static boost::uint8_t B2XX_VREQ_FPGA_DATA = 0x12; -const static boost::uint8_t B2XX_VREQ_SET_FPGA_HASH = 0x1C; -const static boost::uint8_t B2XX_VREQ_GET_FPGA_HASH = 0x1D; -const static boost::uint8_t B2XX_VREQ_FPGA_RESET = 0x62; -const static boost::uint8_t B2XX_VREQ_GET_USB = 0x80; -const static boost::uint8_t B2XX_VREQ_GET_STATUS = 0x83; -const static boost::uint8_t B2XX_VREQ_FX3_RESET = 0x99; -const static boost::uint8_t B2XX_VREQ_EEPROM_WRITE = 0xBA; - -const static boost::uint8_t FX3_STATE_FPGA_READY = 0x00; -const static boost::uint8_t FX3_STATE_CONFIGURING_FPGA = 0x01; -const static boost::uint8_t FX3_STATE_BUSY = 0x02; -const static boost::uint8_t FX3_STATE_RUNNING = 0x03; - -typedef boost::uint32_t hash_type; -typedef std::vector<boost::uint8_t> byte_vector_t; - +#include <b200_iface.hpp> +#include <uhd/transport/usb_control.hpp> +#include <uhd/transport/usb_device_handle.hpp> +#include <uhd/exception.hpp>  namespace po = boost::program_options;  namespace fs = boost::filesystem; @@ -90,422 +61,39 @@ boost::uint16_t atoh(const std::string &string){      return boost::lexical_cast<boost::uint16_t>(string);  } - -/*! - * Create a file hash - * The hash will be used to identify the loaded firmware and fpga image - * \param filename file used to generate hash value - * \return hash value in a size_t type - */ -static hash_type generate_hash(const char *filename) -{ -    std::ifstream file(filename); -    if (not file){ -        std::cerr << std::string("cannot open input file ") + filename -            << std::endl; -    } - -    size_t hash = 0; - -    char ch; -    while (file.get(ch)) { -        boost::hash_combine(hash, ch); -    } - -    if (not file.eof()){ -        std::cerr << std::string("file error ") + filename << std::endl; -    } - -    file.close(); -    return hash_type(hash); -} - -/*! - * Verify checksum of a Intel HEX record - * \param record a line from an Intel HEX file - * \return true if record is valid, false otherwise - */ -bool checksum(std::string *record) { - -    size_t len = record->length(); -    unsigned int i; -    unsigned char sum = 0; -    unsigned int val; - -    for (i = 1; i < len; i += 2) { -        std::istringstream(record->substr(i, 2)) >> std::hex >> val; -        sum += val; -    } - -    if (sum == 0) -       return true; -    else -       return false; -} - - -/*! - * Parse Intel HEX record - * - * \param record a line from an Intel HEX file - * \param len output length of record - * \param addr output address - * \param type output type - * \param data output data - * \return true if record is sucessfully read, false on error - */ -bool parse_record(std::string *record, boost::uint16_t &len, boost::uint16_t &addr, -        uint16_t &type, unsigned char* data) { - -    unsigned int i; -    std::string _data; -    unsigned int val; - -    if (record->substr(0, 1) != ":") -        return false; - -    std::istringstream(record->substr(1, 2)) >> std::hex >> len; -    std::istringstream(record->substr(3, 4)) >> std::hex >> addr; -    std::istringstream(record->substr(7, 2)) >> std::hex >> type; - -    for (i = 0; i < len; i++) { -        std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val; -        data[i] = (unsigned char) val; -    } - -    return true; -} - - -/*! - * Write data to the FX3. - * - * \param dev_handle the libusb-1.0 device handle - * \param request the usb transfer request type - * \param value the USB bValue - * \param index the USB bIndex - * \param buff the data to write - * \param length the number of bytes to write - * \return the number of bytes written - */ -libusb_error fx3_control_write(libusb_device_handle *dev_handle, boost::uint8_t request, -            boost::uint16_t value, boost::uint16_t index, unsigned char *buff, -            boost::uint16_t length, boost::uint32_t timeout = 0) { - -#if 0 -    if(DEBUG) { -        std::cout << "Writing: <" << std::hex << std::setw(6) << std::showbase \ -            << std::internal << std::setfill('0') << (int) request \ -            << ", " << std::setw(6) << (int) VRT_VENDOR_OUT \ -            << ", " << std::setw(6) << value \ -            << ", " << std::setw(6) << index \ -            << ", " << std::dec << std::setw(2) << length \ -            << ">" << std::endl; - -        std::cout << "\t\tData: 0x " << std::noshowbase; - -        for(int count = 0; count < length; count++) { -            std::cout << std::hex << std::setw(2) << (int) buff[count] << " "; -        } - -        std::cout << std::showbase << std::endl; -    } -#endif - -    return (libusb_error) libusb_control_transfer(dev_handle, VRT_VENDOR_OUT, request, \ -               value, index, buff, length, timeout); -} - - -/*! - * Read data from the FX3. - * - * \param dev_handle the libusb-1.0 device handle - * \param request the usb transfer request type - * \param value the USB bValue - * \param index the USB bIndex - * \param buff a buffer to store the read bytes to - * \param length the number of bytes to read - * \return the number of bytes read - */ -libusb_error fx3_control_read(libusb_device_handle *dev_handle, boost::uint8_t request, -            boost::uint16_t value, boost::uint16_t index, unsigned char *buff, -            boost::uint16_t length, boost::uint32_t timeout = 0) { - -#if 0 -    if(DEBUG) { -        std::cout << "Reading: <" << std::hex << std::setw(6) << std::showbase \ -            << std::internal << std::setfill('0') << (int) request \ -            << ", " << std::setw(6) << (int) VRT_VENDOR_IN \ -            << ", " << std::setw(6) << value \ -            << ", " << std::setw(6) << index \ -            << ", " << std::dec << std::setw(2) << length \ -            << ">" << std::endl << std::endl; -    } -#endif - -    return (libusb_error) libusb_control_transfer(dev_handle, VRT_VENDOR_IN, request, \ -               value, index, buff, length, timeout); -} - - -void write_eeprom(libusb_device_handle *dev_handle, boost::uint8_t addr, -        boost::uint8_t offset, const byte_vector_t &bytes) { -    fx3_control_write(dev_handle, B2XX_VREQ_EEPROM_WRITE, -                        0, offset | (boost::uint16_t(addr) << 8), -                        (unsigned char *) &bytes[0], -                        bytes.size()); -} - - -boost::uint8_t get_fx3_status(libusb_device_handle *dev_handle) { - -    unsigned char rx_data[1]; - -    fx3_control_read(dev_handle, B2XX_VREQ_GET_STATUS, 0x00, 0x00, rx_data, 1); - -    return boost::lexical_cast<boost::uint8_t>(rx_data[0]); -} - -void usrp_get_fpga_hash(libusb_device_handle *dev_handle, hash_type &hash) { -    fx3_control_read(dev_handle, B2XX_VREQ_GET_FPGA_HASH, 0x00, 0x00, -            (unsigned char*) &hash, 4, 500); -} - -void usrp_set_fpga_hash(libusb_device_handle *dev_handle, hash_type hash) { -    fx3_control_write(dev_handle, B2XX_VREQ_SET_FPGA_HASH, 0x00, 0x00, -            (unsigned char*) &hash, 4); -} - -boost::int32_t load_fpga(libusb_device_handle *dev_handle, -        const std::string filestring) { - -    if (filestring.empty()) -    { -        std::cerr << "load_fpga: input file is empty." << std::endl; -        exit(-1); -    } - -    boost::uint8_t fx3_state = 0; - -    const char *filename = filestring.c_str(); - -    hash_type hash = generate_hash(filename); -    hash_type loaded_hash; usrp_get_fpga_hash(dev_handle, loaded_hash); -    if (hash == loaded_hash) return 0; - -    size_t file_size = 0; -    { -        std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); -        file_size = file.tellg(); -    } - -    std::ifstream file; -    file.open(filename, std::ios::in | std::ios::binary); - -    if(!file.good()) { -        std::cerr << "load_fpga: cannot open FPGA input file." << std::endl; -        exit(-1); -    } - -    do { -        fx3_state = get_fx3_status(dev_handle); -        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); -    } while(fx3_state != FX3_STATE_FPGA_READY); - -    std::cout << "Loading FPGA image: " \ -        << filestring << "..." << std::flush; - -    unsigned char out_buff[64]; -    memset(out_buff, 0x00, sizeof(out_buff)); -    fx3_control_write(dev_handle, B2XX_VREQ_FPGA_START, 0, 0, out_buff, 1, 1000); - -    do { -        fx3_state = get_fx3_status(dev_handle); -        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); -    } while(fx3_state != FX3_STATE_CONFIGURING_FPGA); - - -    size_t bytes_sent = 0; -    while(!file.eof()) { -        file.read((char *) out_buff, sizeof(out_buff)); -        const std::streamsize n = file.gcount(); -        if(n == 0) continue; - -        boost::uint16_t transfer_count = boost::uint16_t(n); - -        /* Send the data to the device. */ -        fx3_control_write(dev_handle, B2XX_VREQ_FPGA_DATA, 0, 0, out_buff, -                transfer_count, 5000); - -        if (bytes_sent == 0) std::cout << "  0%" << std::flush; -        const size_t percent_before = size_t((bytes_sent*100)/file_size); -        bytes_sent += transfer_count; -        const size_t percent_after = size_t((bytes_sent*100)/file_size); -        if (percent_before/10 != percent_after/10) { -            std::cout << "\b\b\b\b" << std::setw(3) << percent_after -                << "%" << std::flush; -        } -    } - -    file.close(); - -    do { -        fx3_state = get_fx3_status(dev_handle); -        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); -    } while(fx3_state != FX3_STATE_RUNNING); - -    usrp_set_fpga_hash(dev_handle, hash); - -    std::cout << "\b\b\b\b done" << std::endl; - -    return 0; -} - - -/*! - * Program the FX3 with a firmware file (Intel HEX format) - * - * \param dev_handle the libusb-1.0 device handle - * \param filestring the filename of the firmware file - * \return 0 for success, otherwise error code - */ -boost::int32_t fx3_load_firmware(libusb_device_handle *dev_handle, \ -        std::string filestring) { - -    if (filestring.empty()) -    { -        std::cerr << "fx3_load_firmware: input file is empty." << std::endl; -        exit(-1); -    } - -    const char *filename = filestring.c_str(); - -    /* Fields used in each USB control transfer. */ -    boost::uint16_t len = 0; -    boost::uint16_t type = 0; -    boost::uint16_t lower_address_bits = 0x0000; -    unsigned char data[512]; - -    /* Can be set by the Intel HEX record 0x04, used for all 0x00 records -        * thereafter. Note this field takes the place of the 'index' parameter in -        * libusb calls, and is necessary for FX3's 32-bit addressing. */ -    boost::uint16_t upper_address_bits = 0x0000; - -    std::ifstream file; -    file.open(filename, std::ifstream::in); - -    if(!file.good()) { -        std::cerr << "fx3_load_firmware: cannot open firmware input file" -            << std::endl; -        exit(-1); -    } - -    std::cout << "Loading firmware image: " \ -        << filestring << "..." << std::flush; - -    while (!file.eof()) { -        boost::int32_t ret = 0; -        std::string record; -        file >> record; - -        /* Check for valid Intel HEX record. */ -        if (!checksum(&record) || !parse_record(&record, len, \ -                    lower_address_bits, type, data)) { -            std::cerr << "fx3_load_firmware: bad intel hex record checksum" -                    << std::endl; -        } - -        /* Type 0x00: Data. */ -        if (type == 0x00) { -            ret = fx3_control_write(dev_handle, FX3_FIRMWARE_LOAD, \ -                    lower_address_bits, upper_address_bits, data, len); - -            if (ret < 0) { -                std::cerr << "usrp_load_firmware: usrp_control_write failed" -                    << std::endl; -            } -        } - -        /* Type 0x01: EOF. */ -        else if (type == 0x01) { -            if (lower_address_bits != 0x0000 || len != 0 ) { -                std::cerr << "fx3_load_firmware: For EOF record, address must be 0, length must be 0." << std::endl; -            } - -            /* Successful termination! */ -            file.close(); - -            /* Let the system settle. */ -            boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); -            return 0; -        } - -        /* Type 0x04: Extended Linear Address Record. */ -        else if (type == 0x04) { -            if (lower_address_bits != 0x0000 || len != 2 ) { -                std::cerr << "fx3_load_firmware: For ELA record, address must be 0, length must be 2." << std::endl; -            } - -            upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ -                                    + ((boost::uint16_t)(data[1] & 0x00FF)); -        } - -        /* Type 0x05: Start Linear Address Record. */ -        else if (type == 0x05) { -            if (lower_address_bits != 0x0000 || len != 4 ) { -                std::cerr << "fx3_load_firmware: For SLA record, address must be 0, length must be 4." << std::endl; -            } - -            /* The firmware load is complete.  We now need to tell the CPU -                * to jump to an execution address start point, now contained within -                * the data field.  Parse these address bits out, and then push the -                * instruction. */ -            upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ -                                    + ((boost::uint16_t)(data[1] & 0x00FF)); -            lower_address_bits = ((boost::uint16_t)((data[2] & 0x00FF) << 8))\ -                                    + ((boost::uint16_t)(data[3] & 0x00FF)); - -            fx3_control_write(dev_handle, FX3_FIRMWARE_LOAD, lower_address_bits, \ -                    upper_address_bits, 0, 0); - -            std::cout << " done" << std::endl; -        } - -        /* If we receive an unknown record type, error out. */ -        else { -            std::cerr << "fx3_load_firmware: unsupported record type." << std::endl; -        } -    } - -    /* There was no valid EOF. */ -    std::cerr << "fx3_load_firmware: No EOF record found." << std::cout; -    return ~0; -} - -  boost::int32_t main(boost::int32_t argc, char *argv[]) {      boost::uint16_t vid, pid;      std::string pid_str, vid_str, fw_file, fpga_file; -    po::options_description desc("Allowed options"); -    desc.add_options() +    po::options_description visible("Allowed options"); +    visible.add_options()          ("help,h", "help message") -        ("vid,v", po::value<std::string>(&vid_str)->default_value("0x2500"), +        ("vid,v", po::value<std::string>(&vid_str),              "Specify VID of device to use.") -        ("pid,p", po::value<std::string>(&pid_str)->default_value("0x0020"), +        ("pid,p", po::value<std::string>(&pid_str),              "Specify PID of device to use.")          ("speed,S", "Read back the USB mode currently in use.")          ("reset-device,D", "Reset the B2xx Device.")          ("reset-fpga,F", "Reset the FPGA (does not require re-programming.")          ("reset-usb,U", "Reset the USB subsystem on your host computer.")          ("init-device,I", "Initialize a B2xx device.") -        ("load-fw,W", po::value<std::string>(&fw_file)->default_value(""), +        ("load-fw,W", po::value<std::string>(&fw_file),              "Load a firmware (hex) file into the FX3.") -        ("load-fpga,L", po::value<std::string>(&fpga_file)->default_value(""), +        ("load-fpga,L", po::value<std::string>(&fpga_file),              "Load a FPGA (bin) file into the FPGA.")      ; +    // Hidden options provided for testing - use at your own risk! +    po::options_description hidden("Hidden options"); +    hidden.add_options() +    ("uninit-device,U", "Uninitialize a B2xx device.") +    ("read-eeprom,R", "Read first 8 bytes of EEPROM") +    ("erase-eeprom,E", "Erase first 8 bytes of EEPROM"); + +    po::options_description desc; +    desc.add(visible); +    desc.add(hidden); +      po::variables_map vm;      po::store(po::parse_command_line(argc, argv, desc), vm);      po::notify(vm); @@ -567,146 +155,335 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) {          return 0;      } -    vid = atoh(vid_str); -    pid = atoh(pid_str); +    std::vector<uhd::transport::usb_device_handle::sptr> handles; +    uhd::transport::usb_device_handle::sptr handle; +    uhd::transport::usb_control::sptr usb_ctrl; +    b200_iface::sptr b200; + +    vid = B200_VENDOR_ID;   // Default +    pid = B200_PRODUCT_ID;  // Default +    if (vm.count("vid")) +        vid = atoh(vid_str); +    if (vm.count("pid")) +        pid = atoh(pid_str); + +    // Added for testing purposes - not exposed +    if (vm.count("read-eeprom")) { +        uhd::byte_vector_t data; + +        handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); +        if (handles.size() == 0) { +            std::cerr << "Cannot find device with vid: " << boost::format("0x%X") % vid << " and pid: " +                << boost::format("0x%X") % pid << std::endl; +            return -1; +        } +        usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +        b200 = b200_iface::make(usb_ctrl); + +        if (!(handles[0]->firmware_loaded())) +        { +            b200->load_firmware(fw_file); + +            // Now that the firmware is loaded, we need to re-open the device +            handles.clear(); +            handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); +            if (handles.size() == 0) { +                std::cerr << "Unable to reopen device with vid: " << boost::format("0x%X") % vid << " and pid: " +                    << boost::format("0x%X") % pid << std::endl; +                return -1; +            } +            usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +            b200 = b200_iface::make(usb_ctrl); +        } -    /* Pointer to pointer of device, used to retrieve a list of devices. */ -    libusb_device **devs; -    libusb_device_handle *dev_handle; -    libusb_context *ctx = NULL; -    libusb_error error_code; +        try { +            data = b200->read_eeprom(0x0, 0x0, 8); +        } catch (std::exception &e) { +            std::cerr << "Exception while reading EEPROM: " << e.what() << std::endl; +            return -1; +        } +        for (int i = 0; i < 8; i++) +            std::cout << i << ": " << boost::format("0x%X") % (int)data[i] << std::endl; -    libusb_init(&ctx); -    libusb_set_debug(ctx, 3); -    libusb_get_device_list(ctx, &devs); +        return 0; +    } -    /* If we are initializing the device, the VID/PID will default to the -     * Cypress VID/PID for the initial FW load. */ -    if (vm.count("init-device")) { -        dev_handle = libusb_open_device_with_vid_pid(ctx, FX3_VID, -                FX3_DEFAULT_PID); -        if(dev_handle == NULL) { -            std::cerr << "Cannot open device with vid: " << vid << " and pid: " -                << pid << std::endl; +    // Added for testing purposes - not exposed +    if (vm.count("erase-eeprom")) { + +        if (vm.count("vid") && vm.count("pid")) +            handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);                    // try user defined VID/PID first +        if (handles.size() == 0) +            handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID);    // try default FX3 VID/PID next +        if (handles.size() == 0) +            handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID);     // try reenumerated FX3 VID/PID next +        if (handles.size() == 0) +            handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID);     // try default B200 VID/PID next +        if (handles.size() == 0) { +            std::cerr << "Cannot find device" << std::endl;              return -1; -        } else { std::cout << "Uninitialized B2xx detected..." << std::flush; } -        libusb_free_device_list(devs, 1); +        } +        usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +        b200 = b200_iface::make(usb_ctrl); + +        if (!(handles[0]->firmware_loaded())) +        { +            // load FW +            b200->load_firmware(fw_file); + +            // re-open device +            handles.clear(); +            if (vm.count("vid") && vm.count("pid")) +                handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);                    // try user defined VID/PID first +            if (handles.size() == 0) +                handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID);    // try default FX3 VID/PID next +            if (handles.size() == 0) +                handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID);     // try reenumerated FX3 VID/PID next +            if (handles.size() == 0) +                handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID);     // try default B200 VID/PID next +            if (handles.size() == 0) { +                std::cerr << "Cannot find device" << std::endl; +                return -1; +            } +            usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +            b200 = b200_iface::make(usb_ctrl); +        } -        /* Find out if kernel driver is attached, and if so, detach it. */ -        if(libusb_kernel_driver_active(dev_handle, 0) == 1) { -            std::cout << " Competing Driver Identified... " << std::flush; +        uhd::byte_vector_t bytes(8); +        bytes[0] = 0xFF; +        bytes[1] = 0xFF; +        bytes[2] = 0xFF; +        bytes[3] = 0xFF; +        bytes[4] = 0xFF; +        bytes[5] = 0xFF; +        bytes[6] = 0xFF; +        bytes[7] = 0xFF; +        try { +            b200->write_eeprom(0x0, 0x0, bytes); +        } catch (uhd::exception &e) { +            std::cerr << "Exception while writing to EEPROM: " << e.what() << std::endl; +            return -1; +        } -            if(libusb_detach_kernel_driver(dev_handle, 0) == 0) { -                std::cout << " Competing Driver Destroyed!" << std::flush; +        // verify +        uhd::byte_vector_t read_bytes(8); +        try { +            read_bytes = b200->read_eeprom(0x0, 0x0, 8); +        } catch (uhd::exception &e) { +            std::cerr << "Exception while reading from EEPROM: " << e.what() << std::endl; +            return -1; +        } +        bool verified = true; +        for (int i = 0; i < 8; i++) { +            if (bytes[i] != read_bytes[i]) { +                verified = false; +                std::cerr << "Expected: " << bytes[i] << ", Got: " << read_bytes[i] << std::endl;              }          } -        libusb_claim_interface(dev_handle, 0); +        if (!verified) { +            std::cerr << "Verification failed" << std::endl; +            return -1; +        } + +        std::cout << "Erase Successful!" << std::endl; + +        return 0; +    } + +    // Added for testing purposes - not exposed +    if (vm.count("uninit-device")) { + +        handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); +        if (handles.size() == 0) { +            std::cerr << "Cannot find device with vid: " << boost::format("0x%X") % vid << " and pid: " +                << boost::format("0x%X") % pid << std::endl; +            return -1; +        } + +        std::cout << "Initialized B2xx detected..." << std::flush; + +        usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +        b200 = b200_iface::make(usb_ctrl); +          std::cout << " Control of B2xx granted..." << std::endl << std::endl; -        /* Load the FW. */ -        error_code = (libusb_error) fx3_load_firmware(dev_handle, fw_file); -        if(error_code != 0) { -            std::cerr << std::flush << "Error loading firmware. Error code: " -                << error_code << std::endl; -            libusb_release_interface(dev_handle, 0); -            libusb_close(dev_handle); -            libusb_exit(ctx); -            return ~0; +        if (!(handles[0]->firmware_loaded())) +        { +            b200->load_firmware(fw_file); + +            // Now that the firmware is loaded, we need to re-open the device +            handles.clear(); +            handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); +            if (handles.size() == 0) { +                std::cerr << "Unable to reopen device with vid: " << boost::format("0x%X") % vid << " and pid: " +                    << boost::format("0x%X") % pid << std::endl; +                return -1; +            } +            usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +            b200 = b200_iface::make(usb_ctrl);          } -        /* Let the device re-enumerate. */ -        libusb_release_interface(dev_handle, 0); -        libusb_close(dev_handle); -        dev_handle = libusb_open_device_with_vid_pid(ctx, FX3_VID, -                FX3_REENUM_PID); -        if(dev_handle == NULL) { -            std::cerr << "Cannot open device with vid: " << vid << " and pid: " -                << pid << std::endl; +        /* Now, uninitialize the device. */ +        uhd::byte_vector_t bytes(8); +        bytes[0] = 0xFF; +        bytes[1] = 0xFF; +        bytes[2] = 0xFF; +        bytes[3] = 0xFF; +        bytes[4] = 0xFF; +        bytes[5] = 0xFF; +        bytes[6] = 0xFF; +        bytes[7] = 0xFF; + +        try { +            b200->write_eeprom(0x0, 0x0, bytes); +        } catch (uhd::exception &e) { +            std::cerr << "Exception while writing to EEPROM: " << e.what() << std::endl;              return -1; -        } else { -            std::cout << "Detected in-progress init of B2xx..." << std::flush;          } -        //libusb_free_device_list(devs, 1); -        libusb_claim_interface(dev_handle, 0); -        std::cout << " Reenumeration complete, Device claimed..." -            << std::endl; + +        std::cout << "EEPROM uninitialized, resetting device..." +            << std::endl << std::endl; + +        /* Reset the device! */ +        try { +            b200->reset_fx3(); +        } catch (uhd::exception &e) { +            std::cerr << "Exception while resetting FX3: " << e.what() << std::endl; +            return -1; +        } + +        std::cout << "Uninitialization Process Complete." +            << std::endl << std::endl; + +        return 0; +    } + +    /* If we are initializing the device, the VID/PID should default to the +     * Cypress VID/PID for the initial FW load, but we can initialize from any state. */ +    if (vm.count("init-device")) { +        if (vm.count("vid") && vm.count("pid")) +            handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);                    // try user defined VID/PID first +        if (handles.size() == 0) +            handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID);    // try default FX3 VID/PID next +        if (handles.size() == 0) +            handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID);     // try reenumerated FX3 VID/PID next +        if (handles.size() == 0) +            handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID);     // try default B200 VID/PID next +        if (handles.size() == 0) { +            std::cerr << "Cannot find device" << std::endl; +            return -1; +        } + +        std::cout << "Uninitialized B2xx detected..." << std::flush; + +        usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +        b200 = b200_iface::make(usb_ctrl); + +        std::cout << " Control of B2xx granted..." << std::endl << std::endl; + +        if (!(handles[0]->firmware_loaded())) +        { +            // load FW +            b200->load_firmware(fw_file); + +            // re-open device +            handles.clear(); +            if (vm.count("vid") && vm.count("pid")) +                handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);                    // try user defined VID/PID first +            if (handles.size() == 0) +                handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID);    // try default FX3 VID/PID next +            if (handles.size() == 0) +                handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID);     // try reenumerated FX3 VID/PID next +            if (handles.size() == 0) +                handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID);     // try default B200 VID/PID next +            if (handles.size() == 0) { +                std::cerr << "Cannot find device" << std::endl; +                return -1; +            } +            usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +            b200 = b200_iface::make(usb_ctrl); +        }          /* Now, initialize the device. */ -        byte_vector_t bytes(8); +        uhd::byte_vector_t bytes(8);          bytes[0] = 0x43;          bytes[1] = 0x59;          bytes[2] = 0x14;          bytes[3] = 0xB2; -        bytes[4] = (B2XX_PID & 0xff); -        bytes[5] = (B2XX_PID >> 8); -        bytes[6] = (B2XX_VID & 0xff); -        bytes[7] = (B2XX_VID >> 8); -        write_eeprom(dev_handle, 0x0, 0x0, bytes); +        bytes[4] = (B200_PRODUCT_ID & 0xff); +        bytes[5] = (B200_PRODUCT_ID >> 8); +        bytes[6] = (B200_VENDOR_ID & 0xff); +        bytes[7] = (B200_VENDOR_ID >> 8); + +        try { +            b200->write_eeprom(0x0, 0x0, bytes); +        } catch (uhd::exception &e) { +            std::cerr << "Exception while writing to EEPROM: " << e.what() << std::endl; +            return -1; +        } +          std::cout << "EEPROM initialized, resetting device..."              << std::endl << std::endl;          /* Reset the device! */ -        boost::uint8_t data_buffer[1]; -        fx3_control_write(dev_handle, B2XX_VREQ_FX3_RESET, -                0x00, 0x00, data_buffer, 1, 5000); +        try { +            b200->reset_fx3(); +        } catch (const std::exception &e) { +            std::cerr << "Exceptions while resetting device: " << e.what() << std::endl; +            return -1; +        }          std::cout << "Initialization Process Complete."              << std::endl << std::endl; -        libusb_release_interface(dev_handle, 0); -        libusb_close(dev_handle); -        libusb_exit(ctx);          return 0;      } -    dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); -    if(dev_handle == NULL) { -        std::cerr << "Cannot open device with vid: " << vid << " and pid: " -            << pid << std::endl; -            return -1; -    } else { std::cout << "Reactor Core Online..." << std::flush; } -    libusb_free_device_list(devs, 1); +    // open device for all other operations +    handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); +    if (handles.size() == 0) { +        std::cerr << "Cannot find device with vid: " << boost::format("0x%X") % vid << " and pid: " +            << boost::format("0x%X") % pid << std::endl; +        return -1; +    } -    /* Find out if kernel driver is attached, and if so, detach it. */ -    if(libusb_kernel_driver_active(dev_handle, 0) == 1) { -        std::cout << " Competing Driver Identified... " << std::flush; +    std::cout << "Reactor Core Online..." << std::flush; -        if(libusb_detach_kernel_driver(dev_handle, 0) == 0) { -            std::cout << " Competing Driver Destroyed!" << std::flush; -        } -    } +    usb_ctrl = uhd::transport::usb_control::make(handles[0], 0); +    b200 = b200_iface::make(usb_ctrl); -    /* Claim interface 0 of device. */ -    error_code = (libusb_error) libusb_claim_interface(dev_handle, 0);      std::cout << " All Systems Nominal..." << std::endl << std::endl;      boost::uint8_t data_buffer[16];      memset(data_buffer, 0x0, sizeof(data_buffer));      if (vm.count("speed")){ -        error_code = fx3_control_read(dev_handle, B2XX_VREQ_GET_USB, -                0x00, 0x00, data_buffer, 1, 5000); - -        boost::uint8_t speed = boost::lexical_cast<boost::uint8_t>(data_buffer[0]); - +        boost::uint8_t speed; +        try {speed = b200->get_usb_speed();} +        catch (uhd::exception &e) { +            std::cerr << "Exception while getting USB speed: " << e.what() << std::endl; +            return -1; +        }          std::cout << "Currently operating at USB " << (int) speed << std::endl;      } else if (vm.count("reset-device")) { -        error_code = fx3_control_write(dev_handle, B2XX_VREQ_FX3_RESET, -                0x00, 0x00, data_buffer, 1, 5000); +        try {b200->reset_fx3();} +        catch (uhd::exception &e) { +            std::cerr << "Exception while resetting FX3: " << e.what() << std::endl; +            return -1; +        }      } else if (vm.count("reset-fpga")) { -        error_code = fx3_control_write(dev_handle, B2XX_VREQ_FPGA_RESET, -                0x00, 0x00, data_buffer, 1, 5000); +        try {b200->set_fpga_reset_pin(true);} +        catch (uhd::exception &e) { +            std::cerr << "Exception while resetting FPGA: " << e.what() << std::endl; +            return -1; +        }      } else if (vm.count("load-fw")) { -        error_code = (libusb_error) fx3_load_firmware(dev_handle, fw_file); - -        if(error_code != 0) { -            std::cerr << std::flush << "Error loading firmware. Error code: " -                << error_code << std::endl; -            libusb_release_interface(dev_handle, 0); -            libusb_close(dev_handle); -            libusb_exit(ctx); +        std::cout << "Loading firmware" << std::endl; +        try {b200->load_firmware(fw_file);} +        catch (uhd::exception &e) { +            std::cerr << "Exception while loading firmware: " << e.what() << std::endl;              return ~0;          } @@ -714,14 +491,18 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) {              << std::endl;      } else if (vm.count("load-fpga")) { -        error_code = (libusb_error) load_fpga(dev_handle, fpga_file); - -        if(error_code != 0) { -            std::cerr << std::flush << "Error loading FPGA. Error code: " -                << error_code << std::endl; -            libusb_release_interface(dev_handle, 0); -            libusb_close(dev_handle); -            libusb_exit(ctx); +        std::cout << "Loading FPGA image (" << fpga_file << ")" << std::endl; +        uint32_t fx3_state; +        try {fx3_state = b200->load_fpga(fpga_file);} // returns 0 on success, or FX3 state on error +        catch (uhd::exception &e) { +            std::cerr << "Exception while resetting FPGA: " << e.what() << std::endl; +            return ~0; +        } + + +        if (fx3_state != 0) { +            std::cerr << std::flush << "Error loading FPGA. FX3 state: " +            << fx3_state << std::endl;              return ~0;          } @@ -730,18 +511,11 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) {      } else {          std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl; -        libusb_release_interface(dev_handle, 0); -        libusb_close(dev_handle); -        libusb_exit(ctx);          return ~0;      }      std::cout << std::endl << "Reactor Shutting Down..." << std::endl; -    error_code = (libusb_error) libusb_release_interface(dev_handle, 0); -    libusb_close(dev_handle); -    libusb_exit(ctx); -      return 0;  } | 
