aboutsummaryrefslogtreecommitdiffstats
path: root/host/utils
diff options
context:
space:
mode:
Diffstat (limited to 'host/utils')
-rw-r--r--host/utils/CMakeLists.txt77
-rw-r--r--host/utils/clkgen-config.cpp296
-rw-r--r--host/utils/fpga-downloader.cpp267
-rw-r--r--host/utils/uhd_find_devices.cpp60
-rw-r--r--host/utils/uhd_usrp_probe.cpp179
-rw-r--r--host/utils/usrp-e-debug-pins.c77
-rw-r--r--host/utils/usrp-e-i2c.c87
-rw-r--r--host/utils/usrp-e-loopback.c231
-rw-r--r--host/utils/usrp-e-spi.c54
-rw-r--r--host/utils/usrp1_init_eeprom.cpp69
-rwxr-xr-xhost/utils/usrp2_card_burner.py246
-rwxr-xr-xhost/utils/usrp2_card_burner_gui.py169
-rwxr-xr-xhost/utils/usrp2_recovery.py68
-rw-r--r--host/utils/usrp_burn_db_eeprom.cpp100
-rw-r--r--host/utils/usrp_burn_mb_eeprom.cpp81
-rw-r--r--host/utils/usrp_e_regs.hpp196
-rwxr-xr-xhost/utils/usrp_n2xx_net_burner.py288
17 files changed, 2545 insertions, 0 deletions
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
new file mode 100644
index 000000000..a8e50f72b
--- /dev/null
+++ b/host/utils/CMakeLists.txt
@@ -0,0 +1,77 @@
+#
+# Copyright 2010 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/>.
+#
+
+########################################################################
+# Utilities that get installed into the runtime path
+########################################################################
+SET(util_runtime_sources
+ uhd_find_devices.cpp
+ uhd_usrp_probe.cpp
+)
+
+#for each source: build an executable and install
+FOREACH(util_source ${util_runtime_sources})
+ GET_FILENAME_COMPONENT(util_name ${util_source} NAME_WE)
+ ADD_EXECUTABLE(${util_name} ${util_source})
+ TARGET_LINK_LIBRARIES(${util_name} uhd)
+ INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${RUNTIME_DIR})
+ENDFOREACH(util_source)
+
+########################################################################
+# Utilities that get installed into the share path
+########################################################################
+SET(util_share_sources
+ usrp_burn_db_eeprom.cpp
+ usrp_burn_mb_eeprom.cpp
+)
+
+IF(ENABLE_USRP1)
+ LIST(APPEND util_share_sources
+ usrp1_init_eeprom.cpp
+ )
+ENDIF(ENABLE_USRP1)
+
+IF(ENABLE_USRP_E100)
+ ENABLE_LANGUAGE(C)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100/include)
+ LIST(APPEND util_share_sources
+ fpga-downloader.cpp
+ clkgen-config.cpp
+ usrp-e-loopback.c
+ usrp-e-debug-pins.c
+ usrp-e-i2c.c
+ usrp-e-spi.c
+ )
+ENDIF(ENABLE_USRP_E100)
+
+#for each source: build an executable and install
+FOREACH(util_source ${util_share_sources})
+ GET_FILENAME_COMPONENT(util_name ${util_source} NAME_WE)
+ ADD_EXECUTABLE(${util_name} ${util_source})
+ TARGET_LINK_LIBRARIES(${util_name} uhd)
+ INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)
+ENDFOREACH(util_source)
+
+IF(ENABLE_USRP2)
+ INSTALL(PROGRAMS
+ usrp2_recovery.py
+ usrp2_card_burner.py
+ usrp2_card_burner_gui.py
+ usrp_n2xx_net_burner.py
+ DESTINATION ${PKG_DATA_DIR}/utils
+ )
+ENDIF(ENABLE_USRP2)
diff --git a/host/utils/clkgen-config.cpp b/host/utils/clkgen-config.cpp
new file mode 100644
index 000000000..e8279b4ae
--- /dev/null
+++ b/host/utils/clkgen-config.cpp
@@ -0,0 +1,296 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of UHD
+ *
+ * GNU Radio 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, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <cstdlib>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/spi/spidev.h>
+
+
+// Programming data for clock gen chip
+static const unsigned int config_data[] = {
+ 0x000024,
+ 0x023201,
+ 0x000081,
+ 0x000400,
+ 0x00104c,
+ 0x001101,
+ 0x001200,
+ 0x001300,
+ 0x001414,
+ 0x001500,
+ 0x001604,
+ 0x001704,
+ 0x001807,
+ 0x001900,
+ //0x001a00,//for debug
+ 0x001a32,
+ 0x001b12,
+ 0x001c44,
+ 0x001d00,
+ 0x001e00,
+ 0x00f062,
+ 0x00f162,
+ 0x00f262,
+ 0x00f362,
+ 0x00f462,
+ 0x00f562,
+ 0x00f662,
+ 0x00f762,
+ 0x00f862,
+ 0x00f962,
+ 0x00fa62,
+ 0x00fb62,
+ 0x00fc00,
+ 0x00fd00,
+ 0x019021,
+ 0x019100,
+ 0x019200,
+ 0x019333,
+ 0x019400,
+ 0x019500,
+ 0x019611,
+ 0x019700,
+ 0x019800,
+ 0x019900,
+ 0x019a00,
+ 0x019b00,
+ 0x01e003,
+ 0x01e102,
+ 0x023000,
+ 0x023201,
+ 0x0b0201,
+ 0x0b0300,
+ 0x001fff,
+ 0x0a0000,
+ 0x0a0100,
+ 0x0a0200,
+ 0x0a0302,
+ 0x0a0400,
+ 0x0a0504,
+ 0x0a060e,
+ 0x0a0700,
+ 0x0a0810,
+ 0x0a090e,
+ 0x0a0a00,
+ 0x0a0bf0,
+ 0x0a0c0b,
+ 0x0a0d01,
+ 0x0a0e90,
+ 0x0a0f01,
+ 0x0a1001,
+ 0x0a11e0,
+ 0x0a1201,
+ 0x0a1302,
+ 0x0a1430,
+ 0x0a1580,
+ 0x0a16ff,
+ 0x023201,
+ 0x0b0301,
+ 0x023201,
+};
+
+
+const unsigned int CLKGEN_SELECT = 145;
+
+
+enum gpio_direction {IN, OUT};
+
+class gpio {
+ public:
+
+ gpio(unsigned int gpio_num, gpio_direction pin_direction, bool close_action);
+ ~gpio();
+
+ bool get_value();
+ void set_value(bool state);
+
+ private:
+
+ unsigned int gpio_num;
+
+ std::stringstream base_path;
+ std::fstream value_file;
+ std::fstream direction_file;
+ bool close_action; // True set to input and release, false do nothing
+};
+
+class spidev {
+ public:
+
+ spidev(std::string dev_name);
+ ~spidev();
+
+ void send(char *wbuf, char *rbuf, unsigned int nbytes);
+
+ private:
+
+ int fd;
+
+};
+
+gpio::gpio(unsigned int _gpio_num, gpio_direction pin_direction, bool close_action)
+{
+ std::fstream export_file;
+
+ gpio_num = _gpio_num;
+
+ export_file.open("/sys/class/gpio/export", std::ios::out);
+ if (!export_file.is_open()) ///\todo Poor error handling
+ std::cout << "Failed to open gpio export file." << std::endl;
+
+ export_file << gpio_num << std::endl;
+
+ base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush;
+
+ std::string direction_file_name;
+
+ direction_file_name = base_path.str() + "/direction";
+
+ direction_file.open(direction_file_name.c_str());
+ if (!direction_file.is_open())
+ std::cout << "Failed to open direction file." << std::endl;
+ if (pin_direction == OUT)
+ direction_file << "out" << std::endl;
+ else
+ direction_file << "in" << std::endl;
+
+ std::string value_file_name;
+
+ value_file_name = base_path.str() + "/value";
+
+ value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out);
+ if (!value_file.is_open())
+ std::cout << "Failed to open value file." << std::endl;
+}
+
+bool gpio::get_value()
+{
+
+ std::string val;
+
+ std::getline(value_file, val);
+ value_file.seekg(0);
+
+ if (val == "0")
+ return false;
+ else if (val == "1")
+ return true;
+ else
+ std::cout << "Data read from value file|" << val << "|" << std::endl;
+
+ return false;
+}
+
+void gpio::set_value(bool state)
+{
+
+ if (state)
+ value_file << "1" << std::endl;
+ else
+ value_file << "0" << std::endl;
+}
+
+gpio::~gpio()
+{
+ if (close_action) {
+ std::fstream unexport_file;
+
+ direction_file << "in" << std::endl;
+
+ unexport_file.open("/sys/class/gpio/unexport", std::ios::out);
+ if (!unexport_file.is_open()) ///\todo Poor error handling
+ std::cout << "Failed to open gpio export file." << std::endl;
+
+ unexport_file << gpio_num << std::endl;
+
+ }
+
+}
+
+spidev::spidev(std::string fname)
+{
+ int ret;
+ int mode = 0;
+ int speed = 12000;
+ int bits = 24;
+
+ fd = open(fname.c_str(), O_RDWR);
+
+ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
+}
+
+
+spidev::~spidev()
+{
+ close(fd);
+}
+
+void spidev::send(char *buf, char *rbuf, unsigned int nbytes)
+{
+ int ret;
+
+ struct spi_ioc_transfer tr;
+ tr.tx_buf = (unsigned long) buf;
+ tr.rx_buf = (unsigned long) rbuf;
+ tr.len = nbytes;
+ tr.delay_usecs = 0;
+ tr.speed_hz = 12000000;
+ tr.bits_per_word = 24;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+
+}
+
+static void send_config_to_clkgen(gpio &chip_select, const unsigned int data[], unsigned int data_size)
+{
+ spidev spi("/dev/spidev1.0");
+ unsigned int rbuf;
+
+ for (unsigned int i = 0; i < data_size; i++) {
+
+ std::cout << "sending " << std::hex << data[i] << std::endl;
+ chip_select.set_value(0);
+ spi.send((char *)&data[i], (char *)&rbuf, 4);
+ chip_select.set_value(1);
+
+ };
+}
+
+int main(int argc, char *argv[])
+{
+
+ gpio clkgen_select(CLKGEN_SELECT, OUT, true);
+
+ send_config_to_clkgen(clkgen_select, config_data, sizeof(config_data)/sizeof(unsigned int));
+}
+
diff --git a/host/utils/fpga-downloader.cpp b/host/utils/fpga-downloader.cpp
new file mode 100644
index 000000000..80ee71600
--- /dev/null
+++ b/host/utils/fpga-downloader.cpp
@@ -0,0 +1,267 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio 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, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <cstdlib>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/spi/spidev.h>
+
+/*
+ * Configuration connections
+ *
+ * CCK - MCSPI1_CLK
+ * DIN - MCSPI1_MOSI
+ * PROG_B - GPIO_175 - output (change mux)
+ * DONE - GPIO_173 - input (change mux)
+ * INIT_B - GPIO_114 - input (change mux)
+ *
+*/
+
+const unsigned int PROG_B = 175;
+const unsigned int DONE = 173;
+const unsigned int INIT_B = 114;
+
+static std::string bit_file = "safe_u1e.bin";
+
+const int BUF_SIZE = 4096;
+
+enum gpio_direction {IN, OUT};
+
+class gpio {
+ public:
+
+ gpio(unsigned int gpio_num, gpio_direction pin_direction);
+
+ bool get_value();
+ void set_value(bool state);
+
+ private:
+
+ std::stringstream base_path;
+ std::fstream value_file;
+};
+
+class spidev {
+ public:
+
+ spidev(std::string dev_name);
+ ~spidev();
+
+ void send(char *wbuf, char *rbuf, unsigned int nbytes);
+
+ private:
+
+ int fd;
+
+};
+
+gpio::gpio(unsigned int gpio_num, gpio_direction pin_direction)
+{
+ std::fstream export_file;
+
+ export_file.open("/sys/class/gpio/export", std::ios::out);
+ if (!export_file.is_open()) ///\todo Poor error handling
+ std::cout << "Failed to open gpio export file." << std::endl;
+
+ export_file << gpio_num << std::endl;
+
+ base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush;
+
+ std::fstream direction_file;
+ std::string direction_file_name;
+
+ direction_file_name = base_path.str() + "/direction";
+
+ direction_file.open(direction_file_name.c_str());
+ if (!direction_file.is_open())
+ std::cout << "Failed to open direction file." << std::endl;
+ if (pin_direction == OUT)
+ direction_file << "out" << std::endl;
+ else
+ direction_file << "in" << std::endl;
+
+ std::string value_file_name;
+
+ value_file_name = base_path.str() + "/value";
+
+ value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out);
+ if (!value_file.is_open())
+ std::cout << "Failed to open value file." << std::endl;
+}
+
+bool gpio::get_value()
+{
+
+ std::string val;
+
+ std::getline(value_file, val);
+ value_file.seekg(0);
+
+ if (val == "0")
+ return false;
+ else if (val == "1")
+ return true;
+ else
+ std::cout << "Data read from value file|" << val << "|" << std::endl;
+
+ return false;
+}
+
+void gpio::set_value(bool state)
+{
+
+ if (state)
+ value_file << "1" << std::endl;
+ else
+ value_file << "0" << std::endl;
+}
+
+static void prepare_fpga_for_configuration(gpio &prog, gpio &init)
+{
+
+ prog.set_value(true);
+ prog.set_value(false);
+ prog.set_value(true);
+
+#if 0
+ bool ready_to_program(false);
+ unsigned int count(0);
+ do {
+ ready_to_program = init.get_value();
+ count++;
+
+ sleep(1);
+ } while (count < 10 && !ready_to_program);
+
+ if (count == 10) {
+ std::cout << "FPGA not ready for programming." << std::endl;
+ exit(-1);
+ }
+#endif
+}
+
+spidev::spidev(std::string fname)
+{
+ int ret;
+ int mode = 0;
+ int speed = 12000000;
+ int bits = 8;
+
+ fd = open(fname.c_str(), O_RDWR);
+
+ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
+}
+
+
+spidev::~spidev()
+{
+ close(fd);
+}
+
+void spidev::send(char *buf, char *rbuf, unsigned int nbytes)
+{
+ int ret;
+
+ struct spi_ioc_transfer tr;
+ tr.tx_buf = (unsigned long) buf;
+ tr.rx_buf = (unsigned long) rbuf;
+ tr.len = nbytes;
+ tr.delay_usecs = 0;
+ tr.speed_hz = 48000000;
+ tr.bits_per_word = 8;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+
+}
+
+static void send_file_to_fpga(std::string &file_name, gpio &error, gpio &done)
+{
+ std::ifstream bitstream;
+
+ std::cout << "File name - " << file_name.c_str() << std::endl;
+
+ bitstream.open(file_name.c_str(), std::ios::binary);
+ if (!bitstream.is_open())
+ std::cout << "File " << file_name << " not opened succesfully." << std::endl;
+
+ spidev spi("/dev/spidev1.0");
+ char buf[BUF_SIZE];
+ char rbuf[BUF_SIZE];
+
+ do {
+ bitstream.read(buf, BUF_SIZE);
+ spi.send(buf, rbuf, bitstream.gcount());
+
+ if (error.get_value())
+ std::cout << "INIT_B went high, error occured." << std::endl;
+
+ if (!done.get_value())
+ std::cout << "Configuration complete." << std::endl;
+
+ } while (bitstream.gcount() == BUF_SIZE);
+}
+
+int main(int argc, char *argv[])
+{
+
+ gpio gpio_prog_b(PROG_B, OUT);
+ gpio gpio_init_b(INIT_B, IN);
+ gpio gpio_done (DONE, IN);
+
+ if (argc == 2)
+ bit_file = argv[1];
+
+ bool module_found(false);
+ std::ifstream mod_file("/proc/modules");
+ while (!mod_file.eof()) {
+ std::string line;
+ getline(mod_file, line);
+ if (line.find("usrp_e") != std::string::npos)
+ module_found = true;
+ }
+ mod_file.close();
+
+ if (module_found) {
+ std::cout << "USRP Embedded kernel module loaded, not loading FPGA." << std::endl;
+ return -1;
+ }
+
+ std::cout << "FPGA config file: " << bit_file << std::endl;
+
+ prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
+
+ std::cout << "Done = " << gpio_done.get_value() << std::endl;
+
+ send_file_to_fpga(bit_file, gpio_init_b, gpio_done);
+}
+
diff --git a/host/utils/uhd_find_devices.cpp b/host/utils/uhd_find_devices.cpp
new file mode 100644
index 000000000..b778eeb68
--- /dev/null
+++ b/host/utils/uhd_find_devices.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright 2010 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/safe_main.hpp>
+#include <uhd/device.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>()->default_value(""), "device address args")
+ ;
+
+ 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("UHD Find Devices %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //discover the usrps and print the results
+ uhd::device_addrs_t device_addrs = uhd::device::find(vm["args"].as<std::string>());
+
+ if (device_addrs.size() == 0){
+ std::cerr << "No UHD Devices Found" << std::endl;
+ return ~0;
+ }
+
+ for (size_t i = 0; i < device_addrs.size(); i++){
+ std::cout << "--------------------------------------------------" << std::endl;
+ std::cout << "-- UHD Device " << i << std::endl;
+ std::cout << "--------------------------------------------------" << std::endl;
+ std::cout << device_addrs[i].to_pp_string() << std::endl << std::endl;
+ //uhd::device::make(device_addrs[i]); //test make
+ }
+
+ return 0;
+}
diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp
new file mode 100644
index 000000000..5cba7c362
--- /dev/null
+++ b/host/utils/uhd_usrp_probe.cpp
@@ -0,0 +1,179 @@
+//
+// Copyright 2010 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/safe_main.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/usrp/dboard_props.hpp>
+#include <uhd/usrp/codec_props.hpp>
+#include <uhd/usrp/dsp_props.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
+#include <sstream>
+
+namespace po = boost::program_options;
+using namespace uhd;
+
+static std::string indent(size_t level){
+ return (level)? (indent(level-1) + " ") : "";
+}
+
+static std::string make_border(const std::string &text){
+ std::stringstream ss;
+ ss << boost::format(" _____________________________________________________") << std::endl;
+ ss << boost::format(" /") << std::endl;
+ std::vector<std::string> lines = std::split_string(text, "\n");
+ while (lines.back() == "") lines.pop_back(); //strip trailing newlines
+ if (lines.size()) lines[0] = " " + lines[0]; //indent the title line
+ BOOST_FOREACH(const std::string &line, lines){
+ ss << boost::format("| %s") % line << std::endl;
+ }
+ //ss << boost::format(" \\____________________________________________________") << std::endl;
+ return ss.str();
+}
+
+static std::string get_dsp_pp_string(const std::string &type, wax::obj dsp){
+ std::stringstream ss;
+ ss << boost::format("%s DSP: %s") % type % dsp[usrp::DSP_PROP_NAME].as<std::string>() << std::endl;
+ //ss << std::endl;
+ ss << boost::format("Codec Rate: %f Msps") % (dsp[usrp::DSP_PROP_CODEC_RATE].as<double>()/1e6) << std::endl;
+ //ss << boost::format("Host Rate: %f Msps") % (dsp[usrp::DSP_PROP_HOST_RATE].as<double>()/1e6) << std::endl;
+ //ss << boost::format("Freq Shift: %f Mhz") % (dsp[usrp::DSP_PROP_FREQ_SHIFT].as<double>()/1e6) << std::endl;
+ return ss.str();
+}
+
+static std::string prop_names_to_pp_string(const prop_names_t &prop_names){
+ std::stringstream ss; size_t count = 0;
+ BOOST_FOREACH(const std::string &prop_name, prop_names){
+ ss << ((count++)? ", " : "") << prop_name;
+ }
+ return ss.str();
+}
+
+static std::string get_subdev_pp_string(const std::string &type, wax::obj subdev){
+ std::stringstream ss;
+ ss << boost::format("%s Subdev: %s") % type % subdev[usrp::SUBDEV_PROP_NAME].as<std::string>() << std::endl;
+ //ss << std::endl;
+
+ prop_names_t ant_names(subdev[usrp::SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>());
+ ss << boost::format("Antennas: %s") % prop_names_to_pp_string(ant_names) << std::endl;
+
+ freq_range_t freq_range(subdev[usrp::SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>());
+ ss << boost::format("Freq range: %.3f to %.3f Mhz") % (freq_range.start()/1e6) % (freq_range.stop()/1e6) << std::endl;
+
+ prop_names_t gain_names(subdev[usrp::SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>());
+ if (gain_names.size() == 0) ss << "Gain Elements: None" << std::endl;
+ BOOST_FOREACH(const std::string &gain_name, gain_names){
+ gain_range_t gain_range(subdev[named_prop_t(usrp::SUBDEV_PROP_GAIN_RANGE, gain_name)].as<gain_range_t>());
+ ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.start() % gain_range.stop() % gain_range.step() << std::endl;
+ }
+
+ ss << boost::format("Connection Type: %c") % char(subdev[usrp::SUBDEV_PROP_CONNECTION].as<usrp::subdev_conn_t>()) << std::endl;
+ ss << boost::format("Uses LO offset: %s") % (subdev[usrp::SUBDEV_PROP_USE_LO_OFFSET].as<bool>()? "Yes" : "No") << std::endl;
+
+ return ss.str();
+}
+
+static std::string get_codec_pp_string(const std::string &type, wax::obj codec){
+ std::stringstream ss;
+ ss << boost::format("%s Codec: %s") % type % codec[usrp::CODEC_PROP_NAME].as<std::string>() << std::endl;
+ //ss << std::endl;
+ prop_names_t gain_names(codec[usrp::CODEC_PROP_GAIN_NAMES].as<prop_names_t>());
+ if (gain_names.size() == 0) ss << "Gain Elements: None" << std::endl;
+ BOOST_FOREACH(const std::string &gain_name, gain_names){
+ gain_range_t gain_range(codec[named_prop_t(usrp::CODEC_PROP_GAIN_RANGE, gain_name)].as<gain_range_t>());
+ ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.start() % gain_range.stop() % gain_range.step() << std::endl;
+ }
+ return ss.str();
+}
+
+static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard){
+ std::stringstream ss;
+ ss << boost::format("%s Dboard: %s") % type % dboard[usrp::DBOARD_PROP_NAME].as<std::string>() << std::endl;
+ //ss << std::endl;
+ BOOST_FOREACH(const std::string &subdev_name, dboard[usrp::DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){
+ ss << make_border(get_subdev_pp_string(type, dboard[named_prop_t(usrp::DBOARD_PROP_SUBDEV, subdev_name)]));
+ }
+ ss << make_border(get_codec_pp_string(type, dboard[usrp::DBOARD_PROP_CODEC]));
+ return ss.str();
+}
+
+static std::string get_mboard_pp_string(wax::obj mboard){
+ std::stringstream ss;
+ ss << boost::format("Mboard: %s") % mboard[usrp::MBOARD_PROP_NAME].as<std::string>() << std::endl;
+ //ss << std::endl;
+ usrp::mboard_eeprom_t mb_eeprom = mboard[usrp::MBOARD_PROP_EEPROM_MAP].as<usrp::mboard_eeprom_t>();
+ 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;
+ }
+ BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>()){
+ ss << make_border(get_dsp_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DSP, dsp_name)]));
+ }
+ BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>()){
+ ss << make_border(get_dsp_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DSP, dsp_name)]));
+ }
+ BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>()){
+ ss << make_border(get_dboard_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DBOARD, dsp_name)]));
+ }
+ BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>()){
+ ss << make_border(get_dboard_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DBOARD, dsp_name)]));
+ }
+ return ss.str();
+}
+
+
+static std::string get_device_pp_string(device::sptr dev){
+ std::stringstream ss;
+ ss << boost::format("Device: %s") % (*dev)[usrp::DEVICE_PROP_NAME].as<std::string>() << std::endl;
+ //ss << std::endl;
+ BOOST_FOREACH(const std::string &mboard_name, (*dev)[usrp::DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>()){
+ ss << make_border(get_mboard_pp_string((*dev)[named_prop_t(usrp::DEVICE_PROP_MBOARD, mboard_name)]));
+ }
+ return ss.str();
+}
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>()->default_value(""), "device address args")
+ ;
+
+ 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("UHD USRP Probe %s") % desc << std::endl;
+ return ~0;
+ }
+
+ device::sptr dev = device::make(vm["args"].as<std::string>());
+
+ std::cout << make_border(get_device_pp_string(dev)) << std::endl;
+
+ return 0;
+}
diff --git a/host/utils/usrp-e-debug-pins.c b/host/utils/usrp-e-debug-pins.c
new file mode 100644
index 000000000..1ed2c8983
--- /dev/null
+++ b/host/utils/usrp-e-debug-pins.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <linux/usrp_e.h>
+#include "usrp_e_regs.hpp"
+
+// Usage: usrp_e_gpio <string>
+
+static int fp;
+
+static int read_reg(__u16 reg)
+{
+ int ret;
+ struct usrp_e_ctl16 d;
+
+ d.offset = reg;
+ d.count = 1;
+ ret = ioctl(fp, USRP_E_READ_CTL16, &d);
+ return d.buf[0];
+}
+
+static void write_reg(__u16 reg, __u16 val)
+{
+ int ret;
+ struct usrp_e_ctl16 d;
+
+ d.offset = reg;
+ d.count = 1;
+ d.buf[0] = val;
+ ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
+}
+
+int main(int argc, char *argv[])
+{
+ int test;
+
+ test = 0;
+ if (argc < 2) {
+ printf("%s 0|1|off\n", argv[0]);
+ }
+
+ fp = open("/dev/usrp_e0", O_RDWR);
+ printf("fp = %d\n", fp);
+ if (fp < 0) {
+ perror("Open failed");
+ return -1;
+ }
+
+ if (strcmp(argv[1], "0") == 0) {
+ printf("Selected 0 based on %s\n", argv[1]);
+ write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF);
+ write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF);
+ write_reg(UE_REG_GPIO_TX_SEL, 0x0);
+ write_reg(UE_REG_GPIO_RX_SEL, 0x0);
+ write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF);
+ write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF);
+ } else if (strcmp(argv[1], "1") == 0) {
+ printf("Selected 1 based on %s\n", argv[1]);
+ write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF);
+ write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF);
+ write_reg(UE_REG_GPIO_TX_SEL, 0xFFFF);
+ write_reg(UE_REG_GPIO_RX_SEL, 0xFFFF);
+ write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF);
+ write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF);
+ } else {
+ printf("Selected off based on %s\n", argv[1]);
+ write_reg(UE_REG_GPIO_TX_DDR, 0x0);
+ write_reg(UE_REG_GPIO_RX_DDR, 0x0);
+ }
+
+ return 0;
+}
diff --git a/host/utils/usrp-e-i2c.c b/host/utils/usrp-e-i2c.c
new file mode 100644
index 000000000..c6fd4c632
--- /dev/null
+++ b/host/utils/usrp-e-i2c.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/usrp_e.h>
+
+// Usage: usrp_e_i2c w address data0 data1 data 2 ....
+// Usage: usrp_e_i2c r address count
+
+int main(int argc, char *argv[])
+{
+ int fp, ret, i, tmp;
+ struct usrp_e_i2c *i2c_msg;
+ int direction, address, count;
+
+ if (argc < 3) {
+ printf("Usage: usrp-e-i2c w address data0 data1 data2 ...\n");
+ printf("Usage: usrp-e-i2c r address count\n");
+ printf("All addresses and data in hex.\n");
+ exit(-1);
+ }
+
+ if (strcmp(argv[1], "r") == 0) {
+ direction = 0;
+ } else if (strcmp(argv[1], "w") == 0) {
+ direction = 1;
+ } else {
+ return -1;
+ }
+
+ sscanf(argv[2], "%X", &address);
+ printf("Address = %X\n", address);
+
+ fp = open("/dev/usrp_e0", O_RDWR);
+ printf("fp = %d\n", fp);
+ if (fp < 0) {
+ perror("Open failed");
+ return -1;
+ }
+
+// sleep(1);
+
+ if (direction) {
+ count = argc - 3;
+ } else {
+ sscanf(argv[3], "%X", &count);
+ }
+ printf("Count = %X\n", count);
+
+ i2c_msg = malloc(sizeof(i2c_msg) + count * sizeof(char));
+
+ i2c_msg->addr = address;
+ i2c_msg->len = count;
+
+ for (i = 0; i < count; i++) {
+ i2c_msg->data[i] = i;
+ }
+
+ if (direction) {
+ // Write
+
+ for (i=0; i<count; i++) {
+ sscanf(argv[3+i], "%X", &tmp);
+ i2c_msg->data[i] = tmp;
+ }
+
+ ret = ioctl(fp, USRP_E_I2C_WRITE, i2c_msg);
+ printf("Return value from i2c_write ioctl: %d\n", ret);
+ } else {
+ // Read
+
+ ret = ioctl(fp, USRP_E_I2C_READ, i2c_msg);
+ printf("Return value from i2c_read ioctl: %d\n", ret);
+
+ printf("Ioctl: %d Data read :", ret);
+ for (i=0; i<count; i++) {
+ printf(" %X", i2c_msg->data[i]);
+ }
+ printf("\n");
+
+ }
+ return 0;
+}
diff --git a/host/utils/usrp-e-loopback.c b/host/utils/usrp-e-loopback.c
new file mode 100644
index 000000000..454d81ba7
--- /dev/null
+++ b/host/utils/usrp-e-loopback.c
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <linux/usrp_e.h>
+
+#define MAX_PACKET_SIZE 1016
+static int packet_data_length;
+static int error;
+
+struct pkt {
+ int len;
+ int checksum;
+ int seq_num;
+ short data[];
+};
+
+static int length_array[2048];
+static int length_array_tail = 0;
+static int length_array_head = 0;
+
+pthread_mutex_t length_array_mutex; //gotta lock the index to keep it from getting hosed
+
+//yes this is a circular buffer that does not check empty
+//no i don't want to hear about it
+void push_length_array(int length) {
+ pthread_mutex_lock(&length_array_mutex);
+ if(length_array_tail > 2047) length_array_tail = 0;
+ length_array[length_array_tail++] = length;
+ pthread_mutex_unlock(&length_array_mutex);
+}
+
+int pop_length_array(void) {
+ int retval;
+ pthread_mutex_lock(&length_array_mutex);
+ if(length_array_head > 2047) length_array_head = 0;
+ retval = length_array[length_array_head++];
+ pthread_mutex_unlock(&length_array_mutex);
+ return retval;
+}
+
+static int fp;
+
+static int calc_checksum(struct pkt *p)
+{
+ int i, sum;
+
+ i = 0;
+ sum = 0;
+
+ for (i=0; i < p->len; i++)
+ sum ^= p->data[i];
+
+ sum ^= p->seq_num;
+ sum ^= p->len;
+
+ return sum;
+}
+
+static void *read_thread(void *threadid)
+{
+ char *rx_data;
+ int cnt, prev_seq_num, pkt_count, seq_num_failure;
+ struct pkt *p;
+ unsigned long bytes_transfered, elapsed_seconds;
+ struct timeval start_time, finish_time;
+ int expected_count;
+
+ printf("Greetings from the reading thread!\n");
+
+ bytes_transfered = 0;
+ gettimeofday(&start_time, NULL);
+
+ // IMPORTANT: must assume max length packet from fpga
+ rx_data = malloc(2048);
+ p = (struct pkt *) ((void *)rx_data);
+
+ prev_seq_num = 0;
+ pkt_count = 0;
+ seq_num_failure = 0;
+
+ while (1) {
+
+ cnt = read(fp, rx_data, 2048);
+ if (cnt < 0)
+ printf("Error returned from read: %d, sequence number = %d\n", cnt, p->seq_num);
+
+// printf("p->seq_num = %d\n", p->seq_num);
+
+
+ pkt_count++;
+
+ if (p->seq_num != prev_seq_num + 1) {
+ printf("Sequence number fail, current = %d, previous = %d, pkt_count = %d\n",
+ p->seq_num, prev_seq_num, pkt_count);
+
+ seq_num_failure ++;
+ if (seq_num_failure > 2)
+ error = 1;
+ }
+
+ expected_count = pop_length_array()*2+12;
+ if(cnt != expected_count) {
+ printf("Received %d bytes, expected %d\n", cnt, expected_count);
+ }
+
+ prev_seq_num = p->seq_num;
+
+ if (calc_checksum(p) != p->checksum) {
+ printf("Checksum fail packet = %X, expected = %X, pkt_count = %d\n",
+ calc_checksum(p), p->checksum, pkt_count);
+ error = 1;
+ }
+
+ bytes_transfered += cnt;
+
+ if (bytes_transfered > (100 * 1000000)) {
+ gettimeofday(&finish_time, NULL);
+ elapsed_seconds = finish_time.tv_sec - start_time.tv_sec;
+
+ printf("RX data transfer rate = %f K Samples/second\n",
+ (float) bytes_transfered / (float) elapsed_seconds / 4000);
+
+
+ start_time = finish_time;
+ bytes_transfered = 0;
+ }
+
+
+// printf(".");
+// fflush(stdout);
+// printf("\n");
+ }
+
+}
+
+static void *write_thread(void *threadid)
+{
+ int seq_number, i, cnt;
+ void *tx_data;
+ struct pkt *p;
+
+ printf("Greetings from the write thread!\n");
+
+ tx_data = malloc(2048);
+ p = (struct pkt *) ((void *)tx_data);
+
+ for (i=0; i < packet_data_length; i++)
+// p->data[i] = random() >> 16;
+ p->data[i] = i;
+
+ seq_number = 1;
+
+ while (1) {
+ p->seq_num = seq_number++;
+
+ if (packet_data_length > 0)
+ p->len = packet_data_length;
+ else
+ p->len = (random()<<1 & 0x1ff) + (1004 - 512);
+
+ push_length_array(p->len);
+
+ p->checksum = calc_checksum(p);
+
+ cnt = write(fp, tx_data, p->len * 2 + 12);
+ if (cnt < 0)
+ printf("Error returned from write: %d\n", cnt);
+// sleep(1);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ pthread_t tx, rx;
+ pthread_mutex_init(&length_array_mutex, 0);
+ long int t;
+ struct sched_param s = {
+ .sched_priority = 1
+ };
+ void *rb;
+ struct usrp_transfer_frame *tx_rb, *rx_rb;
+
+ if (argc < 2) {
+ printf("%s data_size\n", argv[0]);
+ return -1;
+ }
+
+ packet_data_length = atoi(argv[1]);
+ if(packet_data_length > MAX_PACKET_SIZE) {
+ printf("Packet size must be smaller than %i\n", MAX_PACKET_SIZE);
+ exit(-1);
+ }
+
+ fp = open("/dev/usrp_e0", O_RDWR);
+ printf("fp = %d\n", fp);
+
+ rb = mmap(0, 202 * 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
+ if (!rb) {
+ printf("mmap failed\n");
+ exit;
+ }
+
+
+ sched_setscheduler(0, SCHED_RR, &s);
+ error = 0;
+
+#if 1
+ if (pthread_create(&rx, NULL, read_thread, (void *) t)) {
+ printf("Failed to create rx thread\n");
+ exit(-1);
+ }
+
+ sleep(1);
+#endif
+
+ if (pthread_create(&tx, NULL, write_thread, (void *) t)) {
+ printf("Failed to create tx thread\n");
+ exit(-1);
+ }
+
+// while (!error)
+ sleep(1000000000);
+
+ printf("Done sleeping\n");
+}
diff --git a/host/utils/usrp-e-spi.c b/host/utils/usrp-e-spi.c
new file mode 100644
index 000000000..5203f56a8
--- /dev/null
+++ b/host/utils/usrp-e-spi.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/usrp_e.h>
+
+// Usage: usrp_e_spi w|rb slave data
+
+int main(int argc, char *argv[])
+{
+ int fp, slave, length, ret;
+ unsigned int data;
+ struct usrp_e_spi spi_dat;
+
+ if (argc < 5) {
+ printf("Usage: usrp_e_spi w|rb slave transfer_length data\n");
+ exit(-1);
+ }
+
+ slave = atoi(argv[2]);
+ length = atoi(argv[3]);
+ data = atoll(argv[4]);
+
+ printf("Data = %X\n", data);
+
+ fp = open("/dev/usrp_e0", O_RDWR);
+ printf("fp = %d\n", fp);
+ if (fp < 0) {
+ perror("Open failed");
+ return -1;
+ }
+
+// sleep(1);
+
+
+ spi_dat.slave = slave;
+ spi_dat.data = data;
+ spi_dat.length = length;
+ spi_dat.flags = UE_SPI_PUSH_FALL | UE_SPI_LATCH_RISE;
+
+ if (*argv[1] == 'r') {
+ spi_dat.readback = 1;
+ ret = ioctl(fp, USRP_E_SPI, &spi_dat);
+ printf("Ioctl returns: %d, Data returned = %d\n", ret, spi_dat.data);
+ } else {
+ spi_dat.readback = 0;
+ ioctl(fp, USRP_E_SPI, &spi_dat);
+ }
+
+ return 0;
+}
diff --git a/host/utils/usrp1_init_eeprom.cpp b/host/utils/usrp1_init_eeprom.cpp
new file mode 100644
index 000000000..b05e400b1
--- /dev/null
+++ b/host/utils/usrp1_init_eeprom.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright 2010 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/safe_main.hpp>
+#include <uhd/device.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("image", po::value<std::string>(), "BIN image file")
+ ;
+
+ 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("USRP EEPROM initialization %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //load the options into the address
+ uhd::device_addr_t device_addr;
+ device_addr["type"] = "usrp1";
+ device_addr["uninit"] = "yeah"; //tell find to look for an uninitialized FX2
+
+ //find and create a control transport to do the writing.
+
+ uhd::device_addrs_t found_addrs = uhd::device::find(device_addr);
+
+ if (found_addrs.size() == 0){
+ std::cerr << "No uninitialized USRP devices found" << std::endl;
+ return ~0;
+ }
+
+ 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]);
+ wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD];
+ mb[std::string("load_eeprom")] = vm["image"].as<std::string>();
+ }
+
+
+ std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl;
+ return 0;
+}
diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py
new file mode 100755
index 000000000..1db5e59ce
--- /dev/null
+++ b/host/utils/usrp2_card_burner.py
@@ -0,0 +1,246 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 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 platform
+import tempfile
+import subprocess
+import urllib
+import optparse
+import math
+import os
+import re
+
+########################################################################
+# constants
+########################################################################
+SECTOR_SIZE = 512 # bytes
+MAX_FILE_SIZE = 1 * (2**20) # maximum number of bytes we'll burn to a slot
+
+FPGA_OFFSET = 0 # offset in flash to fpga image
+FIRMWARE_OFFSET = 1 * (2**20) # offset in flash to firmware image
+
+MAX_SD_CARD_SIZE = 2048e6 # bytes (any bigger is sdhc)
+
+########################################################################
+# helper functions
+########################################################################
+def command(*args):
+ p = subprocess.Popen(
+ args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+ ret = p.wait()
+ verbose = p.stdout.read()
+ if ret != 0: raise Exception, verbose
+ return verbose
+
+def get_dd_path():
+ if platform.system() == 'Windows':
+ dd_path = os.path.join(tempfile.gettempdir(), 'dd.exe')
+ if not os.path.exists(dd_path):
+ print 'Downloading dd.exe to %s'%dd_path
+ dd_bin = urllib.urlopen('http://www.ettus.com/downloads/dd.exe').read()
+ open(dd_path, 'wb').write(dd_bin)
+ return dd_path
+ return 'dd'
+
+def int_ceil_div(num, den):
+ return int(math.ceil(float(num)/float(den)))
+
+def get_tmp_file():
+ tmp = tempfile.mkstemp()
+ os.close(tmp[0])
+ return tmp[1]
+
+########################################################################
+# list possible devices
+########################################################################
+def get_raw_device_hints():
+ ####################################################################
+ # Platform Windows: parse the output of dd.exe --list
+ ####################################################################
+ if platform.system() == 'Windows':
+ def extract_info_value(info, key):
+ return info.split(key)[-1].split()[0]
+ def get_info_list(output):
+ in_info = False
+ for line in output.splitlines():
+ if line.startswith('\\\\'): in_info = True; info = ''
+ elif in_info and not line.strip(): in_info = False; yield info
+ if in_info: info += '\n'+line.strip()
+ def is_info_valid(info):
+ try:
+ assert 'link to' in info
+ #handles two spellings of remov(e)able:
+ assert 'remov' in info.lower()
+ if 'size is' in info: assert int(extract_info_value(info, 'size is')) <= MAX_SD_CARD_SIZE
+ return True
+ except: return False
+ def extract_info_name(info):
+ for key in ('Mounted on', 'link to'):
+ if key in info: return extract_info_value(info, key)
+ return info.splitlines()[0].strip()
+
+ return sorted(set(map(extract_info_name, filter(is_info_valid, get_info_list(command(get_dd_path(), '--list'))))))
+
+ ####################################################################
+ # Platform Linux: parse procfs /proc/partitions
+ ####################################################################
+ if platform.system() == 'Linux':
+ devs = list()
+ try: output = open('/proc/partitions', 'r').read()
+ except: return devs
+ for line in output.splitlines():
+ try:
+ major, minor, blocks, name = line.split()
+ assert not name[-1].isdigit() or int(minor) == 0
+ assert int(blocks)*1024 <= MAX_SD_CARD_SIZE
+ except: continue
+ devs.append(os.path.join('/dev', name))
+
+ return sorted(set(devs))
+
+ ####################################################################
+ # Platform Mac OS X: parse diskutil list and info commands
+ ####################################################################
+ if platform.system() == 'Darwin':
+ devs = map(lambda d: d.split()[0], filter(lambda l: l.startswith('/dev'), command('diskutil', 'list').splitlines()))
+ def output_to_info(output):
+ return dict([map(str.strip, pair.lower().split(':')) for pair in filter(lambda l: ':' in l, output.splitlines())])
+ def is_dev_valid(dev):
+ info = output_to_info(command('diskutil', 'info', dev))
+ try:
+ if info.has_key('internal'): assert info['internal'] == 'no'
+ if info.has_key('ejectable'): assert info['ejectable'] == 'yes'
+ if info.has_key('total size'):
+ size_match = re.match('^.*\((\d+)\s*bytes\).*$', info['total size'])
+ if size_match: assert int(size_match.groups()[0]) <= MAX_SD_CARD_SIZE
+ return True
+ except: return False
+
+ return sorted(set(filter(is_dev_valid, devs)))
+
+ ####################################################################
+ # Platform Others:
+ ####################################################################
+ return ()
+
+########################################################################
+# write and verify with dd
+########################################################################
+def verify_image(image_file, device_file, offset):
+ #create a temporary file to store the readback image
+ tmp_file = get_tmp_file()
+
+ #read the image data
+ img_data = open(image_file, 'rb').read()
+ count = int_ceil_div(len(img_data), SECTOR_SIZE)
+
+ #execute a dd subprocess
+ verbose = command(
+ get_dd_path(),
+ "of=%s"%tmp_file,
+ "if=%s"%device_file,
+ "skip=%d"%(offset/SECTOR_SIZE),
+ "bs=%d"%SECTOR_SIZE,
+ "count=%d"%count,
+ )
+
+ #verfy the data
+ tmp_data = open(tmp_file, 'rb').read(len(img_data))
+ if img_data != tmp_data: return 'Verification Failed:\n%s'%verbose
+ return 'Verification Passed:\n%s'%verbose
+
+def write_image(image_file, device_file, offset):
+ #create a temporary file to store the padded image
+ tmp_file = get_tmp_file()
+
+ #write the padded image data
+ img_data = open(image_file, 'rb').read()
+ count = int_ceil_div(len(img_data), SECTOR_SIZE)
+ pad_len = SECTOR_SIZE*count - len(img_data)
+ pad_str = ''.join([chr(0)]*pad_len) #zero-padding
+ open(tmp_file, 'wb').write(img_data + pad_str)
+
+ #execute a dd subprocess
+ verbose = command(
+ get_dd_path(),
+ "if=%s"%tmp_file,
+ "of=%s"%device_file,
+ "seek=%d"%(offset/SECTOR_SIZE),
+ "bs=%d"%SECTOR_SIZE,
+ "count=%d"%count,
+ )
+
+ try: #exec the sync command (only works on linux)
+ if platform.system() == 'Linux': command('sync')
+ except: pass
+
+ return verbose
+
+def write_and_verify(image_file, device_file, offset):
+ if os.path.getsize(image_file) > MAX_FILE_SIZE:
+ raise Exception, 'Image file larger than %d bytes!'%MAX_FILE_SIZE
+ return '%s\n%s'%(
+ write_image(
+ image_file=image_file,
+ device_file=device_file,
+ offset=offset,
+ ), verify_image(
+ image_file=image_file,
+ device_file=device_file,
+ offset=offset,
+ ),
+ )
+
+def burn_sd_card(dev, fw, fpga):
+ verbose = ''
+ if fw: verbose += 'Burn firmware image:\n%s\n'%write_and_verify(
+ image_file=fw, device_file=dev, offset=FIRMWARE_OFFSET
+ )
+ if fpga: verbose += 'Burn fpga image:\n%s\n'%write_and_verify(
+ image_file=fpga, device_file=dev, offset=FPGA_OFFSET
+ )
+ return verbose
+
+########################################################################
+# command line options
+########################################################################
+def get_options():
+ parser = optparse.OptionParser()
+ parser.add_option("--dev", type="string", help="raw device path", default='')
+ parser.add_option("--fw", type="string", help="firmware image path (optional)", default='')
+ parser.add_option("--fpga", type="string", help="fpga image path (optional)", default='')
+ parser.add_option("--list", action="store_true", help="list possible raw devices", default=False)
+ (options, args) = parser.parse_args()
+
+ if options.list:
+ print 'Possible raw devices:'
+ print ' ' + '\n '.join(get_raw_device_hints())
+ exit()
+
+ return options
+
+########################################################################
+# main
+########################################################################
+if __name__=='__main__':
+ options = get_options()
+ if not options.dev: raise Exception, 'no raw device path specified'
+ print burn_sd_card(dev=options.dev, fw=options.fw, fpga=options.fpga)
diff --git a/host/utils/usrp2_card_burner_gui.py b/host/utils/usrp2_card_burner_gui.py
new file mode 100755
index 000000000..58b7a514a
--- /dev/null
+++ b/host/utils/usrp2_card_burner_gui.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 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 usrp2_card_burner #import implementation
+import Tkinter, tkFileDialog, tkFont, tkMessageBox
+import os
+
+class BinFileEntry(Tkinter.Frame):
+ """
+ Simple file entry widget for getting the file path of bin files.
+ Combines a label, entry, and button with file dialog callback.
+ """
+
+ def __init__(self, root, what, def_path=''):
+ self._what = what
+ Tkinter.Frame.__init__(self, root)
+ Tkinter.Label(self, text=what+":").pack(side=Tkinter.LEFT)
+ self._entry = Tkinter.Entry(self, width=50)
+ self._entry.insert(Tkinter.END, def_path)
+ self._entry.pack(side=Tkinter.LEFT)
+ Tkinter.Button(self, text="...", command=self._button_cb).pack(side=Tkinter.LEFT)
+
+ def _button_cb(self):
+ filename = tkFileDialog.askopenfilename(
+ parent=self,
+ filetypes=[('bin files', '*.bin'), ('all files', '*.*')],
+ title="Select bin file for %s"%self._what,
+ initialdir=os.path.dirname(self.get_filename()),
+ )
+
+ # open file on your own
+ if filename:
+ self._entry.delete(0, Tkinter.END)
+ self._entry.insert(0, filename)
+
+ def get_filename(self):
+ return self._entry.get()
+
+class DeviceEntryWidget(Tkinter.Frame):
+ """
+ Simple entry widget for getting the raw device name.
+ Combines a label, entry, and helpful text box with hints.
+ """
+
+ def __init__(self, root, text=''):
+ Tkinter.Frame.__init__(self, root)
+
+ Tkinter.Button(self, text="Rescan for Devices", command=self._reload_cb).pack()
+
+ self._hints = Tkinter.Listbox(self)
+ self._hints.bind("<<ListboxSelect>>", self._listbox_cb)
+ self._reload_cb()
+ self._hints.pack(expand=Tkinter.YES, fill=Tkinter.X)
+
+ frame = Tkinter.Frame(self)
+ frame.pack()
+
+ Tkinter.Label(frame, text="Raw Device:").pack(side=Tkinter.LEFT)
+ self._entry = Tkinter.Entry(frame, width=50)
+ self._entry.insert(Tkinter.END, text)
+ self._entry.pack(side=Tkinter.LEFT)
+
+ def _reload_cb(self):
+ self._hints.delete(0, Tkinter.END)
+ for hint in usrp2_card_burner.get_raw_device_hints():
+ self._hints.insert(Tkinter.END, hint)
+
+ def _listbox_cb(self, event):
+ try:
+ sel = self._hints.get(self._hints.curselection()[0])
+ self._entry.delete(0, Tkinter.END)
+ self._entry.insert(0, sel)
+ except Exception, e: print e
+
+ def get_devname(self):
+ return self._entry.get()
+
+class SectionLabel(Tkinter.Label):
+ """
+ Make a text label with bold font.
+ """
+
+ def __init__(self, root, text):
+ Tkinter.Label.__init__(self, root, text=text)
+
+ #set the font bold
+ f = tkFont.Font(font=self['font'])
+ f['weight'] = 'bold'
+ self['font'] = f.name
+
+class USRP2CardBurnerApp(Tkinter.Frame):
+ """
+ The top level gui application for the usrp2 sd card burner.
+ Creates entry widgets and button with callback to write images.
+ """
+
+ def __init__(self, root, dev, fw, fpga):
+
+ Tkinter.Frame.__init__(self, root)
+
+ #pack the file entry widgets
+ SectionLabel(self, text="Select Images").pack(pady=5)
+ self._fw_img_entry = BinFileEntry(self, "Firmware Image", def_path=fw)
+ self._fw_img_entry.pack()
+ self._fpga_img_entry = BinFileEntry(self, "FPGA Image", def_path=fpga)
+ self._fpga_img_entry.pack()
+
+ #pack the destination entry widget
+ SectionLabel(self, text="Select Device").pack(pady=5)
+ self._raw_dev_entry = DeviceEntryWidget(self, text=dev)
+ self._raw_dev_entry.pack()
+
+ #the do it button
+ SectionLabel(self, text="").pack(pady=5)
+ Tkinter.Label(self, text="Warning! This tool can overwrite your hard drive. Use with caution.").pack()
+ Tkinter.Button(self, text="Burn SD Card", command=self._burn).pack()
+
+ def _burn(self):
+ #grab strings from the gui
+ fw = self._fw_img_entry.get_filename()
+ fpga = self._fpga_img_entry.get_filename()
+ dev = self._raw_dev_entry.get_devname()
+
+ #check input
+ if not dev:
+ tkMessageBox.showerror('Error:', 'No device specified!')
+ return
+ if not fw and not fpga:
+ tkMessageBox.showerror('Error:', 'No images specified!')
+ return
+ if fw and not os.path.exists(fw):
+ tkMessageBox.showerror('Error:', 'Firmware image not found!')
+ return
+ if fpga and not os.path.exists(fpga):
+ tkMessageBox.showerror('Error:', 'FPGA image not found!')
+ return
+
+ #burn the sd card
+ try:
+ verbose = usrp2_card_burner.burn_sd_card(dev=dev, fw=fw, fpga=fpga)
+ tkMessageBox.showinfo('Verbose:', verbose)
+ except Exception, e:
+ tkMessageBox.showerror('Verbose:', 'Error: %s'%str(e))
+
+########################################################################
+# main
+########################################################################
+if __name__=='__main__':
+ options = usrp2_card_burner.get_options()
+ root = Tkinter.Tk()
+ root.title('USRP2 SD Card Burner')
+ USRP2CardBurnerApp(root, dev=options.dev, fw=options.fw, fpga=options.fpga).pack()
+ root.mainloop()
+ exit()
diff --git a/host/utils/usrp2_recovery.py b/host/utils/usrp2_recovery.py
new file mode 100755
index 000000000..5654e93d3
--- /dev/null
+++ b/host/utils/usrp2_recovery.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 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/>.
+#
+
+"""
+The usrp2 recovery app:
+
+When the usrp2 has an unknown or bad ip address in its eeprom,
+it may not be possible to communicate with the usrp2 over ip/udp.
+
+This app will send a raw ethernet packet to bypass the ip layer.
+The packet will contain a known ip address to burn into eeprom.
+Because the recovery packet is sent with a broadcast mac address,
+only one usrp2 should be present on the interface upon execution.
+
+This app requires super-user privileges and only works on linux.
+"""
+
+import socket
+import struct
+import optparse
+
+BCAST_MAC_ADDR = 'ff:ff:ff:ff:ff:ff'
+RECOVERY_ETHERTYPE = 0xbeee
+IP_RECOVERY_CODE = 'addr'
+
+def mac_addr_repr_to_binary_string(mac_addr):
+ return ''.join(map(lambda x: chr(int(x, 16)), mac_addr.split(':')))
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser(usage='usage: %prog [options]\n'+__doc__)
+ parser.add_option('--ifc', type='string', help='ethernet interface name [default=%default]', default='eth0')
+ parser.add_option('--new-ip', type='string', help='ip address to set [default=%default]', default='192.168.10.2')
+ (options, args) = parser.parse_args()
+
+ #create the raw socket
+ print "Opening raw socket on interface:", options.ifc
+ soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
+ soc.bind((options.ifc, RECOVERY_ETHERTYPE))
+
+ #create the recovery packet
+ print "Loading packet with ip address:", options.new_ip
+ packet = struct.pack(
+ '!6s6sH4s4s',
+ mac_addr_repr_to_binary_string(BCAST_MAC_ADDR),
+ mac_addr_repr_to_binary_string(BCAST_MAC_ADDR),
+ RECOVERY_ETHERTYPE,
+ IP_RECOVERY_CODE,
+ socket.inet_aton(options.new_ip),
+ )
+
+ print "Sending packet (%d bytes)"%len(packet)
+ soc.send(packet)
+ print "Done"
diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp
new file mode 100644
index 000000000..9afd71a22
--- /dev/null
+++ b/host/utils/usrp_burn_db_eeprom.cpp
@@ -0,0 +1,100 @@
+//
+// Copyright 2010 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/safe_main.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/usrp/dboard_props.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/assign.hpp>
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ //command line variables
+ std::string args, slot, unit;
+ static const uhd::dict<std::string, mboard_prop_t> unit_to_db_prop = boost::assign::map_list_of
+ ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD)
+ ;
+ static const uhd::dict<std::string, mboard_prop_t> unit_to_db_names_prop = boost::assign::map_list_of
+ ("RX", MBOARD_PROP_RX_DBOARD_NAMES) ("TX", MBOARD_PROP_TX_DBOARD_NAMES)
+ ;
+
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
+ ("slot", po::value<std::string>(&slot)->default_value(""), "dboard slot name [default is blank for automatic]")
+ ("unit", po::value<std::string>(&unit)->default_value(""), "which unit [RX or TX]")
+ ("id", po::value<std::string>(), "dboard id to burn, omit for readback")
+ ;
+
+ 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("USRP Burn Daughterboard EEPROM %s") % desc << std::endl;
+ std::cout << boost::format(
+ "Omit the ID argument to perform readback,\n"
+ "Or specify a new ID to burn into the EEPROM.\n"
+ ) << std::endl;
+ return ~0;
+ }
+
+ //check inputs
+ if (not unit_to_db_prop.has_key(unit)){
+ std::cout << "Error: specify RX or TX for unit" << std::endl;
+ return ~0;
+ }
+
+ //make the device and extract the dboard w/ property
+ device::sptr dev = device::make(args);
+ uhd::prop_names_t dboard_names = (*dev)[DEVICE_PROP_MBOARD][unit_to_db_names_prop[unit]].as<uhd::prop_names_t>();
+ if (dboard_names.size() == 1 and slot.empty()) slot = dboard_names.front();
+ uhd::assert_has(dboard_names, slot, "dboard slot name");
+ wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], slot)];
+ std::string prefix = unit + ":" + slot;
+
+ //read the current dboard id from eeprom
+ if (vm.count("id") == 0){
+ std::cout << boost::format("Getting dbid on %s dboard...") % prefix << std::endl;
+ dboard_id_t id = dboard[DBOARD_PROP_DBOARD_ID].as<dboard_id_t>();
+ std::cout << boost::format(" Current dbid: %s") % id.to_pp_string() << std::endl;
+ }
+
+ //write a new dboard id to eeprom
+ else{
+ dboard_id_t id = dboard_id_t::from_string(vm["id"].as<std::string>());
+ std::cout << boost::format("Setting dbid on %s dboard...") % prefix << std::endl;
+ std::cout << boost::format(" New dbid: %s") % id.to_pp_string() << std::endl;
+ dboard[DBOARD_PROP_DBOARD_ID] = id;
+ }
+
+ std::cout << " Done" << std::endl << std::endl;
+ return 0;
+}
diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp
new file mode 100644
index 000000000..20e1b58b1
--- /dev/null
+++ b/host/utils/usrp_burn_mb_eeprom.cpp
@@ -0,0 +1,81 @@
+//
+// Copyright 2010 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/safe_main.hpp>
+#include <uhd/device.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ std::string args, 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), "the indentifier for a value in EEPROM")
+ ("val", po::value<std::string>(&val), "the new value to set, omit for readback")
+ ;
+
+ 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("key")){
+ 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"
+ "Or specify a new value to burn into the EEPROM.\n"
+ ) << std::endl;
+ return ~0;
+ }
+
+ std::cout << "Creating USRP device from address: " + args << std::endl;
+ uhd::device::sptr dev = uhd::device::make(args);
+ //FIXME the default mboard for now (may be others)
+ wax::obj mboard = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD];
+ std::cout << std::endl;
+
+ if (true /*always readback*/){
+ std::cout << "Fetching current settings from EEPROM..." << std::endl;
+ uhd::usrp::mboard_eeprom_t mb_eeprom = \
+ mboard[uhd::usrp::MBOARD_PROP_EEPROM_MAP].as<uhd::usrp::mboard_eeprom_t>();
+ if (not mb_eeprom.has_key(key)){
+ std::cerr << boost::format("Cannot find value for EEPROM[%s]") % key << std::endl;
+ return ~0;
+ }
+ std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % key % mb_eeprom[key] << std::endl;
+ std::cout << std::endl;
+ }
+ if (vm.count("val")){
+ uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[key] = val;
+ std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % key % val << std::endl;
+ mboard[uhd::usrp::MBOARD_PROP_EEPROM_MAP] = 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 0;
+}
diff --git a/host/utils/usrp_e_regs.hpp b/host/utils/usrp_e_regs.hpp
new file mode 100644
index 000000000..a4f42093e
--- /dev/null
+++ b/host/utils/usrp_e_regs.hpp
@@ -0,0 +1,196 @@
+
+
+////////////////////////////////////////////////////////////////
+//
+// Memory map for embedded wishbone bus
+//
+////////////////////////////////////////////////////////////////
+
+// All addresses are byte addresses. All accesses are word (16-bit) accesses.
+// This means that address bit 0 is usually 0.
+// There are 11 bits of address for the control.
+
+#ifndef __USRP_E_REGS_H
+#define __USRP_E_REGS_H
+
+/////////////////////////////////////////////////////
+// Slave pointers
+
+#define UE_REG_SLAVE(n) ((n)<<7)
+#define UE_REG_SR_ADDR(n) ((UE_REG_SLAVE(5)) + (4*(n)))
+
+/////////////////////////////////////////////////////
+// Slave 0 -- Misc Regs
+
+#define UE_REG_MISC_BASE UE_REG_SLAVE(0)
+
+#define UE_REG_MISC_LED UE_REG_MISC_BASE + 0
+#define UE_REG_MISC_SW UE_REG_MISC_BASE + 2
+#define UE_REG_MISC_CGEN_CTRL UE_REG_MISC_BASE + 4
+#define UE_REG_MISC_CGEN_ST UE_REG_MISC_BASE + 6
+#define UE_REG_MISC_TEST UE_REG_MISC_BASE + 8
+#define UE_REG_MISC_RX_LEN UE_REG_MISC_BASE + 10
+#define UE_REG_MISC_TX_LEN UE_REG_MISC_BASE + 12
+
+/////////////////////////////////////////////////////
+// Slave 1 -- UART
+// CLKDIV is 16 bits, others are only 8
+
+#define UE_REG_UART_BASE UE_REG_SLAVE(1)
+
+#define UE_REG_UART_CLKDIV UE_REG_UART_BASE + 0
+#define UE_REG_UART_TXLEVEL UE_REG_UART_BASE + 2
+#define UE_REG_UART_RXLEVEL UE_REG_UART_BASE + 4
+#define UE_REG_UART_TXCHAR UE_REG_UART_BASE + 6
+#define UE_REG_UART_RXCHAR UE_REG_UART_BASE + 8
+
+/////////////////////////////////////////////////////
+// Slave 2 -- SPI Core
+// This should be accessed through the IOCTL
+// Users should not touch directly
+
+#define UE_REG_SPI_BASE UE_REG_SLAVE(2)
+
+//spi slave constants
+#define UE_SPI_SS_AD9522 (1 << 3)
+#define UE_SPI_SS_AD9862 (1 << 2)
+#define UE_SPI_SS_TX_DB (1 << 1)
+#define UE_SPI_SS_RX_DB (1 << 0)
+
+////////////////////////////////////////////////
+// Slave 3 -- I2C Core
+// This should be accessed through the IOCTL
+// Users should not touch directly
+
+#define UE_REG_I2C_BASE UE_REG_SLAVE(3)
+
+
+////////////////////////////////////////////////
+// Slave 4 -- GPIO
+
+#define UE_REG_GPIO_BASE UE_REG_SLAVE(4)
+
+#define UE_REG_GPIO_RX_IO UE_REG_GPIO_BASE + 0
+#define UE_REG_GPIO_TX_IO UE_REG_GPIO_BASE + 2
+#define UE_REG_GPIO_RX_DDR UE_REG_GPIO_BASE + 4
+#define UE_REG_GPIO_TX_DDR UE_REG_GPIO_BASE + 6
+#define UE_REG_GPIO_RX_SEL UE_REG_GPIO_BASE + 8
+#define UE_REG_GPIO_TX_SEL UE_REG_GPIO_BASE + 10
+#define UE_REG_GPIO_RX_DBG UE_REG_GPIO_BASE + 12
+#define UE_REG_GPIO_TX_DBG UE_REG_GPIO_BASE + 14
+
+//possible bit values for sel when dbg is 0:
+#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
+#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
+
+//possible bit values for sel when dbg is 1:
+#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric
+#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric
+
+
+////////////////////////////////////////////////////
+// Slave 5 -- Settings Bus
+//
+// Output-only, no readback, 32 registers total
+// Each register must be written 32 bits at a time
+// First the address xxx_xx00 and then xxx_xx10
+
+#define UE_REG_SETTINGS_BASE UE_REG_SLAVE(5)
+
+///////////////////////////////////////////////////
+// Slave 6 -- ATR Controller
+// 16 regs
+
+#define UE_REG_ATR_BASE UE_REG_SLAVE(6)
+
+#define UE_REG_ATR_IDLE_RXSIDE UE_REG_ATR_BASE + 0
+#define UE_REG_ATR_IDLE_TXSIDE UE_REG_ATR_BASE + 2
+#define UE_REG_ATR_INTX_RXSIDE UE_REG_ATR_BASE + 4
+#define UE_REG_ATR_INTX_TXSIDE UE_REG_ATR_BASE + 6
+#define UE_REG_ATR_INRX_RXSIDE UE_REG_ATR_BASE + 8
+#define UE_REG_ATR_INRX_TXSIDE UE_REG_ATR_BASE + 10
+#define UE_REG_ATR_FULL_RXSIDE UE_REG_ATR_BASE + 12
+#define UE_REG_ATR_FULL_TXSIDE UE_REG_ATR_BASE + 14
+
+/////////////////////////////////////////////////
+// DSP RX Regs
+////////////////////////////////////////////////
+#define UE_REG_DSP_RX_FREQ UE_REG_SR_ADDR(0)
+#define UE_REG_DSP_RX_SCALE_IQ UE_REG_SR_ADDR(1) // {scale_i,scale_q}
+#define UE_REG_DSP_RX_DECIM_RATE UE_REG_SR_ADDR(2) // hb and decim rate
+#define UE_REG_DSP_RX_DCOFFSET_I UE_REG_SR_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic
+#define UE_REG_DSP_RX_DCOFFSET_Q UE_REG_SR_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits
+#define UE_REG_DSP_RX_MUX UE_REG_SR_ADDR(5)
+
+///////////////////////////////////////////////////
+// VITA RX CTRL regs
+///////////////////////////////////////////////////
+// The following 3 are logically a single command register.
+// They are clocked into the underlying fifo when time_ticks is written.
+#define UE_REG_CTRL_RX_STREAM_CMD UE_REG_SR_ADDR(8) // {now, chain, num_samples(30)
+#define UE_REG_CTRL_RX_TIME_SECS UE_REG_SR_ADDR(9)
+#define UE_REG_CTRL_RX_TIME_TICKS UE_REG_SR_ADDR(10)
+#define UE_REG_CTRL_RX_CLEAR_OVERRUN UE_REG_SR_ADDR(11) // write anything to clear overrun
+#define UE_REG_CTRL_RX_VRT_HEADER UE_REG_SR_ADDR(12) // word 0 of packet. FPGA fills in packet counter
+#define UE_REG_CTRL_RX_VRT_STREAM_ID UE_REG_SR_ADDR(13) // word 1 of packet.
+#define UE_REG_CTRL_RX_VRT_TRAILER UE_REG_SR_ADDR(14)
+#define UE_REG_CTRL_RX_NSAMPS_PER_PKT UE_REG_SR_ADDR(15)
+#define UE_REG_CTRL_RX_NCHANNELS UE_REG_SR_ADDR(16) // 1 in basic case, up to 4 for vector sources
+
+/////////////////////////////////////////////////
+// DSP TX Regs
+////////////////////////////////////////////////
+#define UE_REG_DSP_TX_FREQ UE_REG_SR_ADDR(17)
+#define UE_REG_DSP_TX_SCALE_IQ UE_REG_SR_ADDR(18) // {scale_i,scale_q}
+#define UE_REG_DSP_TX_INTERP_RATE UE_REG_SR_ADDR(19)
+#define UE_REG_DSP_TX_UNUSED UE_REG_SR_ADDR(20)
+#define UE_REG_DSP_TX_MUX UE_REG_SR_ADDR(21)
+
+/////////////////////////////////////////////////
+// VITA TX CTRL regs
+////////////////////////////////////////////////
+#define UE_REG_CTRL_TX_NCHANNELS UE_REG_SR_ADDR(24)
+#define UE_REG_CTRL_TX_CLEAR_UNDERRUN UE_REG_SR_ADDR(25)
+#define UE_REG_CTRL_TX_REPORT_SID UE_REG_SR_ADDR(26)
+#define UE_REG_CTRL_TX_POLICY UE_REG_SR_ADDR(27)
+
+#define UE_FLAG_CTRL_TX_POLICY_WAIT (0x1 << 0)
+#define UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET (0x1 << 1)
+#define UE_FLAG_CTRL_TX_POLICY_NEXT_BURST (0x1 << 2)
+
+/////////////////////////////////////////////////
+// VITA49 64 bit time (write only)
+////////////////////////////////////////////////
+ /*!
+ * \brief Time 64 flags
+ *
+ * <pre>
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------------------------------------------+-+-+
+ * | |S|P|
+ * +-----------------------------------------------------------+-+-+
+ *
+ * P - PPS edge selection (0=negedge, 1=posedge, default=0)
+ * S - Source (0=sma, 1=mimo, 0=default)
+ *
+ * </pre>
+ */
+#define UE_REG_TIME64_SECS UE_REG_SR_ADDR(28) // value to set absolute secs to on next PPS
+#define UE_REG_TIME64_TICKS UE_REG_SR_ADDR(29) // value to set absolute ticks to on next PPS
+#define UE_REG_TIME64_FLAGS UE_REG_SR_ADDR(30) // flags - see chart above
+#define UE_REG_TIME64_IMM UE_REG_SR_ADDR(31) // set immediate (0=latch on next pps, 1=latch immediate, default=0)
+#define UE_REG_TIME64_TPS UE_REG_SR_ADDR(31) // clock ticks per second (counter rollover)
+
+//pps flags (see above)
+#define UE_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
+#define UE_FLAG_TIME64_PPS_POSEDGE (1 << 0)
+#define UE_FLAG_TIME64_PPS_SMA (0 << 1)
+#define UE_FLAG_TIME64_PPS_MIMO (1 << 1)
+
+#define UE_FLAG_TIME64_LATCH_NOW 1
+#define UE_FLAG_TIME64_LATCH_NEXT_PPS 0
+
+#endif
+
diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py
new file mode 100755
index 000000000..21327e0af
--- /dev/null
+++ b/host/utils/usrp_n2xx_net_burner.py
@@ -0,0 +1,288 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 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/>.
+#
+
+# TODO: make it autodetect UHD devices
+# TODO: you should probably watch sequence numbers
+
+import optparse
+import math
+import os
+import re
+import struct
+import socket
+import sys
+
+########################################################################
+# constants
+########################################################################
+UDP_FW_UPDATE_PORT = 49154
+UDP_MAX_XFER_BYTES = 1024
+UDP_TIMEOUT = 3
+UDP_POLL_INTERVAL = 0.10 #in seconds
+
+USRP2_FW_PROTO_VERSION = 7
+
+#from bootloader_utils.h
+
+FPGA_IMAGE_SIZE_BYTES = 1572864
+FW_IMAGE_SIZE_BYTES = 31744
+SAFE_FPGA_IMAGE_LOCATION_ADDR = 0x00000000
+SAFE_FW_IMAGE_LOCATION_ADDR = 0x003F0000
+PROD_FPGA_IMAGE_LOCATION_ADDR = 0x00180000
+PROD_FW_IMAGE_LOCATION_ADDR = 0x00300000
+
+FLASH_DATA_PACKET_SIZE = 256
+
+#see fw_common.h
+FLASH_ARGS_FMT = '!LLLLL256s'
+FLASH_INFO_FMT = '!LLLLL256x'
+FLASH_IP_FMT = '!LLLL260x'
+
+class update_id_t:
+ USRP2_FW_UPDATE_ID_WAT = ord(' ')
+ USRP2_FW_UPDATE_ID_OHAI_LOL = ord('a')
+ USRP2_FW_UPDATE_ID_OHAI_OMG = ord('A')
+ USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = ord('f')
+ USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = ord('F')
+ USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = ord('e')
+ USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = ord('E')
+ USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = ord('d')
+ USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = ord('D')
+ USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = ord('B')
+ USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = ord('w')
+ USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = ord('W')
+ USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = ord('r')
+ USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = ord('R')
+ USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = ord('s')
+ USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = ord('S')
+ USRP2_FW_UPDATE_ID_KTHXBAI = ord('~')
+
+_seq = -1
+def seq():
+ global _seq
+ _seq = _seq+1
+ return _seq
+
+########################################################################
+# helper functions
+########################################################################
+def unpack_flash_args_fmt(s):
+ return struct.unpack(FLASH_ARGS_FMT, s) #(proto_ver, pktid, seq, flash_addr, length, data)
+
+def unpack_flash_info_fmt(s):
+ return struct.unpack(FLASH_INFO_FMT, s) #(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
+
+def unpack_flash_ip_fmt(s):
+ return struct.unpack(FLASH_IP_FMT, s) #(proto_ver, pktid, seq, ip_addr)
+
+def pack_flash_args_fmt(proto_ver, pktid, seq, flash_addr, length, data):
+ return struct.pack(FLASH_ARGS_FMT, proto_ver, pktid, seq, flash_addr, length, data)
+
+def pack_flash_info_fmt(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes):
+ return struct.pack(FLASH_INFO_FMT, proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
+
+def send_and_recv(pkt, ip):
+ update_socket = create_socket()
+
+ try:
+ update_socket.sendto(pkt, (ip, UDP_FW_UPDATE_PORT))
+ except Exception, e:
+ print e
+ sys.exit(1)
+
+ try:
+ (recv_pkt, recv_addr) = update_socket.recvfrom(UDP_MAX_XFER_BYTES)
+ except Exception, e:
+ print e
+ sys.exit(1)
+
+ if recv_addr != (options.ip, UDP_FW_UPDATE_PORT):
+ raise Exception, "Packet received from invalid IP %s, expected %s" % (recv_addr, options.ip)
+
+ return recv_pkt
+
+def create_socket():
+ socket.setdefaulttimeout(UDP_TIMEOUT)
+ update_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ return update_socket
+
+#just here to validate comms
+def init_update(ip):
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0, "")
+ in_pkt = send_and_recv(out_pkt, ip)
+ (proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(in_pkt)
+ if pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG:
+ print "USRP2P found."
+ else:
+ raise Exception, "Invalid reply received from device."
+
+# print "Incoming:\n\tVer: %i\n\tID: %c\n\tSeq: %i\n\tIP: %i\n" % (proto_ver, chr(pktid), rxseq, ip_addr)
+
+def get_flash_info(ip):
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL, seq(), 0, 0, "")
+ in_pkt = send_and_recv(out_pkt, ip)
+
+ (proto_ver, pktid, rxseq, sector_size_bytes, memory_size_bytes) = unpack_flash_info_fmt(in_pkt)
+
+ if pktid != update_id_t.USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG:
+ raise Exception, "Invalid reply %c from device." % (chr(pktid))
+
+
+ return (memory_size_bytes, sector_size_bytes)
+
+def burn_fw(ip, fw, fpga, reset, safe):
+ init_update(ip)
+ (flash_size, sector_size) = get_flash_info(ip)
+
+ print "Flash size: %i\nSector size: %i" % (flash_size, sector_size)
+
+ if fpga:
+ if safe:
+ image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR
+ else:
+ image_location = PROD_FPGA_IMAGE_LOCATION_ADDR
+
+ fpga_file = open(fpga, 'rb')
+ fpga_image = fpga_file.read()
+ erase_image(ip, image_location, FPGA_IMAGE_SIZE_BYTES)
+ write_image(ip, fpga_image, image_location)
+ verify_image(ip, fpga_image, image_location)
+
+ if fw:
+ if safe:
+ image_location = SAFE_FW_IMAGE_LOCATION_ADDR
+ else:
+ image_location = PROD_FW_IMAGE_LOCATION_ADDR
+
+ fw_file = open(fw, 'rb')
+ fw_image = fw_file.read()
+ erase_image(ip, image_location, FW_IMAGE_SIZE_BYTES)
+ write_image(ip, fw_image, image_location)
+ verify_image(ip, fw_image, image_location)
+
+ if reset:
+ reset_usrp(ip)
+
+def write_image(ip, image, addr):
+ print "Writing image"
+#we split the image into smaller (256B) bits and send them down the wire
+ while image:
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL, seq(), addr, FLASH_DATA_PACKET_SIZE, image[:FLASH_DATA_PACKET_SIZE])
+ in_pkt = send_and_recv(out_pkt, ip)
+
+ (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
+
+ if pktid != update_id_t.USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG:
+ raise Exception, "Invalid reply %c from device." % (chr(pktid))
+
+ image = image[FLASH_DATA_PACKET_SIZE:]
+ addr += FLASH_DATA_PACKET_SIZE
+
+def verify_image(ip, image, addr):
+ print "Verifying data"
+ readsize = len(image)
+ readdata = str()
+ while readsize > 0:
+ if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize
+ else: thisreadsize = FLASH_DATA_PACKET_SIZE
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize, "")
+ in_pkt = send_and_recv(out_pkt, ip)
+
+ (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
+
+ if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG:
+ raise Exception, "Invalid reply %c from device." % (chr(pktid))
+
+ readdata += data[:thisreadsize]
+ readsize -= FLASH_DATA_PACKET_SIZE
+ addr += FLASH_DATA_PACKET_SIZE
+
+ print "Read back %i bytes" % len(readdata)
+# print readdata
+
+# for i in range(256, 512):
+# print "out: %i in: %i" % (ord(image[i]), ord(readdata[i]))
+
+ if readdata != image:
+ print "Verify failed. Image did not write correctly."
+ else:
+ print "Success."
+
+def reset_usrp(ip):
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL, seq(), 0, 0, "")
+ in_pkt = send_and_recv(out_pkt, ip)
+
+ (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
+ if pktid == update_id_t.USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG:
+ raise Exception, "Device failed to reset."
+
+def erase_image(ip, addr, length):
+ #get flash info first
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL, seq(), addr, length, "")
+ in_pkt = send_and_recv(out_pkt, ip)
+
+ (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
+
+ if pktid != update_id_t.USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG:
+ raise Exception, "Invalid reply %c from device." % (chr(pktid))
+
+ print "Erasing %i bytes at %i" % (length, addr)
+
+ #now wait for it to finish
+ while(1):
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL, seq(), 0, 0, "")
+ in_pkt = send_and_recv(out_pkt, ip)
+
+ (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
+
+ if pktid == update_id_t.USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG: break
+ elif pktid != update_id_t.USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG:
+ raise Exception, "Invalid reply %c from device." % (chr(pktid))
+
+
+########################################################################
+# command line options
+########################################################################
+def get_options():
+ parser = optparse.OptionParser()
+ parser.add_option("--ip", type="string", help="USRP2P firmware address", default='')
+ parser.add_option("--fw", type="string", help="firmware image path (optional)", default='')
+ parser.add_option("--fpga", type="string", help="fpga image path (optional)", default='')
+ parser.add_option("--reset", action="store_true", help="reset the device after writing", default=False)
+ parser.add_option("--overwrite-safe", action="store_true", help="never ever use this option", default=False)
+ (options, args) = parser.parse_args()
+
+ return options
+
+########################################################################
+# main
+########################################################################
+if __name__=='__main__':
+ options = get_options()
+ if not options.ip: raise Exception, 'no ip address specified'
+
+ if not options.fpga and not options.fw and not options.reset: raise Exception, 'Must specify either a firmware image or FPGA image, and/or reset.'
+
+ if options.overwrite_safe:
+ print("Are you REALLY, REALLY sure you want to overwrite the safe image? This is ALMOST ALWAYS a terrible idea.")
+ print("If your image is faulty, your USRP2+ will become a brick until reprogrammed via JTAG.")
+ response = raw_input("""Type "yes" to continue, or anything else to quit: """)
+ if response != "yes":
+ sys.exit(0)
+
+ burn_fw(ip=options.ip, fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe)