/* -*- c++ -*- */ /* * Copyright 2003,2004,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * * GNU Radio 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, or (at your option) * any later version. * * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include /* needed for usb functions */ #include #include #include #include "time_stuff.h" #include "usrp_standard.h" #include "usrp_bytesex.h" #ifdef HAVE_SCHED_H #include #endif char *prog_name; static bool test_output (usrp_standard_tx_sptr utx, int max_bytes, double ampl, bool dc_p, bool counting_p); static void set_progname (char *path) { char *p = strrchr (path, '/'); if (p != 0) prog_name = p+1; else prog_name = path; } static void usage () { fprintf (stderr, "usage: %s [-f] [-v] [-d] [-c] [-a ][-I ] [-F freq] [-D]\n", prog_name); fprintf (stderr, " [-f] loop forever\n"); fprintf (stderr, " [-M] how many Megabytes to transfer (default 128)\n"); fprintf (stderr, " [-v] verbose\n"); fprintf (stderr, " [-d] dump registers\n"); // fprintf (stderr, " [-l] digital loopback in FPGA\n"); fprintf (stderr, " [-c] Tx counting sequence\n"); fprintf (stderr, " [-D] DC output\n"); fprintf (stderr, " [-B ] set fast usb block_size\n"); fprintf (stderr, " [-N ] set fast usb nblocks\n"); fprintf (stderr, " [-R] set real time scheduling: SCHED_FIFO; pri = midpoint\n"); exit (1); } static void die (const char *msg) { fprintf (stderr, "die: %s: %s\n", prog_name, msg); exit (1); } static void dump_codec_regs (usrp_basic *u, int which_codec, FILE *fp) { for (int i = 0; i < 64; i++){ unsigned char v; u->_read_9862 (which_codec, i, &v); fprintf (fp, "%2d: 0x%02x\n", i, v); } fflush (fp); } static void do_dump_codec_regs (usrp_basic *u) { char name[100]; strcpy (name, "regsXXXXXX"); int fd = mkstemp (name); if (fd == -1){ perror (name); } else { FILE *fp = fdopen (fd, "w"); dump_codec_regs (u, 0, fp); fclose (fp); } } int main (int argc, char **argv) { bool verbose_p = false; bool dump_regs_p = false; bool dc_p = false; // bool loopback_p = false; bool counting_p = false; int max_bytes = 128 * (1L << 20); int ch; int which_board = 0; int interp = 16; // 32.0 MB/sec double center_freq = 0; double ampl = 10000; int fusb_block_size = 0; int fusb_nblocks = 0; bool realtime_p = false; set_progname (argv[0]); while ((ch = getopt (argc, argv, "vfdcI:F:a:DM:B:N:R")) != EOF){ switch (ch){ case 'f': max_bytes = 0; break; case 'v': verbose_p = true; break; case 'd': dump_regs_p = true; break; case 'D': dc_p = true; break; #if 0 case 'l': loopback_p = true; break; #endif case 'c': counting_p = true; break; case 'I': interp = strtol (optarg, 0, 0); break; case 'F': center_freq = strtod (optarg, 0); break; case 'a': ampl = strtod (optarg, 0); break; case 'M': max_bytes = strtol (optarg, 0, 0) * (1L << 20); if (max_bytes < 0) max_bytes = 0; break; case 'B': fusb_block_size = strtol (optarg, 0, 0); break; case 'N': fusb_nblocks = strtol (optarg, 0, 0); break; case 'R': realtime_p = true; break; default: usage (); } } #ifdef HAVE_SCHED_SETSCHEDULER if (realtime_p){ int policy = SCHED_FIFO; int pri = (sched_get_priority_max (policy) - sched_get_priority_min (policy)) / 2; int pid = 0; // this process struct sched_param param; memset(¶m, 0, sizeof(param)); param.sched_priority = pri; int result = sched_setscheduler(pid, policy, ¶m); if (result != 0){ perror ("sched_setscheduler: failed to set real time priority"); } else printf("SCHED_FIFO enabled with priority = %d\n", pri); } #endif usrp_standard_tx_sptr utx; utx = usrp_standard_tx::make (which_board, interp, 1, // nchan -1, // mux fusb_block_size, fusb_nblocks); if (utx == 0) die ("usrp_standard_tx::make"); if (!utx->set_tx_freq (0, center_freq)) die ("utx->set_tx_freq"); if (dump_regs_p) do_dump_codec_regs (utx.get()); fflush (stdout); fflush (stderr); utx->start(); // start data xfers test_output (utx, max_bytes, ampl, dc_p, counting_p); return 0; } static bool test_output (usrp_standard_tx_sptr utx, int max_bytes, double ampl, bool dc_p, bool counting_p) { static const int BUFSIZE = utx->block_size(); static const int N = BUFSIZE/sizeof (short); short buf[N]; int nbytes = 0; int counter = 0; static const int PERIOD = 65; // any value is valid static const int PATLEN = 2 * PERIOD; short pattern[PATLEN]; for (int i = 0; i < PERIOD; i++){ if (dc_p){ pattern[2*i+0] = host_to_usrp_short ((short) ampl); pattern[2*i+1] = host_to_usrp_short ((short) 0); } else { pattern[2*i+0] = host_to_usrp_short ((short) (ampl * cos (2*M_PI * i / PERIOD))); pattern[2*i+1] = host_to_usrp_short ((short) (ampl * sin (2*M_PI * i / PERIOD))); } } double start_wall_time = get_elapsed_time (); double start_cpu_time = get_cpu_usage (); bool underrun; int nunderruns = 0; int pi = 0; for (nbytes = 0; max_bytes == 0 || nbytes < max_bytes; nbytes += BUFSIZE){ if (counting_p){ for (int i = 0; i < N; i++) buf[i] = host_to_usrp_short (counter++ & 0xffff); } else { for (int i = 0; i < N; i++){ buf[i] = pattern[pi]; pi++; if (pi >= PATLEN) pi = 0; } } int ret = utx->write (buf, sizeof (buf), &underrun); if ((unsigned) ret != sizeof (buf)){ fprintf (stderr, "test_output: error, ret = %d\n", ret); } if (underrun){ nunderruns++; printf ("tx_underrun\n"); //printf ("tx_underrun %9d %6d\n", nbytes, nbytes/BUFSIZE); } } utx->wait_for_completion (); double stop_wall_time = get_elapsed_time (); double stop_cpu_time = get_cpu_usage (); double delta_wall = stop_wall_time - start_wall_time; double delta_cpu = stop_cpu_time - start_cpu_time; printf ("xfered %.3g bytes in %.3g seconds. %.4g bytes/sec. cpu time = %.3g\n", (double) max_bytes, delta_wall, max_bytes / delta_wall, delta_cpu); printf ("%d underruns\n", nunderruns); return true; }