summaryrefslogtreecommitdiff
path: root/usrp2/host/apps/rx_streaming_samples.cc
diff options
context:
space:
mode:
Diffstat (limited to 'usrp2/host/apps/rx_streaming_samples.cc')
-rw-r--r--usrp2/host/apps/rx_streaming_samples.cc372
1 files changed, 372 insertions, 0 deletions
diff --git a/usrp2/host/apps/rx_streaming_samples.cc b/usrp2/host/apps/rx_streaming_samples.cc
new file mode 100644
index 000000000..70f2c5d73
--- /dev/null
+++ b/usrp2/host/apps/rx_streaming_samples.cc
@@ -0,0 +1,372 @@
+/* -*- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp2/usrp2.h>
+#include <usrp2/strtod_si.h>
+#include <usrp2/copiers.h>
+#include <usrp2/rx_nop_handler.h>
+#include <gruel/realtime.h>
+#include <sys/time.h>
+#include <iostream>
+#include <string.h>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <stdexcept>
+#include <signal.h>
+
+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 complex_16_file_writer : public usrp2::rx_nop_handler
+{
+ FILE *d_fp;
+ std::string d_filename;
+
+public:
+
+ complex_16_file_writer(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);
+ }
+ }
+
+ ~complex_16_file_writer();
+
+ 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<int16_t> host_items[host_nitems];
+
+ usrp2::copy_u2_complex_16_to_host_complex_16(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;
+ }
+};
+
+complex_16_file_writer::~complex_16_file_writer()
+{
+ fclose(d_fp);
+}
+
+// ------------------------------------------------------------------------
+
+class complex_float_file_writer : public usrp2::rx_nop_handler
+{
+ FILE *d_fp;
+ std::string d_filename;
+
+public:
+
+ complex_float_file_writer(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);
+ }
+ }
+
+ ~complex_float_file_writer();
+
+ 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<float> host_items[host_nitems];
+
+ usrp2::copy_u2_complex_16_to_host_complex_float(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;
+ }
+};
+
+complex_float_file_writer::~complex_float_file_writer()
+{
+ 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, " -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<uint64_t>(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 complex_16_file_writer(output_filename, nsamples));
+ else
+ handler = usrp2::rx_nop_handler::sptr(new complex_float_file_writer(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;
+}