removed gr-vrt
[debian/gnuradio] / vrt / apps / simple_rx_samples.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2009 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <vrt/quadradio.h>
23 #include <vrt/rx.h>
24 #include <vrt/copiers.h>
25
26 #include <errno.h>
27 #include <iostream>
28 #include <boost/scoped_ptr.hpp>
29 #include <boost/shared_ptr.hpp>
30 #include <stdexcept>
31 #include <signal.h>
32 #include <unistd.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <gruel/realtime.h>
37 #include <complex>
38
39 #define MIN_IP_LOCAL_PORT       32768
40 #define MAX_IP_LOCAL_PORT       61000
41
42 static volatile bool signaled = false;
43
44 static void 
45 sig_handler(int sig)
46 {
47   signaled = true;
48 }
49
50 static void
51 install_sig_handler(int signum,
52                     void (*new_handler)(int))
53 {
54   struct sigaction new_action;
55   memset (&new_action, 0, sizeof (new_action));
56
57   new_action.sa_handler = new_handler;
58   sigemptyset (&new_action.sa_mask);
59   new_action.sa_flags = 0;
60
61   if (sigaction (signum, &new_action, 0) < 0){
62     perror ("sigaction (install new)");
63     throw std::runtime_error ("sigaction");
64   }
65 }
66
67 // ------------------------------------------------------------------------
68
69 class rx_nop_handler : public vrt::rx_packet_handler
70 {
71 private:
72   uint64_t      d_max_samples;
73   uint64_t      d_max_quantum;
74   uint64_t      d_nsamples;
75   uint64_t      d_npackets;
76   int           d_last_pkt_cnt;
77   uint64_t      d_nwrong_pkt_cnt;
78
79 protected:
80   bool          d_err;
81
82 public:
83
84   // Shared pointer to an instance of this class
85   typedef boost::shared_ptr<rx_nop_handler> sptr;
86
87   /*!
88    * Constructor
89    *
90    * \param max_samples  Maximum number of samples to copy. Use zero for no maximum.
91    * \param max_quantum  Maximum number of samples required to accept in one call.
92    *                     Use 0 to indicate no maximum.
93    */
94   rx_nop_handler(uint64_t max_samples, uint64_t max_quantum=0)
95     : d_max_samples(max_samples), d_max_quantum(max_quantum),
96       d_nsamples(0), d_npackets(0), 
97       d_last_pkt_cnt(0xf), d_nwrong_pkt_cnt(0),
98       d_err(false){}
99
100     
101     ~rx_nop_handler();
102   
103   bool operator()(const uint32_t *payload,
104                   size_t n32_bit_words,
105                   const vrt::expanded_header *hdr);
106
107   /*!
108    * \brief Returns number of packets this copier was called with
109    */
110   uint64_t npackets() const { return d_npackets; }
111
112   /*!
113    * \brief Returns actual number of samples copied
114    */
115   uint64_t nsamples() const { return d_nsamples; }
116
117   /*!
118    * \brief Returns maximum number of samples that will be copied
119    */
120   uint64_t max_samples() const { return d_max_samples; }
121
122   /*!
123    * Returns true if an error has occurred. Derived classes must set d_err to true
124    * when an error occurs in the () operator
125    */
126   bool has_errored_p() const { return d_err; }
127
128   /*!
129    * \brief Returns true if this instance has reached the maximum number of samples
130    */
131   bool has_finished_p() const 
132   { return d_max_samples == 0 ? false : d_nsamples >= d_max_samples-d_max_quantum; }
133       
134   uint64_t nwrong_pkt_cnt() const { return d_nwrong_pkt_cnt; }
135
136
137 };
138
139
140 rx_nop_handler::~rx_nop_handler()
141 {
142 }
143
144 bool
145 rx_nop_handler::operator()(const uint32_t *payload,
146                            size_t n32_bit_words,
147                            const vrt::expanded_header *hdr)
148 {
149   if (d_npackets != 0 && hdr->pkt_cnt() != ((d_last_pkt_cnt + 1) & 0xf)){
150     d_nwrong_pkt_cnt++;
151     fprintf(stderr, "bad cnt (pkt %lld)\n", d_npackets);
152   }
153   d_last_pkt_cnt = hdr->pkt_cnt();
154
155   d_nsamples += n32_bit_words;
156   d_npackets++;
157
158   return !has_finished_p();
159 }
160
161 // ------------------------------------------------------------------------
162
163 class file_writer_16sc : public rx_nop_handler
164 {
165   FILE         *d_fp;
166   std::string   d_filename;
167   
168 public:
169
170   file_writer_16sc(const std::string &filename, uint64_t max_samples)
171     : rx_nop_handler(max_samples), d_filename(filename)
172   {
173     d_fp = fopen(filename.c_str(), "wb");
174     if (d_fp == 0){
175       perror(filename.c_str());
176       throw std::invalid_argument(filename);
177     }
178   }
179
180   ~file_writer_16sc();
181
182   bool 
183   operator()(const uint32_t *items, size_t nitems, const vrt::expanded_header *hdr)
184   {
185     bool ok = rx_nop_handler::operator()(items, nitems, hdr);
186
187     size_t host_nitems = nitems;
188     std::complex<int16_t> host_items[host_nitems];
189
190     vrt::copy_net_16sc_to_host_16sc(nitems, items, host_items);
191
192     size_t n = 0;
193     while (n < host_nitems){
194       size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
195       n += r;
196       if (r == 0){      // out of space?
197         d_err = true;
198         perror(d_filename.c_str());
199         ok = false;
200         break;
201       }
202     }
203
204     return ok;
205   }
206 };
207
208 file_writer_16sc::~file_writer_16sc()
209 {
210   fclose(d_fp);
211 }
212
213 // ------------------------------------------------------------------------
214
215 class file_writer_32fc : public rx_nop_handler
216 {
217   FILE         *d_fp;
218   std::string   d_filename;
219   
220 public:
221
222   file_writer_32fc(const std::string &filename, uint64_t max_samples)
223     : rx_nop_handler(max_samples), d_filename(filename)
224   {
225     d_fp = fopen(filename.c_str(), "wb");
226     if (d_fp == 0){
227       perror(filename.c_str());
228       throw std::invalid_argument(filename);
229     }
230   }
231
232   ~file_writer_32fc();
233
234   bool 
235   operator()(const uint32_t *items, size_t nitems, const vrt::expanded_header *hdr)
236   {
237     bool ok = rx_nop_handler::operator()(items, nitems, hdr);
238
239     size_t host_nitems = nitems;
240     std::complex<float> host_items[host_nitems];
241
242     vrt::copy_net_16sc_to_host_32fc(nitems, items, host_items);
243
244     size_t n = 0;
245     while (n < host_nitems){
246       size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
247       n += r;
248       if (r == 0){      // out of space?
249         d_err = true;
250         perror(d_filename.c_str());
251         ok = false;
252         break;
253       }
254     }
255
256     return ok;
257   }
258 };
259
260 file_writer_32fc::~file_writer_32fc()
261 {
262   fclose(d_fp);
263 }
264
265 // ------------------------------------------------------------------------
266
267 static void
268 usage(const char *progname)
269 {
270   const char *p = strrchr(progname, '/');       // drop leading directory path
271   if (p)
272     p++;
273
274   if (strncmp(p, "lt-", 3) == 0)                // drop lt- libtool prefix
275     p += 3;
276   
277   fprintf(stderr, "Usage: %s [options]\n\n", p);
278   fprintf(stderr, "Options:\n");
279   fprintf(stderr, "  -h                   show this message and exit\n");
280 //fprintf(stderr, "  -e ETH_INTERFACE     specify ethernet interface [default=eth0]\n");
281 //fprintf(stderr, "  -m MAC_ADDR          mac address of USRP2 HH:HH [default=first one found]\n");
282 //fprintf(stderr, "  -f FREQUENCY         specify receive center frequency in Hz [default=0.0]\n");
283 //fprintf(stderr, "  -d DECIM             specify receive decimation rate [default=5]\n");
284 //fprintf(stderr, "  -g GAIN              specify receive daughterboard gain [default=0]\n");
285   fprintf(stderr, "  -N NSAMPLES          specify number of samples to receive [default=infinite]\n");
286   fprintf(stderr, "  -o OUTPUT_FILENAME   specify file to receive samples [default=none]\n");
287   fprintf(stderr, "  -s                   write complex<short> [default=complex<float>]\n");
288   fprintf(stderr, "  -S samples_per_pkt   specify # of samples per pkt [default=maximum]\n");
289 //fprintf(stderr, "  -v                   verbose output\n");
290 }
291
292
293 int
294 main(int argc, char **argv)
295 {
296   const char *quad_radio_ip = "192.168.123.123";
297   size_t rx_bufsize = 62.5e6;       // sizeof memory mapped network buffer
298   int samples_per_pkt = 0;          // use default
299   uint64_t nsamples = 0;
300   char *output_filename = 0;
301   bool output_shorts = false;
302   int t;
303
304   int ch;
305
306   while ((ch = getopt(argc, argv, "hN:o:sS:")) != EOF){
307     switch (ch){
308     case 'N':
309       nsamples = (uint64_t) strtod(optarg, 0);
310       break;
311
312     case 'o':
313       output_filename = optarg;
314       break;
315
316     case 's':
317       output_shorts = true;
318       break;
319
320     case 'S':
321       errno = 0;
322       t = strtol(optarg, 0, 0);
323       if (errno != 0){
324         usage(argv[0]);
325         exit(1);
326       }
327       samples_per_pkt = t;
328       break;
329
330     case 'h':
331     default:
332       usage(argv[0]);
333       exit(1);
334     }
335   }
336
337
338   install_sig_handler(SIGINT, sig_handler);
339
340   gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
341   if (rt != gruel::RT_OK)
342     std::cerr << "Failed to enable realtime scheduling" << std::endl;
343
344     
345   vrt::quadradio::sptr qr;
346   try {
347     qr = vrt::quadradio::sptr(new vrt::quadradio(quad_radio_ip, rx_bufsize));
348   }
349   catch (...){
350     std::cerr << "Failed to create vrt::quadradio\n";
351     return 1;
352   }
353
354
355   rx_nop_handler::sptr handler;
356   if (output_filename){
357     if (output_shorts)
358       handler = rx_nop_handler::sptr(new file_writer_16sc(output_filename, nsamples));
359     else
360       handler = rx_nop_handler::sptr(new file_writer_32fc(output_filename, nsamples));
361   }
362   else
363     handler = rx_nop_handler::sptr(new rx_nop_handler(nsamples));
364
365
366   printf("samples_per_pkt = %d\n", samples_per_pkt);
367
368   if (!qr->start_streaming(0, samples_per_pkt)){
369     fprintf(stderr, "failed to send_rx_command\n");
370     return 1;
371   }
372
373   // start receiving packets
374
375   while(1
376         && !signaled
377         && !handler->has_errored_p()
378         && !handler->has_finished_p()){
379     bool ok = qr->vrt_rx()->rx_packets(handler.get());
380     if (!ok){
381       fprintf(stderr, "vrt->rx_packets failed\n");
382       break;
383     }
384   }
385
386   qr->stop_streaming(0);
387
388   printf("%llu packets received, %llu bad pkt_cnt field values, %llu samples\n",
389          handler->npackets(), handler->nwrong_pkt_cnt(), handler->nsamples());
390
391   //sleep(1);
392
393   return 0;
394 }