summaryrefslogtreecommitdiffstats
path: root/host/utils
diff options
context:
space:
mode:
Diffstat (limited to 'host/utils')
-rw-r--r--host/utils/CMakeLists.txt23
-rwxr-xr-xhost/utils/FastSendDatagramThreshold.regbin0 -> 312 bytes
-rw-r--r--host/utils/query_gpsdo_sensors.cpp122
-rw-r--r--host/utils/uhd_cal_rx_iq_balance.cpp5
-rw-r--r--host/utils/uhd_cal_tx_dc_offset.cpp5
-rw-r--r--host/utils/uhd_cal_tx_iq_balance.cpp5
-rw-r--r--host/utils/uhd_images_downloader.py.in109
-rw-r--r--host/utils/uhd_usrp_probe.cpp12
-rw-r--r--host/utils/usrp_cal_utils.hpp46
-rwxr-xr-xhost/utils/usrp_n2xx_net_burner.py16
-rwxr-xr-xhost/utils/usrp_n2xx_net_burner_gui.py9
-rw-r--r--host/utils/usrp_n2xx_simple_net_burner.cpp518
-rw-r--r--host/utils/usrp_simple_burner_utils.hpp99
13 files changed, 949 insertions, 20 deletions
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 0ecd6b4e7..9e997071e 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2011 Ettus Research LLC
+# Copyright 2010-2012 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
@@ -38,8 +38,10 @@ ENDFOREACH(util_source)
# Utilities that get installed into the share path
########################################################################
SET(util_share_sources
+ query_gpsdo_sensors.cpp
usrp_burn_db_eeprom.cpp
usrp_burn_mb_eeprom.cpp
+ usrp_n2xx_simple_net_burner.cpp
)
IF(ENABLE_USB)
@@ -64,6 +66,17 @@ FOREACH(util_source ${util_share_sources})
INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)
ENDFOREACH(util_source)
+#UHD images downloader configuration
+CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/uhd_images_downloader.py.in
+ ${CMAKE_CURRENT_BINARY_DIR}/uhd_images_downloader.py
+@ONLY)
+INSTALL(PROGRAMS
+ ${CMAKE_CURRENT_BINARY_DIR}/uhd_images_downloader.py
+ DESTINATION ${PKG_LIB_DIR}/utils
+ COMPONENT utilities
+)
+
IF(ENABLE_USRP2)
IF(WIN32 AND UHD_RELEASE_MODE) #include dd.exe
FILE(DOWNLOAD
@@ -76,8 +89,14 @@ IF(ENABLE_USRP2)
COMPONENT utilities
)
ENDIF(WIN32 AND UHD_RELEASE_MODE)
+ IF(LINUX)
+ INSTALL(PROGRAMS
+ usrp2_recovery.py
+ DESTINATION ${PKG_LIB_DIR}/utils
+ COMPONENT utilities
+ )
+ ENDIF(LINUX)
INSTALL(PROGRAMS
- usrp2_recovery.py
usrp2_card_burner.py
usrp2_card_burner_gui.py
usrp_n2xx_net_burner.py
diff --git a/host/utils/FastSendDatagramThreshold.reg b/host/utils/FastSendDatagramThreshold.reg
new file mode 100755
index 000000000..c0665d09e
--- /dev/null
+++ b/host/utils/FastSendDatagramThreshold.reg
Binary files differ
diff --git a/host/utils/query_gpsdo_sensors.cpp b/host/utils/query_gpsdo_sensors.cpp
new file mode 100644
index 000000000..de6bdcd72
--- /dev/null
+++ b/host/utils/query_gpsdo_sensors.cpp
@@ -0,0 +1,122 @@
+//
+// Copyright 2012 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/utils/paths.hpp>
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/multi_usrp.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+#include <boost/thread.hpp>
+#include <string>
+#include <cmath>
+#include <cstdlib>
+
+namespace po = boost::program_options;
+namespace fs = boost::filesystem;
+
+void print_notes(void) {
+ // Helpful notes
+ std::cout << boost::format("**************************************Helpful Notes on Clock/PPS Selection**************************************\n");
+ std::cout << boost::format("As you can see, the default 10 MHz Reference and 1 PPS signals are now from the GPSDO.\n");
+ std::cout << boost::format("If you would like to use the internal reference(TCXO) in other applications, you must configure that explicitly.\n");
+ std::cout << boost::format("You can no longer select the external SMAs for 10 MHz or 1 PPS signaling.\n");
+ std::cout << boost::format("****************************************************************************************************************\n");
+}
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
+ std::string args;
+
+ //Set up program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "Specify a single USRP.")
+ ;
+ 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")) {
+ std::cout << boost::format("Query GPSDO Sensors %s") % desc << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //Create a USRP device
+ std::cout << boost::format("\nCreating the USRP device with: %s...\n") % args;
+ uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+ std::cout << boost::format("Using Device: %s\n") % usrp->get_pp_string();
+
+ print_notes();
+
+
+ //Verify GPS sensors are present (i.e. EEPROM has been burnt)
+ std::vector<std::string> sensor_names = usrp->get_mboard_sensor_names(0);
+
+ if(std::find(sensor_names.begin(), sensor_names.end(), "gps_locked") == sensor_names.end()) {
+ std::cout << boost::format("\ngps_locked sensor not found. This could mean that you have not installed the GPSDO correctly.\n\n");
+ std::cout << boost::format("Visit this page if the problem persists:\n");
+ std::cout << boost::format("http://files.ettus.com/uhd_docs/manual/html/gpsdo.html\n\n");
+ exit(EXIT_FAILURE);
+ }
+
+ //Check for GPS lock
+ uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("gps_locked",0);
+ if(not gps_locked.to_bool()) {
+ std::cout << boost::format("\nGPS does not have lock. Wait a few minutes and try again.\n");
+ std::cout << boost::format("NMEA strings and device time may not be accurate until lock is achieved.\n\n");
+ } else
+ std::cout << boost::format("GPS Locked\n");
+
+ //Check for 10 MHz lock
+ if(std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end()) {
+ uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("ref_locked",0);
+ if(not gps_locked.to_bool()) {
+ std::cout << boost::format("USRP NOT Locked to GPSDO 10 MHz Reference.\n");
+ std::cout << boost::format("Double check installation instructions: https://www.ettus.com/content/files/gpsdo-kit_2.pdf\n\n");
+ } else
+ std::cout << boost::format("USRP Locked to GPSDO 10 MHz Reference.\n");
+ }else
+ std::cout << boost::format("ref_locked sensor not present on this board.\n");
+
+ //Check PPS and compare UHD device time to GPS time
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ uhd::sensor_value_t gps_time = usrp->get_mboard_sensor("gps_time");
+ const uhd::time_spec_t last_pps_time = usrp->get_time_last_pps();
+ if (last_pps_time.get_full_secs() == gps_time.to_int()) {
+ std::cout << boost::format("GPS and UHD Device time are aligned.\n");
+ } else
+ std::cout << boost::format("\nGPS and UHD Device time are NOT aligned. Try re-running the program. Double check 1 PPS connection from GPSDO.\n\n");
+
+ //print NMEA strings
+ std::cout << boost::format("Printing available NMEA strings:\n");
+ uhd::sensor_value_t gga_string = usrp->get_mboard_sensor("gps_gpgga");
+ uhd::sensor_value_t rmc_string = usrp->get_mboard_sensor("gps_gprmc");
+ std::cout << boost::format("%s\n%s\n%s\n") % gga_string.to_pp_string() % rmc_string.to_pp_string() % gps_time.to_pp_string();
+ std::cout << boost::format("UHD Device time: %.0f seconds\n") % (last_pps_time.get_real_secs());
+
+ //finished
+ std::cout << boost::format("\nDone!\n\n");
+
+ return EXIT_SUCCESS;
+}
diff --git a/host/utils/uhd_cal_rx_iq_balance.cpp b/host/utils/uhd_cal_rx_iq_balance.cpp
index 7b6f10f3b..68d0443da 100644
--- a/host/utils/uhd_cal_rx_iq_balance.cpp
+++ b/host/utils/uhd_cal_rx_iq_balance.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010,2012 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
@@ -135,6 +135,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
usrp->set_rx_antenna("CAL");
usrp->set_tx_antenna("CAL");
+ //fail if daughterboard has no serial
+ check_for_empty_serial(usrp, "RX", "rx", args);
+
//set optimum defaults
set_optimum_defaults(usrp);
diff --git a/host/utils/uhd_cal_tx_dc_offset.cpp b/host/utils/uhd_cal_tx_dc_offset.cpp
index 1b2510ba4..8f69b3ce1 100644
--- a/host/utils/uhd_cal_tx_dc_offset.cpp
+++ b/host/utils/uhd_cal_tx_dc_offset.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010,2012 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
@@ -138,6 +138,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
usrp->set_rx_antenna("CAL");
usrp->set_tx_antenna("CAL");
+ //fail if daughterboard has no serial
+ check_for_empty_serial(usrp, "TX", "tx", args);
+
//set optimum defaults
set_optimum_defaults(usrp);
diff --git a/host/utils/uhd_cal_tx_iq_balance.cpp b/host/utils/uhd_cal_tx_iq_balance.cpp
index cff3d1646..5478b07e3 100644
--- a/host/utils/uhd_cal_tx_iq_balance.cpp
+++ b/host/utils/uhd_cal_tx_iq_balance.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010,2012 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
@@ -138,6 +138,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
usrp->set_rx_antenna("CAL");
usrp->set_tx_antenna("CAL");
+ //fail if daughterboard has no serial
+ check_for_empty_serial(usrp, "TX", "tx", args);
+
//set optimum defaults
set_optimum_defaults(usrp);
diff --git a/host/utils/uhd_images_downloader.py.in b/host/utils/uhd_images_downloader.py.in
new file mode 100644
index 000000000..8c8d2df81
--- /dev/null
+++ b/host/utils/uhd_images_downloader.py.in
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 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/>.
+#
+
+import atexit
+from optparse import OptionParser
+import os
+import os.path
+import shutil
+import sys
+import tempfile
+import urllib2
+import zipfile
+
+class temp_dir():
+
+ def __enter__(self):
+ self.name = tempfile.mkdtemp()
+ return self.name
+ def __exit__(self, type, value, traceback):
+ os.removedirs(self.name)
+
+if __name__ == "__main__":
+
+ #Command line options
+ parser = OptionParser()
+ parser.add_option("--install-location", type="string", default="", help="Set custom install location for images")
+ parser.add_option("--buffer-size", type="int", default=8192, help="Set download buffer size, [default=%default]",)
+ (options, args) = parser.parse_args()
+
+ #Configuring image download info
+ images_src = "@UHD_IMAGES_DOWNLOAD_SRC@"
+ filename = images_src.split("/")[-1]
+
+ with temp_dir() as dirname:
+ os.chdir(dirname)
+
+ #Configuring image destination
+ if options.install_location != "":
+ images_dir = options.install_location
+ elif os.environ.get("UHD_IMAGES_DIR") != "" and os.environ.get("UHD_IMAGES_DIR") != None:
+ images_dir = os.environ.get("UHD_IMAGES_DIR")
+ else:
+ images_dir = "@CMAKE_INSTALL_PREFIX@/share/uhd/images"
+
+ u = urllib2.urlopen(images_src)
+ f = open(filename, "wb")
+ meta = u.info()
+ filesize = float(meta.getheaders("Content-Length")[0])
+
+ print "Downloading images from: %s" % images_src
+
+ filesize_dl = 0.0
+
+ #Downloading file
+ while True:
+ buffer = u.read(options.buffer_size)
+ if not buffer:
+ break
+
+ filesize_dl -= len(buffer)
+ f.write(buffer)
+
+ status = r"%2.2f MB/%2.2f MB (%3.2f" % (-filesize_dl/1e6, filesize/1e6, (-filesize_dl*100.)/filesize) + r"%)"
+ status += chr(8)*(len(status)+1)
+ print status,
+
+ f.close()
+
+ #Extracting contents of zip file
+ if os.path.exists("tempdir"):
+ shutil.rmtree("tempdir")
+ os.mkdir("tempdir")
+
+ images_zip = zipfile.ZipFile(filename)
+ images_zip.extractall("tempdir")
+
+ #Removing images currently in images_dir
+ if os.path.exists(images_dir):
+ try:
+ shutil.rmtree(images_dir)
+ except:
+ sys.stderr.write("\nMake sure you have write permissions in the images directory.\n")
+ sys.exit(0)
+
+ #Copying downloaded images into images_dir
+ shutil.copytree("tempdir/%s/share/uhd/images" % filename[:-4],images_dir)
+
+ #Removing tempdir and zip file
+ shutil.rmtree("tempdir")
+ images_zip.close()
+ os.remove(filename)
+
+ os.chdir(images_dir)
+ print "\nImages successfully installed to: %s" % images_dir
diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp
index 1bd49a5ff..5b3702fb4 100644
--- a/host/utils/uhd_usrp_probe.cpp
+++ b/host/utils/uhd_usrp_probe.cpp
@@ -69,9 +69,9 @@ static std::string prop_names_to_pp_string(const std::vector<std::string> &prop_
return ss.str();
}
-static std::string get_subdev_pp_string(const std::string &type, property_tree::sptr tree, const fs_path &path){
+static std::string get_frontend_pp_string(const std::string &type, property_tree::sptr tree, const fs_path &path){
std::stringstream ss;
- ss << boost::format("%s Subdev: %s") % type % path.leaf() << std::endl;
+ ss << boost::format("%s Frontend: %s") % type % path.leaf() << std::endl;
//ss << std::endl;
ss << boost::format("Name: %s") % (tree->access<std::string>(path / "name").get()) << std::endl;
@@ -123,7 +123,7 @@ static std::string get_dboard_pp_string(const std::string &type, property_tree::
if (not gdb_eeprom.serial.empty()) ss << boost::format("Serial: %s") % gdb_eeprom.serial << std::endl;
}
BOOST_FOREACH(const std::string &name, tree->list(path / (prefix + "_frontends"))){
- ss << make_border(get_subdev_pp_string(type, tree, path / (prefix + "_frontends") / name));
+ ss << make_border(get_frontend_pp_string(type, tree, path / (prefix + "_frontends") / name));
}
ss << make_border(get_codec_pp_string(type, tree, path.branch_path().branch_path() / (prefix + "_codecs") / path.leaf()));
return ss.str();
@@ -137,6 +137,12 @@ static std::string get_mboard_pp_string(property_tree::sptr tree, const fs_path
BOOST_FOREACH(const std::string &key, mb_eeprom.keys()){
if (not mb_eeprom[key].empty()) ss << boost::format("%s: %s") % key % mb_eeprom[key] << std::endl;
}
+ if (tree->exists(path / "fw_version")){
+ ss << "FW Version: " << tree->access<std::string>(path / "fw_version").get() << std::endl;
+ }
+ if (tree->exists(path / "fpga_version")){
+ ss << "FPGA Version: " << tree->access<std::string>(path / "fpga_version").get() << std::endl;
+ }
ss << std::endl;
ss << "Time sources: " << prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "time_source" / "options").get()) << std::endl;
ss << "Clock sources: " << prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "clock_source" / "options").get()) << std::endl;
diff --git a/host/utils/usrp_cal_utils.hpp b/host/utils/usrp_cal_utils.hpp
index ba9ebe35a..bda6fc31b 100644
--- a/host/utils/usrp_cal_utils.hpp
+++ b/host/utils/usrp_cal_utils.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011-2012 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,11 +19,14 @@
#include <uhd/property_tree.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
+#include <uhd/utils/paths.hpp>
#include <boost/filesystem.hpp>
+#include <boost/format.hpp>
#include <iostream>
#include <vector>
#include <complex>
#include <cmath>
+#include <cstdlib>
#include <fstream>
namespace fs = boost::filesystem;
@@ -68,7 +71,13 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
const uhd::fs_path tx_fe_path = "/mboards/0/dboards/A/tx_frontends/0";
const std::string tx_name = tree->access<std::string>(tx_fe_path / "name").get();
- if (tx_name.find("WBX") != std::string::npos or tx_name.find("SBX") != std::string::npos){
+ if (tx_name.find("WBX") != std::string::npos){
+ usrp->set_tx_gain(0);
+ }
+ else if (tx_name.find("SBX") != std::string::npos){
+ usrp->set_tx_gain(0);
+ }
+ else if (tx_name.find("RFX") != std::string::npos){
usrp->set_tx_gain(0);
}
else{
@@ -77,7 +86,13 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
const uhd::fs_path rx_fe_path = "/mboards/0/dboards/A/rx_frontends/0";
const std::string rx_name = tree->access<std::string>(rx_fe_path / "name").get();
- if (rx_name.find("WBX") != std::string::npos or rx_name.find("SBX") != std::string::npos){
+ if (rx_name.find("WBX") != std::string::npos){
+ usrp->set_rx_gain(25);
+ }
+ else if (rx_name.find("SBX") != std::string::npos){
+ usrp->set_rx_gain(25);
+ }
+ else if (rx_name.find("RFX") != std::string::npos){
usrp->set_rx_gain(25);
}
else{
@@ -87,6 +102,30 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
}
/***********************************************************************
+ * Check for empty serial
+ **********************************************************************/
+
+void check_for_empty_serial(
+ uhd::usrp::multi_usrp::sptr usrp,
+ std::string XX,
+ std::string xx,
+ std::string uhd_args
+){
+
+ //extract eeprom
+ uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
+ const uhd::fs_path db_path = "/mboards/0/dboards/A/" + xx + "_eeprom";
+ const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get();
+
+ std::string args_str = "";
+ if(uhd_args != "") args_str = str(boost::format(" --args=%s") % uhd_args);
+
+ std::string error_string = str(boost::format("This %s dboard has no serial!\n\nPlease see the Calibration documentation for details on how to fix this.") % XX);
+
+ if (db_eeprom.serial.empty()) throw std::runtime_error(error_string);
+}
+
+/***********************************************************************
* Sinusoid wave table
**********************************************************************/
class wave_table{
@@ -148,7 +187,6 @@ static void store_results(
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path db_path = "/mboards/0/dboards/A/" + xx + "_eeprom";
const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get();
- if (db_eeprom.serial.empty()) throw std::runtime_error(XX + " dboard has empty serial!");
//make the calibration file path
fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd";
diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py
index f2cfb8ecf..8f16de501 100755
--- a/host/utils/usrp_n2xx_net_burner.py
+++ b/host/utils/usrp_n2xx_net_burner.py
@@ -222,7 +222,9 @@ def enumerate_devices():
pkt = sock.recv(UDP_MAX_XFER_BYTES)
(proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(pkt)
if(pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG):
- yield socket.inet_ntoa(struct.pack("<L", socket.ntohl(ip_addr)))
+ use_addr = socket.inet_ntoa(struct.pack("<L", socket.ntohl(ip_addr)))
+ burner = burner_socket(use_addr, True)
+ yield "%s (%s)" % (socket.inet_ntoa(struct.pack("<L", socket.ntohl(ip_addr))), n2xx_revs[burner.get_hw_rev()][0])
except socket.timeout:
still_goin = False
@@ -230,12 +232,13 @@ def enumerate_devices():
# Burner class, holds a socket and send/recv routines
########################################################################
class burner_socket(object):
- def __init__(self, addr):
+ def __init__(self, addr, quiet):
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ self._quiet = quiet
self._sock.settimeout(UDP_TIMEOUT)
self._sock.connect((addr, UDP_FW_UPDATE_PORT))
self.set_callbacks(lambda *a: None, lambda *a: None)
- self.init_update() #check that the device is there
+ self.init_update(quiet) #check that the device is there
self.get_hw_rev()
def set_callbacks(self, progress_cb, status_cb):
@@ -247,13 +250,13 @@ class burner_socket(object):
return self._sock.recv(UDP_MAX_XFER_BYTES)
#just here to validate comms
- def init_update(self):
+ def init_update(self,quiet):
out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0)
try: in_pkt = self.send_and_recv(out_pkt)
except socket.timeout: raise Exception("No response from device")
(proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(in_pkt)
if pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG:
- print("USRP-N2XX found.")
+ if not quiet: print("USRP-N2XX found.")
else:
raise Exception("Invalid reply received from device.")
@@ -488,6 +491,7 @@ if __name__=='__main__':
if options.list:
print('Possible network devices:')
print(' ' + '\n '.join(enumerate_devices()))
+ #enumerate_devices()
exit()
if not options.addr: raise Exception('no address specified')
@@ -500,7 +504,7 @@ if __name__=='__main__':
response = raw_input("""Type "yes" to continue, or anything else to quit: """)
if response != "yes": sys.exit(0)
- burner = burner_socket(addr=options.addr)
+ burner = burner_socket(addr=options.addr,quiet=False)
if options.read:
if options.fw:
diff --git a/host/utils/usrp_n2xx_net_burner_gui.py b/host/utils/usrp_n2xx_net_burner_gui.py
index e2b79e72c..a9150bd88 100755
--- a/host/utils/usrp_n2xx_net_burner_gui.py
+++ b/host/utils/usrp_n2xx_net_burner_gui.py
@@ -96,7 +96,11 @@ class DeviceEntryWidget(tkinter.Frame):
tkinter.Button(self, text="Rescan for Devices", command=self._reload_cb).pack()
self._hints = tkinter.Listbox(self)
+ self._hints_addrs_only = tkinter.Listbox(self)
+
self._hints.bind("<<ListboxSelect>>", self._listbox_cb)
+ self._hints_addrs_only.bind("<<ListboxSelect>>", self._listbox_cb)
+
self._reload_cb()
self._hints.pack(expand=tkinter.YES, fill=tkinter.X)
@@ -112,10 +116,11 @@ class DeviceEntryWidget(tkinter.Frame):
self._hints.delete(0, tkinter.END)
for hint in usrp_n2xx_net_burner.enumerate_devices():
self._hints.insert(tkinter.END, hint)
+ self._hints_addrs_only.insert(tkinter.END, hint.split(" (")[0])
def _listbox_cb(self, event):
try:
- sel = self._hints.get(self._hints.curselection()[0])
+ sel = self._hints_addrs_only.get(self._hints.curselection()[0])
self._entry.delete(0, tkinter.END)
self._entry.insert(0, sel)
except Exception as e: print(e)
@@ -196,7 +201,7 @@ class USRPN2XXNetBurnerApp(tkinter.Frame):
self._disable_input()
try:
#make a new burner object and attempt the burner operation
- burner = usrp_n2xx_net_burner.burner_socket(addr=addr)
+ burner = usrp_n2xx_net_burner.burner_socket(addr=addr,quiet=False)
for (image_type, fw_img, fpga_img) in (('FPGA', '', fpga), ('Firmware', fw, '')):
#setup callbacks that update the gui
diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp
new file mode 100644
index 000000000..901842538
--- /dev/null
+++ b/host/utils/usrp_n2xx_simple_net_burner.cpp
@@ -0,0 +1,518 @@
+//
+// Copyright 2012 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 <iostream>
+#include <map>
+#include <fstream>
+#include <time.h>
+#include <vector>
+
+#include <boost/foreach.hpp>
+#include <boost/asio.hpp>
+#include <boost/program_options.hpp>
+#include <boost/assign.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <boost/algorithm/string/erase.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/thread/thread.hpp>
+
+#include "usrp_simple_burner_utils.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/property_tree.hpp>
+#include <uhd/transport/if_addrs.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/images.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/utils/safe_call.hpp>
+
+namespace po = boost::program_options;
+using namespace boost::algorithm;
+using namespace uhd;
+using namespace uhd::transport;
+
+//Mapping revision numbers to filenames
+std::map<boost::uint32_t, std::string> filename_map = boost::assign::map_list_of
+ (0xa, "n200_r3")
+ (0x100a, "n200_r4")
+ (0x10a, "n210_r3")
+ (0x110a, "n210_r4")
+;
+
+//Images and image sizes, to be populated as necessary
+boost::uint8_t fpga_image[FPGA_IMAGE_SIZE_BYTES];
+boost::uint8_t fw_image[FW_IMAGE_SIZE_BYTES];
+int fpga_image_size = 0;
+int fw_image_size = 0;
+
+//For non-standard images not covered by uhd::find_image_path()
+bool does_image_exist(std::string image_filepath){
+
+ std::ifstream ifile((char*)image_filepath.c_str());
+ return ifile;
+}
+
+/***********************************************************************
+ * Custom filename validation functions
+ **********************************************************************/
+
+void validate_custom_fpga_file(std::string rev_str, std::string fpga_path){
+
+ //Check for existence of file
+ if(!does_image_exist(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
+ uhd::fs_path custom_fpga_path(fpga_path);
+ if(custom_fpga_path.leaf().find("fw") != std::string::npos){
+ throw std::runtime_error(str(boost::format("Invalid FPGA image filename at path: %s\nFilename indicates that this is a firmware image.")
+ % fpga_path));
+ }
+ if(custom_fpga_path.leaf().find(rev_str) == std::string::npos){
+ 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){
+
+ //Check for existence of file
+ if(!does_image_exist(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
+ uhd::fs_path custom_fw_path(fw_path);
+ if(custom_fw_path.leaf().find("fpga") != std::string::npos){
+ throw std::runtime_error(str(boost::format("Invalid firmware image filename at path: %s\nFilename indicates that this is an FPGA image.")
+ % fw_path));
+ }
+ if(custom_fw_path.leaf().find(erase_tail_copy(rev_str,3)) == std::string::npos){
+ 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)));
+ }
+}
+
+/***********************************************************************
+ * Grabbing and validating image binaries
+ **********************************************************************/
+
+int grab_fpga_image(std::string fpga_path){
+
+ //Reading FPGA image from file
+ std::ifstream to_read_fpga((char*)fpga_path.c_str(), std::ios::binary);
+ to_read_fpga.seekg(0, std::ios::end);
+ fpga_image_size = to_read_fpga.tellg();
+ to_read_fpga.seekg(0, std::ios::beg);
+ char fpga_read[FPGA_IMAGE_SIZE_BYTES];
+ to_read_fpga.read(fpga_read,fpga_image_size);
+ to_read_fpga.close();
+ for(int i = 0; i < fpga_image_size; i++) fpga_image[i] = (boost::uint8_t)fpga_read[i];
+
+ //Checking validity of image
+ if(fpga_image_size > FPGA_IMAGE_SIZE_BYTES){
+ throw std::runtime_error(str(boost::format("FPGA image is too large. %d > %d") % fpga_image_size % FPGA_IMAGE_SIZE_BYTES));
+ }
+
+ //Check sequence of bytes in image
+ bool is_good = false;
+ for(int i = 0; i < 63; i++){
+ if((boost::uint8_t)fpga_image[i] == 255) continue;
+ else if((boost::uint8_t)fpga_image[i] == 170 and
+ (boost::uint8_t)fpga_image[i+1] == 153){
+ is_good = true;
+ break;
+ }
+ }
+
+ if(!is_good) throw std::runtime_error("Not a valid FPGA image.");
+
+ //Return image size
+ return fpga_image_size;
+}
+
+int grab_fw_image(std::string fw_path){
+
+ //Reading firmware image from file
+ std::ifstream to_read_fw((char*)fw_path.c_str(), std::ios::binary);
+ to_read_fw.seekg(0, std::ios::end);
+ fw_image_size = to_read_fw.tellg();
+ to_read_fw.seekg(0, std::ios::beg);
+ char fw_read[FW_IMAGE_SIZE_BYTES];
+ to_read_fw.read(fw_read,fw_image_size);
+ to_read_fw.close();
+ for(int i = 0; i < fw_image_size; i++) fw_image[i] = (boost::uint8_t)fw_read[i];
+
+ //Checking validity of image
+ if(fw_image_size > FW_IMAGE_SIZE_BYTES){
+ throw std::runtime_error(str(boost::format("Firmware image is too large. %d > %d") % fw_image_size % FW_IMAGE_SIZE_BYTES));
+ }
+
+ //Check first four bytes of image
+ for(int i = 0; i < 4; i++) if((boost::uint8_t)fw_image[i] != 11) throw std::runtime_error("Not a valid firmware image.");
+
+ //Return image size
+ return fw_image_size;
+}
+
+boost::uint32_t* get_flash_info(std::string ip_addr){
+
+ boost::uint32_t *flash_info = new boost::uint32_t[2];
+ boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+
+ udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT));
+ usrp2_fw_update_data_t get_flash_info_pkt = usrp2_fw_update_data_t();
+ get_flash_info_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+ get_flash_info_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL);
+ udp_transport->send(boost::asio::buffer(&get_flash_info_pkt, sizeof(get_flash_info_pkt)));
+
+ //Loop and receive until the timeout
+ size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG){
+ flash_info[0] = ntohl(update_data_in->data.flash_info_args.sector_size_bytes);
+ flash_info[1] = ntohl(update_data_in->data.flash_info_args.memory_size_bytes);
+ }
+ else if(ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG){
+ throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") % ntohl(update_data_in->id)));
+ }
+
+ return flash_info;
+}
+
+/***********************************************************************
+ * Image burning functions
+ **********************************************************************/
+
+void erase_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint32_t memory_size){
+
+ //Making sure this won't attempt to erase past end of device
+ if(is_fw){
+ if(PROD_FW_IMAGE_LOCATION_ADDR+FW_IMAGE_SIZE_BYTES > memory_size) throw std::runtime_error("Cannot erase past end of device.");
+ }
+ else{
+ if(PROD_FPGA_IMAGE_LOCATION_ADDR+FPGA_IMAGE_SIZE_BYTES > memory_size) throw std::runtime_error("Cannot erase past end of device.");
+ }
+
+ //Setting up UDP transport
+ boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+
+ //Setting up UDP packet
+ usrp2_fw_update_data_t erase_pkt = usrp2_fw_update_data_t();
+ erase_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL);
+ erase_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+ if(is_fw){
+ erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(PROD_FW_IMAGE_LOCATION_ADDR);
+ erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(FW_IMAGE_SIZE_BYTES);
+ }
+ else{
+ erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(PROD_FPGA_IMAGE_LOCATION_ADDR);
+ erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(FPGA_IMAGE_SIZE_BYTES);
+ }
+
+ //Begin erasing
+ udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt)));
+ size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG){
+ if(is_fw) std::cout << "Erasing firmware image." << std::endl;
+ else std::cout << "Erasing FPGA image." << std::endl;
+ }
+ else if(ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG){
+ throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") % ntohl(update_data_in->id)));
+ }
+
+ //Check for erase completion
+ erase_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL);
+ while(true){
+ udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt)));
+ size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG){
+ if(is_fw) std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") % FW_IMAGE_SIZE_BYTES % PROD_FW_IMAGE_LOCATION_ADDR;
+ else std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") % FPGA_IMAGE_SIZE_BYTES % PROD_FPGA_IMAGE_LOCATION_ADDR;
+ break;
+ }
+ else if(ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG){
+ throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") % ntohl(update_data_in->id)));
+ }
+ }
+}
+
+void write_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, boost::uint32_t memory_size, int image_size){
+
+ boost::uint32_t current_addr;
+ if(is_fw) current_addr = PROD_FW_IMAGE_LOCATION_ADDR;
+ else current_addr = PROD_FPGA_IMAGE_LOCATION_ADDR;
+
+ //Making sure this won't attempt to write past end of device
+ if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot write past end of device.");
+
+ //Setting up UDP transport
+ boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+
+ //Setting up UDP packet
+ usrp2_fw_update_data_t write_pkt = usrp2_fw_update_data_t();
+ write_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL);
+ write_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+ write_pkt.data.flash_args.length = htonx<boost::uint32_t>(FLASH_DATA_PACKET_SIZE);
+
+ //Write image
+ if(is_fw) std::cout << "Writing firmware image." << std::endl;
+ else std::cout << "Writing FPGA image." << std::endl;
+
+ for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){
+ write_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr);
+ std::copy(image+(i*FLASH_DATA_PACKET_SIZE), image+((i+1)*FLASH_DATA_PACKET_SIZE), write_pkt.data.flash_args.data);
+
+ udp_transport->send(boost::asio::buffer(&write_pkt, sizeof(write_pkt)));
+ size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG){
+ throw std::runtime_error(str(boost::format("Invalid reply %d from device.") % ntohl(update_data_in->id)));
+ }
+
+ current_addr += FLASH_DATA_PACKET_SIZE;
+ }
+ std::cout << boost::format(" * Successfully wrote %d bytes.\n") % image_size;
+}
+
+void verify_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, boost::uint32_t memory_size, int image_size){
+
+ int current_index = 0;
+ boost::uint32_t current_addr;
+ if(is_fw) current_addr = PROD_FW_IMAGE_LOCATION_ADDR;
+ else current_addr = PROD_FPGA_IMAGE_LOCATION_ADDR;
+
+ //Array size needs to be known at runtime, this constant is guaranteed to be larger than any firmware or FPGA image
+ boost::uint8_t from_usrp[FPGA_IMAGE_SIZE_BYTES];
+
+ //Making sure this won't attempt to read past end of device
+ if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot read past end of device.");
+
+ //Setting up UDP transport
+ boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+
+ //Setting up UDP packet
+ usrp2_fw_update_data_t verify_pkt = usrp2_fw_update_data_t();
+ verify_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL);
+ verify_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+ verify_pkt.data.flash_args.length = htonx<boost::uint32_t>(FLASH_DATA_PACKET_SIZE);
+
+ //Verify image
+ if(is_fw) std::cout << "Verifying firmware image." << std::endl;
+ else std::cout << "Verifying FPGA image." << std::endl;
+
+ for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){
+ verify_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr);
+
+ udp_transport->send(boost::asio::buffer(&verify_pkt, sizeof(verify_pkt)));
+ size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG){
+ throw std::runtime_error(str(boost::format("Invalid reply %d from device.") % ntohl(update_data_in->id)));
+ }
+ for(int j = 0; j < FLASH_DATA_PACKET_SIZE; j++) from_usrp[current_index+j] = update_data_in->data.flash_args.data[j];
+
+ current_addr += FLASH_DATA_PACKET_SIZE;
+ current_index += FLASH_DATA_PACKET_SIZE;
+ }
+ for(int i = 0; i < image_size; i++) if(from_usrp[i] != image[i]) throw std::runtime_error("Image write failed.");
+
+ std::cout << " * Successful." << std::endl;
+}
+
+void reset_usrp(udp_simple::sptr udp_transport){
+
+ //Set up UDP transport
+ boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+
+ //Set up UDP packet
+ usrp2_fw_update_data_t reset_pkt = usrp2_fw_update_data_t();
+ reset_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL);
+ reset_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+
+ //Reset USRP
+ udp_transport->send(boost::asio::buffer(&reset_pkt, sizeof(reset_pkt)));
+ size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG){
+ throw std::runtime_error("USRP reset failed."); //There should be no response to this UDP packet
+ }
+ else std::cout << "Resetting USRP." << std::endl;
+}
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+
+ //Establish user options
+ std::string fw_path;
+ std::string ip_addr;
+ std::string fpga_path;
+
+ po::options_description desc("Allowed options:");
+ desc.add_options()
+ ("help", "Display this help message.")
+ ("addr", po::value<std::string>(&ip_addr)->default_value("192.168.10.2"), "Specify an IP address.")
+ ("fw", po::value<std::string>(&fw_path), "Specify a filepath for a custom firmware image.")
+ ("fpga", po::value<std::string>(&fpga_path), "Specify a filepath for a custom FPGA image.")
+ ("no_fw", "Do not burn a firmware image.")
+ ("no_fpga", "Do not burn an FPGA image.")
+ ("list", "List available N2XX USRP devices.")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //Apply options
+ if(vm.count("help") > 0){
+ std::cout << boost::format("N2XX Simple Net Burner\n");
+ std::cout << boost::format("Automatically detects and burns standard firmware and FPGA images onto USRP N2XX devices.\n");
+ std::cout << boost::format("Can optionally take user input for custom images.\n\n");
+ std::cout << desc << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ bool burn_fpga = (vm.count("no_fpga") == 0);
+ bool burn_fw = (vm.count("no_fw") == 0);
+ bool use_custom_fpga = (vm.count("fpga") > 0);
+ bool use_custom_fw = (vm.count("fw") > 0);
+ bool list_usrps = (vm.count("list") > 0);
+
+ if(!burn_fpga && !burn_fw){
+ std::cout << "No images will be burned." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!burn_fw && use_custom_fw) std::cout << boost::format("Conflicting firmware options presented. Will not burn a firmware image.\n\n");
+ if(!burn_fpga && use_custom_fpga) std::cout << boost::format("Conflicting FPGA options presented. Will not burn an FPGA image.\n\n");
+
+ //Variables not from options
+ boost::uint32_t hw_rev;
+ bool found_it = false;
+ boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+
+ //List option
+ if(list_usrps){
+ udp_simple::sptr udp_bc_transport;
+ usrp2_fw_update_data_t usrp2_ack_pkt = usrp2_fw_update_data_t();
+ usrp2_ack_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+ usrp2_ack_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_OHAI_LOL);
+
+ std::cout << "Available USRP N2XX devices:" << std::endl;
+
+ //Send UDP packets to all broadcast addresses
+ BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){
+ //Avoid the loopback device
+ if(if_addrs.inet == boost::asio::ip::address_v4::loopback().to_string()) continue;
+ udp_bc_transport = udp_simple::make_broadcast(if_addrs.bcast, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT));
+ udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt)));
+
+ size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_OHAI_OMG){
+ usrp2_ack_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL);
+ udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt)));
+
+ size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG){
+ hw_rev = ntohl(update_data_in->data.hw_rev);
+ }
+
+ std::cout << boost::format(" * %s (%s)\n") % udp_bc_transport->get_recv_addr() % filename_map[hw_rev];
+ }
+
+ }
+ return EXIT_FAILURE;
+ }
+ std::cout << boost::format("Searching for USRP N2XX with IP address %s.\n") % ip_addr;
+
+ //Address specified
+ udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT));
+ 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>(USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL);
+ 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) == USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG){
+ hw_rev = ntohl(update_data_in->data.hw_rev);
+ if(filename_map.find(hw_rev) != filename_map.end()){
+ std::cout << boost::format("Found %s.\n\n") % filename_map[hw_rev];
+ found_it = true;
+ }
+ else throw std::runtime_error("Invalid revision found.");
+ }
+ if(!found_it) throw std::runtime_error("No USRP N2XX found.");
+
+ //Determining default image filenames for validation
+ std::string default_fw_filename = str(boost::format("usrp_%s_fw.bin") % erase_tail_copy(filename_map[hw_rev],3));
+ std::string default_fpga_filename = str(boost::format("usrp_%s_fpga.bin") % filename_map[hw_rev]);
+ std::string default_fw_filepath = "";
+ std::string default_fpga_filepath = "";
+
+ //Check validity of file locations and binaries before attempting burn
+ std::cout << "Searching for specified images." << std::endl << std::endl;
+ if(burn_fpga){
+ if(!use_custom_fpga) fpga_path = find_image_path(default_fpga_filename);
+ else validate_custom_fpga_file(filename_map[hw_rev], fpga_path);
+
+ grab_fpga_image(fpga_path);
+ }
+ if(burn_fw){
+ if(!use_custom_fw) fw_path = find_image_path(default_fw_filename);
+ else validate_custom_fw_file(filename_map[hw_rev], fw_path);
+
+ grab_fw_image(fw_path);
+ }
+
+ std::cout << "Will burn the following images:" << std::endl;
+ if(burn_fw) std::cout << boost::format(" * Firmware: %s\n") % fw_path;
+ if(burn_fpga) std::cout << boost::format(" * FPGA: %s\n") % fpga_path;
+ std::cout << std::endl;
+
+ boost::uint32_t* flash_info = get_flash_info(ip_addr);
+ std::cout << boost::format("Querying %s for flash information.\n") % filename_map[hw_rev];
+ std::cout << boost::format(" * Flash size: %3.2f\n") % flash_info[1];
+ std::cout << boost::format(" * Sector size: %3.2f\n\n") % flash_info[0];
+
+ //Burning images
+
+ 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);
+ }
+ 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);
+ }
+
+ //Prompt user to reset USRP
+ std::string user_response = "foo";
+ bool reset = false;
+ while(user_response != "y" and user_response != "" and user_response != "n"){
+ std::cout << std::endl << "Image burning successful. Reset USRP (Y/n)? ";
+ std::getline(std::cin, user_response);
+ std::transform(user_response.begin(), user_response.end(), user_response.begin(), ::tolower);
+ reset = (user_response == "" or user_response == "y");
+ }
+ std::cout << std::endl; //Formatting
+ if(reset) reset_usrp(udp_transport);
+ else return EXIT_SUCCESS;
+
+ return EXIT_SUCCESS;
+}
diff --git a/host/utils/usrp_simple_burner_utils.hpp b/host/utils/usrp_simple_burner_utils.hpp
new file mode 100644
index 000000000..f386c3620
--- /dev/null
+++ b/host/utils/usrp_simple_burner_utils.hpp
@@ -0,0 +1,99 @@
+//
+// Copyright 2012 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 <iostream>
+#include <math.h>
+#include <stdint.h>
+
+#include <boost/foreach.hpp>
+#include <boost/asio.hpp>
+#include <boost/filesystem.hpp>
+
+#include <uhd/exception.hpp>
+#include <uhd/transport/if_addrs.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <uhd/utils/msg.hpp>
+
+#define UDP_FW_UPDATE_PORT 49154
+#define UDP_MAX_XFER_BYTES 1024
+#define UDP_TIMEOUT 3
+#define UDP_POLL_INTERVAL 0.10 //in seconds
+#define USRP2_FW_PROTO_VERSION 7 //should be unused after r6
+#define USRP2_UDP_UPDATE_PORT 49154
+#define FLASH_DATA_PACKET_SIZE 256
+#define FPGA_IMAGE_SIZE_BYTES 1572864
+#define FW_IMAGE_SIZE_BYTES 31744
+#define PROD_FPGA_IMAGE_LOCATION_ADDR 0x00180000
+#define PROD_FW_IMAGE_LOCATION_ADDR 0x00300000
+#define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000
+#define SAFE_FW_IMAGE_LOCATION_ADDR 0x003F0000
+
+using namespace uhd;
+using namespace uhd::transport;
+namespace asio = boost::asio;
+
+typedef enum {
+ USRP2_FW_UPDATE_ID_WAT = ' ',
+
+ USRP2_FW_UPDATE_ID_OHAI_LOL = 'a',
+ USRP2_FW_UPDATE_ID_OHAI_OMG = 'A',
+
+ USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = 'f',
+ USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = 'F',
+
+ USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = 'e',
+ USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = 'E',
+
+ USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = 'd',
+ USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = 'D',
+ USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = 'B',
+
+ USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = 'w',
+ USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = 'W',
+
+ USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = 'r',
+ USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = 'R',
+
+ USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = 's',
+ USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = 'S',
+
+ USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL = 'v',
+ USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG = 'V',
+
+ USRP2_FW_UPDATE_ID_KTHXBAI = '~'
+
+} usrp2_fw_update_id_t;
+
+typedef struct {
+ uint32_t proto_ver;
+ uint32_t id;
+ uint32_t seq;
+ union {
+ uint32_t ip_addr;
+ uint32_t hw_rev;
+ struct {
+ uint32_t flash_addr;
+ uint32_t length;
+ uint8_t data[256];
+ } flash_args;
+ struct {
+ uint32_t sector_size_bytes;
+ uint32_t memory_size_bytes;
+ } flash_info_args;
+ } data;
+} usrp2_fw_update_data_t;