root / usrp / host / apps / test_usrp_standard_tx.cc @ c276a4ff
History | View | Annotate | Download (8 kB)
| 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/usrp_standard.h> |
| 38 | #include <usrp/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>(&), "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 |