diff options
Diffstat (limited to 'host/utils')
-rw-r--r-- | host/utils/CMakeLists.txt | 16 | ||||
-rw-r--r-- | host/utils/fx2_init_eeprom.cpp | 6 | ||||
-rw-r--r-- | host/utils/ihexcvt.cpp | 250 | ||||
-rw-r--r-- | host/utils/ihexcvt.hpp | 22 | ||||
-rw-r--r-- | host/utils/octoclock_burn_eeprom.cpp | 95 | ||||
-rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 351 | ||||
-rw-r--r-- | host/utils/uhd_usrp_probe.cpp | 5 | ||||
-rw-r--r-- | host/utils/usrp_burn_db_eeprom.cpp | 2 | ||||
-rw-r--r-- | host/utils/usrp_burn_mb_eeprom.cpp | 57 | ||||
-rw-r--r-- | host/utils/usrp_n2xx_simple_net_burner.cpp | 116 | ||||
-rw-r--r-- | host/utils/usrp_x3xx_fpga_burner.cpp | 6 |
11 files changed, 863 insertions, 63 deletions
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 7604a7d37..0d9f306b9 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2013 Ettus Research LLC +# Copyright 2010-2014 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 @@ -64,6 +64,20 @@ IF(ENABLE_USB) # Additional include directories for b2xx_fx3_utils INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/b200 ${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/common) ENDIF(ENABLE_USB) +IF(ENABLE_OCTOCLOCK) + LIST(APPEND util_share_sources + octoclock_burn_eeprom.cpp + ) + + SET(octoclock_burner_sources + octoclock_firmware_burner.cpp + ihexcvt.cpp + ) + + ADD_EXECUTABLE(octoclock_firmware_burner ${octoclock_burner_sources}) + TARGET_LINK_LIBRARIES(octoclock_firmware_burner uhd ${Boost_LIBRARIES}) + UHD_INSTALL(TARGETS octoclock_firmware_burner RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities) +ENDIF(ENABLE_OCTOCLOCK) IF(LINUX AND ENABLE_USB) UHD_INSTALL(FILES diff --git a/host/utils/fx2_init_eeprom.cpp b/host/utils/fx2_init_eeprom.cpp index 701092a5d..5711b73e0 100644 --- a/host/utils/fx2_init_eeprom.cpp +++ b/host/utils/fx2_init_eeprom.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010,2014 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 @@ -72,7 +72,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //find and create a control transport to do the writing. - uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); + uhd::device_addrs_t found_addrs = uhd::device::find(device_addr, uhd::device::USRP); if (found_addrs.size() == 0){ std::cerr << "No USRP devices found" << std::endl; @@ -82,7 +82,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ for (size_t i = 0; i < found_addrs.size(); i++){ std::cout << "Writing EEPROM data..." << std::endl; //uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]); - uhd::device::sptr dev = uhd::device::make(found_addrs[i]); + uhd::device::sptr dev = uhd::device::make(found_addrs[i], uhd::device::USRP); uhd::property_tree::sptr tree = dev->get_tree(); tree->access<std::string>("/mboards/0/load_eeprom").set(vm["image"].as<std::string>()); } diff --git a/host/utils/ihexcvt.cpp b/host/utils/ihexcvt.cpp new file mode 100644 index 000000000..0605ee61c --- /dev/null +++ b/host/utils/ihexcvt.cpp @@ -0,0 +1,250 @@ +/* IHexCvt - Intel HEX File <=> Binary Converter (C++) + Copyright (C) 2014 Ali Nakisaee + +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 2 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, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*/ + +//Include needed stuff from C++ +#include <iostream> +#include <fstream> +#include <string> + +//... and also from C +#include <stdio.h> + +#include <boost/filesystem.hpp> + +#include <uhd/exception.hpp> +#include "ihexcvt.hpp" + +//Avoid repeating 'std::': +using namespace std; + +//The following function reads a hexadecimal number from a text file. +template <class T> +static bool ReadValueFromHex(ifstream& InputFile, T& outCh, unsigned char* ApplyChecksum) +{ + char V, L; + T X = 0; + outCh = 0; + + //Get the characters one by one. + //Remember: These values are big-endian. + //Remember: Every two hex characters (0-9/A-F) indicate ONE byte. + for (size_t i = 0; i < 2 * sizeof(T); i++) + { + InputFile.get( V ); + if (InputFile.fail()) + return false; + + X <<= 4; + if (V >= '0' && V <= '9') + L = (V - '0'); + else if (V >= 'a' && V <= 'f') + L = (V - 'a' + 10); + else if (V >= 'A' && V <= 'F') + L = (V - 'A' + 10); + else + return false; + X |= L; + + //Apply this character to the checksum + if (ApplyChecksum && i % 2 == 1) *ApplyChecksum += X & 0xFF; + } + + //Return... + outCh = X; + return true; +} + +//The following function writes a hexadecimal number from a text file. +template <class T> +static bool WriteHexValue(ofstream& OutFile, T Value, unsigned char* CalcChecksum) +{ + unsigned char V0 = 0; + char C; + + //Remember: These values are big-endian. + for (size_t i = 0; i < sizeof(T); i++) + { + //Get byte #i from the value. + V0 = (Value >> ((sizeof(T) - i - 1) * 8)) & 0xFF; + + //Extract the high nibble (4-bits) + if ((V0 & 0xF0) <= 0x90) + C = (V0 >> 4) + '0'; + else + C = (V0 >> 4) + ('A' - 10); + OutFile.put( C ); + + //Extract the low nibble (4-bits) + if ((V0 & 0xF) <= 0x9) + C = (V0 & 0xF) + '0'; + else + C = (V0 & 0xF) + ('A' - 10); + OutFile.put( C ); + + //Calculate the checksum + if (CalcChecksum) *CalcChecksum += V0; + } + return true; +} + +//Skip any incoming whitespaces +static void SkipWhitespace(ifstream& InputFile) +{ + for (;;) + { + char C; + InputFile.get(C); + if (InputFile.eof() || InputFile.fail()) break; + if (!(C == '\n' || C == '\r' || C == ' ' || C == '\t' || C == '\v')) + { + InputFile.putback(C); + break; + } + } +} + +//The function responsible for conversion from HEX files to BINary. +void Hex2Bin(const char* SrcName, const char* DstName, bool IgnoreChecksum) +{ + ifstream Src(SrcName); + if (Src.bad()) + { + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); + } + + ofstream Dst(DstName, ios_base::binary); + if (Dst.bad()) + { + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); + } + + char Ch; + int LineIdx = 1; + + unsigned char ByteCount; + unsigned short AddressLow; + unsigned short Extra; + unsigned long ExtraL; + unsigned long AddressOffset = 0; + unsigned char RecordType; + unsigned char Data[255]; + unsigned char CurChecksum; + unsigned char FileChecksum; + bool EOFMarker = false; + bool EOFWarn = false; + + for ( ;; ) + { + Src.get(Ch); + if (Src.eof()) + break; + if (EOFMarker && !EOFWarn) + { + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); + } + if (Ch != ':') goto genericErr; + + CurChecksum = 0; + if (!ReadValueFromHex( Src, ByteCount, &CurChecksum )) goto genericErr; + if (!ReadValueFromHex( Src, AddressLow, &CurChecksum )) goto genericErr; + if (!ReadValueFromHex( Src, RecordType, &CurChecksum )) goto genericErr; + + switch (RecordType) + { + case 0x00: //Data record + for (int i = 0; i < ByteCount; i++) + if (!ReadValueFromHex( Src, Data[i], &CurChecksum )) goto genericErr; + break; + case 0x01: //End Marker + if ( ByteCount != 0 ) + { + goto onErrExit; + } + EOFMarker = true; + break; + case 0x02: //Extended Segment Address + if ( ByteCount != 2 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, Extra, &CurChecksum )) goto genericErr; + AddressOffset = (unsigned long)Extra << 4; + break; + case 0x03: //Start Segment Address + if ( ByteCount != 4 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, ExtraL, &CurChecksum )) goto genericErr; + break; + case 0x04: //Extended Linear Address + if ( ByteCount != 2 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, Extra, &CurChecksum )) goto genericErr; + AddressOffset = (unsigned long)Extra << 16; + break; + case 0x05: //Start Linear Address + if ( ByteCount != 4 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, ExtraL, &CurChecksum )) goto genericErr; + break; + } + + //Verify checksum + CurChecksum = (~(CurChecksum & 0xFF) + 1) & 0xFF; + if (!ReadValueFromHex( Src, FileChecksum, NULL )) goto genericErr; + if (CurChecksum != FileChecksum) + { + if (!IgnoreChecksum) goto onErrExit; + } + + //Put Data + if (RecordType == 0x00) + { + Dst.seekp( AddressLow + AddressOffset ); + for (int i = 0; i < ByteCount; i++) + { + Dst.put( Data[i] ); + } + } + + //Skip any white space + SkipWhitespace( Src ); + + LineIdx++; + } + + Dst << flush; + Dst.close(); + + return; + +genericErr: + throw uhd::runtime_error("Invalid Intel .hex file detected."); + +onErrExit: + Dst.close(); + Src.close(); + boost::filesystem::remove(DstName); + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); +} diff --git a/host/utils/ihexcvt.hpp b/host/utils/ihexcvt.hpp new file mode 100644 index 000000000..d577ece1f --- /dev/null +++ b/host/utils/ihexcvt.hpp @@ -0,0 +1,22 @@ +// +// Copyright 2014 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/>. +// +#ifndef _IHEXCVT_HPP_ +#define _IHEXCVT_HPP_ + +void Hex2Bin(const char* SrcName, const char* DstName, bool IgnoreChecksum); + +#endif /* _IHEXCVT_HPP_ */ diff --git a/host/utils/octoclock_burn_eeprom.cpp b/host/utils/octoclock_burn_eeprom.cpp new file mode 100644 index 000000000..033a8f499 --- /dev/null +++ b/host/utils/octoclock_burn_eeprom.cpp @@ -0,0 +1,95 @@ +// +// Copyright 2014 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 <uhd/device.hpp> +#include <uhd/utils/safe_main.hpp> +#include <uhd/usrp_clock/octoclock_eeprom.hpp> +#include <uhd/property_tree.hpp> +#include <uhd/types/device_addr.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/program_options.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <vector> + +namespace po = boost::program_options; + +using namespace uhd; +using namespace uhd::usrp_clock; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + std::string args, input_str, key, val; + + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") + ("values", po::value<std::string>(&input_str), "keys+values to read/write, separate multiple by \",\"") + ("read-all", "Read all motherboard EEPROM values without writing") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help") or (not vm.count("values") and not vm.count("read-all"))){ + std::cout << boost::format("OctoClock Burn EEPROM %s") % desc << std::endl; + std::cout << boost::format( + "Omit the value argument to perform a readback,\n" + "Or specify a new value to burn into the EEPROM.\n" + ) << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Creating OctoClock device from args: " + args << std::endl; + device::sptr oc = device::make(args, device::CLOCK); + property_tree::sptr tree = oc->get_tree(); + octoclock_eeprom_t oc_eeprom = tree->access<octoclock_eeprom_t>("/mboards/0/eeprom").get(); + std::cout << std::endl; + + std::vector<std::string> keys_vec, vals_vec; + if(vm.count("read-all")) keys_vec = oc_eeprom.keys(); //Leaving vals_vec empty will force utility to only read + else if(vm.count("values")){ + //uhd::device_addr_t properly parses input values + device_addr_t vals(input_str); + keys_vec = vals.keys(); + vals_vec = vals.vals(); + } + else throw std::runtime_error("Must specify --values or --read-all option!"); + + std::cout << "Fetching current settings from EEPROM..." << std::endl; + for(size_t i = 0; i < keys_vec.size(); i++){ + if (not oc_eeprom.has_key(keys_vec[i])){ + std::cerr << boost::format("Cannot find value for EEPROM[\"%s\"]") % keys_vec[i] << std::endl; + return EXIT_FAILURE; + } + std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % oc_eeprom[keys_vec[i]] << std::endl; + } + if(!vm.count("read-all")){ + std::cout << std::endl; + for(size_t i = 0; i < vals_vec.size(); i++){ + if(vals_vec[i] != ""){ + oc_eeprom[keys_vec[i]] = vals_vec[i]; + std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % keys_vec[i] % vals_vec[i] << std::endl; + } + } + tree->access<octoclock_eeprom_t>("/mboards/0/eeprom").set(oc_eeprom); + } + std::cout << std::endl << "Power-cycle your device to allow any changes to take effect." << std::endl; + return EXIT_SUCCESS; +} diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp new file mode 100644 index 000000000..bc91f22f9 --- /dev/null +++ b/host/utils/octoclock_firmware_burner.cpp @@ -0,0 +1,351 @@ +// +// Copyright 2014 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 <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/images.hpp> +#include <uhd/utils/paths.hpp> +#include <uhd/utils/safe_main.hpp> + +#include "../lib/usrp_clock/octoclock/common.h" +#include "ihexcvt.hpp" + +#define MAX_FIRMWARE_SIZE 1024*120 +#define BLOCK_SIZE 256 +#define UDP_TIMEOUT 5 + +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; +size_t num_blocks = 0; + +/* + * 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; + } +} + +/* + * 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(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_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(firmware_path.c_str(), std::ios::binary); + firmware_file.seekg(0, std::ios::end); + firmware_size = firmware_file.tellg(); + 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.seekg(0, std::ios::beg); + firmware_file.read((char*)firmware_image, firmware_size); + firmware_file.close(); + + num_blocks = (firmware_size % BLOCK_SIZE) ? (firmware_size / BLOCK_SIZE) + : ((firmware_size / BLOCK_SIZE) + 1); +} + +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 = uhd::htonx<boost::uint16_t>((boost::uint16_t)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, 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; + 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 + 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; + + memset(pkt_out.data, 0, BLOCK_SIZE); + memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], std::min(int(firmware_size-current_pos), BLOCK_SIZE)); + UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FILE_TRANSFER_CMD, pkt_out, len, octoclock_data); + if(not (UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len))){ + std::cout << std::endl; + 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; + + std::cout << "Verifying firmware." << std::endl; + + 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, 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; + throw uhd::runtime_error("Failed to verify OctoClock firmware!"); + } + } + else{ + std::cout << std::endl; + throw uhd::runtime_error("Failed to verify OctoClock firmware!"); + } + } + + std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl; +} + +void 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, RESET_CMD, pkt_out, len, octoclock_data); + if(UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)) std::cout << "done." << std::endl; + else throw uhd::runtime_error("Failed to place device in state to receive firmware."); +} + +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; + + std::cout << std::endl << "Telling OctoClock to load application..." << std::flush; + UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data); + if(UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)) std::cout << "done." << std::endl; + else std::cout << "no ACK. Device may not have loaded application." << std::endl; +} + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + std::string ip_addr; + 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.") + ("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.bin"); + + //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())); + Hex2Bin(firmware_path.c_str(), temp_bin.string().c_str(), false); + + firmware_path = temp_bin.string(); + } + else if(ext == ".bin"){ + 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 in application, quietly reset into bootloader and try to find again + if(octoclocks[0]["type"] == "octoclock"){ + reset_octoclock(ip_addr); + boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); + octoclocks = bootloader_find(ip_addr); + if(octoclocks.size() == 1) std::cout << "found." << std::endl; + else{ + std::cout << std::endl; + throw uhd::runtime_error("Could not find OctoClock with given IP address!"); + } + } + else std::cout << "found." << std::endl; + } + else{ + std::cout << std::endl; + throw uhd::runtime_error("Could not find OctoClock with given IP address!"); + } + + read_firmware(); + + std::signal(SIGINT, &sig_int_handler); + + burn_firmware(udp_transport); + verify_firmware(udp_transport); + finalize(udp_transport); + + std::cout << "Waiting for OctoClock to reinitialize..." << std::flush; + boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); + 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; + throw uhd::runtime_error("OctoClock failed to leave bootloader state."); + } + else{ + std::cout << "found." << std::endl << std::endl + << "Successfully burned firmware." << std::endl << std::endl; + } + } + else{ + std::cout << std::endl; + throw uhd::runtime_error("Failed to reinitialize OctoClock."); + } + + return EXIT_SUCCESS; +} diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index 98ed84850..cfbfe5f20 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -192,6 +192,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("args", po::value<std::string>()->default_value(""), "device address args") ("tree", "specify to print a complete property tree") ("string", po::value<std::string>(), "query a string value from the properties tree") + ("init-only", "skip all queries, only initialize device") ; po::variables_map vm; @@ -209,7 +210,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ return EXIT_SUCCESS; } - device::sptr dev = device::make(vm["args"].as<std::string>()); + device::sptr dev = device::make(vm["args"].as<std::string>(), device::USRP); property_tree::sptr tree = dev->get_tree(); if (vm.count("string")){ @@ -218,7 +219,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } if (vm.count("tree") != 0) print_tree("/", tree); - else std::cout << make_border(get_device_pp_string(tree)) << std::endl; + else if (not vm.count("init-only")) std::cout << make_border(get_device_pp_string(tree)) << std::endl; return EXIT_SUCCESS; } diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp index 3ca953115..7b483d2e7 100644 --- a/host/utils/usrp_burn_db_eeprom.cpp +++ b/host/utils/usrp_burn_db_eeprom.cpp @@ -62,7 +62,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } //make the device and extract the dboard w/ property - device::sptr dev = device::make(args); + device::sptr dev = device::make(args, device::USRP); uhd::property_tree::sptr tree = dev->get_tree(); const uhd::fs_path db_root = "/mboards/0/dboards"; std::vector<std::string> dboard_names = tree->list(db_root); diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp index f3e12c765..92df9d7d4 100644 --- a/host/utils/usrp_burn_mb_eeprom.cpp +++ b/host/utils/usrp_burn_mb_eeprom.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010,2013 Ettus Research LLC +// Copyright 2010,2013-2014 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include <uhd/device.hpp> #include <uhd/property_tree.hpp> #include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/device_addr.hpp> #include <boost/algorithm/string.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> @@ -28,14 +29,16 @@ namespace po = boost::program_options; int UHD_SAFE_MAIN(int argc, char *argv[]){ - std::string args, key, val; + std::string args, input_str, key, val; po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") - ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\"") - ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\"") + ("values", po::value<std::string>(&input_str), "keys+values to read/write, separate multiple by \",\"") + ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\" (DEPRECATED)") + ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\" (DEPRECATED)") + ("read-all", "Read all motherboard EEPROM values without writing") ; po::variables_map vm; @@ -43,7 +46,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::notify(vm); //print the help message - if (vm.count("help") or not vm.count("key")){ + if (vm.count("help") or (not vm.count("key") and not vm.count("values") and not vm.count("read-all"))){ std::cout << boost::format("USRP Burn Motherboard EEPROM %s") % desc << std::endl; std::cout << boost::format( "Omit the value argument to perform a readback,\n" @@ -53,25 +56,35 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } std::cout << "Creating USRP device from address: " + args << std::endl; - uhd::device::sptr dev = uhd::device::make(args); + uhd::device::sptr dev = uhd::device::make(args, uhd::device::USRP); uhd::property_tree::sptr tree = dev->get_tree(); + uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); std::cout << std::endl; - //remove whitespace, split arguments and values - boost::algorithm::erase_all(key, " "); - boost::algorithm::erase_all(val, " "); - std::vector<std::string> keys_vec, vals_vec; - boost::split(keys_vec, key, boost::is_any_of("\"',")); - boost::split(vals_vec, val, boost::is_any_of("\"',")); + if(vm.count("read-all")) keys_vec = mb_eeprom.keys(); //Leaving vals_vec empty will force utility to only read + else if(vm.count("values")){ + //uhd::device_addr_t properly parses input values + uhd::device_addr_t vals(input_str); + keys_vec = vals.keys(); + vals_vec = vals.vals(); + } + else{ + std::cout << "WARNING: Use of --key and --val is deprecated!" << std::endl; + //remove whitespace, split arguments and values + boost::algorithm::erase_all(key, " "); + boost::algorithm::erase_all(val, " "); + + boost::split(keys_vec, key, boost::is_any_of("\"',")); + boost::split(vals_vec, val, boost::is_any_of("\"',")); - if((keys_vec.size() != vals_vec.size()) and val != "") { - //If zero values are given, then user just wants values read to them - throw std::runtime_error("Number of keys must match number of values!"); + if((keys_vec.size() != vals_vec.size()) and val != "") { + //If zero values are given, then user just wants values read to them + throw std::runtime_error("Number of keys must match number of values!"); + } } std::cout << "Fetching current settings from EEPROM..." << std::endl; - uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); for(size_t i = 0; i < keys_vec.size(); i++){ if (not mb_eeprom.has_key(keys_vec[i])){ std::cerr << boost::format("Cannot find value for EEPROM[%s]") % keys_vec[i] << std::endl; @@ -80,16 +93,16 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % mb_eeprom[keys_vec[i]] << std::endl; } std::cout << std::endl; - if (vm.count("val")){ - mb_eeprom = uhd::usrp::mboard_eeprom_t(); - for(size_t i = 0; i < vals_vec.size(); i++){ + mb_eeprom = uhd::usrp::mboard_eeprom_t(); + for(size_t i = 0; i < vals_vec.size(); i++){ + if(vals_vec[i] != ""){ mb_eeprom[keys_vec[i]] = vals_vec[i]; std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % keys_vec[i] % vals_vec[i] << std::endl; } - tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); - std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl; - std::cout << std::endl; } + tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); + std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl; + std::cout << std::endl; std::cout << "Done" << std::endl; return EXIT_SUCCESS; diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp index 2a766a345..fe437a2e5 100644 --- a/host/utils/usrp_n2xx_simple_net_burner.cpp +++ b/host/utils/usrp_n2xx_simple_net_burner.cpp @@ -57,9 +57,11 @@ using namespace uhd::transport; #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 PROD_FW_IMAGE_LOCATION_ADDR 0x00300000 #define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000 + +#define PROD_FW_IMAGE_LOCATION_ADDR 0x00300000 #define SAFE_FW_IMAGE_LOCATION_ADDR 0x003F0000 typedef enum { @@ -113,6 +115,7 @@ typedef struct { //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") @@ -181,25 +184,39 @@ void list_usrps(){ /*********************************************************************** * Find USRP N2XX with specified IP address and return type **********************************************************************/ -boost::uint32_t find_usrp(udp_simple::sptr udp_transport){ +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>(GET_HW_REV_CMD); + 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) == GET_HW_REV_ACK){ + 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 throw std::runtime_error("Invalid revision found."); + 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."); @@ -210,27 +227,27 @@ boost::uint32_t find_usrp(udp_simple::sptr udp_transport){ * Custom filename validation functions **********************************************************************/ -void validate_custom_fpga_file(std::string rev_str, std::string& fpga_path){ +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)); - //Check to find rev_str in filename + //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){ + 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){ +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)); - //Check to find truncated rev_str in filename + //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){ + 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))); } @@ -329,10 +346,12 @@ boost::uint32_t* get_flash_info(std::string& ip_addr){ * Image burning functions **********************************************************************/ -void erase_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint32_t memory_size){ +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 ? PROD_FW_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; + 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; @@ -378,10 +397,13 @@ void erase_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint32_t mem } } -void write_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, boost::uint32_t memory_size, int image_size){ +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 ? PROD_FW_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; + 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"; @@ -418,11 +440,14 @@ void write_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* ima 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){ +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 ? PROD_FW_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; + 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"; @@ -501,6 +526,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("no_fw", "Do not burn a firmware image (DEPRECATED).") ("no-fpga", "Do not burn an FPGA image.") ("no_fpga", "Do not burn an FPGA image (DEPRECATED).") + ("overwrite-safe", "Overwrite safe images (not recommended).") + ("dont-check-rev", "Don't verify images are for correct model before burning.") ("auto-reboot", "Automatically reboot N2XX without prompting.") ("auto_reboot", "Automatically reboot N2XX without prompting (DEPRECATED).") ("list", "List available N2XX USRP devices.") @@ -518,25 +545,52 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ return EXIT_SUCCESS; } - //List option + //List options if(vm.count("list")){ list_usrps(); return EXIT_SUCCESS; } - //Process user options + //Store user options bool burn_fpga = (vm.count("no-fpga") == 0) and (vm.count("no_fpga") == 0); bool burn_fw = (vm.count("no-fw") == 0) and (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) or (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 + } //Print deprecation messages if necessary if(vm.count("no_fpga") > 0) std::cout << "WARNING: --no_fpga option is deprecated! Use --no-fpga instead." << std::endl << std::endl; @@ -546,7 +600,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //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); + 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; @@ -556,7 +610,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ #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); + 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]); @@ -571,7 +625,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ #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); + 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)); @@ -594,15 +648,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //Burning images std::signal(SIGINT, &sig_int_handler); if(burn_fpga){ - erase_image(udp_transport, false, flash_info[1]); - write_image(udp_transport, false, fpga_image, flash_info[1], fpga_image_size); - verify_image(udp_transport, false, fpga_image, flash_info[1], fpga_image_size); + 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]); - write_image(udp_transport, true, fw_image, flash_info[1], fw_image_size); - verify_image(udp_transport, true, fw_image, flash_info[1], fw_image_size); + 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); diff --git a/host/utils/usrp_x3xx_fpga_burner.cpp b/host/utils/usrp_x3xx_fpga_burner.cpp index ea24c4c15..b849cfb92 100644 --- a/host/utils/usrp_x3xx_fpga_burner.cpp +++ b/host/utils/usrp_x3xx_fpga_burner.cpp @@ -118,7 +118,7 @@ boost::uint8_t bitswap(uint8_t b){ } void list_usrps(){ - device_addrs_t found_devices = device::find(device_addr_t("type=x300")); + 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){ @@ -142,7 +142,7 @@ void list_usrps(){ 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_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!"); @@ -161,7 +161,7 @@ device_addr_t find_usrp_with_ethernet(std::string ip_addr, bool output){ 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_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!"); |