/* -*- c++ -*- */ /* * Copyright 2009 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MIN_IP_LOCAL_PORT 32768 #define MAX_IP_LOCAL_PORT 61000 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"); } } // ------------------------------------------------------------------------ class rx_nop_handler : public vrt::rx_packet_handler { private: uint64_t d_max_samples; uint64_t d_max_quantum; uint64_t d_nsamples; uint64_t d_npackets; int d_last_pkt_cnt; uint64_t d_nwrong_pkt_cnt; protected: bool d_err; public: // Shared pointer to an instance of this class typedef boost::shared_ptr sptr; /*! * Constructor * * \param max_samples Maximum number of samples to copy. Use zero for no maximum. * \param max_quantum Maximum number of samples required to accept in one call. * Use 0 to indicate no maximum. */ rx_nop_handler(uint64_t max_samples, uint64_t max_quantum=0) : d_max_samples(max_samples), d_max_quantum(max_quantum), d_nsamples(0), d_npackets(0), d_last_pkt_cnt(0xf), d_nwrong_pkt_cnt(0), d_err(false){} ~rx_nop_handler(); bool operator()(const uint32_t *payload, size_t n32_bit_words, const vrt::expanded_header *hdr); /*! * \brief Returns number of packets this copier was called with */ uint64_t npackets() const { return d_npackets; } /*! * \brief Returns actual number of samples copied */ uint64_t nsamples() const { return d_nsamples; } /*! * \brief Returns maximum number of samples that will be copied */ uint64_t max_samples() const { return d_max_samples; } /*! * Returns true if an error has occurred. Derived classes must set d_err to true * when an error occurs in the () operator */ bool has_errored_p() const { return d_err; } /*! * \brief Returns true if this instance has reached the maximum number of samples */ bool has_finished_p() const { return d_max_samples == 0 ? false : d_nsamples >= d_max_samples-d_max_quantum; } uint64_t nwrong_pkt_cnt() const { return d_nwrong_pkt_cnt; } }; rx_nop_handler::~rx_nop_handler() { } bool rx_nop_handler::operator()(const uint32_t *payload, size_t n32_bit_words, const vrt::expanded_header *hdr) { if (d_npackets != 0 && hdr->pkt_cnt() != ((d_last_pkt_cnt + 1) & 0xf)){ d_nwrong_pkt_cnt++; fprintf(stderr, "bad cnt (pkt %lld)\n", d_npackets); } d_last_pkt_cnt = hdr->pkt_cnt(); d_nsamples += n32_bit_words; d_npackets++; return !has_finished_p(); } // ------------------------------------------------------------------------ class file_writer_16sc : public rx_nop_handler { FILE *d_fp; std::string d_filename; public: file_writer_16sc(const std::string &filename, uint64_t max_samples) : 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 vrt::expanded_header *hdr) { bool ok = rx_nop_handler::operator()(items, nitems, hdr); size_t host_nitems = nitems; std::complex host_items[host_nitems]; vrt::copy_net_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 rx_nop_handler { FILE *d_fp; std::string d_filename; public: file_writer_32fc(const std::string &filename, uint64_t max_samples) : 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 vrt::expanded_header *hdr) { bool ok = rx_nop_handler::operator()(items, nitems, hdr); size_t host_nitems = nitems; std::complex host_items[host_nitems]; vrt::copy_net_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, " -S samples_per_pkt specify # of samples per pkt [default=maximum]\n"); //fprintf(stderr, " -v verbose output\n"); } int main(int argc, char **argv) { const char *quad_radio_ip = "192.168.123.123"; size_t rx_bufsize = 62.5e6; // sizeof memory mapped network buffer int samples_per_pkt = 0; // use default uint64_t nsamples = 0; char *output_filename = 0; bool output_shorts = false; int t; int ch; while ((ch = getopt(argc, argv, "hN:o:sS:")) != EOF){ switch (ch){ case 'N': nsamples = (uint64_t) strtod(optarg, 0); break; case 'o': output_filename = optarg; break; case 's': output_shorts = true; break; case 'S': errno = 0; t = strtol(optarg, 0, 0); if (errno != 0){ usage(argv[0]); exit(1); } samples_per_pkt = t; break; case 'h': default: usage(argv[0]); exit(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; vrt::quadradio::sptr qr; try { qr = vrt::quadradio::sptr(new vrt::quadradio(quad_radio_ip, rx_bufsize)); } catch (...){ std::cerr << "Failed to create vrt::quadradio\n"; return 1; } rx_nop_handler::sptr handler; if (output_filename){ if (output_shorts) handler = rx_nop_handler::sptr(new file_writer_16sc(output_filename, nsamples)); else handler = rx_nop_handler::sptr(new file_writer_32fc(output_filename, nsamples)); } else handler = rx_nop_handler::sptr(new rx_nop_handler(nsamples)); printf("samples_per_pkt = %d\n", samples_per_pkt); if (!qr->start_streaming(samples_per_pkt)){ fprintf(stderr, "failed to send_rx_command\n"); return 1; } // start receiving packets while(1 && !signaled && !handler->has_errored_p() && !handler->has_finished_p()){ bool ok = qr->vrt_rx()->rx_packets(handler.get()); if (!ok){ fprintf(stderr, "vrt->rx_packets failed\n"); break; } } qr->stop_streaming(); printf("%llu packets received, %llu bad pkt_cnt field values, %llu samples\n", handler->npackets(), handler->nwrong_pkt_cnt(), handler->nsamples()); //sleep(1); return 0; }