3 * Copyright 2007,2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
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.
27 * Don't use this as a model for how s/w should be written :-)
33 #include <usrp2/usrp2.h>
34 #include <usrp2/strtod_si.h>
39 #include <gruel/realtime.h>
46 typedef std::complex<float> fcomplex;
48 static volatile bool signaled = false;
51 gen_and_send(usrp2::usrp2::sptr u2, int chan,
52 double *ph, double ph_incr, int nsamples);
62 install_sig_handler(int signum,
63 void (*new_handler)(int))
65 struct sigaction new_action;
66 memset (&new_action, 0, sizeof (new_action));
68 new_action.sa_handler = new_handler;
69 sigemptyset (&new_action.sa_mask);
70 new_action.sa_flags = 0;
72 if (sigaction (signum, &new_action, 0) < 0){
73 perror ("sigaction (install new)");
74 throw std::runtime_error ("sigaction");
80 prettify_progname(const char *progname) // that's probably almost a word ;)
82 const char *p = strrchr(progname, '/'); // drop leading directory path
86 if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix
93 usage(const char *progname)
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");
108 #define GAIN_NOT_SET (-1000)
109 #define MAX_SAMPLES (371)
112 main(int argc, char **argv)
114 const char *interface = "eth0";
115 const char *input_filename = 0;
117 const char *mac_addr_str = "";
120 int32_t samples_per_frame = MAX_SAMPLES;
122 double gain = GAIN_NOT_SET;
128 while ((ch = getopt(argc, argv, "he:m:I:rf:i:S:F:g:")) != EOF){
136 mac_addr_str = optarg;
138 if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
139 std::cerr << "invalid mac addr: " << optarg << std::endl;
147 input_filename = optarg;
155 if (!strtod_si(optarg, &freq)){
156 std::cerr << "invalid number: " << optarg << std::endl;
163 samples_per_frame = strtol(optarg, 0, 0);
167 interp = strtol(optarg, 0, 0);
171 if (!strtod_si(optarg, &tmp)){
172 std::cerr << "invalid number: " << optarg << std::endl;
176 scale = static_cast<int32_t>(tmp);
187 if (argc - optind != 0){
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";
202 if (input_filename == 0)
205 fp = fopen(input_filename, "rb");
207 perror(input_filename);
212 install_sig_handler(SIGINT, sig_handler);
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;
220 usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
223 if (gain != GAIN_NOT_SET){
224 if (!u2->set_tx_gain(gain)){
225 std::cerr << "set_tx_gain failed\n";
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);
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");
242 if (!u2->set_tx_interp(interp)){
243 fprintf(stderr, "set_tx_interp(%d) failed\n", interp);
248 if (!u2->set_tx_scale_iq(scale, scale)){
249 std::cerr << "set_tx_scale_iq failed\n";
255 double baseband_rate = 100e6 / 32;
260 double ph0_incr = 7.5e3/baseband_rate * 2 * M_PI;
261 double ph1_incr = 7.5e3/baseband_rate * 2 * M_PI;
265 gen_and_send(u2, 0, &ph0, ph0_incr, samples_per_frame);
266 gen_and_send(u2, 1, &ph1, ph1_incr, samples_per_frame);
274 gen_and_send(usrp2::usrp2::sptr u2, int chan,
275 double *ph_ptr, double ph_incr, int nsamples)
279 std::complex<float> buf[MAX_SAMPLES];
281 usrp2::tx_metadata md;
283 md.start_of_burst = 1;
294 for (int i = 0; i < nsamples; i++){
297 sincosf((float) ph, &s, &c);
298 buf[i] = std::complex<float>(s * ampl, c * ampl);
301 buf[i] = std::complex<float>(ampl, 0);
305 if (!u2->tx_32fc(chan, buf, nsamples, &md)){
306 fprintf(stderr, "tx_32fc failed\n");
309 ph = fmod(ph, 2*M_PI);