diff options
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)  | 
