Imported Upstream version 3.2.2
[debian/gnuradio] / usrp2 / host / apps / test_mimo_tx.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2008,2009 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 /*
20  * This is a down and dirty test program that confirms that the we can
21  * coherently transmit different signals to two USRP2s connected via a
22  * mimo cable.  It ignores most of its command line arguments, and
23  * requires that special purpose firmware be installed in the two
24  * USRP2s.  The one connected to the ethernet must be running
25  * mimo_tx.bin The other must be running mimo_tx_slave.bin.
26  *
27  * Don't use this as a model for how s/w should be written :-)
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 #include <usrp2/usrp2.h>
34 #include <usrp2/strtod_si.h>
35 #include <iostream>
36 #include <cstdio>
37 #include <complex>
38 #include <getopt.h>
39 #include <gruel/realtime.h>
40 #include <signal.h>
41 #include <string.h>
42 #include <stdexcept>
43 #include <math.h>
44
45
46 typedef std::complex<float> fcomplex;
47
48 static volatile bool signaled = false;
49
50 void 
51 gen_and_send(usrp2::usrp2::sptr u2, int chan,
52              double *ph, double ph_incr, int nsamples);
53
54
55 static void 
56 sig_handler(int sig)
57 {
58   signaled = true;
59 }
60
61 static void
62 install_sig_handler(int signum,
63                     void (*new_handler)(int))
64 {
65   struct sigaction new_action;
66   memset (&new_action, 0, sizeof (new_action));
67
68   new_action.sa_handler = new_handler;
69   sigemptyset (&new_action.sa_mask);
70   new_action.sa_flags = 0;
71
72   if (sigaction (signum, &new_action, 0) < 0){
73     perror ("sigaction (install new)");
74     throw std::runtime_error ("sigaction");
75   }
76 }
77
78
79 static const char *
80 prettify_progname(const char *progname)         // that's probably almost a word ;)
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   return p;
90 }
91
92 static void
93 usage(const char *progname)
94 {
95   fprintf(stderr, "Usage: %s [options]\n\n", prettify_progname(progname));
96   fprintf(stderr, "Options:\n");
97   fprintf(stderr, "  -h                   show this message and exit\n");
98   fprintf(stderr, "  -e ETH_INTERFACE     specify ethernet interface [default=eth0]\n");
99   fprintf(stderr, "  -m MAC_ADDR          mac address of USRP2 HH:HH [default=first one found]\n");
100   fprintf(stderr, "  -I INPUT_FILE        set input filename [default=stdin]\n");
101   fprintf(stderr, "  -r                   repeat.  When EOF of input file is reached, seek to beginning\n");
102   fprintf(stderr, "  -f FREQ              set frequency to FREQ [default=0]\n");
103   fprintf(stderr, "  -i INTERP            set interpolation rate to INTERP [default=32]\n");
104   fprintf(stderr, "  -g gain              set tx gain\n");
105   fprintf(stderr, "  -S SCALE             fpga scaling factor for I & Q [default=256]\n");
106 }
107
108 #define GAIN_NOT_SET (-1000)
109 #define MAX_SAMPLES (371)
110
111 int
112 main(int argc, char **argv)
113 {
114   const char *interface = "eth0";
115   const char *input_filename = 0;
116   bool repeat = false;
117   const char *mac_addr_str = "";
118   double freq = 0;
119   int32_t interp = 32;
120   int32_t samples_per_frame = MAX_SAMPLES;
121   int32_t scale = -1;
122   double gain = GAIN_NOT_SET;
123   
124   int    ch;
125   double tmp;
126
127
128   while ((ch = getopt(argc, argv, "he:m:I:rf:i:S:F:g:")) != EOF){
129     switch (ch){
130
131     case 'e':
132       interface = optarg;
133       break;
134       
135     case 'm':
136       mac_addr_str = optarg;
137 #if 0
138       if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
139         std::cerr << "invalid mac addr: " << optarg << std::endl;
140         usage(argv[0]);
141         return 1;
142       }
143 #endif
144       break;
145
146     case 'I':
147       input_filename = optarg;
148       break;
149       
150     case 'r':
151       repeat = true;
152       break;
153       
154     case 'f':
155       if (!strtod_si(optarg, &freq)){
156         std::cerr << "invalid number: " << optarg << std::endl;
157         usage(argv[0]);
158         return 1;
159       }
160       break;
161
162     case 'F':
163       samples_per_frame = strtol(optarg, 0, 0);
164       break;
165
166     case 'i':
167       interp = strtol(optarg, 0, 0);
168       break;
169
170     case 'S':
171       if (!strtod_si(optarg, &tmp)){
172         std::cerr << "invalid number: " << optarg << std::endl;
173         usage(argv[0]);
174         return 1;
175       }
176       scale = static_cast<int32_t>(tmp);
177       break;
178       
179     case 'h':
180     default:
181       usage(argv[0]);
182       return 1;
183     }
184   }
185
186   
187   if (argc - optind != 0){
188     usage(argv[0]);
189     return 1;
190   }
191   
192   if (samples_per_frame < 9 || samples_per_frame > MAX_SAMPLES){
193     std::cerr << prettify_progname(argv[0])
194               << ": samples_per_frame is out of range.  "
195               << "Must be in [9, " << MAX_SAMPLES << "].\n";
196     usage(argv[0]);
197     return 1;
198   }
199
200
201   FILE *fp = 0;
202   if (input_filename == 0)
203     fp = stdin;
204   else {
205     fp = fopen(input_filename, "rb");
206     if (fp == 0){
207       perror(input_filename);
208       return 1;
209     }
210   }
211
212   install_sig_handler(SIGINT, sig_handler);
213
214
215   gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
216   if (rt != gruel::RT_OK)
217     std::cerr << "Failed to enable realtime scheduling" << std::endl;
218
219
220   usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
221   
222 #if 0
223   if (gain != GAIN_NOT_SET){
224     if (!u2->set_tx_gain(gain)){
225       std::cerr << "set_tx_gain failed\n";
226       return 1;
227     }
228   }
229
230   usrp2::tune_result tr;
231   if (!u2->set_tx_center_freq(freq, &tr)){
232     fprintf(stderr, "set_tx_center_freq(%g) failed\n", freq);
233     return 1;
234   }
235
236   printf("Daughterboard configuration:\n");
237   printf("  baseband_freq=%f\n", tr.baseband_freq);
238   printf("       duc_freq=%f\n", tr.dxc_freq);
239   printf("  residual_freq=%f\n", tr.residual_freq);
240   printf("       inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
241
242   if (!u2->set_tx_interp(interp)){
243     fprintf(stderr, "set_tx_interp(%d) failed\n", interp);
244     return 1;
245   }
246
247   if (scale != -1){
248     if (!u2->set_tx_scale_iq(scale, scale)){
249       std::cerr << "set_tx_scale_iq failed\n";
250       return 1;
251     }
252   }
253 #endif
254
255   double baseband_rate = 100e6 / 32;
256
257   double ph0 = 0;
258   double ph1 = 0;
259
260   double ph0_incr = 7.5e3/baseband_rate * 2 * M_PI;
261   double ph1_incr = 7.5e3/baseband_rate * 2 * M_PI;
262
263   while (!signaled){
264
265     gen_and_send(u2, 0, &ph0, ph0_incr, samples_per_frame);
266     gen_and_send(u2, 1, &ph1, ph1_incr, samples_per_frame);
267
268   }
269
270   return 0;
271 }
272
273 void
274 gen_and_send(usrp2::usrp2::sptr u2, int chan,
275              double *ph_ptr, double ph_incr, int nsamples)
276 {
277   double ph = *ph_ptr;
278   
279   std::complex<float>   buf[MAX_SAMPLES];
280
281   usrp2::tx_metadata    md;
282   md.timestamp = -1;
283   md.start_of_burst = 1;
284   md.send_now = 1;
285
286   float ampl;
287
288   if (chan == 0)
289     ampl = 0.5;
290   else
291     ampl = 0.75;
292
293
294   for (int i = 0; i < nsamples; i++){
295 #if 0
296     float s, c;
297     sincosf((float) ph, &s, &c);
298     buf[i] = std::complex<float>(s * ampl, c * ampl);
299     ph += ph_incr;
300 #else
301     buf[i] = std::complex<float>(ampl, 0);
302 #endif
303   }
304
305   if (!u2->tx_32fc(chan, buf, nsamples, &md)){
306     fprintf(stderr, "tx_32fc failed\n");
307   }
308
309   ph = fmod(ph, 2*M_PI);
310   *ph_ptr = ph;
311 }