aboutsummaryrefslogtreecommitdiffstats
path: root/host/utils
diff options
context:
space:
mode:
Diffstat (limited to 'host/utils')
-rw-r--r--host/utils/CMakeLists.txt16
-rw-r--r--host/utils/fx2_init_eeprom.cpp6
-rw-r--r--host/utils/ihexcvt.cpp250
-rw-r--r--host/utils/ihexcvt.hpp22
-rw-r--r--host/utils/octoclock_burn_eeprom.cpp95
-rw-r--r--host/utils/octoclock_firmware_burner.cpp351
-rw-r--r--host/utils/uhd_usrp_probe.cpp5
-rw-r--r--host/utils/usrp_burn_db_eeprom.cpp2
-rw-r--r--host/utils/usrp_burn_mb_eeprom.cpp57
-rw-r--r--host/utils/usrp_n2xx_simple_net_burner.cpp116
-rw-r--r--host/utils/usrp_x3xx_fpga_burner.cpp6
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!");