diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 381 | ||||
-rwxr-xr-x | host/utils/usrp_n2xx_net_burner.py | 486 | ||||
-rw-r--r-- | host/utils/usrp_n2xx_simple_net_burner.cpp | 634 | ||||
-rw-r--r-- | host/utils/usrp_x3xx_fpga_burner.cpp | 485 |
4 files changed, 26 insertions, 1960 deletions
diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index 7bf1057ee..57d6f3cc8 100644 --- a/host/utils/octoclock_firmware_burner.cpp +++ b/host/utils/octoclock_firmware_burner.cpp @@ -15,95 +15,12 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <algorithm> -#include <csignal> -#include <iostream> -#include <fstream> -#include <stdexcept> -#include <vector> - -#include <boost/foreach.hpp> -#include <boost/asio.hpp> #include <boost/program_options.hpp> -#include <boost/assign.hpp> -#include <boost/cstdint.hpp> -#include <boost/assign/list_of.hpp> #include <boost/format.hpp> -#include <boost/filesystem.hpp> -#include <boost/thread.hpp> - -#include <uhd/device.hpp> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/types/device_addr.hpp> -#include <uhd/types/time_spec.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/safe_main.hpp> - -#include "../lib/usrp_clock/octoclock/common.h" -#include "../lib/utils/ihex.hpp" - -#define MAX_FIRMWARE_SIZE 1024*120 -#define BLOCK_SIZE 256 -#define UDP_TIMEOUT 5 +#include <iostream> -namespace fs = boost::filesystem; namespace po = boost::program_options; -using namespace uhd; -using namespace uhd::transport; - -static int num_ctrl_c = 0; -void sig_int_handler(int){ - num_ctrl_c++; - if(num_ctrl_c == 1){ - std::cout << std::endl << "Are you sure you want to abort the image burning? If you do, your " - "OctoClock device will be bricked!" << std::endl - << "Press Ctrl+C again to abort the image burning procedure." << std::endl << std::endl; - } - else{ - std::cout << std::endl << "Aborting. Your OctoClock device will be bricked." << std::endl - << "Refer to http://files.ettus.com/manual/page_octoclock.html#bootloader" << std::endl - << "for details on restoring your device." << std::endl; - exit(EXIT_FAILURE); - } -} - -boost::uint8_t firmware_image[MAX_FIRMWARE_SIZE]; -size_t firmware_size = 0; -boost::uint8_t octoclock_data[udp_simple::mtu]; -octoclock_packet_t *pkt_in = reinterpret_cast<octoclock_packet_t *>(octoclock_data); -std::string firmware_path, actual_firmware_path; -size_t num_blocks = 0; -bool hex = true; - -static uint16_t calculate_crc(boost::uint8_t* buffer, boost::uint16_t len){ - boost::uint16_t crc = 0xFFFF; - - for(size_t i = 0; i < len; i++){ - crc ^= buffer[i]; - for(boost::uint8_t j = 0; j < 8; ++j){ - if(crc & 1) crc = (crc >> 1) ^ 0xA001; - else crc = (crc >> 1); - } - } - - return crc; -} - -/* - * Functions - */ -void list_octoclocks(){ - device_addrs_t found_octoclocks = device::find(uhd::device_addr_t(), device::CLOCK); - - std::cout << "Available OctoClock devices:" << std::endl; - BOOST_FOREACH(const device_addr_t &oc, found_octoclocks){ - std::cout << " * " << oc["addr"] << std::endl; - } -} - void print_image_loader_warning(const std::string &fw_path, const po::variables_map &vm){ // Newline + indent #ifdef UHD_PLATFORM_WIN32 @@ -115,10 +32,8 @@ void print_image_loader_warning(const std::string &fw_path, const po::variables_ std::string uhd_image_loader = str(boost::format("uhd_image_loader --args=\"type=octoclock,addr=%s\"" "%s --fw-path=%s") % vm["addr"].as<std::string>() % nl % fw_path); - std::cout << "************************************************************************************************" << std::endl - << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl - << " this command:" << std::endl + << "ERROR: This utility has been removed in this version of UHD. Use this command:" << std::endl << std::endl << uhd_image_loader << std::endl << std::endl @@ -126,301 +41,21 @@ void print_image_loader_warning(const std::string &fw_path, const po::variables_ << std::endl; } -/* - * Manually find bootloader. This sends multiple packets in order to increase chances of getting - * bootloader before it switches to the application. - */ -device_addrs_t bootloader_find(const std::string &ip_addr){ - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT)); - - octoclock_packet_t pkt_out; - pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); - pkt_out.code = OCTOCLOCK_QUERY_CMD; - pkt_out.len = 0; - size_t len = 0; - - device_addrs_t addrs; - - boost::system_time comm_timeout = boost::get_system_time() + boost::posix_time::milliseconds(3000); - - while(boost::get_system_time() < comm_timeout){ - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, OCTOCLOCK_QUERY_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(OCTOCLOCK_QUERY_ACK, pkt_out, pkt_in, len) and - pkt_in->proto_ver == OCTOCLOCK_BOOTLOADER_PROTO_VER){ - addrs.push_back(device_addr_t()); - addrs[0]["type"] = "octoclock-bootloader"; - addrs[0]["addr"] = udp_transport->get_recv_addr(); - break; - } - } - - return addrs; -} - -void read_firmware(){ - std::ifstream firmware_file(actual_firmware_path.c_str(), std::ios::binary); - firmware_size = size_t(fs::file_size(actual_firmware_path)); - if(firmware_size > MAX_FIRMWARE_SIZE){ - firmware_file.close(); - throw uhd::runtime_error(str(boost::format("Firmware file too large: %d > %d") - % firmware_size % (MAX_FIRMWARE_SIZE))); - } - firmware_file.read((char*)firmware_image, firmware_size); - firmware_file.close(); - - num_blocks = (firmware_size % BLOCK_SIZE) ? ((firmware_size / BLOCK_SIZE) + 1) - : (firmware_size / BLOCK_SIZE); -} - -void burn_firmware(udp_simple::sptr udp_transport){ - octoclock_packet_t pkt_out; - pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); - pkt_out.len = (boost::uint16_t)firmware_size; - pkt_out.crc = calculate_crc(firmware_image, firmware_size); - size_t len = 0, current_pos = 0; - - //Tell OctoClock not to jump to application, wait for us instead - std::cout << "Telling OctoClock to prepare for firmware download..." << std::flush; - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, PREPARE_FW_BURN_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)) std::cout << "ready." << std::endl; - else{ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Could not get OctoClock in valid state for firmware download."); - } - - std::cout << std::endl << "Burning firmware." << std::endl; - pkt_out.code = FILE_TRANSFER_CMD; - - //Actual burning below - size_t num_tries = 0; - for(size_t i = 0; i < num_blocks; i++){ - num_tries = 0; - pkt_out.sequence++; - pkt_out.addr = i*BLOCK_SIZE; - std::cout << "\r * Progress: " << int(double(i)/double(num_blocks)*100) - << "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush; - - memset(pkt_out.data, 0, BLOCK_SIZE); - memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], BLOCK_SIZE); - - bool success = false; - while(num_tries <= 5){ - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, FILE_TRANSFER_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len)){ - success = true; - break; - } - else{ - num_tries++; - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - } - } - if(not success){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to burn firmware to OctoClock!"); - } - - current_pos += BLOCK_SIZE; - } - - std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl; -} - -void verify_firmware(udp_simple::sptr udp_transport){ - octoclock_packet_t pkt_out; - pkt_out.proto_ver = OCTOCLOCK_FW_COMPAT_NUM; - pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); - size_t len = 0, current_pos = 0; - - for(size_t i = 0; i < num_blocks; i++){ - pkt_out.sequence++; - pkt_out.addr = i*BLOCK_SIZE; - std::cout << "\r * Progress: " << int(double(i)/double(num_blocks)*100) - << "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush; - - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, READ_FW_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(READ_FW_ACK, pkt_out, pkt_in, len)){ - if(memcmp((void*)(pkt_in->data), &firmware_image[i*BLOCK_SIZE], - std::min(int(firmware_size-current_pos), BLOCK_SIZE))){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to verify OctoClock firmware!"); - } - } - else{ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to verify OctoClock firmware!"); - } - } - - std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl; -} - -bool reset_octoclock(const std::string &ip_addr){ - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT)); - - octoclock_packet_t pkt_out; - pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); - size_t len; - - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, RESET_CMD, pkt_out, len, octoclock_data); - if(not UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to place device in state to receive firmware."); - } - - boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - return (bootloader_find(ip_addr).size() == 1); -} - -void finalize(udp_simple::sptr udp_transport){ - octoclock_packet_t pkt_out; - pkt_out.len = 0; - pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); - size_t len = 0; - - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data); - if(not UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - std::cout << "no ACK. Bootloader may not have loaded application." << std::endl; - } -} - -void octoclock_convert_ihex(const std::string &hex_path, const std::string &bin_path){ - ihex_reader hex_reader(hex_path); - hex_reader.to_bin_file(bin_path); -} - -int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){ - - std::string ip_addr; +int main(int argc, const char *argv[]) +{ + std::string ip_addr, firmware_path; po::options_description desc("Allowed options"); desc.add_options() ("help", "Display this help message.") - ("addr", po::value<std::string>(&ip_addr), "Specify an IP address.") - ("fw-path", po::value<std::string>(&firmware_path), "Specify a custom firmware path.") + ("addr", po::value<std::string>(&ip_addr)->default_value("addr=1.2.3.4"), "Specify an IP address.") + ("fw-path", po::value<std::string>(&firmware_path)->default_value("path/to/firmware"), "Specify a custom firmware path.") ("list", "List all available OctoClock devices.") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); - //Print help message - if(vm.count("help")){ - std::cout << "OctoClock Firmware Burner" << std::endl << std::endl; - - std::cout << "Burns a firmware image file onto an OctoClock device. Specify" << std::endl - << "the address of the OctoClock with the --addr option. To burn" << std::endl - << "a custom firmware image, use the --fw-path option. Otherwise, the" << std::endl - << "utility will use the default image. To list all available" << std::endl - << "OctoClock devices without burning firmware, use the --list" << std::endl - << "option." << std::endl << std::endl; - - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - - //List all available devices - if(vm.count("list")){ - list_octoclocks(); - return EXIT_SUCCESS; - } - - if(not (vm.count("addr"))){ - throw uhd::runtime_error("You must specify an address with the --addr option!"); - } - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_FW_PORT)); - - //If custom path given, make sure it exists - if(vm.count("fw-path")){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(firmware_path.find("~/") == 0) firmware_path.replace(0,1,getenv("HOME")); - #endif - - if(not fs::exists(firmware_path)){ - throw uhd::runtime_error(str(boost::format("This filepath does not exist: %s") % firmware_path)); - } - } - else firmware_path = find_image_path("octoclock_r4_fw.hex"); - - //If Intel hex file detected, convert to binary - std::string ext = fs::extension(firmware_path); - if(ext == ".hex"){ - std::cout << "Found firmware at path: " << firmware_path << std::endl; - - //Write firmware .bin file to temporary directory - fs::path temp_bin = fs::path(fs::path(get_tmp_path()) / str(boost::format("octoclock_fw_%d.bin") - % time_spec_t::get_system_time().get_full_secs())); - octoclock_convert_ihex(firmware_path, temp_bin.string()); - - actual_firmware_path = temp_bin.string(); - } - else if(ext == ".bin"){ - hex = false; - actual_firmware_path = firmware_path; - std::cout << "Found firmware at path: " << firmware_path << std::endl; - } - else throw uhd::runtime_error("The firmware file has in improper extension (must be .hex or .bin)."); - - std::cout << std::endl << boost::format("Searching for OctoClock with IP address %s...") % ip_addr << std::flush; - device_addrs_t octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK); - if(octoclocks.size() == 1){ - if(octoclocks[0]["type"] == "octoclock"){ - std::cout << "found. Resetting..." << std::flush; - if(reset_octoclock(ip_addr)) std::cout << "successful." << std::endl; - else{ - std::cout << "failed." << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to reset OctoClock device into its bootloader."); - } - } - else std::cout << "found." << std::endl; - } - else{ - std::cout << "failed." << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Could not find OctoClock with given IP address!"); - } - - read_firmware(); - print_image_loader_warning(firmware_path, vm); - std::signal(SIGINT, &sig_int_handler); - - burn_firmware(udp_transport); - std::cout << "Verifying firmware." << std::endl; - verify_firmware(udp_transport); - std::cout << std::endl << "Telling OctoClock bootloader to load application..." << std::flush; - finalize(udp_transport); - std::cout << "done." << std::endl; - - std::cout << "Waiting for OctoClock to reinitialize..." << std::flush; - boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK); - if(octoclocks.size() == 1){ - if(octoclocks[0]["type"] == "octoclock-bootloader"){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Firmware did not load properly."); - } - else{ - std::cout << "found." << std::endl << std::endl - << "Successfully burned firmware." << std::endl << std::endl; - } - } - else{ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to reinitialize OctoClock."); - } - if(hex) fs::remove(actual_firmware_path); - - return EXIT_SUCCESS; + return EXIT_FAILURE; } diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py index 5605b0028..372078f91 100755 --- a/host/utils/usrp_n2xx_net_burner.py +++ b/host/utils/usrp_n2xx_net_burner.py @@ -16,8 +16,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -# TODO: make it autodetect UHD devices - import optparse import math import os @@ -29,72 +27,7 @@ import time import platform import subprocess -######################################################################## -# constants -######################################################################## -UDP_FW_UPDATE_PORT = 49154 -UDP_MAX_XFER_BYTES = 1024 -UDP_TIMEOUT = 3 -UDP_POLL_INTERVAL = 0.10 #in seconds - -USRP2_FW_PROTO_VERSION = 7 #should be unused after r6 - -#from bootloader_utils.h - -FPGA_IMAGE_SIZE_BYTES = 1572864 -FW_IMAGE_SIZE_BYTES = 31744 -SAFE_FPGA_IMAGE_LOCATION_ADDR = 0x00000000 -SAFE_FW_IMAGE_LOCATION_ADDR = 0x003F0000 -PROD_FPGA_IMAGE_LOCATION_ADDR = 0x00180000 -PROD_FW_IMAGE_LOCATION_ADDR = 0x00300000 - -FLASH_DATA_PACKET_SIZE = 256 - -#see fw_common.h -FLASH_ARGS_FMT = '!LLLLL256s' -FLASH_INFO_FMT = '!LLLLL256x' -FLASH_IP_FMT = '!LLLL260x' -FLASH_HW_REV_FMT = '!LLLL260x' - -n2xx_revs = { - 0x0a00: ["n200_r3", "n200_r2"], - 0x0a10: ["n200_r4"], - 0x0a01: ["n210_r3", "n210_r2"], - 0x0a11: ["n210_r4"] - } - -class update_id_t: - USRP2_FW_UPDATE_ID_WAT = ord(' ') - USRP2_FW_UPDATE_ID_OHAI_LOL = ord('a') - USRP2_FW_UPDATE_ID_OHAI_OMG = ord('A') - USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = ord('f') - USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = ord('F') - USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = ord('e') - USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = ord('E') - USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = ord('d') - USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = ord('D') - USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = ord('B') - USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = ord('w') - USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = ord('W') - USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = ord('r') - USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = ord('R') - USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = ord('s') - USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = ord('S') - USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL = ord('v') - USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG = ord('V') - USRP2_FW_UPDATE_ID_KTHXBAI = ord('~') - -_seq = -1 -def seq(): - global _seq - _seq = _seq+1 - return _seq - -######################################################################## -# print equivalent uhd_image_loader command -######################################################################## def print_image_loader_warning(fw, fpga, reset, safe, addr): - # Newline + indent if platform.system() == "Windows": nl = " ^\n " @@ -121,8 +54,7 @@ def print_image_loader_warning(fw, fpga, reset, safe, addr): print("") print("************************************************************************************************") - print("WARNING: This utility will be removed in an upcoming version of UHD. In the future, use") - print(" this command:") + print("ERROR: This utility has been removed in this version of UHD. Use this command:") print("") print(uhd_image_loader) print("") @@ -130,383 +62,16 @@ def print_image_loader_warning(fw, fpga, reset, safe, addr): print("") ######################################################################## -# helper functions -######################################################################## -def unpack_flash_args_fmt(s): - return struct.unpack(FLASH_ARGS_FMT, s) #(proto_ver, pktid, seq, flash_addr, length, data) - -def unpack_flash_info_fmt(s): - return struct.unpack(FLASH_INFO_FMT, s) #(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes) - -def unpack_flash_ip_fmt(s): - return struct.unpack(FLASH_IP_FMT, s) #(proto_ver, pktid, seq, ip_addr) - -def unpack_flash_hw_rev_fmt(s): - return struct.unpack(FLASH_HW_REV_FMT, s) #proto_ver, pktid, seq, hw_rev - -def pack_flash_args_fmt(proto_ver, pktid, seq, flash_addr, length, data=bytes()): - return struct.pack(FLASH_ARGS_FMT, proto_ver, pktid, seq, flash_addr, length, data) - -def pack_flash_info_fmt(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes): - return struct.pack(FLASH_INFO_FMT, proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes) - -def pack_flash_hw_rev_fmt(proto_ver, pktid, seq, hw_rev): - return struct.pack(FLASH_HW_REV_FMT, proto_ver, pktid, seq, hw_rev) - -def is_valid_fpga_image(fpga_image): - for i in range(0,63): - if fpga_image[i:i+1] == bytes(b'\xFF'): continue - if fpga_image[i:i+2] == bytes(b'\xAA\x99'): return True - return False - -def is_valid_fw_image(fw_image): - return fw_image[:4] == bytes(b'\x0B\x0B\x0B\x0B') - - -######################################################################## -# interface discovery and device enumeration -######################################################################## -def command(*args): - p = subprocess.Popen( - args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) - ret = p.wait() - verbose = p.stdout.read().decode('utf-8') - if ret != 0: raise Exception(verbose) - return verbose - -def get_interfaces(): - if(platform.system() is "Windows"): return win_get_interfaces() - else: return unix_get_interfaces() - -def unix_get_interfaces(): - ifconfig = command("/sbin/ifconfig") - ip_addr_re = "cast\D*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" - bcasts = re.findall(ip_addr_re, ifconfig) - return bcasts - -def win_get_interfaces(): - from ctypes import Structure, windll, sizeof - from ctypes import POINTER, byref - from ctypes import c_ulong, c_uint, c_ubyte, c_char - MAX_ADAPTER_DESCRIPTION_LENGTH = 128 - MAX_ADAPTER_NAME_LENGTH = 256 - MAX_ADAPTER_ADDRESS_LENGTH = 8 - class IP_ADDR_STRING(Structure): - pass - LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING) - IP_ADDR_STRING._fields_ = [ - ("next", LP_IP_ADDR_STRING), - ("ipAddress", c_char * 16), - ("ipMask", c_char * 16), - ("context", c_ulong)] - class IP_ADAPTER_INFO (Structure): - pass - LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO) - IP_ADAPTER_INFO._fields_ = [ - ("next", LP_IP_ADAPTER_INFO), - ("comboIndex", c_ulong), - ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)), - ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)), - ("addressLength", c_uint), - ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH), - ("index", c_ulong), - ("type", c_uint), - ("dhcpEnabled", c_uint), - ("currentIpAddress", LP_IP_ADDR_STRING), - ("ipAddressList", IP_ADDR_STRING), - ("gatewayList", IP_ADDR_STRING), - ("dhcpServer", IP_ADDR_STRING), - ("haveWins", c_uint), - ("primaryWinsServer", IP_ADDR_STRING), - ("secondaryWinsServer", IP_ADDR_STRING), - ("leaseObtained", c_ulong), - ("leaseExpires", c_ulong)] - GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo - GetAdaptersInfo.restype = c_ulong - GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)] - adapterList = (IP_ADAPTER_INFO * 10)() - buflen = c_ulong(sizeof(adapterList)) - rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen)) - if rc == 0: - for a in adapterList: - adNode = a.ipAddressList - while True: - #convert ipAddr and ipMask into hex addrs that can be turned into a bcast addr - try: - ipAddr = adNode.ipAddress.decode() - ipMask = adNode.ipMask.decode() - except: ipAddr = None - if ipAddr and ipMask: - hexAddr = struct.unpack("<L", socket.inet_aton(ipAddr))[0] - hexMask = struct.unpack("<L", socket.inet_aton(ipMask))[0] - if(hexAddr and hexMask): #don't broadcast on 255.255.255.255, that's just lame - yield socket.inet_ntoa(struct.pack("<L", (hexAddr & hexMask) | (~hexMask) & 0xFFFFFFFF)) - try: adNode = adNode.next - except: break - if not adNode: break - -def enumerate_devices(): - for bcast_addr in get_interfaces(): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - sock.settimeout(0.1) - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, 0, 0, 0) - sock.sendto(out_pkt, (bcast_addr, UDP_FW_UPDATE_PORT)) - still_goin = True - while(still_goin): - try: - pkt = sock.recv(UDP_MAX_XFER_BYTES) - (proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(pkt) - if(pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG): - use_addr = socket.inet_ntoa(struct.pack("<L", socket.ntohl(ip_addr))) - burner = burner_socket(use_addr, True) - yield "%s (%s)" % (socket.inet_ntoa(struct.pack("<L", socket.ntohl(ip_addr))), n2xx_revs[burner.get_hw_rev()][0]) - except socket.timeout: - still_goin = False - -######################################################################## # Burner class, holds a socket and send/recv routines ######################################################################## class burner_socket(object): - def __init__(self, addr, quiet): - self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + def __init__(self, addr): self._addr = addr - self._quiet = quiet - self._sock.settimeout(UDP_TIMEOUT) - self._sock.connect((addr, UDP_FW_UPDATE_PORT)) - self.set_callbacks(lambda *a: None, lambda *a: None) - self.init_update(quiet) #check that the device is there - self.get_hw_rev() - - def set_callbacks(self, progress_cb, status_cb): - self._progress_cb = progress_cb - self._status_cb = status_cb - - def send_and_recv(self, pkt): - self._sock.send(pkt) - return self._sock.recv(UDP_MAX_XFER_BYTES) - - #just here to validate comms - def init_update(self,quiet): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0) - try: in_pkt = self.send_and_recv(out_pkt) - except socket.timeout: raise Exception("No response from device") - (proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(in_pkt) - if pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG: - if not quiet: print("USRP-N2XX found.") - else: - raise Exception("Invalid reply received from device.") - - def get_hw_rev(self): - out_pkt = pack_flash_hw_rev_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL, seq(), 0) - in_pkt = self.send_and_recv(out_pkt) - (proto_ver, pktid, rxseq, hw_rev) = unpack_flash_hw_rev_fmt(in_pkt) - if(pktid != update_id_t.USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG): hw_rev = 0 - return socket.ntohs(hw_rev) - - memory_size_bytes = 0 - sector_size_bytes = 0 - def get_flash_info(self): - if (self.memory_size_bytes != 0) and (self.sector_size_bytes != 0): - return (self.memory_size_bytes, self.sector_size_bytes) - - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL, seq(), 0, 0) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, self.sector_size_bytes, self.memory_size_bytes) = unpack_flash_info_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - return (self.memory_size_bytes, self.sector_size_bytes) def burn_fw(self, fw, fpga, reset, safe, check_rev=True): + " Just a dummy lol " print_image_loader_warning(fw, fpga, reset, safe, self._addr) - (flash_size, sector_size) = self.get_flash_info() - hw_rev = self.get_hw_rev() - - if hw_rev in n2xx_revs: print("Hardware type: %s" % n2xx_revs[hw_rev][0]) - print("Flash size: %i\nSector size: %i\n" % (flash_size, sector_size)) - - if fpga: - #validate fpga image name against hardware rev - if(check_rev and hw_rev != 0 and not any(name in fpga for name in n2xx_revs[hw_rev])): - raise Exception("Error: incorrect FPGA image version. Please use the correct image for device %s" % n2xx_revs[hw_rev][0]) - - if safe: image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR - else: image_location = PROD_FPGA_IMAGE_LOCATION_ADDR - - fpga_file = open(fpga, 'rb') - fpga_image = fpga_file.read() - - if len(fpga_image) > FPGA_IMAGE_SIZE_BYTES: - raise Exception("Error: FPGA image file too large.") - - if not is_valid_fpga_image(fpga_image): - raise Exception("Error: Invalid FPGA image file.") - - if (len(fpga_image) + image_location) > flash_size: - raise Exception("Error: Cannot write past end of device") - - print("Begin FPGA write: this should take about 1 minute...") - start_time = time.time() - self.erase_image(image_location, FPGA_IMAGE_SIZE_BYTES) - self.write_image(fpga_image, image_location) - self.verify_image(fpga_image, image_location) - print("Time elapsed: %f seconds"%(time.time() - start_time)) - print("\n\n") - - if fw: - if safe: image_location = SAFE_FW_IMAGE_LOCATION_ADDR - else: image_location = PROD_FW_IMAGE_LOCATION_ADDR - - fw_file = open(fw, 'rb') - fw_image = fw_file.read() - - if len(fw_image) > FW_IMAGE_SIZE_BYTES: - raise Exception("Error: Firmware image file too large.") - - if not is_valid_fw_image(fw_image): - raise Exception("Error: Invalid firmware image file.") - - if (len(fw_image) + image_location) > flash_size: - raise Exception("Error: Cannot write past end of device") - - print("Begin firmware write: this should take about 1 second...") - start_time = time.time() - self.erase_image(image_location, FW_IMAGE_SIZE_BYTES) - self.write_image(fw_image, image_location) - self.verify_image(fw_image, image_location) - print("Time elapsed: %f seconds"%(time.time() - start_time)) - print("\n\n") - - if reset: self.reset_usrp() - - def write_image(self, image, addr): - print("Writing image") - self._status_cb("Writing") - writedata = image - #we split the image into smaller (256B) bits and send them down the wire - (mem_size, sector_size) = self.get_flash_info() - if (addr + len(writedata)) > mem_size: - raise Exception("Error: Cannot write past end of device") - - while writedata: - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL, seq(), addr, FLASH_DATA_PACKET_SIZE, writedata[:FLASH_DATA_PACKET_SIZE]) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - writedata = writedata[FLASH_DATA_PACKET_SIZE:] - addr += FLASH_DATA_PACKET_SIZE - self._progress_cb(float(len(image)-len(writedata))/len(image)) - - def verify_image(self, image, addr): - print("Verifying data") - self._status_cb("Verifying") - readsize = len(image) - readdata = bytes() - while readsize > 0: - if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize - else: thisreadsize = FLASH_DATA_PACKET_SIZE - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - readdata += data[:thisreadsize] - readsize -= FLASH_DATA_PACKET_SIZE - addr += FLASH_DATA_PACKET_SIZE - self._progress_cb(float(len(readdata))/len(image)) - - print("Read back %i bytes" % len(readdata)) - # print readdata - - # for i in range(256, 512): - # print "out: %i in: %i" % (ord(image[i]), ord(readdata[i])) - - if readdata != image: - raise Exception("Verify failed. Image did not write correctly.") - else: - print("Success.") - - def read_image(self, image, size, addr): - print("Reading image") - readsize = size - readdata = str() - while readsize > 0: - if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize - else: thisreadsize = FLASH_DATA_PACKET_SIZE - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - readdata += data[:thisreadsize] - readsize -= FLASH_DATA_PACKET_SIZE - addr += FLASH_DATA_PACKET_SIZE - - print("Read back %i bytes" % len(readdata)) - - #write to disk - f = open(image, 'w') - f.write(readdata) - f.close() - - def reset_usrp(self): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL, seq(), 0, 0) - try: in_pkt = self.send_and_recv(out_pkt) - except socket.timeout: return - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - if pktid == update_id_t.USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG: - raise Exception("Device failed to reset.") - - def erase_image(self, addr, length): - self._status_cb("Erasing") - #get flash info first - (flash_size, sector_size) = self.get_flash_info() - if (addr + length) > flash_size: - raise Exception("Cannot erase past end of device") - - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL, seq(), addr, length) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - print("Erasing %i bytes at %i" % (length, addr)) - start_time = time.time() - - #now wait for it to finish - while(True): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL, seq(), 0, 0) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid == update_id_t.USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG: break - elif pktid != update_id_t.USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - time.sleep(0.01) #decrease network overhead by waiting a bit before polling - self._progress_cb(min(1.0, (time.time() - start_time)/(length/80e3))) - - ######################################################################## # command line options ######################################################################## @@ -529,47 +94,4 @@ def get_options(): ######################################################################## if __name__=='__main__': options = get_options() - - if options.list: - print('Possible network devices:') - print(' ' + '\n '.join(enumerate_devices())) - #enumerate_devices() - exit() - - if not options.addr: raise Exception('no address specified') - - if not options.fpga and not options.fw and not options.reset: raise Exception('Must specify either a firmware image or FPGA image, and/or reset.') - - if options.overwrite_safe and not options.read: - print("Are you REALLY, REALLY sure you want to overwrite the safe image? This is ALMOST ALWAYS a terrible idea.") - print("If your image is faulty, your USRP2+ will become a brick until reprogrammed via JTAG.") - - python_major_version = int(platform.python_version_tuple()[0]) - if python_major_version > 2: - response = input("""Type "yes" to continue, or anything else to quit: """) - else: - response = raw_input("""Type "yes" to continue, or anything else to quit: """) - if response != "yes": sys.exit(0) - - burner = burner_socket(addr=options.addr,quiet=False) - - if options.read: - if options.fw: - file = options.fw - if os.path.isfile(file): - response = raw_input("File already exists -- overwrite? (y/n) ") - if response != "y": sys.exit(0) - size = FW_IMAGE_SIZE_BYTES - addr = SAFE_FW_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FW_IMAGE_LOCATION_ADDR - burner.read_image(file, size, addr) - - if options.fpga: - file = options.fpga - if os.path.isfile(file): - response = input("File already exists -- overwrite? (y/n) ") - if response != "y": sys.exit(0) - size = FPGA_IMAGE_SIZE_BYTES - addr = SAFE_FPGA_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FPGA_IMAGE_LOCATION_ADDR - burner.read_image(file, size, addr) - - else: burner.burn_fw(fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe, check_rev=not options.dont_check_rev) + burner_socket(options.addr).burn_fw(fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe, check_rev=not options.dont_check_rev) diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp index b105e9cb6..9077ef2f6 100644 --- a/host/utils/usrp_n2xx_simple_net_burner.cpp +++ b/host/utils/usrp_n2xx_simple_net_burner.cpp @@ -15,171 +15,11 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <csignal> -#include <iostream> -#include <fstream> -#include <time.h> -#include <vector> - -#include <boost/foreach.hpp> -#include <boost/asio.hpp> -#include <boost/filesystem.hpp> #include <boost/program_options.hpp> -#include <boost/assign.hpp> -#include <boost/assign/list_of.hpp> #include <boost/format.hpp> -#include <boost/algorithm/string/erase.hpp> -#include <boost/filesystem.hpp> -#include <boost/thread/thread.hpp> - -#include <uhd/exception.hpp> -#include <uhd/property_tree.hpp> -#include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/safe_main.hpp> -#include <uhd/utils/safe_call.hpp> +#include <iostream> -namespace fs = boost::filesystem; namespace po = boost::program_options; -using namespace boost::algorithm; -using namespace uhd; -using namespace uhd::transport; - -#define UDP_FW_UPDATE_PORT 49154 -#define UDP_MAX_XFER_BYTES 1024 -#define UDP_TIMEOUT 3 -#define UDP_POLL_INTERVAL 0.10 //in seconds -#define USRP2_FW_PROTO_VERSION 7 //should be unused after r6 -#define USRP2_UDP_UPDATE_PORT 49154 -#define FLASH_DATA_PACKET_SIZE 256 -#define FPGA_IMAGE_SIZE_BYTES 1572864 -#define FW_IMAGE_SIZE_BYTES 31744 - -#define PROD_FPGA_IMAGE_LOCATION_ADDR 0x00180000 -#define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000 - -#define PROD_FW_IMAGE_LOCATION_ADDR 0x00300000 -#define SAFE_FW_IMAGE_LOCATION_ADDR 0x003F0000 - -typedef enum { - UNKNOWN = ' ', - - USRP2_QUERY = 'a', - USRP2_ACK = 'A', - - GET_FLASH_INFO_CMD = 'f', - GET_FLASH_INFO_ACK = 'F', - - ERASE_FLASH_CMD = 'e', - ERASE_FLASH_ACK = 'E', - - CHECK_ERASING_DONE_CMD = 'd', - DONE_ERASING_ACK = 'D', - NOT_DONE_ERASING_ACK = 'B', - - WRITE_FLASH_CMD = 'w', - WRITE_FLASH_ACK = 'W', - - READ_FLASH_CMD = 'r', - READ_FLASH_ACK = 'R', - - RESET_USRP_CMD = 's', - RESET_USRP_ACK = 'S', - - GET_HW_REV_CMD = 'v', - GET_HW_REV_ACK = 'V', - -} usrp2_fw_update_id_t; - -typedef struct { - boost::uint32_t proto_ver; - boost::uint32_t id; - boost::uint32_t seq; - union { - boost::uint32_t ip_addr; - boost::uint32_t hw_rev; - struct { - boost::uint32_t flash_addr; - boost::uint32_t length; - boost::uint8_t data[256]; - } flash_args; - struct { - boost::uint32_t sector_size_bytes; - boost::uint32_t memory_size_bytes; - } flash_info_args; - } data; -} usrp2_fw_update_data_t; - -//Mapping revision numbers to filenames -uhd::dict<boost::uint32_t, std::string> filename_map = boost::assign::map_list_of - (0, "N2XX") - (0xa, "n200_r3") - (0x100a, "n200_r4") - (0x10a, "n210_r3") - (0x110a, "n210_r4") -; - -boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu]; -boost::uint8_t fpga_image[FPGA_IMAGE_SIZE_BYTES]; -boost::uint8_t fw_image[FW_IMAGE_SIZE_BYTES]; - -/*********************************************************************** - * Signal handlers - **********************************************************************/ -static int num_ctrl_c = 0; -void sig_int_handler(int){ - num_ctrl_c++; - if(num_ctrl_c == 1){ - std::cout << std::endl << "Are you sure you want to abort the image burning? If you do, your " - "USRP-N Series unit will be bricked!" << std::endl - << "Press Ctrl+C again to abort the image burning procedure." << std::endl << std::endl; - } - else{ - std::cout << std::endl << "Aborting. Your USRP-N Series unit will be bricked." << std::endl - << "Refer to http://files.ettus.com/manual/page_usrp2.html#usrp2_loadflash_brick" << std::endl - << "for details on restoring your device." << std::endl; - exit(EXIT_FAILURE); - } -} - -/*********************************************************************** - * List all connected USRP N2XX devices - **********************************************************************/ -void list_usrps(){ - udp_simple::sptr udp_bc_transport; - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - boost::uint32_t hw_rev; - - usrp2_fw_update_data_t usrp2_ack_pkt = usrp2_fw_update_data_t(); - usrp2_ack_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION); - usrp2_ack_pkt.id = htonx<boost::uint32_t>(USRP2_QUERY); - - std::cout << "Available USRP N2XX devices:" << std::endl; - - //Send UDP packets to all broadcast addresses - BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){ - //Avoid the loopback device - if(if_addrs.inet == boost::asio::ip::address_v4::loopback().to_string()) continue; - udp_bc_transport = udp_simple::make_broadcast(if_addrs.bcast, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT)); - udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt))); - - size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_ACK){ - usrp2_ack_pkt.id = htonx<boost::uint32_t>(GET_HW_REV_CMD); - udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt))); - - size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == GET_HW_REV_ACK){ - hw_rev = ntohl(update_data_in->data.hw_rev); - } - - std::cout << boost::format(" * %s (%s)\n") % udp_bc_transport->get_recv_addr() % filename_map[hw_rev]; - } - } -} /*********************************************************************** * Find USRP N2XX with specified IP address and return type @@ -225,8 +65,7 @@ void print_image_loader_warning(const std::string &fw_path, } std::cout << "************************************************************************************************" << std::endl - << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl - << " this command:" << std::endl + << "ERROR: This utility has been removed in this version of UHD. Use this command:" << std::endl << std::endl << uhd_image_loader << std::endl << std::endl @@ -234,336 +73,8 @@ void print_image_loader_warning(const std::string &fw_path, << std::endl; } -/*********************************************************************** - * Find USRP N2XX with specified IP address and return type - **********************************************************************/ -boost::uint32_t find_usrp(udp_simple::sptr udp_transport, bool check_rev){ - boost::uint32_t hw_rev; - bool found_it = false; - - // If the user chooses to not care about the rev, simply check - // for the presence of a USRP N2XX. - boost::uint32_t cmd_id = (check_rev) ? GET_HW_REV_CMD - : USRP2_QUERY; - boost::uint32_t ack_id = (check_rev) ? GET_HW_REV_ACK - : USRP2_ACK; - - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - usrp2_fw_update_data_t hw_info_pkt = usrp2_fw_update_data_t(); - hw_info_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION); - hw_info_pkt.id = htonx<boost::uint32_t>(cmd_id); - udp_transport->send(boost::asio::buffer(&hw_info_pkt, sizeof(hw_info_pkt))); - - //Loop and receive until the timeout - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == ack_id){ - hw_rev = ntohl(update_data_in->data.hw_rev); - if(filename_map.has_key(hw_rev)){ - std::cout << boost::format("Found %s.\n\n") % filename_map[hw_rev]; - found_it = true; - } - else{ - if(check_rev) throw std::runtime_error("Invalid revision found."); - else{ - hw_rev = 0; - std::cout << "Found USRP N2XX." << std::endl; - found_it = true; - } - } - } - if(not found_it) throw std::runtime_error("No USRP N2XX found."); - - return hw_rev; -} - -/*********************************************************************** - * Custom filename validation functions - **********************************************************************/ - -void validate_custom_fpga_file(std::string rev_str, std::string& fpga_path, bool check_rev){ - - //Check for existence of file - if(not fs::exists(fpga_path)) throw std::runtime_error(str(boost::format("No file at specified FPGA path: %s") % fpga_path)); - - //If user cares about revision, use revision string to detect invalid image filename - uhd::fs_path custom_fpga_path(fpga_path); - if(custom_fpga_path.leaf().find(rev_str) == std::string::npos and check_rev){ - throw std::runtime_error(str(boost::format("Invalid FPGA image filename at path: %s\nFilename must contain '%s' to be considered valid for this model.") - % fpga_path % rev_str)); - } -} - -void validate_custom_fw_file(std::string rev_str, std::string& fw_path, bool check_rev){ - - //Check for existence of file - if(not fs::exists(fw_path)) throw std::runtime_error(str(boost::format("No file at specified firmware path: %s") % fw_path)); - - //If user cares about revision, use revision string to detect invalid image filename - uhd::fs_path custom_fw_path(fw_path); - if(custom_fw_path.leaf().find(erase_tail_copy(rev_str,3)) == std::string::npos and check_rev){ - throw std::runtime_error(str(boost::format("Invalid firmware image filename at path: %s\nFilename must contain '%s' to be considered valid for this model.") - % fw_path % erase_tail_copy(rev_str,3))); - } -} - -/*********************************************************************** - * Reading and validating image binaries - **********************************************************************/ - -int read_fpga_image(std::string& fpga_path){ - - //Check size of given image - std::ifstream fpga_file(fpga_path.c_str(), std::ios::binary); - fpga_file.seekg(0, std::ios::end); - size_t fpga_image_size = size_t(fpga_file.tellg()); - if(fpga_image_size > FPGA_IMAGE_SIZE_BYTES){ - throw std::runtime_error(str(boost::format("FPGA image is too large. %d > %d") - % fpga_image_size % FPGA_IMAGE_SIZE_BYTES)); - } - - //Check sequence of bytes in image before reading - boost::uint8_t fpga_test_bytes[63]; - fpga_file.seekg(0, std::ios::beg); - fpga_file.read((char*)fpga_test_bytes,63); - bool is_good = false; - for(int i = 0; i < 63; i++){ - if(fpga_test_bytes[i] == 255) continue; - else if(fpga_test_bytes[i] == 170 and - fpga_test_bytes[i+1] == 153){ - is_good = true; - break; - } - } - if(not is_good) throw std::runtime_error("Not a valid FPGA image."); - - //With image validated, read into utility - fpga_file.seekg(0, std::ios::beg); - fpga_file.read((char*)fpga_image,fpga_image_size); - fpga_file.close(); - - //Return image size - return fpga_image_size; -} - -int read_fw_image(std::string& fw_path){ - - //Check size of given image - std::ifstream fw_file(fw_path.c_str(), std::ios::binary); - fw_file.seekg(0, std::ios::end); - size_t fw_image_size = size_t(fw_file.tellg()); - if(fw_image_size > FW_IMAGE_SIZE_BYTES){ - throw std::runtime_error(str(boost::format("Firmware image is too large. %d > %d") - % fw_image_size % FW_IMAGE_SIZE_BYTES)); - } - - //Check sequence of bytes in image before reading - boost::uint8_t fw_test_bytes[4]; - fw_file.seekg(0, std::ios::beg); - fw_file.read((char*)fw_test_bytes,4); - for(int i = 0; i < 4; i++) if(fw_test_bytes[i] != 11) throw std::runtime_error("Not a valid firmware image."); - - //With image validated, read into utility - fw_file.seekg(0, std::ios::beg); - fw_file.read((char*)fw_image,fw_image_size); - fw_file.close(); - - return fw_image_size; -} - -boost::uint32_t* get_flash_info(std::string& ip_addr){ - - boost::uint32_t *flash_info = new boost::uint32_t[2]; - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT)); - usrp2_fw_update_data_t get_flash_info_pkt = usrp2_fw_update_data_t(); - get_flash_info_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION); - get_flash_info_pkt.id = htonx<boost::uint32_t>(GET_FLASH_INFO_CMD); - udp_transport->send(boost::asio::buffer(&get_flash_info_pkt, sizeof(get_flash_info_pkt))); - - //Loop and receive until the timeout - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == GET_FLASH_INFO_ACK){ - flash_info[0] = ntohl(update_data_in->data.flash_info_args.sector_size_bytes); - flash_info[1] = ntohl(update_data_in->data.flash_info_args.memory_size_bytes); - } - else if(ntohl(update_data_in->id) != GET_FLASH_INFO_ACK){ - throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") - % ntohl(update_data_in->id))); - } - - return flash_info; -} - -/*********************************************************************** - * Image burning functions - **********************************************************************/ - -void erase_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint32_t memory_size, bool overwrite_safe){ - - boost::uint32_t image_location_addr = is_fw ? overwrite_safe ? SAFE_FW_IMAGE_LOCATION_ADDR - : PROD_FW_IMAGE_LOCATION_ADDR - : overwrite_safe ? SAFE_FPGA_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; - boost::uint32_t image_size = is_fw ? FW_IMAGE_SIZE_BYTES - : FPGA_IMAGE_SIZE_BYTES; - - //Making sure this won't attempt to erase past end of device - if((image_location_addr+image_size) > memory_size) throw std::runtime_error("Cannot erase past end of device."); - - //UDP receive buffer - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Setting up UDP packet - usrp2_fw_update_data_t erase_pkt = usrp2_fw_update_data_t(); - erase_pkt.id = htonx<boost::uint32_t>(ERASE_FLASH_CMD); - erase_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION); - erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(image_location_addr); - erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(image_size); - - //Begin erasing - udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == ERASE_FLASH_ACK){ - if(is_fw) std::cout << "Erasing firmware image." << std::endl; - else std::cout << "Erasing FPGA image." << std::endl; - } - else if(ntohl(update_data_in->id) != ERASE_FLASH_ACK){ - throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") - % ntohl(update_data_in->id))); - } - - //Check for erase completion - erase_pkt.id = htonx<boost::uint32_t>(CHECK_ERASING_DONE_CMD); - while(true){ - udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == DONE_ERASING_ACK){ - std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") - % image_size % image_location_addr; - break; - } - else if(ntohl(update_data_in->id) != NOT_DONE_ERASING_ACK){ - throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") - % ntohl(update_data_in->id))); - } - } -} - -void write_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, - boost::uint32_t memory_size, int image_size, bool overwrite_safe){ - - boost::uint32_t begin_addr = is_fw ? overwrite_safe ? SAFE_FW_IMAGE_LOCATION_ADDR - : PROD_FW_IMAGE_LOCATION_ADDR - : overwrite_safe ? SAFE_FPGA_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; - boost::uint32_t current_addr = begin_addr; - std::string type = is_fw ? "firmware" : "FPGA"; - - //Making sure this won't attempt to write past end of device - if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot write past end of device."); - - //UDP receive buffer - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Setting up UDP packet - usrp2_fw_update_data_t write_pkt = usrp2_fw_update_data_t(); - write_pkt.id = htonx<boost::uint32_t>(WRITE_FLASH_CMD); - write_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION); - write_pkt.data.flash_args.length = htonx<boost::uint32_t>(FLASH_DATA_PACKET_SIZE); - - for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){ - //Print progress - std::cout << "\rWriting " << type << " image (" - << int((double(current_addr-begin_addr)/double(image_size))*100) << "%)." << std::flush; - - write_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr); - std::copy(image+(i*FLASH_DATA_PACKET_SIZE), image+((i+1)*FLASH_DATA_PACKET_SIZE), write_pkt.data.flash_args.data); - - udp_transport->send(boost::asio::buffer(&write_pkt, sizeof(write_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != WRITE_FLASH_ACK){ - throw std::runtime_error(str(boost::format("Invalid reply %d from device.") - % ntohl(update_data_in->id))); - } - - current_addr += FLASH_DATA_PACKET_SIZE; - } - std::cout << std::flush << "\rWriting " << type << " image (100%)." << std::endl; - std::cout << boost::format(" * Successfully wrote %d bytes.\n") % image_size; -} - -void verify_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, - boost::uint32_t memory_size, int image_size, bool overwrite_safe){ - - int current_index = 0; - boost::uint32_t begin_addr = is_fw ? overwrite_safe ? SAFE_FW_IMAGE_LOCATION_ADDR - : PROD_FW_IMAGE_LOCATION_ADDR - : overwrite_safe ? SAFE_FPGA_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; - boost::uint32_t current_addr = begin_addr; - std::string type = is_fw ? "firmware" : "FPGA"; - - //Array size needs to be known at runtime, this constant is guaranteed to be larger than any firmware or FPGA image - boost::uint8_t from_usrp[FPGA_IMAGE_SIZE_BYTES]; - - //Making sure this won't attempt to read past end of device - if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot read past end of device."); - - //UDP receive buffer - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Setting up UDP packet - usrp2_fw_update_data_t verify_pkt = usrp2_fw_update_data_t(); - verify_pkt.id = htonx<boost::uint32_t>(READ_FLASH_CMD); - verify_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION); - verify_pkt.data.flash_args.length = htonx<boost::uint32_t>(FLASH_DATA_PACKET_SIZE); - - for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){ - //Print progress - std::cout << "\rVerifying " << type << " image (" - << int((double(current_addr-begin_addr)/double(image_size))*100) << "%)." << std::flush; - - verify_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr); - - udp_transport->send(boost::asio::buffer(&verify_pkt, sizeof(verify_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != READ_FLASH_ACK){ - throw std::runtime_error(str(boost::format("Invalid reply %d from device.") - % ntohl(update_data_in->id))); - } - for(int j = 0; j < FLASH_DATA_PACKET_SIZE; j++) from_usrp[current_index+j] = update_data_in->data.flash_args.data[j]; - - current_addr += FLASH_DATA_PACKET_SIZE; - current_index += FLASH_DATA_PACKET_SIZE; - } - for(int i = 0; i < image_size; i++) if(from_usrp[i] != image[i]) throw std::runtime_error("Image write failed."); - - std::cout << std::flush << "\rVerifying " << type << " image (100%)." << std::endl; - std::cout << " * Successful." << std::endl; -} - -void reset_usrp(udp_simple::sptr udp_transport){ - - //Set up UDP transport - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Set up UDP packet - usrp2_fw_update_data_t reset_pkt = usrp2_fw_update_data_t(); - reset_pkt.id = htonx<boost::uint32_t>(RESET_USRP_CMD); - reset_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION); - - //Reset USRP - udp_transport->send(boost::asio::buffer(&reset_pkt, sizeof(reset_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == RESET_USRP_ACK){ - throw std::runtime_error("USRP reset failed."); //There should be no response to this UDP packet - } - else std::cout << std::endl << "Resetting USRP." << std::endl; -} - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - +int main(int argc, char *argv[]) +{ //Establish user options std::string fw_path; std::string ip_addr; @@ -586,142 +97,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); - //Print help message - if(vm.count("help") > 0){ - std::cout << boost::format("N2XX Simple Net Burner\n"); - std::cout << boost::format("Automatically detects and burns standard firmware and FPGA images onto USRP N2XX devices.\n"); - std::cout << boost::format("Can optionally take user input for custom images.\n\n"); - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - - //List options - if(vm.count("list")){ - list_usrps(); - return EXIT_SUCCESS; - } - - //Store user options - bool burn_fpga = (vm.count("no-fpga") == 0); - bool burn_fw = (vm.count("no-fw") == 0); - bool use_custom_fpga = (vm.count("fpga") > 0); - bool use_custom_fw = (vm.count("fw") > 0); - bool auto_reboot = (vm.count("auto-reboot") > 0); - bool check_rev = (vm.count("dont-check-rev") == 0); - bool overwrite_safe = (vm.count("overwrite-safe") > 0); - int fpga_image_size = 0; - int fw_image_size = 0; - - //Process options and detect invalid option combinations - if(not burn_fpga && not burn_fw){ - std::cout << "No images will be burned." << std::endl; - return EXIT_FAILURE; - } - if(not check_rev){ - //Without knowing a revision, the utility cannot automatically generate a filepath, so the user - //must specify one. The user must also burn both types of images for consistency. - if(not (burn_fpga and burn_fw)) - throw std::runtime_error("If the --dont-check-rev option is used, both FPGA and firmware images need to be burned."); - if(not (use_custom_fpga and use_custom_fw)) - throw std::runtime_error("If the --dont-check-rev option is used, the user must specify image filepaths."); - } - if(overwrite_safe){ - //If the user specifies overwriting safe images, both image types must be burned for consistency. - if(not (burn_fpga and burn_fw)) - throw std::runtime_error("If the --overwrite-safe option is used, both FPGA and firmware images need to be burned."); - - std::cout << "Are you REALLY sure you want to overwrite the safe images?" << std::endl; - std::cout << "This is ALMOST ALWAYS a terrible idea." << std::endl; - std::cout << "Type \"yes\" to continue, or anything else to quit: " << std::flush; - std::string safe_response; - std::getline(std::cin, safe_response); - if(safe_response != "yes"){ - std::cout << "Exiting." << std::endl; - return EXIT_SUCCESS; - } - else std::cout << std::endl; //Formatting - } - - //Find USRP and establish connection - std::cout << boost::format("Searching for USRP N2XX with IP address %s.\n") % ip_addr; - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT)); - boost::uint32_t hw_rev = find_usrp(udp_transport, check_rev); - - //Check validity of file locations and binaries before attempting burn - std::cout << "Searching for specified images." << std::endl << std::endl; - if(burn_fpga){ - if(use_custom_fpga){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME")); - #endif - validate_custom_fpga_file(filename_map[hw_rev], fpga_path, check_rev); - } - else{ - std::string default_fpga_filename = str(boost::format("usrp_%s_fpga.bin") % filename_map[hw_rev]); - fpga_path = find_image_path(default_fpga_filename); - } - - fpga_image_size = read_fpga_image(fpga_path); - } - if(burn_fw){ - if(use_custom_fw){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(fw_path.find("~/") == 0) fw_path.replace(0,1,getenv("HOME")); - #endif - validate_custom_fw_file(filename_map[hw_rev], fw_path, check_rev); - } - else{ - std::string default_fw_filename = str(boost::format("usrp_%s_fw.bin") % erase_tail_copy(filename_map[hw_rev],3)); - fw_path = find_image_path(default_fw_filename); - } - - fw_image_size = read_fw_image(fw_path); - } - print_image_loader_warning(fw_path, fpga_path, vm); - std::cout << "Will burn the following images:" << std::endl; - if(burn_fw) std::cout << boost::format(" * Firmware: %s\n") % fw_path; - if(burn_fpga) std::cout << boost::format(" * FPGA: %s\n") % fpga_path; - std::cout << std::endl; - - boost::uint32_t* flash_info = get_flash_info(ip_addr); - std::cout << boost::format("Querying %s for flash information.\n") % filename_map[hw_rev]; - std::cout << boost::format(" * Flash size: %3.2f\n") % flash_info[1]; - std::cout << boost::format(" * Sector size: %3.2f\n\n") % flash_info[0]; - - //Burning images - std::signal(SIGINT, &sig_int_handler); - if(burn_fpga){ - erase_image(udp_transport, false, flash_info[1], overwrite_safe); - write_image(udp_transport, false, fpga_image, flash_info[1], fpga_image_size, overwrite_safe); - verify_image(udp_transport, false, fpga_image, flash_info[1], fpga_image_size, overwrite_safe); - } - if(burn_fpga and burn_fw) std::cout << std::endl; //Formatting - if(burn_fw){ - erase_image(udp_transport, true, flash_info[1], overwrite_safe); - write_image(udp_transport, true, fw_image, flash_info[1], fw_image_size, overwrite_safe); - verify_image(udp_transport, true, fw_image, flash_info[1], fw_image_size, overwrite_safe); - } - - delete(flash_info); - - //Reset USRP N2XX - bool reset = false; - if(auto_reboot) reset = true; - else{ - std::string user_response = "foo"; - while(user_response != "y" and user_response != "" and user_response != "n"){ - std::cout << std::endl << "Image burning successful. Reset USRP (Y/n)? "; - std::getline(std::cin, user_response); - std::transform(user_response.begin(), user_response.end(), user_response.begin(), ::tolower); - reset = (user_response == "" or user_response == "y"); - } - std::cout << std::endl; //Formatting - } - if(reset) reset_usrp(udp_transport); - - return EXIT_SUCCESS; + return EXIT_FAILURE; } diff --git a/host/utils/usrp_x3xx_fpga_burner.cpp b/host/utils/usrp_x3xx_fpga_burner.cpp index 704b291be..8f297865b 100644 --- a/host/utils/usrp_x3xx_fpga_burner.cpp +++ b/host/utils/usrp_x3xx_fpga_burner.cpp @@ -15,188 +15,14 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <csignal> #include <iostream> -#include <map> -#include <fstream> -#include <stdexcept> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <vector> - -#include <boost/foreach.hpp> -#include <boost/asio.hpp> #include <boost/program_options.hpp> -#include <boost/property_tree/ptree.hpp> -#include <boost/property_tree/xml_parser.hpp> -#include <boost/assign.hpp> -#include <boost/cstdint.hpp> -#include <boost/assign/list_of.hpp> #include <boost/format.hpp> -#include <boost/algorithm/string/erase.hpp> -#include <boost/filesystem.hpp> -#include <boost/thread/thread.hpp> - -#include <uhd/exception.hpp> -#include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/nirio/niusrprio_session.h> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/device.hpp> -#include <uhd/types/device_addr.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/safe_main.hpp> -#include <uhd/utils/safe_call.hpp> - -extern "C" { -#include "cdecode.h" -} - -#define X300_FPGA_BIN_SIZE_BYTES 15877916 -#define X300_FPGA_BIT_MAX_SIZE_BYTES 15878032 -#define X300_FPGA_PROG_UDP_PORT 49157 -#define X300_FLASH_SECTOR_SIZE 131072 -#define X300_PACKET_SIZE_BYTES 256 -#define X300_FPGA_SECTOR_START 32 -#define X300_MAX_RESPONSE_BYTES 128 -#define UDP_TIMEOUT 3 -#define FPGA_LOAD_TIMEOUT 15 -#define X300_FPGA_PROG_FLAGS_ACK 1 -#define X300_FPGA_PROG_FLAGS_ERROR 2 -#define X300_FPGA_PROG_FLAGS_INIT 4 -#define X300_FPGA_PROG_FLAGS_CLEANUP 8 -#define X300_FPGA_PROG_FLAGS_ERASE 16 -#define X300_FPGA_PROG_FLAGS_VERIFY 32 -#define X300_FPGA_PROG_CONFIGURE 64 -#define X300_FPGA_PROG_CONFIG_STATUS 128 - -namespace fs = boost::filesystem; namespace po = boost::program_options; -using namespace uhd; -using namespace uhd::transport; - -static int num_ctrl_c = 0; -void sig_int_handler(int){ - num_ctrl_c++; - if(num_ctrl_c == 1){ - std::cout << std::endl << "Are you sure you want to abort the image burning? If you do, your " - "USRP-X series device will be bricked!" << std::endl - << "Press Ctrl+C again to abort the image burning procedure." << std::endl << std::endl; - } - else{ - std::cout << std::endl << "Aborting. Your USRP X-Series device will be bricked." << std::endl - << "http://files.ettus.com/manual/page_usrp_x3x0.html#x3x0_load_fpga_imgs_jtag" << std::endl - << "for details on restoring your device." << std::endl; - exit(EXIT_FAILURE); - } -} - -typedef struct { - boost::uint32_t flags; - boost::uint32_t sector; - boost::uint32_t index; - boost::uint32_t size; - boost::uint16_t data[128]; -} x300_fpga_update_data_t; - -boost::uint8_t x300_data_in_mem[udp_simple::mtu]; -boost::uint8_t intermediary_packet_data[X300_PACKET_SIZE_BYTES]; - -boost::uint8_t bitswap(uint8_t b){ - b = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4); - b = ((b & 0xCC) >> 2) | ((b & 0x33) << 2); - b = ((b & 0xAA) >> 1) | ((b & 0x55) << 1); - - return b; -} - -void list_usrps(){ - device_addrs_t found_devices = device::find(device_addr_t("type=x300"), device::USRP); - - std::cout << "Available X3x0 devices:" << std::endl; - BOOST_FOREACH(const device_addr_t &dev, found_devices){ - std::string dev_string; - if(dev.has_key("addr")){ - dev_string = str(boost::format(" * %s (%s, addr: %s)") - % dev["product"] - % dev["fpga"] - % dev["addr"]); - } - else{ - dev_string = str(boost::format(" * %s (%s, resource: %s)") - % dev["product"] - % dev["fpga"] - % dev["resource"]); - } - std::cout << dev_string << std::endl; - } -} - -device_addr_t find_usrp_with_ethernet(std::string ip_addr, bool output){ - if(output) std::cout << "Attempting to find X3x0 with IP address: " << ip_addr << std::endl; - const device_addr_t dev = device_addr_t(str(boost::format("addr=%s") % ip_addr)); - device_addrs_t found_devices = device::find(dev, device::USRP); - - if(found_devices.size() < 1) { - throw std::runtime_error("Could not find X3x0 with the specified address!"); - } - else if(found_devices.size() > 1) { - throw std::runtime_error("Found multiple X3x0 units with the specified address!"); - } - else { - if(output) std::cout << (boost::format("Found %s (%s).\n\n") - % found_devices[0]["product"] - % found_devices[0]["fpga"]); - } - return found_devices[0]; -} - -device_addr_t find_usrp_with_pcie(std::string resource, bool output){ - if(output) std::cout << "Attempting to find X3x0 with resource: " << resource << std::endl; - const device_addr_t dev = device_addr_t(str(boost::format("resource=%s") % resource)); - device_addrs_t found_devices = device::find(dev, device::USRP); - - if(found_devices.size() < 1) { - throw std::runtime_error("Could not find X3x0 with the specified resource!"); - } - else { - if(output) std::cout << (boost::format("Found %s (%s).\n\n") - % found_devices[0]["product"] - % found_devices[0]["fpga"]); - } - return found_devices[0]; -} - -std::string get_default_image_path(std::string model, std::string image_type){ - std::transform(model.begin(), model.end(), model.begin(), ::tolower); - - std::string image_name = str(boost::format("usrp_%s_fpga_%s.bit") - % model.c_str() % image_type.c_str()); - - return find_image_path(image_name); -} - -void extract_from_lvbitx(std::string lvbitx_path, std::vector<char> &bitstream){ - boost::property_tree::ptree pt; - boost::property_tree::xml_parser::read_xml(lvbitx_path.c_str(), pt, - boost::property_tree::xml_parser::no_comments | - boost::property_tree::xml_parser::trim_whitespace); - std::string const encoded_bitstream(pt.get<std::string>("Bitfile.Bitstream")); - std::vector<char> decoded_bitstream(encoded_bitstream.size()); - - base64_decodestate decode_state; - base64_init_decodestate(&decode_state); - size_t const decoded_size = base64_decode_block(encoded_bitstream.c_str(), - encoded_bitstream.size(), &decoded_bitstream.front(), &decode_state); - decoded_bitstream.resize(decoded_size); - bitstream.swap(decoded_bitstream); -} - -void print_image_loader_warning(const std::string &fpga_path, const po::variables_map &vm){ - +void print_image_loader_warning(const std::string &fpga_path, const po::variables_map &vm) +{ // Newline + indent #ifdef UHD_PLATFORM_WIN32 const std::string nl = " ^\n "; @@ -210,11 +36,9 @@ void print_image_loader_warning(const std::string &fpga_path, const po::variable if(vm.count("addr") > 0){ uhd_image_loader += str(boost::format(",addr=%s") % vm["addr"].as<std::string>()); - if(vm.count("configure") > 0){ uhd_image_loader += ",configure"; } - if(vm.count("verify") > 0){ uhd_image_loader += ",verify"; } @@ -251,8 +75,7 @@ void print_image_loader_warning(const std::string &fpga_path, const po::variable } std::cout << "************************************************************************************************" << std::endl - << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl - << " this command:" << std::endl + << "ERROR: This utility has been removed in this version of UHD. Use this command:" << std::endl << std::endl << uhd_image_loader << std::endl << std::endl @@ -260,218 +83,17 @@ void print_image_loader_warning(const std::string &fpga_path, const po::variable << std::endl; } -void ethernet_burn(udp_simple::sptr udp_transport, std::string fpga_path, bool verify){ - boost::uint32_t max_size; - std::vector<char> bitstream; - - if(fs::extension(fpga_path) == ".bit") max_size = X300_FPGA_BIT_MAX_SIZE_BYTES; - else max_size = X300_FPGA_BIN_SIZE_BYTES; //Use for both .bin and .lvbitx - - bool is_lvbitx = (fs::extension(fpga_path) == ".lvbitx"); - - size_t fpga_image_size; - FILE* file; - if((file = fopen(fpga_path.c_str(), "rb"))){ - fseek(file, 0, SEEK_END); - if(is_lvbitx){ - extract_from_lvbitx(fpga_path, bitstream); - fpga_image_size = bitstream.size(); - } - else fpga_image_size = ftell(file); - if(fpga_image_size > max_size){ - fclose(file); - throw std::runtime_error(str(boost::format("FPGA size is too large (%d > %d).") - % fpga_image_size % max_size)); - } - rewind(file); - } - else{ - throw std::runtime_error(str(boost::format("Could not find FPGA image at location: %s") - % fpga_path.c_str())); - } - - const x300_fpga_update_data_t *update_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - x300_fpga_update_data_t ack_packet; - ack_packet.flags = htonx<boost::uint32_t>(X300_FPGA_PROG_FLAGS_ACK | X300_FPGA_PROG_FLAGS_INIT); - ack_packet.sector = 0; - ack_packet.size = 0; - ack_packet.index = 0; - memset(ack_packet.data, 0, sizeof(ack_packet.data)); - udp_transport->send(boost::asio::buffer(&ack_packet, sizeof(ack_packet))); - - udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT); - if((ntohl(update_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) != X300_FPGA_PROG_FLAGS_ERROR){ - std::cout << "Burning image: " << fpga_path << std::endl; - if(verify) std::cout << "NOTE: Verifying image. Burning will take much longer." << std::endl; - std::cout << std::endl; - } - else{ - throw std::runtime_error("Failed to start image burning! Did you specify the correct IP address? If so, power-cycle the device and try again."); - } - - size_t current_pos = 0; - size_t sectors = fpga_image_size / X300_FLASH_SECTOR_SIZE; - - //Each sector - for(size_t i = 0; i < fpga_image_size; i += X300_FLASH_SECTOR_SIZE){ - - //Print progress percentage at beginning of each sector - std::cout << "\rProgress: " << int(double(i)/double(fpga_image_size)*100) - << "% (" << (i / X300_FLASH_SECTOR_SIZE) << "/" - << sectors << " sectors)" << std::flush; - - //Each packet - for(size_t j = i; (j < fpga_image_size and j < (i+X300_FLASH_SECTOR_SIZE)); j += X300_PACKET_SIZE_BYTES){ - x300_fpga_update_data_t send_packet; - - send_packet.flags = X300_FPGA_PROG_FLAGS_ACK; - if(verify) send_packet.flags |= X300_FPGA_PROG_FLAGS_VERIFY; - if(j == i) send_packet.flags |= X300_FPGA_PROG_FLAGS_ERASE; //Erase the sector before writing - send_packet.flags = htonx<boost::uint32_t>(send_packet.flags); - - send_packet.sector = htonx<boost::uint32_t>(X300_FPGA_SECTOR_START + (i/X300_FLASH_SECTOR_SIZE)); - send_packet.index = htonx<boost::uint32_t>((j % X300_FLASH_SECTOR_SIZE) / 2); - send_packet.size = htonx<boost::uint32_t>(X300_PACKET_SIZE_BYTES / 2); - memset(intermediary_packet_data,0,X300_PACKET_SIZE_BYTES); - memset(send_packet.data,0,X300_PACKET_SIZE_BYTES); - if(!is_lvbitx) current_pos = ftell(file); - - if(current_pos + X300_PACKET_SIZE_BYTES > fpga_image_size){ - if(is_lvbitx){ - memcpy(intermediary_packet_data, (&bitstream[current_pos]), (bitstream.size()-current_pos+1)); - } - else{ - size_t len = fread(intermediary_packet_data, sizeof(boost::uint8_t), (fpga_image_size-current_pos), file); - if(len != (fpga_image_size-current_pos)){ - throw std::runtime_error("Error reading from file!"); - } - } - } - else{ - if(is_lvbitx){ - memcpy(intermediary_packet_data, (&bitstream[current_pos]), X300_PACKET_SIZE_BYTES); - current_pos += X300_PACKET_SIZE_BYTES; - } - else{ - size_t len = fread(intermediary_packet_data, sizeof(boost::uint8_t), X300_PACKET_SIZE_BYTES, file); - if(len != X300_PACKET_SIZE_BYTES){ - throw std::runtime_error("Error reading from file!"); - } - } - } - - for(size_t k = 0; k < X300_PACKET_SIZE_BYTES; k++){ - intermediary_packet_data[k] = bitswap(intermediary_packet_data[k]); - } - - memcpy(send_packet.data, intermediary_packet_data, X300_PACKET_SIZE_BYTES); - - for(size_t k = 0; k < (X300_PACKET_SIZE_BYTES/2); k++){ - send_packet.data[k] = htonx<boost::uint16_t>(send_packet.data[k]); - } - - udp_transport->send(boost::asio::buffer(&send_packet, sizeof(send_packet))); - - if (udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT) == 0) - throw std::runtime_error("Timed out waiting for ACK!"); - - const x300_fpga_update_data_t *update_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - if((ntohl(update_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) == X300_FPGA_PROG_FLAGS_ERROR){ - throw std::runtime_error("Transfer or data verification failed!"); - } - } - } - fclose(file); - - //Send clean-up signal - x300_fpga_update_data_t cleanup_packet; - cleanup_packet.flags = htonx<boost::uint32_t>(X300_FPGA_PROG_FLAGS_ACK | X300_FPGA_PROG_FLAGS_CLEANUP); - cleanup_packet.sector = 0; - cleanup_packet.size = 0; - cleanup_packet.index = 0; - memset(cleanup_packet.data, 0, sizeof(cleanup_packet.data)); - udp_transport->send(boost::asio::buffer(&cleanup_packet, sizeof(cleanup_packet))); - - if (udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT) == 0) - throw std::runtime_error("Timed out waiting for ACK!"); - const x300_fpga_update_data_t *cleanup_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - if((ntohl(cleanup_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) == X300_FPGA_PROG_FLAGS_ERROR){ - throw std::runtime_error("Transfer or data verification failed!"); - } - - std::cout << "\rProgress: " << "100% (" << sectors << "/" << sectors << " sectors)" << std::endl; -} - -void pcie_burn(std::string resource, std::string rpc_port, std::string fpga_path) -{ - std::cout << "Burning image: " << fpga_path << std::endl; - std::cout << "This will take 3-10 minutes." << std::endl; - - nirio_status status = NiRio_Status_Success; - - uhd::niusrprio::niusrprio_session fpga_session(resource, rpc_port); - nirio_status_chain(fpga_session.download_bitstream_to_flash(fpga_path), status); - - if(nirio_status_fatal(status)) throw std::runtime_error("Failed to burn FPGA image!"); -} - -bool configure_fpga(udp_simple::sptr udp_transport, std::string ip_addr){ - x300_fpga_update_data_t configure_packet; - configure_packet.flags = htonx<boost::uint32_t>(X300_FPGA_PROG_CONFIGURE | X300_FPGA_PROG_FLAGS_ACK); - configure_packet.sector = 0; - configure_packet.size = 0; - configure_packet.index = 0; - memset(configure_packet.data, 0, sizeof(configure_packet.data)); - udp_transport->send(boost::asio::buffer(&configure_packet, sizeof(configure_packet))); - - udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT); - const x300_fpga_update_data_t *configure_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - bool successful = false; - - if((ntohl(configure_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) == X300_FPGA_PROG_FLAGS_ERROR){ - throw std::runtime_error("Transfer or data verification failed!"); - } - else{ - std::cout << std::endl << "Waiting for X3x0 to configure FPGA image and reload." << std::endl; - boost::this_thread::sleep(boost::posix_time::milliseconds(5000)); - - x300_fpga_update_data_t config_status_packet; - configure_packet.flags = htonx<boost::uint32_t>(X300_FPGA_PROG_CONFIG_STATUS); - config_status_packet.sector = 0; - config_status_packet.size = 0; - config_status_packet.index = 0; - memset(config_status_packet.data, 0, sizeof(config_status_packet.data)); - for(int i = 0; i < 5; i++){ - udp_transport->send(boost::asio::buffer(&config_status_packet, sizeof(config_status_packet))); - udp_transport->recv(boost::asio::buffer(x300_data_in_mem), 1); - const x300_fpga_update_data_t *config_status_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - if((ntohl(config_status_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) != X300_FPGA_PROG_FLAGS_ERROR - and udp_transport->get_recv_addr() == ip_addr){ - successful = true; - break; - } - successful = false; //If it worked, the break would skip this - } - } - return successful; -} - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - memset(intermediary_packet_data, 0, X300_PACKET_SIZE_BYTES); +int main(int argc, char *argv[]){ std::string ip_addr, resource, fpga_path, image_type, rpc_port; po::options_description desc("Allowed options"); desc.add_options() ("help", "Display this help message.") - ("addr", po::value<std::string>(&ip_addr), "Specify an IP address.") + ("addr", po::value<std::string>(&ip_addr)->default_value("1.2.3.4"), "Specify an IP address.") ("resource", po::value<std::string>(&resource), "Specify an NI-RIO resource.") ("rpc-port", po::value<std::string>(&rpc_port)->default_value("5444"), "Specify a port to communicate with the RPC server.") - ("type", po::value<std::string>(&image_type), "Specify an image type (1G, HGS, XGS), leave blank for current type.") - ("fpga-path", po::value<std::string>(&fpga_path), "Specify an FPGA path (overrides --type option).") + ("type", po::value<std::string>(&image_type)->default_value("HG"), "Specify an image type (1G, HG, XG), leave blank for current type.") + ("fpga-path", po::value<std::string>(&fpga_path)->default_value("/path/to/fpga-image.bit"), "Specify an FPGA path (overrides --type option).") ("configure", "Initialize FPGA with image currently burned to flash (Ethernet only).") ("verify", "Verify data downloaded to flash (Ethernet only, download will take much longer)") ("list", "List all available X3x0 devices.") @@ -480,97 +102,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); - //Print help message - if(vm.count("help")){ - std::cout << "USRP X3x0 FPGA Burner" << std::endl << std::endl; - - std::cout << "Burns an FPGA image onto a USRP X300/X310. To burn the image" << std::endl - << "over Ethernet, specify an IP address with the --addr option," << std::endl - << "or to burn over PCIe, specify an NI-RIO resource (ex. RIO0)" << std::endl - << "with the --resource option." << std::endl << std::endl; - - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - - //List all available devices - if(vm.count("list")){ - list_usrps(); - return EXIT_SUCCESS; - } - - /* - * The user must specify whether to burn the image over Ethernet or PCI-e. - */ - if(not (vm.count("addr") xor vm.count("resource"))){ - throw std::runtime_error("You must specify addr OR resource!"); - } - - /* - * With settings validated, find X3x0 with specified arguments. - */ - device_addr_t dev = (vm.count("addr")) ? find_usrp_with_ethernet(ip_addr, true) - : find_usrp_with_pcie(resource, true); - - /* - * If custom FPGA path is given, ignore specified type and let FPGA - * figure it out. - */ - if(vm.count("fpga-path")){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME")); - #endif - } - else{ - if(vm.count("type")){ - //Make sure the specified type is 1G, HGS, or XGS - if((image_type != "1G") and (image_type != "HGS") and (image_type != "XGS")){ - throw std::runtime_error("--type must be 1G, HGS, or XGS!"); - } - else fpga_path = get_default_image_path(dev["product"], image_type); - } - else{ - //Use default image of currently present FPGA type - fpga_path = get_default_image_path(dev["product"], dev["fpga"]); - } - } - - /* - * Check validity of image through extension - */ - std::string ext = fs::extension(fpga_path.c_str()); - if(ext != ".bin" and ext != ".bit" and ext != ".lvbitx"){ - throw std::runtime_error("The image filename must end in .bin, .bit, or .lvbitx."); - } - print_image_loader_warning(fpga_path, vm); - std::signal(SIGINT, &sig_int_handler); - if(vm.count("addr")){ - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(X300_FPGA_PROG_UDP_PORT)); - - ethernet_burn(udp_transport, fpga_path, (vm.count("verify") > 0)); - - if(vm.count("configure")){ - if(configure_fpga(udp_transport, ip_addr)) std::cout << "Successfully configured FPGA!" << std::endl; - else throw std::runtime_error("FPGA configuring failed!"); - } - } - else pcie_burn(resource, rpc_port, fpga_path); - - /* - * Attempt to find USRP after burning - */ - std::cout << std::endl << "Attempting to find device..." << std::flush; - boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); //Sometimes needed for Ethernet to reconnect - device_addr_t found_usrp = (vm.count("addr")) ? find_usrp_with_ethernet(ip_addr, false) - : find_usrp_with_pcie(resource, false); - std::cout << "found!" << std::endl; //If unsuccessful, runtime error would occur in find functions - std::cout << "Successfully burned FPGA image!" << std::endl << std::endl; - - if(vm.count("addr")) std::cout << str(boost::format("Power-cycle the USRP %s to use the new image.") % found_usrp["product"]) << std::endl; - else std::cout << str(boost::format("Power-cycle the USRP %s and reboot your machine to use the new image.") % found_usrp["product"]) << std::endl; - - return EXIT_SUCCESS; + return EXIT_FAILURE; } + |