commit-gnuradio
[Top][All Lists]
Advanced

[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();
     





reply via email to

[Prev in Thread] Current Thread [Next in Thread]