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