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