diff options
Diffstat (limited to 'host/utils')
-rw-r--r-- | host/utils/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/utils/b2xx_fx3_utils.cpp | 943 | ||||
-rw-r--r-- | host/utils/uhd_images_downloader.py.in | 412 | ||||
-rw-r--r-- | host/utils/usrp_burn_mb_eeprom.cpp | 43 | ||||
-rw-r--r-- | host/utils/usrp_n2xx_simple_net_burner.cpp | 12 |
5 files changed, 736 insertions, 676 deletions
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 92df0b7cf..abf2a546b 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -50,6 +50,8 @@ IF(ENABLE_USB) b2xx_fx3_utils.cpp ) INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS}) + # Additional include directories for b2xx_fx3_utils + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/b200 ${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/common) ENDIF(ENABLE_USB) IF(LINUX AND ENABLE_USB) diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp index 36688c6c7..96cd1f3e7 100644 --- a/host/utils/b2xx_fx3_utils.cpp +++ b/host/utils/b2xx_fx3_utils.cpp @@ -34,43 +34,37 @@ #include <boost/thread/thread.hpp> #include <boost/functional/hash.hpp> +#include <b200_iface.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 <uhd/transport/usb_control.hpp> +#include <uhd/transport/usb_device_handle.hpp> +#include <uhd/exception.hpp> +#include <uhd/utils/images.hpp> namespace po = boost::program_options; namespace fs = boost::filesystem; +struct vid_pid_t { + boost::uint16_t vid; + boost::uint16_t pid; +}; +const static vid_pid_t known_vid_pids[] = { + {FX3_VID, FX3_DEFAULT_PID}, + {FX3_VID, FX3_REENUM_PID}, + {B200_VENDOR_ID, B200_PRODUCT_ID} + }; +const static std::vector<vid_pid_t> known_vid_pid_vector(known_vid_pids, known_vid_pids + (sizeof(known_vid_pids) / sizeof(known_vid_pids[0]))); +const static boost::uint8_t eeprom_init_values[] = { + 0x43, + 0x59, + 0x14, + 0xB2, + (B200_PRODUCT_ID & 0xff), + (B200_PRODUCT_ID >> 8), + (B200_VENDOR_ID & 0xff), + (B200_VENDOR_ID >> 8) + }; +const static uhd::byte_vector_t eeprom_init_value_vector(eeprom_init_values, eeprom_init_values + (sizeof(eeprom_init_values) / sizeof(eeprom_init_values[0]))); //!used with lexical cast to parse a hex string template <class T> struct to_hex{ @@ -90,657 +84,472 @@ 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) +int reset_usb() { - std::ifstream file(filename); - if (not file){ - std::cerr << std::string("cannot open input file ") + filename - << std::endl; - } - - size_t hash = 0; + /* Okay, first, we need to discover what the path is to the ehci and + * xhci device files. */ + std::set<fs::path> path_list; + path_list.insert("/sys/bus/pci/drivers/xhci-pci/"); + path_list.insert("/sys/bus/pci/drivers/ehci-pci/"); + path_list.insert("/sys/bus/pci/drivers/xhci_hcd/"); + path_list.insert("/sys/bus/pci/drivers/ehci_hcd/"); - char ch; - while (file.get(ch)) { - boost::hash_combine(hash, ch); - } - - if (not file.eof()){ - std::cerr << std::string("file error ") + filename << std::endl; - } + /* Check each of the possible paths above to find which ones this system + * uses. */ + for(std::set<fs::path>::iterator found = path_list.begin(); + found != path_list.end(); ++found) { - file.close(); - return hash_type(hash); -} + if(fs::exists(*found)) { -/*! - * 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; - } + fs::path devpath = *found; - if (sum == 0) - return true; - else - return false; -} + std::set<fs::path> globbed; + /* Now, glob all of the files in the directory. */ + fs::directory_iterator end_itr; + for(fs::directory_iterator itr(devpath); itr != end_itr; ++itr) { + globbed.insert((*itr).path()); + } -/*! - * 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; + /* Check each file path string to see if it is a device file. */ + for(std::set<fs::path>::iterator it = globbed.begin(); + it != globbed.end(); ++it) { + + std::string file = fs::path((*it).filename()).string(); + + if (file.length() < 5) + continue; + + if(file.compare(0, 5, "0000:") == 0) { + /* Un-bind the device. */ + std::fstream unbind((devpath.string() + "unbind").c_str(), + std::fstream::out); + unbind << file; + unbind.close(); + + /* Re-bind the device. */ + std::cout << "Re-binding: " << file << " in " + << devpath.string() << std::endl; + std::fstream bind((devpath.string() + "bind").c_str(), + std::fstream::out); + bind << file; + bind.close(); + } + } + } } - return true; + return 0; } +uhd::transport::usb_device_handle::sptr open_device(const boost::uint16_t vid, const boost::uint16_t pid, const bool user_supplied = false) +{ + std::vector<uhd::transport::usb_device_handle::sptr> handles; + uhd::transport::usb_device_handle::sptr handle; + vid_pid_t vp = {vid, pid}; + + try { + // try caller's VID/PID first + handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid); + if (user_supplied && handles.size() == 0) + std::cerr << (boost::format("Failed to open device with VID 0x%04x and PID 0x%04x - trying other known VID/PIDs") % vid % pid).str() << std::endl; + + // try known VID/PIDs next + for (size_t i = 0; handles.size() == 0 && i < known_vid_pid_vector.size(); i++) + { + vp = known_vid_pid_vector[i]; + handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid); + } -/*! - * 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] << " "; + if (handles.size() > 0) + { + handle = handles[0]; + std::cout << (boost::format("Device opened (VID=0x%04x,PID=0x%04x)") % vp.vid % vp.pid).str() << std::endl; } - std::cout << std::showbase << std::endl; + if (!handle) + std::cerr << "Cannot open device" << 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; + catch(const std::exception &e) { + std::cerr << "Failed to communicate with the device!" << std::endl; + #ifdef UHD_PLATFORM_WIN32 + std::cerr << "The necessary drivers are not installed. Read the UHD Transport Application Notes for details:\nhttp://files.ettus.com/uhd_docs/manual/html/transport.html" << std::endl; + #endif /* UHD_PLATFORM_WIN32 */ + handle.reset(); } -#endif - return (libusb_error) libusb_control_transfer(dev_handle, VRT_VENDOR_IN, request, \ - value, index, buff, length, timeout); + return handle; } +b200_iface::sptr make_b200_iface(const uhd::transport::usb_device_handle::sptr &handle) +{ + b200_iface::sptr b200; -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]; + try { + uhd::transport::usb_control::sptr usb_ctrl = uhd::transport::usb_control::make(handle, 0); + b200 = b200_iface::make(usb_ctrl); - fx3_control_read(dev_handle, B2XX_VREQ_GET_STATUS, 0x00, 0x00, rx_data, 1); + if (!b200) + std::cerr << "Cannot create device interface" << std::endl; + } + catch(const std::exception &e) { + std::cerr << "Failed to communicate with the device!" << std::endl; + #ifdef UHD_PLATFORM_WIN32 + std::cerr << "The necessary drivers are not installed. Read the UHD Transport Application Notes for details:\nhttp://files.ettus.com/uhd_docs/manual/html/transport.html" << std::endl; + #endif /* UHD_PLATFORM_WIN32 */ + b200.reset(); + } - return boost::lexical_cast<boost::uint8_t>(rx_data[0]); + return b200; } -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); -} +int read_eeprom(b200_iface::sptr& b200, uhd::byte_vector_t& data) +{ + try { + data = b200->read_eeprom(0x0, 0x0, 8); + } catch (std::exception &e) { + std::cerr << "Exception while reading EEPROM: " << e.what() << std::endl; + return -1; + } -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); + return 0; } -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); +int write_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data) +{ + try { + b200->write_eeprom(0x0, 0x0, data); + } catch (std::exception &e) { + std::cerr << "Exception while writing EEPROM: " << e.what() << std::endl; + return -1; } - boost::uint8_t fx3_state = 0; - - const char *filename = filestring.c_str(); + return 0; +} - hash_type hash = generate_hash(filename); - hash_type loaded_hash; usrp_get_fpga_hash(dev_handle, loaded_hash); - if (hash == loaded_hash) return 0; +int verify_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data) +{ + bool verified = true; + uhd::byte_vector_t read_bytes; + if (read_eeprom(b200, read_bytes)) + return -1; - size_t file_size = 0; + if (data.size() != read_bytes.size()) { - std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); - file_size = file.tellg(); + std::cerr << "ERROR: Only able to verify first " << std::min(data.size(), read_bytes.size()) << " bytes." << std::endl; + verified = false; } - 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); + for (size_t i = 0; i < std::min(data.size(), read_bytes.size()); i++) { + if (data[i] != read_bytes[i]) { + verified = false; + std::cerr << "Byte " << i << " Expected: " << data[i] << ", Got: " << read_bytes[i] << std::endl; + } } - 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; - } + if (!verified) { + std::cerr << "Verification failed" << std::endl; + return -1; } - file.close(); + return 0; +} + +int write_and_verify_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data) +{ + if (write_eeprom(b200, data)) + return -1; + if (verify_eeprom(b200, data)) + return -1; - do { - fx3_state = get_fx3_status(dev_handle); - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - } while(fx3_state != FX3_STATE_RUNNING); + return 0; +} - usrp_set_fpga_hash(dev_handle, hash); +int erase_eeprom(b200_iface::sptr& b200) +{ + uhd::byte_vector_t bytes(8); - std::cout << "\b\b\b\b done" << std::endl; + memset(&bytes[0], 0xFF, 8); + if (write_and_verify_eeprom(b200, bytes)) + return -1; 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; + bool user_supplied_vid_pid = false; -/*! - * 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); - } + po::options_description visible("Allowed options"); + visible.add_options() + ("help,h", "help message") + ("vid,v", po::value<std::string>(&vid_str), + "Specify VID of device to use.") + ("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), + "Load a firmware (hex) file into the FX3.") + ("load-fpga,L", po::value<std::string>(&fpga_file), + "Load a FPGA (bin) file into the FPGA.") + ; - const char *filename = filestring.c_str(); + // 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"); - /* 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]; + po::options_description desc; + desc.add(visible); + desc.add(hidden); - /* 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; + po::variables_map vm; - std::ifstream file; - file.open(filename, std::ifstream::in); + try { + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + } catch (std::exception &e) { + std::cerr << "Exception while parsing arguments: " << e.what() << std::endl; + std::cout << boost::format("B2xx Utility Program %s") % visible << std::endl; + return ~0; + } - if(!file.good()) { - std::cerr << "fx3_load_firmware: cannot open firmware input file" - << std::endl; - exit(-1); + if (vm.count("help")){ + try { + std::cout << boost::format("B2xx Utility Program %s") % visible << std::endl; + } catch(...) {} + return ~0; } - std::cout << "Loading firmware image: " \ - << filestring << "..." << std::flush; + if (vm.count("reset-usb")) { + return reset_usb(); + } - while (!file.eof()) { - boost::int32_t ret = 0; - std::string record; - file >> record; + uhd::transport::usb_device_handle::sptr handle; + b200_iface::sptr b200; - /* 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; + vid = B200_VENDOR_ID; // Default + pid = B200_PRODUCT_ID; // Default + if (vm.count("vid") && vm.count("pid")) + { + try { + vid = atoh(vid_str); + pid = atoh(pid_str); + } catch (std::exception &e) { + std::cerr << "Exception while parsing VID and PID: " << e.what() << std:: endl; + return ~0; } + user_supplied_vid_pid = true; + } - /* 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; - } - } + // open the device + handle = open_device(vid, pid, user_supplied_vid_pid); + if (!handle) + return -1; + std::cout << "B2xx detected..." << std::flush; - /* 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; - } + // make the interface + b200 = make_b200_iface(handle); + if (!b200) + return -1; + std::cout << " Control of B2xx granted..." << std::endl << std::endl; - /* Successful termination! */ - file.close(); + // if we are supposed to load a new firmware image and one already exists, reset the FX3 so we can load the new one + if (vm.count("load-fw") && handle->firmware_loaded()) + { + std::cout << "Overwriting existing firmware" << std::endl; - /* Let the system settle. */ - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - return 0; + // before we reset, make sure we have a good firmware file + if(!(fs::exists(fw_file))) + { + std::cerr << "Invalid firmware filepath: " << fw_file << std::endl; + return -1; } - /* 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)); + // reset the device + try { + b200->reset_fx3(); + } catch (std::exception &e) { + std::cerr << "Exception while reseting FX3: " << e.what() << std::endl; } - /* 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; - } + // re-open device + b200.reset(); + handle.reset(); + boost::this_thread::sleep(boost::posix_time::seconds(2)); // wait 2 seconds for FX3 to reset + handle = open_device(vid, pid); + if (!handle) + return -1; + b200 = make_b200_iface(handle); + if (!b200) + return -1; + } - /* 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)); + // Check to make sure firmware is loaded + if (!(handle->firmware_loaded())) + { + std::cout << "Loading firmware" << std::endl; - fx3_control_write(dev_handle, FX3_FIRMWARE_LOAD, lower_address_bits, \ - upper_address_bits, 0, 0); + if (fw_file.empty()) + fw_file = uhd::find_image_path(B200_FW_FILE_NAME); - std::cout << " done" << std::endl; + if(fw_file.empty()) { + std::cerr << "Firmware image not found!" << std::endl; + return -1; } - /* If we receive an unknown record type, error out. */ - else { - std::cerr << "fx3_load_firmware: unsupported record type." << std::endl; + if(!(fs::exists(fw_file))) { + std::cerr << "Invalid filepath: " << fw_file << std::endl; + return -1; } - } - - /* There was no valid EOF. */ - std::cerr << "fx3_load_firmware: No EOF record found." << std::cout; - return ~0; -} + // load firmware + try { + b200->load_firmware(fw_file); + } catch (std::exception &e) { + std::cerr << "Exception while loading firmware: " << e.what() << std::endl; + 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; + // re-open device + b200.reset(); + handle.reset(); + handle = open_device(vid, pid); + if (!handle) + return -1; + b200 = make_b200_iface(handle); + if (!b200) + return -1; - po::options_description desc("Allowed options"); - desc.add_options() - ("help,h", "help message") - ("vid,v", po::value<std::string>(&vid_str)->default_value("0x2500"), - "Specify VID of device to use.") - ("pid,p", po::value<std::string>(&pid_str)->default_value("0x0020"), - "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 a firmware (hex) file into the FX3.") - ("load-fpga,L", po::value<std::string>(&fpga_file)->default_value(""), - "Load a FPGA (bin) file into the FPGA.") - ; + std::cout << "Firmware loaded" << std::endl; + } - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); + // Added for testing purposes - not exposed + if (vm.count("read-eeprom")) + { + uhd::byte_vector_t data; - if (vm.count("help")){ - std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl; - return ~0; - } else if (vm.count("reset-usb")) { - /* Okay, first, we need to discover what the path is to the ehci and - * xhci device files. */ - std::set<fs::path> path_list; - path_list.insert("/sys/bus/pci/drivers/xhci-pci/"); - path_list.insert("/sys/bus/pci/drivers/ehci-pci/"); - path_list.insert("/sys/bus/pci/drivers/xhci_hcd/"); - path_list.insert("/sys/bus/pci/drivers/ehci_hcd/"); - - /* Check each of the possible paths above to find which ones this system - * uses. */ - for(std::set<fs::path>::iterator found = path_list.begin(); - found != path_list.end(); ++found) { - - if(fs::exists(*found)) { - - fs::path devpath = *found; - - std::set<fs::path> globbed; - - /* Now, glob all of the files in the directory. */ - fs::directory_iterator end_itr; - for(fs::directory_iterator itr(devpath); itr != end_itr; ++itr) { - globbed.insert((*itr).path()); - } + if (read_eeprom(b200, data)) + return -1; - /* Check each file path string to see if it is a device file. */ - for(std::set<fs::path>::iterator it = globbed.begin(); - it != globbed.end(); ++it) { - - std::string file = fs::path((*it).filename()).string(); - - if(file.compare(0, 5, "0000:") == 0) { - /* Un-bind the device. */ - std::fstream unbind((devpath.string() + "unbind").c_str(), - std::fstream::out); - unbind << file; - unbind.close(); - - /* Re-bind the device. */ - std::cout << "Re-binding: " << file << " in " - << devpath.string() << std::endl; - std::fstream bind((devpath.string() + "bind").c_str(), - std::fstream::out); - bind << file; - bind.close(); - } - } - } - } + for (int i = 0; i < 8; i++) + std::cout << i << ": " << boost::format("0x%X") % (int)data[i] << std::endl; return 0; } - vid = atoh(vid_str); - pid = atoh(pid_str); - - /* 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; - - libusb_init(&ctx); - libusb_set_debug(ctx, 3); - libusb_get_device_list(ctx, &devs); - - /* 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 (erase_eeprom(b200)) return -1; - } else { std::cout << "Uninitialized B2xx detected..." << std::flush; } - libusb_free_device_list(devs, 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 << "Erase Successful!" << std::endl; - if(libusb_detach_kernel_driver(dev_handle, 0) == 0) { - std::cout << " Competing Driver Destroyed!" << std::flush; - } - } - libusb_claim_interface(dev_handle, 0); - 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; - } + return 0; + } - /* 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; - 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; + // Added for testing purposes - not exposed + if (vm.count("uninit-device")) + { + // erase EEPROM + erase_eeprom(b200); - /* Now, initialize the device. */ - 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); - std::cout << "EEPROM initialized, resetting device..." + std::cout << "EEPROM uninitialized, 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); + // 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 << "Initialization Process Complete." + std::cout << "Uninitialization 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; + /* 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")) + { + /* Now, initialize the device. */ + if (write_and_verify_eeprom(b200, eeprom_init_value_vector)) return -1; - } else { std::cout << "Reactor Core Online..." << std::flush; } - libusb_free_device_list(devs, 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 << "EEPROM initialized, resetting device..." + << std::endl << std::endl; - if(libusb_detach_kernel_driver(dev_handle, 0) == 0) { - std::cout << " Competing Driver Destroyed!" << std::flush; + /* Reset the device! */ + try { + b200->reset_fx3(); + } catch (const std::exception &e) { + std::cerr << "Exception while resetting device: " << e.what() << std::endl; + return -1; } - } - /* Claim interface 0 of device. */ - error_code = (libusb_error) libusb_claim_interface(dev_handle, 0); - std::cout << " All Systems Nominal..." << std::endl << std::endl; + std::cout << "Initialization Process Complete." + << std::endl << std::endl; + return 0; + } 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); + if (vm.count("reset-device")) { + 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); - - } 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); - return ~0; + try {b200->set_fpga_reset_pin(true);} + catch (uhd::exception &e) { + std::cerr << "Exception while resetting FPGA: " << e.what() << std::endl; + return -1; } - std::cout << "Firmware load complete, releasing USB interface..." - << 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 loading FPGA: " << e.what() << std::endl; + return ~0; + } + + if (fx3_state != 0) { + std::cerr << std::flush << "Error loading FPGA. FX3 state (" + << fx3_state << "): " << b200_iface::fx3_state_string(fx3_state) << std::endl; return ~0; } std::cout << "FPGA load complete, releasing USB interface..." << std::endl; - - } 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); + std::cout << "Operation complete! I did it! I did it!" << std::endl; return 0; } diff --git a/host/utils/uhd_images_downloader.py.in b/host/utils/uhd_images_downloader.py.in index e7fc9e8a5..697bd4e16 100644 --- a/host/utils/uhd_images_downloader.py.in +++ b/host/utils/uhd_images_downloader.py.in @@ -16,117 +16,341 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import atexit -import hashlib +import sys, os, string, tempfile, math +import traceback +import shutil, hashlib, urllib2, zipfile + from optparse import OptionParser -import os -import os.path -import shutil -import string -import sys -import tempfile -import urllib2 -import zipfile + +_DEFAULT_BUFFER_SIZE = 8192 +_BASE_DIR_STRUCTURE_PARTS = ["share", "uhd", "images"] +_BASE_DIR_STRUCTURE = os.path.join(_BASE_DIR_STRUCTURE_PARTS) +_DEFAULT_INSTALL_PATH = os.path.join("@CMAKE_INSTALL_PREFIX@", *_BASE_DIR_STRUCTURE) +_AUTOGEN_IMAGES_SOURCE = "@UHD_IMAGES_DOWNLOAD_SRC@" +_AUTOGEN_IMAGES_CHECKSUM = "@UHD_IMAGES_MD5SUM@" +_IMAGES_CHECKSUM_TYPE = "md5" +_CONTACT = "support@ettus.com" def md5Checksum(filePath): - with open(filePath, 'rb') as fh: - m = hashlib.md5() - while True: - data = fh.read(8192) - if not data: - break - m.update(data) - return m.hexdigest() + try: + with open(filePath, 'rb') as fh: + m = hashlib.md5() + while True: + data = fh.read(_DEFAULT_BUFFER_SIZE) + if not data: + break + m.update(data) + return m.hexdigest() + except Exception, e: + print "Failed to calculated MD5 sum of: %s (%s)" % (filePath, e) + raise e -class temp_dir(): +_checksum_fns = { + 'md5': md5Checksum +} +class temporary_directory(): def __enter__(self): - self.name = tempfile.mkdtemp() - return self.name + try: + self.name = tempfile.mkdtemp() + return self.name + except Exception, e: + print "Failed to create a temporary directory (%s)" % (e) + raise e + + # Can return 'True' to suppress incoming exception def __exit__(self, type, value, traceback): - os.removedirs(self.name) - -if __name__ == "__main__": + try: + shutil.rmtree(self.name) + except Exception, e: + print "Could not delete temporary directory: %s (%s)" % (self.name, e) - #Command line options - parser = OptionParser() - parser.add_option("--install-location", type="string", default="", help="Set custom install location for images") - parser.add_option("--buffer-size", type="int", default=8192, help="Set download buffer size, [default=%default]",) - (options, args) = parser.parse_args() +class uhd_images_downloader(): + def __init__(self): + pass - #Configuring image download info - images_src = "@UHD_IMAGES_DOWNLOAD_SRC@" - images_zip_md5sum = "@UHD_IMAGES_MD5SUM@" - filename = images_src.split("/")[-1] - - with temp_dir() as dirname: - os.chdir(dirname) - - #Configuring image destination - if options.install_location != "": - images_dir = options.install_location - elif os.environ.get("UHD_IMAGES_DIR") != "" and os.environ.get("UHD_IMAGES_DIR") != None: - images_dir = os.environ.get("UHD_IMAGES_DIR") - else: - images_dir = "@CMAKE_INSTALL_PREFIX@/share/uhd/images" - + def download(self, images_url, filename, buffer_size=_DEFAULT_BUFFER_SIZE, print_progress=False): opener = urllib2.build_opener() opener.add_headers = [('User-Agent', 'UHD Images Downloader')] - u = opener.open(images_src) - f = open(filename, "wb") + u = opener.open(images_url) meta = u.info() filesize = float(meta.getheaders("Content-Length")[0]) - print "Downloading images from: %s" % images_src + filesize_dl = 0 - filesize_dl = 0.0 - - #Downloading file - while True: - buffer = u.read(options.buffer_size) - if not buffer: - break - - filesize_dl -= len(buffer) - f.write(buffer) + with open(filename, "wb") as f: + while True: + buffer = u.read(buffer_size) + if not buffer: + break + + f.write(buffer) - status = r"%2.2f MB/%2.2f MB (%3.2f" % (-filesize_dl/1e6, filesize/1e6, (-filesize_dl*100.)/filesize) + r"%)" - status += chr(8)*(len(status)+1) - print status, + filesize_dl += len(buffer) + + if print_progress: + status = r"%05d kB / %05d kB (%03d%%)" % (int(math.ceil(filesize_dl/1000.)), int(math.ceil(filesize/1000.)), int(math.ceil(filesize_dl*100.)/filesize)) + status += chr(8)*(len(status)+1) + print status, - f.close() - - #Checking md5sum of zip file - downloaded_zip_md5sum = md5Checksum(filename) - if images_zip_md5sum != downloaded_zip_md5sum: - print "\nMD5 checksum does not match!" - print "Expected %s, got %s" % (images_zip_md5sum, downloaded_zip_md5sum) - os.remove(filename) - os.chdir("/".join(images_dir.split("/")[:-1])) + if print_progress: + print + + return (filesize, filesize_dl) + + def check_directories(self, dirs, print_progress=False): + if dirs is None or dirs == "": + dirs = "." + dirs = os.path.abspath(dirs) + + def _check_part(head, tail=None): + if print_progress: + print "Checking: %s" % (head) + if tail is not None and tail == "": + return True + if not os.path.exists(head): + if print_progress: + print "Does not exist: %s" % (head) + return _check_part(*os.path.split(head)) + if not os.path.isdir(head): + if print_progress: + print "Is not a directory: %s" % (head) + return (False, head) + if not os.access(head, os.W_OK): + if print_progress: + print "Write permission denied on: %s" % (head) + return (False, head) + if print_progress: + print "Write permission granted on: %s" % (head) + return (True, head) + + return _check_part(dirs) + + def validate_checksum(self, checksum_fn, file_path, expecting, print_progress=False): + if checksum_fn is None: + return (True, "") + + calculated_checksum = checksum_fn(file_path) + + if (expecting is not None) and (expecting != "") and calculated_checksum != expecting: + return (False, calculated_checksum) + + return (True, calculated_checksum) + + def extract_images_archive(self, archive_path, destination=None, print_progress=False): + if not os.path.exists(archive_path): + if print_progress: + print "Path does not exist: %s" % (archive_path) + raise Exception("path does not exist: %s" % (archive_path)) + + if print_progress: + print "Archive path: %s" % (archive_path) + + (head, tail) = os.path.split(archive_path) + + if not os.access(head, os.W_OK): + if print_progress: + print "Write access denied on: %s" % (head) + raise Exception("write access denied on: %s" % (head)) + + (root, ext) = os.path.splitext(tail) + temp_dir = os.path.join(head, root) + + if print_progress: + print "Temporary extraction location: %s" % (temp_dir) + + if os.path.exists(temp_dir): + if print_progress: + print "Deleting existing location: %s" % (temp_dir) + shutil.rmtree(temp_dir) + + if print_progress: + print "Creating directory: %s" % (temp_dir) + os.mkdir(temp_dir) + + if print_progress: + print "Extracting archive %s to %s" % (archive_path, temp_dir) + + images_zip = zipfile.ZipFile(archive_path) + images_zip.extractall(temp_dir) + images_zip.close() + + return temp_dir + + def install_images(self, source, dest, keep=False, print_progress=False): + if not os.path.exists(source): + if print_progress: + print "Source path does not exist: %s" % (source) + return + + if keep: + if print_progress: + print "Not wiping directory tree (existing files will be overwritten): %s" % (dest) + elif os.path.exists(dest): + if print_progress: + print "Deleting directory tree: %s" % (dest) + shutil.rmtree(dest) + + (head, tail) = os.path.split(source) + + if print_progress: + print "Source install path: %s" % (source) + + uhd_source = os.path.join(source, tail, *_BASE_DIR_STRUCTURE_PARTS) + + if print_progress: + print "Copying files from: %s" % (uhd_source) + print "Copying files to: %s" % (dest) + + if keep: + # mgrant @ http://stackoverflow.com/questions/12683834/how-to-copy-directory-recursively-in-python-and-overwrite-all + def _recursive_overwrite(src, dest, ignore=None): + if os.path.isdir(src): + if not os.path.isdir(dest): + os.makedirs(dest) + files = os.listdir(src) + if ignore is not None: + ignored = ignore(src, files) + else: + ignored = set() + for f in files: + if f not in ignored: + _recursive_overwrite(os.path.join(src, f), os.path.join(dest, f), ignore) + else: + shutil.copyfile(src, dest) + + _recursive_overwrite(uhd_source, dest) else: - #Extracting contents of zip file - if os.path.exists("tempdir"): - shutil.rmtree("tempdir") - os.mkdir("tempdir") - - images_zip = zipfile.ZipFile(filename) - images_zip.extractall("tempdir") + shutil.copytree(uhd_source, dest) - #Removing images currently in images_dir - if os.path.exists(images_dir): - try: - shutil.rmtree(images_dir) - except: - sys.stderr.write("\nMake sure you have write permissions in the images directory.\n") - sys.exit(0) - - #Copying downloaded images into images_dir - shutil.copytree("tempdir/%s/share/uhd/images" % filename[:-4],images_dir) - - #Removing tempdir and zip file - shutil.rmtree("tempdir") - images_zip.close() - os.remove(filename) +def main(): + if os.environ.get("UHD_IMAGES_DIR") != None and os.environ.get("UHD_IMAGES_DIR") != "": + default_images_dir = os.environ.get("UHD_IMAGES_DIR") + print "UHD_IMAGES_DIR environment variable is set. Default install location: %s" % default_images_dir + else: + default_images_dir = _DEFAULT_INSTALL_PATH + + parser = OptionParser() + parser.add_option("-i", "--install-location", type="string", default=default_images_dir, + help="Set custom install location for images [default=%default]") + parser.add_option("--buffer-size", type="int", default=_DEFAULT_BUFFER_SIZE, + help="Set download buffer size [default=%default]") + parser.add_option("-u", "--url", type="string", default=_AUTOGEN_IMAGES_SOURCE, + help="Set images download location [default=%default]") + parser.add_option("-c", "--checksum", type="string", default=_AUTOGEN_IMAGES_CHECKSUM, + help="Validate images archive against this checksum (blank to skip) [default=%default]") + parser.add_option("-t", "--checksum-type", type="string", default=_IMAGES_CHECKSUM_TYPE, + help=("Select checksum hash function (options: %s) [default=%%default]" % (",".join(_checksum_fns.keys())))) + parser.add_option("-k", "--keep", action="store_true", default=False, + help="Do not clear images directory before extracting new files [default=%default]") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Enable verbose output [default=%default]") + + (options, args) = parser.parse_args() + + if options.buffer_size <= 0: + print "Invalid buffer size: %s" % (options.buffer_size) + return 1 + + checksum_fn = None + if options.checksum != "": + options.checksum_type = options.checksum_type.lower() + if not _checksum_fns.has_key(options.checksum_type): + print "Not a supported checksum function: %s" % (options.checksum_type) + return 1 + checksum_fn = _checksum_fns[options.checksum_type] + + url_parts = options.url.split("/") + if len(url_parts) <= 1 or url_parts[-1] == "": + print "Not a valid URL: %s" % (options.url) + return 1 + images_filename = url_parts[-1] + + images_dir = os.path.abspath(options.install_location) # This will use the current working directory if it's not absolute + + if options.verbose: + print "Requested install location: %s" % (options.install_location) + print "Images source: %s" % (options.url) + print "Images filename: %s" % (images_filename) + print "Images checksum: %s (%s)" % (options.checksum, _IMAGES_CHECKSUM_TYPE) + print "Final install location: %s" % (images_dir) + else: + print "Images destination: %s" % (images_dir) + + downloader = uhd_images_downloader() + + try: + (access, last_path) = downloader.check_directories(images_dir, print_progress=options.verbose) + if access: + with temporary_directory() as temp_dir: + if options.verbose: + print "Using temporary directory: %s" % (temp_dir) + + print "Downloading images from: %s" % options.url + + temp_images_dest = os.path.join(temp_dir, images_filename) + + print "Downloading images to: %s" % (temp_images_dest) + + (reported_size, downloaded_size) = downloader.download(images_url=options.url, filename=temp_images_dest, buffer_size=options.buffer_size, print_progress=True) + + if options.verbose: + print "Downloaded %d of %d bytes" % (downloaded_size, reported_size) + + (checksum_match, calculated_checksum) = downloader.validate_checksum(checksum_fn, temp_images_dest, options.checksum, print_progress=options.verbose) + + if options.verbose: + print "Calculated checksum: %s" % (calculated_checksum) + + if checksum_match: + if options.verbose: + if options.checksum == "": + print "Ignoring checksum" + else: + print "Checksum OK" + + try: + extract_path = downloader.extract_images_archive(temp_images_dest, print_progress=options.verbose) + + if options.verbose: + print "Image archive extracted to: %s" % (extract_path) + + downloader.install_images(extract_path, images_dir, options.keep, print_progress=options.verbose) + + print + print "Images successfully installed to: %s" % (images_dir) + except Exception, e: + print "Failed to install image archive: %s" % (e) + print "This is usually a permissions problem." + print "Please check your file system access rights and try again." + + if options.verbose: + traceback.print_exc() + else: + print "You can run this again with the '--verbose' flag to see more information" + print "If the problem persists, please email the output to: %s" % (_CONTACT) + else: + print "Checksum of downloaded file is not correct (not installing - see options to override)" + print "Expected: %s" % (options.checksum) + print "Calculated: %s" % (calculated_checksum) + print "Please try downloading again." + print "If the problem persists, please email the output to: %s" % (_CONTACT) + else: + print "You do not have sufficient permissions to write to: %s" % (last_path) + print "Are you root?" + except KeyboardInterrupt: + print + print "Cancelled at user request" + except Exception, e: + print "Downloader raised an unhandled exception: %s" % (e) + if options.verbose: + traceback.print_exc() + else: + print "You can run this again with the '--verbose' flag to see more information" + print "If the problem persists, please email the output to: %s" % (_CONTACT) + return 1 + + return 0 - os.chdir(images_dir) - print "\nImages successfully installed to: %s" % images_dir +if __name__ == "__main__": + sys.exit(main()) diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp index 1b13fb615..ce0879c8e 100644 --- a/host/utils/usrp_burn_mb_eeprom.cpp +++ b/host/utils/usrp_burn_mb_eeprom.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010,2013 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,9 +19,11 @@ #include <uhd/device.hpp> #include <uhd/property_tree.hpp> #include <uhd/usrp/mboard_eeprom.hpp> +#include <boost/algorithm/string.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> #include <iostream> +#include <vector> namespace po = boost::program_options; @@ -32,8 +34,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") - ("key", po::value<std::string>(&key), "the indentifier for a value in EEPROM") - ("val", po::value<std::string>(&val), "the new value to set, omit for readback") + ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\"") + ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\"") ; po::variables_map vm; @@ -55,20 +57,35 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::property_tree::sptr tree = dev->get_tree(); std::cout << std::endl; - if (true /*always readback*/){ - std::cout << "Fetching current settings from EEPROM..." << std::endl; - uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); - if (not mb_eeprom.has_key(key)){ - std::cerr << boost::format("Cannot find value for EEPROM[%s]") % key << std::endl; + //remove whitespace, split arguments and values + boost::algorithm::erase_all(key, " "); + boost::algorithm::erase_all(val, " "); + + std::vector<std::string> keys_vec, vals_vec; + boost::split(keys_vec, key, boost::is_any_of("\"',")); + boost::split(vals_vec, val, boost::is_any_of("\"',")); + + if((keys_vec.size() != vals_vec.size()) and val != "") { + //If zero values are given, then user just wants values read to them + throw std::runtime_error("Number of keys must match number of values!"); + } + + std::cout << "Fetching current settings from EEPROM..." << std::endl; + uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); + for(size_t i = 0; i < keys_vec.size(); i++){ + if (not mb_eeprom.has_key(keys_vec[i])){ + std::cerr << boost::format("Cannot find value for EEPROM[%s]") % keys_vec[i] << std::endl; return EXIT_FAILURE; } - std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % key % mb_eeprom[key] << std::endl; - std::cout << std::endl; + std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % mb_eeprom[keys_vec[i]] << std::endl; } + std::cout << std::endl; if (vm.count("val")){ - uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[key] = val; - std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % key % val << std::endl; - tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); + for(size_t i = 0; i < vals_vec.size(); i++){ + uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[keys_vec[i]] = vals_vec[i]; + std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % keys_vec[i] % vals_vec[i] << std::endl; + tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); + } std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl; std::cout << std::endl; } diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp index c3ccba173..1898ee9ae 100644 --- a/host/utils/usrp_n2xx_simple_net_burner.cpp +++ b/host/utils/usrp_n2xx_simple_net_burner.cpp @@ -468,13 +468,21 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << "Searching for specified images." << std::endl << std::endl; if(burn_fpga){ if(!use_custom_fpga) fpga_path = find_image_path(default_fpga_filename); - else validate_custom_fpga_file(filename_map[hw_rev], fpga_path); + else{ + //Replace ~ with home directory + if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME")); + validate_custom_fpga_file(filename_map[hw_rev], fpga_path); + } grab_fpga_image(fpga_path); } if(burn_fw){ if(!use_custom_fw) fw_path = find_image_path(default_fw_filename); - else validate_custom_fw_file(filename_map[hw_rev], fw_path); + else{ + //Replace ~ with home directory + if(fw_path.find("~/") == 0) fw_path.replace(0,1,getenv("HOME")); + validate_custom_fw_file(filename_map[hw_rev], fw_path); + } grab_fw_image(fw_path); } |