diff options
Diffstat (limited to 'host/lib/usrp/b200')
-rw-r--r-- | host/lib/usrp/b200/b200_iface.cpp | 314 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_iface.hpp | 18 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 21 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.hpp | 16 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_io_impl.cpp | 34 |
5 files changed, 296 insertions, 107 deletions
diff --git a/host/lib/usrp/b200/b200_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp index 1d05e159c..5d799bf01 100644 --- a/host/lib/usrp/b200/b200_iface.cpp +++ b/host/lib/usrp/b200/b200_iface.cpp @@ -17,6 +17,7 @@ #include "b200_iface.hpp" +#include <uhd/config.hpp> #include <uhd/utils/msg.hpp> #include <uhd/exception.hpp> #include <boost/functional/hash.hpp> @@ -62,6 +63,7 @@ const static boost::uint8_t B200_VREQ_FX3_RESET = 0x99; const static boost::uint8_t B200_VREQ_EEPROM_WRITE = 0xBA; const static boost::uint8_t B200_VREQ_EEPROM_READ = 0xBB; +const static boost::uint8_t FX3_STATE_UNDEFINED = 0x00; const static boost::uint8_t FX3_STATE_FPGA_READY = 0x01; const static boost::uint8_t FX3_STATE_CONFIGURING_FPGA = 0x02; const static boost::uint8_t FX3_STATE_BUSY = 0x03; @@ -69,6 +71,11 @@ const static boost::uint8_t FX3_STATE_RUNNING = 0x04; const static boost::uint8_t FX3_STATE_UNCONFIGURED = 0x05; const static boost::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 boost::uint32_t hash_type; @@ -83,6 +90,9 @@ typedef boost::uint32_t hash_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); @@ -115,15 +125,15 @@ static hash_type generate_hash(const char *filename) * \param record a line from an Intel HEX file * \return true if record is valid, false otherwise */ -bool checksum(std::string *record) { +bool checksum(const std::string& record) { - size_t len = record->length(); + 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; + std::istringstream(record.substr(i, 2)) >> std::hex >> val; sum += val; } @@ -144,22 +154,25 @@ bool checksum(std::string *record) { * \param data output data * \return true if record is sucessfully read, false on error */ -bool parse_record(std::string *record, boost::uint16_t &len, \ +bool parse_record(const std::string& record, boost::uint16_t &len, \ boost::uint16_t &addr, boost::uint16_t &type, unsigned char* data) { unsigned int i; std::string _data; unsigned int val; - if (record->substr(0, 1) != ":") + 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; + 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; + + if (len > (2 * (record.length() - 9))) // sanity check to prevent buffer overrun + return false; for (i = 0; i < len; i++) { - std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val; + std::istringstream(record.substr(9 + 2 * i, 2)) >> std::hex >> val; data[i] = (unsigned char) val; } @@ -174,19 +187,16 @@ class b200_iface_impl : public b200_iface{ public: b200_iface_impl(usb_control::sptr usb_ctrl): - _usb_ctrl(usb_ctrl) - { + _usb_ctrl(usb_ctrl) { //NOP } - int fx3_control_write(boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, unsigned char *buff, boost::uint16_t length, - boost::int32_t timeout = 0) - { + boost::int32_t timeout = 0) { return _usb_ctrl->submit(VRT_VENDOR_OUT, // bmReqeustType request, // bRequest value, // wValue @@ -196,14 +206,12 @@ public: timeout); // timeout } - int fx3_control_read(boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, unsigned char *buff, boost::uint16_t length, - boost::int32_t timeout = 0) - { + boost::int32_t timeout = 0) { return _usb_ctrl->submit(VRT_VENDOR_IN, // bmReqeustType request, // bRequest value, // wValue @@ -213,37 +221,45 @@ public: timeout); // timeout } - - void write_i2c(boost::uint16_t addr, const byte_vector_t &bytes) + void write_i2c(UHD_UNUSED(boost::uint16_t addr), UHD_UNUSED(const byte_vector_t &bytes)) { throw uhd::not_implemented_error("b200 write i2c"); } - byte_vector_t read_i2c(boost::uint16_t addr, size_t num_bytes) + byte_vector_t read_i2c(UHD_UNUSED(boost::uint16_t addr), UHD_UNUSED(size_t num_bytes)) { throw uhd::not_implemented_error("b200 read i2c"); } void write_eeprom(boost::uint16_t addr, boost::uint16_t offset, - const byte_vector_t &bytes) - { - fx3_control_write(B200_VREQ_EEPROM_WRITE, + const byte_vector_t &bytes) { + int ret = fx3_control_write(B200_VREQ_EEPROM_WRITE, 0, offset | (boost::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( boost::uint16_t addr, boost::uint16_t offset, - size_t num_bytes - ){ + 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 < 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; } @@ -251,8 +267,7 @@ public: unsigned char *tx_data, size_t num_tx_bits, unsigned char *rx_data, - size_t num_rx_bits - ){ + size_t num_rx_bits) { int ret = 0; boost::uint16_t tx_length = num_tx_bits / 8; @@ -264,9 +279,10 @@ public: 0x00, tx_data, tx_length); } - if(ret < 0) { - throw uhd::io_error("transact_spi: fx3_control_write failed!"); - } + if (ret < 0) + throw uhd::io_error((boost::format("Failed to write SPI (%d: %s)") % ret % libusb_error_name(ret)).str()); + else if (ret != tx_length) + throw uhd::io_error((boost::format("Short write on write SPI (expecting: %d, returned: %d)") % tx_length % ret).str()); if(num_rx_bits) { @@ -275,25 +291,38 @@ public: ret = fx3_control_read(B200_VREQ_LOOP, 0x00, \ 0x00, rx_data, total_length); - if(ret < 0) { - throw uhd::io_error("transact_spi: readback failed!"); - } + if (ret < 0) + throw uhd::io_error((boost::format("Failed to readback (%d: %s)") % ret % libusb_error_name(ret)).str()); + else if (ret != total_length) + throw uhd::io_error((boost::format("Short read on readback (expecting: %d, returned: %d)") % total_length % ret).str()); } } void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64]) { - fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, 64); - int ret = 0; - for (size_t i = 0; i < 30; i++) + const int bytes_to_write = 64; + const int bytes_to_read = 64; + const size_t read_retries = 30; + + int ret = fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, bytes_to_write); + if (ret < 0) + throw uhd::io_error((boost::format("Failed to write AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str()); + else if (ret != bytes_to_write) + throw uhd::io_error((boost::format("Short write on write AD9361 (expecting: %d, returned: %d)") % bytes_to_write % ret).str()); + + for (size_t i = 0; i < read_retries; i++) { - ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, 64, 1000); - if (ret == 64) return; + ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, bytes_to_read, 1000); + if (ret < 0) + throw uhd::io_error((boost::format("Failed to read AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str()); + + if (ret == bytes_to_read) + return; } - throw uhd::io_error(str(boost::format("ad9361_transact failed with usb error: %d") % ret)); - } + throw uhd::io_error(str(boost::format("Failed to read complete AD9361 (expecting: %d, last read: %d)") % bytes_to_read % ret)); + } - void load_firmware(const std::string filestring, bool force = false) + void load_firmware(const std::string filestring, UHD_UNUSED(bool force) = false) { const char *filename = filestring.c_str(); @@ -323,8 +352,11 @@ public: std::string record; file >> record; + if (!(record.length() > 0)) + continue; + /* Check for valid Intel HEX record. */ - if (!checksum(&record) || !parse_record(&record, len, \ + if (!checksum(record) || !parse_record(record, len, \ lower_address_bits, type, data)) { throw uhd::io_error("fx3_load_firmware: bad intel hex record checksum"); } @@ -397,46 +429,75 @@ public: throw uhd::io_error("fx3_load_firmware: No EOF record found."); } - void reset_fx3(void) { unsigned char data[4]; memset(data, 0x00, sizeof(data)); + const int bytes_to_send = sizeof(data); - fx3_control_write(B200_VREQ_FX3_RESET, 0x00, 0x00, data, 4); + 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) { unsigned char data[4]; memset(data, 0x00, sizeof(data)); + const int bytes_to_send = sizeof(data); - fx3_control_write(B200_VREQ_GPIF_RESET, 0x00, 0x00, data, 4); + 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) - { + void set_fpga_reset_pin(const bool reset) { unsigned char data[4]; memset(data, (reset)? 0xFF : 0x00, sizeof(data)); UHD_THROW_INVALID_CODE_PATH(); - fx3_control_write(B200_VREQ_FPGA_RESET, 0x00, 0x00, data, 4); + // 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()); + */ } boost::uint8_t get_usb_speed(void) { unsigned char rx_data[1]; + memset(rx_data, 0x00, sizeof(rx_data)); + const int bytes_to_recv = sizeof(rx_data); - fx3_control_read(B200_VREQ_GET_USB, 0x00, 0x00, rx_data, 1); + 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<boost::uint8_t>(rx_data[0]); } - boost::uint8_t get_fx3_status(void) { unsigned char rx_data[1]; + memset(rx_data, 0x00, sizeof(rx_data)); + const int bytes_to_recv = sizeof(rx_data); - fx3_control_read(B200_VREQ_GET_STATUS, 0x00, 0x00, &rx_data[0], 1); + 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<boost::uint8_t>(rx_data[0]); } @@ -444,40 +505,72 @@ public: boost::uint16_t get_compat_num(void) { unsigned char rx_data[2]; + memset(rx_data, 0x00, sizeof(rx_data)); + const int bytes_to_recv = sizeof(rx_data); - fx3_control_read(B200_VREQ_GET_COMPAT , 0x00, 0x00, rx_data, 2); - - boost::uint16_t compat = 0x0000; - compat |= (((uint16_t) rx_data[0]) << 8); - compat |= (rx_data[1] & 0x00FF); + 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 compat; + return (((uint16_t)rx_data[0]) << 8) | rx_data[1]; } void usrp_get_firmware_hash(hash_type &hash) { - fx3_control_read(B200_VREQ_GET_FW_HASH, 0x00, 0x00, - (unsigned char*) &hash, 4, 500); + 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) { - fx3_control_write(B200_VREQ_SET_FW_HASH, 0x00, 0x00, - (unsigned char*) &hash, 4); + 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) { - fx3_control_read(B200_VREQ_GET_FPGA_HASH, 0x00, 0x00, - (unsigned char*) &hash, 4, 500); + 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) { - fx3_control_write(B200_VREQ_SET_FPGA_HASH, 0x00, 0x00, - (unsigned char*) &hash, 4); + 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()); } boost::uint32_t load_fpga(const std::string filestring) { boost::uint8_t fx3_state = 0; boost::uint32_t wait_count; + int ret = 0; + int bytes_to_xfer = 0; const char *filename = filestring.c_str(); @@ -485,9 +578,27 @@ public: hash_type loaded_hash; usrp_get_fpga_hash(loaded_hash); if (hash == loaded_hash) return 0; - unsigned char out_buff[64]; - memset(out_buff, 0x00, sizeof(out_buff)); - fx3_control_write(B200_VREQ_FPGA_CONFIG, 0, 0, out_buff, 1, 1000); + // 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)."); + + 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); + 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 size_t file_size = 0; { @@ -498,15 +609,26 @@ public: std::ifstream file; file.open(filename, std::ios::in | std::ios::binary); - if(!file.good()) { + 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)) { + if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) { return fx3_state; } @@ -518,13 +640,18 @@ public: if (load_img_msg) UHD_MSG(status) << "Loading FPGA image: " \ << filestring << "..." << std::flush; - fx3_control_write(B200_VREQ_FPGA_START, 0, 0, out_buff, 1, 1000); + 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)) { + if((wait_count >= 1000) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) { return fx3_state; } @@ -534,15 +661,20 @@ public: } while(fx3_state != FX3_STATE_CONFIGURING_FPGA); size_t bytes_sent = 0; - while(!file.eof()) { - file.read((char *) out_buff, sizeof(out_buff)); + while (!file.eof()) { + file.read((char *) out_buff, transfer_size); const std::streamsize n = file.gcount(); - if(n == 0) continue; + if(n == 0) + continue; boost::uint16_t transfer_count = boost::uint16_t(n); /* Send the data to the device. */ - fx3_control_write(B200_VREQ_FPGA_DATA, 0, 0, out_buff, transfer_count, 5000); + 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()); if (load_img_msg) { @@ -563,7 +695,7 @@ public: do { fx3_state = get_fx3_status(); - if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR)) { + if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) { return fx3_state; } @@ -574,7 +706,8 @@ public: usrp_set_fpga_hash(hash); - if (load_img_msg) UHD_MSG(status) << "\b\b\b\b done" << std::endl; + if (load_img_msg) + UHD_MSG(status) << "\b\b\b\b done" << std::endl; return 0; } @@ -583,6 +716,29 @@ private: usb_control::sptr _usb_ctrl; }; + +std::string b200_iface::fx3_state_string(boost::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 **********************************************************************/ diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp index 1247d1f86..20b4a7a89 100644 --- a/host/lib/usrp/b200/b200_iface.hpp +++ b/host/lib/usrp/b200/b200_iface.hpp @@ -25,7 +25,17 @@ #include <boost/utility.hpp> #include "ad9361_ctrl.hpp" -class b200_iface: boost::noncopyable, public virtual uhd::i2c_iface, +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; + +static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex"; +static const std::string B200_FPGA_FILE_NAME = "usrp_b200_fpga.bin"; +static const std::string B210_FPGA_FILE_NAME = "usrp_b210_fpga.bin"; + +class UHD_API b200_iface: boost::noncopyable, public virtual uhd::i2c_iface, public ad9361_ctrl_iface_type { public: typedef boost::shared_ptr<b200_iface> sptr; @@ -64,6 +74,12 @@ 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; + + static std::string fx3_state_string(boost::uint8_t state); }; diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 0da388b93..132b1198d 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; @@ -252,7 +255,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr) //////////////////////////////////////////////////////////////////// _async_task_data.reset(new AsyncTaskData()); _async_task_data->async_md.reset(new async_md_type(1000/*messages deep*/)); - _async_task = uhd::task::make(boost::bind(&b200_impl::handle_async_task, this, _ctrl_transport, _async_task_data)); + _async_task = uhd::msg_task::make(boost::bind(&b200_impl::handle_async_task, this, _ctrl_transport, _async_task_data)); //////////////////////////////////////////////////////////////////// // Local control endpoint @@ -474,7 +477,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr) b200_impl::~b200_impl(void) { - UHD_SAFE_CALL + UHD_SAFE_CALL ( _async_task.reset(); ) @@ -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/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 818906e60..bee42679b 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -44,13 +44,9 @@ #include <uhd/transport/bounded_buffer.hpp> #include <boost/weak_ptr.hpp> #include "recv_packet_demuxer_3000.hpp" - -static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex"; -static const std::string B200_FPGA_FILE_NAME = "usrp_b200_fpga.bin"; -static const std::string B210_FPGA_FILE_NAME = "usrp_b210_fpga.bin"; -static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x03; +static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x04; static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0x00; -static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x02; +static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x03; static const double B200_LINK_RATE_BPS = (5e9)/8; //practical link rate (5 Gbps) static const double B200_BUS_CLOCK_RATE = 100e6; static const double B200_DEFAULT_TICK_RATE = 32e6; @@ -120,7 +116,7 @@ struct b200_impl : public uhd::device boost::weak_ptr<uhd::tx_streamer> _tx_streamer; //async ctrl + msgs - uhd::task::sptr _async_task; + uhd::msg_task::sptr _async_task; typedef uhd::transport::bounded_buffer<uhd::async_metadata_t> async_md_type; struct AsyncTaskData { @@ -130,10 +126,10 @@ struct b200_impl : public uhd::device b200_uart::sptr gpsdo_uart; }; boost::shared_ptr<AsyncTaskData> _async_task_data; - void handle_async_task(uhd::transport::zero_copy_if::sptr, boost::shared_ptr<AsyncTaskData>); + boost::optional<uhd::msg_task::msg_type_t> handle_async_task(uhd::transport::zero_copy_if::sptr, boost::shared_ptr<AsyncTaskData>); - void register_loopback_self_test(wb_iface::sptr iface); - void codec_loopback_self_test(wb_iface::sptr iface); + void register_loopback_self_test(uhd::wb_iface::sptr iface); + void codec_loopback_self_test(uhd::wb_iface::sptr iface); void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &); void check_fw_compat(void); void check_fpga_compat(void); diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index d643ef855..4768aa37b 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -139,27 +139,44 @@ bool b200_impl::recv_async_msg( return _async_task_data->async_md->pop_with_timed_wait(async_metadata, timeout); } -void b200_impl::handle_async_task( +/* + * This method is constantly called in a msg_task loop. + * Incoming messages are dispatched in to the hosts radio_ctrl_cores. + * The radio_ctrl_core queues are accessed via a weak_ptr to them, stored in AsyncTaskData. + * During shutdown the radio_ctrl_core dtor's are called. + * An empty peek32(0) is sent out to flush pending async messages. + * The response to those messages can't be delivered to the ctrl_core queues anymore + * because the shared pointer corresponding to the weak_ptrs is no longer valid. + * Those stranded messages are put into a dump_queue implemented in msg_task. + * A radio_ctrl_core can search for missing messages there. + */ +boost::optional<uhd::msg_task::msg_type_t> b200_impl::handle_async_task( uhd::transport::zero_copy_if::sptr xport, boost::shared_ptr<AsyncTaskData> data ) { managed_recv_buffer::sptr buff = xport->get_recv_buff(); - if (not buff or buff->size() < 8) return; + if (not buff or buff->size() < 8) + return NULL; + const boost::uint32_t sid = uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]); - switch (sid) - { + switch (sid) { //if the packet is a control response case B200_RESP0_MSG_SID: case B200_RESP1_MSG_SID: case B200_LOCAL_RESP_SID: { - radio_ctrl_core_3000::sptr ctrl; + radio_ctrl_core_3000::sptr ctrl; if (sid == B200_RESP0_MSG_SID) ctrl = data->radio_ctrl[0].lock(); if (sid == B200_RESP1_MSG_SID) ctrl = data->radio_ctrl[1].lock(); if (sid == B200_LOCAL_RESP_SID) ctrl = data->local_ctrl.lock(); - if (ctrl) ctrl->push_response(buff->cast<const boost::uint32_t *>()); + if (ctrl){ + ctrl->push_response(buff->cast<const boost::uint32_t *>()); + } + else{ + return std::make_pair(sid, uhd::msg_task::buff_to_vector(buff->cast<boost::uint8_t *>(), buff->size() ) ); + } break; } @@ -204,6 +221,7 @@ void b200_impl::handle_async_task( default: UHD_MSG(error) << "Got a ctrl packet with unknown SID " << sid << std::endl; } + return NULL; } /*********************************************************************** @@ -231,14 +249,14 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_) //calculate packet size static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer + //+ sizeof(vrt::if_packet_info_t().tlr) //no longer using trailer - sizeof(vrt::if_packet_info_t().cid) //no class id ever used - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size; const size_t bpi = convert::get_bytes_per_item(args.otw_format); size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi)); - spp = std::min<size_t>(2000, spp); //magic maximum for framing at full rate + spp = std::min<size_t>(4092, spp); //FPGA FIFO maximum for framing at full rate //make the new streamer given the samples per packet if (not my_streamer) my_streamer = boost::make_shared<sph::recv_packet_streamer>(spp); |