/* -*- c++ -*- */ /* * Copyright 2007,2008,2009 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * This is a down and dirty test program that confirms that the we can * coherently transmit different signals to two USRP2s connected via a * mimo cable. It ignores most of its command line arguments, and * requires that special purpose firmware be installed in the two * USRP2s. The one connected to the ethernet must be running * mimo_tx.bin The other must be running mimo_tx_slave.bin. * * Don't use this as a model for how s/w should be written :-) */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include typedef std::complex fcomplex; static volatile bool signaled = false; void gen_and_send(usrp2::usrp2::sptr u2, int chan, double *ph, double ph_incr, int nsamples); static void sig_handler(int sig) { signaled = true; } static void install_sig_handler(int signum, void (*new_handler)(int)) { struct sigaction new_action; memset (&new_action, 0, sizeof (new_action)); new_action.sa_handler = new_handler; sigemptyset (&new_action.sa_mask); new_action.sa_flags = 0; if (sigaction (signum, &new_action, 0) < 0){ perror ("sigaction (install new)"); throw std::runtime_error ("sigaction"); } } static const char * prettify_progname(const char *progname) // that's probably almost a word ;) { const char *p = strrchr(progname, '/'); // drop leading directory path if (p) p++; if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix p += 3; return p; } static void usage(const char *progname) { fprintf(stderr, "Usage: %s [options]\n\n", prettify_progname(progname)); fprintf(stderr, "Options:\n"); fprintf(stderr, " -h show this message and exit\n"); fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface [default=eth0]\n"); fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH [default=first one found]\n"); fprintf(stderr, " -I INPUT_FILE set input filename [default=stdin]\n"); fprintf(stderr, " -r repeat. When EOF of input file is reached, seek to beginning\n"); fprintf(stderr, " -f FREQ set frequency to FREQ [default=0]\n"); fprintf(stderr, " -i INTERP set interpolation rate to INTERP [default=32]\n"); fprintf(stderr, " -g gain set tx gain\n"); fprintf(stderr, " -S SCALE fpga scaling factor for I & Q [default=256]\n"); } #define GAIN_NOT_SET (-1000) #define MAX_SAMPLES (371) int main(int argc, char **argv) { const char *interface = "eth0"; const char *input_filename = 0; bool repeat = false; const char *mac_addr_str = ""; double freq = 0; int32_t interp = 32; int32_t samples_per_frame = MAX_SAMPLES; int32_t scale = -1; double gain = GAIN_NOT_SET; int ch; double tmp; while ((ch = getopt(argc, argv, "he:m:I:rf:i:S:F:g:")) != EOF){ switch (ch){ case 'e': interface = optarg; break; case 'm': mac_addr_str = optarg; #if 0 if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){ std::cerr << "invalid mac addr: " << optarg << std::endl; usage(argv[0]); return 1; } #endif break; case 'I': input_filename = optarg; break; case 'r': repeat = true; break; case 'f': if (!strtod_si(optarg, &freq)){ std::cerr << "invalid number: " << optarg << std::endl; usage(argv[0]); return 1; } break; case 'F': samples_per_frame = strtol(optarg, 0, 0); break; case 'i': interp = strtol(optarg, 0, 0); break; case 'S': if (!strtod_si(optarg, &tmp)){ std::cerr << "invalid number: " << optarg << std::endl; usage(argv[0]); return 1; } scale = static_cast(tmp); break; case 'h': default: usage(argv[0]); return 1; } } if (argc - optind != 0){ usage(argv[0]); return 1; } if (samples_per_frame < 9 || samples_per_frame > MAX_SAMPLES){ std::cerr << prettify_progname(argv[0]) << ": samples_per_frame is out of range. " << "Must be in [9, " << MAX_SAMPLES << "].\n"; usage(argv[0]); return 1; } FILE *fp = 0; if (input_filename == 0) fp = stdin; else { fp = fopen(input_filename, "rb"); if (fp == 0){ perror(input_filename); return 1; } } install_sig_handler(SIGINT, sig_handler); gruel::rt_status_t rt = gruel::enable_realtime_scheduling(); if (rt != gruel::RT_OK) std::cerr << "Failed to enable realtime scheduling" << std::endl; usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str); #if 0 if (gain != GAIN_NOT_SET){ if (!u2->set_tx_gain(gain)){ std::cerr << "set_tx_gain failed\n"; return 1; } } usrp2::tune_result tr; if (!u2->set_tx_center_freq(freq, &tr)){ fprintf(stderr, "set_tx_center_freq(%g) failed\n", freq); return 1; } printf("Daughterboard configuration:\n"); printf(" baseband_freq=%f\n", tr.baseband_freq); printf(" duc_freq=%f\n", tr.dxc_freq); printf(" residual_freq=%f\n", tr.residual_freq); printf(" inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no"); if (!u2->set_tx_interp(interp)){ fprintf(stderr, "set_tx_interp(%d) failed\n", interp); return 1; } if (scale != -1){ if (!u2->set_tx_scale_iq(scale, scale)){ std::cerr << "set_tx_scale_iq failed\n"; return 1; } } #endif double baseband_rate = 100e6 / 32; double ph0 = 0; double ph1 = 0; double ph0_incr = 7.5e3/baseband_rate * 2 * M_PI; double ph1_incr = 7.5e3/baseband_rate * 2 * M_PI; while (!signaled){ gen_and_send(u2, 0, &ph0, ph0_incr, samples_per_frame); gen_and_send(u2, 1, &ph1, ph1_incr, samples_per_frame); } return 0; } void gen_and_send(usrp2::usrp2::sptr u2, int chan, double *ph_ptr, double ph_incr, int nsamples) { double ph = *ph_ptr; std::complex buf[MAX_SAMPLES]; usrp2::tx_metadata md; md.timestamp = -1; md.start_of_burst = 1; md.send_now = 1; float ampl; if (chan == 0) ampl = 0.5; else ampl = 0.75; for (int i = 0; i < nsamples; i++){ #if 0 float s, c; sincosf((float) ph, &s, &c); buf[i] = std::complex(s * ampl, c * ampl); ph += ph_incr; #else buf[i] = std::complex(ampl, 0); #endif } if (!u2->tx_32fc(chan, buf, nsamples, &md)){ fprintf(stderr, "tx_32fc failed\n"); } ph = fmod(ph, 2*M_PI); *ph_ptr = ph; }