Imported Upstream version 3.0.4
[debian/gnuradio] / usrp / host / apps / test_usrp_standard_tx.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2003,2004 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
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <usb.h>                        /* needed for usb functions */
32 #include <getopt.h>
33 #include <assert.h>
34 #include <math.h>
35 #include "time_stuff.h"
36 #include "usrp_standard.h"
37 #include "usrp_bytesex.h"
38
39 #ifdef HAVE_SCHED_H
40 #include <sched.h>
41 #endif
42
43 char *prog_name;
44
45 static bool test_output (usrp_standard_tx *utx, int max_bytes, double ampl,
46                          bool dc_p, bool counting_p);
47
48 static void
49 set_progname (char *path)
50 {
51   char *p = strrchr (path, '/');
52   if (p != 0)
53     prog_name = p+1;
54   else
55     prog_name = path;
56 }
57
58 static void
59 usage ()
60 {
61   fprintf (stderr, 
62            "usage: %s [-f] [-v] [-d] [-c] [-a <ampl>][-I <interp>] [-F freq] [-D]\n", prog_name);
63   fprintf (stderr, "  [-f] loop forever\n");
64   fprintf (stderr, "  [-M] how many Megabytes to transfer (default 128)\n");
65   fprintf (stderr, "  [-v] verbose\n");
66   fprintf (stderr, "  [-d] dump registers\n");
67   // fprintf (stderr, "  [-l] digital loopback in FPGA\n");
68   fprintf (stderr, "  [-c] Tx counting sequence\n");
69   fprintf (stderr, "  [-D] DC output\n");
70
71   fprintf (stderr, "  [-B <fusb_block_size>] set fast usb block_size\n");
72   fprintf (stderr, "  [-N <fusb_nblocks>] set fast usb nblocks\n");
73   fprintf (stderr, "  [-R] set real time scheduling: SCHED_FIFO; pri = midpoint\n");
74
75   exit (1);
76 }
77
78 static void
79 die (const char *msg)
80 {
81   fprintf (stderr, "die: %s: %s\n", prog_name, msg);
82   exit (1);
83 }
84
85 static void
86 dump_codec_regs (usrp_basic *u, int which_codec, FILE *fp)
87 {
88   for (int i = 0; i < 64; i++){
89     unsigned char v;
90     u->_read_9862 (which_codec, i, &v);
91     fprintf (fp, "%2d:  0x%02x\n", i, v); 
92   }
93   fflush (fp);
94 }
95
96 static void
97 do_dump_codec_regs (usrp_basic *u)
98 {
99   char name[100];
100   strcpy (name, "regsXXXXXX");
101   int fd = mkstemp (name);
102   if (fd == -1){
103     perror (name);
104   }
105   else {
106     FILE *fp = fdopen (fd, "w");
107     dump_codec_regs (u, 0, fp);
108     fclose (fp);
109   }
110 }
111
112 int
113 main (int argc, char **argv)
114 {
115   bool  verbose_p = false;
116   bool  dump_regs_p = false;
117   bool  dc_p = false;
118   // bool  loopback_p = false;
119   bool  counting_p = false;
120   int   max_bytes = 128 * (1L << 20);
121   int   ch;
122   int   which_board = 0;
123   int   interp = 16;                    // 32.0 MB/sec 
124   double        center_freq = 0;
125   double        ampl = 10000;
126   int   fusb_block_size = 0;
127   int   fusb_nblocks = 0;
128   bool  realtime_p = false;
129
130
131   set_progname (argv[0]);
132
133   while ((ch = getopt (argc, argv, "vfdcI:F:a:DM:B:N:R")) != EOF){
134     switch (ch){
135     case 'f':
136       max_bytes = 0;
137       break;
138
139     case 'v':
140       verbose_p = true;
141       break;
142
143     case 'd':
144       dump_regs_p = true;
145       break;
146       
147     case 'D':
148       dc_p = true;
149       break;
150       
151 #if 0
152     case 'l':
153       loopback_p = true;
154       break;
155 #endif
156       
157     case 'c':
158       counting_p = true;
159       break;
160       
161     case 'I':
162       interp = strtol (optarg, 0, 0);
163       break;
164                       
165     case 'F':
166       center_freq = strtod (optarg, 0);
167       break;
168       
169     case 'a':
170       ampl = strtod (optarg, 0);
171       break;
172
173     case 'M':
174       max_bytes = strtol (optarg, 0, 0) * (1L << 20);
175       if (max_bytes < 0) max_bytes = 0;
176       break;
177
178     case 'B':
179       fusb_block_size = strtol (optarg, 0, 0);
180       break;
181
182     case 'N':
183       fusb_nblocks = strtol (optarg, 0, 0);
184       break;
185
186     case 'R':
187       realtime_p = true;
188       break;
189
190     default:
191       usage ();
192     }
193   }
194
195 #ifdef HAVE_SCHED_SETSCHEDULER
196   if (realtime_p){
197     int policy = SCHED_FIFO;
198     int pri = (sched_get_priority_max (policy) - sched_get_priority_min (policy)) / 2;
199     int pid = 0;  // this process
200
201     struct sched_param param;
202     memset(&param, 0, sizeof(param));
203     param.sched_priority = pri;
204     int result = sched_setscheduler(pid, policy, &param);
205     if (result != 0){
206       perror ("sched_setscheduler: failed to set real time priority");
207     }
208     else
209       printf("SCHED_FIFO enabled with priority = %d\n", pri);
210   }
211 #endif
212
213   usrp_standard_tx *utx;
214
215   utx = usrp_standard_tx::make (which_board,
216                                 interp,
217                                 1,      // nchan
218                                 -1,     // mux
219                                 fusb_block_size,
220                                 fusb_nblocks);
221
222   if (utx == 0)
223     die ("usrp_standard_tx::make");
224     
225   if (!utx->set_tx_freq (0, center_freq))
226     die ("utx->set_tx_freq");
227     
228   if (dump_regs_p)
229     do_dump_codec_regs (utx);
230   
231   
232   fflush (stdout);
233   fflush (stderr);
234
235   utx->start();         // start data xfers
236
237   test_output (utx, max_bytes, ampl, dc_p, counting_p);
238
239   delete utx;
240
241   return 0;
242 }
243
244
245 static bool
246 test_output (usrp_standard_tx *utx, int max_bytes, double ampl,
247              bool dc_p, bool counting_p)
248 {
249   static const int BUFSIZE = utx->block_size();
250   static const int N = BUFSIZE/sizeof (short);
251
252   short            buf[N];
253   int              nbytes = 0;
254   int              counter = 0;
255
256   static const int    PERIOD = 65;              // any value is valid
257   static const int    PATLEN = 2 * PERIOD;      
258   short               pattern[PATLEN];
259
260   for (int i = 0; i < PERIOD; i++){
261     if (dc_p){
262       pattern[2*i+0] = host_to_usrp_short ((short) ampl);
263       pattern[2*i+1] = host_to_usrp_short ((short) 0);
264     }
265     else {
266       pattern[2*i+0] = host_to_usrp_short ((short) (ampl * cos (2*M_PI * i / PERIOD)));
267       pattern[2*i+1] = host_to_usrp_short ((short) (ampl * sin (2*M_PI * i / PERIOD)));
268     }
269   }
270
271   double           start_wall_time = get_elapsed_time ();
272   double           start_cpu_time  = get_cpu_usage ();
273
274   bool  underrun;
275   int   nunderruns = 0;
276   int   pi = 0;
277
278   for (nbytes = 0; max_bytes == 0 || nbytes < max_bytes; nbytes += BUFSIZE){
279
280     if (counting_p){
281       for (int i = 0; i < N; i++)
282         buf[i] = host_to_usrp_short (counter++ & 0xffff);
283     }
284     else {
285       for (int i = 0; i < N; i++){
286         buf[i] = pattern[pi];
287         pi++;
288         if (pi >= PATLEN)
289           pi = 0;
290       }
291     }
292
293     int ret = utx->write (buf, sizeof (buf), &underrun);
294     if ((unsigned) ret != sizeof (buf)){
295       fprintf (stderr, "test_output: error, ret = %d\n", ret);
296     }
297
298     if (underrun){
299       nunderruns++;
300       printf ("tx_underrun\n");
301       //printf ("tx_underrun %9d %6d\n", nbytes, nbytes/BUFSIZE);
302     }
303   }
304
305   utx->wait_for_completion ();
306
307   double stop_wall_time = get_elapsed_time ();
308   double stop_cpu_time  = get_cpu_usage ();
309
310   double delta_wall = stop_wall_time - start_wall_time;
311   double delta_cpu  = stop_cpu_time  - start_cpu_time;
312
313   printf ("xfered %.3g bytes in %.3g seconds.  %.4g bytes/sec.  cpu time = %.3g\n",
314           (double) max_bytes, delta_wall, max_bytes / delta_wall, delta_cpu);
315
316   printf ("%d underruns\n", nunderruns);
317
318   return true;
319 }