1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
|
//
// Copyright 2012-2013 Ettus Research LLC
// Copyright 2018-2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include "b200_iface.hpp"
#include <uhd/config.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/log.hpp>
#include <uhdlib/utils/ihex.hpp>
#include <libusb.h>
#include <stdint.h>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <chrono>
#include <cstring>
#include <fstream>
#include <functional>
#include <iomanip>
#include <string>
#include <thread>
#include <vector>
//! libusb_error_name is only in newer API
#ifndef HAVE_LIBUSB_ERROR_NAME
# define libusb_error_name(code) str(boost::format("LIBUSB_ERROR_CODE %d") % code)
#endif
using namespace uhd;
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 | LIBUSB_ENDPOINT_IN);
const static uint8_t B200_VREQ_FPGA_START = 0x02;
const static uint8_t B200_VREQ_FPGA_DATA = 0x12;
const static uint8_t B200_VREQ_GET_COMPAT = 0x15;
const static uint8_t B200_VREQ_SET_FPGA_HASH = 0x1C;
const static uint8_t B200_VREQ_GET_FPGA_HASH = 0x1D;
const static uint8_t B200_VREQ_SET_FW_HASH = 0x1E;
const static uint8_t B200_VREQ_GET_FW_HASH = 0x1F;
const static uint8_t B200_VREQ_LOOP = 0x22;
const static uint8_t B200_VREQ_FPGA_CONFIG = 0x55;
// const static uint8_t B200_VREQ_FPGA_RESET = 0x62;
const static uint8_t B200_VREQ_GPIF_RESET = 0x72;
const static uint8_t B200_VREQ_GET_USB = 0x80;
const static uint8_t B200_VREQ_GET_STATUS = 0x83;
const static uint8_t B200_VREQ_FX3_RESET = 0x99;
const static uint8_t B200_VREQ_EEPROM_WRITE = 0xBA;
const static uint8_t B200_VREQ_EEPROM_READ = 0xBB;
const static uint8_t FX3_STATE_UNDEFINED = 0x00;
const static uint8_t FX3_STATE_FPGA_READY = 0x01;
const static uint8_t FX3_STATE_CONFIGURING_FPGA = 0x02;
const static uint8_t FX3_STATE_BUSY = 0x03;
const static uint8_t FX3_STATE_RUNNING = 0x04;
const static uint8_t FX3_STATE_UNCONFIGURED = 0x05;
const static uint8_t FX3_STATE_ERROR = 0x06;
const static int VREQ_MAX_SIZE_USB2 = 64;
const static int VREQ_MAX_SIZE_USB3 = 512;
const static int VREQ_DEFAULT_SIZE = VREQ_MAX_SIZE_USB2;
const static int VREQ_MAX_SIZE = VREQ_MAX_SIZE_USB3;
typedef uint32_t hash_type;
/***********************************************************************
* Helper Functions
**********************************************************************/
/*!
* Create a file hash
* The hash will be used to identify the loaded fpga image
* \param filename file used to generate hash value
* \return hash value in a uint32_t type
*/
static hash_type generate_hash(const char* filename)
{
if (filename == NULL)
return hash_type(0);
std::ifstream file(filename);
if (not file) {
throw uhd::io_error(std::string("cannot open input file ") + filename);
}
hash_type hash = 0;
char ch;
long long count = 0;
while (file.get(ch)) {
count++;
// hash algorithm derived from boost hash_combine
// http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
hash ^= ch + 0x9e3779b9 + (hash << 6) + (hash >> 2);
}
if (count == 0) {
throw uhd::io_error(std::string("empty input file ") + filename);
}
if (not file.eof()) {
throw uhd::io_error(std::string("file error ") + filename);
}
file.close();
return hash_type(hash);
}
/***********************************************************************
* The implementation class
**********************************************************************/
class b200_iface_impl : public b200_iface
{
public:
b200_iface_impl(usb_control::sptr usb_ctrl) : _usb_ctrl(usb_ctrl)
{
// NOP
}
int fx3_control_write(uint8_t request,
uint16_t value,
uint16_t index,
unsigned char* buff,
uint16_t length,
uint32_t timeout = 0)
{
return _usb_ctrl->submit(VRT_VENDOR_OUT, // bmReqeustType
request, // bRequest
value, // wValue
index, // wIndex
buff, // data
length, // wLength
timeout); // timeout
}
int fx3_control_read(uint8_t request,
uint16_t value,
uint16_t index,
unsigned char* buff,
uint16_t length,
uint32_t timeout = 0)
{
return _usb_ctrl->submit(VRT_VENDOR_IN, // bmReqeustType
request, // bRequest
value, // wValue
index, // wIndex
buff, // data
length, // wLength
timeout); // timeout
}
void write_i2c(
UHD_UNUSED(uint16_t addr), UHD_UNUSED(const byte_vector_t& bytes)) override
{
throw uhd::not_implemented_error("b200 write i2c");
}
byte_vector_t read_i2c(
UHD_UNUSED(uint16_t addr), UHD_UNUSED(size_t num_bytes)) override
{
throw uhd::not_implemented_error("b200 read i2c");
}
void write_eeprom(uint16_t addr, uint16_t offset, const byte_vector_t& bytes) override
{
int ret = fx3_control_write(B200_VREQ_EEPROM_WRITE,
0,
offset | (uint16_t(addr) << 8),
(unsigned char*)&bytes[0],
bytes.size());
if (ret < 0)
throw uhd::io_error((boost::format("Failed to write EEPROM (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if ((size_t)ret != bytes.size())
throw uhd::io_error((
boost::format("Short write on write EEPROM (expecting: %d, returned: %d)")
% bytes.size() % ret)
.str());
}
byte_vector_t read_eeprom(uint16_t addr, uint16_t offset, size_t num_bytes) override
{
byte_vector_t recv_bytes(num_bytes);
int bytes_read = fx3_control_read(B200_VREQ_EEPROM_READ,
0,
offset | (uint16_t(addr) << 8),
(unsigned char*)&recv_bytes[0],
num_bytes);
if (bytes_read < 0)
throw uhd::io_error((boost::format("Failed to read EEPROM (%d: %s)")
% bytes_read % libusb_error_name(bytes_read))
.str());
else if ((size_t)bytes_read != num_bytes)
throw uhd::io_error(
(boost::format("Short read on read EEPROM (expecting: %d, returned: %d)")
% num_bytes % bytes_read)
.str());
return recv_bytes;
}
void load_firmware(
const std::string filestring, UHD_UNUSED(bool force) = false) override
{
if (load_img_msg) {
UHD_LOGGER_INFO("B200") << "Loading firmware image: " << filestring << "...";
}
ihex_reader file_reader(filestring);
try {
file_reader.read(std::bind(&b200_iface_impl::fx3_control_write,
this,
FX3_FIRMWARE_LOAD,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
0));
} catch (const uhd::io_error& e) {
throw uhd::io_error(
str(boost::format("Could not load firmware: \n%s") % e.what()));
}
// TODO
// usrp_set_firmware_hash(hash); //set hash before reset
/* Success! Let the system settle. */
// TODO: Replace this with a polling loop in the FX3, or find out
// what the actual, correct timeout value is.
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
void reset_fx3(void) override
{
unsigned char data[4];
memset(data, 0x00, sizeof(data));
const int bytes_to_send = sizeof(data);
int ret = fx3_control_write(B200_VREQ_FX3_RESET, 0x00, 0x00, data, bytes_to_send);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to reset FX3 (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if (ret != bytes_to_send)
throw uhd::io_error(
(boost::format("Short write on reset FX3 (expecting: %d, returned: %d)")
% bytes_to_send % ret)
.str());
}
void reset_gpif(void) override
{
unsigned char data[4];
memset(data, 0x00, sizeof(data));
const int bytes_to_send = sizeof(data);
int ret =
fx3_control_write(B200_VREQ_GPIF_RESET, 0x00, 0x00, data, bytes_to_send);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to reset GPIF (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if (ret != bytes_to_send)
throw uhd::io_error(
(boost::format("Short write on reset GPIF (expecting: %d, returned: %d)")
% bytes_to_send % ret)
.str());
}
void set_fpga_reset_pin(const bool reset) override
{
unsigned char data[4];
memset(data, (reset) ? 0xFF : 0x00, sizeof(data));
UHD_THROW_INVALID_CODE_PATH();
// Below is dead code as long as UHD_THROW_INVALID_CODE_PATH(); is declared above.
// It is preserved here in a comment in case it is needed later:
/*
const int bytes_to_send = sizeof(data);
int ret = fx3_control_write(B200_VREQ_FPGA_RESET, 0x00, 0x00, data,
bytes_to_send); if (ret < 0) throw uhd::io_error((boost::format("Failed to reset
FPGA (%d: %s)") % ret % libusb_error_name(ret)).str()); else if (ret !=
bytes_to_send) throw uhd::io_error((boost::format("Short write on reset FPGA
(expecting: %d, returned: %d)") % bytes_to_send % ret).str());
*/
}
uint8_t get_usb_speed(void) override
{
unsigned char rx_data[1];
memset(rx_data, 0x00, sizeof(rx_data));
const int bytes_to_recv = sizeof(rx_data);
int ret = fx3_control_read(B200_VREQ_GET_USB, 0x00, 0x00, rx_data, bytes_to_recv);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to get USB speed (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if (ret != bytes_to_recv)
throw uhd::io_error((
boost::format("Short read on get USB speed (expecting: %d, returned: %d)")
% bytes_to_recv % ret)
.str());
return boost::lexical_cast<uint8_t>(rx_data[0]);
}
uint8_t get_fx3_status(void) override
{
unsigned char rx_data[1];
memset(rx_data, 0x00, sizeof(rx_data));
const int bytes_to_recv = sizeof(rx_data);
int ret =
fx3_control_read(B200_VREQ_GET_STATUS, 0x00, 0x00, rx_data, bytes_to_recv);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to get FX3 status (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if (ret != bytes_to_recv)
throw uhd::io_error(
(boost::format(
"Short read on get FX3 status (expecting: %d, returned: %d)")
% bytes_to_recv % ret)
.str());
return boost::lexical_cast<uint8_t>(rx_data[0]);
}
uint16_t get_compat_num(void) override
{
unsigned char rx_data[2];
memset(rx_data, 0x00, sizeof(rx_data));
const int bytes_to_recv = sizeof(rx_data);
int ret =
fx3_control_read(B200_VREQ_GET_COMPAT, 0x00, 0x00, rx_data, bytes_to_recv);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to get compat num (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if (ret != bytes_to_recv)
throw uhd::io_error(
(boost::format(
"Short read on get compat num (expecting: %d, returned: %d)")
% bytes_to_recv % ret)
.str());
return (((uint16_t)rx_data[0]) << 8) | rx_data[1];
}
void usrp_get_firmware_hash(hash_type& hash)
{
const int bytes_to_recv = 4;
if (sizeof(hash_type) != bytes_to_recv)
throw uhd::type_error(
(boost::format("hash_type is %d bytes but transfer length is %d bytes")
% sizeof(hash_type) % bytes_to_recv)
.str());
int ret = fx3_control_read(
B200_VREQ_GET_FW_HASH, 0x00, 0x00, (unsigned char*)&hash, bytes_to_recv, 500);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to get firmware hash (%d: %s)")
% ret % libusb_error_name(ret))
.str());
else if (ret != bytes_to_recv)
throw uhd::io_error(
(boost::format(
"Short read on get firmware hash (expecting: %d, returned: %d)")
% bytes_to_recv % ret)
.str());
}
void usrp_set_firmware_hash(hash_type hash)
{
const int bytes_to_send = 4;
if (sizeof(hash_type) != bytes_to_send)
throw uhd::type_error(
(boost::format("hash_type is %d bytes but transfer length is %d bytes")
% sizeof(hash_type) % bytes_to_send)
.str());
int ret = fx3_control_write(
B200_VREQ_SET_FW_HASH, 0x00, 0x00, (unsigned char*)&hash, bytes_to_send);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to set firmware hash (%d: %s)")
% ret % libusb_error_name(ret))
.str());
else if (ret != bytes_to_send)
throw uhd::io_error(
(boost::format(
"Short write on set firmware hash (expecting: %d, returned: %d)")
% bytes_to_send % ret)
.str());
}
void usrp_get_fpga_hash(hash_type& hash)
{
const int bytes_to_recv = 4;
if (sizeof(hash_type) != bytes_to_recv)
throw uhd::type_error(
(boost::format("hash_type is %d bytes but transfer length is %d bytes")
% sizeof(hash_type) % bytes_to_recv)
.str());
int ret = fx3_control_read(B200_VREQ_GET_FPGA_HASH,
0x00,
0x00,
(unsigned char*)&hash,
bytes_to_recv,
500);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to get FPGA hash (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if (ret != bytes_to_recv)
throw uhd::io_error((
boost::format("Short read on get FPGA hash (expecting: %d, returned: %d)")
% bytes_to_recv % ret)
.str());
}
void usrp_set_fpga_hash(hash_type hash)
{
const int bytes_to_send = 4;
if (sizeof(hash_type) != bytes_to_send)
throw uhd::type_error(
(boost::format("hash_type is %d bytes but transfer length is %d bytes")
% sizeof(hash_type) % bytes_to_send)
.str());
int ret = fx3_control_write(
B200_VREQ_SET_FPGA_HASH, 0x00, 0x00, (unsigned char*)&hash, bytes_to_send);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to set FPGA hash (%d: %s)") % ret
% libusb_error_name(ret))
.str());
else if (ret != bytes_to_send)
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) override
{
uint8_t fx3_state = 0;
uint32_t wait_count;
int ret = 0;
int bytes_to_xfer = 0;
const char* filename = filestring.c_str();
hash_type hash = generate_hash(filename);
hash_type loaded_hash;
usrp_get_fpga_hash(loaded_hash);
if (hash == loaded_hash and !force)
return 0;
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
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 != transfer_size)
throw uhd::io_error(
(boost::format("load_fpga: short read on firmware loopback request "
"(expecting: %d, returned: %d)")
% transfer_size % nread)
.str());
const size_t file_size = _get_file_size(filename);
std::ifstream file;
file.open(filename, std::ios::in | std::ios::binary);
if (!file.good()) {
throw uhd::io_error("load_fpga: cannot open FPGA input file.");
}
// Zero the hash, in case we abort programming another image and revert to the
// previously programmed image
usrp_set_fpga_hash(0);
memset(out_buff, 0x00, sizeof(out_buff));
bytes_to_xfer = 1;
ret =
fx3_control_write(B200_VREQ_FPGA_CONFIG, 0, 0, out_buff, bytes_to_xfer, 1000);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to start FPGA config (%d: %s)")
% ret % libusb_error_name(ret))
.str());
else if (ret != bytes_to_xfer)
throw uhd::io_error(
(boost::format(
"Short write on start FPGA config (expecting: %d, returned: %d)")
% bytes_to_xfer % ret)
.str());
wait_count = 0;
do {
fx3_state = get_fx3_status();
if ((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR)
|| (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
wait_count++;
} while (fx3_state != FX3_STATE_FPGA_READY);
if (load_img_msg) {
UHD_LOGGER_INFO("B200") << "Loading FPGA image: " << filestring << "...";
}
bytes_to_xfer = 1;
ret =
fx3_control_write(B200_VREQ_FPGA_START, 0, 0, out_buff, bytes_to_xfer, 1000);
if (ret < 0)
throw uhd::io_error((boost::format("Failed to start FPGA bitstream (%d: %s)")
% ret % libusb_error_name(ret))
.str());
else if (ret != bytes_to_xfer)
throw uhd::io_error(
(boost::format(
"Short write on start FPGA bitstream (expecting: %d, returned: %d)")
% bytes_to_xfer % ret)
.str());
wait_count = 0;
do {
fx3_state = get_fx3_status();
if ((wait_count >= 1000) || (fx3_state == FX3_STATE_ERROR)
|| (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
wait_count++;
} while (fx3_state != FX3_STATE_CONFIGURING_FPGA);
size_t bytes_sent = 0;
while (!file.eof()) {
file.read((char*)out_buff, 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_FPGA_DATA, 0, 0, out_buff, transfer_count, 5000);
if (nwritten < 0)
throw uhd::io_error(
(boost::format("load_fpga: 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_fpga: 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 (load_img_msg) {
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);
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")
<< "FPGA load: " << std::setw(3) << percent_after << "%";
}
}
}
file.close();
wait_count = 0;
do {
fx3_state = get_fx3_status();
if ((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR)
|| (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
wait_count++;
} while (fx3_state != FX3_STATE_RUNNING);
usrp_set_fpga_hash(hash);
if (load_img_msg) {
UHD_LOGGER_DEBUG("B200") << "FPGA image loaded!";
}
return 0;
}
uint32_t load_bootloader(const std::string filestring) override
{
// 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;
};
std::string b200_iface::fx3_state_string(uint8_t state)
{
switch (state) {
case FX3_STATE_FPGA_READY:
return std::string("Ready");
case FX3_STATE_CONFIGURING_FPGA:
return std::string("Configuring FPGA");
case FX3_STATE_BUSY:
return std::string("Busy");
case FX3_STATE_RUNNING:
return std::string("Running");
case FX3_STATE_UNCONFIGURED:
return std::string("Unconfigured");
case FX3_STATE_ERROR:
return std::string("Error");
default:
break;
}
return std::string("Unknown");
}
/***********************************************************************
* Make an instance of the implementation
**********************************************************************/
b200_iface::sptr b200_iface::make(usb_control::sptr usb_ctrl)
{
return sptr(new b200_iface_impl(usb_ctrl));
}
|