Imported Upstream version 3.2.2
[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 <cstdio>
31 #include <string.h>
32 #include <boost/scoped_ptr.hpp>
33 #include <boost/shared_ptr.hpp>
34 #include <stdexcept>
35 #include <signal.h>
36
37 static volatile bool signaled = false;
38
39 static void 
40 sig_handler(int sig)
41 {
42   signaled = true;
43 }
44
45 static void
46 install_sig_handler(int signum,
47                     void (*new_handler)(int))
48 {
49   struct sigaction new_action;
50   memset (&new_action, 0, sizeof (new_action));
51
52   new_action.sa_handler = new_handler;
53   sigemptyset (&new_action.sa_mask);
54   new_action.sa_flags = 0;
55
56   if (sigaction (signum, &new_action, 0) < 0){
57     perror ("sigaction (install new)");
58     throw std::runtime_error ("sigaction");
59   }
60 }
61
62 // ------------------------------------------------------------------------
63
64 // FIXME make this a template
65
66 class file_writer_16sc : public usrp2::rx_nop_handler
67 {
68   FILE         *d_fp;
69   std::string   d_filename;
70   
71 public:
72
73   file_writer_16sc(const std::string &filename, uint64_t max_samples)
74     : usrp2::rx_nop_handler(max_samples), d_filename(filename)
75   {
76     d_fp = fopen(filename.c_str(), "wb");
77     if (d_fp == 0){
78       perror(filename.c_str());
79       throw std::invalid_argument(filename);
80     }
81   }
82
83   ~file_writer_16sc();
84
85   bool 
86   operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
87   {
88     bool ok = rx_nop_handler::operator()(items, nitems, metadata);
89
90     size_t host_nitems = nitems;
91     std::complex<int16_t> host_items[host_nitems];
92
93     usrp2::copy_u2_16sc_to_host_16sc(nitems, items, host_items);
94
95     size_t n = 0;
96     while (n < host_nitems){
97       size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
98       n += r;
99       if (r == 0){      // out of space?
100         d_err = true;
101         perror(d_filename.c_str());
102         ok = false;
103         break;
104       }
105     }
106
107     return ok;
108   }
109 };
110
111 file_writer_16sc::~file_writer_16sc()
112 {
113   fclose(d_fp);
114 }
115
116 // ------------------------------------------------------------------------
117
118 class file_writer_32fc : public usrp2::rx_nop_handler
119 {
120   FILE         *d_fp;
121   std::string   d_filename;
122   
123 public:
124
125   file_writer_32fc(const std::string &filename, uint64_t max_samples)
126     : usrp2::rx_nop_handler(max_samples), d_filename(filename)
127   {
128     d_fp = fopen(filename.c_str(), "wb");
129     if (d_fp == 0){
130       perror(filename.c_str());
131       throw std::invalid_argument(filename);
132     }
133   }
134
135   ~file_writer_32fc();
136
137   bool 
138   operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
139   {
140     bool ok = rx_nop_handler::operator()(items, nitems, metadata);
141
142     size_t host_nitems = nitems;
143     std::complex<float> host_items[host_nitems];
144
145     usrp2::copy_u2_16sc_to_host_32fc(nitems, items, host_items);
146
147     size_t n = 0;
148     while (n < host_nitems){
149       size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
150       n += r;
151       if (r == 0){      // out of space?
152         d_err = true;
153         perror(d_filename.c_str());
154         ok = false;
155         break;
156       }
157     }
158
159     return ok;
160   }
161 };
162
163 file_writer_32fc::~file_writer_32fc()
164 {
165   fclose(d_fp);
166 }
167
168 // ------------------------------------------------------------------------
169
170 static void
171 usage(const char *progname)
172 {
173   const char *p = strrchr(progname, '/');       // drop leading directory path
174   if (p)
175     p++;
176
177   if (strncmp(p, "lt-", 3) == 0)                // drop lt- libtool prefix
178     p += 3;
179   
180   fprintf(stderr, "Usage: %s [options]\n\n", p);
181   fprintf(stderr, "Options:\n");
182   fprintf(stderr, "  -h                   show this message and exit\n");
183   fprintf(stderr, "  -e ETH_INTERFACE     specify ethernet interface [default=eth0]\n");
184   fprintf(stderr, "  -m MAC_ADDR          mac address of USRP2 HH:HH [default=first one found]\n");
185   fprintf(stderr, "  -f FREQUENCY         specify receive center frequency in Hz [default=0.0]\n");
186   fprintf(stderr, "  -d DECIM             specify receive decimation rate [default=5]\n");
187   fprintf(stderr, "  -g GAIN              specify receive daughterboard gain [default=0]\n");
188   fprintf(stderr, "  -N NSAMPLES          specify number of samples to receive [default=infinite]\n");
189   fprintf(stderr, "  -o OUTPUT_FILENAME   specify file to receive samples [default=none]\n");
190   fprintf(stderr, "  -s                   write complex<short> [default=complex<float>]\n");
191   fprintf(stderr, "  -v                   verbose output\n");
192 }
193
194 int
195 main(int argc, char **argv)
196 {
197   // options and their defaults
198   const char *interface = "eth0";
199   const char *mac_addr_str = "";
200   double rx_freq = 0.0;
201   int rx_decim = 5;
202   double rx_gain = 0.0;
203   uint64_t nsamples = 0;
204   bool output_shorts = false;
205   char *output_filename = 0;
206   bool verbose = false;
207
208   int ch;
209
210   while ((ch = getopt(argc, argv, "he:m:f:d:g:N:o:sv")) != EOF){
211     double tmp;
212     switch (ch){
213
214     case 'e':
215       interface = optarg;
216       break;
217       
218     case 'm':
219       mac_addr_str = optarg;
220       break;
221
222     case 'f':
223       if (!strtod_si(optarg, &rx_freq)) {
224         std::cerr << "invalid number: " << optarg << std::endl;
225         usage(argv[0]);
226         exit(1);
227       }
228       break;
229
230     case 'g':
231       if (!strtod_si(optarg, &rx_gain)) {
232         std::cerr << "invalid number: " << optarg << std::endl;
233         usage(argv[0]);
234         exit(1);
235       }
236       break;
237
238     case 'd':
239       rx_decim = strtol(optarg, 0, 0);
240       if (rx_decim < 4 or rx_decim > 512) { 
241         std::cerr << "invalid decimation rate: " << optarg << std::endl;
242         usage(argv[0]);
243         exit(1);
244       }
245       break;
246
247     case 'N':
248       if (!strtod_si(optarg, &tmp)) {
249         std::cerr << "invalid number: " << optarg << std::endl;
250         usage(argv[0]);
251         exit(1);
252       }
253       nsamples = static_cast<uint64_t>(tmp);
254       break;
255       
256     case 's':
257       output_shorts = true;
258       break;
259
260     case 'o':
261       output_filename = optarg;
262       break;
263       
264     case 'v':
265       verbose = true;
266       break;
267
268     case 'h':
269     default:
270       usage(argv[0]);
271       exit(1);
272     }
273   }
274
275
276   install_sig_handler(SIGINT, sig_handler);
277
278   usrp2::rx_nop_handler::sptr handler;
279
280   if (output_filename){
281     if (output_shorts)
282       handler = usrp2::rx_nop_handler::sptr(new file_writer_16sc(output_filename, nsamples));
283     else
284       handler = usrp2::rx_nop_handler::sptr(new file_writer_32fc(output_filename, nsamples));
285   }
286   else
287     handler = usrp2::rx_nop_handler::sptr(new usrp2::rx_nop_handler(nsamples));
288
289   gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
290   if (rt != gruel::RT_OK)
291     std::cerr << "Failed to enable realtime scheduling" << std::endl;
292
293   usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
294   
295   // FIXME in case it was left running...
296   if (!u2->stop_rx_streaming()){
297     fprintf(stderr, "stop_rx_streaming failed\n");
298   }
299
300   if (!u2->set_rx_gain(rx_gain)){
301     fprintf(stderr, "set_rx_gain(%f) failed\n", rx_gain);
302     exit(1);
303   }
304
305   usrp2::tune_result tr;
306   if (!u2->set_rx_center_freq(rx_freq, &tr)){
307     fprintf(stderr, "set_rx_center_freq(%g) failed\n", rx_freq);
308     exit(1);
309   }
310
311   if (verbose){
312     printf("USRP2 MAC address: %s\n\n", u2->mac_addr().c_str());
313     printf("Daughterboard configuration:\n");
314     printf("  baseband_freq=%f\n", tr.baseband_freq);
315     printf("       ddc_freq=%f\n", tr.dxc_freq);
316     printf("  residual_freq=%f\n", tr.residual_freq);
317     printf("       inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
318   }
319   
320   if (!u2->set_rx_decim(rx_decim)) {
321     fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim);
322     exit(1);
323   }
324
325   if (verbose)
326     printf("USRP2 using decimation rate of %d\n", rx_decim);
327     
328   if (!u2->start_rx_streaming(0)){
329     fprintf(stderr, "start_rx_streaming failed\n");
330     exit(1);
331   }
332
333   if (verbose) {
334     if (nsamples > 0)
335         printf("Receiving %zd samples\n\n", nsamples);
336     else
337         printf("Receiving infinite samples\n\n");
338   }
339   
340   struct timeval start, end;
341   gettimeofday(&start, 0);
342
343   while (!signaled && 
344          !handler->has_errored_p() && 
345          !handler->has_finished_p()) {
346     bool ok = u2->rx_samples(0, handler.get());
347     if (!ok){
348       fprintf(stderr, "u2->rx_samples failed\n");
349       return 1;
350     }
351   }
352
353   gettimeofday(&end, 0);
354   long n_usecs = end.tv_usec-start.tv_usec;
355   long n_secs = end.tv_sec-start.tv_sec;
356   double elapsed = (double)n_secs + (double)n_usecs*1e-6;
357   double mbs = handler->nsamples()*sizeof(uint32_t)/elapsed/1e6;
358   double pps = handler->nframes()/elapsed;
359   
360   u2->stop_rx_streaming();
361
362   if (verbose){
363     printf("\nCopy handler called %li times.\n", handler->nframes());
364     printf("Copy handler called with %li bytes.\n\n", handler->nsamples()*sizeof(uint32_t));
365     printf("Elapsed time was %5.3f seconds.\n", elapsed);
366     printf("Packet rate was %1.0f pkts/sec.\n", pps);
367     printf("Approximate throughput was %5.2f MB/sec.\n", mbs);
368     printf("Total instances of overruns was %d.\n", u2->rx_overruns());
369     printf("Total missing frames was %d.\n", u2->rx_missing());
370   }
371
372   return 0;
373 }