Remove obsolete app
[debian/gnuradio] / usrp2 / host / apps / bitrot / rx_samples.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007 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 #include "usrp2_basic.h"
23 #include <iostream>
24 #include <complex>
25 #include <getopt.h>
26 #include <string.h>
27 #include "strtod_si.h"
28 #include <signal.h>
29 #include <stdexcept>
30 #include "gri_if_stats.h"
31 #include <gr_realtime.h>
32
33
34 typedef std::complex<float> fcomplex;
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  * Vectorize me!
64  */
65 void
66 convert_samples_to_complex(size_t nsamples,
67                            uint32_t *i_samples,
68                            fcomplex *c_samples)
69 {
70   uint32_t *p = i_samples;
71   for (size_t i = 0; i < nsamples; i++){
72     int16_t  si = ((int16_t) (p[i] >> 16));
73     int16_t  sq = ((int16_t) (p[i] & 0xffff));
74     c_samples[i] = fcomplex((float) si, (float) sq);
75   }
76 }
77
78
79 static void
80 usage(const char *progname)
81 {
82   const char *p = strrchr(progname, '/');       // drop leading directory path
83   if (p)
84     p++;
85
86   if (strncmp(p, "lt-", 3) == 0)                // drop lt- libtool prefix
87     p += 3;
88   
89   fprintf(stderr, "Usage: %s [options]\n\n", p);
90   fprintf(stderr, "Options:\n");
91   fprintf(stderr, "  -h                   show this message and exit\n");
92   fprintf(stderr, "  -e ETH_INTERFACE     specify ethernet interface [default=eth0]\n");
93   fprintf(stderr, "  -m MAC_ADDR          mac address of USRP2 HH:HH [default=first one found]\n");
94   fprintf(stderr, "  -o OUTPUT_FILE       set output filename [default=NONE]\n");
95   fprintf(stderr, "  -f FREQ              set frequency to FREQ [default=0]\n");
96   fprintf(stderr, "  -d DECIM             set decimation rate to DECIM [default=32]\n");
97   fprintf(stderr, "  -N NSAMPLES          total number of samples to receive [default=2.5e6]\n");
98   fprintf(stderr, "  -F SAMPLES_PER_FRAME number of samples in each frame [default=371]\n");
99   fprintf(stderr, "  -S SCALE             fpga scaling factor for I & Q [default=1024]\n");
100   fprintf(stderr, "  -M DONT_LOCK|LOCK_TO_SMA|LOCK_TO_MIMO   specify MIMO clock source\n");
101   fprintf(stderr, "  -P                   provide clock to MIMO connector\n");
102 }
103
104 struct pkt_info {
105   int           d_nsamples;
106   int           d_timestamp;
107   unsigned int  d_seqno;
108
109   pkt_info(int nsamples, int timestamp, int seqno)
110     : d_nsamples(nsamples),
111       d_timestamp(timestamp),
112       d_seqno(seqno) {}
113 };
114
115 int
116 main(int argc, char **argv)
117 {
118
119   // options and their defaults
120   const char *interface = "eth0";
121   const char *mac_addr_str = 0;
122   const char *output_filename = 0;
123   double freq = 0;
124   int32_t decim = 32;
125   int32_t nsamples = static_cast<int32_t>(2.5e6);
126   int32_t samples_per_frame = 371;
127   int32_t scale = 1024;
128   int     mimo_config = MC_WE_DONT_LOCK;
129   bool    provide_clock = false;
130
131   int    ch;
132   double tmp;
133   u2_mac_addr_t mac_addr;
134
135   setvbuf(stdout, 0, _IOFBF, 64 * 1024); // make stdout fully buffered
136
137   while ((ch = getopt(argc, argv, "he:m:o:f:d:N:F:S:M:P")) != EOF){
138     switch (ch){
139
140     case 'e':
141       interface = optarg;
142       break;
143       
144     case 'm':
145       mac_addr_str = optarg;
146       if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
147         std::cerr << "invalid mac addr: " << optarg << std::endl;
148         usage(argv[0]);
149         exit(1);
150       }
151       break;
152
153     case 'o':
154       output_filename = optarg;
155       break;
156       
157     case 'f':
158       if (!strtod_si(optarg, &freq)){
159         std::cerr << "invalid number: " << optarg << std::endl;
160         usage(argv[0]);
161         exit(1);
162       }
163       break;
164
165     case 'N':
166       if (!strtod_si(optarg, &tmp)){
167         std::cerr << "invalid number: " << optarg << std::endl;
168         usage(argv[0]);
169         exit(1);
170       }
171       nsamples = static_cast<int32_t>(tmp);
172       break;
173
174     case 'F':
175       samples_per_frame = strtol(optarg, 0, 0);
176       break;
177
178     case 'd':
179       decim = strtol(optarg, 0, 0);
180       break;
181
182     case 'S':
183       if (!strtod_si(optarg, &tmp)){
184         std::cerr << "invalid number: " << optarg << std::endl;
185         usage(argv[0]);
186         exit(1);
187       }
188       scale = static_cast<int32_t>(tmp);
189       break;
190       
191     case 'M':
192       if (strcmp(optarg, "DONT_LOCK") == 0)
193         mimo_config = MC_WE_DONT_LOCK;
194       else if (strcmp(optarg, "LOCK_TO_SMA") == 0)
195         mimo_config = MC_WE_LOCK_TO_SMA;
196       else if (strcmp(optarg, "LOCK_TO_MIMO") == 0)
197         mimo_config = MC_WE_LOCK_TO_MIMO;
198       else {
199         usage(argv[0]);
200         exit(1);
201       }
202       break;
203
204     case 'P':
205       provide_clock = true;
206       break;
207
208     case 'h':
209     default:
210       usage(argv[0]);
211       exit(1);
212     }
213   }
214   
215   if (argc - optind != 0){
216     usage(argv[0]);
217     exit(1);
218   }
219
220   FILE *of = 0;
221   if (output_filename)
222     of = fopen(output_filename, "wb");
223
224   usrp2_basic *u2 = new usrp2_basic();
225
226   if (!u2->open(interface)){
227     std::cerr << "couldn't open " << interface << std::endl;
228     return 0;
229   }
230
231
232   install_sig_handler(SIGINT, sig_handler);
233   if (1){
234     install_sig_handler(SIGALRM, sig_handler);
235     alarm(5);
236   }
237
238   
239   std::vector<op_id_reply_t> r = u2->find_usrps();
240
241   for (size_t i = 0; i < r.size(); i++){
242     std::cout << r[i] << std::endl;
243   }
244
245   if (r.size() == 0){
246     std::cerr << "No USRP2 found.\n";
247     return 1;
248   }
249
250   u2_mac_addr_t which = r[0].addr;      // pick the first one
251
252
253   gr_rt_status_t rt = gr_enable_realtime_scheduling();
254   if (rt != RT_OK)
255     std::cerr << "failed to enable realtime scheduling\n";
256
257   if (provide_clock)
258     mimo_config |= MC_PROVIDE_CLK_TO_MIMO;
259
260   u2->config_mimo(which, mimo_confg);
261   
262
263   gri_if_stats start, stop;
264   gri_get_if_stats(interface, &start);
265
266   if (!u2->start_rx(which, freq, decim, nsamples, samples_per_frame, scale, scale)){
267     std::cerr << "start_rx failed\n";
268     return 1;
269   }
270
271
272   std::vector<pkt_info> history;
273   history.reserve(64*1024);             // preallocate 64K entries
274
275   
276   long total_samples_recvd = 0;
277
278   while (!signaled && total_samples_recvd < nsamples){
279     u2_eth_samples_t    pkt;
280     // fcomplex         c_samples[U2_MAX_SAMPLES];
281     
282     // read samples
283     int n = u2->read_samples(which, &pkt);
284     if (n <= 0)
285       break;
286     
287     total_samples_recvd += n;
288
289     history.push_back(pkt_info(n, u2p_timestamp(&pkt.hdrs.fixed), pkt.hdrs.thdr.seqno));
290
291     // convert_samples_to_complex(n, pkt.samples, c_samples);
292     // size_t r = fwrite(c_samples, sizeof(fcomplex), n, of);
293
294     if (of){
295       fwrite(pkt.samples, sizeof(uint32_t), n, of);
296       fflush(of);
297     }
298   }
299
300
301   gri_get_if_stats(interface, &stop);
302
303   if (!u2->stop_rx(which)){
304     std::cerr << "stop_rx failed\n";
305     return 1;
306   }
307
308
309   long expected_rx_packets =
310     (nsamples + samples_per_frame - 1)/samples_per_frame;
311
312   long expected_rx_bytes   =
313     expected_rx_packets * sizeof(u2_eth_packet_t) + nsamples * 4;
314
315
316   long total_pkts_recvd = 0;
317   total_samples_recvd = 0;
318
319   int nbad_seqno = 0;
320
321   for (unsigned i = 0; i < history.size(); i++){
322     total_pkts_recvd++;
323     total_samples_recvd += history[i].d_nsamples;
324
325     bool bad_seqno = history[i].d_seqno != (i & 0xff);
326     if (bad_seqno)
327       nbad_seqno++;
328     
329     printf("%3d  %8d  %8ld  %8ld  %3d %s\n",
330            history[i].d_nsamples,
331            history[i].d_timestamp,
332            total_pkts_recvd, total_samples_recvd,
333            history[i].d_seqno,
334            bad_seqno ? "BAD SEQNO" : ""
335            );
336   }
337
338   if (nbad_seqno == 0)
339     printf("\nAll sequence numbers are correct\n");
340   else
341     printf("\n%d sequence numbers were INCORRECT\n", nbad_seqno);
342     
343
344   printf("\nUser space statistics:\n");
345   printf("  rx_samples:  %8ld",     total_samples_recvd);
346   printf("   expected  %8d  %s\n",
347          nsamples,
348          nsamples - total_samples_recvd == 0 ? "OK" : "NOT OK");
349   
350   printf("  rx_packets:  %8ld",     total_pkts_recvd);
351   printf("   expected  %8ld  %s\n",
352          expected_rx_packets,
353          expected_rx_packets - total_pkts_recvd == 0 ? "OK" : "NOT OK");
354   
355
356   fflush(stdout);
357
358   printf("\nKernel interface statistics:\n");
359
360   long long delta;
361   delta = stop.rx_bytes - start.rx_bytes;
362   printf("  rx_bytes:    %8Ld",     delta);
363   printf("   expected  %8ld  %s\n",
364          expected_rx_bytes,
365          expected_rx_bytes - delta == 0 ? "OK" : "NOT OK");
366
367   delta = stop.rx_packets - start.rx_packets;
368   printf("  rx_packets:  %8Ld",     delta);
369   printf("   expected  %8ld  %s\n",
370          expected_rx_packets,
371          expected_rx_packets - delta == 0 ? "OK" : "NOT OK");
372
373   printf("  rx_errs:     %8Ld\n",   stop.rx_errs - start.rx_errs);
374   printf("  rx_drop:     %8Ld\n",   stop.rx_drop - start.rx_drop);
375   printf("  tx_bytes:    %8Ld\n",   stop.tx_bytes - start.tx_bytes);
376   printf("  tx_packets:  %8Ld\n",   stop.tx_packets - start.tx_packets);
377   printf("  tx_errs:     %8Ld\n",   stop.tx_errs - start.tx_errs);
378   printf("  tx_drop:     %8Ld\n",   stop.tx_drop - start.tx_drop);
379
380
381   return 0;
382 }