Merged r9433:9527 from features/gr-usrp2 into trunk. Adds usrp2 and gr-usrp2 top...
[debian/gnuradio] / usrp2 / host / apps / rx_streaming_samples.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2008 Free Software Foundation, Inc.
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
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>
28 #include <sys/time.h>
29 #include <iostream>
30 #include <string.h>
31 #include <boost/scoped_ptr.hpp>
32 #include <boost/shared_ptr.hpp>
33 #include <stdexcept>
34 #include <signal.h>
35
36 static volatile bool signaled = false;
37
38 static void 
39 sig_handler(int sig)
40 {
41   signaled = true;
42 }
43
44 static void
45 install_sig_handler(int signum,
46                     void (*new_handler)(int))
47 {
48   struct sigaction new_action;
49   memset (&new_action, 0, sizeof (new_action));
50
51   new_action.sa_handler = new_handler;
52   sigemptyset (&new_action.sa_mask);
53   new_action.sa_flags = 0;
54
55   if (sigaction (signum, &new_action, 0) < 0){
56     perror ("sigaction (install new)");
57     throw std::runtime_error ("sigaction");
58   }
59 }
60
61 // ------------------------------------------------------------------------
62
63 // FIXME make this a template
64
65 class complex_16_file_writer : public usrp2::rx_nop_handler
66 {
67   FILE         *d_fp;
68   std::string   d_filename;
69   
70 public:
71
72   complex_16_file_writer(const std::string &filename, uint64_t max_samples)
73     : usrp2::rx_nop_handler(max_samples), d_filename(filename)
74   {
75     d_fp = fopen(filename.c_str(), "wb");
76     if (d_fp == 0){
77       perror(filename.c_str());
78       throw std::invalid_argument(filename);
79     }
80   }
81
82   ~complex_16_file_writer();
83
84   bool 
85   operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
86   {
87     bool ok = rx_nop_handler::operator()(items, nitems, metadata);
88
89     size_t host_nitems = nitems;
90     std::complex<int16_t> host_items[host_nitems];
91
92     usrp2::copy_u2_complex_16_to_host_complex_16(nitems, items, host_items);
93
94     size_t n = 0;
95     while (n < host_nitems){
96       size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
97       n += r;
98       if (r == 0){      // out of space?
99         d_err = true;
100         perror(d_filename.c_str());
101         ok = false;
102         break;
103       }
104     }
105
106     return ok;
107   }
108 };
109
110 complex_16_file_writer::~complex_16_file_writer()
111 {
112   fclose(d_fp);
113 }
114
115 // ------------------------------------------------------------------------
116
117 class complex_float_file_writer : public usrp2::rx_nop_handler
118 {
119   FILE         *d_fp;
120   std::string   d_filename;
121   
122 public:
123
124   complex_float_file_writer(const std::string &filename, uint64_t max_samples)
125     : usrp2::rx_nop_handler(max_samples), d_filename(filename)
126   {
127     d_fp = fopen(filename.c_str(), "wb");
128     if (d_fp == 0){
129       perror(filename.c_str());
130       throw std::invalid_argument(filename);
131     }
132   }
133
134   ~complex_float_file_writer();
135
136   bool 
137   operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
138   {
139     bool ok = rx_nop_handler::operator()(items, nitems, metadata);
140
141     size_t host_nitems = nitems;
142     std::complex<float> host_items[host_nitems];
143
144     usrp2::copy_u2_complex_16_to_host_complex_float(nitems, items, host_items);
145
146     size_t n = 0;
147     while (n < host_nitems){
148       size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
149       n += r;
150       if (r == 0){      // out of space?
151         d_err = true;
152         perror(d_filename.c_str());
153         ok = false;
154         break;
155       }
156     }
157
158     return ok;
159   }
160 };
161
162 complex_float_file_writer::~complex_float_file_writer()
163 {
164   fclose(d_fp);
165 }
166
167 // ------------------------------------------------------------------------
168
169 static void
170 usage(const char *progname)
171 {
172   const char *p = strrchr(progname, '/');       // drop leading directory path
173   if (p)
174     p++;
175
176   if (strncmp(p, "lt-", 3) == 0)                // drop lt- libtool prefix
177     p += 3;
178   
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");
191 }
192
193 int
194 main(int argc, char **argv)
195 {
196   // options and their defaults
197   const char *interface = "eth0";
198   const char *mac_addr_str = "";
199   double rx_freq = 0.0;
200   int rx_decim = 5;
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;
206
207   int ch;
208
209   while ((ch = getopt(argc, argv, "he:m:f:d:g:N:o:sv")) != EOF){
210     double tmp;
211     switch (ch){
212
213     case 'e':
214       interface = optarg;
215       break;
216       
217     case 'm':
218       mac_addr_str = optarg;
219       break;
220
221     case 'f':
222       if (!strtod_si(optarg, &rx_freq)) {
223         std::cerr << "invalid number: " << optarg << std::endl;
224         usage(argv[0]);
225         exit(1);
226       }
227       break;
228
229     case 'g':
230       if (!strtod_si(optarg, &rx_gain)) {
231         std::cerr << "invalid number: " << optarg << std::endl;
232         usage(argv[0]);
233         exit(1);
234       }
235       break;
236
237     case 'd':
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;
241         usage(argv[0]);
242         exit(1);
243       }
244       break;
245
246     case 'N':
247       if (!strtod_si(optarg, &tmp)) {
248         std::cerr << "invalid number: " << optarg << std::endl;
249         usage(argv[0]);
250         exit(1);
251       }
252       nsamples = static_cast<uint64_t>(tmp);
253       break;
254       
255     case 's':
256       output_shorts = true;
257       break;
258
259     case 'o':
260       output_filename = optarg;
261       break;
262       
263     case 'v':
264       verbose = true;
265       break;
266
267     case 'h':
268     default:
269       usage(argv[0]);
270       exit(1);
271     }
272   }
273
274
275   install_sig_handler(SIGINT, sig_handler);
276
277   usrp2::rx_nop_handler::sptr handler;
278
279   if (output_filename){
280     if (output_shorts)
281       handler = usrp2::rx_nop_handler::sptr(new complex_16_file_writer(output_filename, nsamples));
282     else
283       handler = usrp2::rx_nop_handler::sptr(new complex_float_file_writer(output_filename, nsamples));
284   }
285   else
286     handler = usrp2::rx_nop_handler::sptr(new usrp2::rx_nop_handler(nsamples));
287
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;
291
292   usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
293   
294   // FIXME in case it was left running...
295   if (!u2->stop_rx_streaming()){
296     fprintf(stderr, "stop_rx_streaming failed\n");
297   }
298
299   if (!u2->set_rx_gain(rx_gain)){
300     fprintf(stderr, "set_rx_gain(%f) failed\n", rx_gain);
301     exit(1);
302   }
303
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);
307     exit(1);
308   }
309
310   if (verbose){
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");
317   }
318   
319   if (!u2->set_rx_decim(rx_decim)) {
320     fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim);
321     exit(1);
322   }
323
324   if (verbose)
325     printf("USRP2 using decimation rate of %d\n", rx_decim);
326     
327   if (!u2->start_rx_streaming(0)){
328     fprintf(stderr, "start_rx_streaming failed\n");
329     exit(1);
330   }
331
332   if (verbose) {
333     if (nsamples > 0)
334         printf("Receiving %zd samples\n\n", nsamples);
335     else
336         printf("Receiving infinite samples\n\n");
337   }
338   
339   struct timeval start, end;
340   gettimeofday(&start, 0);
341
342   while (!signaled && 
343          !handler->has_errored_p() && 
344          !handler->has_finished_p()) {
345     bool ok = u2->rx_samples(0, handler.get());
346     if (!ok){
347       fprintf(stderr, "u2->rx_samples failed\n");
348       return 1;
349     }
350   }
351
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;
358   
359   u2->stop_rx_streaming();
360
361   if (verbose){
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());
369   }
370
371   return 0;
372 }