aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/b200/b200_iface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/b200/b200_iface.cpp')
-rw-r--r--host/lib/usrp/b200/b200_iface.cpp170
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;
};