Merge branch 'dfsg-orig'
[debian/gnuradio] / usrp / host / apps / test_usrp_standard_tx.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2003,2004,2008,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
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 <iostream>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <getopt.h>
33 #include <assert.h>
34 #include <math.h>
35 #include "time_stuff.h"
36 #include <usrp/usrp_standard.h>
37 #include <usrp/usrp_bytesex.h>
38 #include <boost/program_options.hpp>
39
40 enum {
41   GR_SIN_WAVE,
42   GR_CONST_WAVE
43 };
44
45 namespace po = boost::program_options;
46
47 char *prog_name;
48
49 usrp_subdev_spec
50 str_to_subdev(std::string spec_str)
51 {
52   usrp_subdev_spec spec;
53   if(spec_str == "A" || spec_str == "A:0" || spec_str == "0:0") {
54     spec.side = 0;
55     spec.subdev = 0;
56   }
57   else if(spec_str == "A:1" || spec_str == "0:1") {
58     spec.side = 0;
59     spec.subdev = 1;
60   }
61   else if(spec_str == "B" || spec_str == "B:0" || spec_str == "1:0") {
62     spec.side = 1;
63     spec.subdev = 0;
64   }
65   else if(spec_str == "B:1" || spec_str == "1:1") {
66     spec.side = 1;
67     spec.subdev = 1;
68   }
69   else {
70     throw std::range_error("Incorrect subdevice specifications.\n");
71   }
72
73   return spec;
74 }
75
76
77 static void
78 set_progname (char *path)
79 {
80   char *p = strrchr (path, '/');
81   if (p != 0)
82     prog_name = p+1;
83   else
84     prog_name = path;
85 }
86
87 static void
88 die (const char *msg)
89 {
90   fprintf (stderr, "die: %s: %s\n", prog_name, msg);
91   exit (1);
92 }
93
94
95 static bool
96 test_output (usrp_standard_tx_sptr utx, long long max_bytes, double ampl, int waveform)
97 {
98   const int BUFSIZE = utx->block_size();
99   const int N = BUFSIZE/sizeof (short);
100
101   short         buf[N];
102   long long     nbytes = 0;
103
104   // ----------------------------------------------------------------
105   // one time initialization of the pattern we're going to transmit
106
107   const int     PERIOD = 65;            // any value is valid
108   const int     PATLEN = 2 * PERIOD;    
109   short         pattern[PATLEN];
110
111   for (int i = 0; i < PERIOD; i++){
112     if (waveform == GR_CONST_WAVE){
113       pattern[2*i+0] = host_to_usrp_short((short) ampl);
114       pattern[2*i+1] = host_to_usrp_short((short) 0);
115     }
116     else {
117       pattern[2*i+0] = host_to_usrp_short((short) (ampl * cos(2*M_PI * i / PERIOD)));
118       pattern[2*i+1] = host_to_usrp_short((short) (ampl * sin(2*M_PI * i / PERIOD)));
119     }
120   }
121
122   // ----------------------------------------------------------------
123
124   double start_wall_time = get_elapsed_time ();
125   double start_cpu_time  = get_cpu_usage ();
126
127   bool  underrun;
128   int   nunderruns = 0;
129   int   pi = 0;
130
131   for (nbytes = 0; max_bytes == 0 || nbytes < max_bytes; nbytes += BUFSIZE){
132
133     for (int i = 0; i < N; i++){
134       buf[i] = pattern[pi];
135       pi++;
136       if (pi >= PATLEN)
137         pi = 0;
138     }
139
140     int ret = utx->write (buf, sizeof (buf), &underrun);
141     if ((unsigned) ret != sizeof (buf)){
142       fprintf (stderr, "test_output: error, ret = %d\n", ret);
143     }
144
145     if (underrun){
146       nunderruns++;
147       printf ("tx_underrun\n");
148       //printf ("tx_underrun %9d %6d\n", nbytes, nbytes/BUFSIZE);
149     }
150   }
151
152   utx->wait_for_completion ();
153
154   double stop_wall_time = get_elapsed_time ();
155   double stop_cpu_time  = get_cpu_usage ();
156
157   double delta_wall = stop_wall_time - start_wall_time;
158   double delta_cpu  = stop_cpu_time  - start_cpu_time;
159
160   printf ("xfered %.3g bytes in %.3g seconds.  %.4g bytes/sec.  cpu time = %.3g\n",
161           (double) max_bytes, delta_wall, max_bytes / delta_wall, delta_cpu);
162
163   printf ("%d underruns\n", nunderruns);
164
165   return true;
166 }
167
168 int
169 main (int argc, char **argv)
170 {
171   int which = 0;                       // specify which USRP board
172   usrp_subdev_spec spec(0,0);          // specify the d'board side
173   int interp = 16;                     // set the interpolation rate
174   double rf_freq = -1;                 // set the frequency
175   float amp = 10000;                   // set the amplitude of the output
176   float gain = -1;                     // set the d'board PGA gain
177   int waveform;
178   int   fusb_block_size = 0;
179   int   fusb_nblocks = 0;
180   bool  realtime_p = false;
181   double nsamples = 32e6;
182
183   set_progname (argv[0]);
184
185   po::options_description cmdconfig("Program options");
186   cmdconfig.add_options()
187     ("help,h", "produce help message")
188     ("which,W", po::value<int>(&which), "select which USRP board")
189     ("tx-subdev-spec,T", po::value<std::string>(), "select USRP Tx side A or B")
190     ("rf-freq,f", po::value<double>(), "set RF center frequency to FREQ")
191     ("interp,i", po::value<int>(&interp), "set fgpa interpolation rate to INTERP")
192
193     ("sine", "generate a complex sinusoid [default]")
194     ("const", "generate a constant output")
195
196     //("waveform-freq,w", po::value<double>(&wfreq), "set waveform frequency to FREQ")
197     ("amplitude,a", po::value<float>(&amp), "set amplitude")
198     ("gain,g", po::value<float>(&gain), "set output gain to GAIN [default=MAX]")
199     //("offset,o", po::value<float>(&offset), "set waveform offset to OFFSET")
200     ("nsamples,N", po::value<double>(&nsamples), "number of samples to send [default=32M]")
201     ;
202   
203   po::variables_map vm;
204   po::store(po::command_line_parser(argc, argv).
205             options(cmdconfig).run(), vm);
206   po::notify(vm);
207   
208   if (vm.count("help")) {
209     std::cout << cmdconfig << "\n";
210     return 1;
211   }
212   
213   if(vm.count("tx-subdev-spec")) {
214     std::string s = vm["tx-subdev-spec"].as<std::string>();
215     spec = str_to_subdev(s);
216   }
217
218   if(vm.count("sine")) {
219     waveform = GR_SIN_WAVE;
220   }
221   else if(vm.count("const")) {
222     waveform = GR_CONST_WAVE;
223   }
224   else {
225     waveform = GR_SIN_WAVE;
226   }
227
228   printf("which:    %d\n", which);
229   printf("interp:   %d\n", interp);
230   printf("rf_freq:  %g\n", rf_freq);
231   printf("amp:      %f\n", amp);
232   printf("nsamples: %g\n", nsamples);
233
234
235   if (realtime_p){
236     // FIXME
237   }
238
239   usrp_standard_tx_sptr utx;
240
241   utx = usrp_standard_tx::make (which,
242                                 interp,
243                                 1,      // nchan
244                                 -1,     // mux
245                                 fusb_block_size,
246                                 fusb_nblocks);
247
248   if (utx == 0)
249     die ("usrp_standard_tx::make");
250
251   // FIXME
252
253   db_base_sptr subdev = utx->selected_subdev(spec);
254   printf("Subdevice name is %s\n", subdev->name().c_str());
255   printf("Subdevice freq range: (%g, %g)\n", 
256          subdev->freq_min(), subdev->freq_max());
257
258   unsigned int mux = utx->determine_tx_mux_value(spec);
259   printf("mux: %#08x\n",  mux);
260   utx->set_mux(mux);
261
262   if(gain == -1)
263     gain = subdev->gain_max();
264   subdev->set_gain(gain);
265
266   float input_rate = utx->dac_rate() / utx->interp_rate();
267   printf("baseband rate: %g\n",  input_rate);
268
269   usrp_tune_result r;
270
271   if (rf_freq < 0)
272     rf_freq = (subdev->freq_min() + subdev->freq_max()) * 0.5;
273   double target_freq = rf_freq;
274   bool ok = utx->tune(subdev->which(), subdev, target_freq, &r);
275
276   if(!ok) {
277     throw std::runtime_error("Could not set frequency.");
278   }
279
280   subdev->set_enable(true);
281   
282   printf("target_freq:     %f\n", target_freq);
283   printf("ok:              %s\n", ok ? "true" : "false");
284   printf("r.baseband_freq: %f\n", r.baseband_freq);
285   printf("r.dxc_freq:      %f\n", r.dxc_freq);
286   printf("r.residual_freq: %f\n", r.residual_freq);
287   printf("r.inverted:      %d\n", r.inverted);
288
289
290   fflush (stdout);
291   fflush (stderr);
292
293   utx->start();         // start data xfers
294
295   test_output (utx, (long long) nsamples, amp, waveform);
296
297   return 0;
298 }  
299
300
301 #if 0
302     case 'B':
303       fusb_block_size = strtol (optarg, 0, 0);
304       break;
305
306     case 'N':
307       fusb_nblocks = strtol (optarg, 0, 0);
308       break;
309
310     case 'R':
311       realtime_p = true;
312       break;
313
314 #endif