Example #1
0
/*
 * Ethernet communication functions
 */
static UHD_INLINE size_t x300_send_and_recv(udp_simple::sptr xport,
                                            uint32_t pkt_code,
                                            x300_fpga_update_data_t *pkt_out,
                                            uint8_t* data){
    pkt_out->flags = uhd::htonx<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);
}
void erase_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint32_t memory_size){

    //Making sure this won't attempt to erase past end of device
    if(is_fw){
        if(PROD_FW_IMAGE_LOCATION_ADDR+FW_IMAGE_SIZE_BYTES > memory_size) throw std::runtime_error("Cannot erase past end of device.");
    }
    else{
        if(PROD_FPGA_IMAGE_LOCATION_ADDR+FPGA_IMAGE_SIZE_BYTES > memory_size) throw std::runtime_error("Cannot erase past end of device.");
    }

    //Setting up UDP transport
    boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
    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>(USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL);
    erase_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
    if(is_fw){
        erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(PROD_FW_IMAGE_LOCATION_ADDR);
        erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(FW_IMAGE_SIZE_BYTES);
    }
    else{
        erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(PROD_FPGA_IMAGE_LOCATION_ADDR);
        erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(FPGA_IMAGE_SIZE_BYTES);
    }

    //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) == USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG){
        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) != USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG){
        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>(USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL);
    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) == USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG){
            if(is_fw) std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") % FW_IMAGE_SIZE_BYTES % PROD_FW_IMAGE_LOCATION_ADDR;
            else std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") % FPGA_IMAGE_SIZE_BYTES % PROD_FPGA_IMAGE_LOCATION_ADDR;
            break;
        }
        else if(ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG){
            throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") % ntohl(update_data_in->id)));
        }
    }
}
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 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;
}
void verify_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, boost::uint32_t memory_size, int image_size){

    int current_index = 0;
    boost::uint32_t current_addr;
    if(is_fw) current_addr = PROD_FW_IMAGE_LOCATION_ADDR;
    else current_addr = PROD_FPGA_IMAGE_LOCATION_ADDR;

    //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.");

    //Setting up UDP transport
    boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
    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>(USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL);
    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);

    //Verify image
    if(is_fw) std::cout << "Verifying firmware image." << std::endl;
    else std::cout << "Verifying FPGA image." << std::endl;

    for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){
        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) != USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG){
            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 << " * Successful." << std::endl;
}
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;
}
/***********************************************************************
 * 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;
}
void write_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, boost::uint32_t memory_size, int image_size){

    boost::uint32_t current_addr;
    if(is_fw) current_addr = PROD_FW_IMAGE_LOCATION_ADDR;
    else current_addr = PROD_FPGA_IMAGE_LOCATION_ADDR;

    //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.");

    //Setting up UDP transport
    boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
    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>(USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL);
    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);

    //Write image
    if(is_fw) std::cout << "Writing firmware image." << std::endl;
    else std::cout << "Writing FPGA image." << std::endl;

    for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){
        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) != USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG){
            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 << boost::format(" * Successfully wrote %d bytes.\n") % image_size;
}
/***********************************************************************
 * Find USRP N2XX with specified IP address and return type
 **********************************************************************/
boost::uint32_t find_usrp(udp_simple::sptr udp_transport){
    boost::uint32_t hw_rev;
    bool found_it = false;

    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>(GET_HW_REV_CMD);
    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) == GET_HW_REV_ACK){
        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 throw std::runtime_error("Invalid revision found.");
    }
    if(not found_it) throw std::runtime_error("No USRP N2XX found.");

    return hw_rev;
}