summaryrefslogtreecommitdiff
path: root/vrt/apps
diff options
context:
space:
mode:
authoreb2009-08-15 18:34:45 +0000
committereb2009-08-15 18:34:45 +0000
commitea57c1b52b8bed12296ba51441afcfc57a0b9d34 (patch)
treef86aee7b4b75aef3d27f7d876431296838e8cb8e /vrt/apps
parentcdecd3aa94c0ed24312c869c27b3cbd01998004e (diff)
downloadgnuradio-ea57c1b52b8bed12296ba51441afcfc57a0b9d34.tar.gz
gnuradio-ea57c1b52b8bed12296ba51441afcfc57a0b9d34.tar.bz2
gnuradio-ea57c1b52b8bed12296ba51441afcfc57a0b9d34.zip
Merged VRT work-in-progress from eb/vrt2 (11518:11598) into trunk.
Passes distcheck. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11600 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'vrt/apps')
-rw-r--r--vrt/apps/Makefile.am36
-rw-r--r--vrt/apps/simple_rx_samples.cc394
2 files changed, 430 insertions, 0 deletions
diff --git a/vrt/apps/Makefile.am b/vrt/apps/Makefile.am
new file mode 100644
index 000000000..631d9020b
--- /dev/null
+++ b/vrt/apps/Makefile.am
@@ -0,0 +1,36 @@
+#
+# Copyright 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 <http://www.gnu.org/licenses/>.
+#
+
+include $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = \
+ $(VRT_INCLUDES) \
+ $(STD_DEFINES_AND_INCLUDES) \
+ $(CPPUNIT_INCLUDES)
+
+LDADD = \
+ $(VRT_LA) \
+ $(GRUEL_LA)
+
+
+bin_PROGRAMS =
+
+noinst_PROGRAMS = \
+ simple_rx_samples
+
+simple_rx_samples_SOURCES = simple_rx_samples.cc
+
diff --git a/vrt/apps/simple_rx_samples.cc b/vrt/apps/simple_rx_samples.cc
new file mode 100644
index 000000000..6b09afda5
--- /dev/null
+++ b/vrt/apps/simple_rx_samples.cc
@@ -0,0 +1,394 @@
+/* -*- 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 <vrt/quadradio.h>
+#include <vrt/rx.h>
+#include <vrt/copiers.h>
+
+#include <errno.h>
+#include <iostream>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <stdexcept>
+#include <signal.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <gruel/realtime.h>
+#include <complex>
+
+#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<rx_nop_handler> 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<int16_t> 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<float> 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<short> [default=complex<float>]\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;
+}