Revision bbeb2189

b/host/usrp_e_utils/CMakeLists.txt
27 27
    INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/e100/include)
28 28

  
29 29
    SET(usrp_e_utils_sources
30
        usrp-e-loopback.c
30
        usrp-e-loopback.cpp
31 31
        usrp-e-wb-test.cpp
32 32
        usrp-e-debug-pins.c
33 33
        usrp-e-gpio.c
b/host/usrp_e_utils/common.hpp
23 23

  
24 24
static int fp;
25 25

  
26
static int peek16(int reg){
26
static inline int peek16(int reg){
27 27
    int ret;
28 28
    struct usrp_e_ctl16 d;
29 29

  
......
33 33
    return d.buf[0];
34 34
}
35 35

  
36
static void poke16(int reg, int val){
36
static inline void poke16(int reg, int val){
37 37
    int ret;
38 38
    struct usrp_e_ctl16 d;
39 39

  
......
43 43
    ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
44 44
}
45 45

  
46
static int peek32(int reg){
46
static inline int peek32(int reg){
47 47
    int ret;
48 48
    struct usrp_e_ctl32 d;
49 49

  
......
53 53
    return d.buf[0];
54 54
}
55 55

  
56
static void poke32(int reg, int val){
56
static inline void poke32(int reg, int val){
57 57
    int ret;
58 58
    struct usrp_e_ctl32 d;
59 59

  
/dev/null
1
#include <stdio.h>
2
#include <string.h>
3
#include <sys/types.h>
4
#include <sys/ioctl.h>
5
#include <fcntl.h>
6
#include <pthread.h>
7
#include <stdlib.h>
8
#include <unistd.h>
9
#include <stddef.h>
10
#include <stdint.h>
11
#include <sys/mman.h>
12
#include <sys/time.h>
13
#include <poll.h>
14
#include "linux/usrp_e.h"
15

  
16
// max length #define PKT_DATA_LENGTH 1016
17
static int packet_data_length;
18
static int error;
19

  
20
struct pkt {
21
	uint32_t words32;
22
	uint32_t len;
23
	uint32_t checksum;
24
	uint32_t seq_num;
25
	uint16_t data[1024-8];
26
};
27

  
28
void print_pkt(const struct pkt *p){
29
	printf("p->words32 %d\n", p->words32);
30
	printf("p->len %d\n", p->len);
31
	printf("p->checksum %d\n", p->checksum);
32
	printf("p->seq_num %d\n", p->seq_num);
33
	size_t i;
34
	for (i = 0; i < 5; i++){
35
		printf("  buff[%u] = 0x%.4x\n", i, p->data[i]);
36
	}
37
}
38

  
39
struct ring_buffer_info (*rxi)[];
40
struct ring_buffer_info (*txi)[];
41
struct pkt (*rx_buf)[200];
42
struct pkt (*tx_buf)[200];
43

  
44
static int fp;
45
static struct usrp_e_ring_buffer_size_t rb_size;
46

  
47
static int calc_checksum(struct pkt *p)
48
{
49
	int i, sum;
50

  
51
	i = 0;
52
	sum = 0;
53

  
54
	if (p->len < 1016) {
55
		for (i=0; i < p->len; i++)
56
			sum += p->data[i];
57
	
58
		sum += p->seq_num;
59
		sum += p->len;
60
	} else {	
61
		printf("Bad packet length = %d received.\n", p->len);
62
	}
63

  
64
	return sum;
65
}
66

  
67
static struct timeval delta_time(struct timeval f, struct timeval s)
68
{
69
	struct timeval d;
70

  
71
	if (f.tv_usec > s.tv_usec) {
72
		d.tv_usec = f.tv_usec - s.tv_usec;
73
		d.tv_sec = f.tv_sec - s.tv_sec;
74
	} else {
75
		d.tv_usec = f.tv_usec - s.tv_usec + 1e6;
76
		d.tv_sec = f.tv_sec - s.tv_sec - 1;
77
	}
78

  
79
	return d;
80
}
81

  
82
static void *read_thread(void *threadid)
83
{
84
	int cnt, prev_seq_num, pkt_count, seq_num_failure;
85
	struct pkt *p;
86
	unsigned long bytes_transfered;
87
	struct timeval start_time;
88
	int rb_read;
89

  
90
	printf("Greetings from the reading thread!\n");
91
	printf("sizeof pkt = %d\n", sizeof(struct pkt));
92

  
93
	rb_read = 0;
94

  
95
	bytes_transfered = 0;
96
	gettimeofday(&start_time, NULL);
97

  
98
	prev_seq_num = 0;
99
	pkt_count = 0;
100
	seq_num_failure = 0;
101

  
102
	while (1) {
103

  
104
		if (!((*rxi)[rb_read].flags & RB_USER)) {
105
//			printf("Waiting for data\n");
106
			struct pollfd pfd;
107
			pfd.fd = fp;
108
			pfd.events = POLLIN;
109
			poll(&pfd, 1, -1);
110
		}
111

  
112
		(*rxi)[rb_read].flags = RB_USER_PROCESS;
113

  
114
//		printf("pkt received, rb_read = %d\n", rb_read);
115

  
116
		cnt = (*rxi)[rb_read].len;
117
		p = &(*rx_buf)[rb_read];
118

  
119
//		cnt = read(fp, rx_data, 2048);
120
//		if (cnt < 0)
121
//			printf("Error returned from read: %d, sequence number = %d\n", cnt, p->seq_num);
122

  
123
//		printf("p = %X, p->seq_num = %d p->len = %d\n", p, p->seq_num, p->len);
124

  
125

  
126
		pkt_count++;
127

  
128
		if (p->seq_num != prev_seq_num + 1) {
129
			printf("Sequence number fail, current = %d, previous = %d, pkt_count = %d\n",
130
				p->seq_num, prev_seq_num, pkt_count);
131
			printf("pkt received, rb_read = %d\n", rb_read);
132
			printf("p = %p, p->seq_num = %d p->len = %d\n", p, p->seq_num, p->len);
133

  
134
			seq_num_failure ++;
135
			if (seq_num_failure > 2)
136
				error = 1;
137
		}
138

  
139
		prev_seq_num = p->seq_num;
140

  
141
		if (calc_checksum(p) != p->checksum) {
142
			printf("Checksum fail packet = %X, expected = %X, pkt_count = %d\n",
143
				calc_checksum(p), p->checksum, pkt_count);
144
			error = 1;
145
		}
146

  
147
		(*rxi)[rb_read].flags = RB_KERNEL;
148

  
149
		rb_read++;
150
		if (rb_read == rb_size.num_rx_frames)
151
			rb_read = 0;
152

  
153
		bytes_transfered += p->len*2;//cnt;
154

  
155
		if (bytes_transfered > (100 * 1000000)) {
156
			struct timeval finish_time, d_time;
157
			float elapsed_seconds;
158

  
159
			gettimeofday(&finish_time, NULL);
160
			d_time = delta_time(finish_time, start_time);
161
			elapsed_seconds = (float)d_time.tv_sec + ((float)d_time.tv_usec * 1e-6f);
162

  
163
			printf("RX data transfer rate = %f K Samples/second\n",
164
				(float) bytes_transfered / elapsed_seconds / 4000.0f);
165

  
166

  
167
			start_time = finish_time;
168
			bytes_transfered = 0;
169
		}
170

  
171

  
172
//		printf(".");
173
//		fflush(stdout);
174
//		printf("\n");
175
	}
176
	return NULL;
177
}
178

  
179
static void *write_thread(void *threadid)
180
{
181
	int seq_number, i, cnt, rb_write;
182
	void *tx_data;
183
	struct pkt *p;
184

  
185
	printf("Greetings from the write thread!\n");
186

  
187
	tx_data = malloc(2048);
188
	p = (struct pkt *) ((void *)tx_data);
189

  
190
	for (i=0; i < packet_data_length; i++)
191
//		p->data[i] = random() >> 16;
192
		p->data[i] = i;
193

  
194
	seq_number = 1;
195
	rb_write = 0;
196

  
197
	while (1) {
198
		p->seq_num = seq_number++;
199

  
200
		if (packet_data_length > 0)
201
			p->len = packet_data_length;
202
		else
203
			p->len = (random() & 0x1fe) + (1000 - 512);
204

  
205
		p->words32 = 4 /*hdr*/ + p->len/2;
206

  
207
		p->checksum = calc_checksum(p);
208

  
209
		if (!((*txi)[rb_write].flags & RB_KERNEL)) {
210
//			printf("Waiting for space\n");
211
			struct pollfd pfd;
212
			pfd.fd = fp;
213
			pfd.events = POLLOUT;
214
			poll(&pfd, 1, -1);
215
		}
216

  
217
		memcpy(&(*tx_buf)[rb_write], tx_data, p->words32*sizeof(uint32_t));
218

  
219
		(*txi)[rb_write].len = p->words32*sizeof(uint32_t);
220
		(*txi)[rb_write].flags = RB_USER;
221

  
222
		rb_write++;
223
		if (rb_write == rb_size.num_tx_frames)
224
			rb_write = 0;
225

  
226
		cnt = write(fp, NULL, 0);
227
//		if (cnt < 0)
228
//			printf("Error returned from write: %d\n", cnt);
229
//		sleep(1);
230

  
231
	}
232
	return NULL;
233
}
234

  
235

  
236
int main(int argc, char *argv[])
237
{
238
	pthread_t tx, rx;
239
	long int t = 0;
240
	struct sched_param s = {
241
		.sched_priority = 1
242
	};
243
	int ret, map_size, page_size;
244
	void *rb;
245
	struct usrp_e_ctl16 d;
246

  
247
	if (argc < 2) {
248
		printf("%s data_size\n", argv[0]);
249
		return -1;
250
	}
251

  
252
	packet_data_length = atoi(argv[1]);
253

  
254
	if (packet_data_length > 1016) {
255
		packet_data_length = 1016;
256
		printf("Max data length = 1016, clamping.\n");
257
	}
258

  
259
	fp = open("/dev/usrp_e0", O_RDWR);
260
	printf("fp = %d\n", fp);
261

  
262
	d.offset = 14;
263
	d.count = 1;
264
	d.buf[0] = (1<<8) | (1<<9);
265
	ioctl(fp, USRP_E_WRITE_CTL16, &d);
266

  
267
	page_size = getpagesize();
268

  
269
	ret = ioctl(fp, USRP_E_GET_RB_INFO, &rb_size);
270

  
271
	map_size = (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * page_size +
272
		(rb_size.num_rx_frames + rb_size.num_tx_frames) * (page_size >> 1);
273

  
274
	rb = mmap(0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
275
	if (rb == MAP_FAILED) {
276
		perror("mmap failed");
277
		return -1;
278
	}
279

  
280
	printf("rb = %p\n", rb);
281

  
282
	rxi = rb;
283
	rx_buf = rb + (rb_size.num_pages_rx_flags * page_size);
284
	txi = rb +  (rb_size.num_pages_rx_flags * page_size) +
285
		(rb_size.num_rx_frames * page_size >> 1);
286
	tx_buf = rb +  (rb_size.num_pages_rx_flags * page_size) +
287
		(rb_size.num_rx_frames * page_size >> 1) +
288
		(rb_size.num_pages_tx_flags * page_size);
289

  
290
	printf("rxi = %p, rx_buf = %p, txi = %p, tx_buf = %p\n", rxi, rx_buf, txi, tx_buf);
291

  
292
	if ((ret = sched_setscheduler(0, SCHED_RR, &s)))
293
		perror("sched_setscheduler");
294

  
295
	error = 0;
296

  
297
#if 1
298
	if (pthread_create(&rx, NULL, read_thread, (void *) t)) {
299
		printf("Failed to create rx thread\n");
300
		exit(-1);
301
	}
302

  
303
	sleep(1);
304
#endif
305

  
306
#if 1
307
	if (pthread_create(&tx, NULL, write_thread, (void *) t)) {
308
		printf("Failed to create tx thread\n");
309
		exit(-1);
310
	}
311

  
312
	sleep(1);
313
#endif
314

  
315
//	while (!error)
316
		sleep(1000000000);
317

  
318
	printf("Done sleeping\n");
319

  
320
	return 0;
321
}
b/host/usrp_e_utils/usrp-e-loopback.cpp
1
//
2
// Copyright 2011 Ettus Research LLC
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

  
18
#include "common.hpp"
19
#include <cstdlib>
20
#include <cstdio>
21
#include <ctime>
22
#include <iostream>
23
#include <boost/thread/thread.hpp>
24
#include <boost/format.hpp>
25
#include <boost/cstdint.hpp>
26
#include <sys/mman.h> //mmap
27
#include <unistd.h> //getpagesize
28
#include <poll.h> //poll
29

  
30
static const size_t bytes_per_frame = 2048;
31

  
32
static const int poll_timeout_ms = 100;
33

  
34
struct loopback_pkt_hdr_type{
35
    boost::uint32_t words32;
36
    boost::uint32_t checksum;
37
    boost::uint64_t seq_num;
38
};
39

  
40
struct loopback_pkt_type{
41
    loopback_pkt_hdr_type hdr;
42
    boost::uint32_t data[(bytes_per_frame-sizeof(loopback_pkt_hdr_type))/sizeof(boost::uint32_t)];
43
};
44

  
45
static ring_buffer_info (*recv_info)[];
46
static ring_buffer_info (*send_info)[];
47
static loopback_pkt_type (*recv_buff)[];
48
static loopback_pkt_type (*send_buff)[];
49

  
50
static struct usrp_e_ring_buffer_size_t rb_size;
51

  
52
static bool running = true;
53

  
54
static boost::uint64_t seq_errors = 0;
55
static boost::uint64_t checksum_errors = 0;
56
static boost::uint64_t sent_words32 = 0;
57
static boost::uint64_t recvd_words32 = 0;
58

  
59
static inline void print_pkt(const loopback_pkt_type &pkt){
60
    std::cout << std::endl;
61
    std::cout << "pkt.hdr.words32 " << pkt.hdr.words32 << std::endl;
62
    std::cout << "pkt.hdr.checksum " << pkt.hdr.checksum << std::endl;
63
    std::cout << "pkt.hdr.seq_num " << pkt.hdr.seq_num << std::endl;
64
}
65

  
66
boost::uint32_t my_checksum(void *buff, size_t size32){
67
    boost::uint32_t x = 0;
68
    for (size_t i = 0; i < size32; i++){
69
        x += reinterpret_cast<boost::uint32_t *>(buff)[i];
70
        x ^= reinterpret_cast<boost::uint32_t *>(buff)[i];
71
    }
72
    return x;
73
}
74

  
75
/***********************************************************************
76
 * Read thread - recv frames and verify checksum
77
 **********************************************************************/
78
static void read_thread(void){
79
    std::cout << "start read thread... " << std::endl;
80

  
81
    boost::uint64_t seq_num = 0;
82
    size_t index = 0;
83

  
84
    while (running){
85

  
86
        loopback_pkt_type &pkt = (*recv_buff)[index];
87
        ring_buffer_info &info = (*recv_info)[index];
88

  
89
        //wait for frame available
90
        if (not (info.flags & RB_USER)){
91
            pollfd pfd;
92
            pfd.fd = fp;
93
            pfd.events = POLLIN;
94
            if (poll(&pfd, 1, poll_timeout_ms) <= 0){
95
                std::cout << "Read poll timeout, exiting read thread!" << std::endl;
96
                running = false;
97
                return;
98
            }
99
        }
100
        info.flags = RB_USER_PROCESS;
101

  
102
        //print_pkt(pkt);
103

  
104
        //handle checksum
105
        const boost::uint32_t expected_checksum = pkt.hdr.checksum;
106
        pkt.hdr.checksum = 0; //set to zero for calculation
107
        const boost::uint32_t actual_checksum = my_checksum(&pkt, pkt.hdr.words32);
108
        if (expected_checksum != actual_checksum){
109
            checksum_errors++;
110
            std::cerr << "C";
111
        }
112
        else{
113
            recvd_words32 += pkt.hdr.words32;
114
        }
115

  
116
        //handle sequence
117
        if (seq_num != pkt.hdr.seq_num){
118
            seq_errors++;
119
            std::cerr << "S";
120
        }
121
        seq_num = pkt.hdr.seq_num+1;
122

  
123
        //release the packet
124
        info.flags = RB_KERNEL;
125

  
126
        //increment index and wrap around to zero
127
        index++;
128
        if (index == size_t(rb_size.num_rx_frames)) index = 0;
129
    }
130

  
131
}
132

  
133
/***********************************************************************
134
 * Write thread - send frames and calculate checksum
135
 **********************************************************************/
136
static void write_thread(const size_t num_words32){
137
    std::cout << "start write thread... " << std::endl;
138

  
139
    srandom(std::time(NULL));
140

  
141
    boost::uint64_t seq_num = 0;
142
    size_t index = 0;
143

  
144
    //write into tmp and memcopy into pkt to avoid cache issues
145
    loopback_pkt_type pkt_tmp;
146

  
147
    while (running){
148

  
149
        ring_buffer_info &info = (*send_info)[index];
150

  
151
        //wait for frame available
152
        if (not (info.flags & RB_KERNEL)){
153
            pollfd pfd;
154
            pfd.fd = fp;
155
            pfd.events = POLLOUT;
156
            if (poll(&pfd, 1, poll_timeout_ms) <= 0){
157
                std::cout << "Write poll timeout, exiting write thread!" << std::endl;
158
                running = false;
159
                return;
160
            }
161
        }
162

  
163
        //fill packet header and body
164
        const boost::uint32_t seed = random();
165
        pkt_tmp.hdr.words32 = sizeof(pkt_tmp.hdr)/sizeof(boost::uint32_t) + num_words32;
166
        pkt_tmp.hdr.checksum = 0; //set to zero for checksum()
167
        pkt_tmp.hdr.seq_num = seq_num++;
168
        for (size_t i = 0; i < num_words32; i++) pkt_tmp.data[i] = seed + i;
169
        pkt_tmp.hdr.checksum = my_checksum(&pkt_tmp, pkt_tmp.hdr.words32);
170
        sent_words32 += pkt_tmp.hdr.words32;
171

  
172
        loopback_pkt_type &pkt = (*send_buff)[index];
173
        std::memcpy(&pkt, &pkt_tmp, pkt_tmp.hdr.words32*sizeof(boost::uint32_t));
174

  
175
        //print_pkt(pkt);
176

  
177
        //commit the packet
178
        info.len = pkt_tmp.hdr.words32*sizeof(boost::uint32_t);
179
        info.flags = RB_USER;
180
        ::write(fp, NULL, 0);
181

  
182
        //increment index and wrap around to zero
183
        index++;
184
        if (index == size_t(rb_size.num_tx_frames)) index = 0;
185
    }
186
}
187

  
188
/***********************************************************************
189
 * Setup memory mapped ring buffer
190
 **********************************************************************/
191
static void setup_ring(void){
192
    std::cout << "setup memory mapped ring buffer... " << std::flush;
193

  
194
    //calculate various sizes
195
    const size_t page_size = getpagesize();
196
    ioctl(fp, USRP_E_GET_RB_INFO, &rb_size);
197
    const size_t map_size = (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * page_size +
198
        (rb_size.num_rx_frames + rb_size.num_tx_frames) * (page_size >> 1);
199

  
200
    //call into memory map
201
    void *mem = ::mmap(0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
202
    if (mem == MAP_FAILED) {
203
        std::cerr << "mmap failed" << std::endl;
204
        std::exit(-1);
205
    }
206

  
207
    //calculate the memory offsets for info and buffers
208
    const size_t recv_info_off = 0;
209
    const size_t recv_buff_off = recv_info_off + (rb_size.num_pages_rx_flags * page_size);
210
    const size_t send_info_off = recv_buff_off + (rb_size.num_rx_frames * page_size/2);
211
    const size_t send_buff_off = send_info_off + (rb_size.num_pages_tx_flags * page_size);
212

  
213
    //set the internal pointers for info and buffers
214
    typedef ring_buffer_info (*rbi_pta)[];
215
    typedef loopback_pkt_type (*pkt_pta)[];
216
    char *rb_ptr = reinterpret_cast<char *>(mem);
217
    recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
218
    recv_buff = reinterpret_cast<pkt_pta>(rb_ptr + recv_buff_off);
219
    send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
220
    send_buff = reinterpret_cast<pkt_pta>(rb_ptr + send_buff_off);
221

  
222
    std::cout << "done" << std::endl;
223
}
224

  
225
/***********************************************************************
226
 * Main
227
 **********************************************************************/
228
#include <boost/program_options.hpp>
229

  
230
int main(int argc, char *argv[]){
231

  
232
    //variables to be set by po
233
    double duration;
234
    size_t nwords;
235

  
236
    //setup the program options
237
    namespace po = boost::program_options;
238
    po::options_description desc("Allowed options");
239
    desc.add_options()
240
        ("help", "help message")
241
        ("duration", po::value<double>(&duration)->default_value(10), "number of seconds to run loopback")
242
        ("nwords", po::value<size_t>(&nwords)->default_value(400), "number of words32 to send per packet")
243
    ;
244
    po::variables_map vm;
245
    po::store(po::parse_command_line(argc, argv, desc), vm);
246
    po::notify(vm);
247

  
248
    //print the help message
249
    if (vm.count("help")){
250
        std::cout << boost::format("UHD USRP-E-Loopback %s") % desc << std::endl;
251
        return ~0;
252
    }
253

  
254
    if ((fp = ::open("/dev/usrp_e0", O_RDWR)) < 0){
255
        std::cerr << "Open failed" << std::endl;
256
        return -1;
257
    }
258

  
259
    //set the mode to loopback
260
    poke16(E100_REG_MISC_XFER_RATE, (1<<8) | (1<<9));
261

  
262
    //setup the ring buffer
263
    setup_ring();
264

  
265
    //spawn threads
266
    boost::thread_group tg;
267
    tg.create_thread(boost::bind(&read_thread));
268
    tg.create_thread(boost::bind(&write_thread, nwords));
269

  
270
    const boost::system_time start_time = boost::get_system_time();
271
    const boost::system_time finish_time = start_time + boost::posix_time::milliseconds(long(duration*1000));
272
    while (boost::get_system_time() < finish_time){
273
        boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
274
        std::cerr << ".";
275
    }
276
    running = false;
277
    tg.join_all();
278

  
279
    std::cout << std::endl;
280
    std::cout << "seq_errors          " << seq_errors << std::endl;
281
    std::cout << "checksum_errors     " << checksum_errors << std::endl;
282
    std::cout << "sent_words32        " << sent_words32 << std::endl;
283
    std::cout << "recvd_words32       " << recvd_words32 << std::endl;
284
    std::cout << "approx send rate    " << (sent_words32/duration)/1e6 << "Msps" << std::endl;
285
    std::cout << "approx recv rate    " << (recvd_words32/duration)/1e6 << "Msps" << std::endl;
286

  
287
    ::close(fp);
288
    return seq_errors + checksum_errors;
289
}

Also available in: Unified diff