3 * Copyright 2007,2008 Free Software Foundation, Inc.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <usrp2/usrp2.h>
24 #include <usrp2/strtod_si.h>
25 #include <usrp2/copiers.h>
26 #include <usrp2/rx_nop_handler.h>
27 #include <gruel/realtime.h>
31 #include <boost/scoped_ptr.hpp>
32 #include <boost/shared_ptr.hpp>
36 static volatile bool signaled = false;
45 install_sig_handler(int signum,
46 void (*new_handler)(int))
48 struct sigaction new_action;
49 memset (&new_action, 0, sizeof (new_action));
51 new_action.sa_handler = new_handler;
52 sigemptyset (&new_action.sa_mask);
53 new_action.sa_flags = 0;
55 if (sigaction (signum, &new_action, 0) < 0){
56 perror ("sigaction (install new)");
57 throw std::runtime_error ("sigaction");
61 // ------------------------------------------------------------------------
63 // FIXME make this a template
65 class complex_16_file_writer : public usrp2::rx_nop_handler
68 std::string d_filename;
72 complex_16_file_writer(const std::string &filename, uint64_t max_samples)
73 : usrp2::rx_nop_handler(max_samples), d_filename(filename)
75 d_fp = fopen(filename.c_str(), "wb");
77 perror(filename.c_str());
78 throw std::invalid_argument(filename);
82 ~complex_16_file_writer();
85 operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
87 bool ok = rx_nop_handler::operator()(items, nitems, metadata);
89 size_t host_nitems = nitems;
90 std::complex<int16_t> host_items[host_nitems];
92 usrp2::copy_u2_complex_16_to_host_complex_16(nitems, items, host_items);
95 while (n < host_nitems){
96 size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
98 if (r == 0){ // out of space?
100 perror(d_filename.c_str());
110 complex_16_file_writer::~complex_16_file_writer()
115 // ------------------------------------------------------------------------
117 class complex_float_file_writer : public usrp2::rx_nop_handler
120 std::string d_filename;
124 complex_float_file_writer(const std::string &filename, uint64_t max_samples)
125 : usrp2::rx_nop_handler(max_samples), d_filename(filename)
127 d_fp = fopen(filename.c_str(), "wb");
129 perror(filename.c_str());
130 throw std::invalid_argument(filename);
134 ~complex_float_file_writer();
137 operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
139 bool ok = rx_nop_handler::operator()(items, nitems, metadata);
141 size_t host_nitems = nitems;
142 std::complex<float> host_items[host_nitems];
144 usrp2::copy_u2_complex_16_to_host_complex_float(nitems, items, host_items);
147 while (n < host_nitems){
148 size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
150 if (r == 0){ // out of space?
152 perror(d_filename.c_str());
162 complex_float_file_writer::~complex_float_file_writer()
167 // ------------------------------------------------------------------------
170 usage(const char *progname)
172 const char *p = strrchr(progname, '/'); // drop leading directory path
176 if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix
179 fprintf(stderr, "Usage: %s [options]\n\n", p);
180 fprintf(stderr, "Options:\n");
181 fprintf(stderr, " -h show this message and exit\n");
182 fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface [default=eth0]\n");
183 fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH [default=first one found]\n");
184 fprintf(stderr, " -f FREQUENCY specify receive center frequency in Hz [default=0.0]\n");
185 fprintf(stderr, " -d DECIM specify receive decimation rate [default=5]\n");
186 fprintf(stderr, " -g GAIN specify receive daughterboard gain [default=0]\n");
187 fprintf(stderr, " -N NSAMPLES specify number of samples to receive [default=infinite]\n");
188 fprintf(stderr, " -o OUTPUT_FILENAME specify file to receive samples [default=none]\n");
189 fprintf(stderr, " -s write complex<short> [default=complex<float>]\n");
190 fprintf(stderr, " -v verbose output\n");
194 main(int argc, char **argv)
196 // options and their defaults
197 const char *interface = "eth0";
198 const char *mac_addr_str = "";
199 double rx_freq = 0.0;
201 double rx_gain = 0.0;
202 uint64_t nsamples = 0;
203 bool output_shorts = false;
204 char *output_filename = 0;
205 bool verbose = false;
209 while ((ch = getopt(argc, argv, "he:m:f:d:g:N:o:sv")) != EOF){
218 mac_addr_str = optarg;
222 if (!strtod_si(optarg, &rx_freq)) {
223 std::cerr << "invalid number: " << optarg << std::endl;
230 if (!strtod_si(optarg, &rx_gain)) {
231 std::cerr << "invalid number: " << optarg << std::endl;
238 rx_decim = strtol(optarg, 0, 0);
239 if (rx_decim < 4 or rx_decim > 512) {
240 std::cerr << "invalid decimation rate: " << optarg << std::endl;
247 if (!strtod_si(optarg, &tmp)) {
248 std::cerr << "invalid number: " << optarg << std::endl;
252 nsamples = static_cast<uint64_t>(tmp);
256 output_shorts = true;
260 output_filename = optarg;
275 install_sig_handler(SIGINT, sig_handler);
277 usrp2::rx_nop_handler::sptr handler;
279 if (output_filename){
281 handler = usrp2::rx_nop_handler::sptr(new complex_16_file_writer(output_filename, nsamples));
283 handler = usrp2::rx_nop_handler::sptr(new complex_float_file_writer(output_filename, nsamples));
286 handler = usrp2::rx_nop_handler::sptr(new usrp2::rx_nop_handler(nsamples));
288 gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
289 if (rt != gruel::RT_OK)
290 std::cerr << "Failed to enable realtime scheduling" << std::endl;
292 usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
294 // FIXME in case it was left running...
295 if (!u2->stop_rx_streaming()){
296 fprintf(stderr, "stop_rx_streaming failed\n");
299 if (!u2->set_rx_gain(rx_gain)){
300 fprintf(stderr, "set_rx_gain(%f) failed\n", rx_gain);
304 usrp2::tune_result tr;
305 if (!u2->set_rx_center_freq(rx_freq, &tr)){
306 fprintf(stderr, "set_rx_center_freq(%g) failed\n", rx_freq);
311 printf("USRP2 MAC address: %s\n\n", u2->mac_addr().c_str());
312 printf("Daughterboard configuration:\n");
313 printf(" baseband_freq=%f\n", tr.baseband_freq);
314 printf(" ddc_freq=%f\n", tr.dxc_freq);
315 printf(" residual_freq=%f\n", tr.residual_freq);
316 printf(" inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
319 if (!u2->set_rx_decim(rx_decim)) {
320 fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim);
325 printf("USRP2 using decimation rate of %d\n", rx_decim);
327 if (!u2->start_rx_streaming(0)){
328 fprintf(stderr, "start_rx_streaming failed\n");
334 printf("Receiving %zd samples\n\n", nsamples);
336 printf("Receiving infinite samples\n\n");
339 struct timeval start, end;
340 gettimeofday(&start, 0);
343 !handler->has_errored_p() &&
344 !handler->has_finished_p()) {
345 bool ok = u2->rx_samples(0, handler.get());
347 fprintf(stderr, "u2->rx_samples failed\n");
352 gettimeofday(&end, 0);
353 long n_usecs = end.tv_usec-start.tv_usec;
354 long n_secs = end.tv_sec-start.tv_sec;
355 double elapsed = (double)n_secs + (double)n_usecs*1e-6;
356 double mbs = handler->nsamples()*sizeof(uint32_t)/elapsed/1e6;
357 double pps = handler->nframes()/elapsed;
359 u2->stop_rx_streaming();
362 printf("\nCopy handler called %li times.\n", handler->nframes());
363 printf("Copy handler called with %li bytes.\n\n", handler->nsamples()*sizeof(uint32_t));
364 printf("Elapsed time was %5.3f seconds.\n", elapsed);
365 printf("Packet rate was %1.0f pkts/sec.\n", pps);
366 printf("Approximate throughput was %5.2f MB/sec.\n", mbs);
367 printf("Total instances of overruns was %d.\n", u2->rx_overruns());
368 printf("Total missing frames was %d.\n", u2->rx_missing());