[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r9115 - in usrp2/branches/developers/eb/merge-wip/host
From: |
eb |
Subject: |
[Commit-gnuradio] r9115 - in usrp2/branches/developers/eb/merge-wip/host-ng: . apps include/usrp2 lib |
Date: |
Thu, 31 Jul 2008 22:40:48 -0600 (MDT) |
Author: eb
Date: 2008-07-31 22:40:47 -0600 (Thu, 31 Jul 2008)
New Revision: 9115
Added:
usrp2/branches/developers/eb/merge-wip/host-ng/apps/test2_usrp2.cc
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copiers.h
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/metadata.h
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/rx_sample_handler.h
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/strtod_si.h
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/tune_result.h
usrp2/branches/developers/eb/merge-wip/host-ng/lib/copiers.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/data_handler.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.h
usrp2/branches/developers/eb/merge-wip/host-ng/lib/rx_sample_handler.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/strtod_si.c
usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_bytesex.h
Modified:
usrp2/branches/developers/eb/merge-wip/host-ng/apps/
usrp2/branches/developers/eb/merge-wip/host-ng/apps/Makefile.am
usrp2/branches/developers/eb/merge-wip/host-ng/apps/test.sh
usrp2/branches/developers/eb/merge-wip/host-ng/apps/test_usrp2.cc
usrp2/branches/developers/eb/merge-wip/host-ng/configure.ac
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/Makefile.am
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copy_handler.h
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/data_handler.h
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/usrp2.h
usrp2/branches/developers/eb/merge-wip/host-ng/lib/Makefile.am
usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.h
usrp2/branches/developers/eb/merge-wip/host-ng/lib/copy_handler.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.h
usrp2/branches/developers/eb/merge-wip/host-ng/lib/find.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.cc
usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.h
usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_thread.cc
Log:
Merged features/host-ng/host-ng -r8608:9111 into trunk/host-ng.
Property changes on: usrp2/branches/developers/eb/merge-wip/host-ng/apps
___________________________________________________________________
Name: svn:ignore
- Makefile
Makefile.in
.libs
.deps
test_eth
test_usrp2
cerr
*.sh
+ Makefile
Makefile.in
.libs
.deps
test_eth
test_usrp2
test2_usrp2
cerr
*.sh
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/apps/Makefile.am
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/apps/Makefile.am
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/apps/Makefile.am
2008-08-01 04:40:47 UTC (rev 9115)
@@ -17,16 +17,16 @@
include $(top_srcdir)/Makefile.common
-AM_CPPFLAGS = -Wall -Werror
-INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES)
+#AM_CXXFLAGS = -Wall -Werror (handle this with: $ ./configure CXXFLAGS="-Wall
-Werror -O2 -g")
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) $(GRUEL_CFLAGS)
LDADD = \
../lib/libusrp2ng.la \
- $(GNURADIO_CORE_LIBS)
+ -lgruel
noinst_PROGRAMS = \
- test_usrp2
+ test2_usrp2
-test_usrp2_SOURCES = \
- test_usrp2.cc
+test2_usrp2_SOURCES = \
+ test2_usrp2.cc
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/apps/test.sh
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/apps/test.sh 2008-08-01
04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/apps/test.sh 2008-08-01
04:40:47 UTC (rev 9115)
@@ -1,5 +1,5 @@
#!/bin/sh
-sudo ./test_usrp2 1>cerr 2>&1
+sudo ./test_usrp2 -d 4
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/apps/test2_usrp2.cc
(from rev 9111, usrp2/branches/features/host-ng/host-ng/apps/test2_usrp2.cc)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/apps/test2_usrp2.cc
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/apps/test2_usrp2.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,380 @@
+/* -*- 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/tune_result.h>
+#include <usrp2/strtod_si.h>
+#include <usrp2/rx_sample_handler.h>
+#include <usrp2/copiers.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>
+
+// ------------------------------------------------------------------------
+
+class rx_nop_handler : public usrp2::rx_sample_handler
+{
+ size_t d_max_samples;
+ size_t d_nsamples;
+ size_t d_nframes;
+
+public:
+
+ rx_nop_handler(size_t max_samples)
+ : d_max_samples(max_samples), d_nsamples(0), d_nframes(0) {}
+
+ ~rx_nop_handler();
+
+ size_t nframes() const { return d_nframes; }
+ size_t nsamples() const { return d_nsamples; }
+ size_t max_samples() const { return d_max_samples; }
+
+ bool
+ operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata
*metadata)
+ {
+ // printf("W0: %08x TS: %08x\n", metadata->word0, metadata->timestamp);
+ // printf("I0: %08x\n", items[0]);
+
+ d_nsamples += nitems;
+ d_nframes++;
+
+ return d_nsamples < d_max_samples;
+ }
+};
+
+rx_nop_handler::~rx_nop_handler()
+{
+ // nop
+}
+
+// ------------------------------------------------------------------------
+
+// FIXME make this a template
+
+class complex_16_file_writer : public rx_nop_handler
+{
+ FILE *d_fp;
+ std::string d_filename;
+
+public:
+
+ complex_16_file_writer(const std::string &filename, size_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);
+ }
+ }
+
+ ~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?
+ 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 rx_nop_handler
+{
+ FILE *d_fp;
+ std::string d_filename;
+
+public:
+
+ complex_float_file_writer(const std::string &filename, size_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);
+ }
+ }
+
+ ~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?
+ 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=250e6]\n");
+//fprintf(stderr, " -b BUFSIZE specify size of receive buffer
[default=64k]\n");
+ fprintf(stderr, " -o OUTPUT_FILENAME specify file to receive samples
[default=none]\n");
+ fprintf(stderr, " -s write complex<short>
[default=complex<float>]\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;
+ size_t nsamples = static_cast<size_t>(250e6);
+ bool output_shorts = false;
+ char *output_filename = 0;
+
+ int ch;
+
+ while ((ch = getopt(argc, argv, "he:m:f:d:g:N:o:s")) != 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<size_t>(tmp);
+ break;
+
+#if 0
+ case 'b':
+ if (!strtod_si(optarg, &tmp)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ bufsize = static_cast<size_t>(tmp);
+ break;
+#endif
+
+ case 's':
+ output_shorts = true;
+ break;
+
+ case 'o':
+ output_filename = optarg;
+ break;
+
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+
+ typedef boost::shared_ptr<rx_nop_handler> handler_sptr;
+ handler_sptr handler;
+
+ if (output_filename){
+ if (output_shorts)
+ handler = handler_sptr(new complex_16_file_writer(output_filename,
nsamples));
+ else
+ handler = handler_sptr(new complex_float_file_writer(output_filename,
nsamples));
+ }
+ else
+ handler = handler_sptr(new 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ printf("Receiving %zd samples\n\n", nsamples);
+
+ struct timeval start, end;
+ gettimeofday(&start, 0);
+
+
+ while(handler->nsamples() < handler->max_samples()){
+ 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();
+
+ printf("\nCopy handler called %zd times.\n", handler->nframes());
+ printf("Copy handler called with %zd 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;
+}
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/apps/test_usrp2.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/apps/test_usrp2.cc
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/apps/test_usrp2.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -21,9 +21,14 @@
#endif
#include <usrp2/usrp2.h>
-#include <gr_realtime.h>
+#include <usrp2/tune_result.h>
+#include <usrp2/strtod_si.h>
+#include <usrp2/copy_handler.h>
+#include <gruel/realtime.h>
+#include <sys/time.h>
#include <iostream>
#include <string.h>
+#include <boost/scoped_ptr.hpp>
static void
usage(const char *progname)
@@ -40,6 +45,11 @@
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 SAMPLES specify number of samples to receive
[default=250e6]\n");
+ fprintf(stderr, " -b BUFSIZE specify size of receive buffer
[default=64k]\n");
}
int
@@ -48,10 +58,15 @@
// 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;
+ double samples = 250e6;
+ double bufsize = 65536;
+
int ch;
- while ((ch = getopt(argc, argv, "he:m:")) != EOF){
+ while ((ch = getopt(argc, argv, "he:m:f:d:g:n:b:")) != EOF){
switch (ch){
case 'e':
@@ -62,32 +77,144 @@
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, &samples)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'b':
+ if (!strtod_si(optarg, &bufsize)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
case 'h':
default:
usage(argv[0]);
exit(1);
}
}
-
- gr_rt_status_t rt = gr_enable_realtime_scheduling();
- if (rt != RT_OK)
+
+ 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);
- u2->set_rx_gain(1.0);
- u2->set_rx_freq(0.0, NULL);
- u2->set_rx_decim(5);
- //u2->start_rx_streaming();
+ // 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);
+ }
+
+ 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");
- struct timespec ts;
- ts.tv_sec = 10;
- ts.tv_nsec = 0;
- int r = nanosleep(&ts, 0);
- if (r == -1)
- perror("nanosleep");
+ if (!u2->set_rx_decim(rx_decim)) {
+ fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim);
+ exit(1);
+ }
+
+ printf("USRP2 using decimation rate of %d\n", rx_decim);
+
+ if (!u2->start_rx_streaming()){
+ fprintf(stderr, "start_rx_streaming failed\n");
+ exit(1);
+ }
+
+ size_t nsamples = static_cast<size_t>(samples);
+ size_t buflen = static_cast<size_t>(bufsize);
+ boost::scoped_ptr<unsigned char> buf(new unsigned char[buflen]);
+
+ printf("Receiving %li samples into buffer of length %li bytes.\n\n",
nsamples, buflen);
- //u2->stop_rx_streaming();
+ struct timeval start, end;
+ gettimeofday(&start, 0);
+
+ printf("Each '.' is 100 packets:\n");
+
+ unsigned long bytes = 0;
+ unsigned long times = 0;
+
+ do {
+ usrp2::copy_handler h(buf.get(), buflen);
+ bool ok;
+ unsigned int n = 0;
+ do {
+ ok = u2->rx_samples(0, &h);
+ if (h.times() > n) {
+ printf("."); fflush(stdout);
+ n = n+100;
+ }
+ }
+ while (ok && !h.full() && (bytes+h.bytes()) <= nsamples*4);
+ if (!ok)
+ break;
+
+ bytes += h.bytes();
+ times += h.times();
+ }
+ while (bytes <= nsamples*4); // FIXME will vary by sample format
+
+ 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 = bytes/elapsed/1e6;
+ double pps = times/elapsed;
+ u2->stop_rx_streaming();
+
+ printf("\nCopy handler called %li times.\n", times);
+ printf("Copy handler called with %li bytes.\n\n", bytes);
+ 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;
}
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/configure.ac
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/configure.ac 2008-08-01
04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/configure.ac 2008-08-01
04:40:47 UTC (rev 9115)
@@ -1,4 +1,4 @@
-dnl Copyright 2001,2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
+dnl Copyright 2001,2002,2003,2004,2005,2006,2007,2008 Free Software
Foundation, Inc.
dnl
dnl This program is free software: you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
@@ -81,10 +81,11 @@
AC_PROG_INSTALL
AC_PATH_PROG([RM_PROG], [rm])
+AC_LIBTOOL_WIN32_DLL
dnl AC_DISABLE_SHARED dnl don't build shared libraries
AC_ENABLE_SHARED dnl do build shared libraries
AC_DISABLE_STATIC dnl don't build static libraries
-AC_PROG_LIBTOOL
+m4_ifdef([LT_INIT],[LT_INIT],[AC_PROG_LIBTOOL])
dnl GR_FORTRAN
GR_NO_UNDEFINED dnl do we need the -no-undefined linker flag
@@ -160,6 +161,10 @@
#endif
])
+PKG_CHECK_MODULES(GRUEL, gruel > 3)
+AC_SUBST(GRUEL_LIBS)
+AC_SUBST(GRUEL_CFLAGS)
+
dnl Do we have "dot", part of the graphviz package from AT&T?
dnl Doxgen will use it to draw pretty diagrams ;-)
AC_CHECK_PROG(HAVE_DOT, [dot],[YES],[NO])
Modified:
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/Makefile.am
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/Makefile.am
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/Makefile.am
2008-08-01 04:40:47 UTC (rev 9115)
@@ -22,6 +22,9 @@
usrp2includedir = $(includedir)/usrp2
usrp2include_HEADERS = \
+ copiers.h \
copy_handler.h \
data_handler.h \
+ strtod_si.h \
+ tune_result.h \
usrp2.h
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copiers.h
(from rev 9111, usrp2/branches/features/host-ng/host-ng/include/usrp2/copiers.h)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copiers.h
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copiers.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,63 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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/>.
+ */
+
+#ifndef INCLUDED_USRP2_COPIERS_H
+#define INCLUDED_USRP2_COPIERS_H
+
+#include <complex>
+#include <stdint.h>
+
+namespace usrp2 {
+
+ // FIXME we may want to rework this, but this will get us on the air
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from USRP2 wire format to host format
+ * ----------------------------------------------------------------
+ */
+
+ void
+ copy_u2_complex_16_to_host_complex_16(size_t nitems,
+ const uint32_t *items,
+ std::complex<int16_t> *host_items);
+
+ void
+ copy_u2_complex_16_to_host_complex_float(size_t nitems,
+ const uint32_t *items,
+ std::complex<float> *host_items);
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from host format to USRP2 wire format
+ * ----------------------------------------------------------------
+ */
+
+ void
+ copy_host_complex_16_to_u2_complex_16(size_t nitems,
+ const std::complex<int16_t> *host_items,
+ uint32_t *items);
+
+ void
+ copy_host_complex_float_to_u2_complex_16(size_t nitems,
+ const std::complex<float>
*host_items,
+ uint32_t *items);
+}
+
+
+#endif /* INCLUDED_USRP2_COPIERS_H */
Modified:
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copy_handler.h
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copy_handler.h
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copy_handler.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -26,18 +26,24 @@
namespace usrp2 {
- class copy_handler : data_handler, boost::noncopyable
+ class copy_handler : public data_handler, boost::noncopyable
{
uint8_t *d_dest; // next write pointer
- unsigned int d_space; // space left in destination buffer
- unsigned int d_bytes; // total bytes copied
- unsigned int d_times; // number of times invoked
+ size_t d_space; // space left in destination buffer
+ size_t d_bytes; // total bytes copied
+ size_t d_times; // number of times invoked
public:
- copy_handler(void *dest, unsigned int len);
+ copy_handler(void *dest, size_t len);
~copy_handler();
- virtual uint32_t operator()(const void *base, unsigned int len);
+ virtual data_handler::result operator()(const void *base, size_t len);
+
+ size_t bytes() const { return d_bytes; }
+ size_t times() const { return d_times; }
+
+ static const size_t MIN_COPY_LEN = 1484; // FIXME: calculate eth packet -
thdr
+ bool full() const { return d_space < MIN_COPY_LEN; }
};
} // namespace usrp2
Modified:
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/data_handler.h
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/data_handler.h
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/data_handler.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -22,24 +22,32 @@
#define INCLUDED_DATA_HANDLER_H
#include <stdint.h>
+#include <stddef.h>
namespace usrp2 {
/*!
- * \brief abstract function object called to handle received data blocks
+ * \brief Abstract function object called to handle received data blocks.
*/
class data_handler
{
public:
- static const unsigned int KEEP = 0x0001; // do not discard data
- static const unsigned int DONE = 0x0002; // do not call this object again
+
+ enum result_bits {
+ RELEASE = 0x0000, //< OK to release data (opposite of KEEP)
+ KEEP = 0x0001, //< do not discard data
+ DONE = 0x0002, //< do not call this object again
+ };
+ typedef int result; //< bitmask of result_bits
+
/*!
* \param base points to the beginning of the data
* \param len is the length in bytes of the data
+ * \returns bitmask composed of DONE, KEEP
*/
- virtual unsigned int operator()(const void *base, unsigned int len) = 0;
- virtual ~data_handler();
+ virtual result operator()(const void *base, size_t len) = 0;
+ virtual ~data_handler();
};
} // namespace usrp2
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/metadata.h
(from rev 9111,
usrp2/branches/features/host-ng/host-ng/include/usrp2/metadata.h)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/metadata.h
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/metadata.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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/>.
+ */
+#ifndef INCLUDED_USRP2_METADATA_H
+#define INCLUDED_USRP2_METADATA_H
+
+#include <stdint.h>
+
+namespace usrp2 {
+
+ //! type of the timestamp returned from the USRP2 FPGA
+ typedef uint32_t fpga_timestamp;
+
+ /*!
+ * \brief metadata associated with received frames
+ */
+ struct rx_metadata {
+ uint32_t word0; //< debugging, extensions
+ fpga_timestamp timestamp; //< time that first sample of
frame was received
+ unsigned int start_of_burst : 1; //< this frame is the start of
a burst
+ unsigned int end_of_burst : 1; //< this frame is the end of a
burst
+ unsigned int rx_overrun : 1; //< An Rx overrun occurred in
the FPGA
+ // rssi
+ // agc_mode
+
+ rx_metadata() :
+ word0(0), timestamp(0), start_of_burst(0), end_of_burst(0),
rx_overrun(0) {}
+ };
+
+ /*!
+ * \brief metadata associated with transmitted frames
+ */
+ struct tx_metadata {
+ fpga_timestamp timestamp; //< time to transmit first
sample of frame
+ unsigned int send_now : 1; //< ignore timestamp, send now
+ unsigned int start_of_burst : 1; //< this frame is the start of
a burst
+ unsigned int end_of_burst : 1; //< this frame is the end of a
burst
+ // ...
+
+ tx_metadata() :
+ timestamp(0), send_now(0), start_of_burst(0), end_of_burst(0) {}
+ };
+
+}; // usrp2
+
+#endif /* INCLUDED_USRP2_METADATA_H */
Copied:
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/rx_sample_handler.h
(from rev 9111,
usrp2/branches/features/host-ng/host-ng/include/usrp2/rx_sample_handler.h)
===================================================================
---
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/rx_sample_handler.h
(rev 0)
+++
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/rx_sample_handler.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,58 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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/>.
+ */
+#ifndef INCLUDED_USRP2_RX_SAMPLE_HANDLER_H
+#define INCLUDED_USRP2_RX_SAMPLE_HANDLER_H
+
+#include <usrp2/metadata.h>
+#include <stddef.h>
+
+
+namespace usrp2 {
+
+ /*!
+ * \brief Abstract function object called to handle received data blocks.
+ *
+ * An object derived from this class is passed to usrp2::rx_samples
+ * to process the received frames of samples.
+ */
+ class rx_sample_handler {
+ public:
+ virtual ~rx_sample_handler();
+
+ /*!
+ * \param items points to the first 32-bit word of uninterpreted sample
data in the frame.
+ * \param nitems is the number of entries in the frame in units of
uint32_t's.
+ * \param metadata is the additional per frame data provided by the USRP2
FPGA.
+ *
+ * \p items points to the raw sample data received off of the ethernet.
The data is
+ * packed into big-endian 32-bit unsigned ints for transport, but the
actual format
+ * of the data is dependent on the current configuration of the USRP2.
The most common
+ * format is 16-bit I & Q, with I in the top of the 32-bit word.
+ *
+ * This is the general purpose, low level interface and relies on other
functions
+ * to handle all required endian-swapping and format conversion. \sa
FIXME.
+ *
+ * \returns true if the object wants to be called again with new data;
+ * false if no additional data is wanted.
+ */
+ virtual bool operator()(const uint32_t *items, size_t nitems, const
rx_metadata *metadata) = 0;
+ };
+
+};
+
+#endif /* INCLUDED_RX_SAMPLE_HANDLER_H */
Copied:
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/strtod_si.h (from
rev 9111, usrp2/branches/features/host-ng/host-ng/include/usrp2/strtod_si.h)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/strtod_si.h
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/strtod_si.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 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/>.
+ */
+
+#ifndef INCLUDED_STRTOD_SI_H
+#define INCLUDED_STRTOD_SI_H
+
+#include "usrp2_cdefs.h"
+__U2_BEGIN_DECLS
+
+
+/*!
+ * \brief convert string at s to double honoring any trailing SI suffixes
+ *
+ * \param[in] s is the string to convert
+ * \param[out] result is the converted value
+ * \returns non-zero iff conversion was successful.
+ */
+int strtod_si(const char *s, double *result);
+
+__U2_END_DECLS
+
+
+#endif /* INCLUDED_STRTOD_SI_H */
+
Copied:
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/tune_result.h
(from rev 9111,
usrp2/branches/features/host-ng/host-ng/include/usrp2/tune_result.h)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/tune_result.h
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/tune_result.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,45 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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/>.
+ */
+
+#ifndef INCLUDED_TUNE_RESULT_H
+#define INCLUDED_TUNE_RESULT_H
+
+namespace usrp2 {
+
+ class tune_result
+ {
+ public:
+ // RF frequency that corresponds to DC in the IF
+ double baseband_freq;
+
+ // frequency programmed into the DDC/DUC
+ double dxc_freq;
+
+ // residual frequency (typically < 0.01 Hz)
+ double residual_freq;
+
+ // is the spectrum inverted?
+ bool spectrum_inverted;
+
+ tune_result()
+ : baseband_freq(0), dxc_freq(0), residual_freq(0),
spectrum_inverted(false) {}
+ };
+
+} // namespace usrp2
+
+#endif /* INCLUDED_TUNE_RESULT_H */
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/usrp2.h
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/usrp2.h
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/usrp2.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -22,130 +22,179 @@
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
+#include <usrp2/rx_sample_handler.h>
namespace usrp2 {
-/*!
- * Structure to hold properties of USRP2 hardware devices.
- *
- */
-struct props
-{
- std::string addr;
- uint16_t hw_rev;
- uint8_t fpga_md5sum[16];
- uint8_t sw_md5sum[16];
-};
+ /*!
+ * Structure to hold properties of USRP2 hardware devices.
+ *
+ */
+ struct props
+ {
+ std::string addr;
+ uint16_t hw_rev;
+ uint8_t fpga_md5sum[16];
+ uint8_t sw_md5sum[16];
+ };
-typedef std::vector<props> props_vector_t;
+ typedef std::vector<props> props_vector_t;
-props_vector_t find(const std::string &ifc, const std::string &addr="");
+ /*!
+ * \brief Search the ethernet for all USRP2s or for a specific USRP2.
+ *
+ * \param ifc is the name of the OS ethernet interface (e.g., "eth0")
+ * \param mac_addr is the MAC address of the desired USRP2, or "" to search
for all.
+ * mac_addr must be either a zero length string, "", or must be of the form
+ * "01:02:03:04:05:06" or "05:06".
+ *
+ * \returns a vector of properties, 1 entry for each matching USRP2 found.
+ */
+ props_vector_t find(const std::string &ifc, const std::string &mac_addr="");
-/*!
- * Structure to hold results of tuning
- */
-class usrp2_tune_result
-{
-public:
- // RF frequency that corresponds to DC in the IF
- double baseband_freq;
+ class tune_result;
+
+ class usrp2 : boost::noncopyable
+ {
+ public:
+ static const unsigned int MAX_CHAN = 30;
- // frequency programmed into the DDC/DUC
- double dxc_freq;
+ /*!
+ * Shared pointer to this class
+ */
+ typedef boost::shared_ptr<usrp2> sptr;
+
+ /*!
+ * Static function to return an instance of usrp2 as a shared pointer
+ *
+ * \param ifc Network interface name, e.g., "eth0"
+ * \param addr Network mac address, e.g., "01:02:03:04:05:06", "05:06" or
"".
+ * "" will autoselect a USRP2 if there is only a single one
on the local ethernet.
+ */
+ static sptr make(const std::string &ifc, const std::string &addr="");
- // residual frequency (typically < 0.01 Hz)
- double residual_freq;
+ /*!
+ * Class destructor
+ */
+ ~usrp2();
- // is the spectrum inverted?
- bool spectrum_inverted;
+ /*
+ * ----------------------------------------------------------------
+ * Rx configuration and control
+ * ----------------------------------------------------------------
+ */
- usrp2_tune_result()
- : baseband_freq(0), dxc_freq(0), residual_freq(0),
spectrum_inverted(false) {}
- ~usrp2_tune_result();
-};
+ /*!
+ * Set receiver gain
+ */
+ bool set_rx_gain(double gain);
-class usrp2 : boost::noncopyable
-{
-public:
- /*!
- * Shared pointer to this class
- */
- typedef boost::shared_ptr<usrp2> sptr;
-
- /*!
- * Static function to return an instance of usrp2 as a shared pointer
- *
- * \param ifc Network interface name, e.g., "eth0"
- * \param addr Network mac address, e.g., "01:02:03:04:05:06" or "05:06",
- * default is auto-select
- */
- static sptr make(const std::string &ifc, const std::string &addr="");
+ /*!
+ * Set receiver center frequency
+ */
+ bool set_rx_center_freq(double frequency, tune_result *result);
- /*!
- * Class destructor
- */
- ~usrp2();
+ /*!
+ * Set receiver sample rate decimation
+ */
+ bool set_rx_decim(int decimation_factor);
- /*
- * Rx configuration and control
- */
+ /*!
+ * Set receiver IQ magnitude scaling
+ */
+ bool set_rx_scale_iq(int scale_i, int scale_q);
- /*!
- * Set receiver gain
- */
- bool set_rx_gain(double gain);
+ /*!
+ * Set received sample format
+ *
+ * domain: complex or real
+ * type: floating, fixed point, or raw
+ * depth: bits per sample
+ *
+ * Sets format over the wire for samples from USRP2.
+ */
+ // bool set_rx_format(...);
- /*!
- * Set receiver center frequency
- */
- bool set_rx_freq(double frequency, usrp2_tune_result *result);
+ /*!
+ * Start streaming receive mode. USRP2 will send a continuous stream of
+ * DSP pipeline samples to host. Call rx_samples(...) to access.
+ *
+ * \param channel Stream channel number (0-30)
+ * \param items_per_frame Number of 32-bit items per frame.
+ */
+ bool start_rx_streaming(unsigned int channel=0, unsigned int
items_per_frame=0);
+
+ /*!
+ * Stop streaming receive mode.
+ */
+ bool stop_rx_streaming(unsigned int channel=0);
- /*!
- * Set receiver sample rate decimation
- */
- bool set_rx_decim(int decimation_factor);
+ /*!
+ * \brief Receive data from the specified channel
+ * This method is used to receive all data: streaming or discrete.
+ */
+ bool rx_samples(unsigned int channel, rx_sample_handler *handler);
- /*!
- * Set receiver IQ magnitude scaling
- */
- bool set_rx_scale_iq(int scale_i, int scale_q);
+ /*!
+ * Returns number of times receive overruns have occurred
+ */
+ unsigned int rx_overruns();
+
+ /*!
+ * Returns total number of missing frames from overruns.
+ */
+ unsigned int rx_missing();
- /*!
- * Set received sample format
- *
- * domain: complex or real
- * type: floating, fixed point, or raw
- * depth: bits per sample
- *
- * Sets format over the wire for samples from USRP2 and determines
- * default reader and writer functors
- *
- */
- // bool set_rx_format(...);
+ /*
+ * ----------------------------------------------------------------
+ * Tx configuration and control
+ * ----------------------------------------------------------------
+ */
- /*!
- * Start streaming receive mode. USRP2 will send a continuous stream of
- * DSP pipeline samples to host. Call rx_samples(...) to access.
- *
- * \param items_per_frame Interpreted according to current receive format
- */
- bool start_rx_streaming(unsigned int items_per_frame=0);
-
- /*!
- * Stop streaming receive mode.
- */
- bool stop_rx_streaming();
+ /*!
+ * Set receiver gain
+ */
+ bool set_tx_gain(double gain);
- /* Ignore :-) */
- class impl;
+ /*!
+ * Set transmitter center frequency
+ */
+ bool set_tx_center_freq(double frequency, tune_result *result);
-private:
- // Only usrp2::make factory function can instantiate this class
- usrp2(const std::string &ifc, const std::string &addr);
+ /*!
+ * Set transmitter sample rate interpolation
+ */
+ bool set_tx_interp(int interpolation_factor);
+
+ /*!
+ * Set transmit IQ magnitude scaling
+ */
+ bool set_tx_scale_iq(int scale_i, int scale_q);
+
+ /*!
+ * Set transmit sample format
+ *
+ * domain: complex or real
+ * type: floating, fixed point, or raw
+ * depth: bits per sample
+ *
+ * Sets format over the wire for samples to USRP2.
+ */
+ // bool set_tx_format(...);
+
+ // bool tx_samples(...)
+
+
+
+ class impl; // implementation details
+
+ private:
+ // Only usrp2::make factory function can instantiate this class
+ usrp2(const std::string &ifc, const std::string &addr);
- // All private state is held in opaque pointer
- std::auto_ptr<impl> d_impl;
-};
+ // All private state is held in opaque pointer
+ std::auto_ptr<impl> d_impl;
+ };
};
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/Makefile.am
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/Makefile.am
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/Makefile.am
2008-08-01 04:40:47 UTC (rev 9115)
@@ -17,25 +17,31 @@
include $(top_srcdir)/Makefile.common
-AM_CPPFLAGS = -Wall -Werror
-INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES)
+#AM_CXXFLAGS = -Wall -Werror (handle this with: $ ./configure CXXFLAGS="-Wall
-Werror -O2 -g")
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) $(GRUEL_CFLAGS)
$(BOOST_CFLAGS)
lib_LTLIBRARIES = \
libusrp2ng.la
libusrp2ng_la_SOURCES = \
control.cc \
+ copiers.cc \
copy_handler.cc \
+ data_handler.cc \
eth_buffer.cc \
ethernet.cc \
find.cc \
pktfilter.cc \
+ ring.cc \
+ rx_sample_handler.cc \
+ strtod_si.c \
usrp2.cc \
usrp2_impl.cc \
usrp2_thread.cc
libusrp2ng_la_LIBADD = \
- $(GR_OMNITHREAD_LIBS)
+ $(GR_OMNITHREAD_LIBS) \
+ $(GRUEL_LIBS)
# Private headers not needed for above the API development
noinst_HEADERS = \
@@ -44,5 +50,6 @@
eth_common.h \
ethernet.h \
pktfilter.h \
+ ring.h \
usrp2_impl.h \
usrp2_thread.h
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.cc
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -23,28 +23,28 @@
#include <config.h>
#endif
+#include <omni_time.h>
#include "control.h"
#include <iostream>
namespace usrp2 {
- pending_reply::pending_reply(int rid, void *buffer, int len)
+ pending_reply::pending_reply(unsigned int rid, void *buffer, size_t len)
: d_rid(rid), d_mutex(), d_cond(&d_mutex), d_buffer(buffer), d_len(len)
{
}
pending_reply::~pending_reply()
{
- signal();
+ signal(); // Needed?
}
int
- pending_reply::wait(int secs, long nsecs)
+ pending_reply::wait(double secs)
{
- int res = d_cond.timedwait(secs, nsecs);
- if (res == 0)
- std::cerr << "usrp2: no response to command packet" << std::endl;
- return res;
+ omni_mutex_lock l(d_mutex);
+ omni_time abs_timeout = omni_time::time(omni_time(secs));
+ return d_cond.timedwait(abs_timeout.d_secs, abs_timeout.d_nsecs);
}
void
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.h
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.h
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/control.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -30,27 +30,48 @@
{
u2_eth_packet_t h;
op_config_rx_v2_t op;
- op_eop_t eop;
+ op_generic_t eop;
};
+ struct op_start_rx_streaming_cmd
+ {
+ u2_eth_packet_t h;
+ op_start_rx_streaming_t op;
+ op_generic_t eop;
+ };
+
+ struct op_stop_rx_cmd {
+ u2_eth_packet_t h;
+ op_generic_t op;
+ op_generic_t eop;
+ };
+
+ struct op_config_tx_v2_cmd
+ {
+ u2_eth_packet_t h;
+ op_config_tx_v2_t op;
+ op_generic_t eop;
+ };
+
+
/*!
* Control mechanism to allow API calls to block waiting for reply packets
*/
class pending_reply
{
private:
- int d_rid;
+ unsigned int d_rid;
omni_mutex d_mutex;
omni_condition d_cond;
void *d_buffer;
- int d_len;
+ size_t d_len;
public:
/*!
* Construct a pending reply from the reply ID, response packet
* buffer, and buffer length.
*/
- pending_reply(int rid, void *buffer, int len);
+ pending_reply(unsigned int rid, void *buffer, size_t len);
/*!
* Destructor. Signals creating thread.
@@ -62,7 +83,7 @@
* Returns: 1 = ok, reply packet in buffer
* 0 = timeout
*/
- int wait(int secs, long nsecs);
+ int wait(double secs);
/*!
* Allows creating thread to resume after copying reply into buffer
@@ -72,12 +93,17 @@
/*!
* Retrieve pending reply ID
*/
- int rid() const { return d_rid; }
+ unsigned int rid() const { return d_rid; }
/*!
* Retrieve destination buffer address
*/
void *buffer() const { return d_buffer; }
+
+ /*!
+ * Retrieve destination buffer length
+ */
+ size_t len() const { return d_len; }
};
} // namespace usrp2
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/lib/copiers.cc (from rev
9111, usrp2/branches/features/host-ng/host-ng/lib/copiers.cc)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/copiers.cc
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/copiers.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,133 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <usrp2/copiers.h>
+#include <gruel/inet.h>
+#include <gr_math.h>
+#include <math.h>
+#include <stdexcept>
+#include <assert.h>
+#include <string.h>
+
+// FIXME need gruel::not_implemented
+
+namespace usrp2 {
+
+ /*
+ * N.B., in all of these, uint32_t *items is NOT 32-bit aligned!
+ * FIXME Needs fix for non-x86 machines.
+ */
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from USRP2 wire format to host format
+ * ----------------------------------------------------------------
+ */
+ void
+ copy_u2_complex_16_to_host_complex_16(size_t nitems,
+ const uint32_t *items,
+ std::complex<int16_t> *host_items)
+ {
+#ifdef WORDS_BIGENDIAN
+
+ assert(sizeof(items[0]) == sizeof(host_items[0]));
+ memcpy(host_items, items, nitems * sizeof(items[0]));
+
+#else
+
+ // FIXME SIMD welcome here
+
+ for (size_t i = 0; i < nitems; i++){
+ uint32_t t = ntohx(items[i]);
+ //printf("%9d\n", items[i]);
+ host_items[i] = std::complex<int16_t>((t >> 16), t & 0xffff);
+ }
+
+#endif
+ }
+
+
+ /*
+ * endian swap if required and map [-32768, 32767] -> [1.0, +1.0)
+ */
+ void
+ copy_u2_complex_16_to_host_complex_float(size_t nitems,
+ const uint32_t *items,
+ std::complex<float> *host_items)
+ {
+ for (size_t i = 0; i < nitems; i++){
+ uint32_t t = ntohx(items[i]);
+ int16_t re = (t >> 16) & 0xffff;
+ int16_t im = (t & 0xffff);
+ host_items[i] = std::complex<float>(re * 1.0/32768, im * 1.0/32768);
+ }
+ }
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from host format to USRP2 wire format
+ * ----------------------------------------------------------------
+ */
+ void
+ copy_host_complex_16_to_u2_complex_16(size_t nitems,
+ const std::complex<int16_t> *host_items,
+ uint32_t *items)
+ {
+#ifdef WORDS_BIGENDIAN
+
+ assert(sizeof(items[0]) == sizeof(host_items[0]));
+ memcpy(items, host_items, nitems * sizeof(items[0]));
+
+#else
+
+ // FIXME SIMD welcome here
+
+ for (size_t i = 0; i < nitems; i++){
+ items[i] = htonl((host_items[i].real() << 16) | (host_items[i].imag() &
0xffff));
+ }
+
+#endif
+ }
+
+
+ static inline int16_t
+ clip_and_scale(float x)
+ {
+ return static_cast<int16_t>(rintf(gr_branchless_clip(x, 1.0) * 32767.0));
+ }
+
+ void
+ copy_host_complex_float_to_u2_complex_16(size_t nitems,
+ const std::complex<float>
*host_items,
+ uint32_t *items)
+ {
+ for (size_t i = 0; i < nitems; i++){
+ int16_t re = clip_and_scale(host_items[i].real());
+ int16_t im = clip_and_scale(host_items[i].imag());
+
+ items[i] = htonl((re << 16) | (im & 0xffff));
+ }
+ }
+
+}
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/copy_handler.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/copy_handler.cc
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/copy_handler.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -24,10 +24,11 @@
#endif
#include <usrp2/copy_handler.h>
+#include <iostream>
namespace usrp2 {
- copy_handler::copy_handler(void *dest, unsigned int len)
+ copy_handler::copy_handler(void *dest, size_t len)
: d_dest((uint8_t *)dest), d_space(len), d_bytes(0), d_times(0)
{
}
@@ -37,8 +38,8 @@
// NOP
}
- uint32_t
- copy_handler::operator()(const void *base, unsigned int len)
+ data_handler::result
+ copy_handler::operator()(const void *base, size_t len)
{
if (len > d_space)
return KEEP|DONE; // can't do anything, retry later
@@ -47,10 +48,10 @@
d_space -= len;
d_bytes += len;
d_times++;
+
+ if (d_space < MIN_COPY_LEN)
+ return DONE; // don't call me anymore
- if (d_space == 0)
- return DONE; // don't call me anymore
-
return 0;
}
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/lib/data_handler.cc
(from rev 9111, usrp2/branches/features/host-ng/host-ng/lib/data_handler.cc)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/data_handler.cc
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/data_handler.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,32 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <usrp2/data_handler.h>
+
+namespace usrp2 {
+
+ data_handler::~data_handler()
+ {
+ // default nop destructor
+ }
+
+}
+
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.cc
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -33,8 +33,10 @@
#include <iostream>
#include <cmath>
#include <errno.h>
+#include <stdexcept>
-#define ETH_BUFFER_DEBUG 1 // define to 0 or 1
+
+#define ETH_BUFFER_DEBUG 0 // define to 0 or 1
#if ETH_BUFFER_DEBUG
#define DEBUG_LOG(x) ::write(2, (x), 1)
#else
@@ -47,18 +49,10 @@
namespace usrp2 {
- data_handler::~data_handler()
- {
- // default nop destructor
- }
-
eth_buffer::eth_buffer(size_t rx_bufsize)
: d_fd(0), d_using_tpring(false), d_buflen(0), d_buf(0), d_frame_nr(0),
- d_head(0), d_ring(0), d_ethernet(new ethernet())
+ d_frame_size(0), d_head(0), d_ring(0), d_ethernet(new ethernet())
{
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: constructor" << std::endl;
-
if (rx_bufsize == 0)
d_buflen = (size_t)MAX_MEM_SIZE;
else
@@ -69,19 +63,12 @@
eth_buffer::~eth_buffer()
{
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: destructor" << std::endl;
-
close();
}
bool
eth_buffer::open(const std::string &ifname, int protocol)
{
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: using interface " << ifname
- << ", protocol=" << protocol << std::endl;
-
if (!d_ethernet->open(ifname, protocol)) {
std::cerr << "eth_buffer: unable to open interface "
<< ifname << std::endl;
@@ -97,6 +84,7 @@
// Calculate minimum power-of-two aligned size for frames
req.tp_frame_size =
(unsigned int)rint(pow(2,
ceil(log2(TPACKET_ALIGN(TPACKET_HDRLEN)+TPACKET_ALIGN(MAX_PKT_SIZE)))));
+ d_frame_size = req.tp_frame_size;
// Calculate minimum contiguous pages needed to enclose a frame
int npages = (page_size > req.tp_frame_size) ? 1 :
((req.tp_frame_size+page_size-1)/page_size);
@@ -114,6 +102,7 @@
req.tp_frame_nr = d_buflen/req.tp_frame_size;
d_frame_nr = req.tp_frame_nr;
+#if 0
if (ETH_BUFFER_DEBUG)
std::cerr << "eth_buffer:"
<< " frame_size=" << req.tp_frame_size
@@ -122,6 +111,7 @@
<< " frame_nr=" << req.tp_frame_nr
<< " buflen=" << d_buflen
<< std::endl;
+#endif
// Try to get kernel shared memory buffer
if (setsockopt(d_fd, SOL_PACKET, PACKET_RX_RING, (void *)&req,
sizeof(req))) {
@@ -132,27 +122,25 @@
return false;
}
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: using malloc'd memory for buffer" <<
std::endl;
+ std::cerr << "eth_buffer: using malloc'd memory for buffer" << std::endl;
}
else {
d_using_tpring = true;
- d_buf = (uint8_t *)mmap(0, d_buflen, PROT_READ|PROT_WRITE, MAP_SHARED,
d_fd, 0);
- if (!d_buf) {
+ void *p = mmap(0, d_buflen, PROT_READ|PROT_WRITE, MAP_SHARED, d_fd, 0);
+ if (p == MAP_FAILED){
perror("eth_buffer: mmap");
return false;
}
+ d_buf = (uint8_t *) p;
if (ETH_BUFFER_DEBUG)
std::cerr << "eth_buffer: using kernel shared mem for buffer" <<
std::endl;
}
- // Initialize packet ring
+ // Initialize our pointers into the packet ring
d_ring = std::vector<uint8_t *>(req.tp_frame_nr);
for (unsigned int i=0; i < req.tp_frame_nr; i++) {
d_ring[i] = (uint8_t *)(d_buf+i*req.tp_frame_size);
- ((tpacket_hdr *)(d_ring[i]))->tp_status = TP_STATUS_KERNEL; // free
- ((tpacket_hdr *)(d_ring[i]))->tp_len = req.tp_frame_size;
}
// If not using kernel ring, instantiate select/read thread here
@@ -183,15 +171,15 @@
return (((tpacket_hdr *)d_ring[d_head])->tp_status != TP_STATUS_KERNEL);
}
- int
- eth_buffer::rx_frames(data_handler *f, int timeout)
+ eth_buffer::result
+ eth_buffer::rx_frames(data_handler *f, int timeout_in_ms)
{
- DEBUG_LOG("'");
+ DEBUG_LOG("\n");
while (!frame_available()) {
- if (timeout == 0) {
+ if (timeout_in_ms == 0) {
DEBUG_LOG("w");
- return 0; // would block
+ return EB_WOULD_BLOCK;
}
struct pollfd pfd;
@@ -201,16 +189,15 @@
DEBUG_LOG("P");
- int pres = poll(&pfd, 1, timeout);
+ int pres = poll(&pfd, 1, timeout_in_ms);
if (pres == -1) {
perror("poll");
- DEBUG_LOG("E");
- return -1;
+ return EB_ERROR;
}
if (pres == 0) {
- DEBUG_LOG("-");
- return 2;
+ DEBUG_LOG("t");
+ return EB_TIMED_OUT;
}
}
@@ -219,37 +206,52 @@
// Get start of ethernet frame and length
tpacket_hdr *hdr = (tpacket_hdr *)d_ring[d_head];
void *base = (uint8_t *)hdr+hdr->tp_mac;
- unsigned int len = hdr->tp_len;
+ size_t len = hdr->tp_len;
+ // FYI, (base % 4 == 2) Not what we want given the current FPGA
+ // code. This means that our uint32_t samples are not 4-byte
+ // aligned. We'll have to deal with it downstream.
+
+ if (0)
+ fprintf(stderr, "eth_buffer: base = %p tp_mac = %3d tp_net = %3d\n",
+ base, hdr->tp_mac, hdr->tp_net);
+
// Invoke data handler
- unsigned int r = 0;
- r = (*f)(base, len);
-
- // data_handler::KEEP not yet implemented
- hdr->tp_status = TP_STATUS_KERNEL; // mark it free
- if (++d_head == d_frame_nr)
- d_head = 0;
+ data_handler::result r = (*f)(base, len);
+ if (!(r & data_handler::KEEP))
+ hdr->tp_status = TP_STATUS_KERNEL; // mark it free
+ inc_head();
+
if (r & data_handler::DONE)
break;
}
DEBUG_LOG("|");
- return 1;
+ return EB_OK;
}
- int
+ eth_buffer::result
eth_buffer::tx_frame(const void *base, size_t len, int flags)
{
- // TODO: implement flags
DEBUG_LOG("T");
+
+ if (flags & EF_DONTWAIT) // FIXME: implement flags
+ throw std::runtime_error("tx_frame: EF_DONTWAIT not implemented");
+
int res = d_ethernet->write_packet(base, len);
-
if (res < 0 || (unsigned int)res != len)
- return -1;
+ return EB_ERROR;
- return 1;
+ return EB_OK;
}
+
+ void
+ eth_buffer::release_frame(void *base)
+ {
+ // Get d_frame_size aligned header
+ tpacket_hdr *hdr = (tpacket_hdr *)((intptr_t)base & ~(d_frame_size-1));
+ hdr->tp_status = TP_STATUS_KERNEL; // mark it free
+ }
} // namespace usrp2
-
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.h
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.h
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/eth_buffer.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -49,6 +49,7 @@
size_t d_buflen; // length of our buffer
uint8_t *d_buf; // packet ring
unsigned int d_frame_nr; // max frames on ring
+ size_t d_frame_size; // frame storage size
unsigned int d_head; // pointer to next frame
std::vector<uint8_t *> d_ring; // pointers into buffer
@@ -56,8 +57,24 @@
bool frame_available();
+ void inc_head()
+ {
+ if (d_head + 1 >= d_frame_nr)
+ d_head = 0;
+ else
+ d_head = d_head + 1;
+ }
+
+
public:
+ enum result {
+ EB_OK, //< everything's fine
+ EB_ERROR, //< A non-recoverable error occurred
+ EB_WOULD_BLOCK, //< A timeout of 0 was specified and nothing was ready
+ EB_TIMED_OUT, //< The timeout expired before anything was ready
+ };
+
static const unsigned int MAX_PKTLEN = 1512;
static const unsigned int MIN_PKTLEN = 64;
@@ -96,7 +113,7 @@
/*!
* \brief Call \p f for each frame in the receive buffer.
* \param f is the frame data handler
- * \param timeout controls behavior when there are no frames to read
+ * \param timeout (in ms) controls behavior when there are no frames to
read
*
* If \p timeout is 0, rx_frames will not wait for frames if none are
* available, and f will not be invoked. If \p timeout is -1 (the
@@ -107,14 +124,14 @@
* invoked.
*
* \p f will be called on each ethernet frame that is available.
- * \p f returns a bit vector with one of the following set or cleared:
+ * \p f returns a bit mask with one of the following set or cleared:
*
* data_handler::KEEP - hold onto the frame and present it again during
- the next call to rx_frames, otherwise discard it
+ * the next call to rx_frames, otherwise discard it
*
- * data_handler::BREAK - return from rx_frames even though more frames
- * might be available, otherwise continue if more
- * frames are ready
+ * data_handler::DONE - return from rx_frames now even though more frames
+ * might be available; otherwise continue if more
+ * frames are ready.
*
* The idea of holding onto a frame for the next iteration allows
* the caller to scan the received packet stream for particular
@@ -123,14 +140,22 @@
* frames received, will be presented in order to \p f.
* See usrp2.cc for an example of the pattern.
*
- * \returns 0 if \p timeout is 0 and the call would have blocked
- * \returns 1 if at least one frame was received
- * \returns 2 if timeout occurred
- * \returns -1 if there was an unrecoverable error.
+ * \returns EB_OK if at least one frame was received
+ * \returns EB_WOULD_BLOCK if \p timeout is 0 and the call would have
blocked
+ * \returns EB_TIMED_OUT if timeout occurred
+ * \returns EB_ERROR if there was an unrecoverable error.
*/
- int rx_frames(data_handler *f, int timeout=-1);
+ result rx_frames(data_handler *f, int timeout=-1);
/*
+ * \brief Release frame from buffer
+ *
+ * Call to release a frame previously held by a data_handler::KEEP.
+ * The pointer may be offset from the base of the frame up to its length.
+ */
+ void release_frame(void *p);
+
+ /*
* \brief Write an ethernet frame to the interface.
*
* \param base points to the beginning of the frame (the 14-byte ethernet
header).
@@ -139,11 +164,11 @@
*
* The frame must begin with a 14-byte ethernet header.
*
- * \returns 0 if flags contains EF_DONT_WAIT and the call would have
blocked
- * \returns 1 if the frame was successfully enqueued.
- * \returns -1 if there was an unrecoverable error.
+ * \returns EB_OK if the frame was successfully enqueued.
+ * \returns EB_WOULD_BLOCK if flags contains EF_DONT_WAIT and the call
would have blocked.
+ * \returns EB_ERROR if there was an unrecoverable error.
*/
- int tx_frame(const void *base, size_t len, int flags=0);
+ result tx_frame(const void *base, size_t len, int flags=0);
/*
* \brief Write an ethernet frame to the interface using scatter/gather.
@@ -154,11 +179,17 @@
*
* The frame must begin with a 14-byte ethernet header.
*
- * \returns 0 if flags contains EF_DONT_WAIT and the call would have
blocked
- * \returns 1 if the frame was successfully enqueued.
- * \returns -1 if there was an unrecoverable error.
+ * \returns EB_OK if the frame was successfully enqueued.
+ * \returns EB_WOULD_BLOCK if flags contains EF_DONT_WAIT and the call
would have blocked.
+ * \returns EB_ERROR if there was an unrecoverable error.
*/
- int tx_framev(const eth_iovec *iov, int iovcnt, int flags=0);
+ result tx_framev(const eth_iovec *iov, int iovcnt, int flags=0);
+
+ /*
+ * \brief Returns maximum possible number of frames in buffer
+ */
+ unsigned int max_frames() const { return d_frame_nr; }
+
};
}; // namespace usrp2
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/find.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/find.cc 2008-08-01
04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/find.cc 2008-08-01
04:40:47 UTC (rev 9115)
@@ -23,14 +23,91 @@
#include <usrp2_eth_packet.h>
#include <usrp2/usrp2.h>
#include <boost/scoped_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "ethernet.h"
#include "pktfilter.h"
#include <iostream>
+#include <stdexcept>
#define FIND_DEBUG 0
+
+// FIXME move to gruel
+
+static struct timeval
+time_duration_to_timeval(boost::posix_time::time_duration delta)
+{
+ long total_us = delta.total_microseconds();
+ if (total_us < 0)
+ throw std::invalid_argument("duration_to_time: delta is negative");
+
+ struct timeval tv;
+ tv.tv_sec = total_us / 1000000;
+ tv.tv_usec = total_us % 1000000;
+ return tv;
+}
+
+
namespace usrp2 {
+ static props
+ reply_to_props(const op_id_reply_t *r)
+ {
+ const uint8_t *mac = (const uint8_t *)&r->addr;
+ char addr_buf[128];
+ snprintf(addr_buf, sizeof(addr_buf), "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ props p;
+ p.addr = std::string(addr_buf);
+ p.hw_rev = ntohs(r->hw_rev);
+ memcpy(p.fpga_md5sum, r->fpga_md5sum, sizeof(p.fpga_md5sum));
+ memcpy(p.sw_md5sum, r->sw_md5sum, sizeof(p.sw_md5sum));
+ return p;
+ }
+
+ static void
+ read_replies(ethernet *enet, struct timeval timeout,
+ const std::string &target_addr, props_vector_t &result)
+ {
+ struct reply {
+ u2_eth_packet_t h;
+ op_id_reply_t op_id_reply;
+ };
+
+ uint8_t pktbuf[ethernet::MAX_PKTLEN];
+ memset(pktbuf, 0, sizeof(pktbuf));
+
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(enet->fd(), &read_fds);
+
+ select(enet->fd()+1, &read_fds, 0, 0, &timeout);
+ while(1) {
+ memset(pktbuf, 0, sizeof(pktbuf));
+ int len = enet->read_packet_dont_block(pktbuf, sizeof(pktbuf));
+ if (len < 0){
+ perror("usrp2_basic: read_packet_dont_block");
+ return;
+ }
+ if (len == 0)
+ break;
+
+ reply *rp = (reply *)pktbuf;
+ if (u2p_chan(&rp->h.fixed) != CONTROL_CHAN) // ignore
+ continue;
+ if (rp->op_id_reply.opcode != OP_ID_REPLY) // ignore
+ continue;
+
+ props p = reply_to_props(&rp->op_id_reply);
+ if (FIND_DEBUG)
+ std::cerr << "usrp2::find: response from " << p.addr << std::endl;
+
+ if ((target_addr == "") || (target_addr == p.addr))
+ result.push_back(p);
+ }
+ }
+
props_vector_t
find(const std::string &ifc, const std::string &addr)
{
@@ -43,15 +120,9 @@
props_vector_t result;
struct command {
u2_eth_packet_t h;
- op_id_t op_id;
+ op_generic_t op_id;
};
- struct reply {
- u2_eth_packet_t h;
- op_id_reply_t op_id_reply;
- };
-
- std::vector<op_id_reply_t> replies;
std::auto_ptr<ethernet> enet(new ethernet());
if (!enet->open(ifc, htons(U2_ETHERTYPE)))
@@ -77,7 +148,7 @@
u2p_set_word0(&c->h.fixed, 0, CONTROL_CHAN);
u2p_set_timestamp(&c->h.fixed, -1);
c->op_id.opcode = OP_ID;
- c->op_id.len = sizeof(op_id_t);
+ c->op_id.len = sizeof(c->op_id);
int len = std::max((size_t) ethernet::MIN_PKTLEN, sizeof(command));
if (enet->write_packet(c, len) != len)
return result;
@@ -86,50 +157,22 @@
std::cerr << "usrp2::find: broadcast ID command" << std::endl;
/*
- * Wait no longer than 10ms and read all packets available.
+ * Gather all responses that occur within 50ms
*/
- fd_set read_fds;
- FD_ZERO(&read_fds);
- FD_SET(enet->fd(), &read_fds);
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 10 * 1000; // 10 ms
-
- select(enet->fd()+1, &read_fds, 0, 0, &timeout);
- while(1) {
- memset(pktbuf, 0, sizeof(pktbuf));
- len = enet->read_packet_dont_block(pktbuf, sizeof(pktbuf));
- if (len < 0){
- perror("usrp2_basic: read_packet_dont_block");
- return result;
- }
- if (len == 0)
+ boost::posix_time::ptime
start(boost::posix_time::microsec_clock::universal_time());
+ boost::posix_time::ptime limit(start +
boost::posix_time::milliseconds(50));
+ boost::posix_time::ptime now;
+
+ while (1){
+ now = boost::posix_time::microsec_clock::universal_time();
+ if (now >= limit)
break;
-
- reply *rp = (reply *)pktbuf;
- if (u2p_chan(&rp->h.fixed) != CONTROL_CHAN) // ignore
- continue;
- if (rp->op_id_reply.opcode != OP_ID_REPLY) // ignore
- continue;
-
- const uint8_t *mac = (const uint8_t *)&rp->op_id_reply.addr;
- char addr_buf[128];
- snprintf(addr_buf, sizeof(addr_buf), "%02x:%02x:%02x:%02x:%02x:%02x",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-
- props p;
- p.addr = std::string(addr_buf);
- p.hw_rev = ntohs(rp->op_id_reply.hw_rev);
- memcpy(&p.fpga_md5sum, &rp->op_id_reply.fpga_md5sum,
sizeof(p.fpga_md5sum));
- memcpy(&p.sw_md5sum, &rp->op_id_reply.sw_md5sum, sizeof(p.sw_md5sum));
-
- if (FIND_DEBUG)
- std::cerr << "usrp2::find: response from " << p.addr << std::endl;
-
- if ((addr == "") || (addr == p.addr))
- result.push_back(p);
+
+ boost::posix_time::time_duration delta(limit - now);
+ struct timeval timeout = time_duration_to_timeval(delta);
+
+ read_replies(enet.get(), timeout, addr, result);
}
-
return result;
}
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.cc (from rev
9111, usrp2/branches/features/host-ng/host-ng/lib/ring.cc)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.cc
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.cc 2008-08-01
04:40:47 UTC (rev 9115)
@@ -0,0 +1,78 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ring.h"
+
+namespace usrp2 {
+
+ ring::ring(unsigned int entries)
+ : d_max(entries), d_read_ind(0), d_write_ind(0), d_ring(entries),
+ d_mutex(), d_not_empty(&d_mutex)
+ {
+ for (unsigned int i = 0; i < entries; i++) {
+ d_ring[i].d_base = 0;
+ d_ring[i].d_len = 0;
+ }
+ }
+
+ void
+ ring::wait_for_not_empty()
+ {
+ omni_mutex_lock l(d_mutex);
+ while (empty())
+ d_not_empty.wait();
+ }
+
+ bool
+ ring::enqueue(void *p, size_t len)
+ {
+ omni_mutex_lock l(d_mutex);
+ if (full())
+ return false;
+
+ d_ring[d_write_ind].d_len = len;
+ d_ring[d_write_ind].d_base = p;
+
+ inc_write_ind();
+ d_not_empty.signal();
+ return true;
+ }
+
+ bool
+ ring::dequeue(void **p, size_t *len)
+ {
+ omni_mutex_lock l(d_mutex);
+ if (empty())
+ return false;
+
+ *p = d_ring[d_read_ind].d_base;
+ *len = d_ring[d_read_ind].d_len;
+
+ inc_read_ind();
+ return true;
+ }
+
+} // namespace usrp2
+
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.h (from rev
9111, usrp2/branches/features/host-ng/host-ng/lib/ring.h)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.h
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.h 2008-08-01
04:40:47 UTC (rev 9115)
@@ -0,0 +1,83 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_RING_H
+#define INCLUDED_RING_H
+
+#include <omnithread.h>
+#include <stddef.h>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+namespace usrp2 {
+
+ class ring;
+ typedef boost::shared_ptr<ring> ring_sptr;
+
+ class ring
+ {
+ private:
+
+ size_t d_max;
+ size_t d_read_ind;
+ size_t d_write_ind;
+
+ struct ring_desc
+ {
+ void *d_base;
+ size_t d_len;
+ };
+ std::vector<ring_desc> d_ring;
+
+ omni_mutex d_mutex;
+ omni_condition d_not_empty;
+
+ void inc_read_ind()
+ {
+ if (d_read_ind + 1 >= d_max)
+ d_read_ind = 0;
+ else
+ d_read_ind = d_read_ind + 1;
+ }
+
+ void inc_write_ind()
+ {
+ if (d_write_ind + 1 >= d_max)
+ d_write_ind = 0;
+ else
+ d_write_ind = d_write_ind + 1;
+ }
+
+ bool empty() const { return d_read_ind == d_write_ind; }
+ bool full() const { return (d_write_ind+1)%d_max == d_read_ind; }
+
+ public:
+
+ ring(unsigned int entries);
+
+ void wait_for_not_empty();
+
+ bool enqueue(void *p, size_t len);
+ bool dequeue(void **p, size_t *len);
+ };
+
+} // namespace usrp2
+
+#endif /* INCLUDED_RING_H */
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/lib/rx_sample_handler.cc
(from rev 9111,
usrp2/branches/features/host-ng/host-ng/lib/rx_sample_handler.cc)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/rx_sample_handler.cc
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/rx_sample_handler.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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/rx_sample_handler.h>
+
+usrp2::rx_sample_handler::~rx_sample_handler()
+{
+ // nop
+}
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/lib/strtod_si.c (from
rev 9111, usrp2/branches/features/host-ng/host-ng/lib/strtod_si.c)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/strtod_si.c
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/strtod_si.c
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 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 <usrp2/strtod_si.h>
+#include <stdlib.h>
+
+#define true 1
+#define false 0
+
+int
+strtod_si(const char *s, double *result)
+{
+ *result = 0;
+
+ char *endptr;
+ double r = strtod(s, &endptr);
+ if (s == endptr)
+ return false;
+
+ switch (*endptr){
+ case 'p': r *= 1e-12; break;
+ case 'n': r *= 1e-9; break;
+ case 'u': r *= 1e-6; break;
+ case 'm': r *= 1e-3; break;
+ case 'k': r *= 1e3; break;
+ case 'M': r *= 1e6; break;
+ case 'G': r *= 1e9; break;
+ case 'T': r *= 1e12; break;
+ default:
+ // ignore. FIXME could be more robust
+ break;
+ }
+
+ *result = r;
+ return true;
+}
+
+
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2.cc 2008-08-01
04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2.cc 2008-08-01
04:40:47 UTC (rev 9115)
@@ -45,6 +45,8 @@
// NOP
}
+ // Receive
+
bool
usrp2::set_rx_gain(double gain)
{
@@ -52,9 +54,9 @@
}
bool
- usrp2::set_rx_freq(double frequency, usrp2_tune_result *result)
+ usrp2::set_rx_center_freq(double frequency, tune_result *result)
{
- return d_impl->set_rx_freq(frequency, result);
+ return d_impl->set_rx_center_freq(frequency, result);
}
bool
@@ -70,15 +72,62 @@
}
bool
- usrp2::start_rx_streaming(unsigned int items_per_frame)
+ usrp2::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
{
- return d_impl->start_rx_streaming(items_per_frame);
+ return d_impl->start_rx_streaming(channel, items_per_frame);
}
bool
- usrp2::stop_rx_streaming()
+ usrp2::rx_samples(unsigned int channel, rx_sample_handler *handler)
{
- return d_impl->stop_rx_streaming();
+ return d_impl->rx_samples(channel, handler);
}
+ bool
+ usrp2::stop_rx_streaming(unsigned int channel)
+ {
+ return d_impl->stop_rx_streaming(channel);
+ }
+
+ unsigned int
+ usrp2::rx_overruns()
+ {
+ return d_impl->rx_overruns();
+ }
+
+ unsigned int
+ usrp2::rx_missing()
+ {
+ return d_impl->rx_missing();
+ }
+
+ // Transmit
+
+ bool
+ usrp2::set_tx_gain(double gain)
+ {
+ return d_impl->set_tx_gain(gain);
+ }
+
+ bool
+ usrp2::set_tx_center_freq(double frequency, tune_result *result)
+ {
+ return d_impl->set_tx_center_freq(frequency, result);
+ }
+
+ bool
+ usrp2::set_tx_interp(int interpolation_factor)
+ {
+ return d_impl->set_tx_interp(interpolation_factor);
+ }
+
+ bool
+ usrp2::set_tx_scale_iq(int scale_i, int scale_q)
+ {
+ return d_impl->set_tx_scale_iq(scale_i, scale_q);
+ }
+
+
+
+
} // namespace usrp2
Copied: usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_bytesex.h
(from rev 9111, usrp2/branches/features/host-ng/host-ng/lib/usrp2_bytesex.h)
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_bytesex.h
(rev 0)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_bytesex.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -0,0 +1,19 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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/>.
+ */
+
+#include <gruel/inet.h>
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.cc
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -21,25 +21,35 @@
#endif
#include <usrp2/usrp2.h>
+#include <usrp2/tune_result.h>
+#include <gruel/inet.h>
#include <usrp2_types.h>
#include "usrp2_impl.h"
#include "usrp2_thread.h"
#include "eth_buffer.h"
#include "pktfilter.h"
#include "control.h"
+#include "ring.h"
#include <stdexcept>
#include <iostream>
#include <stdio.h>
+#include <stddef.h>
+#include <assert.h>
-#define USRP2_IMPL_DEBUG 1
+#define USRP2_IMPL_DEBUG 0
#if USRP2_IMPL_DEBUG
#define DEBUG_LOG(x) ::write(2, x, 1)
#else
#define DEBUG_LOG(x)
#endif
+static const int DEFAULT_RX_SCALE = 1024;
+static const int DEFAULT_TX_SCALE = 3000;
+
namespace usrp2 {
+ static const double DEF_CMD_TIMEOUT = 0.1;
+
std::string
opcode_to_string(int opcode)
{
@@ -56,12 +66,12 @@
case OP_CONFIG_TX_REPLY_V2: return "OP_CONFIG_TX_REPLY_V2";
case OP_START_RX_STREAMING: return "OP_START_RX_STREAMING";
case OP_STOP_RX: return "OP_STOP_RX";
- case OP_START_RX: return "OP_START_RX";
- case OP_CONFIG_TX: return "OP_CONFIG_TX";
+#if 0
case OP_WRITE_REG: return "OP_WRITE_REG";
case OP_WRITE_REG_MASKED: return "OP_WRITE_REG_MASKED";
case OP_READ_REG: return "OP_READ_REG";
case OP_READ_REG_REPLY: return "OP_READ_REG_REPLY";
+#endif
default:
char buf[64];
snprintf(buf, sizeof(buf), "<unknown opcode: %d>", opcode);
@@ -70,45 +80,87 @@
}
+ /*!
+ * \param p points to fixed header
+ * \param payload_len_in_bytes is length of the fixed hdr and the payload
+ * \param[out] items is set to point to the first uint32 item in the payload
+ * \param[out] nitems is set to the number of uint32 items in the payload
+ * \param[out] md is filled in with the parsed metadata from the frame.
+ */
+ static bool
+ parse_rx_metadata(void *p, size_t payload_len_in_bytes,
+ uint32_t **items, size_t *nitems_in_uint32s, rx_metadata
*md)
+ {
+ if (payload_len_in_bytes < sizeof(u2_fixed_hdr_t)) // invalid format
+ return false;
+
+ // FIXME deal with the fact that (p % 4) == 2
+ //assert((((uintptr_t) p) % 4) == 0); // must be 4-byte
aligned
+
+ u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
+
+ // FIXME unaligned loads!
+ md->word0 = u2p_word0(fh);
+ md->timestamp = u2p_timestamp(fh);
+
+ // md->start_of_burst = (md->word0 & XXX) != 0;
+ // md->end_of_burst = (md->word0 & XXX) != 0;
+ // md->rx_overrun = (md->word0 & XXX) != 0;
+
+ *items = (uint32_t *)(&fh[1]);
+ size_t nbytes = payload_len_in_bytes - sizeof(u2_fixed_hdr_t);
+ assert((nbytes % sizeof(uint32_t)) == 0);
+ *nitems_in_uint32s = nbytes / sizeof(uint32_t);
+
+ return true;
+ }
+
+
usrp2::impl::impl(const std::string &ifc, const std::string &addr)
- : d_buffer(new eth_buffer()), d_pf(0), d_bg_thread(0), d_bg_running(false),
+ : d_eth_buf(new eth_buffer()), d_pf(0), d_bg_thread(0),
d_bg_running(false),
d_rx_decim(0), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
- d_num_rx_frames(0), d_num_rx_lost(0), d_num_rx_bytes(0),
- d_pending_replies(0)
+ d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0),
d_num_rx_bytes(0),
+ d_num_enqueued(0), d_enqueued_mutex(),
d_bg_pending_cond(&d_enqueued_mutex),
+ d_channel_rings(NCHANS)
{
props_vector_t u2s = find(ifc, addr);
if (u2s.size() != 1)
throw std::runtime_error("Unable to find requested USRP2.");
- if (!d_buffer->open(ifc, htons(U2_ETHERTYPE)))
+ if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
throw std::runtime_error("Unable to register USRP2 protocol");
- d_pf = pktfilter::make_ethertype_inbound(U2_ETHERTYPE, d_buffer->mac());
- if (!d_pf || !d_buffer->attach_pktfilter(d_pf))
+ d_pf = pktfilter::make_ethertype_inbound(U2_ETHERTYPE, d_eth_buf->mac());
+ if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
throw std::runtime_error("Unable to attach packet filter.");
d_addr = u2s[0].addr;
if (USRP2_IMPL_DEBUG)
std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
-
+
+ memset(d_pending_replies, 0, sizeof(d_pending_replies));
+
d_bg_thread = new usrp2_thread(this);
d_bg_thread->start();
+
+ set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE); // set workable
default
+ set_tx_scale_iq(DEFAULT_TX_SCALE, DEFAULT_TX_SCALE); // set workable
default
}
usrp2::impl::~impl()
{
-
stop_bg();
d_bg_thread = 0; // thread class deletes itself
delete d_pf;
- d_buffer->close();
- delete d_buffer;
+ d_eth_buf->close();
+ delete d_eth_buf;
if (USRP2_IMPL_DEBUG) {
- std::cerr << "usrp2 destructor: received " << d_num_rx_frames
- << " frames, with " << d_num_rx_lost << " lost ("
- << (int)(100.0*d_num_rx_lost/d_num_rx_frames)
+ std::cerr << std::endl
+ << "usrp2 destructor: received " << d_num_rx_frames
+ << " frames, with " << d_num_rx_missing << " lost ("
+ << (d_num_rx_frames == 0 ? 0 :
(int)(100.0*d_num_rx_missing/d_num_rx_frames))
<< "%), totaling " << d_num_rx_bytes
<< " bytes" << std::endl;
}
@@ -145,7 +197,7 @@
{
p->ehdr.ethertype = htons(U2_ETHERTYPE);
parse_mac_addr(dst, &p->ehdr.dst);
- memcpy(&p->ehdr.src, d_buffer->mac(), 6);
+ memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
p->thdr.flags = 0; // FIXME transport header values?
p->thdr.seqno = d_tx_seqno++;
p->thdr.ack = 0;
@@ -171,18 +223,198 @@
memset(cmd, 0, sizeof(*cmd));
init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
cmd->op.opcode = OP_CONFIG_RX_V2;
- cmd->op.len = sizeof(op_config_rx_v2_t);
- cmd->op.rid = d_next_rid++; // TODO: reserve rid=0
+ cmd->op.len = sizeof(cmd->op);
+ cmd->op.rid = d_next_rid++;
cmd->eop.opcode = OP_EOP;
- cmd->eop.len = sizeof(op_eop_t);
+ cmd->eop.len = sizeof(cmd->eop);
}
+ void
+ usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
+ {
+ memset(cmd, 0, sizeof(*cmd));
+ init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
+ cmd->op.opcode = OP_CONFIG_TX_V2;
+ cmd->op.len = sizeof(cmd->op);
+ cmd->op.rid = d_next_rid++;
+ cmd->eop.opcode = OP_EOP;
+ cmd->eop.len = sizeof(cmd->eop);
+ }
+
+ bool
+ usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double
secs)
+ {
+ if (p)
+ d_pending_replies[p->rid()] = p;
+
+ // Transmit command
+ if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
+ d_pending_replies[p->rid()] = 0;
+ return false;
+ }
+
+ int res = 1;
+ if (p)
+ res = p->wait(secs);
+
+ d_pending_replies[p->rid()] = 0;
+ return res == 1;
+ }
+
+ // ----------------------------------------------------------------
+ // Background loop: received packet demuxing
+ // ----------------------------------------------------------------
+
+ void
+ usrp2::impl::stop_bg()
+ {
+ d_bg_running = false;
+ d_bg_pending_cond.signal();
+
+ void *dummy_status;
+ d_bg_thread->join(&dummy_status);
+ }
+
+ void
+ usrp2::impl::bg_loop()
+ {
+ d_bg_running = true;
+ while(d_bg_running) {
+ DEBUG_LOG(":");
+ // Receive available frames from ethernet buffer. Handler will
+ // process control frames, enqueue data packets in channel
+ // rings, and signal blocked API threads
+ int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
+ if (res == eth_buffer::EB_ERROR)
+ break;
+
+ // Wait for user API thread(s) to process all enqueued packets.
+ // The channel ring thread that decrements d_num_enqueued to zero
+ // will signal this thread to continue.
+ {
+ omni_mutex_lock l(d_enqueued_mutex);
+ while(d_num_enqueued > 0 && d_bg_running)
+ d_bg_pending_cond.wait();
+ }
+ }
+ d_bg_running = false;
+ }
+
+ //
+ // passed to eth_buffer::rx_frames
+ //
+ data_handler::result
+ usrp2::impl::operator()(const void *base, size_t len)
+ {
+ u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
+
+ // FIXME unaligned load!
+ int chan = u2p_chan(&pkt->hdrs.fixed);
+
+ if (chan == CONTROL_CHAN) { // control packets
+ DEBUG_LOG("c");
+ return handle_control_packet(base, len);
+ }
+ else { // data packets
+ return handle_data_packet(base, len);
+ }
+
+ // not reached
+ }
+
+ data_handler::result
+ usrp2::impl::handle_control_packet(const void *base, size_t len)
+ {
+ // point to beginning of payload (subpackets)
+ unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
+
+ // FIXME (p % 4) == 2. Not good. Must watch for unaligned loads.
+
+ // FIXME iterate over payload, handling more than a single subpacket.
+
+ //int opcode = p[0];
+ unsigned int oplen = p[1];
+ unsigned int rid = p[2];
+
+ pending_reply *rp = d_pending_replies[rid];
+ if (rp) {
+ unsigned int buflen = rp->len();
+ if (oplen != buflen) {
+ std::cerr << "usrp2: mismatched command reply length ("
+ << oplen << " != " << buflen << ")"
+ << std::endl;
+ }
+
+ // Copy reply into caller's buffer
+ memcpy(rp->buffer(), p, std::min(oplen, buflen));
+ rp->signal();
+ d_pending_replies[rid] = 0;
+ return data_handler::RELEASE;
+ }
+
+ // TODO: handle unsolicited, USRP2 initiated, or late replies
+ DEBUG_LOG("l");
+ return data_handler::RELEASE;
+ }
+
+ data_handler::result
+ usrp2::impl::handle_data_packet(const void *base, size_t len)
+ {
+ u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
+ d_num_rx_frames++;
+ d_num_rx_bytes += len;
+
+ /* --- FIXME start of fake transport layer handler --- */
+
+ if (d_rx_seqno != -1) {
+ int expected_seqno = (d_rx_seqno + 1) & 0xFF;
+ int seqno = pkt->hdrs.thdr.seqno;
+
+ if (seqno != expected_seqno) {
+ ::write(2, "uS", 2); // missing sequence number
+ int missing = seqno - expected_seqno;
+ if (missing < 0)
+ missing += 256;
+
+ d_num_rx_overruns++;
+ d_num_rx_missing += missing;
+ }
+ }
+
+ d_rx_seqno = pkt->hdrs.thdr.seqno;
+
+ /* --- end of fake transport layer handler --- */
+
+ // FIXME unaligned load!
+ unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
+
+ if (!d_channel_rings[chan]) {
+ DEBUG_LOG("!");
+ return data_handler::RELEASE; // discard packet, no channel handler
+ }
+
+ // Strip off ethernet header and transport header and enqueue the rest
+
+ size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
+ if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
+ inc_enqueued();
+ DEBUG_LOG("+");
+ return data_handler::KEEP; // channel ring runner will mark frame
done
+ }
+ else {
+ DEBUG_LOG("!");
+ return data_handler::RELEASE; // discard, no room in channel ring
+ }
+ return data_handler::RELEASE;
+ }
+
+ // ----------------------------------------------------------------
+ // Receive
+ // ----------------------------------------------------------------
+
bool
usrp2::impl::set_rx_gain(double gain)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting receive gain to " << gain << std::endl;
-
op_config_rx_v2_cmd cmd;
op_config_rx_reply_v2_t reply;
@@ -191,26 +423,16 @@
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- // enqueue p into pending list
-
- // Transmit command
- if (d_buffer->tx_frame(&cmd, sizeof(cmd)) != 1)
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
- // Wait for reply or timeout
- if (p.wait(0, 10000000) == 0)
- return false;
-
- // Process reply here
- return true;
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
bool
- usrp2::impl::set_rx_freq(double frequency, usrp2_tune_result *result)
+ usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting frequency to " << frequency << std::endl;
-
op_config_rx_v2_cmd cmd;
op_config_rx_reply_v2_t reply;
@@ -221,245 +443,303 @@
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- // enqueue p into pending list
-
- // Transmit command
- if (d_buffer->tx_frame(&cmd, sizeof(cmd)) != 1)
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
- // Wait for reply or timeout
- if (p.wait(0, 10000000) == 0)
- return false;
+ bool success = (ntohx(reply.ok) == 1);
+ if (result && success) {
+ result->baseband_freq =
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
+ ntohl(reply.baseband_freq_lo)));
- // Process reply here
- return true;
+ result->dxc_freq =
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
+ ntohl(reply.ddc_freq_lo)));
+
+ result->residual_freq =
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
+ ntohl(reply.residual_freq_lo)));
+
+ result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
+ }
+
+ return success;
}
bool
usrp2::impl::set_rx_decim(int decimation_factor)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting receive decimation rate to "
- << decimation_factor << std::endl;
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
+ op_config_rx_v2_cmd cmd;
+ op_config_rx_reply_v2_t reply;
+
+ init_config_rx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_INTERP_DECIM);
+ cmd.op.decim = htonl(decimation_factor);
- struct command {
- u2_eth_packet_t h;
- op_config_rx_v2_t op;
- op_eop_t eop;
- };
-
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op.opcode = OP_CONFIG_RX_V2;
- c->op.len = sizeof(op_config_rx_v2_t);
- c->op.rid = d_next_rid++;
-
- c->op.valid = htons(CFGV_INTERP_DECIM);
- c->op.decim = htonl(decimation_factor);
-
- c->eop.opcode = OP_EOP;
- c->eop.len = sizeof(op_eop_t);
-
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
-
- // FIXME wait for corresponding reply, etc.
-
- d_rx_decim = decimation_factor;
- return true;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
bool
usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting RX IQ scaling to "
- << scale_i << ", " << scale_q << std::endl;
+ op_config_rx_v2_cmd cmd;
+ op_config_rx_reply_v2_t reply;
+
+ init_config_rx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_SCALE_IQ);
+ cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
-
- struct command {
- u2_eth_packet_t h;
- op_config_rx_v2_t op;
- op_eop_t eop;
- };
-
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op.opcode = OP_CONFIG_RX_V2;
- c->op.len = sizeof(op_config_rx_v2_t);
- c->op.rid = d_next_rid++;
-
- c->op.valid = htons(CFGV_SCALE_IQ);
- c->op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
-
- c->eop.opcode = OP_EOP;
- c->eop.len = sizeof(op_eop_t);
-
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
-
- // FIXME wait for corresponding reply, etc.
-
- return true;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
bool
- usrp2::impl::start_rx_streaming(unsigned int items_per_frame)
+ usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int
items_per_frame)
{
- // Assume for now rx format is complex floats
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel number (" << channel
+ << ")" << std::endl;
+ return false;
+ }
+
+ if (channel > 0) { // until firmware supports multiple streams
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
+
+ if (d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " already streaming" << std::endl;
+ return false;
+ }
+
+ d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
+
if (items_per_frame == 0)
- items_per_frame = 250; // TODO: calculate from d_itemsize;
+ items_per_frame = U2_MAX_SAMPLES; // minimize overhead
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
+ op_start_rx_streaming_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
+ cmd.op.opcode = OP_START_RX_STREAMING;
+ cmd.op.len = sizeof(cmd.op);
+ cmd.op.rid = d_next_rid++;
+ cmd.op.items_per_frame = htonl(items_per_frame);
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
- struct command {
- u2_eth_packet_t h;
- op_start_rx_streaming_t op;
- op_eop_t eop;
- };
-
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op.opcode = OP_START_RX_STREAMING;
- c->op.len = sizeof(op_start_rx_streaming_t);
- c->op.items_per_frame = htonl(items_per_frame);
-
- c->eop.opcode = OP_EOP;
- c->eop.len = sizeof(op_eop_t);
-
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
-
- return true;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
bool
- usrp2::impl::stop_rx_streaming()
+ usrp2::impl::stop_rx_streaming(unsigned int channel)
{
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel number (" << channel
+ << ")" << std::endl;
+ return false;
+ }
+
+ if (channel > 0) { // until firmware supports multiple streams
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
+
+#if 0 // don't be overzealous.
+ if (!d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " not streaming" << std::endl;
+ return false;
+ }
+#endif
+
+ op_stop_rx_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
+ cmd.op.opcode = OP_STOP_RX;
+ cmd.op.len = sizeof(cmd.op);
+ cmd.op.rid = d_next_rid++;
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
- struct command {
- u2_eth_packet_t h;
- op_id_t op_stop_rx;
- };
-
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op_stop_rx.opcode = OP_STOP_RX;
- c->op_stop_rx.len = sizeof(op_stop_rx_t);
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
-
- return true;
+
+ bool success = (ntohx(reply.ok) == 1);
+ if (success)
+ d_channel_rings[channel].reset();
+
+ return success;
}
- void
- usrp2::impl::bg_loop()
+
+ bool
+ usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
{
- d_bg_running = true;
- while(d_bg_running) {
- int res = d_buffer->rx_frames(this, 1000);
- if (res == -1)
- break;
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel (" << channel
+ << " )" << std::endl;
+ return false;
}
- }
-
- unsigned int
- usrp2::impl::operator()(const void *base, unsigned int len)
- {
- u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
- int chan = u2p_chan(&pkt->hdrs.fixed);
-
- if (chan == CONTROL_CHAN) { // control packets
- DEBUG_LOG("C");
- return handle_control_packet(base, len);
+
+ if (channel > 0) {
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
}
- else { // data packets
- DEBUG_LOG("D");
- return handle_data_packet(base, len);
+
+ ring_sptr rp = d_channel_rings[channel];
+ if (!rp){
+ std::cerr << "usrp2: channel " << channel
+ << " not receiving" << std::endl;
+ return false;
}
+
+ // Wait for frames available in channel ring
+ DEBUG_LOG("W");
+ rp->wait_for_not_empty();
+ DEBUG_LOG("s");
+
+ // Iterate through frames and present to user
+ void *p;
+ size_t frame_len_in_bytes;
+ while (rp->dequeue(&p, &frame_len_in_bytes)) {
+ uint32_t *items; // points to beginning of data
items
+ size_t nitems_in_uint32s;
+ rx_metadata md;
+ if (!parse_rx_metadata(p, frame_len_in_bytes, &items,
&nitems_in_uint32s, &md))
+ return false;
- // not reached
+ bool want_more = (*handler)(items, nitems_in_uint32s, &md);
+ d_eth_buf->release_frame(p);
+ DEBUG_LOG("-");
+ dec_enqueued();
+
+ if (!want_more)
+ break;
+ }
+ return true;
}
- unsigned int
- usrp2::impl::handle_control_packet(const void *base, unsigned int len)
+ // ----------------------------------------------------------------
+ // Transmit
+ // ----------------------------------------------------------------
+
+ bool
+ usrp2::impl::set_tx_gain(double gain)
{
- // point to beginning of payload (subpackets)
- unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
+
+ init_config_tx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_GAIN);
+ cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
- // FIXME iterate over payload, handling more than a single
- // subpacket, when (if?) the firmware starts sending them
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
+ }
+
+ bool
+ usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
+ {
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
+
+ init_config_tx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_FREQ);
+ u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
+ cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
+ cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
- int opcode = p[0];
- int oplen = p[1];
- int rid = p[2];
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
- if (USRP2_IMPL_DEBUG) {
- std::cerr << "cmd reply: id=" << rid
- << " len=" << oplen
- << " op=" << opcode_to_string(opcode)
- << std::endl;
+ bool success = (ntohx(reply.ok) == 1);
+ if (result && success) {
+ result->baseband_freq =
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
+ ntohl(reply.baseband_freq_lo)));
+
+ result->dxc_freq =
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
+ ntohl(reply.duc_freq_lo)));
+
+ result->residual_freq =
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
+ ntohl(reply.residual_freq_lo)));
+
+ result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
}
- // handle command reply here
- return 0;
+ return success;
}
- unsigned int
- usrp2::impl::handle_data_packet(const void *base, unsigned int len)
+ bool
+ usrp2::impl::set_tx_interp(int interpolation_factor)
{
- u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
- d_num_rx_frames++;
- d_num_rx_bytes += len;
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
+
+ init_config_tx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_INTERP_DECIM);
+ cmd.op.interp = htonl(interpolation_factor);
- if (d_rx_seqno != -1) {
- int expected_seqno = (d_rx_seqno + 1) & 0xFF;
- int seqno = pkt->hdrs.thdr.seqno;
-
- if (seqno != expected_seqno) {
- ::write(2, "uS", 2); // missing sequence number
- int missing = expected_seqno - seqno;
- if (missing < 0)
- missing += 256;
-
- d_num_rx_lost += missing;
- }
- }
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
- d_rx_seqno = pkt->hdrs.thdr.seqno;
-
- // enqueue in channel ring here
- return 0; // will be KEEP, as the channel ring runner will retire packet
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
+
+ bool
+ usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
+ {
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
- void
- usrp2::impl::stop_bg()
- {
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2_thread::stop: joining background thread "
- << this << std::endl;
- d_bg_running = false;
+ init_config_tx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_SCALE_IQ);
+ cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
- void *dummy_status;
- d_bg_thread->join(&dummy_status);
-
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2_thread::stop: join returned" << std::endl;
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
-
+
} // namespace usrp2
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.h
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.h
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_impl.h
2008-08-01 04:40:47 UTC (rev 9115)
@@ -22,10 +22,10 @@
#include <usrp2/usrp2.h>
#include <usrp2/data_handler.h>
#include <usrp2_eth_packet.h>
+#include <boost/scoped_ptr.hpp>
#include "control.h"
-
+#include "ring.h"
#include <string>
-#include <list>
namespace usrp2 {
@@ -34,48 +34,81 @@
class usrp2_thread;
class usrp2_tune_result;
class pending_reply;
+ class ring;
- class usrp2::impl : public data_handler
+ class usrp2::impl : private data_handler
{
- eth_buffer *d_buffer;
- pktfilter *d_pf;
- std::string d_addr;
- usrp2_thread *d_bg_thread;
- volatile bool d_bg_running; // TODO: multistate if needed
+ static const size_t NRIDS = 256;
+ static const size_t NCHANS = 32;
+
+ eth_buffer *d_eth_buf;
+ pktfilter *d_pf;
+ std::string d_addr;
+ usrp2_thread *d_bg_thread;
+ volatile bool d_bg_running; // TODO: multistate if needed
- int d_rx_decim;
- int d_rx_seqno;
- int d_tx_seqno;
- int d_next_rid;
- unsigned int d_num_rx_frames;
- unsigned int d_num_rx_lost;
- unsigned int d_num_rx_bytes;
+ int d_rx_decim;
+ int d_rx_seqno;
+ int d_tx_seqno;
+ int d_next_rid;
+ unsigned int d_num_rx_frames;
+ unsigned int d_num_rx_missing;
+ unsigned int d_num_rx_overruns;
+ unsigned int d_num_rx_bytes;
+
+ unsigned int d_num_enqueued;
+ omni_mutex d_enqueued_mutex;
+ omni_condition d_bg_pending_cond;
+
+ // all pending_replies are stack allocated, thus no possibility of leaking
these
+ pending_reply *d_pending_replies[NRIDS]; // indexed by 8-bit reply id
+
+ std::vector<ring_sptr> d_channel_rings; // indexed by 5-bit channel
number
+
+ void inc_enqueued() {
+ omni_mutex_lock l(d_enqueued_mutex);
+ d_num_enqueued++;
+ }
- std::list<pending_reply *> d_pending_replies;
- omni_mutex d_reply_mutex;
-
+ void dec_enqueued() {
+ omni_mutex_lock l(d_enqueued_mutex);
+ if (--d_num_enqueued == 0)
+ d_bg_pending_cond.signal();
+ }
+
static bool parse_mac_addr(const std::string &s, u2_mac_addr_t *p);
void init_et_hdrs(u2_eth_packet_t *p, const std::string &dst);
void init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
int word0_flags, int chan, uint32_t timestamp);
void stop_bg();
void init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd);
- virtual unsigned int operator()(const void *base, unsigned int len);
- unsigned int handle_control_packet(const void *base, unsigned int len);
- unsigned int handle_data_packet(const void *base, unsigned int len);
+ void init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd);
+ bool transmit_cmd(void *cmd, size_t len, pending_reply *p, double
secs=0.0);
+ virtual data_handler::result operator()(const void *base, size_t len);
+ data_handler::result handle_control_packet(const void *base, size_t len);
+ data_handler::result handle_data_packet(const void *base, size_t len);
public:
impl(const std::string &ifc, const std::string &addr);
~impl();
void bg_loop();
+
bool set_rx_gain(double gain);
- bool set_rx_freq(double frequency, usrp2_tune_result *result);
+ bool set_rx_center_freq(double frequency, tune_result *result);
bool set_rx_decim(int decimation_factor);
bool set_rx_scale_iq(int scale_i, int scale_q);
- bool start_rx_streaming(unsigned int items_per_frame);
- bool stop_rx_streaming();
+ bool start_rx_streaming(unsigned int channel, unsigned int
items_per_frame);
+ bool rx_samples(unsigned int channel, rx_sample_handler *handler);
+ bool stop_rx_streaming(unsigned int channel);
+ unsigned int rx_overruns() const { return d_num_rx_overruns; }
+ unsigned int rx_missing() const { return d_num_rx_missing; }
+ bool set_tx_gain(double gain);
+ bool set_tx_center_freq(double frequency, tune_result *result);
+ bool set_tx_interp(int interpolation_factor);
+ bool set_tx_scale_iq(int scale_i, int scale_q);
+
};
} // namespace usrp2
Modified: usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_thread.cc
===================================================================
--- usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_thread.cc
2008-08-01 04:32:24 UTC (rev 9114)
+++ usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_thread.cc
2008-08-01 04:40:47 UTC (rev 9115)
@@ -22,6 +22,7 @@
#include "usrp2_thread.h"
#include "usrp2_impl.h"
+#include <gruel/realtime.h>
#include <iostream>
#define USRP2_THREAD_DEBUG 1
@@ -43,23 +44,15 @@
void
usrp2_thread::start()
{
- if (USRP2_THREAD_DEBUG)
- std::cerr << "usrp2_thread::start() "
- << this << std::endl;
-
start_undetached();
}
void *
usrp2_thread::run_undetached(void *arg)
{
-#if 0
- // FIXME hoist this from gnuradio-core into another library.
- gr_rt_status_t rt = gr_enable_realtime_scheduling();
- if (rt != RT_OK)
- std::cerr << "failed to enable realtime scheduling\n";
-#endif
-
+ if (gruel::enable_realtime_scheduling() != gruel::RT_OK)
+ std::cerr << "usrp2: failed to enable realtime scheduling" << std::endl;
+
// This is the first code to run in the new thread context.
d_u2->bg_loop();
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r9115 - in usrp2/branches/developers/eb/merge-wip/host-ng: . apps include/usrp2 lib,
eb <=