aboutsummaryrefslogtreecommitdiffstats
path: root/host/usrp_e_utils
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2011-08-28 03:33:49 +0000
committerJosh Blum <josh@joshknows.com>2011-08-31 18:44:34 -0700
commitbbeb2189d587c0edc12873a1b5940ee0030148db (patch)
tree09fc0d2a6723d6554893b1ed2cbdb52f0f4748c6 /host/usrp_e_utils
parent26bfe6d54a4ecd82f4efcf6cc1c6f69d216adb1c (diff)
downloaduhd-bbeb2189d587c0edc12873a1b5940ee0030148db.tar.gz
uhd-bbeb2189d587c0edc12873a1b5940ee0030148db.tar.bz2
uhd-bbeb2189d587c0edc12873a1b5940ee0030148db.zip
e100: reimplemented loopback for easy regression testing
Diffstat (limited to 'host/usrp_e_utils')
-rw-r--r--host/usrp_e_utils/CMakeLists.txt2
-rw-r--r--host/usrp_e_utils/common.hpp8
-rw-r--r--host/usrp_e_utils/usrp-e-loopback.c321
-rw-r--r--host/usrp_e_utils/usrp-e-loopback.cpp289
4 files changed, 294 insertions, 326 deletions
diff --git a/host/usrp_e_utils/CMakeLists.txt b/host/usrp_e_utils/CMakeLists.txt
index 10117ef13..721a40093 100644
--- a/host/usrp_e_utils/CMakeLists.txt
+++ b/host/usrp_e_utils/CMakeLists.txt
@@ -27,7 +27,7 @@ IF(ENABLE_USRP_E_UTILS)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/e100/include)
SET(usrp_e_utils_sources
- usrp-e-loopback.c
+ usrp-e-loopback.cpp
usrp-e-wb-test.cpp
usrp-e-debug-pins.c
usrp-e-gpio.c
diff --git a/host/usrp_e_utils/common.hpp b/host/usrp_e_utils/common.hpp
index 1fc9a1f7b..989aecd06 100644
--- a/host/usrp_e_utils/common.hpp
+++ b/host/usrp_e_utils/common.hpp
@@ -23,7 +23,7 @@
static int fp;
-static int peek16(int reg){
+static inline int peek16(int reg){
int ret;
struct usrp_e_ctl16 d;
@@ -33,7 +33,7 @@ static int peek16(int reg){
return d.buf[0];
}
-static void poke16(int reg, int val){
+static inline void poke16(int reg, int val){
int ret;
struct usrp_e_ctl16 d;
@@ -43,7 +43,7 @@ static void poke16(int reg, int val){
ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
}
-static int peek32(int reg){
+static inline int peek32(int reg){
int ret;
struct usrp_e_ctl32 d;
@@ -53,7 +53,7 @@ static int peek32(int reg){
return d.buf[0];
}
-static void poke32(int reg, int val){
+static inline void poke32(int reg, int val){
int ret;
struct usrp_e_ctl32 d;
diff --git a/host/usrp_e_utils/usrp-e-loopback.c b/host/usrp_e_utils/usrp-e-loopback.c
deleted file mode 100644
index bf0bb7d43..000000000
--- a/host/usrp_e_utils/usrp-e-loopback.c
+++ /dev/null
@@ -1,321 +0,0 @@
-#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 <stdint.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <poll.h>
-#include "linux/usrp_e.h"
-
-// max length #define PKT_DATA_LENGTH 1016
-static int packet_data_length;
-static int error;
-
-struct pkt {
- uint32_t words32;
- uint32_t len;
- uint32_t checksum;
- uint32_t seq_num;
- uint16_t data[1024-8];
-};
-
-void print_pkt(const struct pkt *p){
- printf("p->words32 %d\n", p->words32);
- printf("p->len %d\n", p->len);
- printf("p->checksum %d\n", p->checksum);
- printf("p->seq_num %d\n", p->seq_num);
- size_t i;
- for (i = 0; i < 5; i++){
- printf(" buff[%u] = 0x%.4x\n", i, p->data[i]);
- }
-}
-
-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;
-
- if (p->len < 1016) {
- for (i=0; i < p->len; i++)
- sum += p->data[i];
-
- sum += p->seq_num;
- sum += p->len;
- } else {
- printf("Bad packet length = %d received.\n", p->len);
- }
-
- return sum;
-}
-
-static 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, prev_seq_num, pkt_count, seq_num_failure;
- struct pkt *p;
- unsigned long bytes_transfered;
- struct timeval start_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;
- 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 = %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;
- }
-
- 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 += p->len*2;//cnt;
-
- if (bytes_transfered > (100 * 1000000)) {
- struct timeval finish_time, d_time;
- float elapsed_seconds;
-
- gettimeofday(&finish_time, NULL);
- d_time = delta_time(finish_time, start_time);
- elapsed_seconds = (float)d_time.tv_sec + ((float)d_time.tv_usec * 1e-6f);
-
- printf("RX data transfer rate = %f K Samples/second\n",
- (float) bytes_transfered / elapsed_seconds / 4000.0f);
-
-
- start_time = finish_time;
- bytes_transfered = 0;
- }
-
-
-// printf(".");
-// fflush(stdout);
-// printf("\n");
- }
- return NULL;
-}
-
-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() & 0x1fe) + (1000 - 512);
-
- p->words32 = 4 /*hdr*/ + p->len/2;
-
- 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;
- poll(&pfd, 1, -1);
- }
-
- memcpy(&(*tx_buf)[rb_write], tx_data, p->words32*sizeof(uint32_t));
-
- (*txi)[rb_write].len = p->words32*sizeof(uint32_t);
- (*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;
- long int t = 0;
- struct sched_param s = {
- .sched_priority = 1
- };
- int ret, map_size, page_size;
- void *rb;
- struct usrp_e_ctl16 d;
-
- if (argc < 2) {
- printf("%s data_size\n", argv[0]);
- return -1;
- }
-
- packet_data_length = atoi(argv[1]);
-
- if (packet_data_length > 1016) {
- packet_data_length = 1016;
- printf("Max data length = 1016, clamping.\n");
- }
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- 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");
-
- 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 1
- if (pthread_create(&tx, NULL, write_thread, (void *) t)) {
- printf("Failed to create tx thread\n");
- exit(-1);
- }
-
- sleep(1);
-#endif
-
-// while (!error)
- sleep(1000000000);
-
- printf("Done sleeping\n");
-
- return 0;
-}
diff --git a/host/usrp_e_utils/usrp-e-loopback.cpp b/host/usrp_e_utils/usrp-e-loopback.cpp
new file mode 100644
index 000000000..5b1003440
--- /dev/null
+++ b/host/usrp_e_utils/usrp-e-loopback.cpp
@@ -0,0 +1,289 @@
+//
+// 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/>.
+//
+
+#include "common.hpp"
+#include <cstdlib>
+#include <cstdio>
+#include <ctime>
+#include <iostream>
+#include <boost/thread/thread.hpp>
+#include <boost/format.hpp>
+#include <boost/cstdint.hpp>
+#include <sys/mman.h> //mmap
+#include <unistd.h> //getpagesize
+#include <poll.h> //poll
+
+static const size_t bytes_per_frame = 2048;
+
+static const int poll_timeout_ms = 100;
+
+struct loopback_pkt_hdr_type{
+ boost::uint32_t words32;
+ boost::uint32_t checksum;
+ boost::uint64_t seq_num;
+};
+
+struct loopback_pkt_type{
+ loopback_pkt_hdr_type hdr;
+ boost::uint32_t data[(bytes_per_frame-sizeof(loopback_pkt_hdr_type))/sizeof(boost::uint32_t)];
+};
+
+static ring_buffer_info (*recv_info)[];
+static ring_buffer_info (*send_info)[];
+static loopback_pkt_type (*recv_buff)[];
+static loopback_pkt_type (*send_buff)[];
+
+static struct usrp_e_ring_buffer_size_t rb_size;
+
+static bool running = true;
+
+static boost::uint64_t seq_errors = 0;
+static boost::uint64_t checksum_errors = 0;
+static boost::uint64_t sent_words32 = 0;
+static boost::uint64_t recvd_words32 = 0;
+
+static inline void print_pkt(const loopback_pkt_type &pkt){
+ std::cout << std::endl;
+ std::cout << "pkt.hdr.words32 " << pkt.hdr.words32 << std::endl;
+ std::cout << "pkt.hdr.checksum " << pkt.hdr.checksum << std::endl;
+ std::cout << "pkt.hdr.seq_num " << pkt.hdr.seq_num << std::endl;
+}
+
+boost::uint32_t my_checksum(void *buff, size_t size32){
+ boost::uint32_t x = 0;
+ for (size_t i = 0; i < size32; i++){
+ x += reinterpret_cast<boost::uint32_t *>(buff)[i];
+ x ^= reinterpret_cast<boost::uint32_t *>(buff)[i];
+ }
+ return x;
+}
+
+/***********************************************************************
+ * Read thread - recv frames and verify checksum
+ **********************************************************************/
+static void read_thread(void){
+ std::cout << "start read thread... " << std::endl;
+
+ boost::uint64_t seq_num = 0;
+ size_t index = 0;
+
+ while (running){
+
+ loopback_pkt_type &pkt = (*recv_buff)[index];
+ ring_buffer_info &info = (*recv_info)[index];
+
+ //wait for frame available
+ if (not (info.flags & RB_USER)){
+ pollfd pfd;
+ pfd.fd = fp;
+ pfd.events = POLLIN;
+ if (poll(&pfd, 1, poll_timeout_ms) <= 0){
+ std::cout << "Read poll timeout, exiting read thread!" << std::endl;
+ running = false;
+ return;
+ }
+ }
+ info.flags = RB_USER_PROCESS;
+
+ //print_pkt(pkt);
+
+ //handle checksum
+ const boost::uint32_t expected_checksum = pkt.hdr.checksum;
+ pkt.hdr.checksum = 0; //set to zero for calculation
+ const boost::uint32_t actual_checksum = my_checksum(&pkt, pkt.hdr.words32);
+ if (expected_checksum != actual_checksum){
+ checksum_errors++;
+ std::cerr << "C";
+ }
+ else{
+ recvd_words32 += pkt.hdr.words32;
+ }
+
+ //handle sequence
+ if (seq_num != pkt.hdr.seq_num){
+ seq_errors++;
+ std::cerr << "S";
+ }
+ seq_num = pkt.hdr.seq_num+1;
+
+ //release the packet
+ info.flags = RB_KERNEL;
+
+ //increment index and wrap around to zero
+ index++;
+ if (index == size_t(rb_size.num_rx_frames)) index = 0;
+ }
+
+}
+
+/***********************************************************************
+ * Write thread - send frames and calculate checksum
+ **********************************************************************/
+static void write_thread(const size_t num_words32){
+ std::cout << "start write thread... " << std::endl;
+
+ srandom(std::time(NULL));
+
+ boost::uint64_t seq_num = 0;
+ size_t index = 0;
+
+ //write into tmp and memcopy into pkt to avoid cache issues
+ loopback_pkt_type pkt_tmp;
+
+ while (running){
+
+ ring_buffer_info &info = (*send_info)[index];
+
+ //wait for frame available
+ if (not (info.flags & RB_KERNEL)){
+ pollfd pfd;
+ pfd.fd = fp;
+ pfd.events = POLLOUT;
+ if (poll(&pfd, 1, poll_timeout_ms) <= 0){
+ std::cout << "Write poll timeout, exiting write thread!" << std::endl;
+ running = false;
+ return;
+ }
+ }
+
+ //fill packet header and body
+ const boost::uint32_t seed = random();
+ pkt_tmp.hdr.words32 = sizeof(pkt_tmp.hdr)/sizeof(boost::uint32_t) + num_words32;
+ pkt_tmp.hdr.checksum = 0; //set to zero for checksum()
+ pkt_tmp.hdr.seq_num = seq_num++;
+ for (size_t i = 0; i < num_words32; i++) pkt_tmp.data[i] = seed + i;
+ pkt_tmp.hdr.checksum = my_checksum(&pkt_tmp, pkt_tmp.hdr.words32);
+ sent_words32 += pkt_tmp.hdr.words32;
+
+ loopback_pkt_type &pkt = (*send_buff)[index];
+ std::memcpy(&pkt, &pkt_tmp, pkt_tmp.hdr.words32*sizeof(boost::uint32_t));
+
+ //print_pkt(pkt);
+
+ //commit the packet
+ info.len = pkt_tmp.hdr.words32*sizeof(boost::uint32_t);
+ info.flags = RB_USER;
+ ::write(fp, NULL, 0);
+
+ //increment index and wrap around to zero
+ index++;
+ if (index == size_t(rb_size.num_tx_frames)) index = 0;
+ }
+}
+
+/***********************************************************************
+ * Setup memory mapped ring buffer
+ **********************************************************************/
+static void setup_ring(void){
+ std::cout << "setup memory mapped ring buffer... " << std::flush;
+
+ //calculate various sizes
+ const size_t page_size = getpagesize();
+ ioctl(fp, USRP_E_GET_RB_INFO, &rb_size);
+ const size_t 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);
+
+ //call into memory map
+ void *mem = ::mmap(0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
+ if (mem == MAP_FAILED) {
+ std::cerr << "mmap failed" << std::endl;
+ std::exit(-1);
+ }
+
+ //calculate the memory offsets for info and buffers
+ const size_t recv_info_off = 0;
+ const size_t recv_buff_off = recv_info_off + (rb_size.num_pages_rx_flags * page_size);
+ const size_t send_info_off = recv_buff_off + (rb_size.num_rx_frames * page_size/2);
+ const size_t send_buff_off = send_info_off + (rb_size.num_pages_tx_flags * page_size);
+
+ //set the internal pointers for info and buffers
+ typedef ring_buffer_info (*rbi_pta)[];
+ typedef loopback_pkt_type (*pkt_pta)[];
+ char *rb_ptr = reinterpret_cast<char *>(mem);
+ recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
+ recv_buff = reinterpret_cast<pkt_pta>(rb_ptr + recv_buff_off);
+ send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
+ send_buff = reinterpret_cast<pkt_pta>(rb_ptr + send_buff_off);
+
+ std::cout << "done" << std::endl;
+}
+
+/***********************************************************************
+ * Main
+ **********************************************************************/
+#include <boost/program_options.hpp>
+
+int main(int argc, char *argv[]){
+
+ //variables to be set by po
+ double duration;
+ size_t nwords;
+
+ //setup the program options
+ namespace po = boost::program_options;
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("duration", po::value<double>(&duration)->default_value(10), "number of seconds to run loopback")
+ ("nwords", po::value<size_t>(&nwords)->default_value(400), "number of words32 to send per packet")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD USRP-E-Loopback %s") % desc << std::endl;
+ return ~0;
+ }
+
+ if ((fp = ::open("/dev/usrp_e0", O_RDWR)) < 0){
+ std::cerr << "Open failed" << std::endl;
+ return -1;
+ }
+
+ //set the mode to loopback
+ poke16(E100_REG_MISC_XFER_RATE, (1<<8) | (1<<9));
+
+ //setup the ring buffer
+ setup_ring();
+
+ //spawn threads
+ boost::thread_group tg;
+ tg.create_thread(boost::bind(&read_thread));
+ tg.create_thread(boost::bind(&write_thread, nwords));
+
+ const boost::system_time start_time = boost::get_system_time();
+ const boost::system_time finish_time = start_time + boost::posix_time::milliseconds(long(duration*1000));
+ while (boost::get_system_time() < finish_time){
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
+ std::cerr << ".";
+ }
+ running = false;
+ tg.join_all();
+
+ std::cout << std::endl;
+ std::cout << "seq_errors " << seq_errors << std::endl;
+ std::cout << "checksum_errors " << checksum_errors << std::endl;
+ std::cout << "sent_words32 " << sent_words32 << std::endl;
+ std::cout << "recvd_words32 " << recvd_words32 << std::endl;
+ std::cout << "approx send rate " << (sent_words32/duration)/1e6 << "Msps" << std::endl;
+ std::cout << "approx recv rate " << (recvd_words32/duration)/1e6 << "Msps" << std::endl;
+
+ ::close(fp);
+ return seq_errors + checksum_errors;
+}