/* -*- c++ -*- */ /* * Copyright 2007,2008 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 . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include static volatile bool signaled = false; 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"); } } // ------------------------------------------------------------------------ // FIXME make this a template class file_writer_16sc : public usrp2::rx_nop_handler { FILE *d_fp; std::string d_filename; public: file_writer_16sc(const std::string &filename, uint64_t max_samples) : usrp2::rx_nop_handler(max_samples), d_filename(filename) { d_fp = fopen(filename.c_str(), "wb"); if (d_fp == 0){ perror(filename.c_str()); throw std::invalid_argument(filename); } } ~file_writer_16sc(); bool operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata) { bool ok = rx_nop_handler::operator()(items, nitems, metadata); size_t host_nitems = nitems; std::complex host_items[host_nitems]; usrp2::copy_u2_16sc_to_host_16sc(nitems, items, host_items); size_t n = 0; while (n < host_nitems){ size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp); n += r; if (r == 0){ // out of space? d_err = true; perror(d_filename.c_str()); ok = false; break; } } return ok; } }; file_writer_16sc::~file_writer_16sc() { fclose(d_fp); } // ------------------------------------------------------------------------ class file_writer_32fc : public usrp2::rx_nop_handler { FILE *d_fp; std::string d_filename; public: file_writer_32fc(const std::string &filename, uint64_t max_samples) : usrp2::rx_nop_handler(max_samples), d_filename(filename) { d_fp = fopen(filename.c_str(), "wb"); if (d_fp == 0){ perror(filename.c_str()); throw std::invalid_argument(filename); } } ~file_writer_32fc(); bool operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata) { bool ok = rx_nop_handler::operator()(items, nitems, metadata); size_t host_nitems = nitems; std::complex host_items[host_nitems]; usrp2::copy_u2_16sc_to_host_32fc(nitems, items, host_items); size_t n = 0; while (n < host_nitems){ size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp); n += r; if (r == 0){ // out of space? d_err = true; perror(d_filename.c_str()); ok = false; break; } } return ok; } }; file_writer_32fc::~file_writer_32fc() { fclose(d_fp); } // ------------------------------------------------------------------------ static void usage(const char *progname) { const char *p = strrchr(progname, '/'); // drop leading directory path if (p) p++; if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix p += 3; fprintf(stderr, "Usage: %s [options]\n\n", p); 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, " -f FREQUENCY specify receive center frequency in Hz [default=0.0]\n"); fprintf(stderr, " -d DECIM specify receive decimation rate [default=5]\n"); fprintf(stderr, " -g GAIN specify receive daughterboard gain [default=0]\n"); fprintf(stderr, " -N NSAMPLES specify number of samples to receive [default=infinite]\n"); fprintf(stderr, " -o OUTPUT_FILENAME specify file to receive samples [default=none]\n"); fprintf(stderr, " -s write complex [default=complex]\n"); fprintf(stderr, " -v verbose output\n"); } int main(int argc, char **argv) { // options and their defaults const char *interface = "eth0"; const char *mac_addr_str = ""; double rx_freq = 0.0; int rx_decim = 5; double rx_gain = 0.0; uint64_t nsamples = 0; bool output_shorts = false; char *output_filename = 0; bool verbose = false; int ch; while ((ch = getopt(argc, argv, "he:m:f:d:g:N:o:sv")) != EOF){ double tmp; switch (ch){ case 'e': interface = optarg; break; case 'm': mac_addr_str = optarg; break; case 'f': if (!strtod_si(optarg, &rx_freq)) { std::cerr << "invalid number: " << optarg << std::endl; usage(argv[0]); exit(1); } break; case 'g': if (!strtod_si(optarg, &rx_gain)) { std::cerr << "invalid number: " << optarg << std::endl; usage(argv[0]); exit(1); } break; case 'd': rx_decim = strtol(optarg, 0, 0); if (rx_decim < 4 or rx_decim > 512) { std::cerr << "invalid decimation rate: " << optarg << std::endl; usage(argv[0]); exit(1); } break; case 'N': if (!strtod_si(optarg, &tmp)) { std::cerr << "invalid number: " << optarg << std::endl; usage(argv[0]); exit(1); } nsamples = static_cast(tmp); break; case 's': output_shorts = true; break; case 'o': output_filename = optarg; break; case 'v': verbose = true; break; case 'h': default: usage(argv[0]); exit(1); } } install_sig_handler(SIGINT, sig_handler); usrp2::rx_nop_handler::sptr handler; if (output_filename){ if (output_shorts) handler = usrp2::rx_nop_handler::sptr(new file_writer_16sc(output_filename, nsamples)); else handler = usrp2::rx_nop_handler::sptr(new file_writer_32fc(output_filename, nsamples)); } else handler = usrp2::rx_nop_handler::sptr(new usrp2::rx_nop_handler(nsamples)); 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); // FIXME in case it was left running... if (!u2->stop_rx_streaming()){ fprintf(stderr, "stop_rx_streaming failed\n"); } if (!u2->set_rx_gain(rx_gain)){ fprintf(stderr, "set_rx_gain(%f) failed\n", rx_gain); exit(1); } usrp2::tune_result tr; if (!u2->set_rx_center_freq(rx_freq, &tr)){ fprintf(stderr, "set_rx_center_freq(%g) failed\n", rx_freq); exit(1); } if (verbose){ printf("USRP2 MAC address: %s\n\n", u2->mac_addr().c_str()); printf("Daughterboard configuration:\n"); printf(" baseband_freq=%f\n", tr.baseband_freq); printf(" ddc_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_rx_decim(rx_decim)) { fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim); exit(1); } if (verbose) printf("USRP2 using decimation rate of %d\n", rx_decim); if (!u2->start_rx_streaming(0)){ fprintf(stderr, "start_rx_streaming failed\n"); exit(1); } if (verbose) { if (nsamples > 0) printf("Receiving %zd samples\n\n", nsamples); else printf("Receiving infinite samples\n\n"); } struct timeval start, end; gettimeofday(&start, 0); while (!signaled && !handler->has_errored_p() && !handler->has_finished_p()) { bool ok = u2->rx_samples(0, handler.get()); if (!ok){ fprintf(stderr, "u2->rx_samples failed\n"); return 1; } } gettimeofday(&end, 0); long n_usecs = end.tv_usec-start.tv_usec; long n_secs = end.tv_sec-start.tv_sec; double elapsed = (double)n_secs + (double)n_usecs*1e-6; double mbs = handler->nsamples()*sizeof(uint32_t)/elapsed/1e6; double pps = handler->nframes()/elapsed; u2->stop_rx_streaming(); if (verbose){ printf("\nCopy handler called %li times.\n", handler->nframes()); printf("Copy handler called with %li bytes.\n\n", handler->nsamples()*sizeof(uint32_t)); printf("Elapsed time was %5.3f seconds.\n", elapsed); printf("Packet rate was %1.0f pkts/sec.\n", pps); printf("Approximate throughput was %5.2f MB/sec.\n", mbs); printf("Total instances of overruns was %d.\n", u2->rx_overruns()); printf("Total missing frames was %d.\n", u2->rx_missing()); } return 0; }