summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/CMakeLists.txt31
-rw-r--r--host/apps/omap_debug/Makefile30
-rw-r--r--host/apps/omap_debug/clkgen-config.cc296
-rw-r--r--host/apps/omap_debug/fpga-downloader.cc253
-rw-r--r--host/apps/omap_debug/usrp-e-loopback.c194
-rw-r--r--host/apps/omap_debug/usrp-e-mm-loopback.c260
-rw-r--r--host/apps/omap_debug/usrp-e-random-loopback.c149
-rw-r--r--host/apps/omap_debug/usrp-e-timed.c233
-rw-r--r--host/docs/general.rst49
-rw-r--r--host/docs/identification.rst44
-rw-r--r--host/docs/images.rst2
-rw-r--r--host/docs/transport.rst16
-rw-r--r--host/include/uhd/config.hpp2
-rw-r--r--host/include/uhd/transport/if_addrs.hpp1
-rw-r--r--host/include/uhd/transport/zero_copy.hpp34
-rw-r--r--host/include/uhd/types/ref_vector.hpp2
-rw-r--r--host/include/uhd/usrp/dboard_eeprom.hpp35
-rw-r--r--host/include/uhd/utils/algorithm.hpp14
-rw-r--r--host/lib/CMakeLists.txt3
-rw-r--r--host/lib/convert/CMakeLists.txt18
-rw-r--r--host/lib/transport/CMakeLists.txt33
-rw-r--r--host/lib/transport/if_addrs.cpp16
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp492
-rw-r--r--host/lib/transport/udp_common.hpp53
-rw-r--r--host/lib/transport/udp_simple.cpp160
-rw-r--r--host/lib/transport/udp_zero_copy.cpp (renamed from host/lib/transport/udp_zero_copy_asio.cpp)82
-rw-r--r--host/lib/transport/zero_copy.cpp114
-rw-r--r--host/lib/types/CMakeLists.txt15
-rw-r--r--host/lib/types/time_spec.cpp16
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp28
-rw-r--r--host/lib/usrp/dboard_eeprom.cpp64
-rw-r--r--host/lib/usrp/mboard_eeprom.cpp12
-rw-r--r--host/lib/usrp/usrp1/dboard_impl.cpp21
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp137
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp10
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp5
-rw-r--r--host/lib/usrp/usrp_e100/dboard_impl.cpp10
-rw-r--r--host/lib/usrp/usrp_e100/io_impl.cpp48
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp160
-rw-r--r--host/lib/utils/CMakeLists.txt57
-rw-r--r--host/lib/utils/load_modules.cpp14
-rw-r--r--host/lib/utils/thread_priority.cpp10
-rw-r--r--host/usrp_e_utils/CMakeLists.txt1
-rw-r--r--host/usrp_e_utils/usrp-e-loopback.c170
-rw-r--r--host/usrp_e_utils/usrp-e-timed.c (renamed from host/apps/omap_debug/usrp-e-crc-rw.c)143
-rwxr-xr-xhost/utils/usrp_n2xx_net_burner.py428
46 files changed, 1286 insertions, 2679 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index baa5ab662..e4f272a76 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -79,19 +79,18 @@ IF(MSVC)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/msvc)
ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp
ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max
- ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split
- ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc
+ ADD_DEFINITIONS( #stop all kinds of compatibility warnings
+ -D_SCL_SECURE_NO_WARNINGS
+ -D_CRT_SECURE_NO_WARNINGS
+ -D_CRT_SECURE_NO_DEPRECATE
+ -D_CRT_NONSTDC_NO_DEPRECATE
+ )
ENDIF(MSVC)
########################################################################
# Setup Boost
########################################################################
-IF(UNIX AND EXISTS "/usr/lib64")
- LIST(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
-ENDIF(UNIX AND EXISTS "/usr/lib64")
-
-SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44")
-FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} COMPONENTS
+SET(BOOST_REQUIRED_COMPONENTS
date_time
filesystem
program_options
@@ -101,6 +100,22 @@ FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} COMPONENTS
unit_test_framework
)
+IF(UNIX AND EXISTS "/usr/lib64")
+ LIST(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
+ENDIF(UNIX AND EXISTS "/usr/lib64")
+
+IF(MSVC)
+ SET(BOOST_ALL_DYN_LINK "${BOOST_ALL_DYN_LINK}" CACHE BOOL "boost enable dynamic linking")
+ IF(BOOST_ALL_DYN_LINK)
+ ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc
+ ELSE(BOOST_ALL_DYN_LINK)
+ UNSET(BOOST_REQUIRED_COMPONENTS) #empty components list for static link
+ ENDIF(BOOST_ALL_DYN_LINK)
+ENDIF(MSVC)
+
+SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44")
+FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
+
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
diff --git a/host/apps/omap_debug/Makefile b/host/apps/omap_debug/Makefile
index 46d4714a8..f8b9f2bd9 100644
--- a/host/apps/omap_debug/Makefile
+++ b/host/apps/omap_debug/Makefile
@@ -1,27 +1,12 @@
CFLAGS=-Wall -I../../lib/usrp/usrp_e/ -march=armv7-a -mtune=cortex-a8 -mfpu=neon -O3
CXXFLAGS=-Wall -I../../lib/usrp/usrp_e/ -march=armv7-a -mtune=cortex-a8 -mfpu=neon -O3
-all : usrp-e-spi usrp-e-i2c usrp-e-loopback usrp-e-mm-loopback usrp-e-uart usrp-e-led usrp-e-ctl usrp-e-button usrp-e-uart-rx fpga-downloader usrp-e-gpio usrp-e-debug-pins usrp-e-random-loopback usrp-e-timed usrp-e-lb-test usrp-e-crc-rw clkgen-config
+all : usrp-e-spi usrp-e-i2c usrp-e-uart usrp-e-led usrp-e-ctl usrp-e-button usrp-e-uart-rx usrp-e-gpio usrp-e-debug-pins
usrp-e-spi : usrp-e-spi.c
usrp-e-i2c : usrp-e-i2c.c
-usrp-e-loopback : usrp-e-loopback.c
- gcc -o $@ $< -lpthread ${CFLAGS}
-
-usrp-e-mm-loopback : usrp-e-mm-loopback.c
- gcc -o $@ $< -lpthread ${CFLAGS}
-
-usrp-e-timed : usrp-e-timed.c
- gcc -o $@ $< -lpthread ${CFLAGS}
-
-usrp-e-random-loopback : usrp-e-random-loopback.c
- gcc -o $@ $< -lpthread ${CFLAGS}
-
-usrp-e-crc-rw : usrp-e-crc-rw.c
- gcc -o $@ $< -lpthread ${CFLAGS}
-
usrp-e-uart : usrp-e-uart.c
usrp-e-uart-rx : usrp-e-uart-rx.c
@@ -32,30 +17,17 @@ usrp-e-ctl : usrp-e-ctl.c
usrp-e-button : usrp-e-button.c
-fpga-downloader : fpga-downloader.cc
-
-clkgen-config : clkgen-config.cc
-
usrp-e-gpio : usrp-e-gpio.c
-usrp-e-lb-test : usrp-e-lb-test.c
-
usrp-e-debug-pins : usrp-e-debug-pins.c
clean :
rm -f usrp-e-spi
rm -f usrp-e-i2c
- rm -f usrp-e-loopback
- rm -f usrp-e-mm-loopback
- rm -f usrp-e-timed
- rm -f usrp-e-rw-random
rm -f usrp-e-uart
rm -f usrp-e-uart-rx
rm -f usrp-e-led
rm -f usrp-e-ctl
rm -f usrp-e-button
- rm -f fpga-downloader
rm -f usrp-e-gpio
rm -f usrp-e-debug-pins
rm -f usrp-e-lb-test
- rm -f usrp-e-crc-rw
- rm -f clkgen-config
diff --git a/host/apps/omap_debug/clkgen-config.cc b/host/apps/omap_debug/clkgen-config.cc
deleted file mode 100644
index e8279b4ae..000000000
--- a/host/apps/omap_debug/clkgen-config.cc
+++ /dev/null
@@ -1,296 +0,0 @@
-/* -*- 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/apps/omap_debug/fpga-downloader.cc b/host/apps/omap_debug/fpga-downloader.cc
deleted file mode 100644
index 4e475b5c1..000000000
--- a/host/apps/omap_debug/fpga-downloader.cc
+++ /dev/null
@@ -1,253 +0,0 @@
-/* -*- 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 <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;
-
- if (gpio_num != 114) {
- 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];
-
- 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/apps/omap_debug/usrp-e-loopback.c b/host/apps/omap_debug/usrp-e-loopback.c
deleted file mode 100644
index d11cf7d09..000000000
--- a/host/apps/omap_debug/usrp-e-loopback.c
+++ /dev/null
@@ -1,194 +0,0 @@
-#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 "usrp_e.h"
-
-// max length #define PKT_DATA_LENGTH 1016
-static int packet_data_length;
-static int error;
-
-struct pkt {
- int len;
- int checksum;
- int seq_num;
- short data[];
-};
-
-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;
-
- 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;
- }
-
- 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() & 0x1ff) + (1004 - 512);
-
- 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;
- 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]);
-
- 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/apps/omap_debug/usrp-e-mm-loopback.c b/host/apps/omap_debug/usrp-e-mm-loopback.c
deleted file mode 100644
index b67eecd21..000000000
--- a/host/apps/omap_debug/usrp-e-mm-loopback.c
+++ /dev/null
@@ -1,260 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <sys/mman.h>
-#include <poll.h>
-#include "usrp_e.h"
-
-// max length #define PKT_DATA_LENGTH 1016
-static int packet_data_length;
-static int error;
-
-struct pkt {
- int len;
- int checksum;
- int seq_num;
- short data[1024-6];
-};
-
-struct ring_buffer_info (*rxi)[];
-struct ring_buffer_info (*txi)[];
-struct pkt (*rx_buf)[200];
-struct pkt (*tx_buf)[200];
-
-static int fp;
-static struct usrp_e_ring_buffer_size_t rb_size;
-
-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)
-{
- 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 rb_read;
-
- printf("Greetings from the reading thread!\n");
- printf("sizeof pkt = %d\n", sizeof(struct pkt));
-
- rb_read = 0;
-
- bytes_transfered = 0;
- gettimeofday(&start_time, NULL);
-
- prev_seq_num = 0;
- pkt_count = 0;
- seq_num_failure = 0;
-
- while (1) {
-
- if (!((*rxi)[rb_read].flags & RB_USER)) {
-// printf("Waiting for data\n");
- struct pollfd pfd;
- pfd.fd = fp;
- pfd.events = POLLIN;
- ssize_t ret = poll(&pfd, 1, -1);
- }
-
- (*rxi)[rb_read].flags = RB_USER_PROCESS;
-
-// printf("pkt received, rb_read = %d\n", rb_read);
-
- cnt = (*rxi)[rb_read].len;
- p = &(*rx_buf)[rb_read];
-
-// 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 = %X, p->seq_num = %d p->len = %d\n", p, p->seq_num, p->len);
-
-
- 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);
- printf("pkt received, rb_read = %d\n", rb_read);
- printf("p = %X, p->seq_num = %d p->len = %d\n", p, p->seq_num, p->len);
-
- seq_num_failure ++;
- if (seq_num_failure > 2)
- error = 1;
- }
-
- 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;
- }
-
- (*rxi)[rb_read].flags = RB_KERNEL;
-
- rb_read++;
- if (rb_read == rb_size.num_rx_frames)
- rb_read = 0;
-
- 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, rb_write;
- 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;
- rb_write = 0;
-
- while (1) {
- p->seq_num = seq_number++;
-
- if (packet_data_length > 0)
- p->len = packet_data_length;
- else
- p->len = (random() & 0x1ff) + (1004 - 512);
-
- p->checksum = calc_checksum(p);
-
- if (!((*txi)[rb_write].flags & RB_KERNEL)) {
-// printf("Waiting for space\n");
- struct pollfd pfd;
- pfd.fd = fp;
- pfd.events = POLLOUT;
- ssize_t ret = poll(&pfd, 1, -1);
- }
-
- memcpy(&(*tx_buf)[rb_write], tx_data, p->len * 2 + 12);
-
- (*txi)[rb_write].len = p->len * 2 + 12;
- (*txi)[rb_write].flags = RB_USER;
-
- rb_write++;
- if (rb_write == rb_size.num_tx_frames)
- rb_write = 0;
-
- cnt = write(fp, NULL, 0);
-// if (cnt < 0)
-// printf("Error returned from write: %d\n", cnt);
-// sleep(1);
- }
-}
-
-
-int main(int argc, char *argv[])
-{
- pthread_t tx, rx;
- long int t;
- struct sched_param s = {
- .sched_priority = 1
- };
- int ret, map_size, page_size;
- void *rb;
-
- if (argc < 2) {
- printf("%s data_size\n", argv[0]);
- return -1;
- }
-
- packet_data_length = atoi(argv[1]);
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- page_size = getpagesize();
-
- ret = ioctl(fp, USRP_E_GET_RB_INFO, &rb_size);
-
- map_size = (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * page_size +
- (rb_size.num_rx_frames + rb_size.num_tx_frames) * (page_size >> 1);
-
- rb = mmap(0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
- if (rb == MAP_FAILED) {
- perror("mmap failed");
- return -1;
- }
-
- printf("rb = %X\n", rb);
-
- rxi = rb;
- rx_buf = rb + (rb_size.num_pages_rx_flags * page_size);
- txi = rb + (rb_size.num_pages_rx_flags * page_size) +
- (rb_size.num_rx_frames * page_size >> 1);
- tx_buf = rb + (rb_size.num_pages_rx_flags * page_size) +
- (rb_size.num_rx_frames * page_size >> 1) +
- (rb_size.num_pages_tx_flags * page_size);
-
- printf("rxi = %X, rx_buf = %X, txi = %X, tx_buf = %X\n", rxi, rx_buf, txi, tx_buf);
-
- 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/apps/omap_debug/usrp-e-random-loopback.c b/host/apps/omap_debug/usrp-e-random-loopback.c
deleted file mode 100644
index 5960b8fbd..000000000
--- a/host/apps/omap_debug/usrp-e-random-loopback.c
+++ /dev/null
@@ -1,149 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include "usrp_e.h"
-
-// max length #define PKT_DATA_LENGTH 1014
-static int packet_data_length;
-
-struct pkt {
- int checksum;
- int seq_num;
- int len;
- short data[];
-};
-
-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;
-
- return sum;
-}
-
-int randN(int n)
-{
- long tmp;
-
- tmp = rand() % n;
-
- return tmp;
-}
-
-static void *read_thread(void *threadid)
-{
- int cnt, prev_seq_num;
- struct usrp_transfer_frame *rx_data;
- struct pkt *p;
-
- printf("Greetings from the reading thread!\n");
-
- // IMPORTANT: must assume max length packet from fpga
- rx_data = malloc(sizeof(struct usrp_transfer_frame) + sizeof(struct pkt) + (1014 * 2));
- rx_data = malloc(2048);
- p = (struct pkt *) ((void *)rx_data + offsetof(struct usrp_transfer_frame, buf));
- //p = &(rx_data->buf[0]);
- printf("Address of rx_data = %p, p = %p\n", rx_data, p);
- printf("offsetof = %d\n", offsetof(struct usrp_transfer_frame, buf));
- printf("sizeof rx data = %d\n", sizeof(struct usrp_transfer_frame) + sizeof(struct pkt));
-
- prev_seq_num = 0;
-
- while (1) {
-
- cnt = read(fp, rx_data, 2048);
-// printf("Packet received, status = %X, len = %d\n", rx_data->status, rx_data->len);
-// printf("p->seq_num = %d\n", p->seq_num);
-
- if (p->seq_num != prev_seq_num + 1)
- printf("Sequence number fail, current = %d, previous = %d\n",
- p->seq_num, prev_seq_num);
- prev_seq_num = p->seq_num;
-
- if (calc_checksum(p) != p->checksum)
- printf("Checksum fail packet = %d, expected = %d\n",
- calc_checksum(p), p->checksum);
- printf(".");
- fflush(stdout);
-// printf("\n");
- }
-
-}
-
-static void *write_thread(void *threadid)
-{
- int seq_number, i, cnt, pkt_cnt;
- struct usrp_transfer_frame *tx_data;
- struct pkt *p;
-
- printf("Greetings from the write thread!\n");
-
- // Allocate max length buffer for frame
- tx_data = malloc(2048);
- p = (struct pkt *) ((void *)tx_data + offsetof(struct usrp_transfer_frame, buf));
- printf("Address of tx_data = %p, p = %p\n", tx_data, p);
-
- printf("sizeof rp_transfer_frame = %d, sizeof pkt = %d\n", sizeof(struct usrp_transfer_frame), sizeof(struct pkt));
-
- for (i=0; i < 1014; i++)
-// p->data[i] = random() >> 16;
- p->data[i] = i;
-
- tx_data->status = 0xdeadbeef;
- tx_data->len = 8 + packet_data_length * 2;
-
- printf("tx_data->len = %d\n", tx_data->len);
-
- seq_number = 1;
-
- while (1) {
- pkt_cnt = randN(16);
- for (i = 0; i < pkt_cnt; i++) {
- p->seq_num = seq_number++;
- p->len = randN(1013) + 1;
- p->checksum = calc_checksum(p);
- tx_data->len = 12 + p->len * 2;
- cnt = write(fp, tx_data, tx_data->len + 8);
- }
- sleep(random() >> 31);
- }
-}
-
-
-int main(int argc, char *argv[])
-{
- pthread_t tx, rx;
- long int t;
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- if (pthread_create(&rx, NULL, read_thread, (void *) t)) {
- printf("Failed to create rx thread\n");
- exit(-1);
- }
-
- sleep(1);
-
- if (pthread_create(&tx, NULL, write_thread, (void *) t)) {
- printf("Failed to create tx thread\n");
- exit(-1);
- }
-
- sleep(1000000000);
-
- printf("Done sleeping\n");
-}
diff --git a/host/apps/omap_debug/usrp-e-timed.c b/host/apps/omap_debug/usrp-e-timed.c
deleted file mode 100644
index 3cb33ce2d..000000000
--- a/host/apps/omap_debug/usrp-e-timed.c
+++ /dev/null
@@ -1,233 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include "usrp_e.h"
-
-// max length #define PKT_DATA_LENGTH 1016
-static int packet_data_length;
-
-struct pkt {
- int checksum;
- int seq_num;
- short data[];
-};
-
-static int fp;
-
-static int calc_checksum(struct pkt *p)
-{
- int i, sum;
-
- i = 0;
- sum = 0;
-
- for (i=0; i < packet_data_length; i++)
- sum += p->data[i];
-
- sum += p->seq_num;
-
- return sum;
-}
-
-static void *read_thread(void *threadid)
-{
- int cnt, prev_seq_num;
- struct usrp_transfer_frame *rx_data;
- struct pkt *p;
- int rx_pkt_cnt;
- int i;
- unsigned long bytes_transfered, elapsed_seconds;
- struct timeval start_time, finish_time;
-
- 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(sizeof(struct usrp_transfer_frame) + sizeof(struct pkt) + (1016 * 2));
- p = (struct pkt *) ((void *)rx_data + offsetof(struct usrp_transfer_frame, buf));
- //p = &(rx_data->buf[0]);
- printf("Address of rx_data = %p, p = %p\n", rx_data, p);
- printf("offsetof = %d\n", offsetof(struct usrp_transfer_frame, buf));
- printf("sizeof rx data = %d\n", sizeof(struct usrp_transfer_frame) + sizeof(struct pkt));
-
- prev_seq_num = 0;
-
- rx_pkt_cnt = 0;
-
- while (1) {
-
- cnt = read(fp, rx_data, 2048);
- if (cnt < 0)
- printf("Error returned from read: %d\n", cnt);
- rx_pkt_cnt++;
-
-#if 0
- if (rx_pkt_cnt == 512) {
- printf(".");
- fflush(stdout);
- rx_pkt_cnt = 0;
- }
-#endif
-
- if (rx_data->status & RB_OVERRUN)
- printf("O");
-
- bytes_transfered += rx_data->len;
-
- 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;
- }
- }
-
-}
-
-static void *write_thread(void *threadid)
-{
- int seq_number, i, cnt, tx_pkt_cnt;
- struct usrp_transfer_frame *tx_data;
- struct pkt *p;
- unsigned long bytes_transfered, elapsed_seconds;
- struct timeval start_time, finish_time;
-
- printf("Greetings from the write thread!\n");
-
- bytes_transfered = 0;
- gettimeofday(&start_time, NULL);
-
- tx_data = malloc(sizeof(struct usrp_transfer_frame) + sizeof(struct pkt) + (packet_data_length * 2));
- p = (struct pkt *) ((void *)tx_data + offsetof(struct usrp_transfer_frame, buf));
- printf("Address of tx_data = %p, p = %p\n", tx_data, p);
-
- printf("sizeof rp_transfer_frame = %d, sizeof pkt = %d\n", sizeof(struct usrp_transfer_frame), sizeof(struct pkt));
-
- for (i=0; i < packet_data_length; i++)
-// p->data[i] = random() >> 16;
- p->data[i] = i;
-
- tx_data->status = 0;
- tx_data->len = 8 + packet_data_length * 2;
-
- printf("tx_data->len = %d\n", tx_data->len);
-
- seq_number = 1;
- tx_pkt_cnt = 0;
-
- while (1) {
-
- tx_pkt_cnt++;
-
-#if 0
- if (tx_pkt_cnt == 512) {
- printf(".");
- fflush(stdout);
- }
- if (tx_pkt_cnt == 1024) {
- printf("'");
- fflush(stdout);
- }
- if (tx_pkt_cnt == 1536) {
- printf(":");
- fflush(stdout);
- tx_pkt_cnt = 0;
- }
-#endif
-
-// printf("tx status = %X, len = %d\n", tx_data->status, tx_data->len);
- p->seq_num = seq_number++;
- p->checksum = calc_checksum(p);
- cnt = write(fp, tx_data, 2048);
- if (cnt < 0)
- printf("Error returned from write: %d\n", cnt);
-
- bytes_transfered += tx_data->len;
-
- if (bytes_transfered > (100 * 1000000)) {
- gettimeofday(&finish_time, NULL);
- elapsed_seconds = finish_time.tv_sec - start_time.tv_sec;
-
- printf("TX data transfer rate = %f K Samples/second\n",
- (float) bytes_transfered / (float) elapsed_seconds / 4000);
-
-
- start_time = finish_time;
- bytes_transfered = 0;
- }
-// sleep(1);
- }
-}
-
-
-int main(int argc, char *argv[])
-{
- pthread_t tx, rx;
- long int t;
- int fpga_config_flag ,decimation;
- struct usrp_e_ctl16 d;
- struct sched_param s = {
- .sched_priority = 1
- };
-
- if (argc < 4) {
- printf("%s r|w|rw decimation data_size\n", argv[0]);
- return -1;
- }
-
- decimation = atoi(argv[2]);
- packet_data_length = atoi(argv[3]);
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- fpga_config_flag = 0;
- if (strcmp(argv[1], "w") == 0)
- fpga_config_flag |= (1 << 15);
- else if (strcmp(argv[1], "r") == 0)
- fpga_config_flag |= (1 << 14);
- else if (strcmp(argv[1], "rw") == 0)
- fpga_config_flag |= ((1 << 15) | (1 << 14));
-
- fpga_config_flag |= decimation;
-
- d.offset = 14;
- d.count = 1;
- d.buf[0] = fpga_config_flag;
- ioctl(fp, USRP_E_WRITE_CTL16, &d);
-
- sleep(1); // in case the kernel threads need time to start. FIXME if so
-
- sched_setscheduler(0, SCHED_RR, &s);
-
- if (fpga_config_flag & (1 << 14)) {
- if (pthread_create(&rx, NULL, read_thread, (void *) t)) {
- printf("Failed to create rx thread\n");
- exit(-1);
- }
- }
-
- sleep(1);
-
- if (fpga_config_flag & (1 << 15)) {
- if (pthread_create(&tx, NULL, write_thread, (void *) t)) {
- printf("Failed to create tx thread\n");
- exit(-1);
- }
- }
-
- sleep(10000);
-
- printf("Done sleeping\n");
-}
diff --git a/host/docs/general.rst b/host/docs/general.rst
index 90a880c2e..50ef24d6c 100644
--- a/host/docs/general.rst
+++ b/host/docs/general.rst
@@ -5,55 +5,6 @@ UHD - General Application Notes
.. contents:: Table of Contents
------------------------------------------------------------------------
-Finding devices
-------------------------------------------------------------------------
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Device addressing
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Deviced are addressed through key/value string pairs.
-These string pairs can be used to narrow down the search for a specific device or group of devices.
-Most UHD utility applications and examples have a --args parameter that takes a device address;
-where the device address is expressed as a delimited string.
-
-* See the documentation in types/device_addr.hpp for reference.
-* See device-specific application notes for usage.
-
-**Example:**
-::
-
- serial=0x1234, type=usrpx
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Device discovery
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Devices attached to your system can be discovered using the "uhd_find_devices" program.
-The find devices program scans your system for supported devices and prints
-out an enumerated list of discovered devices and their addresses.
-The list of discovered devices can be narrowed down by specifying device address args.
-
-**Usage:**
-::
-
- uhd_find_devices
-
- -- OR --
-
- uhd_find_devices --args <device-specific-address-args>
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Device properties
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Properties of devices attached to your system can be probed with the "uhd_usrp_probe" program.
-The usrp probe program constructs an instance of the device and prints out its properties;
-properties such as detected daughter-boards, frequency range, gain ranges, etc...
-
-**Usage:**
-::
-
- uhd_usrp_probe --args <device-specific-address-args>
-
-------------------------------------------------------------------------
Misc notes
------------------------------------------------------------------------
diff --git a/host/docs/identification.rst b/host/docs/identification.rst
index 49d36ec1a..90484744c 100644
--- a/host/docs/identification.rst
+++ b/host/docs/identification.rst
@@ -7,20 +7,36 @@ UHD - Device Identification Notes
------------------------------------------------------------------------
Identifying USRPs
------------------------------------------------------------------------
-Every device has several ways of identifying it on the host system:
+Devices are addressed through key/value string pairs.
+These string pairs can be used to narrow down the search for a specific device or group of devices.
+Most UHD utility applications and examples have a --args parameter that takes a device address;
+where the device address is expressed as a delimited string.
+See the documentation in types/device_addr.hpp for reference.
-* **Serial:** A globally unique identifier.
-* **Address:** A unique identifier on a network.
-* **Name:** An optional user-set identifier.
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Common device identifiers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Every device has several ways of identifying it on the host system:
-The address is only applicable for network-based devices.
-See the USRP2 application notes.
++------------+------------+--------------------------------------------+
+| Identifier | Key | Notes |
++============+============+============================================+
+| Serial | serial | globally unique identifier |
++------------+------------+--------------------------------------------+
+| Address | addr | unique identifier on a network |
++------------+------------+--------------------------------------------+
+| Name | name | optional user-set identifier |
++------------+------------+--------------------------------------------+
+| Type | type | hardware series identifier |
++------------+------------+--------------------------------------------+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Device discovery via command line
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-A "find devices" utility application comes bundled with the UHD.
-The find devices application will search for all devices on the host system and print the results.
+Devices attached to your system can be discovered using the "uhd_find_devices" program.
+The find devices program scans your system for supported devices and prints
+out an enumerated list of discovered devices and their addresses.
+The list of discovered devices can be narrowed down by specifying device address args.
::
@@ -60,6 +76,18 @@ The hint argument can be populated to narrow the scope of the search.
hint["serial"] = "12345678";
uhd::device_addrs_t dev_addrs = uhd::device::find(hint);
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Device properties
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Properties of devices attached to your system can be probed with the "uhd_usrp_probe" program.
+The usrp probe program constructs an instance of the device and prints out its properties;
+properties such as detected daughter-boards, frequency range, gain ranges, etc...
+
+**Usage:**
+::
+
+ uhd_usrp_probe --args <device-specific-address-args>
+
------------------------------------------------------------------------
Naming a USRP
------------------------------------------------------------------------
diff --git a/host/docs/images.rst b/host/docs/images.rst
index 612a00aa5..f5be88a65 100644
--- a/host/docs/images.rst
+++ b/host/docs/images.rst
@@ -12,6 +12,8 @@ The methods of loading images into the device varies among devices:
* **USRP1:** The host code will automatically load the firmware and FPGA at runtime.
* **USRP2:** The user must manually write the images onto the USRP2 SD card.
+* **USRP-N Series:** The user must manually transfer the images over ethernet.
+* **USRP-E Series:** The host code will automatically load the FPGA at runtime.
------------------------------------------------------------------------
Pre-built images
diff --git a/host/docs/transport.rst b/host/docs/transport.rst
index 6b9d28bfa..2371d2497 100644
--- a/host/docs/transport.rst
+++ b/host/docs/transport.rst
@@ -17,13 +17,9 @@ that are known to perform well on a variety of systems.
The transport parameters are defined below for the various transports in the UHD:
------------------------------------------------------------------------
-UDP transport (ASIO)
+UDP transport (sockets)
------------------------------------------------------------------------
-The UDP transport is implemented with Boost's ASIO library.
-ASIO provides an asynchronous API for user-space sockets.
-The transport implementation allocates a number of buffers
-and submits asynchronous requests for send and receive.
-IO service threads run in the background to process these requests.
+The UDP transport is implemented with standard user-space/Berkeley sockets.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Transport parameters
@@ -35,8 +31,12 @@ The following parameters can be used to alter the transport's default behavior:
* **send_frame_size:** The size of a single send buffer in bytes
* **num_send_frames:** The number of send buffers to allocate
-**Note:** num_recv_frames and num_send_frames will not have an effect
-as the asynchronous send implementation is currently unimplemented.
+**Note1:** num_recv_frames and num_send_frames do not affect performance.
+
+**Note2:** recv_frame_size and send_frame_size can be used to
+increase or decrease the maximum number of samples per packet.
+The frame sizes default to an MTU of 1472 bytes per IP/UDP packet,
+and may be increased if permitted by your network hardware.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Flow control parameters
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
index 912fbc204..1a04680e9 100644
--- a/host/include/uhd/config.hpp
+++ b/host/include/uhd/config.hpp
@@ -27,7 +27,7 @@
//# pragma warning(disable: 4512) // assignment operator can't not be generated
//# pragma warning(disable: 4100) // unreferenced formal parameter
//# pragma warning(disable: 4996) // <symbol> was declared deprecated
-//# pragma warning(disable: 4355) // 'this' : used in base member initializer list
+# pragma warning(disable: 4355) // 'this' : used in base member initializer list
//# pragma warning(disable: 4706) // assignment within conditional expression
# pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B'
//# pragma warning(disable: 4127) // conditional expression is constant
diff --git a/host/include/uhd/transport/if_addrs.hpp b/host/include/uhd/transport/if_addrs.hpp
index c831750d7..689aff42c 100644
--- a/host/include/uhd/transport/if_addrs.hpp
+++ b/host/include/uhd/transport/if_addrs.hpp
@@ -31,7 +31,6 @@ namespace uhd{ namespace transport{
std::string inet;
std::string mask;
std::string bcast;
- if_addrs_t(void);
};
/*!
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
index d5a536b27..092028d09 100644
--- a/host/include/uhd/transport/zero_copy.hpp
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -21,7 +21,6 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include <boost/function.hpp>
namespace uhd{ namespace transport{
@@ -30,23 +29,9 @@ namespace uhd{ namespace transport{
* Contains a reference to transport-managed memory,
* and a method to release the memory after reading.
*/
- class UHD_API managed_recv_buffer : boost::noncopyable{
+ class UHD_API managed_recv_buffer{
public:
typedef boost::shared_ptr<managed_recv_buffer> sptr;
- typedef boost::function<void(void)> release_fcn_t;
-
- /*!
- * Make a safe managed receive buffer:
- * A safe managed buffer ensures that release is called once,
- * either by the user or automatically upon deconstruction.
- * \param buff a pointer into read-only memory
- * \param size the length of the buffer in bytes
- * \param release_fcn callback to release the memory
- * \return a new managed receive buffer
- */
- static sptr make_safe(
- const void *buff, size_t size, const release_fcn_t &release_fcn
- );
/*!
* Signal to the transport that we are done with the buffer.
@@ -81,24 +66,9 @@ namespace uhd{ namespace transport{
* Contains a reference to transport-managed memory,
* and a method to commit the memory after writing.
*/
- class UHD_API managed_send_buffer : boost::noncopyable{
+ class UHD_API managed_send_buffer{
public:
typedef boost::shared_ptr<managed_send_buffer> sptr;
- typedef boost::function<void(size_t)> commit_fcn_t;
-
- /*!
- * Make a safe managed send buffer:
- * A safe managed buffer ensures that commit is called once,
- * either by the user or automatically upon deconstruction.
- * In the later case, the deconstructor will call commit(0).
- * \param buff a pointer into writable memory
- * \param size the length of the buffer in bytes
- * \param commit_fcn callback to commit the memory
- * \return a new managed send buffer
- */
- static sptr make_safe(
- void *buff, size_t size, const commit_fcn_t &commit_fcn
- );
/*!
* Signal to the transport that we are done with the buffer.
diff --git a/host/include/uhd/types/ref_vector.hpp b/host/include/uhd/types/ref_vector.hpp
index 2928cb150..bbfb5434d 100644
--- a/host/include/uhd/types/ref_vector.hpp
+++ b/host/include/uhd/types/ref_vector.hpp
@@ -27,7 +27,7 @@ namespace uhd{
* - Provides a std::vector-like interface for an array.
* - Statically sized, and does not manage the memory.
*/
-template <typename T> class ref_vector{
+template <typename T> class UHD_API ref_vector{
public:
/*!
* Create a reference vector of size 1 from a pointer.
diff --git a/host/include/uhd/usrp/dboard_eeprom.hpp b/host/include/uhd/usrp/dboard_eeprom.hpp
index 108027b46..394d71dd6 100644
--- a/host/include/uhd/usrp/dboard_eeprom.hpp
+++ b/host/include/uhd/usrp/dboard_eeprom.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -26,33 +26,32 @@
namespace uhd{ namespace usrp{
struct UHD_API dboard_eeprom_t{
- /*!
- * The dboard id that was read from eeprom or will be set to eeprom.
- */
+
+ //! The ID for the daughterboard type
dboard_id_t id;
+ //! The unique serial number
+ std::string serial;
+
/*!
- * Create a dboard eeprom struct from the bytes read out of eeprom.
- * The constructor will parse out the dboard id from a vector of bytes.
- * To be valid, the bytes vector should be at least num_bytes() long.
- * If the parsing fails due to bad checksum or incomplete length,
- * the dboard id in this struct will be set to dboard_id::NONE.
- * \param bytes the vector of bytes
+ * Create an empty dboard eeprom struct.
*/
- dboard_eeprom_t(const uhd::byte_vector_t &bytes = uhd::byte_vector_t(0));
+ dboard_eeprom_t(void);
/*!
- * Get the bytes that would be written to dboard eeprom.
- * \return a vector of bytes
+ * Load the object with bytes from the eeprom.
+ * \param iface the serial interface with i2c
+ * \param addr the i2c address for the eeprom
*/
- uhd::byte_vector_t get_eeprom_bytes(void);
+ void load(i2c_iface &iface, boost::uint8_t addr);
/*!
- * Get the number of bytes in the dboard eeprom segment.
- * Use this value when reading out of the dboard eeprom.
- * \return the number of bytes used by dboard eeprom
+ * Store the object to bytes in the eeprom.
+ * \param iface the serial interface with i2c
+ * \param addr the i2c address for the eeprom
*/
- static size_t num_bytes(void);
+ void store(i2c_iface &iface, boost::uint8_t addr);
+
};
}} //namespace
diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp
index 5e2230371..d3a07db96 100644
--- a/host/include/uhd/utils/algorithm.hpp
+++ b/host/include/uhd/utils/algorithm.hpp
@@ -30,20 +30,6 @@
namespace std{
/*!
- * A wrapper around std::copy that takes ranges instead of iterators.
- *
- * Copy the elements of the source range into the destination range.
- * The destination range should be at least as large as the source range.
- *
- * \param src the range of elements to copy from
- * \param dst the range of elements to be filled
- */
- template<typename RangeSrc, typename RangeDst> inline
- void copy(const RangeSrc &src, RangeDst &dst){
- std::copy(boost::begin(src), boost::end(src), boost::begin(dst));
- }
-
- /*!
* A wrapper around std::sort that takes a range instead of an iterator.
*
* The elements are sorted into ascending order using the less-than operator.
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index d2845ffda..c8a5dd51e 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -108,6 +108,9 @@ ADD_LIBRARY(uhd SHARED ${libuhd_sources})
TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${libuhd_libs})
SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS")
SET_TARGET_PROPERTIES(uhd PROPERTIES SOVERSION ${UHD_VERSION_MAJOR})
+IF(DEFINED LIBUHD_OUTPUT_NAME)
+ SET_TARGET_PROPERTIES(uhd PROPERTIES OUTPUT_NAME ${LIBUHD_OUTPUT_NAME})
+ENDIF(DEFINED LIBUHD_OUTPUT_NAME)
INSTALL(TARGETS uhd
LIBRARY DESTINATION ${LIBRARY_DIR} # .so file
diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt
index a9f977cdc..abc9c2707 100644
--- a/host/lib/convert/CMakeLists.txt
+++ b/host/lib/convert/CMakeLists.txt
@@ -22,15 +22,31 @@ INCLUDE(CheckIncludeFileCXX)
MESSAGE(STATUS "")
########################################################################
-# Check for SIMD headers
+# Check for SSE2 SIMD headers
########################################################################
+IF(CMAKE_COMPILER_IS_GNUCXX)
+ SET(EMMINTRIN_FLAGS -msse2)
+ELSEIF(MSVC)
+ SET(EMMINTRIN_FLAGS /arch:SSE2)
+ENDIF()
+
+SET(CMAKE_REQUIRED_FLAGS ${EMMINTRIN_FLAGS})
CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H)
+UNSET(CMAKE_REQUIRED_FLAGS)
+
IF(HAVE_EMMINTRIN_H)
+ SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_with_sse2.cpp
+ PROPERTIES COMPILE_FLAGS ${EMMINTRIN_FLAGS}
+ )
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/convert_with_sse2.cpp
)
ENDIF(HAVE_EMMINTRIN_H)
+########################################################################
+# Check for NEON SIMD headers
+########################################################################
CHECK_INCLUDE_FILE_CXX(arm_neon.h HAVE_ARM_NEON_H)
IF(HAVE_ARM_NEON_H)
LIBUHD_APPEND_SOURCES(
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 8765c6703..a5bf9c5f1 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -48,20 +48,36 @@ ENDIF(ENABLE_USB)
########################################################################
MESSAGE(STATUS "")
MESSAGE(STATUS "Configuring interface address discovery...")
-
+INCLUDE(CheckCXXSourceCompiles)
INCLUDE(CheckIncludeFileCXX)
-CHECK_INCLUDE_FILE_CXX(ifaddrs.h HAVE_IFADDRS_H)
+
+CHECK_CXX_SOURCE_COMPILES("
+ #include <ifaddrs.h>
+ int main(){
+ struct ifaddrs *ifap;
+ getifaddrs(&ifap);
+ return 0;
+ }
+ " HAVE_GETIFADDRS
+)
+
CHECK_INCLUDE_FILE_CXX(winsock2.h HAVE_WINSOCK2_H)
-IF(HAVE_IFADDRS_H)
+IF(HAVE_GETIFADDRS)
MESSAGE(STATUS " Interface address discovery supported through getifaddrs.")
- ADD_DEFINITIONS(-DHAVE_IFADDRS_H)
+ SET(IF_ADDRS_DEFS HAVE_GETIFADDRS)
ELSEIF(HAVE_WINSOCK2_H)
MESSAGE(STATUS " Interface address discovery supported through SIO_GET_INTERFACE_LIST.")
- ADD_DEFINITIONS(-DHAVE_WINSOCK2_H)
-ELSE(HAVE_IFADDRS_H)
+ SET(IF_ADDRS_DEFS HAVE_SIO_GET_INTERFACE_LIST)
+ELSE()
MESSAGE(STATUS " Interface address discovery not supported.")
-ENDIF(HAVE_IFADDRS_H)
+ SET(IF_ADDRS_DEFS HAVE_IF_ADDRS_DUMMY)
+ENDIF()
+
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${IF_ADDRS_DEFS}"
+)
########################################################################
# Append to the list of sources for lib uhd
@@ -75,7 +91,6 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cpp
${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy_asio.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vrt_packet_handler.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/zero_copy.cpp
)
diff --git a/host/lib/transport/if_addrs.cpp b/host/lib/transport/if_addrs.cpp
index 17cf8455b..b7c8ad844 100644
--- a/host/lib/transport/if_addrs.cpp
+++ b/host/lib/transport/if_addrs.cpp
@@ -20,14 +20,10 @@
#include <boost/cstdint.hpp>
#include <iostream>
-uhd::transport::if_addrs_t::if_addrs_t(void){
- /* NOP */
-}
-
/***********************************************************************
* Interface address discovery through ifaddrs api
**********************************************************************/
-#if defined(HAVE_IFADDRS_H)
+#ifdef HAVE_GETIFADDRS
#include <ifaddrs.h>
static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr *addr){
@@ -59,10 +55,12 @@ std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
return if_addrs;
}
+#endif /* HAVE_GETIFADDRS */
+
/***********************************************************************
* Interface address discovery through windows api
**********************************************************************/
-#elif defined(HAVE_WINSOCK2_H)
+#ifdef HAVE_SIO_GET_INTERFACE_LIST
#include <winsock2.h>
std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
@@ -98,13 +96,15 @@ std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
return if_addrs;
}
+#endif /* HAVE_SIO_GET_INTERFACE_LIST */
+
/***********************************************************************
* Interface address discovery not included
**********************************************************************/
-#else /* HAVE_IFADDRS_H */
+#ifdef HAVE_IF_ADDRS_DUMMY
std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
return std::vector<if_addrs_t>();
}
-#endif /* HAVE_IFADDRS_H */
+#endif /* HAVE_IF_ADDRS_DUMMY */
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 6fab5ae6f..87adece45 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -21,258 +21,88 @@
#include <uhd/transport/buffer_pool.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/assert.hpp>
+#include <boost/function.hpp>
#include <boost/foreach.hpp>
-#include <boost/thread.hpp>
-#include <vector>
+#include <boost/thread/thread.hpp>
+#include <list>
#include <iostream>
using namespace uhd;
using namespace uhd::transport;
-static const double CLEANUP_TIMEOUT = 0.2; //seconds
static const size_t DEFAULT_NUM_XFERS = 16; //num xfers
static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes
/***********************************************************************
- * Helper functions
- ***********************************************************************/
-/*
- * Print the values of a libusb_transfer struct
- * http://libusb.sourceforge.net/api-1.0/structlibusb__transfer.html
- */
-void pp_transfer(libusb_transfer *lut)
-{
- std::cout << "Libusb transfer" << std::endl;
- std::cout << " flags: 0x" << std::hex << (unsigned int) lut->flags << std::endl;
- std::cout << " endpoint: 0x" << std::hex << (unsigned int) lut->endpoint << std::endl;
- std::cout << " type: 0x" << std::hex << (unsigned int) lut->type << std::endl;
- std::cout << " timeout: " << std::dec << lut->timeout << std::endl;
- std::cout << " status: 0x" << std::hex << lut->status << std::endl;
- std::cout << " length: " << std::dec << lut->length << std::endl;
- std::cout << " actual_length: " << std::dec << lut->actual_length << std::endl;
-}
-
-/***********************************************************************
- * USB asynchronous zero_copy endpoint
- * This endpoint implementation provides asynchronous I/O to libusb-1.0
- * devices. Each endpoint is directional and two can be combined to
- * create a bidirectional interface. It is a zero copy implementation
- * with respect to libusb, however, each send and recv requires a copy
- * operation from kernel to userspace; this is due to the usbfs
- * interface provided by the kernel.
+ * Reusable managed receiver buffer:
+ * - Associated with a particular libusb transfer struct.
+ * - Submits the transfer to libusb in the release method.
**********************************************************************/
-class usb_endpoint {
+class libusb_zero_copy_mrb : public managed_recv_buffer{
public:
- typedef boost::shared_ptr<usb_endpoint> sptr;
-
- usb_endpoint(
- libusb::device_handle::sptr handle,
- int endpoint,
- bool input,
- size_t transfer_size,
- size_t num_transfers
- );
-
- ~usb_endpoint(void);
+ libusb_zero_copy_mrb(libusb_transfer *lut):
+ _lut(lut), _expired(true) { /* NOP */ }
- // Exposed interface for submitting / retrieving transfer buffers
-
- //! Submit a new transfer that was presumably just filled or emptied.
- void submit(libusb_transfer *lut);
-
- /*!
- * Get an available transfer:
- * For inputs, this is a just filled transfer.
- * For outputs, this is a just emptied transfer.
- * \param timeout the timeout to wait for a lut
- * \return the transfer pointer or NULL if timeout
- */
- libusb_transfer *get_lut_with_wait(double timeout);
+ void release(void){
+ if (_expired) return;
+ UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
+ _expired = true;
+ }
- //Callback use only
- void callback_handle_transfer(libusb_transfer *lut);
+ sptr get_new(void){
+ _expired = false;
+ return sptr(this, &libusb_zero_copy_mrb::fake_deleter);
+ }
private:
- libusb::device_handle::sptr _handle;
- int _endpoint;
- bool _input;
-
- //! hold a bounded buffer of completed transfers
- bounded_buffer<libusb_transfer *> _completed_list;
-
- //! a list of all transfer structs we allocated
- std::vector<libusb_transfer *> _all_luts;
+ static void fake_deleter(void *obj){
+ static_cast<libusb_zero_copy_mrb *>(obj)->release();
+ }
- //! memory allocated for the transfer buffers
- buffer_pool::sptr _buffer_pool;
+ const void *get_buff(void) const{return _lut->buffer;}
+ size_t get_size(void) const{return _lut->actual_length;}
- // Calls for processing asynchronous I/O
- libusb_transfer *allocate_transfer(void *mem, size_t len);
- void print_transfer_status(libusb_transfer *lut);
+ libusb_transfer *_lut;
+ bool _expired;
};
-
-/*
- * Callback function called when submitted transfers complete.
- * The endpoint upon which the transfer is part of is recovered
- * and the transfer moved from pending to completed state.
- * Callbacks occur during the reaping calls where libusb_handle_events()
- * is used. The callback only modifies the transfer state by moving
- * it from the pending to completed status list.
- * \param lut pointer to libusb_transfer
- */
-static void callback(libusb_transfer *lut){
- usb_endpoint *endpoint = (usb_endpoint *) lut->user_data;
- endpoint->callback_handle_transfer(lut);
-}
-
-
-/*
- * Accessor call to allow list access from callback space
- * \param pointer to libusb_transfer
- */
-void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){
- _completed_list.push_with_haste(lut);
-}
-
-
-/*
- * Constructor
- * Allocate libusb transfers and mark as free. For IN endpoints,
- * submit the transfers so that they're ready to return when
- * data is available.
- */
-usb_endpoint::usb_endpoint(
- libusb::device_handle::sptr handle,
- int endpoint,
- bool input,
- size_t transfer_size,
- size_t num_transfers
-):
- _handle(handle),
- _endpoint(endpoint),
- _input(input),
- _completed_list(num_transfers)
-{
- _buffer_pool = buffer_pool::make(num_transfers, transfer_size);
- for (size_t i = 0; i < num_transfers; i++){
- _all_luts.push_back(allocate_transfer(_buffer_pool->at(i), transfer_size));
-
- //input luts are immediately submitted to be filled
- //output luts go into the completed list as free buffers
- if (_input) this->submit(_all_luts.back());
- else _completed_list.push_with_haste(_all_luts.back());
+/***********************************************************************
+ * Reusable managed send buffer:
+ * - Associated with a particular libusb transfer struct.
+ * - Submits the transfer to libusb in the commit method.
+ **********************************************************************/
+class libusb_zero_copy_msb : public managed_send_buffer{
+public:
+ libusb_zero_copy_msb(libusb_transfer *lut):
+ _lut(lut), _expired(true) { /* NOP */ }
+
+ void commit(size_t len){
+ if (_expired) return;
+ _lut->length = len;
+ UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
+ _expired = true;
}
-}
-
-/*
- * Destructor
- * Make sure all the memory is freed. Cancel any pending transfers.
- * When all completed transfers are moved to the free list, release
- * the transfers. Libusb will deallocate the data buffer held by
- * each transfer.
- */
-usb_endpoint::~usb_endpoint(void){
- //cancel all transfers
- BOOST_FOREACH(libusb_transfer *lut, _all_luts){
- libusb_cancel_transfer(lut);
+ sptr get_new(void){
+ _expired = false;
+ return sptr(this, &libusb_zero_copy_msb::fake_deleter);
}
- //collect canceled transfers (drain the queue)
- while (this->get_lut_with_wait(CLEANUP_TIMEOUT) != NULL){};
-
- //free all transfers
- BOOST_FOREACH(libusb_transfer *lut, _all_luts){
- libusb_free_transfer(lut);
+private:
+ static void fake_deleter(void *obj){
+ static_cast<libusb_zero_copy_msb *>(obj)->commit(0);
}
-}
-
-
-/*
- * Allocate a libusb transfer
- * The allocated transfer - and buffer it contains - is repeatedly
- * submitted, reaped, and reused and should not be freed until shutdown.
- * \param mem a pointer to the buffer memory
- * \param len size of the individual buffer
- * \return pointer to an allocated libusb_transfer
- */
-libusb_transfer *usb_endpoint::allocate_transfer(void *mem, size_t len){
- libusb_transfer *lut = libusb_alloc_transfer(0);
- UHD_ASSERT_THROW(lut != NULL);
-
- unsigned int endpoint = ((_endpoint & 0x7f) | (_input ? 0x80 : 0));
- unsigned char *buff = reinterpret_cast<unsigned char *>(mem);
- libusb_transfer_cb_fn lut_callback = libusb_transfer_cb_fn(&callback);
-
- libusb_fill_bulk_transfer(lut, // transfer
- _handle->get(), // dev_handle
- endpoint, // endpoint
- buff, // buffer
- len, // length
- lut_callback, // callback
- this, // user_data
- 0); // timeout
- return lut;
-}
+ void *get_buff(void) const{return _lut->buffer;}
+ size_t get_size(void) const{return _lut->length;}
-/*
- * Asynchonous transfer submission
- * Submit a libusb transfer to libusb add pending status
- * \param lut pointer to libusb_transfer
- * \return true on success or false on error
- */
-void usb_endpoint::submit(libusb_transfer *lut){
- UHD_ASSERT_THROW(libusb_submit_transfer(lut) == 0);
-}
-
-/*
- * Print status errors of a completed transfer
- * \param lut pointer to an libusb_transfer
- */
-void usb_endpoint::print_transfer_status(libusb_transfer *lut){
- std::cout << "here " << lut->status << std::endl;
- switch (lut->status) {
- case LIBUSB_TRANSFER_COMPLETED:
- if (lut->actual_length < lut->length) {
- std::cerr << "USB: transfer completed with short write,"
- << " length = " << lut->length
- << " actual = " << lut->actual_length << std::endl;
- }
-
- if ((lut->actual_length < 0) || (lut->length < 0)) {
- std::cerr << "USB: transfer completed with invalid response"
- << std::endl;
- }
- break;
- case LIBUSB_TRANSFER_CANCELLED:
- break;
- case LIBUSB_TRANSFER_NO_DEVICE:
- std::cerr << "USB: device was disconnected" << std::endl;
- break;
- case LIBUSB_TRANSFER_OVERFLOW:
- std::cerr << "USB: device sent more data than requested" << std::endl;
- break;
- case LIBUSB_TRANSFER_TIMED_OUT:
- std::cerr << "USB: transfer timed out" << std::endl;
- break;
- case LIBUSB_TRANSFER_STALL:
- std::cerr << "USB: halt condition detected (stalled)" << std::endl;
- break;
- case LIBUSB_TRANSFER_ERROR:
- std::cerr << "USB: transfer failed" << std::endl;
- break;
- default:
- std::cerr << "USB: received unknown transfer status" << std::endl;
- }
-}
+ libusb_transfer *_lut;
+ bool _expired;
+};
-libusb_transfer *usb_endpoint::get_lut_with_wait(double timeout){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- libusb_transfer *lut = NULL;
- if (_completed_list.pop_with_timed_wait(lut, timeout)) return lut;
- return NULL;
+//! helper function: handles all async callbacks
+static void libusb_async_cb(libusb_transfer *lut){
+ (*static_cast<boost::function<void()> *>(lut->user_data))();
}
/***********************************************************************
@@ -286,16 +116,107 @@ public:
size_t recv_endpoint,
size_t send_endpoint,
const device_addr_t &hints
- );
+ ):
+ _handle(handle),
+ _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", DEFAULT_XFER_SIZE))),
+ _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_XFERS))),
+ _send_frame_size(size_t(hints.cast<double>("send_frame_size", DEFAULT_XFER_SIZE))),
+ _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_XFERS))),
+ _recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)),
+ _send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)),
+ _pending_recv_buffs(_num_recv_frames),
+ _pending_send_buffs(_num_send_frames)
+ {
+ _handle->claim_interface(2 /*in interface*/);
+ _handle->claim_interface(1 /*out interface*/);
+
+ //allocate libusb transfer structs and managed receive buffers
+ for (size_t i = 0; i < get_num_recv_frames(); i++){
+
+ libusb_transfer *lut = libusb_alloc_transfer(0);
+ UHD_ASSERT_THROW(lut != NULL);
+
+ _mrb_pool.push_back(libusb_zero_copy_mrb(lut));
+ _callbacks.push_back(boost::bind(
+ &libusb_zero_copy_impl::handle_recv, this, &_mrb_pool.back()
+ ));
+
+ libusb_fill_bulk_transfer(
+ lut, // transfer
+ _handle->get(), // dev_handle
+ (recv_endpoint & 0x7f) | 0x80, // endpoint
+ static_cast<unsigned char *>(_recv_buffer_pool->at(i)), // buffer
+ this->get_recv_frame_size(), // length
+ libusb_transfer_cb_fn(&libusb_async_cb), // callback
+ static_cast<void *>(&_callbacks.back()), // user_data
+ 0 // timeout
+ );
+
+ _all_luts.push_back(lut);
+ _mrb_pool.back().get_new();
+ }
+
+ //allocate libusb transfer structs and managed send buffers
+ for (size_t i = 0; i < get_num_send_frames(); i++){
+
+ libusb_transfer *lut = libusb_alloc_transfer(0);
+ UHD_ASSERT_THROW(lut != NULL);
+
+ _msb_pool.push_back(libusb_zero_copy_msb(lut));
+ _callbacks.push_back(boost::bind(
+ &libusb_zero_copy_impl::handle_send, this, &_msb_pool.back()
+ ));
+
+ libusb_fill_bulk_transfer(
+ lut, // transfer
+ _handle->get(), // dev_handle
+ (send_endpoint & 0x7f) | 0x00, // endpoint
+ static_cast<unsigned char *>(_send_buffer_pool->at(i)), // buffer
+ this->get_send_frame_size(), // length
+ libusb_transfer_cb_fn(&libusb_async_cb), // callback
+ static_cast<void *>(&_callbacks.back()), // user_data
+ 0 // timeout
+ );
+
+ _all_luts.push_back(lut);
+ libusb_async_cb(lut);
+ }
+
+ //spawn the event handler threads
+ size_t concurrency = hints.cast<size_t>("concurrency_hint", 1);
+ for (size_t i = 0; i < concurrency; i++) _thread_group.create_thread(
+ boost::bind(&libusb_zero_copy_impl::run_event_loop, this)
+ );
+ }
~libusb_zero_copy_impl(void){
+ //shutdown the threads
_threads_running = false;
_thread_group.interrupt_all();
_thread_group.join_all();
+
+ //cancel and free all transfers
+ BOOST_FOREACH(libusb_transfer *lut, _all_luts){
+ libusb_cancel_transfer(lut);
+ libusb_free_transfer(lut);
+ }
}
- managed_recv_buffer::sptr get_recv_buff(double);
- managed_send_buffer::sptr get_send_buff(double);
+ managed_recv_buffer::sptr get_recv_buff(double timeout){
+ libusb_zero_copy_mrb *mrb = NULL;
+ if (_pending_recv_buffs.pop_with_timed_wait(mrb, timeout)){
+ return mrb->get_new();
+ }
+ return managed_recv_buffer::sptr();
+ }
+
+ managed_send_buffer::sptr get_send_buff(double timeout){
+ libusb_zero_copy_msb *msb = NULL;
+ if (_pending_send_buffs.pop_with_timed_wait(msb, timeout)){
+ return msb->get_new();
+ }
+ return managed_send_buffer::sptr();
+ }
size_t get_num_recv_frames(void) const { return _num_recv_frames; }
size_t get_num_send_frames(void) const { return _num_send_frames; }
@@ -304,125 +225,50 @@ public:
size_t get_send_frame_size(void) const { return _send_frame_size; }
private:
- void release(libusb_transfer *lut){
- _recv_ep->submit(lut);
+ //! Handle a bound async callback for recv
+ void handle_recv(libusb_zero_copy_mrb *mrb){
+ _pending_recv_buffs.push_with_haste(mrb);
}
- void commit(libusb_transfer *lut, size_t num_bytes){
- lut->length = num_bytes;
- try{
- _send_ep->submit(lut);
- }
- catch(const std::exception &e){
- std::cerr << "Error in commit: " << e.what() << std::endl;
- }
+ //! Handle a bound async callback for send
+ void handle_send(libusb_zero_copy_msb *msb){
+ _pending_send_buffs.push_with_haste(msb);
}
libusb::device_handle::sptr _handle;
const size_t _recv_frame_size, _num_recv_frames;
const size_t _send_frame_size, _num_send_frames;
- usb_endpoint::sptr _recv_ep, _send_ep;
- //event handler threads
+ //! Storage for transfer related objects
+ buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool;
+ bounded_buffer<libusb_zero_copy_mrb *> _pending_recv_buffs;
+ bounded_buffer<libusb_zero_copy_msb *> _pending_send_buffs;
+ std::list<libusb_zero_copy_mrb> _mrb_pool;
+ std::list<libusb_zero_copy_msb> _msb_pool;
+ std::list<boost::function<void()> > _callbacks;
+
+ //! a list of all transfer structs we allocated
+ std::list<libusb_transfer *> _all_luts;
+
+ //! event handler threads
boost::thread_group _thread_group;
bool _threads_running;
void run_event_loop(void){
set_thread_priority_safe();
- libusb::session::sptr session = libusb::session::get_global_session();
+ libusb_context *context = libusb::session::get_global_session()->get_context();
_threads_running = true;
try{
while(_threads_running){
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000; //100ms
- libusb_handle_events_timeout(session->get_context(), &tv);
+ libusb_handle_events_timeout(context, &tv);
}
} catch(const boost::thread_interrupted &){}
}
-};
-
-/*
- * Constructor
- * Initializes libusb, opens devices, and sets up interfaces for I/O.
- * Finally, creates endpoints for asynchronous I/O.
- */
-libusb_zero_copy_impl::libusb_zero_copy_impl(
- libusb::device_handle::sptr handle,
- size_t recv_endpoint,
- size_t send_endpoint,
- const device_addr_t &hints
-):
- _handle(handle),
- _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", DEFAULT_XFER_SIZE))),
- _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_XFERS))),
- _send_frame_size(size_t(hints.cast<double>("send_frame_size", DEFAULT_XFER_SIZE))),
- _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_XFERS)))
-{
- _handle->claim_interface(2 /*in interface*/);
- _handle->claim_interface(1 /*out interface*/);
-
- _recv_ep = usb_endpoint::sptr(new usb_endpoint(
- _handle, // libusb device_handle
- recv_endpoint, // USB endpoint number
- true, // IN endpoint
- this->get_recv_frame_size(), // buffer size per transfer
- this->get_num_recv_frames() // number of libusb transfers
- ));
-
- _send_ep = usb_endpoint::sptr(new usb_endpoint(
- _handle, // libusb device_handle
- send_endpoint, // USB endpoint number
- false, // OUT endpoint
- this->get_send_frame_size(), // buffer size per transfer
- this->get_num_send_frames() // number of libusb transfers
- ));
-
- //spawn the event handler threads
- size_t concurrency = hints.cast<size_t>("concurrency_hint", 1);
- for (size_t i = 0; i < concurrency; i++) _thread_group.create_thread(
- boost::bind(&libusb_zero_copy_impl::run_event_loop, this)
- );
-}
-
-/*
- * Construct a managed receive buffer from a completed libusb transfer
- * (happy with buffer full of data) obtained from the receive endpoint.
- * Return empty pointer if no transfer is available (timeout or error).
- * \return pointer to a managed receive buffer
- */
-managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(double timeout){
- libusb_transfer *lut = _recv_ep->get_lut_with_wait(timeout);
- if (lut == NULL) {
- return managed_recv_buffer::sptr();
- }
- else {
- return managed_recv_buffer::make_safe(
- lut->buffer, lut->actual_length,
- boost::bind(&libusb_zero_copy_impl::release, this, lut)
- );
- }
-}
-
-/*
- * Construct a managed send buffer from a free libusb transfer (with
- * empty buffer). Return empty pointer of no transfer is available
- * (timeout or error).
- * \return pointer to a managed send buffer
- */
-managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){
- libusb_transfer *lut = _send_ep->get_lut_with_wait(timeout);
- if (lut == NULL) {
- return managed_send_buffer::sptr();
- }
- else {
- return managed_send_buffer::make_safe(
- lut->buffer, this->get_send_frame_size(),
- boost::bind(&libusb_zero_copy_impl::commit, this, lut, _1)
- );
- }
-}
+};
/***********************************************************************
* USB zero_copy make functions
diff --git a/host/lib/transport/udp_common.hpp b/host/lib/transport/udp_common.hpp
new file mode 100644
index 000000000..47775d9c4
--- /dev/null
+++ b/host/lib/transport/udp_common.hpp
@@ -0,0 +1,53 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP
+
+#include <uhd/config.hpp>
+#include <boost/asio.hpp>
+
+namespace uhd{ namespace transport{
+
+ typedef boost::shared_ptr<boost::asio::ip::udp::socket> socket_sptr;
+
+ /*!
+ * Wait for the socket to become ready for a receive operation.
+ * \param sock_fd the open socket file descriptor
+ * \param timeout the timeout duration in seconds
+ * \return true when the socket is ready for receive
+ */
+ UHD_INLINE bool wait_for_recv_ready(int sock_fd, double timeout){
+ //setup timeval for timeout
+ timeval tv;
+ //If the tv_usec > 1 second on some platforms, select will
+ //error EINVAL: An invalid timeout interval was specified.
+ tv.tv_sec = int(timeout);
+ tv.tv_usec = int(timeout*1000000)%1000000;
+
+ //setup rset for timeout
+ fd_set rset;
+ FD_ZERO(&rset);
+ FD_SET(sock_fd, &rset);
+
+ //call select with timeout on receive socket
+ return ::select(sock_fd+1, &rset, NULL, NULL, &tv) > 0;
+ }
+
+}} //namespace uhd::transport
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */
diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp
index 6799ac7b2..1ee036d52 100644
--- a/host/lib/transport/udp_simple.cpp
+++ b/host/lib/transport/udp_simple.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -15,159 +15,69 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "udp_common.hpp"
#include <uhd/transport/udp_simple.hpp>
-#include <boost/asio.hpp>
-#include <boost/thread.hpp>
#include <boost/format.hpp>
#include <iostream>
using namespace uhd::transport;
+namespace asio = boost::asio;
/***********************************************************************
- * Helper Functions
+ * UDP simple implementation: connected and broadcast
**********************************************************************/
-/*!
- * Wait for available data or timeout.
- * \param socket the asio socket
- * \param timeout the timeout in seconds
- * \return false for timeout, true for data
- */
-static bool wait_available(
- boost::asio::ip::udp::socket &socket, double timeout
-){
- #if defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)
-
- //setup timeval for timeout
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = long(timeout*1e6);
-
- //setup rset for timeout
- fd_set rset;
- FD_ZERO(&rset);
- FD_SET(socket.native(), &rset);
-
- return ::select(socket.native()+1, &rset, NULL, NULL, &tv) > 0;
-
- #else /*defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)*/
-
- //FIXME: why does select fail on macintosh?
- for (size_t i = 0; i < size_t(timeout*1e3); i++){
- if (socket.available()) return true;
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
- }
- return false;
-
- #endif /*defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)*/
-}
-
-/***********************************************************************
- * UDP connected implementation class
- **********************************************************************/
-class udp_connected_impl : public udp_simple{
+class udp_simple_impl : public udp_simple{
public:
- //structors
- udp_connected_impl(const std::string &addr, const std::string &port);
- ~udp_connected_impl(void);
-
- //send/recv
- size_t send(const boost::asio::const_buffer &);
- size_t recv(const boost::asio::mutable_buffer &, double);
-
-private:
- boost::asio::ip::udp::socket *_socket;
- boost::asio::io_service _io_service;
-};
+ udp_simple_impl(
+ const std::string &addr, const std::string &port, bool bcast, bool connect
+ ):_connected(connect){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
-udp_connected_impl::udp_connected_impl(const std::string &addr, const std::string &port){
- //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+ //resolve the address
+ asio::ip::udp::resolver resolver(_io_service);
+ asio::ip::udp::resolver::query query(asio::ip::udp::v4(), addr, port);
+ _receiver_endpoint = *resolver.resolve(query);
- // resolve the address
- boost::asio::ip::udp::resolver resolver(_io_service);
- boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
- boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
+ //create and open the socket
+ _socket = socket_sptr(new asio::ip::udp::socket(_io_service));
+ _socket->open(asio::ip::udp::v4());
- // Create, open, and connect the socket
- _socket = new boost::asio::ip::udp::socket(_io_service);
- _socket->open(boost::asio::ip::udp::v4());
- _socket->connect(receiver_endpoint);
-}
+ //allow broadcasting
+ _socket->set_option(asio::socket_base::broadcast(bcast));
-udp_connected_impl::~udp_connected_impl(void){
- delete _socket;
-}
-
-size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){
- return _socket->send(boost::asio::buffer(buff));
-}
+ //connect the socket
+ if (connect) _socket->connect(_receiver_endpoint);
-size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff, double timeout){
- if (not wait_available(*_socket, timeout)) return 0;
- return _socket->receive(boost::asio::buffer(buff));
-}
+ }
-/***********************************************************************
- * UDP broadcast implementation class
- **********************************************************************/
-class udp_broadcast_impl : public udp_simple{
-public:
- //structors
- udp_broadcast_impl(const std::string &addr, const std::string &port);
- ~udp_broadcast_impl(void);
+ size_t send(const asio::const_buffer &buff){
+ if (_connected) return _socket->send(asio::buffer(buff));
+ return _socket->send_to(asio::buffer(buff), _receiver_endpoint);
+ }
- //send/recv
- size_t send(const boost::asio::const_buffer &);
- size_t recv(const boost::asio::mutable_buffer &, double);
+ size_t recv(const asio::mutable_buffer &buff, double timeout){
+ if (not wait_for_recv_ready(_socket->native(), timeout)) return 0;
+ return _socket->receive(asio::buffer(buff));
+ }
private:
- boost::asio::ip::udp::socket *_socket;
- boost::asio::ip::udp::endpoint _receiver_endpoint;
- boost::asio::io_service _io_service;
+ bool _connected;
+ asio::io_service _io_service;
+ socket_sptr _socket;
+ asio::ip::udp::endpoint _receiver_endpoint;
};
-udp_broadcast_impl::udp_broadcast_impl(const std::string &addr, const std::string &port){
- //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
-
- // resolve the address
- boost::asio::ip::udp::resolver resolver(_io_service);
- boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
- _receiver_endpoint = *resolver.resolve(query);
-
- // Create and open the socket
- _socket = new boost::asio::ip::udp::socket(_io_service);
- _socket->open(boost::asio::ip::udp::v4());
-
- // Allow broadcasting
- boost::asio::socket_base::broadcast option(true);
- _socket->set_option(option);
-
-}
-
-udp_broadcast_impl::~udp_broadcast_impl(void){
- delete _socket;
-}
-
-size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){
- return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint);
-}
-
-size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff, double timeout){
- if (not wait_available(*_socket, timeout)) return 0;
- boost::asio::ip::udp::endpoint sender_endpoint;
- return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint);
-}
-
/***********************************************************************
* UDP public make functions
**********************************************************************/
udp_simple::sptr udp_simple::make_connected(
const std::string &addr, const std::string &port
){
- return sptr(new udp_connected_impl(addr, port));
+ return sptr(new udp_simple_impl(addr, port, false, true /* no bcast, connect */));
}
udp_simple::sptr udp_simple::make_broadcast(
const std::string &addr, const std::string &port
){
- return sptr(new udp_broadcast_impl(addr, port));
+ return sptr(new udp_simple_impl(addr, port, true, false /* bcast, no connect */));
}
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy.cpp
index 2794d383c..dda3bb547 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy.cpp
@@ -15,16 +15,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "udp_common.hpp"
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/transport/udp_simple.hpp> //mtu
#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/buffer_pool.hpp>
-#include <uhd/utils/assert.hpp>
#include <uhd/utils/warning.hpp>
-#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <iostream>
-#include <vector>
+#include <list>
using namespace uhd;
using namespace uhd::transport;
@@ -40,20 +39,18 @@ static const size_t DEFAULT_NUM_FRAMES = 32;
**********************************************************************/
class udp_zero_copy_asio_mrb : public managed_recv_buffer{
public:
- typedef boost::shared_ptr<udp_zero_copy_asio_mrb> sptr;
typedef boost::function<void(udp_zero_copy_asio_mrb *)> release_cb_type;
udp_zero_copy_asio_mrb(void *mem, const release_cb_type &release_cb):
- _mem(mem), _release_cb(release_cb){/* NOP */}
+ _mem(mem), _len(0), _release_cb(release_cb){/* NOP */}
void release(void){
- if (_expired) return;
+ if (_len == 0) return;
this->_release_cb(this);
- _expired = true;
+ _len = 0;
}
sptr get_new(size_t len){
- _expired = false;
_len = len;
return sptr(this, &udp_zero_copy_asio_mrb::fake_deleter);
}
@@ -68,7 +65,6 @@ private:
const void *get_buff(void) const{return _mem;}
size_t get_size(void) const{return _len;}
- bool _expired;
void *_mem;
size_t _len;
release_cb_type _release_cb;
@@ -81,20 +77,18 @@ private:
**********************************************************************/
class udp_zero_copy_asio_msb : public managed_send_buffer{
public:
- typedef boost::shared_ptr<udp_zero_copy_asio_msb> sptr;
typedef boost::function<void(udp_zero_copy_asio_msb *, size_t)> commit_cb_type;
udp_zero_copy_asio_msb(void *mem, const commit_cb_type &commit_cb):
- _mem(mem), _commit_cb(commit_cb){/* NOP */}
+ _mem(mem), _len(0), _commit_cb(commit_cb){/* NOP */}
void commit(size_t len){
- if (_expired) return;
+ if (_len == 0) return;
this->_commit_cb(this, len);
- _expired = true;
+ _len = 0;
}
sptr get_new(size_t len){
- _expired = false;
_len = len;
return sptr(this, &udp_zero_copy_asio_msb::fake_deleter);
}
@@ -107,7 +101,6 @@ private:
void *get_buff(void) const{return _mem;}
size_t get_size(void) const{return _len;}
- bool _expired;
void *_mem;
size_t _len;
commit_cb_type _commit_cb;
@@ -135,7 +128,8 @@ public:
_num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_FRAMES))),
_recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)),
_send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)),
- _pending_recv_buffs(_num_recv_frames), _pending_send_buffs(_num_send_frames)
+ _pending_recv_buffs(_num_recv_frames),
+ _pending_send_buffs(_num_send_frames)
{
//std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
@@ -145,34 +139,28 @@ public:
asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
//create, open, and connect the socket
- _socket = new asio::ip::udp::socket(_io_service);
+ _socket = socket_sptr(new asio::ip::udp::socket(_io_service));
_socket->open(asio::ip::udp::v4());
_socket->connect(receiver_endpoint);
_sock_fd = _socket->native();
//allocate re-usable managed receive buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
- _mrb_pool.push_back(udp_zero_copy_asio_mrb::sptr(
- new udp_zero_copy_asio_mrb(_recv_buffer_pool->at(i),
+ _mrb_pool.push_back(udp_zero_copy_asio_mrb(_recv_buffer_pool->at(i),
boost::bind(&udp_zero_copy_asio_impl::release, this, _1))
- ));
- handle_recv(_mrb_pool.back().get());
+ );
+ handle_recv(&_mrb_pool.back());
}
//allocate re-usable managed send buffers
for (size_t i = 0; i < get_num_send_frames(); i++){
- _msb_pool.push_back(udp_zero_copy_asio_msb::sptr(
- new udp_zero_copy_asio_msb(_send_buffer_pool->at(i),
+ _msb_pool.push_back(udp_zero_copy_asio_msb(_send_buffer_pool->at(i),
boost::bind(&udp_zero_copy_asio_impl::commit, this, _1, _2))
- ));
- handle_send(_msb_pool.back().get());
+ );
+ handle_send(&_msb_pool.back());
}
}
- ~udp_zero_copy_asio_impl(void){
- delete _socket;
- }
-
//get size for internal socket buffer
template <typename Opt> size_t get_buff_size(void) const{
Opt option;
@@ -190,30 +178,24 @@ public:
/*******************************************************************
* Receive implementation:
*
- * Use select to perform a blocking receive with timeout.
+ * Perform a non-blocking receive for performance,
+ * and then fall back to a blocking receive with timeout.
* Return the managed receive buffer with the new length.
* When the caller is finished with the managed buffer,
* the managed receive buffer is released back into the queue.
******************************************************************/
- UHD_INLINE bool is_recv_ready(double timeout){
- //setup timeval for timeout
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = long(timeout*1e6);
-
- //setup rset for timeout
- fd_set rset;
- FD_ZERO(&rset);
- FD_SET(_sock_fd, &rset);
-
- //call select with timeout on receive socket
- return ::select(_sock_fd+1, &rset, NULL, NULL, &tv) > 0;
- }
-
managed_recv_buffer::sptr get_recv_buff(double timeout){
udp_zero_copy_asio_mrb *mrb = NULL;
- if (is_recv_ready(timeout) and _pending_recv_buffs.pop_with_timed_wait(mrb, timeout)){
- return mrb->get_new(::recv(_sock_fd, mrb->cast<char *>(), _recv_frame_size, 0));
+ if (_pending_recv_buffs.pop_with_timed_wait(mrb, timeout)){
+
+ #ifdef MSG_DONTWAIT //try a non-blocking recv() if supported
+ ssize_t ret = ::recv(_sock_fd, mrb->cast<char *>(), _recv_frame_size, MSG_DONTWAIT);
+ if (ret > 0) return mrb->get_new(ret);
+ #endif
+
+ if (wait_for_recv_ready(_sock_fd, timeout)) return mrb->get_new(
+ ::recv(_sock_fd, mrb->cast<char *>(), _recv_frame_size, 0)
+ );
}
return managed_recv_buffer::sptr();
}
@@ -264,12 +246,12 @@ private:
buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool;
bounded_buffer<udp_zero_copy_asio_mrb *> _pending_recv_buffs;
bounded_buffer<udp_zero_copy_asio_msb *> _pending_send_buffs;
- std::vector<udp_zero_copy_asio_msb::sptr> _msb_pool;
- std::vector<udp_zero_copy_asio_mrb::sptr> _mrb_pool;
+ std::list<udp_zero_copy_asio_msb> _msb_pool;
+ std::list<udp_zero_copy_asio_mrb> _mrb_pool;
//asio guts -> socket and service
asio::io_service _io_service;
- asio::ip::udp::socket *_socket;
+ socket_sptr _socket;
int _sock_fd;
};
diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp
deleted file mode 100644
index b91eaae1d..000000000
--- a/host/lib/transport/zero_copy.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-// Copyright 2010-2011 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/transport/zero_copy.hpp>
-
-using namespace uhd::transport;
-
-/***********************************************************************
- * Safe managed receive buffer
- **********************************************************************/
-static void release_nop(void){
- /* NOP */
-}
-
-class safe_managed_receive_buffer : public managed_recv_buffer{
-public:
- safe_managed_receive_buffer(
- const void *buff, size_t size, const release_fcn_t &release_fcn
- ):
- _buff(buff), _size(size), _release_fcn(release_fcn)
- {
- /* NOP */
- }
-
- ~safe_managed_receive_buffer(void){
- _release_fcn();
- }
-
- void release(void){
- release_fcn_t release_fcn = _release_fcn;
- _release_fcn = &release_nop;
- return release_fcn();
- }
-
-private:
- const void *get_buff(void) const{
- return _buff;
- }
-
- size_t get_size(void) const{
- return _size;
- }
-
- const void *_buff;
- size_t _size;
- release_fcn_t _release_fcn;
-};
-
-managed_recv_buffer::sptr managed_recv_buffer::make_safe(
- const void *buff, size_t size, const release_fcn_t &release_fcn
-){
- return sptr(new safe_managed_receive_buffer(buff, size, release_fcn));
-}
-
-/***********************************************************************
- * Safe managed send buffer
- **********************************************************************/
-static void commit_nop(size_t){
- /* NOP */
-}
-
-class safe_managed_send_buffer : public managed_send_buffer{
-public:
- safe_managed_send_buffer(
- void *buff, size_t size, const commit_fcn_t &commit_fcn
- ):
- _buff(buff), _size(size), _commit_fcn(commit_fcn)
- {
- /* NOP */
- }
-
- ~safe_managed_send_buffer(void){
- _commit_fcn(0);
- }
-
- void commit(size_t num_bytes){
- commit_fcn_t commit_fcn = _commit_fcn;
- _commit_fcn = &commit_nop;
- return commit_fcn(num_bytes);
- }
-
-private:
- void *get_buff(void) const{
- return _buff;
- }
-
- size_t get_size(void) const{
- return _size;
- }
-
- void *_buff;
- size_t _size;
- commit_fcn_t _commit_fcn;
-};
-
-safe_managed_send_buffer::sptr managed_send_buffer::make_safe(
- void *buff, size_t size, const commit_fcn_t &commit_fcn
-){
- return sptr(new safe_managed_send_buffer(buff, size, commit_fcn));
-}
diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt
index ad625111e..957dfd345 100644
--- a/host/lib/types/CMakeLists.txt
+++ b/host/lib/types/CMakeLists.txt
@@ -58,19 +58,24 @@ CHECK_CXX_SOURCE_COMPILES("
IF(HAVE_CLOCK_GETTIME)
MESSAGE(STATUS " High resolution timing supported through clock_gettime.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_CLOCK_GETTIME)
- SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lrt")
+ SET(TIME_SPEC_DEFS HAVE_CLOCK_GETTIME)
+ LIBUHD_APPEND_LIBS("-lrt")
ELSEIF(HAVE_MACH_ABSOLUTE_TIME)
MESSAGE(STATUS " High resolution timing supported through mach_absolute_time.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_MACH_ABSOLUTE_TIME)
+ SET(TIME_SPEC_DEFS HAVE_MACH_ABSOLUTE_TIME)
ELSEIF(HAVE_QUERY_PERFORMANCE_COUNTER)
MESSAGE(STATUS " High resolution timing supported through QueryPerformanceCounter.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER)
+ SET(TIME_SPEC_DEFS HAVE_QUERY_PERFORMANCE_COUNTER)
ELSE()
MESSAGE(STATUS " High resolution timing supported though microsec_clock.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_MICROSEC_CLOCK)
+ SET(TIME_SPEC_DEFS HAVE_MICROSEC_CLOCK)
ENDIF()
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${TIME_SPEC_DEFS}"
+)
+
########################################################################
# This file included, use CMake directory variables
########################################################################
diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp
index 4a41f0fb9..a785332c2 100644
--- a/host/lib/types/time_spec.cpp
+++ b/host/lib/types/time_spec.cpp
@@ -36,26 +36,26 @@ static UHD_INLINE time_spec_t time_spec_t_from_counts(intmax_t counts, intmax_t
return time_spec_t(time_t(divres.quot), double(divres.rem)/freq);
}
-#ifdef TIME_SPEC_USE_CLOCK_GETTIME
+#ifdef HAVE_CLOCK_GETTIME
#include <time.h>
time_spec_t time_spec_t::get_system_time(void){
timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
return time_spec_t(ts.tv_sec, ts.tv_nsec, 1e9);
}
-#endif /* TIME_SPEC_USE_CLOCK_GETTIME */
+#endif /* HAVE_CLOCK_GETTIME */
-#ifdef TIME_SPEC_USE_MACH_ABSOLUTE_TIME
+#ifdef HAVE_MACH_ABSOLUTE_TIME
#include <mach/mach_time.h>
time_spec_t time_spec_t::get_system_time(void){
mach_timebase_info_data_t info; mach_timebase_info(&info);
intmax_t nanosecs = mach_absolute_time()*info.numer/info.denom;
return time_spec_t_from_counts(nanosecs, intmax_t(1e9));
}
-#endif /* TIME_SPEC_USE_MACH_ABSOLUTE_TIME */
+#endif /* HAVE_MACH_ABSOLUTE_TIME */
-#ifdef TIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER
+#ifdef HAVE_QUERY_PERFORMANCE_COUNTER
#include <Windows.h>
time_spec_t time_spec_t::get_system_time(void){
LARGE_INTEGER counts, freq;
@@ -63,10 +63,10 @@ time_spec_t time_spec_t::get_system_time(void){
QueryPerformanceFrequency(&freq);
return time_spec_t_from_counts(counts.QuadPart, freq.QuadPart);
}
-#endif /* TIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER */
+#endif /* HAVE_QUERY_PERFORMANCE_COUNTER */
-#ifdef TIME_SPEC_USE_MICROSEC_CLOCK
+#ifdef HAVE_MICROSEC_CLOCK
#include <boost/date_time/posix_time/posix_time.hpp>
namespace pt = boost::posix_time;
time_spec_t time_spec_t::get_system_time(void){
@@ -78,7 +78,7 @@ time_spec_t time_spec_t::get_system_time(void){
double(pt::time_duration::ticks_per_second())
);
}
-#endif /* TIME_SPEC_USE_MICROSEC_CLOCK */
+#endif /* HAVE_MICROSEC_CLOCK */
/***********************************************************************
* Time spec constructors
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 3b0c562ee..3e3cf00f2 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -25,10 +25,6 @@
#define MIXER_ENB MIXER_IO
#define MIXER_DIS 0
-// Power constants
-#define POWER_UP 0
-#define POWER_DOWN POWER_IO
-
// Antenna constants
#define ANT_TX 0 //the tx line is transmitting
#define ANT_RX ANTSW_IO //the tx line is receiving
@@ -100,6 +96,7 @@ private:
double _rx_lo_freq, _tx_lo_freq;
std::string _rx_ant;
uhd::dict<std::string, double> _rx_gains;
+ boost::uint16_t _power_up;
void set_rx_lo_freq(double freq);
void set_tx_lo_freq(double freq);
@@ -130,7 +127,7 @@ private:
* Register the RFX dboards (min freq, max freq, rx div2, tx div2)
**********************************************************************/
static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t args){
- return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), false, true));
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), true, true));
}
static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t args){
@@ -178,7 +175,8 @@ rfx_xcvr::rfx_xcvr(
_div2(map_list_of
(dboard_iface::UNIT_RX, rx_div2)
(dboard_iface::UNIT_TX, tx_div2)
- )
+ ),
+ _power_up((get_rx_id() == 0x0024 && get_tx_id() == 0x0028) ? POWER_IO : 0)
{
//enable the clocks that we need
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
@@ -192,15 +190,15 @@ rfx_xcvr::rfx_xcvr(
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables);
//setup the tx atr (this does not change with antenna)
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, POWER_UP | ANT_RX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_TX | MIXER_ENB);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_TX | MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, _power_up | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, _power_up | ANT_RX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, _power_up | ANT_TX | MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_TX | MIXER_ENB);
//setup the rx atr (this does not change with antenna)
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_XX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_RX2| MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, _power_up | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, _power_up | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX2| MIXER_ENB);
//set some default values
set_rx_lo_freq((_freq_range.start() + _freq_range.stop())/2.0);
@@ -226,7 +224,7 @@ void rfx_xcvr::set_rx_ant(const std::string &ant){
//set the rx atr regs that change with antenna setting
this->get_iface()->set_atr_reg(
dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
- POWER_UP | MIXER_ENB | ((ant == "TX/RX")? ANT_TXRX : ANT_RX2)
+ _power_up | MIXER_ENB | ((ant == "TX/RX")? ANT_TXRX : ANT_RX2)
);
//shadow the setting
@@ -363,7 +361,7 @@ double rfx_xcvr::set_lo_freq(
regs.a_counter = A;
regs.b_counter = B;
regs.cp_gain_1 = adf4360_regs_t::CP_GAIN_1_SET1;
- regs.divide_by_2_output = (_div2[unit])?
+ regs.divide_by_2_output = (_div2[unit] && (get_rx_id() != 0x0024)) ? // Special case RFX400 RX Mixer divides by two
adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 :
adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ;
regs.divide_by_2_prescaler = adf4360_regs_t::DIVIDE_BY_2_PRESCALER_FUND;
diff --git a/host/lib/usrp/dboard_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp
index fa3631948..c47390bf8 100644
--- a/host/lib/usrp/dboard_eeprom.cpp
+++ b/host/lib/usrp/dboard_eeprom.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -18,6 +18,7 @@
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/utils/assert.hpp>
#include <boost/format.hpp>
+#include <algorithm>
#include <iostream>
using namespace uhd;
@@ -25,6 +26,30 @@ using namespace uhd::usrp;
static const bool _dboard_eeprom_debug = false;
+/***********************************************************************
+ * Utility functions
+ **********************************************************************/
+
+//! create a string from a byte vector, return empty if invalid ascii
+static const std::string bytes_to_string(const byte_vector_t &bytes){
+ std::string out;
+ BOOST_FOREACH(boost::uint8_t byte, bytes){
+ if (byte < 32 or byte > 127) return out;
+ out += byte;
+ }
+ return out;
+}
+
+//! create a byte vector from a string, null terminate unless max length
+static const byte_vector_t string_to_bytes(const std::string &string, size_t max_length){
+ byte_vector_t bytes;
+ for (size_t i = 0; i < std::min(string.size(), max_length); i++){
+ bytes.push_back(string[i]);
+ }
+ if (bytes.size() < max_length - 1) bytes.push_back('\0');
+ return bytes;
+}
+
////////////////////////////////////////////////////////////////////////
// format of daughterboard EEPROM
// 00: 0xDB code for ``I'm a daughterboard''
@@ -49,6 +74,8 @@ static const bool _dboard_eeprom_debug = false;
#define DB_EEPROM_OFFSET_0_MSB 0x06
#define DB_EEPROM_OFFSET_1_LSB 0x07 // offset correction for ADC or DAC 1
#define DB_EEPROM_OFFSET_1_MSB 0x08
+#define DB_EEPROM_SERIAL 0x09
+#define DB_EEPROM_SERIAL_LEN 0x09 //9 ASCII characters
#define DB_EEPROM_CHKSUM 0x1f
#define DB_EEPROM_CLEN 0x20 // length of common portion of eeprom
@@ -68,7 +95,14 @@ static boost::uint8_t checksum(const byte_vector_t &bytes){
return boost::uint8_t(sum);
}
-dboard_eeprom_t::dboard_eeprom_t(const byte_vector_t &bytes){
+dboard_eeprom_t::dboard_eeprom_t(void){
+ id = dboard_id_t::none();
+ serial = "";
+}
+
+void dboard_eeprom_t::load(i2c_iface &iface, boost::uint8_t addr){
+ byte_vector_t bytes = iface.read_eeprom(addr, 0, DB_EEPROM_CLEN);
+
if (_dboard_eeprom_debug){
for (size_t i = 0; i < bytes.size(); i++){
std::cout << boost::format(
@@ -76,28 +110,44 @@ dboard_eeprom_t::dboard_eeprom_t(const byte_vector_t &bytes){
) << std::endl;
}
}
+
try{
UHD_ASSERT_THROW(bytes.size() >= DB_EEPROM_CLEN);
UHD_ASSERT_THROW(bytes[DB_EEPROM_MAGIC] == DB_EEPROM_MAGIC_VALUE);
UHD_ASSERT_THROW(bytes[DB_EEPROM_CHKSUM] == checksum(bytes));
+
+ //parse the ids
id = dboard_id_t::from_uint16(0
| (boost::uint16_t(bytes[DB_EEPROM_ID_LSB]) << 0)
| (boost::uint16_t(bytes[DB_EEPROM_ID_MSB]) << 8)
);
+
+ //parse the serial
+ serial = bytes_to_string(
+ byte_vector_t(&bytes.at(DB_EEPROM_SERIAL),
+ &bytes.at(DB_EEPROM_SERIAL+DB_EEPROM_SERIAL_LEN))
+ );
+
}catch(const uhd::assert_error &){
id = dboard_id_t::none();
+ serial = "";
}
}
-byte_vector_t dboard_eeprom_t::get_eeprom_bytes(void){
+void dboard_eeprom_t::store(i2c_iface &iface, boost::uint8_t addr){
byte_vector_t bytes(DB_EEPROM_CLEN, 0); //defaults to all zeros
bytes[DB_EEPROM_MAGIC] = DB_EEPROM_MAGIC_VALUE;
+
+ //load the id bytes
bytes[DB_EEPROM_ID_LSB] = boost::uint8_t(id.to_uint16() >> 0);
bytes[DB_EEPROM_ID_MSB] = boost::uint8_t(id.to_uint16() >> 8);
+
+ //load the serial bytes
+ byte_vector_t ser_bytes = string_to_bytes(serial, DB_EEPROM_SERIAL_LEN);
+ std::copy(ser_bytes.begin(), ser_bytes.end(), &bytes.at(DB_EEPROM_SERIAL));
+
+ //load the checksum
bytes[DB_EEPROM_CHKSUM] = checksum(bytes);
- return bytes;
-}
-size_t dboard_eeprom_t::num_bytes(void){
- return DB_EEPROM_CLEN;
+ iface.write_eeprom(addr, 0, bytes);
}
diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp
index f7f4b2c68..c90f4a2db 100644
--- a/host/lib/usrp/mboard_eeprom.cpp
+++ b/host/lib/usrp/mboard_eeprom.cpp
@@ -17,12 +17,12 @@
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/types/mac_addr.hpp>
-#include <uhd/utils/algorithm.hpp>
#include <uhd/utils/byteswap.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
+#include <algorithm>
#include <cstddef>
using namespace uhd;
@@ -38,6 +38,12 @@ static const size_t NAME_MAX_LEN = 32 - SERIAL_LEN;
* Utility functions
**********************************************************************/
+//! A wrapper around std::copy that takes ranges instead of iterators.
+template<typename RangeSrc, typename RangeDst> inline
+void byte_copy(const RangeSrc &src, RangeDst &dst){
+ std::copy(boost::begin(src), boost::end(src), boost::begin(dst));
+}
+
//! create a string from a byte vector, return empty if invalid ascii
static const std::string bytes_to_string(const byte_vector_t &bytes){
std::string out;
@@ -84,7 +90,7 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
)).to_string();
boost::asio::ip::address_v4::bytes_type ip_addr_bytes;
- std::copy(iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], 4), ip_addr_bytes);
+ byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], 4), ip_addr_bytes);
mb_eeprom["ip-addr"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
//extract the serial
@@ -126,7 +132,7 @@ static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
if (mb_eeprom.has_key("ip-addr")){
byte_vector_t ip_addr_bytes(4);
- std::copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(), ip_addr_bytes);
+ byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(), ip_addr_bytes);
iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], ip_addr_bytes);
}
diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp
index 2a2762a82..d794b8653 100644
--- a/host/lib/usrp/usrp1/dboard_impl.cpp
+++ b/host/lib/usrp/usrp1/dboard_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -57,13 +57,8 @@ void usrp1_impl::dboard_init(void)
BOOST_FOREACH(dboard_slot_t dboard_slot, _dboard_slots){
//read the tx and rx dboard eeproms
- _rx_db_eeproms[dboard_slot] = dboard_eeprom_t(_iface->read_eeprom(
- get_rx_ee_addr(dboard_slot), 0, dboard_eeprom_t::num_bytes()
- ));
-
- _tx_db_eeproms[dboard_slot] = dboard_eeprom_t(_iface->read_eeprom(
- get_tx_ee_addr(dboard_slot), 0, dboard_eeprom_t::num_bytes()
- ));
+ _rx_db_eeproms[dboard_slot].load(*_iface, get_rx_ee_addr(dboard_slot));
+ _tx_db_eeproms[dboard_slot].load(*_iface, get_tx_ee_addr(dboard_slot));
//create a new dboard interface and manager
_dboard_ifaces[dboard_slot] = make_dboard_iface(
@@ -143,10 +138,7 @@ void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_
switch(key.as<dboard_prop_t>()) {
case DBOARD_PROP_DBOARD_ID:
_rx_db_eeproms[dboard_slot].id = val.as<dboard_id_t>();
- _iface->write_eeprom(
- get_rx_ee_addr(dboard_slot), 0,
- _rx_db_eeproms[dboard_slot].get_eeprom_bytes()
- );
+ _rx_db_eeproms[dboard_slot].store(*_iface, get_rx_ee_addr(dboard_slot));
return;
default:
@@ -208,10 +200,7 @@ void usrp1_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_
switch(key.as<dboard_prop_t>()) {
case DBOARD_PROP_DBOARD_ID:
_tx_db_eeproms[dboard_slot].id = val.as<dboard_id_t>();
- _iface->write_eeprom(
- get_tx_ee_addr(dboard_slot), 0,
- _tx_db_eeproms[dboard_slot].get_eeprom_bytes()
- );
+ _tx_db_eeproms[dboard_slot].store(*_iface, get_tx_ee_addr(dboard_slot));
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index 88cbab073..8beeccf8f 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -37,21 +37,64 @@ static const size_t alignment_padding = 512;
/***********************************************************************
* Helper struct to associate an offset with a buffer
**********************************************************************/
-class offset_send_buffer{
-public:
- typedef boost::shared_ptr<offset_send_buffer> sptr;
+struct offset_send_buffer{
+ offset_send_buffer(void){
+ /* NOP */
+ }
- static sptr make(managed_send_buffer::sptr buff, size_t offset = 0){
- return sptr(new offset_send_buffer(buff, offset));
+ offset_send_buffer(managed_send_buffer::sptr buff, size_t offset = 0):
+ buff(buff), offset(offset)
+ {
+ /* NOP */
}
//member variables
managed_send_buffer::sptr buff;
size_t offset; /* in bytes */
+};
+
+/***********************************************************************
+ * Reusable managed send buffer to handle aligned commits
+ **********************************************************************/
+class offset_managed_send_buffer : public managed_send_buffer{
+public:
+ typedef boost::function<void(offset_send_buffer&, offset_send_buffer&, size_t)> commit_cb_type;
+ offset_managed_send_buffer(const commit_cb_type &commit_cb):
+ _expired(true), _commit_cb(commit_cb)
+ {
+ /* NOP */
+ }
+
+ bool expired(void){return _expired;}
+
+ void commit(size_t size){
+ if (_expired) return;
+ this->_commit_cb(_curr_buff, _next_buff, size);
+ _expired = true;
+ }
+
+ sptr get_new(
+ offset_send_buffer &curr_buff,
+ offset_send_buffer &next_buff
+ ){
+ _expired = false;
+ _curr_buff = curr_buff;
+ _next_buff = next_buff;
+ return sptr(this, &offset_managed_send_buffer::fake_deleter);
+ }
private:
- offset_send_buffer(managed_send_buffer::sptr buff, size_t offset):
- buff(buff), offset(offset){/* NOP */}
+ static void fake_deleter(void *){
+ //dont do anything and assume the bastard committed it
+ //static_cast<offset_managed_send_buffer *>(obj)->commit(0);
+ }
+
+ void *get_buff(void) const{return _curr_buff.buff->cast<char *>() + _curr_buff.offset;}
+ size_t get_size(void) const{return _curr_buff.buff->size() - _curr_buff.offset;}
+
+ bool _expired;
+ offset_send_buffer _curr_buff, _next_buff;
+ commit_cb_type _commit_cb;
};
/***********************************************************************
@@ -60,10 +103,12 @@ private:
struct usrp1_impl::io_impl{
io_impl(zero_copy_if::sptr data_transport):
data_transport(data_transport),
+ get_recv_buffs_fcn(boost::bind(&usrp1_impl::io_impl::get_recv_buffs, this, _1)),
+ get_send_buffs_fcn(boost::bind(&usrp1_impl::io_impl::get_send_buffs, this, _1)),
underflow_poll_samp_count(0),
overflow_poll_samp_count(0),
- curr_buff_committed(true),
- curr_buff(offset_send_buffer::make(data_transport->get_send_buff()))
+ curr_buff(offset_send_buffer(data_transport->get_send_buff())),
+ omsb(boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, _1, _2, _3))
{
/* NOP */
}
@@ -74,6 +119,13 @@ struct usrp1_impl::io_impl{
zero_copy_if::sptr data_transport;
+ //timeouts set on calls to recv/send (passed into get buffs methods)
+ double recv_timeout, send_timeout;
+
+ //bound callbacks for get buffs (bound once here, not in fast-path)
+ vrt_packet_handler::get_recv_buffs_t get_recv_buffs_fcn;
+ vrt_packet_handler::get_send_buffs_t get_send_buffs_fcn;
+
//state management for the vrt packet handler code
vrt_packet_handler::recv_state packet_handler_recv_state;
vrt_packet_handler::send_state packet_handler_send_state;
@@ -86,11 +138,16 @@ struct usrp1_impl::io_impl{
//all of this to ensure only aligned lengths are committed
//NOTE: you must commit before getting a new buffer
//since the vrt packet handler obeys this, we are ok
- bool curr_buff_committed;
- offset_send_buffer::sptr curr_buff;
- void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t);
+ offset_send_buffer curr_buff;
+ offset_managed_send_buffer omsb;
+ void commit_send_buff(offset_send_buffer&, offset_send_buffer&, size_t);
void flush_send_buff(void);
- bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double);
+ bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &);
+ bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){
+ UHD_ASSERT_THROW(buffs.size() == 1);
+ buffs[0] = data_transport->get_recv_buff(recv_timeout);
+ return buffs[0].get() != NULL;
+ }
};
/*!
@@ -99,12 +156,12 @@ struct usrp1_impl::io_impl{
* Commit the current buffer at multiples of alignment.
*/
void usrp1_impl::io_impl::commit_send_buff(
- offset_send_buffer::sptr curr,
- offset_send_buffer::sptr next,
+ offset_send_buffer &curr,
+ offset_send_buffer &next,
size_t num_bytes
){
//total number of bytes now in the current buffer
- size_t bytes_in_curr_buffer = curr->offset + num_bytes;
+ size_t bytes_in_curr_buffer = curr.offset + num_bytes;
//calculate how many to commit and remainder
size_t num_bytes_remaining = bytes_in_curr_buffer % alignment_padding;
@@ -112,17 +169,16 @@ void usrp1_impl::io_impl::commit_send_buff(
//copy the remainder into the next buffer
std::memcpy(
- next->buff->cast<char *>() + next->offset,
- curr->buff->cast<char *>() + num_bytes_to_commit,
+ next.buff->cast<char *>() + next.offset,
+ curr.buff->cast<char *>() + num_bytes_to_commit,
num_bytes_remaining
);
//update the offset into the next buffer
- next->offset += num_bytes_remaining;
+ next.offset += num_bytes_remaining;
//commit the current buffer
- curr->buff->commit(num_bytes_to_commit);
- curr_buff_committed = true;
+ curr.buff->commit(num_bytes_to_commit);
}
/*!
@@ -130,14 +186,14 @@ void usrp1_impl::io_impl::commit_send_buff(
*/
void usrp1_impl::io_impl::flush_send_buff(void){
//calculate the number of bytes to alignment
- size_t bytes_to_pad = (-1*curr_buff->offset)%alignment_padding;
+ size_t bytes_to_pad = (-1*curr_buff.offset)%alignment_padding;
//send at least alignment_padding to guarantee zeros are sent
if (bytes_to_pad == 0) bytes_to_pad = alignment_padding;
//get the buffer, clear, and commit (really current buffer)
vrt_packet_handler::managed_send_buffs_t buffs(1);
- if (this->get_send_buffs(buffs, 0.1)){
+ if (this->get_send_buffs(buffs)){
std::memset(buffs[0]->cast<void *>(), 0, bytes_to_pad);
buffs[0]->commit(bytes_to_pad);
}
@@ -148,25 +204,19 @@ void usrp1_impl::io_impl::flush_send_buff(void){
* Always grab the next send buffer so we can timeout here.
*/
bool usrp1_impl::io_impl::get_send_buffs(
- vrt_packet_handler::managed_send_buffs_t &buffs, double timeout
+ vrt_packet_handler::managed_send_buffs_t &buffs
){
- UHD_ASSERT_THROW(curr_buff_committed and buffs.size() == 1);
+ UHD_ASSERT_THROW(omsb.expired() and buffs.size() == 1);
//try to get a new managed buffer with timeout
- offset_send_buffer::sptr next_buff(offset_send_buffer::make(data_transport->get_send_buff(timeout)));
- if (not next_buff->buff.get()) return false; /* propagate timeout here */
-
- //calculate the buffer pointer and size given the offset
- //references to the buffers are held in the bound function
- buffs[0] = managed_send_buffer::make_safe(
- curr_buff->buff->cast<char *>() + curr_buff->offset,
- curr_buff->buff->size() - curr_buff->offset,
- boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, curr_buff, next_buff, _1)
- );
+ offset_send_buffer next_buff(data_transport->get_send_buff(send_timeout));
+ if (not next_buff.buff.get()) return false; /* propagate timeout here */
+
+ //make a new managed buffer with the offset buffs
+ buffs[0] = omsb.get_new(curr_buff, next_buff);
//store the next buffer for the next call
curr_buff = next_buff;
- curr_buff_committed = false;
return true;
}
@@ -226,6 +276,7 @@ size_t usrp1_impl::send(
){
if (_soft_time_ctrl->send_pre(metadata, timeout)) return num_samps;
+ _io_impl->send_timeout = timeout;
size_t num_samps_sent = vrt_packet_handler::send(
_io_impl->packet_handler_send_state, //last state of the send handler
buffs, num_samps, //buffer to fill
@@ -233,7 +284,7 @@ size_t usrp1_impl::send(
io_type, _tx_otw_type, //input and output types to convert
_clock_ctrl->get_master_clock_freq(), //master clock tick rate
&usrp1_bs_vrt_packer,
- boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1, timeout),
+ _io_impl->get_send_buffs_fcn,
get_max_send_samps_per_packet(),
0, //vrt header offset
_tx_subdev_spec.size() //num channels
@@ -281,15 +332,6 @@ static void usrp1_bs_vrt_unpacker(
if_packet_info.has_tlr = false;
}
-static bool get_recv_buffs(
- zero_copy_if::sptr zc_if, double timeout,
- vrt_packet_handler::managed_recv_buffs_t &buffs
-){
- UHD_ASSERT_THROW(buffs.size() == 1);
- buffs[0] = zc_if->get_recv_buff(timeout);
- return buffs[0].get() != NULL;
-}
-
size_t usrp1_impl::get_max_recv_samps_per_packet(void) const {
return _data_transport->get_recv_frame_size()
/ _rx_otw_type.get_sample_size()
@@ -302,6 +344,7 @@ size_t usrp1_impl::recv(
rx_metadata_t &metadata, const io_type_t &io_type,
recv_mode_t recv_mode, double timeout
){
+ _io_impl->recv_timeout = timeout;
size_t num_samps_recvd = vrt_packet_handler::recv(
_io_impl->packet_handler_recv_state, //last state of the recv handler
buffs, num_samps, //buffer to fill
@@ -309,7 +352,7 @@ size_t usrp1_impl::recv(
io_type, _rx_otw_type, //input and output types to convert
_clock_ctrl->get_master_clock_freq(), //master clock tick rate
&usrp1_bs_vrt_unpacker,
- boost::bind(&get_recv_buffs, _data_transport, timeout, _1),
+ _io_impl->get_recv_buffs_fcn,
&vrt_packet_handler::handle_overflow_nop,
0, //vrt header offset
_rx_subdev_spec.size() //num channels
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index 4192c4f78..52da50132 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -35,8 +35,8 @@ using namespace uhd::usrp;
**********************************************************************/
void usrp2_mboard_impl::dboard_init(void){
//read the dboard eeprom to extract the dboard ids
- _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
- _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _rx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_RX_DB);
+ _tx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB);
//create a new dboard interface and manager
_dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
@@ -105,7 +105,7 @@ void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
case DBOARD_PROP_DBOARD_ID:
_rx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(USRP2_I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
+ _rx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_RX_DB);
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -162,7 +162,7 @@ void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
case DBOARD_PROP_DBOARD_ID:
_tx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(USRP2_I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
+ _tx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB);
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 67b52db71..b20b6652e 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -121,13 +121,12 @@ struct usrp2_impl::io_impl{
io_impl(size_t send_frame_size, const std::vector<zero_copy_if::sptr> &xports):
xports(xports),
+ get_recv_buffs_fcn(boost::bind(&usrp2_impl::io_impl::get_recv_buffs, this, _1)),
+ get_send_buffs_fcn(boost::bind(&usrp2_impl::io_impl::get_send_buffs, this, _1)),
packet_handler_recv_state(xports.size()),
packet_handler_send_state(xports.size()),
async_msg_fifo(100/*messages deep*/)
{
- get_recv_buffs_fcn = boost::bind(&usrp2_impl::io_impl::get_recv_buffs, this, _1);
- get_send_buffs_fcn = boost::bind(&usrp2_impl::io_impl::get_send_buffs, this, _1);
-
for (size_t i = 0; i < xports.size(); i++){
fc_mons.push_back(flow_control_monitor::sptr(
new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size)
diff --git a/host/lib/usrp/usrp_e100/dboard_impl.cpp b/host/lib/usrp/usrp_e100/dboard_impl.cpp
index 9f2bfb8ae..4297d41f1 100644
--- a/host/lib/usrp/usrp_e100/dboard_impl.cpp
+++ b/host/lib/usrp/usrp_e100/dboard_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -31,8 +31,8 @@ using namespace uhd::usrp;
* Dboard Initialization
**********************************************************************/
void usrp_e100_impl::dboard_init(void){
- _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
- _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_DB);
+ _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_DB);
//create a new dboard interface and manager
_dboard_iface = make_usrp_e100_dboard_iface(
@@ -105,7 +105,7 @@ void usrp_e100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
switch(key.as<dboard_prop_t>()){
case DBOARD_PROP_DBOARD_ID:
_rx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
+ _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_DB);
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -164,7 +164,7 @@ void usrp_e100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
switch(key.as<dboard_prop_t>()){
case DBOARD_PROP_DBOARD_ID:
_tx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
+ _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_DB);
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp
index 5fb2da7b8..fc6aaeaee 100644
--- a/host/lib/usrp/usrp_e100/io_impl.cpp
+++ b/host/lib/usrp/usrp_e100/io_impl.cpp
@@ -48,13 +48,10 @@ static const bool recv_debug = false;
* - vrt packet handler states
**********************************************************************/
struct usrp_e100_impl::io_impl{
- //state management for the vrt packet handler code
- vrt_packet_handler::recv_state packet_handler_recv_state;
- vrt_packet_handler::send_state packet_handler_send_state;
- zero_copy_if::sptr data_xport;
- bool continuous_streaming;
io_impl(usrp_e100_iface::sptr iface):
data_xport(usrp_e100_make_mmap_zero_copy(iface)),
+ get_recv_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_recv_buffs, this, _1)),
+ get_send_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_send_buffs, this, _1)),
recv_pirate_booty(data_xport->get_num_recv_frames()),
async_msg_fifo(100/*messages deep*/)
{
@@ -67,12 +64,34 @@ struct usrp_e100_impl::io_impl{
recv_pirate_crew.join_all();
}
- bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, double timeout){
+ bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){
UHD_ASSERT_THROW(buffs.size() == 1);
boost::this_thread::disable_interruption di; //disable because the wait can throw
- return recv_pirate_booty.pop_with_timed_wait(buffs.front(), timeout);
+ return recv_pirate_booty.pop_with_timed_wait(buffs.front(), recv_timeout);
}
+ bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs){
+ UHD_ASSERT_THROW(buffs.size() == 1);
+ buffs[0] = data_xport->get_send_buff(send_timeout);
+ return buffs[0].get() != NULL;
+ }
+
+ //The data transport is listed first so that it is deconstructed last,
+ //which is after the states and booty which may hold managed buffers.
+ zero_copy_if::sptr data_xport;
+
+ //bound callbacks for get buffs (bound once here, not in fast-path)
+ vrt_packet_handler::get_recv_buffs_t get_recv_buffs_fcn;
+ vrt_packet_handler::get_send_buffs_t get_send_buffs_fcn;
+
+ //timeouts set on calls to recv/send (passed into get buffs methods)
+ double recv_timeout, send_timeout;
+
+ //state management for the vrt packet handler code
+ vrt_packet_handler::recv_state packet_handler_recv_state;
+ vrt_packet_handler::send_state packet_handler_send_state;
+ bool continuous_streaming;
+
//a pirate's life is the life for me!
void recv_pirate_loop(usrp_e100_clock_ctrl::sptr);
bounded_buffer<managed_recv_buffer::sptr> recv_pirate_booty;
@@ -204,15 +223,6 @@ void usrp_e100_impl::handle_overrun(size_t){
/***********************************************************************
* Data Send
**********************************************************************/
-bool get_send_buffs(
- zero_copy_if::sptr trans, double timeout,
- vrt_packet_handler::managed_send_buffs_t &buffs
-){
- UHD_ASSERT_THROW(buffs.size() == 1);
- buffs[0] = trans->get_send_buff(timeout);
- return buffs[0].get() != NULL;
-}
-
size_t usrp_e100_impl::get_max_send_samps_per_packet(void) const{
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
@@ -227,6 +237,7 @@ size_t usrp_e100_impl::send(
const tx_metadata_t &metadata, const io_type_t &io_type,
send_mode_t send_mode, double timeout
){
+ _io_impl->send_timeout = timeout;
return vrt_packet_handler::send(
_io_impl->packet_handler_send_state, //last state of the send handler
buffs, num_samps, //buffer to fill
@@ -234,7 +245,7 @@ size_t usrp_e100_impl::send(
io_type, _send_otw_type, //input and output types to convert
_clock_ctrl->get_fpga_clock_rate(), //master clock tick rate
uhd::transport::vrt::if_hdr_pack_le,
- boost::bind(&get_send_buffs, _io_impl->data_xport, timeout, _1),
+ _io_impl->get_send_buffs_fcn,
get_max_send_samps_per_packet()
);
}
@@ -257,6 +268,7 @@ size_t usrp_e100_impl::recv(
rx_metadata_t &metadata, const io_type_t &io_type,
recv_mode_t recv_mode, double timeout
){
+ _io_impl->recv_timeout = timeout;
return vrt_packet_handler::recv(
_io_impl->packet_handler_recv_state, //last state of the recv handler
buffs, num_samps, //buffer to fill
@@ -264,7 +276,7 @@ size_t usrp_e100_impl::recv(
io_type, _recv_otw_type, //input and output types to convert
_clock_ctrl->get_fpga_clock_rate(), //master clock tick rate
uhd::transport::vrt::if_hdr_unpack_le,
- boost::bind(&usrp_e100_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout),
+ _io_impl->get_recv_buffs_fcn,
boost::bind(&usrp_e100_impl::handle_overrun, this, _1)
);
}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp
index 4e0137fdb..c155d426a 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp
@@ -22,7 +22,7 @@
#include <sys/mman.h> //mmap
#include <unistd.h> //getpagesize
#include <poll.h> //poll
-#include <boost/bind.hpp>
+#include <vector>
#include <iostream>
using namespace uhd;
@@ -33,6 +33,82 @@ static const bool sp_verbose = false; //slow-path verbose
static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout
/***********************************************************************
+ * Reusable managed receiver buffer:
+ * - The buffer knows how to claim and release a frame.
+ **********************************************************************/
+class usrp_e100_mmap_zero_copy_mrb : public managed_recv_buffer{
+public:
+ usrp_e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info):
+ _mem(mem), _info(info) { /* NOP */ }
+
+ void release(void){
+ if (_info->flags != RB_USER_PROCESS) return;
+ if (fp_verbose) std::cout << "recv buff: release" << std::endl;
+ _info->flags = RB_KERNEL; //release the frame
+ }
+
+ bool ready(void){return _info->flags & RB_USER;}
+
+ sptr get_new(void){
+ if (fp_verbose) std::cout << " make_recv_buff: " << get_size() << std::endl;
+ _info->flags = RB_USER_PROCESS; //claim the frame
+ return sptr(this, &usrp_e100_mmap_zero_copy_mrb::fake_deleter);
+ }
+
+private:
+ static void fake_deleter(void *obj){
+ static_cast<usrp_e100_mmap_zero_copy_mrb *>(obj)->release();
+ }
+
+ const void *get_buff(void) const{return _mem;}
+ size_t get_size(void) const{return _info->len;}
+
+ void *_mem;
+ ring_buffer_info *_info;
+};
+
+/***********************************************************************
+ * Reusable managed send buffer:
+ * - The buffer knows how to claim and release a frame.
+ **********************************************************************/
+class usrp_e100_mmap_zero_copy_msb : public managed_send_buffer{
+public:
+ usrp_e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd):
+ _mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ }
+
+ void commit(size_t len){
+ if (_info->flags != RB_USER_PROCESS) return;
+ if (fp_verbose) std::cout << "send buff: commit " << len << std::endl;
+ _info->len = len;
+ _info->flags = RB_USER; //release the frame
+ if (::write(_fd, NULL, 0) < 0){ //notifies the kernel
+ std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl;
+ }
+ }
+
+ bool ready(void){return _info->flags & RB_KERNEL;}
+
+ sptr get_new(void){
+ if (fp_verbose) std::cout << " make_send_buff: " << get_size() << std::endl;
+ _info->flags = RB_USER_PROCESS; //claim the frame
+ return sptr(this, &usrp_e100_mmap_zero_copy_msb::fake_deleter);
+ }
+
+private:
+ static void fake_deleter(void *obj){
+ static_cast<usrp_e100_mmap_zero_copy_msb *>(obj)->commit(0);
+ }
+
+ void *get_buff(void) const{return _mem;}
+ size_t get_size(void) const{return _len;}
+
+ void *_mem;
+ ring_buffer_info *_info;
+ size_t _len;
+ int _fd;
+};
+
+/***********************************************************************
* The zero copy interface implementation
**********************************************************************/
class usrp_e100_mmap_zero_copy_impl : public zero_copy_if{
@@ -81,13 +157,32 @@ public:
std::cout << "send_buff_off: " << send_buff_off << std::endl;
}
+ //pointers to sections in the mapped memory
+ ring_buffer_info (*recv_info)[], (*send_info)[];
+ char *recv_buff, *send_buff;
+
//set the internal pointers for info and buffers
typedef ring_buffer_info (*rbi_pta)[];
char *rb_ptr = reinterpret_cast<char *>(_mapped_mem);
- _recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
- _recv_buff = rb_ptr + recv_buff_off;
- _send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
- _send_buff = rb_ptr + send_buff_off;
+ recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
+ recv_buff = rb_ptr + recv_buff_off;
+ send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
+ send_buff = rb_ptr + send_buff_off;
+
+ //initialize the managed receive buffers
+ for (size_t i = 0; i < get_num_recv_frames(); i++){
+ _mrb_pool.push_back(usrp_e100_mmap_zero_copy_mrb(
+ recv_buff + get_recv_frame_size()*i, (*recv_info) + i
+ ));
+ }
+
+ //initialize the managed send buffers
+ for (size_t i = 0; i < get_num_recv_frames(); i++){
+ _msb_pool.push_back(usrp_e100_mmap_zero_copy_msb(
+ send_buff + get_send_frame_size()*i, (*send_info) + i,
+ get_send_frame_size(), _fd
+ ));
+ }
}
~usrp_e100_mmap_zero_copy_impl(void){
@@ -97,13 +192,10 @@ public:
managed_recv_buffer::sptr get_recv_buff(double timeout){
if (fp_verbose) std::cout << "get_recv_buff: " << _recv_index << std::endl;
-
- //grab pointers to the info and buffer
- ring_buffer_info *info = (*_recv_info) + _recv_index;
- void *mem = _recv_buff + _frame_size*_recv_index;
+ usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];
//poll/wait for a ready frame
- if (not (info->flags & RB_USER)){
+ if (not mrb.ready()){
for (size_t i = 0; i < poll_breakout; i++){
pollfd pfd;
pfd.fd = _fd;
@@ -115,18 +207,11 @@ public:
return managed_recv_buffer::sptr(); //timed-out for real
} found_user_frame:
- //the process has claimed the frame
- info->flags = RB_USER_PROCESS;
-
//increment the index for the next call
- if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0;
+ if (++_recv_index == get_num_recv_frames()) _recv_index = 0;
//return the managed buffer for this frame
- if (fp_verbose) std::cout << " make_recv_buff: " << info->len << std::endl;
- return managed_recv_buffer::make_safe(
- mem, info->len,
- boost::bind(&usrp_e100_mmap_zero_copy_impl::release, this, info)
- );
+ return mrb.get_new();
}
size_t get_num_recv_frames(void) const{
@@ -139,13 +224,10 @@ public:
managed_send_buffer::sptr get_send_buff(double timeout){
if (fp_verbose) std::cout << "get_send_buff: " << _send_index << std::endl;
-
- //grab pointers to the info and buffer
- ring_buffer_info *info = (*_send_info) + _send_index;
- void *mem = _send_buff + _frame_size*_send_index;
+ usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];
//poll/wait for a ready frame
- if (not (info->flags & RB_KERNEL)){
+ if (not msb.ready()){
pollfd pfd;
pfd.fd = _fd;
pfd.events = POLLOUT;
@@ -155,14 +237,10 @@ public:
}
//increment the index for the next call
- if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0;
+ if (++_send_index == get_num_send_frames()) _send_index = 0;
//return the managed buffer for this frame
- if (fp_verbose) std::cout << " make_send_buff: " << _frame_size << std::endl;
- return managed_send_buffer::make_safe(
- mem, _frame_size,
- boost::bind(&usrp_e100_mmap_zero_copy_impl::commit, this, info, _1)
- );
+ return msb.get_new();
}
size_t get_num_send_frames(void) const{
@@ -174,21 +252,7 @@ public:
}
private:
-
- void release(ring_buffer_info *info){
- if (fp_verbose) std::cout << "recv buff: release" << std::endl;
- info->flags = RB_KERNEL;
- }
-
- void commit(ring_buffer_info *info, size_t len){
- if (fp_verbose) std::cout << "send buff: commit " << len << std::endl;
- info->len = len;
- info->flags = RB_USER;
- if (::write(_fd, NULL, 0) < 0){
- std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl;
- }
- }
-
+ //file descriptor for mmap
int _fd;
//the mapped memory itself
@@ -198,9 +262,9 @@ private:
usrp_e_ring_buffer_size_t _rb_size;
size_t _frame_size, _map_size;
- //pointers to sections in the mapped memory
- ring_buffer_info (*_recv_info)[], (*_send_info)[];
- char *_recv_buff, *_send_buff;
+ //re-usable managed buffers
+ std::vector<usrp_e100_mmap_zero_copy_mrb> _mrb_pool;
+ std::vector<usrp_e100_mmap_zero_copy_msb> _msb_pool;
//indexes into sub-sections of mapped memory
size_t _recv_index, _send_index;
diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt
index 5fa5b4d6d..a4d3b2db2 100644
--- a/host/lib/utils/CMakeLists.txt
+++ b/host/lib/utils/CMakeLists.txt
@@ -24,8 +24,8 @@
########################################################################
MESSAGE(STATUS "")
MESSAGE(STATUS "Configuring priority scheduling...")
-
INCLUDE(CheckCXXSourceCompiles)
+
CHECK_CXX_SOURCE_COMPILES("
#include <pthread.h>
int main(){
@@ -48,34 +48,63 @@ CHECK_CXX_SOURCE_COMPILES("
IF(HAVE_PTHREAD_SETSCHEDPARAM)
MESSAGE(STATUS " Priority scheduling supported through pthread_setschedparam.")
- ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM)
+ SET(THREAD_PRIO_DEFS HAVE_PTHREAD_SETSCHEDPARAM)
ELSEIF(HAVE_WIN_SETTHREADPRIORITY)
MESSAGE(STATUS " Priority scheduling supported through windows SetThreadPriority.")
- ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY)
-ELSE(HAVE_PTHREAD_SETSCHEDPARAM)
+ SET(THREAD_PRIO_DEFS HAVE_WIN_SETTHREADPRIORITY)
+ELSE()
MESSAGE(STATUS " Priority scheduling not supported.")
-ENDIF(HAVE_PTHREAD_SETSCHEDPARAM)
+ SET(THREAD_PRIO_DEFS HAVE_THREAD_PRIO_DUMMY)
+ENDIF()
+
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${THREAD_PRIO_DEFS}"
+)
########################################################################
# Setup defines for module loading
########################################################################
MESSAGE(STATUS "")
MESSAGE(STATUS "Configuring module loading...")
+INCLUDE(CheckCXXSourceCompiles)
-INCLUDE(CheckIncludeFileCXX)
-CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H)
-CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H)
+SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS})
+CHECK_CXX_SOURCE_COMPILES("
+ #include <dlfcn.h>
+ int main(){
+ dlopen(0, 0);
+ return 0;
+ }
+ " HAVE_DLOPEN
+)
+UNSET(CMAKE_REQUIRED_LIBRARIES)
-IF(HAVE_DLFCN_H)
+CHECK_CXX_SOURCE_COMPILES("
+ #include <windows.h>
+ int main(){
+ LoadLibrary(0);
+ return 0;
+ }
+ " HAVE_LOAD_LIBRARY
+)
+
+IF(HAVE_DLOPEN)
MESSAGE(STATUS " Module loading supported through dlopen.")
- ADD_DEFINITIONS(-DHAVE_DLFCN_H)
+ SET(LOAD_MODULES_DEFS HAVE_DLOPEN)
LIBUHD_APPEND_LIBS(${CMAKE_DL_LIBS})
-ELSEIF(HAVE_WINDOWS_H)
+ELSEIF(HAVE_LOAD_LIBRARY)
MESSAGE(STATUS " Module loading supported through LoadLibrary.")
- ADD_DEFINITIONS(-DHAVE_WINDOWS_H)
-ELSE(HAVE_DLFCN_H)
+ SET(LOAD_MODULES_DEFS HAVE_LOAD_LIBRARY)
+ELSE()
MESSAGE(STATUS " Module loading not supported.")
-ENDIF(HAVE_DLFCN_H)
+ SET(LOAD_MODULES_DEFS HAVE_LOAD_MODULES_DUMMY)
+ENDIF()
+
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${LOAD_MODULES_DEFS}"
+)
########################################################################
# Append sources
diff --git a/host/lib/utils/load_modules.cpp b/host/lib/utils/load_modules.cpp
index 623d31eb6..fa9b22438 100644
--- a/host/lib/utils/load_modules.cpp
+++ b/host/lib/utils/load_modules.cpp
@@ -29,9 +29,8 @@ namespace fs = boost::filesystem;
/***********************************************************************
* Module Load Function
**********************************************************************/
-#if defined(HAVE_DLFCN_H)
+#ifdef HAVE_DLOPEN
#include <dlfcn.h>
-
static void load_module(const std::string &file_name){
if (dlopen(file_name.c_str(), RTLD_LAZY) == NULL){
throw std::runtime_error(str(
@@ -39,10 +38,11 @@ static void load_module(const std::string &file_name){
));
}
}
+#endif /* HAVE_DLOPEN */
-#elif defined(HAVE_WINDOWS_H)
-#include <windows.h>
+#ifdef HAVE_LOAD_LIBRARY
+#include <windows.h>
static void load_module(const std::string &file_name){
if (LoadLibrary(file_name.c_str()) == NULL){
throw std::runtime_error(str(
@@ -50,16 +50,16 @@ static void load_module(const std::string &file_name){
));
}
}
+#endif /* HAVE_LOAD_LIBRARY */
-#else
+#ifdef HAVE_LOAD_MODULES_DUMMY
static void load_module(const std::string &file_name){
throw std::runtime_error(str(
boost::format("Module loading not supported: Cannot load \"%s\"") % file_name
));
}
-
-#endif
+#endif /* HAVE_LOAD_MODULES_DUMMY */
/***********************************************************************
* Load Modules
diff --git a/host/lib/utils/thread_priority.cpp b/host/lib/utils/thread_priority.cpp
index 40b74f655..18f372ec0 100644
--- a/host/lib/utils/thread_priority.cpp
+++ b/host/lib/utils/thread_priority.cpp
@@ -44,7 +44,7 @@ static void check_priority_range(float priority){
/***********************************************************************
* Pthread API to set priority
**********************************************************************/
-#if defined(HAVE_PTHREAD_SETSCHEDPARAM)
+#ifdef HAVE_PTHREAD_SETSCHEDPARAM
#include <pthread.h>
void uhd::set_thread_priority(float priority, bool realtime){
@@ -67,11 +67,12 @@ static void check_priority_range(float priority){
int ret = pthread_setschedparam(pthread_self(), policy, &sp);
if (ret != 0) throw std::runtime_error("error in pthread_setschedparam");
}
+#endif /* HAVE_PTHREAD_SETSCHEDPARAM */
/***********************************************************************
* Windows API to set priority
**********************************************************************/
-#elif defined(HAVE_WIN_SETTHREADPRIORITY)
+#ifdef HAVE_WIN_SETTHREADPRIORITY
#include <windows.h>
void uhd::set_thread_priority(float priority, bool realtime){
@@ -93,13 +94,14 @@ static void check_priority_range(float priority){
if (SetThreadPriority(GetCurrentThread(), priorities[pri_index]) == 0)
throw std::runtime_error("error in SetThreadPriority");
}
+#endif /* HAVE_WIN_SETTHREADPRIORITY */
/***********************************************************************
* Unimplemented API to set priority
**********************************************************************/
-#else
+#ifdef HAVE_LOAD_MODULES_DUMMY
void uhd::set_thread_priority(float, bool){
throw std::runtime_error("set thread priority not implemented");
}
-#endif /* HAVE_PTHREAD_SETSCHEDPARAM */
+#endif /* HAVE_LOAD_MODULES_DUMMY */
diff --git a/host/usrp_e_utils/CMakeLists.txt b/host/usrp_e_utils/CMakeLists.txt
index 5123af592..1ecd2ac46 100644
--- a/host/usrp_e_utils/CMakeLists.txt
+++ b/host/usrp_e_utils/CMakeLists.txt
@@ -34,6 +34,7 @@ IF(ENABLE_USRP_E_UTILS)
SET(usrp_e_utils_sources
usrp-e-utility.cpp
usrp-e-loopback.c
+ usrp-e-timed.c
usrp-e-wb-test.cpp
usrp-e-debug-pins.c
usrp-e-i2c.c
diff --git a/host/usrp_e_utils/usrp-e-loopback.c b/host/usrp_e_utils/usrp-e-loopback.c
index 454d81ba7..a63882475 100644
--- a/host/usrp_e_utils/usrp-e-loopback.c
+++ b/host/usrp_e_utils/usrp-e-loopback.c
@@ -1,14 +1,18 @@
#include <stdio.h>
+#include <string.h>
#include <sys/types.h>
+#include <sys/ioctl.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>
+#include <sys/time.h>
+#include <poll.h>
+#include "linux/usrp_e.h"
-#define MAX_PACKET_SIZE 1016
+// max length #define PKT_DATA_LENGTH 1016
static int packet_data_length;
static int error;
@@ -16,34 +20,16 @@ struct pkt {
int len;
int checksum;
int seq_num;
- short data[];
+ short data[1024-6];
};
-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;
-}
+struct ring_buffer_info (*rxi)[];
+struct ring_buffer_info (*txi)[];
+struct pkt (*rx_buf)[200];
+struct pkt (*tx_buf)[200];
static int fp;
+static struct usrp_e_ring_buffer_size_t rb_size;
static int calc_checksum(struct pkt *p)
{
@@ -53,43 +39,56 @@ static int calc_checksum(struct pkt *p)
sum = 0;
for (i=0; i < p->len; i++)
- sum ^= p->data[i];
+ sum += p->data[i];
- sum ^= p->seq_num;
- sum ^= p->len;
+ 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;
+ int rb_read;
printf("Greetings from the reading thread!\n");
+ printf("sizeof pkt = %d\n", sizeof(struct pkt));
+
+ rb_read = 0;
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);
+ if (!((*rxi)[rb_read].flags & RB_USER)) {
+// printf("Waiting for data\n");
+ struct pollfd pfd;
+ pfd.fd = fp;
+ pfd.events = POLLIN;
+ poll(&pfd, 1, -1);
+ }
+
+ (*rxi)[rb_read].flags = RB_USER_PROCESS;
-// printf("p->seq_num = %d\n", p->seq_num);
+// printf("pkt received, rb_read = %d\n", rb_read);
+
+ cnt = (*rxi)[rb_read].len;
+ p = &(*rx_buf)[rb_read];
+
+// 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 = %X, p->seq_num = %d p->len = %d\n", p, p->seq_num, p->len);
pkt_count++;
@@ -97,17 +96,14 @@ static void *read_thread(void *threadid)
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);
+ printf("pkt received, rb_read = %d\n", rb_read);
+ printf("p = %p, p->seq_num = %d p->len = %d\n", p, p->seq_num, p->len);
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) {
@@ -116,6 +112,12 @@ static void *read_thread(void *threadid)
error = 1;
}
+ (*rxi)[rb_read].flags = RB_KERNEL;
+
+ rb_read++;
+ if (rb_read == rb_size.num_rx_frames)
+ rb_read = 0;
+
bytes_transfered += cnt;
if (bytes_transfered > (100 * 1000000)) {
@@ -135,12 +137,12 @@ static void *read_thread(void *threadid)
// fflush(stdout);
// printf("\n");
}
-
+ return NULL;
}
static void *write_thread(void *threadid)
{
- int seq_number, i, cnt;
+ int seq_number, i, cnt, rb_write;
void *tx_data;
struct pkt *p;
@@ -154,6 +156,7 @@ static void *write_thread(void *threadid)
p->data[i] = i;
seq_number = 1;
+ rb_write = 0;
while (1) {
p->seq_num = seq_number++;
@@ -161,30 +164,46 @@ static void *write_thread(void *threadid)
if (packet_data_length > 0)
p->len = packet_data_length;
else
- p->len = (random()<<1 & 0x1ff) + (1004 - 512);
-
- push_length_array(p->len);
+ p->len = (random() & 0x1ff) + (1004 - 512);
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);
+ if (!((*txi)[rb_write].flags & RB_KERNEL)) {
+// printf("Waiting for space\n");
+ struct pollfd pfd;
+ pfd.fd = fp;
+ pfd.events = POLLOUT;
+ poll(&pfd, 1, -1);
+ }
+
+ memcpy(&(*tx_buf)[rb_write], tx_data, p->len * 2 + 12);
+
+ (*txi)[rb_write].len = p->len * 2 + 12;
+ (*txi)[rb_write].flags = RB_USER;
+
+ rb_write++;
+ if (rb_write == rb_size.num_tx_frames)
+ rb_write = 0;
+
+ cnt = write(fp, NULL, 0);
+// if (cnt < 0)
+// printf("Error returned from write: %d\n", cnt);
// sleep(1);
}
+ return NULL;
}
int main(int argc, char *argv[])
{
pthread_t tx, rx;
- pthread_mutex_init(&length_array_mutex, 0);
- long int t;
+ long int t = 0;
struct sched_param s = {
.sched_priority = 1
};
+ int ret, map_size, page_size;
void *rb;
- struct usrp_transfer_frame *tx_rb, *rx_rb;
+ struct usrp_e_ctl16 d;
if (argc < 2) {
printf("%s data_size\n", argv[0]);
@@ -192,22 +211,43 @@ int main(int argc, char *argv[])
}
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;
+ d.offset = 14;
+ d.count = 1;
+ d.buf[0] = (1<<8) | (1<<9);
+ ioctl(fp, USRP_E_WRITE_CTL16, &d);
+
+ page_size = getpagesize();
+
+ ret = ioctl(fp, USRP_E_GET_RB_INFO, &rb_size);
+
+ map_size = (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * page_size +
+ (rb_size.num_rx_frames + rb_size.num_tx_frames) * (page_size >> 1);
+
+ rb = mmap(0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
+ if (rb == MAP_FAILED) {
+ perror("mmap failed");
+ return -1;
}
+ printf("rb = %p\n", rb);
+
+ rxi = rb;
+ rx_buf = rb + (rb_size.num_pages_rx_flags * page_size);
+ txi = rb + (rb_size.num_pages_rx_flags * page_size) +
+ (rb_size.num_rx_frames * page_size >> 1);
+ tx_buf = rb + (rb_size.num_pages_rx_flags * page_size) +
+ (rb_size.num_rx_frames * page_size >> 1) +
+ (rb_size.num_pages_tx_flags * page_size);
+
+ printf("rxi = %p, rx_buf = %p, txi = %p, tx_buf = %p\n", rxi, rx_buf, txi, tx_buf);
+
+ if ((ret = sched_setscheduler(0, SCHED_RR, &s)))
+ perror("sched_setscheduler");
- sched_setscheduler(0, SCHED_RR, &s);
error = 0;
#if 1
@@ -228,4 +268,6 @@ int main(int argc, char *argv[])
sleep(1000000000);
printf("Done sleeping\n");
+
+ return 0;
}
diff --git a/host/apps/omap_debug/usrp-e-crc-rw.c b/host/usrp_e_utils/usrp-e-timed.c
index c6f3427f0..06dfdf512 100644
--- a/host/apps/omap_debug/usrp-e-crc-rw.c
+++ b/host/usrp_e_utils/usrp-e-timed.c
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <poll.h>
#include <sys/mman.h>
-#include "usrp_e.h"
+#include "linux/usrp_e.h"
// max length #define PKT_DATA_LENGTH 1016
static int packet_data_length;
@@ -32,7 +32,7 @@ static u_int32_t chksum_crc32_gentab(void)
unsigned long crc, poly;
unsigned long i, j;
- poly = 0xEDB88320L;
+ poly = 0x04C11DB7L;
for (i = 0; i < 256; i++) {
crc = i;
@@ -44,24 +44,45 @@ static u_int32_t chksum_crc32_gentab(void)
}
}
crc_tab[i] = crc;
+// printf("crc_tab[%d] = %X\n", i , crc);
}
return 0;
}
+struct timeval delta_time(struct timeval f, struct timeval s)
+{
+ struct timeval d;
+
+ if (f.tv_usec > s.tv_usec) {
+ d.tv_usec = f.tv_usec - s.tv_usec;
+ d.tv_sec = f.tv_sec - s.tv_sec;
+ } else {
+ d.tv_usec = f.tv_usec - s.tv_usec + 1e6;
+ d.tv_sec = f.tv_sec - s.tv_sec - 1;
+ }
+
+ return d;
+}
+
+
static void *read_thread(void *threadid)
{
- int cnt;
+ unsigned int cnt;
int rx_pkt_cnt, rb_read;
- int i;
- unsigned long crc;
- unsigned int rx_crc;
- unsigned long bytes_transfered, elapsed_seconds;
- struct timeval start_time, finish_time;
-
+ unsigned int i;
+ unsigned long crc, ck_sum;
+ unsigned int rx_crc, pkt_len, pkt_seq;
+ unsigned long bytes_transfered;
+ struct timeval start_time;
+ unsigned int prev_seq = 0;
+ int first = 1;
+ long tid;
__u8 *p;
- printf("Greetings from the reading thread!\n");
+
+ tid = (long)threadid;
+ printf("Greetings from the reading thread(%ld)!\n", tid);
// IMPORTANT: must assume max length packet from fpga
@@ -77,7 +98,7 @@ static void *read_thread(void *threadid)
struct pollfd pfd;
pfd.fd = fp;
pfd.events = POLLIN;
- ssize_t ret = poll(&pfd, 1, -1);
+ poll(&pfd, 1, -1);
}
(*rxi)[rb_read].flags = RB_USER_PROCESS;
@@ -87,16 +108,40 @@ static void *read_thread(void *threadid)
rx_crc = *(int *) &p[cnt-4];
crc = 0xFFFFFFFF;
- for (i = 0; i < cnt - 4; i+=2) {
- crc = ((crc >> 8) & 0x00FFFFFF) ^
- crc_tab[(crc ^ p[i+1]) & 0xFF];
-//printf("idx = %d, data = %X, crc = %X\n", i, p[i+1],crc);
+ ck_sum = 0;
+
+ pkt_len = *(unsigned int *) &p[0];
+ pkt_seq = *(unsigned int *) &p[4];
+
+// printf("Pkt len = %X, pkt seq = %X, driver len = %X\n", pkt_len, pkt_seq, cnt);
+
+ if (pkt_len != (cnt - 4))
+ printf("Packet length check fail, driver len = %ud, content = %ud\n",
+ cnt, pkt_len);
+
+ if (!first && (pkt_seq != (prev_seq + 1)))
+ printf("Sequence number check fail, pkt_seq = %ud, prev_seq = %ud\n",
+ pkt_seq, prev_seq);
+ first = 0;
+ prev_seq = pkt_seq;
+
+ for (i = 0; i < cnt-4; i++) {
+ ck_sum += p[i];
+
crc = ((crc >> 8) & 0x00FFFFFF) ^
crc_tab[(crc ^ p[i]) & 0xFF];
-//printf("idx = %d, data = %X, crc = %X\n", i, p[i],crc);
+//printf("idx = %d, data = %X, crc = %X, ck_sum = %X\n", i, p[i], crc, ck_sum);
+// crc = ((crc >> 8) & 0x00FFFFFF) ^
+// crc_tab[(crc ^ p[i+1]) & 0xFF];
+//printf("idx = %d, data = %X, crc = %X\n", i, p[i+1],crc);
}
(*rxi)[rb_read].flags = RB_KERNEL;
+ write(fp, NULL, 1);
+
+ if (rx_crc != ck_sum)
+ printf("Ck_sum eror, calc ck_sum = %lX, rx ck_sum = %X\n",
+ ck_sum, rx_crc);
#if 0
if (rx_crc != (crc & 0xFFFFFFFF)) {
@@ -112,10 +157,18 @@ static void *read_thread(void *threadid)
bytes_transfered += cnt;
if (bytes_transfered > (100 * 1000000)) {
+ struct timeval finish_time, d_time;
+ float elapsed_seconds;
+
gettimeofday(&finish_time, NULL);
- elapsed_seconds = finish_time.tv_sec - start_time.tv_sec;
- printf("Bytes transfered = %ld, elapsed seconds = %ld\n", bytes_transfered, elapsed_seconds);
+ printf("sec = %ld, usec = %ld\n", finish_time.tv_sec, finish_time.tv_usec);
+
+ d_time = delta_time(finish_time, start_time);
+
+ elapsed_seconds = (float)d_time.tv_sec + ((float)d_time.tv_usec * 1e-6f);
+
+ printf("Bytes transfered = %ld, elapsed seconds = %f\n", bytes_transfered, elapsed_seconds);
printf("RX data transfer rate = %f K Samples/second\n",
(float) bytes_transfered / (float) elapsed_seconds / 4000);
@@ -124,6 +177,7 @@ static void *read_thread(void *threadid)
bytes_transfered = 0;
}
}
+ return NULL;
}
static void *write_thread(void *threadid)
@@ -131,11 +185,14 @@ static void *write_thread(void *threadid)
int i, tx_pkt_cnt, rb_write;
int tx_len;
unsigned long crc;
- unsigned long bytes_transfered, elapsed_seconds;
- struct timeval start_time, finish_time;
+ unsigned long bytes_transfered;
+ struct timeval start_time;
+ unsigned int pkt_seq = 0;
+ long tid;
__u8 *p;
- printf("Greetings from the write thread!\n");
+ tid = (long)threadid;
+ printf("Greetings from the write thread(%ld)!\n", tid);
rb_write = 0;
tx_pkt_cnt = 0;
@@ -176,19 +233,28 @@ static void *write_thread(void *threadid)
struct pollfd pfd;
pfd.fd = fp;
pfd.events = POLLOUT;
- ssize_t ret = poll(&pfd, 1, -1);
+ poll(&pfd, 1, -1);
}
// printf("Got space\n");
- crc = 0xFFFFFFFF;
- for (i = 0; i < tx_len-4; i++) {
+ for (i=8; i < tx_len-4; i++) {
p[i] = i & 0xFF;
+ }
+
+ *(unsigned int *) &p[0] = tx_len-4;
+ *(unsigned int *) &p[4] = pkt_seq;
+ pkt_seq++;
+
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < tx_len-4; i++) {
+// printf("%X ", p[i]);
crc = ((crc >> 8) & 0x00FFFFFF) ^
crc_tab[(crc ^ p[i]) & 0xFF];
}
- *(int *) &p[tx_len-4] = crc;
+ *(unsigned int *) &p[tx_len-4] = crc;
+// printf("\n crc = %lX\n", crc);
(*txi)[rb_write].len = tx_len;
(*txi)[rb_write].flags = RB_USER;
@@ -200,10 +266,16 @@ static void *write_thread(void *threadid)
bytes_transfered += tx_len;
if (bytes_transfered > (100 * 1000000)) {
+ struct timeval finish_time, d_time;
+ float elapsed_seconds;
+
gettimeofday(&finish_time, NULL);
- elapsed_seconds = finish_time.tv_sec - start_time.tv_sec;
- printf("Bytes transfered = %d, elapsed seconds = %d\n", bytes_transfered, elapsed_seconds);
+ d_time = delta_time(finish_time, start_time);
+
+ elapsed_seconds = (float)d_time.tv_sec - ((float)d_time.tv_usec * 1e-6f);
+
+ printf("Bytes transfered = %ld, elapsed seconds = %f\n", bytes_transfered, elapsed_seconds);
printf("TX data transfer rate = %f K Samples/second\n",
(float) bytes_transfered / (float) elapsed_seconds / 4000);
@@ -214,13 +286,14 @@ static void *write_thread(void *threadid)
// sleep(1);
}
+ return NULL;
}
int main(int argc, char *argv[])
{
pthread_t tx, rx;
- long int t;
+ long int t=0;
int fpga_config_flag ,decimation;
int ret, map_size, page_size;
void *rb;
@@ -256,7 +329,7 @@ int main(int argc, char *argv[])
return -1;
}
- printf("rb = %X\n", rb);
+ printf("rb = %p\n", rb);
rxi = rb;
rx_buf = rb + (rb_size.num_pages_rx_flags * page_size);
@@ -266,13 +339,13 @@ int main(int argc, char *argv[])
(rb_size.num_rx_frames * page_size >> 1) +
(rb_size.num_pages_tx_flags * page_size);
- fpga_config_flag = 0;
+ fpga_config_flag = (1<<8);
if (strcmp(argv[1], "w") == 0)
- fpga_config_flag |= (1 << 15);
+ fpga_config_flag |= (1 << 11);
else if (strcmp(argv[1], "r") == 0)
- fpga_config_flag |= (1 << 14);
+ fpga_config_flag |= (1 << 10);
else if (strcmp(argv[1], "rw") == 0)
- fpga_config_flag |= ((1 << 15) | (1 << 14));
+ fpga_config_flag |= ((1 << 10) | (1 << 11));
fpga_config_flag |= decimation;
@@ -285,7 +358,7 @@ int main(int argc, char *argv[])
sched_setscheduler(0, SCHED_RR, &s);
- if (fpga_config_flag & (1 << 14)) {
+ if (fpga_config_flag & (1 << 10)) {
if (pthread_create(&rx, NULL, read_thread, (void *) t)) {
printf("Failed to create rx thread\n");
exit(-1);
@@ -294,7 +367,7 @@ int main(int argc, char *argv[])
sleep(1);
- if (fpga_config_flag & (1 << 15)) {
+ if (fpga_config_flag & (1 << 11)) {
if (pthread_create(&tx, NULL, write_thread, (void *) t)) {
printf("Failed to create tx thread\n");
exit(-1);
diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py
index f52a2cbc1..6fdc9df20 100755
--- a/host/utils/usrp_n2xx_net_burner.py
+++ b/host/utils/usrp_n2xx_net_burner.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2010 Ettus Research LLC
+# Copyright 2010-2011 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
@@ -27,6 +27,7 @@ import re
import struct
import socket
import sys
+import time
########################################################################
# constants
@@ -75,77 +76,28 @@ class update_id_t:
_seq = -1
def seq():
- global _seq
- _seq = _seq+1
- return _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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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 is_valid_fpga_image(fpga_image):
for i in range(0,63):
if ord(fpga_image[i]) == 0xFF:
@@ -154,7 +106,7 @@ def is_valid_fpga_image(fpga_image):
return 1
return 0
-
+
def is_valid_fw_image(fw_image):
for i in range(0,4):
if ord(fw_image[i]) != 0x0B:
@@ -162,132 +114,205 @@ def is_valid_fw_image(fw_image):
return 1
-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()
-
- if len(fpga_image) > FPGA_IMAGE_SIZE_BYTES:
- print "Error: FPGA image file too large."
- return 0
-
- if not is_valid_fpga_image(fpga_image):
- print "Error: Invalid FPGA image file."
- return 0
-
- 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()
-
- if len(fw_image) > FW_IMAGE_SIZE_BYTES:
- print "Error: Firmware image file too large."
- return 0
-
- if not is_valid_fw_image(fw_image):
- print "Error: Invalid firmware image file."
- return 0
-
- 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))
+########################################################################
+# Burner class, holds a socket and send/recv routines
+########################################################################
+class burner_socket(object):
+ def __init__(self, ip):
+ self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ self._sock.settimeout(UDP_TIMEOUT)
+ self._sock.connect((ip, UDP_FW_UPDATE_PORT))
+
+ def send_and_recv(self, pkt):
+ try: self._sock.send(pkt)
+ except Exception, e:
+ print e
+ sys.exit(1)
+
+ try: recv_pkt = self._sock.recv(UDP_MAX_XFER_BYTES)
+ except Exception, e:
+ print e
+ sys.exit(1)
+
+ return recv_pkt
+
+ #just here to validate comms
+ def init_update(self):
+ out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0, "")
+ in_pkt = self.send_and_recv(out_pkt)
+ (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(self):
+ 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 = self.send_and_recv(out_pkt)
+
+ (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(self, fw, fpga, reset, safe):
+ (flash_size, sector_size) = self.get_flash_info()
+
+ print "Flash size: %i\nSector size: %i\n\n" % (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()
+
+ if len(fpga_image) > FPGA_IMAGE_SIZE_BYTES:
+ print "Error: FPGA image file too large."
+ return 0
+
+ if not is_valid_fpga_image(fpga_image):
+ print "Error: Invalid FPGA image file."
+ return 0
+
+ print "Begin FPGA write: this should take about 1 minute..."
+ start_time = time.time()
+ self.erase_image(image_location, FPGA_IMAGE_SIZE_BYTES)
+ self.write_image(fpga_image, image_location)
+ self.verify_image(fpga_image, image_location)
+ print "Time elapsed: %f seconds"%(time.time() - start_time)
+ print "\n\n"
+
+ 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()
+
+ if len(fw_image) > FW_IMAGE_SIZE_BYTES:
+ print "Error: Firmware image file too large."
+ return 0
+
+ if not is_valid_fw_image(fw_image):
+ print "Error: Invalid firmware image file."
+ return 0
+
+ print "Begin firmware write: this should take about 1 second..."
+ start_time = time.time()
+ self.erase_image(image_location, FW_IMAGE_SIZE_BYTES)
+ self.write_image(fw_image, image_location)
+ self.verify_image(fw_image, image_location)
+ print "Time elapsed: %f seconds"%(time.time() - start_time)
+ print "\n\n"
+
+ if reset: self.reset_usrp()
+
+ def write_image(self, 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 = self.send_and_recv(out_pkt)
+
+ (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(self, 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 = self.send_and_recv(out_pkt)
+
+ (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 read_image(self, image, size, addr):
+ print "Reading image"
+ readsize = size
+ 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 = self.send_and_recv(out_pkt)
+
+ (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)
+
+ #write to disk
+ f = open(image, 'w')
+ f.write(readdata)
+ f.close()
+
+ def reset_usrp(self):
+ 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 = self.send_and_recv(out_pkt)
+
+ (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(self, 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 = self.send_and_recv(out_pkt)
+
+ (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(True):
+ 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 = self.send_and_recv(out_pkt)
+
+ (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))
########################################################################
@@ -299,6 +324,7 @@ def get_options():
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("--read", action="store_true", help="read to file instead of write from file", default=False)
parser.add_option("--overwrite-safe", action="store_true", help="never ever use this option", default=False)
(options, args) = parser.parse_args()
@@ -312,12 +338,32 @@ if __name__=='__main__':
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:
+
+ if options.overwrite_safe and not options.read:
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)
+ if response != "yes": sys.exit(0)
+
+ burner = burner_socket(ip=options.ip)
+
+ if options.read:
+ if options.fw:
+ file = options.fw
+ if os.path.isfile(file):
+ response = raw_input("File already exists -- overwrite? (y/n) ")
+ if response != "y": sys.exit(0)
+ size = FW_IMAGE_SIZE_BYTES
+ addr = SAFE_FW_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FW_IMAGE_LOCATION_ADDR
+ burner.read_image(file, size, addr)
+
+ if options.fpga:
+ file = options.fpga
+ if os.path.isfile(file):
+ response = raw_input("File already exists -- overwrite? (y/n) ")
+ if response != "y": sys.exit(0)
+ size = FPGA_IMAGE_SIZE_BYTES
+ addr = SAFE_FPGA_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FPGA_IMAGE_LOCATION_ADDR
+ burner.read_image(file, size, addr)
+
+ else: burner.burn_fw(fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe)