diff options
Diffstat (limited to 'host/lib/usrp/usrp2')
| -rw-r--r-- | host/lib/usrp/usrp2/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/n200_image_loader.cpp | 616 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.cpp | 10 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 2 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 3 | 
5 files changed, 627 insertions, 19 deletions
| diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index c6257c7fe..bd302895b 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2011-2012,2014 Ettus Research LLC +# Copyright 2011-2012,2014-2015 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 @@ -25,18 +25,6 @@  LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF)  IF(ENABLE_USRP2) -    ######################################################################## -    # Define UHD_PKG_DATA_PATH for usrp2_iface.cpp -    ######################################################################## -    FILE(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX} UHD_PKG_PATH) -    STRING(REPLACE "\\" "\\\\" UHD_PKG_PATH ${UHD_PKG_PATH}) - -    SET_SOURCE_FILES_PROPERTIES( -        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp -        PROPERTIES COMPILE_DEFINITIONS -        "UHD_LIB_DIR=\"lib${LIB_SUFFIX}\"" -    ) -      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp @@ -45,5 +33,6 @@ IF(ENABLE_USRP2)          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_fifo_ctrl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/n200_image_loader.cpp      )  ENDIF(ENABLE_USRP2) diff --git a/host/lib/usrp/usrp2/n200_image_loader.cpp b/host/lib/usrp/usrp2/n200_image_loader.cpp new file mode 100644 index 000000000..ce956c22c --- /dev/null +++ b/host/lib/usrp/usrp2/n200_image_loader.cpp @@ -0,0 +1,616 @@ +// +// Copyright 2015 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <cstring> +#include <iostream> +#include <fstream> + +#include <boost/asio/ip/address_v4.hpp> +#include <boost/assign.hpp> +#include <boost/filesystem.hpp> +#include <boost/format.hpp> +#include <boost/thread.hpp> +#include <boost/algorithm/string/erase.hpp> + +#include <uhd/config.hpp> +#include <uhd/image_loader.hpp> +#include <uhd/exception.hpp> +#include <uhd/transport/if_addrs.hpp> +#include <uhd/transport/udp_simple.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/utils/paths.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/types/dict.hpp> + +#include "fw_common.h" +#include "usrp2_iface.hpp" +#include "usrp2_impl.hpp" + +typedef boost::asio::ip::address_v4 ip_v4; + +namespace fs = boost::filesystem; +using namespace boost::algorithm; + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; + +/* + * Constants + */ + +#define N200_FLASH_DATA_PACKET_SIZE 256 +#define N200_UDP_FW_UPDATE_PORT 49154 +#define UDP_TIMEOUT 0.5 + +#define N200_FW_MAX_SIZE_BYTES 31744 +#define N200_PROD_FW_IMAGE_ADDR  0x00300000 +#define N200_SAFE_FW_IMAGE_ADDR  0x003F0000 + +#define N200_FPGA_MAX_SIZE_BYTES 1572864 +#define N200_PROD_FPGA_IMAGE_ADDR  0x00180000 +#define N200_SAFE_FPGA_IMAGE_ADDR  0x00000000 + +/* + * Packet codes + */ +typedef enum { +    UNKNOWN = ' ', + +    N200_QUERY = 'a', +    N200_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_CMD = 's', +    RESET_ACK = 'S', + +    GET_HW_REV_CMD = 'v', +    GET_HW_REV_ACK = 'V', +} n200_fw_update_id_t; + +/* + * Mapping revision numbers to names + */ +static const uhd::dict<boost::uint32_t, std::string> n200_filename_map = boost::assign::map_list_of +    (0,      "n2xx")    // Is an N-Series, but the EEPROM value is invalid +    (0xa,    "n200_r3") +    (0x100a, "n200_r4") +    (0x10a,  "n210_r3") +    (0x110a, "n210_r4") +; + +/* + * Packet structure + */ +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; +} n200_fw_update_data_t; + +/* + * N-Series burn session + */ +typedef struct { +    bool               fw; +    bool               overwrite_safe; +    bool               reset; +    uhd::device_addr_t dev_addr; +    std::string        burn_type; +    std::string        filepath; +    boost::uint8_t     data_in[udp_simple::mtu]; +    boost::uint32_t    size; +    boost::uint32_t    max_size; +    boost::uint32_t    flash_addr; +    udp_simple::sptr   xport; +} n200_session_t; + +/*********************************************************************** + * uhd::image_loader functionality + **********************************************************************/ + +static void print_usrp2_error(const image_loader::image_loader_args_t &image_loader_args){ +    #ifdef UHD_PLATFORM_WIN32 +    std::string usrp2_card_burner_gui = "\""; +    const std::string nl = " ^\n    "; +    #else +    std::string usrp2_card_burner_gui = "sudo \""; +    const std::string nl = " \\\n    "; +    #endif + +    usrp2_card_burner_gui += find_utility("usrp2_card_burner_gui.py"); +    usrp2_card_burner_gui += "\""; + +    if(image_loader_args.load_firmware){ +        usrp2_card_burner_gui += str(boost::format("%s--fw=\"%s\"") +                                     % nl +                                     % ((image_loader_args.firmware_path == "") +                                             ? find_image_path("usrp2_fw.bin") +                                             : image_loader_args.firmware_path)); +    } +    if(image_loader_args.load_fpga){ +        usrp2_card_burner_gui += str(boost::format("%s--fpga=\"%s\"") +                                     % nl +                                     % ((image_loader_args.fpga_path == "") +                                             ? find_image_path("usrp2_fpga.bin") +                                             : image_loader_args.fpga_path)); +    } + +    throw uhd::runtime_error(str(boost::format("The specified device is a USRP2, which is not supported by this utility.\n" +                                               "Instead, plug the device's SD card into your machine and run this command:\n\n" +                                               "%s" +                                              ) % usrp2_card_burner_gui)); +} + +/* + * Ethernet communication functions + */ +static UHD_INLINE size_t n200_send_and_recv(udp_simple::sptr xport, +                                            n200_fw_update_id_t pkt_code, +                                            n200_fw_update_data_t *pkt_out, +                                            boost::uint8_t* data){ +    pkt_out->proto_ver = htonx<boost::uint32_t>(USRP2_FW_COMPAT_NUM); +    pkt_out->id = htonx<boost::uint32_t>(pkt_code); +    xport->send(boost::asio::buffer(pkt_out, sizeof(*pkt_out))); +    return xport->recv(boost::asio::buffer(data, udp_simple::mtu), UDP_TIMEOUT); +} + +static UHD_INLINE bool n200_response_matches(const n200_fw_update_data_t *pkt_in, +                                             n200_fw_update_id_t pkt_code, +                                             size_t len){ +    return (len > offsetof(n200_fw_update_data_t, data) and +            ntohl(pkt_in->id) == pkt_code); +} + +static uhd::device_addr_t n200_find(const image_loader::image_loader_args_t &image_loader_args){ +    bool user_specified = image_loader_args.args.has_key("addr") or +                          image_loader_args.args.has_key("serial") or +                          image_loader_args.args.has_key("name"); + +    uhd::device_addrs_t found = usrp2_find(image_loader_args.args); +    if(found.size() > 0){ +        uhd::device_addr_t ret = found[0]; + +        /* +         * Make sure the device found is an N-Series and not a USRP2. A USRP2 +         * will not respond to this query. If the user supplied specific +         * arguments that led to a USRP2, throw an error. +         */ +        udp_simple::sptr rev_xport = udp_simple::make_connected( +                                         ret["addr"], +                                         BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT) +                                     ); + +        n200_fw_update_data_t pkt_out; +        boost::uint8_t data_in[udp_simple::mtu]; +        const n200_fw_update_data_t *pkt_in = reinterpret_cast<const n200_fw_update_data_t*>(data_in); + +        size_t len = n200_send_and_recv(rev_xport, GET_HW_REV_CMD, &pkt_out, data_in); +        if(n200_response_matches(pkt_in, GET_HW_REV_ACK, len)){ +            boost::uint32_t rev = ntohl(pkt_in->data.hw_rev); +            ret["hw_rev"] = n200_filename_map.get(rev, "n2xx"); +            return ret; +        } +        else if(len > offsetof(n200_fw_update_data_t, data) and ntohl(pkt_in->id) != GET_HW_REV_ACK){ +            throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.") +                                         % ntohl(pkt_in->id))); +        } +        else if(user_specified){ +            // At this point, we haven't received any response, so assume it's a USRP2 +            print_usrp2_error(image_loader_args); +        } +    } + +    return uhd::device_addr_t(); +} + +/* + * Validate and read firmware image + */ +static void n200_validate_firmware_image(n200_session_t &session){ +    if(not fs::exists(session.filepath)){ +        throw uhd::runtime_error(str(boost::format("Could not find image at path \"%s\".") +                                     % session.filepath)); +    } + +    session.size     = fs::file_size(session.filepath); +    session.max_size = N200_FW_MAX_SIZE_BYTES; + +    if(session.size > session.max_size){ +        throw uhd::runtime_error(str(boost::format("The specified FPGA image is too large: %d vs. %d") +                                     % session.size % session.max_size)); +    } + +    // File must have proper header +    std::ifstream image_file(session.filepath.c_str(), std::ios::binary); +    boost::uint8_t test_bytes[4]; +    image_file.seekg(0, std::ios::beg); +    image_file.read((char*)test_bytes,4); +    image_file.close(); +    for(int i = 0; i < 4; i++) if(test_bytes[i] != 11){ +        throw uhd::runtime_error(str(boost::format("The file at path \"%s\" is not a valid firmware image.") +                                     % session.filepath)); +    } +} + +/* + * Validate and validate FPGA image + */ +static void n200_validate_fpga_image(n200_session_t &session){ +    if(not fs::exists(session.filepath)){ +        throw uhd::runtime_error(str(boost::format("Could not find image at path \"%s\".") +                                     % session.filepath)); +    } + +    session.size     = fs::file_size(session.filepath); +    session.max_size = N200_FPGA_MAX_SIZE_BYTES; + +    if(session.size > session.max_size){ +        throw uhd::runtime_error(str(boost::format("The specified FPGA image is too large: %d vs. %d") +                                     % session.size % session.max_size)); +    } + +    // File must have proper header +    std::ifstream image_file(session.filepath.c_str(), std::ios::binary); +    boost::uint8_t test_bytes[63]; +    image_file.seekg(0, std::ios::beg); +    image_file.read((char*)test_bytes, 63); +    bool is_good = false; +    for(int i = 0; i < 63; i++){ +        if(test_bytes[i] == 255) continue; +        else if(test_bytes[i] == 170 and +                test_bytes[i+1] == 153){ +            is_good = true; +            break; +        } +    } +    image_file.close(); +    if(not is_good){ +        throw uhd::runtime_error(str(boost::format("The file at path \"%s\" is not a valid FPGA image.") +                                     % session.filepath)); +    } +} + +/* + * Set up a session for burning an N-Series image. This session info + * will be passed into the erase, burn, and verify functions. + */ +static void n200_setup_session(n200_session_t &session, +                               const image_loader::image_loader_args_t &image_loader_args, +                               bool fw){ + + +    session.fw = fw; +    session.reset = image_loader_args.args.has_key("reset"); + +    /* +     * If no filepath is given, attempt to determine the default image by +     * querying the device for its revision. If the device has a corrupt +     * EEPROM or is otherwise unable to provide its revision, this is +     * impossible, and the user must manually provide a firmware file. +     */ +    if((session.fw and image_loader_args.firmware_path == "") or +       image_loader_args.fpga_path == ""){ +        if(session.dev_addr["hw_rev"] == "n2xx"){ +            throw uhd::runtime_error("This device's revision cannot be determined. " +                                     "You must manually specify a filepath."); +        } +        else{ +            session.filepath = session.fw ? find_image_path(str(boost::format("usrp_%s_fw.bin") +                                                                % erase_tail_copy(session.dev_addr["hw_rev"],3))) +                                          : find_image_path(str(boost::format("usrp_%s_fpga.bin") +                                                                % session.dev_addr["hw_rev"])); +        } +    } +    else{ +        session.filepath = session.fw ? image_loader_args.firmware_path +                                      : image_loader_args.fpga_path; +    } +    if(session.fw) n200_validate_firmware_image(session); +    else           n200_validate_fpga_image(session); + +    session.overwrite_safe = image_loader_args.args.has_key("overwrite-safe"); +    if(session.overwrite_safe){ +        session.flash_addr = session.fw ? N200_SAFE_FW_IMAGE_ADDR +                                        : N200_SAFE_FPGA_IMAGE_ADDR; +        session.burn_type = session.fw ? "firmware safe" +                                       : "FPGA safe"; +    } +    else{ +        session.flash_addr = session.fw ? N200_PROD_FW_IMAGE_ADDR +                                        : N200_PROD_FPGA_IMAGE_ADDR; +        session.burn_type = session.fw ? "firmware" +                                       : "FPGA"; +    } + +    session.xport = udp_simple::make_connected(session.dev_addr["addr"], +                                               BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT)); +} + +static void n200_erase_image(n200_session_t &session){ + +    // UDP receive buffer +    n200_fw_update_data_t pkt_out; +    const n200_fw_update_data_t *pkt_in = reinterpret_cast<const n200_fw_update_data_t*>(session.data_in); + +    // Setting up UDP packet +    pkt_out.data.flash_args.flash_addr = htonx<boost::uint32_t>(session.flash_addr); +    pkt_out.data.flash_args.length = htonx<boost::uint32_t>(session.size); + +    // Begin erasing +    size_t len = n200_send_and_recv(session.xport, ERASE_FLASH_CMD, &pkt_out, session.data_in); +    if(n200_response_matches(pkt_in, ERASE_FLASH_ACK, len)){ +        std::cout << boost::format("-- Erasing %s image...") % session.burn_type << std::flush; +    } +    else if(len < offsetof(n200_fw_update_data_t, data)){ +        std::cout << "failed." << std::endl; +        throw uhd::runtime_error("Timed out waiting for reply from device."); +    } +    else if(ntohl(pkt_in->id) != ERASE_FLASH_ACK){ +        std::cout << "failed." << std::endl; +        throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.\n") +                                     % ntohl(pkt_in->id))); +    } +    else{ +        std::cout << "failed." << std::endl; +        throw uhd::runtime_error("Did not receive response from device."); +    } + +    // Check for erase completion +    while(true){ +        len = n200_send_and_recv(session.xport, CHECK_ERASING_DONE_CMD, &pkt_out, session.data_in); +        if(n200_response_matches(pkt_in, DONE_ERASING_ACK, len)){ +            std::cout << "successful." << std::endl; +            break; +        } +        else if(len < offsetof(n200_fw_update_data_t, data)){ +            std::cout << "failed." << std::endl; +            throw uhd::runtime_error("Timed out waiting for reply from device."); +        } +        else if(ntohl(pkt_in->id) != NOT_DONE_ERASING_ACK){ +            std::cout << "failed." << std::endl; +            throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.\n") +                                         % ntohl(pkt_in->id))); +        } +    } +} + +static void n200_write_image(n200_session_t &session){ + +    // UDP receive buffer +    n200_fw_update_data_t pkt_out; +    const n200_fw_update_data_t *pkt_in = reinterpret_cast<const n200_fw_update_data_t*>(session.data_in); +    size_t len = 0; + +    // Write image +    std::ifstream image(session.filepath.c_str(), std::ios::binary); +    boost::uint32_t current_addr = session.flash_addr; +    pkt_out.data.flash_args.length = htonx<boost::uint32_t>(N200_FLASH_DATA_PACKET_SIZE); +    for(size_t i = 0; i < ((session.size/N200_FLASH_DATA_PACKET_SIZE)+1); i++){ +        pkt_out.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr); +        memset(pkt_out.data.flash_args.data, 0x0, N200_FLASH_DATA_PACKET_SIZE); +        image.read((char*)pkt_out.data.flash_args.data, N200_FLASH_DATA_PACKET_SIZE); + +        len = n200_send_and_recv(session.xport, WRITE_FLASH_CMD, &pkt_out, session.data_in); +        if(n200_response_matches(pkt_in, WRITE_FLASH_ACK, len)){ +            std::cout << boost::format("\r-- Writing %s image (%d%%)") +                             % session.burn_type +                             % int((double(current_addr-session.flash_addr)/double(session.size))*100) +                      << std::flush; +        } +        else if(len < offsetof(n200_fw_update_data_t, data)){ +            image.close(); +            std::cout << boost::format("\r--Writing %s image..failed at %d%%.") +                             % session.burn_type +                             % int((double(current_addr-session.flash_addr)/double(session.size))*100) +                      << std::endl; +            throw uhd::runtime_error("Timed out waiting for reply from device."); +        } +        else if(ntohl(pkt_in->id) != WRITE_FLASH_ACK){ +            image.close(); +            std::cout << boost::format("\r--Writing %s image..failed at %d%%.") +                             % session.burn_type +                             % int((double(current_addr-session.flash_addr)/double(session.size))*100) +                      << std::endl; +            throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.\n") +                                             % ntohl(pkt_in->id))); +        } + +        current_addr += N200_FLASH_DATA_PACKET_SIZE; +    } +    std::cout << boost::format("\r-- Writing %s image...successful.") +                     % session.burn_type +              << std::endl; + +    image.close(); +} + +static void n200_verify_image(n200_session_t &session){ + +    // UDP receive buffer +    n200_fw_update_data_t pkt_out; +    const n200_fw_update_data_t *pkt_in = reinterpret_cast<const n200_fw_update_data_t*>(session.data_in); +    size_t len = 0; + +    // Read and verify image +    std::ifstream image(session.filepath.c_str(), std::ios::binary); +    boost::uint8_t image_part[N200_FLASH_DATA_PACKET_SIZE]; +    boost::uint32_t current_addr = session.flash_addr; +    pkt_out.data.flash_args.length = htonx<boost::uint32_t>(N200_FLASH_DATA_PACKET_SIZE); +    boost::uint16_t cmp_len = 0; +    for(size_t i = 0; i < ((session.size/N200_FLASH_DATA_PACKET_SIZE)+1); i++){ +        memset(image_part, 0x0, N200_FLASH_DATA_PACKET_SIZE); +        memset((void*)pkt_in->data.flash_args.data, 0x0, N200_FLASH_DATA_PACKET_SIZE); + +        pkt_out.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr); +        image.read((char*)image_part, N200_FLASH_DATA_PACKET_SIZE); +        cmp_len = image.gcount(); + +        len = n200_send_and_recv(session.xport, READ_FLASH_CMD, &pkt_out, session.data_in); +        if(n200_response_matches(pkt_in, READ_FLASH_ACK, len)){ +            std::cout << boost::format("\r-- Verifying %s image (%d%%)") +                             % session.burn_type +                             % int((double(current_addr-session.flash_addr)/double(session.size))*100) +                      << std::flush; + +            if(memcmp(image_part, pkt_in->data.flash_args.data, cmp_len)){ +                std::cout << boost::format("\r-- Verifying %s image...failed at %d%%.") +                                 % session.burn_type +                                 % int((double(current_addr-session.flash_addr)/double(session.size))*100) +                          << std::endl; +                throw uhd::runtime_error(str(boost::format("Failed to verify %s image.") +                                                 % session.burn_type)); +            } +        } +        else if(len < offsetof(n200_fw_update_data_t, data)){ +            image.close(); +            std::cout << boost::format("\r-- Verifying %s image...failed at %d%%.") +                             % session.burn_type +                             % int((double(current_addr-session.flash_addr)/double(session.size))*100) +                      << std::endl; +            throw uhd::runtime_error("Timed out waiting for reply from device."); +        } +        else if(ntohl(pkt_in->id) != READ_FLASH_ACK){ +            image.close(); +            std::cout << boost::format("\r-- Verifying %s image...failed at %d%%.") +                             % session.burn_type +                             % int((double(current_addr-session.flash_addr)/double(session.size))*100) +                      << std::endl; +            throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.\n") +                                         % ntohl(pkt_in->id))); +        } + +        current_addr += N200_FLASH_DATA_PACKET_SIZE; +    } +    std::cout << boost::format("\r-- Verifying %s image...successful.") % session.burn_type +              << std::endl; + +    image.close(); +} + +static void n200_reset(n200_session_t &session){ + +    // UDP receive buffer +    n200_fw_update_data_t pkt_out; + +    // There should be no response +    std::cout << "-- Resetting device..." << std::flush; +    size_t len = n200_send_and_recv(session.xport, RESET_CMD, &pkt_out, session.data_in); +    if(len > 0){ +        std::cout << "failed." << std::endl; +        throw uhd::runtime_error("Failed to reset N200."); +    } +    std::cout << "successful." << std::endl; +} + +// n210_r4 -> N210 r4 +static std::string nice_name(const std::string &fw_rev){ +    std::string ret = fw_rev; +    ret[0] = ::toupper(ret[0]); + +    size_t pos = 0; +    if((pos = fw_rev.find("_")) != std::string::npos){ +        ret[pos] = ' '; +    } + +    return ret; +} + +static bool n200_image_loader(const image_loader::image_loader_args_t &image_loader_args){ +    // See if any N2x0 with the given args is found +    // This will throw if specific args lead to a USRP2 +    n200_session_t session; +    session.dev_addr = n200_find(image_loader_args); +    if(session.dev_addr.size() == 0 or (!image_loader_args.load_firmware and !image_loader_args.load_fpga)){ +        return false; +    } + +    std::cout << boost::format("Unit: USRP %s (%s, %s)") +                 % nice_name(session.dev_addr.get("hw_rev")) +                 % session.dev_addr.get("serial") +                 % session.dev_addr.get("addr") +             << std::endl; + +    if(image_loader_args.load_firmware){ +        n200_setup_session(session, +                           image_loader_args, +                           true +                          ); + +        std::cout << "Firmware image: " << session.filepath << std::endl; + +        n200_erase_image(session); +        n200_write_image(session); +        n200_verify_image(session); +        if(session.reset and !image_loader_args.load_fpga){ +            n200_reset(session); +        } +    } +    if(image_loader_args.load_fpga){ +        n200_setup_session(session, +                           image_loader_args, +                           false +                          ); + +        std::cout << "FPGA image: " << session.filepath << std::endl; + +        n200_erase_image(session); +        n200_write_image(session); +        n200_verify_image(session); +        if(session.reset){ +            n200_reset(session); +        } +    } + +    return true; +} + +UHD_STATIC_BLOCK(register_n200_image_loader){ +    std::string recovery_instructions = "Aborting. Your USRP-N Series unit will likely be unusable.\n" +                                        "Refer to http://files.ettus.com/manual/page_usrp2.html#usrp2_loadflash_brick\n" +                                        "for details on restoring your device."; + +    image_loader::register_image_loader("usrp2", n200_image_loader, recovery_instructions); +} diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 1d41173f8..2b382ae38 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -387,15 +387,15 @@ public:          //create the burner commands          if (this->get_rev() == USRP2_REV3 or this->get_rev() == USRP2_REV4){ -            const std::string card_burner = (fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "usrp2_card_burner_gui.py").string(); -            const std::string card_burner_cmd = str(boost::format("\"%s%s\" %s--fpga=\"%s\" %s--fw=\"%s\"") % sudo % card_burner % ml % fpga_image_path % ml % fw_image_path); +            const std::string card_burner = uhd::find_utility("usrp2_card_burner_gui.py"); +            const std::string card_burner_cmd = str(boost::format(" %s\"%s\" %s--fpga=\"%s\" %s--fw=\"%s\"") % sudo % card_burner % ml % fpga_image_path % ml % fw_image_path);              return str(boost::format("%s\n%s") % print_utility_error("uhd_images_downloader.py") % card_burner_cmd);          }          else{              const std::string addr = _ctrl_transport->get_recv_addr(); -            const std::string net_burner_path = (fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "usrp_n2xx_simple_net_burner").string(); -            const std::string net_burner_cmd = str(boost::format("\"%s\" %s--addr=\"%s\"") % net_burner_path % ml % addr); -            return str(boost::format("%s\n%s") % print_utility_error("uhd_images_downloader.py") % net_burner_cmd); +            const std::string image_loader_path = (fs::path(uhd::get_pkg_path()) / "bin" / "uhd_image_loader").string(); +            const std::string image_loader_cmd = str(boost::format(" \"%s\" %s--args=\"type=usrp2,addr=%s\"") % image_loader_path % ml % addr); +            return str(boost::format("%s\n%s") % print_utility_error("uhd_images_downloader.py") % image_loader_cmd);          }      } diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 1acc1dad3..6073ec1c0 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -48,7 +48,7 @@ static const size_t DEFAULT_NUM_FRAMES = 32;  /***********************************************************************   * Discovery over the udp transport   **********************************************************************/ -static device_addrs_t usrp2_find(const device_addr_t &hint_){ +device_addrs_t usrp2_find(const device_addr_t &hint_){      //handle the multi-device discovery      device_addrs_t hints = separate_device_addr(hint_);      if (hints.size() > 1){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 701403029..07cd98b4c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -42,6 +42,7 @@  #include <uhd/transport/vrt_if_packet.hpp>  #include <uhd/transport/udp_simple.hpp>  #include <uhd/transport/udp_zero_copy.hpp> +#include <uhd/types/device_addr.hpp>  #include <uhd/usrp/dboard_manager.hpp>  #include <uhd/usrp/subdev_spec.hpp>  #include <boost/weak_ptr.hpp> @@ -55,6 +56,8 @@ static const boost::uint32_t USRP2_TX_ASYNC_SID = 2;  static const boost::uint32_t USRP2_RX_SID_BASE = 3;  static const std::string USRP2_EEPROM_MAP_KEY = "N100"; +uhd::device_addrs_t usrp2_find(const uhd::device_addr_t &hint_); +  //! Make a usrp2 dboard interface.  uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(      uhd::timed_wb_iface::sptr wb_iface, | 
