diff options
Diffstat (limited to 'host/lib/usrp/b200/b200_iface.cpp')
-rw-r--r-- | host/lib/usrp/b200/b200_iface.cpp | 170 |
1 files changed, 149 insertions, 21 deletions
diff --git a/host/lib/usrp/b200/b200_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp index 432201429..082be071c 100644 --- a/host/lib/usrp/b200/b200_iface.cpp +++ b/host/lib/usrp/b200/b200_iface.cpp @@ -1,6 +1,6 @@ // // Copyright 2012-2013 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company +// Copyright 2018-2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // @@ -15,6 +15,7 @@ #include <boost/functional/hash.hpp> #include <boost/lexical_cast.hpp> #include <boost/format.hpp> +#include <boost/filesystem.hpp> #include <libusb.h> #include <fstream> #include <string> @@ -37,6 +38,10 @@ using namespace uhd::transport; static const bool load_img_msg = true; const static uint8_t FX3_FIRMWARE_LOAD = 0xA0; + +// 32 KB - 256 bytes for EEPROM storage +constexpr size_t BOOTLOADER_MAX_SIZE = 32512; + const static uint8_t VRT_VENDOR_OUT = (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT); const static uint8_t VRT_VENDOR_IN = (LIBUSB_REQUEST_TYPE_VENDOR @@ -365,6 +370,29 @@ public: throw uhd::io_error((boost::format("Short write on set FPGA hash (expecting: %d, returned: %d)") % bytes_to_send % ret).str()); } + // Establish default largest possible control request transfer size based on operating + // USB speed + int _get_transfer_size() + { + switch (get_usb_speed()) + { + case 2: + return VREQ_DEFAULT_SIZE; + case 3: + return VREQ_MAX_SIZE_USB3; + default: + throw uhd::io_error( + "load_fpga: get_usb_speed returned invalid USB speed (not 2 or 3)."); + } + } + + size_t _get_file_size(const char * filename) + { + boost::filesystem::path path(filename); + auto filesize = boost::filesystem::file_size(path); + return static_cast<size_t>(filesize); + } + uint32_t load_fpga(const std::string filestring, bool force) { uint8_t fx3_state = 0; @@ -378,33 +406,20 @@ public: hash_type loaded_hash; usrp_get_fpga_hash(loaded_hash); if (hash == loaded_hash and !force) return 0; - // Establish default largest possible control request transfer size based on operating USB speed - int transfer_size = VREQ_DEFAULT_SIZE; - int current_usb_speed = get_usb_speed(); - if (current_usb_speed == 3) - transfer_size = VREQ_MAX_SIZE_USB3; - else if (current_usb_speed != 2) - throw uhd::io_error("load_fpga: get_usb_speed returned invalid USB speed (not 2 or 3)."); + const int transfer_size = _get_transfer_size(); UHD_ASSERT_THROW(transfer_size <= VREQ_MAX_SIZE); unsigned char out_buff[VREQ_MAX_SIZE]; // Request loopback read, which will indicate the firmware's current control request buffer size - // Make sure that if operating as USB2, requested length is within spec - int ntoread = std::min(transfer_size, (int)sizeof(out_buff)); - int nread = fx3_control_read(B200_VREQ_LOOP, 0, 0, out_buff, ntoread, 1000); + int nread = fx3_control_read(B200_VREQ_LOOP, 0, 0, out_buff, transfer_size, 1000); if (nread < 0) throw uhd::io_error((boost::format("load_fpga: unable to complete firmware loopback request (%d: %s)") % nread % libusb_error_name(nread)).str()); - else if (nread != ntoread) - throw uhd::io_error((boost::format("load_fpga: short read on firmware loopback request (expecting: %d, returned: %d)") % ntoread % nread).str()); - transfer_size = std::min(transfer_size, nread); // Select the smaller value + else if (nread != transfer_size) + throw uhd::io_error((boost::format("load_fpga: short read on firmware loopback request (expecting: %d, returned: %d)") % transfer_size % nread).str()); - size_t file_size = 0; - { - std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); - file_size = size_t(file.tellg()); - } + const size_t file_size = _get_file_size(filename); std::ifstream file; file.open(filename, std::ios::in | std::ios::binary); @@ -481,7 +496,7 @@ public: const size_t LOG_GRANULARITY = 10; // %. Keep this an integer divisor of 100. if (load_img_msg) { - if (bytes_sent == 0) UHD_LOGGER_DEBUG("B200") << " 0%" << std::flush; + if (bytes_sent == 0) UHD_LOGGER_DEBUG("B200") << "FPGA load: 0%" << std::flush; const size_t percent_before = size_t((bytes_sent*100)/file_size) - (size_t((bytes_sent*100)/file_size) % LOG_GRANULARITY); @@ -491,7 +506,8 @@ public: (size_t((bytes_sent*100)/file_size) % LOG_GRANULARITY); if (percent_before != percent_after) { - UHD_LOGGER_DEBUG("B200") << std::setw(3) << percent_after << "%"; + UHD_LOGGER_DEBUG("B200") + << "FPGA load: " << std::setw(3) << percent_after << "%"; } } } @@ -520,6 +536,118 @@ public: return 0; } + uint32_t load_bootloader(const std::string filestring) + { + // open bootloader file + const char* filename = filestring.c_str(); + + const size_t file_size = _get_file_size(filename); + + if (file_size > BOOTLOADER_MAX_SIZE) { + throw uhd::runtime_error( + (boost::format("Bootloader img file is too large for EEPROM! (expecting: " + "less than %d actual: %d") + % BOOTLOADER_MAX_SIZE % file_size) + .str()); + } + std::ifstream file; + file.open(filename, std::ios::in | std::ios::binary); + + if (!file.good()) { + throw uhd::io_error("load_bootloader: cannot open bootloader input file."); + } + + // allocate buffer + const int transfer_size = _get_transfer_size(); + UHD_ASSERT_THROW(transfer_size <= VREQ_MAX_SIZE); + std::vector<uint8_t> out_buff(transfer_size); + + // Request loopback read, which will indicate the firmware's current control + // request buffer size + int nread = + fx3_control_read(B200_VREQ_LOOP, 0, 0, out_buff.data(), transfer_size, 1000); + if (nread < 0) { + throw uhd::io_error((boost::format("load_bootloader: unable to complete " + "firmware loopback request (%d: %s)") + % nread % libusb_error_name(nread)) + .str()); + } else if (nread != transfer_size) { + throw uhd::io_error( + (boost::format("load_bootloader: short read on firmware loopback request " + "(expecting: %d, returned: %d)") + % transfer_size % nread) + .str()); + } + // ensure FX3 is in non-error state + { + uint8_t fx3_state = get_fx3_status(); + + if (fx3_state == FX3_STATE_ERROR or fx3_state == FX3_STATE_UNDEFINED) { + return fx3_state; + } + } + + UHD_LOGGER_INFO("B200") << "Loading bootloader image: " << filestring << "..."; + + size_t bytes_sent = 0; + while (!file.eof()) { + file.read((char*)&out_buff[0], transfer_size); + const std::streamsize n = file.gcount(); + if (n == 0) + continue; + + uint16_t transfer_count = uint16_t(n); + + // Send the data to the device + int nwritten = fx3_control_write( + B200_VREQ_EEPROM_WRITE, 0, bytes_sent, out_buff.data(), transfer_count, 5000); + if (nwritten < 0) { + throw uhd::io_error( + (boost::format( + "load_bootloader: cannot write bitstream to FX3 (%d: %s)") + % nwritten % libusb_error_name(nwritten)) + .str()); + } else if (nwritten != transfer_count) { + throw uhd::io_error( + (boost::format( + "load_bootloader: short write while transferring bitstream " + "to FX3 (expecting: %d, returned: %d)") + % transfer_count % nwritten) + .str()); + } + + const size_t LOG_GRANULARITY = 10; // %. Keep this an integer divisor of 100. + + if (bytes_sent == 0) + UHD_LOGGER_DEBUG("B200") << "Bootloader load: 0%" << std::flush; + const size_t percent_before = + size_t((bytes_sent * 100) / file_size) + - (size_t((bytes_sent * 100) / file_size) % LOG_GRANULARITY); + bytes_sent += transfer_count; + const size_t percent_after = + size_t((bytes_sent * 100) / file_size) + - (size_t((bytes_sent * 100) / file_size) % LOG_GRANULARITY); + if (percent_before != percent_after) { + UHD_LOGGER_DEBUG("B200") << "Bootloader load: " << std::setw(3) << percent_after << "%"; + } + } + + file.close(); + + // ensure FX3 is in non-error state + { + uint8_t fx3_state = get_fx3_status(); + + if (fx3_state == FX3_STATE_ERROR or fx3_state == FX3_STATE_UNDEFINED) { + return fx3_state; + } + } + + UHD_LOGGER_DEBUG("B200") << "Bootloader image loaded!"; + + return 0; + } + private: usb_control::sptr _usb_ctrl; }; |