commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r9142 - in usrp2/trunk: firmware firmware/apps firmwar


From: eb
Subject: [Commit-gnuradio] r9142 - in usrp2/trunk: firmware firmware/apps firmware/include firmware/lib host/apps host-ng host-ng/apps host-ng/include/usrp2 host-ng/lib
Date: Fri, 1 Aug 2008 14:34:21 -0600 (MDT)

Author: eb
Date: 2008-08-01 14:34:19 -0600 (Fri, 01 Aug 2008)
New Revision: 9142

Added:
   usrp2/trunk/firmware/lib/usrp2_bytesex.h
   usrp2/trunk/host-ng/apps/find_usrps.cc
   usrp2/trunk/host-ng/apps/gen_2tone.py
   usrp2/trunk/host-ng/apps/gen_const.cc
   usrp2/trunk/host-ng/apps/gen_sine.py
   usrp2/trunk/host-ng/apps/rx_samples.cc
   usrp2/trunk/host-ng/apps/stdin_int32_fft.py
   usrp2/trunk/host-ng/apps/streaming_fft.py
   usrp2/trunk/host-ng/apps/test2_usrp2.cc
   usrp2/trunk/host-ng/apps/tx_samples.cc
   usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc
   usrp2/trunk/host-ng/include/usrp2/copiers.h
   usrp2/trunk/host-ng/include/usrp2/metadata.h
   usrp2/trunk/host-ng/include/usrp2/rx_sample_handler.h
   usrp2/trunk/host-ng/include/usrp2/strtod_si.h
   usrp2/trunk/host-ng/include/usrp2/tune_result.h
   usrp2/trunk/host-ng/lib/copiers.cc
   usrp2/trunk/host-ng/lib/data_handler.cc
   usrp2/trunk/host-ng/lib/ring.cc
   usrp2/trunk/host-ng/lib/ring.h
   usrp2/trunk/host-ng/lib/rx_sample_handler.cc
   usrp2/trunk/host-ng/lib/strtod_si.c
   usrp2/trunk/host-ng/lib/usrp2_bytesex.h
Removed:
   usrp2/trunk/firmware/apps/app_common.h
   usrp2/trunk/firmware/apps/rx_only.c
   usrp2/trunk/firmware/apps/tx_only.c
   usrp2/trunk/firmware/include/usrp2_bytesex.h
   usrp2/trunk/host/apps/find_usrps.cc
   usrp2/trunk/host/apps/gen_2tone.py
   usrp2/trunk/host/apps/gen_const.cc
   usrp2/trunk/host/apps/gen_sine.py
   usrp2/trunk/host/apps/rx_samples.cc
   usrp2/trunk/host/apps/stdin_int32_fft.py
   usrp2/trunk/host/apps/streaming_fft.py
   usrp2/trunk/host/apps/tx_samples.cc
   usrp2/trunk/host/apps/u2_burn_mac_addr.cc
Modified:
   usrp2/trunk/firmware/apps/Makefile.am
   usrp2/trunk/firmware/apps/app_common_v2.c
   usrp2/trunk/firmware/apps/app_common_v2.h
   usrp2/trunk/firmware/include/usrp2_eth_packet.h
   usrp2/trunk/firmware/lib/memory_map.h
   usrp2/trunk/firmware/u2_flash_tool
   usrp2/trunk/host-ng/apps/
   usrp2/trunk/host-ng/apps/Makefile.am
   usrp2/trunk/host-ng/apps/test.sh
   usrp2/trunk/host-ng/apps/test_usrp2.cc
   usrp2/trunk/host-ng/configure.ac
   usrp2/trunk/host-ng/include/usrp2/Makefile.am
   usrp2/trunk/host-ng/include/usrp2/copy_handler.h
   usrp2/trunk/host-ng/include/usrp2/data_handler.h
   usrp2/trunk/host-ng/include/usrp2/usrp2.h
   usrp2/trunk/host-ng/lib/Makefile.am
   usrp2/trunk/host-ng/lib/control.cc
   usrp2/trunk/host-ng/lib/control.h
   usrp2/trunk/host-ng/lib/copy_handler.cc
   usrp2/trunk/host-ng/lib/eth_buffer.cc
   usrp2/trunk/host-ng/lib/eth_buffer.h
   usrp2/trunk/host-ng/lib/ethernet.cc
   usrp2/trunk/host-ng/lib/ethernet.h
   usrp2/trunk/host-ng/lib/find.cc
   usrp2/trunk/host-ng/lib/usrp2.cc
   usrp2/trunk/host-ng/lib/usrp2_impl.cc
   usrp2/trunk/host-ng/lib/usrp2_impl.h
   usrp2/trunk/host-ng/lib/usrp2_thread.cc
Log:
The grand unified merger!  merged eb/merge-wip -r9112:9140 into
usrp2/trunk.  This brings everything from features/host-ng into the
trunk.  The firmware, host-ng and fpga code all match.  What a concept!

The host directory currently won't build.  As soon as everything we
need is extracted from it, we'll nuke it and svn mv host-ng to host.



Modified: usrp2/trunk/firmware/apps/Makefile.am
===================================================================
--- usrp2/trunk/firmware/apps/Makefile.am       2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/firmware/apps/Makefile.am       2008-08-01 20:34:19 UTC (rev 
9142)
@@ -1,5 +1,5 @@
 #
-# Copyright 2007 Free Software Foundation, Inc.
+# 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
@@ -30,7 +30,6 @@
        ibs_rx_test \
        ibs_tx_test \
        rcv_eth_packets \
-       rx_only \
        rx_only_v2 \
        read_dbids \
        test1 \
@@ -41,12 +40,9 @@
        test_lsdac \
        test_serdes \
        timer_test \
-       tx_only \
        tx_only_v2 \
        tx_standalone \
        txrx \
-       eth_to_serdes \
-       serdes_to_dsp \
        sd_gentest \
        sd_bounce
 
@@ -54,13 +50,11 @@
 # tx_drop_SOURCES = tx_drop.c app_common.c
 # tx_drop_rate_limited_SOURCES = tx_drop_rate_limited.c app_common.c
 # tx_drop2_SOURCES = tx_drop2.c app_common.c
-tx_only_SOURCES = tx_only.c app_common.c
-rx_only_SOURCES = rx_only.c app_common.c
 rx_only_v2_SOURCES = rx_only_v2.c app_common_v2.c
 tx_only_v2_SOURCES = tx_only_v2.c app_common_v2.c
 txrx_SOURCES = txrx.c app_common_v2.c
-eth_to_serdes_SOURCES = eth_to_serdes.c app_passthru.c
-serdes_to_dsp_SOURCES = serdes_to_dsp.c app_common.c
+#eth_to_serdes_SOURCES = eth_to_serdes.c app_passthru.c
+#serdes_to_dsp_SOURCES = serdes_to_dsp.c app_common.c
 
 
 

Deleted: usrp2/trunk/firmware/apps/app_common.h

Modified: usrp2/trunk/firmware/apps/app_common_v2.c
===================================================================
--- usrp2/trunk/firmware/apps/app_common_v2.c   2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/firmware/apps/app_common_v2.c   2008-08-01 20:34:19 UTC (rev 
9142)
@@ -39,15 +39,19 @@
 static unsigned char exp_seqno = 0;
 
 
-void config_mimo_cmd(op_config_mimo_t *p /* , op_generic_t *r */);
-
-
-static void
+static bool
 burn_mac_addr(const op_burn_mac_addr_t *p)
 {
-  ethernet_set_mac_addr(&p->addr);
+  return ethernet_set_mac_addr(&p->addr);
 }
 
+static bool
+config_mimo_cmd(const op_config_mimo_t *p)
+{
+  clocks_mimo_config(p->flags);
+  return true;
+}
+
 void
 set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt)
 {
@@ -94,168 +98,38 @@
 }
 
 
-void
-handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
+static size_t
+op_id_cmd(const op_generic_t *p,
+         void *reply_payload, size_t reply_payload_space)
 {
-  unsigned char reply[sizeof(u2_eth_packet_t) + sizeof(u2_subpkt_t)] _AL4;
-  unsigned char *s = &reply[sizeof(u2_eth_packet_t)];
-  size_t reply_len = 0;
+  op_id_reply_t *r = (op_id_reply_t *) reply_payload;
+  if (reply_payload_space < sizeof(*r))        // no room
+    return 0;
 
-  // initialize reply
-  memset(reply, 0, sizeof(reply));
-  set_reply_hdr((u2_eth_packet_t *) reply, pkt);
+  // Build reply subpacket
 
-  // point to beginning of payload (subpackets)
-  unsigned char *p = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t);
+  r->opcode = OP_ID_REPLY;
+  r->len = sizeof(op_id_reply_t);
+  r->rid = p->rid;
+  r->addr = *ethernet_mac_addr();
+  r->hw_rev = 0x0000;  // FIXME
+  // r->fpga_md5sum = ;        // FIXME
+  // r->sw_md5sum = ;  // FIXME
 
-  // FIXME iterate over payload, handling more than a single subpacket
+  // FIXME Add d'board info, including dbid, min/max gain, min/max freq
 
-  int opcode = p[0];
-
-  switch(opcode){
-  case OP_ID:
-    {
-      op_id_reply_t *r = (op_id_reply_t *) s;
-      reply_len = sizeof(u2_eth_packet_t) + sizeof(op_id_reply_t);
-      r->opcode = OP_ID_REPLY;
-      r->len = sizeof(op_id_reply_t);
-      r->rid = ((op_id_t *) p)->rid;
-      r->addr = *ethernet_mac_addr();
-      r->hw_rev = 0x0000;      // FIXME
-      // r->fpga_md5sum = ;    // FIXME
-      // r->sw_md5sum = ;      // FIXME
-
-      // FIXME Add d'board info, including dbid, min/max gain, min/max freq
-    }
-    send_reply(reply, reply_len);
-    break;
-    
-  case OP_CONFIG_TX_V2:
-    config_tx_v2_cmd((op_config_tx_v2_t *) p, (op_config_tx_reply_v2_t *) s);
-    send_reply(reply, sizeof(u2_eth_packet_t) + s[1]);
-    break;
-
-  case OP_CONFIG_RX_V2:
-    config_rx_v2_cmd((op_config_rx_v2_t *) p, (op_config_rx_reply_v2_t *) s);
-    send_reply(reply, sizeof(u2_eth_packet_t) + s[1]);
-    break;
-
-  case OP_START_RX_STREAMING:
-    start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) p);
-    break;
-    
-  case OP_STOP_RX:
-    stop_rx_cmd();
-    break;
-    
-  case OP_BURN_MAC_ADDR:
-    burn_mac_addr((op_burn_mac_addr_t *) p);
-    break;
-
-  case OP_READ_TIME:
-    {
-      op_read_time_reply_t *r = (op_read_time_reply_t *) s;
-      reply_len = sizeof(u2_eth_packet_t) + sizeof(op_read_time_reply_t);
-      r->opcode = OP_READ_TIME_REPLY;
-      r->len = sizeof(op_read_time_reply_t);
-      r->rid = ((op_read_time_t *) p)->rid;
-      r->time = timer_regs->time;
-    }
-    send_reply(reply, reply_len);
-    break;
-
-  case OP_CONFIG_MIMO:
-    config_mimo_cmd((op_config_mimo_t *) p);
-    break;
-    
-  default:
-    printf("app_common_v2: unhandled opcode = %d\n", opcode);
-    break;
-  }
+  return r->len;
 }
 
 
-/*
- * Called when an ethernet packet is received.
- * Return true if we handled it here, otherwise
- * it'll be passed on to the DSP Tx pipe
- */
-bool
-eth_pkt_inspector(dbsm_t *sm, int bufno)
+static size_t
+config_tx_v2_cmd(const op_config_tx_v2_t *p,
+                void *reply_payload, size_t reply_payload_space)
 {
-  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno);
-  size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4;
+  op_config_tx_reply_v2_t *r = (op_config_tx_reply_v2_t *) reply_payload;
+  if (reply_payload_space < sizeof(*r))
+    return 0;                                  // no room
 
-  // static size_t last_len = 0;  // kludge
-
-  // hal_toggle_leds(0x1);
-
-  // inspect rcvd frame and figure out what do do.
-
-  if (pkt->ehdr.ethertype != U2_ETHERTYPE)
-    return true;       // ignore, probably bogus PAUSE frame from MAC
-
-  int chan = u2p_chan(&pkt->fixed);
-
-  switch (chan){
-  case CONTROL_CHAN:
-    handle_control_chan_frame(pkt, byte_len);
-    return true;       // we handled the packet
-    break;
-
-  case 0:
-  default:
-#if 0
-    if (last_len != 0){
-      if (byte_len != last_len){
-       printf("Len: %d last: %d\n", byte_len, last_len);
-      }
-    }
-    last_len = byte_len;
-
-    if((pkt->thdr.seqno) == exp_seqno){
-      exp_seqno++;
-      //putchar('.');
-    }
-    else {
-      puts("Seq");
-      //printf("S%d %d ",exp_seqno,pkt->thdr.seqno);
-      exp_seqno = pkt->thdr.seqno + 1;
-    }
-#endif
-    return false;      // pass it on to Tx DSP
-    break;
-  }
-}
-
-/*
- * Called when eth phy state changes (w/ interrupts disabled)
- */
-void
-link_changed_callback(int speed)
-{
-  link_is_up = speed != 0;
-  hal_set_leds(link_is_up ? 0x10 : 0x0, 0x10);
-  printf("\neth link changed: speed = %d\n", speed);
-}
-
-
-void
-print_tune_result(char *msg, bool tune_ok,
-                 u2_fxpt_freq_t target_freq, struct tune_result *r)
-{
-  printf("db_tune %s %s\n", msg, tune_ok ? "true" : "false");
-  putstr("  target_freq   "); print_fxpt_freq(target_freq); newline();
-  putstr("  baseband_freq "); print_fxpt_freq(r->baseband_freq); newline();
-  putstr("  dxc_freq      "); print_fxpt_freq(r->dxc_freq); newline();
-  putstr("  residual_freq "); print_fxpt_freq(r->residual_freq); newline();
-  printf("  inverted      %s\n", r->inverted ? "true" : "false");
-}
-
-
-void 
-config_tx_v2_cmd(const op_config_tx_v2_t *p, op_config_tx_reply_v2_t *r)
-{
   struct tune_result   tune_result;
   memset(&tune_result, 0, sizeof(tune_result));
 
@@ -276,29 +150,33 @@
     int interp = p->interp;
     int hb1 = 0;
     int hb2 = 0;
-    
-    if(!(interp & 1)) {
-      hb1 = 1;
-      interp = interp >> 1;
-      }
-   
-    if(!(interp & 1)) {
+
+    if (!(interp & 1)){
       hb2 = 1;
       interp = interp >> 1;
     }
+
+    if (!(interp & 1)){
+      hb1 = 1;
+      interp = interp >> 1;
+    }
     
-    dsp_tx_regs->interp_rate =(hb1<<9) | (hb2<<8) | interp;
-    // printf("Interp: %d, register %d\n", p->interp, (hb1<<9) | (hb2<<8) | 
interp);
+    if (p->interp < MIN_INTERP || p->interp > MAX_INTERP)
+      ok = false;
+    else {
+      dsp_tx_regs->interp_rate = (hb1<<9) | (hb2<<8) | interp;
+      // printf("Interp: %d, register %d\n", p->interp, (hb1<<9) | (hb2<<8) | 
interp);
+    }
   }
-  
+
   if (p->valid & CFGV_SCALE_IQ){
     dsp_tx_regs->scale_iq = p->scale_iq;
   }
 
-  // Build reply; it's sent by our caller.
+  // Build reply subpacket
 
   r->opcode = OP_CONFIG_TX_REPLY_V2;
-  r->len = sizeof(op_config_tx_reply_v2_t);
+  r->len = sizeof(*r);
   r->rid = p->rid;
   r->ok = ok;
   r->inverted = tune_result.inverted;
@@ -308,11 +186,17 @@
   r->duc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq);
   r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq);
   r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq);
+  return r->len;
 }
 
-void
-config_rx_v2_cmd(const op_config_rx_v2_t *p, op_config_rx_reply_v2_t *r)
+static size_t
+config_rx_v2_cmd(const op_config_rx_v2_t *p, 
+                void *reply_payload, size_t reply_payload_space)
 {
+  op_config_rx_reply_v2_t *r = (op_config_rx_reply_v2_t *) reply_payload;
+  if (reply_payload_space < sizeof(*r))
+    return 0;                          // no room
+
   struct tune_result   tune_result;
   memset(&tune_result, 0, sizeof(tune_result));
 
@@ -344,18 +228,22 @@
       decim = decim >> 1;
     }
     
-    dsp_rx_regs->decim_rate = (hb1<<9) | (hb2<<8) | decim;
-    // printf("Decim: %d, register %d\n", p->decim, (hb1<<9) | (hb2<<8) | 
decim);
+    if (decim < MIN_DECIM || decim > MAX_DECIM)
+      ok = false;
+    else {
+      dsp_rx_regs->decim_rate = (hb1<<9) | (hb2<<8) | decim;
+      // printf("Decim: %d, register %d\n", p->decim, (hb1<<9) | (hb2<<8) | 
decim);
+    }
   }
 
   if (p->valid & CFGV_SCALE_IQ){
     dsp_rx_regs->scale_iq = p->scale_iq;
   }
 
-  // Build reply; it's sent by our caller.
+  // Build reply subpacket
 
   r->opcode = OP_CONFIG_RX_REPLY_V2;
-  r->len = sizeof(op_config_rx_reply_v2_t);
+  r->len = sizeof(*r);
   r->rid = p->rid;
   r->ok = ok;
   r->inverted = tune_result.inverted;
@@ -365,11 +253,220 @@
   r->ddc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq);
   r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq);
   r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq);
+
+  return r->len;
 }
 
+static size_t
+read_time_cmd(const op_generic_t *p,
+             void *reply_payload, size_t reply_payload_space)
+{
+  op_read_time_reply_t *r = (op_read_time_reply_t *) reply_payload;
+  if (reply_payload_space < sizeof(*r))                
+    return 0;                                  // no room
+
+  r->opcode = OP_READ_TIME_REPLY;
+  r->len = sizeof(*r);
+  r->rid = p->rid;
+  r->time = timer_regs->time;
+
+  return r->len;
+}
+
+static size_t
+generic_reply(const op_generic_t *p,
+             void *reply_payload, size_t reply_payload_space,
+             bool ok)
+{
+  op_generic_t *r = (op_generic_t *) reply_payload;
+  if (reply_payload_space < sizeof(*r))                
+    return 0;                                  // no room
+
+  r->opcode = p->opcode | OP_REPLY_BIT;
+  r->len = sizeof(*r);
+  r->rid = p->rid;
+  r->ok = ok;
+
+  return r->len;
+}
+
+static size_t
+add_eop(void *reply_payload, size_t reply_payload_space)
+{
+  op_generic_t *r = (op_generic_t *) reply_payload;
+  if (reply_payload_space < sizeof(*r))                
+    return 0;                                  // no room
+
+  r->opcode = OP_EOP;
+  r->len = sizeof(*r);
+  r->rid = 0;
+  r->ok =  0;
+
+  return r->len;
+}
+
 void
-config_mimo_cmd(op_config_mimo_t *p /* , op_generic_t *r */)
+handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
 {
-  clocks_mimo_config(p->flags);
-  // FIXME build generic reply
+  unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4;
+  unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)];
+  int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t);
+
+  // initialize reply
+  memset(reply, 0, sizeof(reply));
+  set_reply_hdr((u2_eth_packet_t *) reply, pkt);
+
+  // point to beginning of payload (subpackets)
+  unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t);
+  int payload_len = len - sizeof(u2_eth_packet_t);
+
+  size_t subpktlen = 0;
+
+  while (payload_len >= sizeof(op_generic_t)){
+    const op_generic_t *gp = (const op_generic_t *) payload;
+    subpktlen = 0;
+
+    switch(gp->opcode){
+    case OP_EOP:               // end of subpackets
+      goto end_of_subpackets;
+
+    case OP_ID:
+      subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space);
+      break;
+    
+    case OP_CONFIG_TX_V2:
+      subpktlen = config_tx_v2_cmd((op_config_tx_v2_t *) payload,
+                                  reply_payload, reply_payload_space);
+      break;
+
+    case OP_CONFIG_RX_V2:
+      subpktlen = config_rx_v2_cmd((op_config_rx_v2_t *) payload,
+                                  reply_payload, reply_payload_space);
+      break;
+
+    case OP_START_RX_STREAMING:
+      start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) 
payload);
+      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true);
+      break;
+    
+    case OP_STOP_RX:
+      stop_rx_cmd();
+      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true);
+      break;
+    
+    case OP_BURN_MAC_ADDR:
+      subpktlen = generic_reply(gp, reply_payload, reply_payload_space,
+                               burn_mac_addr((op_burn_mac_addr_t *) payload));
+      break;
+
+    case OP_CONFIG_MIMO:
+      subpktlen = generic_reply(gp, reply_payload, reply_payload_space,
+                               config_mimo_cmd((op_config_mimo_t *) payload));
+      break;
+
+    case OP_READ_TIME:
+      subpktlen = read_time_cmd(gp, reply_payload, reply_payload_space);
+      break;
+
+    default:
+      printf("app_common_v2: unhandled opcode = %d\n", gp->opcode);
+      break;
+    }
+
+    int t = (gp->len + 3) & ~3;                // bump to a multiple of 4
+    payload += t;
+    payload_len -= t;
+
+    subpktlen = (subpktlen + 3) & ~3;  // bump to a multiple of 4
+    reply_payload += subpktlen;
+    reply_payload_space -= subpktlen;
+  }
+
+ end_of_subpackets:
+
+  // add the EOP marker
+  subpktlen = add_eop(reply_payload, reply_payload_space);
+  subpktlen = (subpktlen + 3) & ~3;    // bump to a multiple of 4
+  reply_payload += subpktlen;
+  reply_payload_space -= subpktlen;
+
+  send_reply(reply, reply_payload - reply);
 }
+
+
+/*
+ * Called when an ethernet packet is received.
+ * Return true if we handled it here, otherwise
+ * it'll be passed on to the DSP Tx pipe
+ */
+bool
+eth_pkt_inspector(dbsm_t *sm, int bufno)
+{
+  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno);
+  size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4;
+
+  //static size_t last_len = 0;
+
+  // hal_toggle_leds(0x1);
+
+  // inspect rcvd frame and figure out what do do.
+
+  if (pkt->ehdr.ethertype != U2_ETHERTYPE)
+    return true;       // ignore, probably bogus PAUSE frame from MAC
+
+  int chan = u2p_chan(&pkt->fixed);
+
+  switch (chan){
+  case CONTROL_CHAN:
+    handle_control_chan_frame(pkt, byte_len);
+    return true;       // we handled the packet
+    break;
+
+  case 0:
+  default:
+#if 0
+    if (last_len != 0){
+      if (byte_len != last_len){
+       printf("Len: %d last: %d\n", byte_len, last_len);
+      }
+    }
+    last_len = byte_len;
+
+    if((pkt->thdr.seqno) == exp_seqno){
+      exp_seqno++;
+      //putchar('.');
+    }
+    else {
+      // putchar('S');
+      //printf("S%d %d ",exp_seqno,pkt->thdr.seqno);
+      exp_seqno = pkt->thdr.seqno + 1;
+    }
+#endif
+    return false;      // pass it on to Tx DSP
+    break;
+  }
+}
+
+/*
+ * Called when eth phy state changes (w/ interrupts disabled)
+ */
+void
+link_changed_callback(int speed)
+{
+  link_is_up = speed != 0;
+  hal_set_leds(link_is_up ? 0x10 : 0x0, 0x10);
+  printf("\neth link changed: speed = %d\n", speed);
+}
+
+
+void
+print_tune_result(char *msg, bool tune_ok,
+                 u2_fxpt_freq_t target_freq, struct tune_result *r)
+{
+  printf("db_tune %s %s\n", msg, tune_ok ? "true" : "false");
+  putstr("  target_freq   "); print_fxpt_freq(target_freq); newline();
+  putstr("  baseband_freq "); print_fxpt_freq(r->baseband_freq); newline();
+  putstr("  dxc_freq      "); print_fxpt_freq(r->dxc_freq); newline();
+  putstr("  residual_freq "); print_fxpt_freq(r->residual_freq); newline();
+  printf("  inverted      %s\n", r->inverted ? "true" : "false");
+}

Modified: usrp2/trunk/firmware/apps/app_common_v2.h
===================================================================
--- usrp2/trunk/firmware/apps/app_common_v2.h   2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/firmware/apps/app_common_v2.h   2008-08-01 20:34:19 UTC (rev 
9142)
@@ -54,8 +54,6 @@
                  u2_fxpt_freq_t target_freq, struct tune_result *r);
 
 
-void config_tx_v2_cmd(const op_config_tx_v2_t *p, op_config_tx_reply_v2_t *r);
-void config_rx_v2_cmd(const op_config_rx_v2_t *p, op_config_rx_reply_v2_t *r);
 void start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t 
*p);
 void stop_rx_cmd(void);
 

Deleted: usrp2/trunk/firmware/apps/rx_only.c

Deleted: usrp2/trunk/firmware/apps/tx_only.c

Deleted: usrp2/trunk/firmware/include/usrp2_bytesex.h

Modified: usrp2/trunk/firmware/include/usrp2_eth_packet.h
===================================================================
--- usrp2/trunk/firmware/include/usrp2_eth_packet.h     2008-08-01 20:25:36 UTC 
(rev 9141)
+++ usrp2/trunk/firmware/include/usrp2_eth_packet.h     2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2007 Free Software Foundation, Inc.
+ * 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
@@ -33,6 +33,9 @@
  * All these data structures are BIG-ENDIAN on the wire
  */
 
+// FIXME gcc specific.  Really ought to come from compiler.h
+#define _AL4   __attribute__((aligned (4)))
+
 /*
  * \brief The classic 14-byte ethernet header
  */
@@ -155,48 +158,55 @@
 
 /*
  * Opcodes for control channel
+ *
+ * Reply opcodes are the same as the request opcode with the OP_REPLY_BIT set 
(0x80).
  */
-#define        OP_EOP                  0       // marks last subpacket in 
packet
-#define OP_ID                  1
-#define        OP_ID_REPLY             2
-#define        OP_BURN_MAC_ADDR        3
-#define        OP_READ_TIME            4       // What time is it? (100 MHz 
counter)
-#define        OP_READ_TIME_REPLY      5       // This time.
-#define        OP_CONFIG_RX_V2         6
-#define        OP_CONFIG_RX_REPLY_V2   7
-#define        OP_CONFIG_TX_V2         8
-#define        OP_CONFIG_TX_REPLY_V2   9
-#define        OP_START_RX_STREAMING  10
-#define        OP_STOP_RX             11
-#define        OP_CONFIG_MIMO         12       // FIXME on merge
+#define OP_REPLY_BIT             0x80
 
-#define        OP_START_RX            20       // deprecated
-#define OP_CONFIG_TX          21       // deprecated
+#define        OP_EOP                       0  // marks last subpacket in 
packet
 
-#define        OP_WRITE_REG           25       // not implemented
-#define        OP_WRITE_REG_MASKED    26
-#define        OP_READ_REG            27
-#define        OP_READ_REG_REPLY      28
+#define OP_ID                       1
+#define        OP_ID_REPLY                  (OP_ID | OP_REPLY_BIT)
+#define        OP_BURN_MAC_ADDR             2
+#define OP_BURN_MAC_ADDR_REPLY      (OP_BURN_MAC_ADDR | OP_REPLY_BIT)
+#define        OP_READ_TIME                 3  // What time is it? (100 MHz 
counter)
+#define        OP_READ_TIME_REPLY           (OP_READ_TIME | OP_REPLY_BIT)
+#define        OP_CONFIG_RX_V2              4
+#define        OP_CONFIG_RX_REPLY_V2        (OP_CONFIG_RX_V2 | OP_REPLY_BIT)
+#define        OP_CONFIG_TX_V2              5
+#define        OP_CONFIG_TX_REPLY_V2        (OP_CONFIG_TX_V2 | OP_REPLY_BIT)
+#define        OP_START_RX_STREAMING        6
+#define        OP_START_RX_STREAMING_REPLY  (OP_START_RX_STREAMING | 
OP_REPLY_BIT)
+#define        OP_STOP_RX                   7
+#define        OP_STOP_RX_REPLY             (OP_STOP_RX | OP_REPLY_BIT)
+#define        OP_CONFIG_MIMO               8
+#define OP_CONFIG_MIMO_REPLY        (OP_CONFIG_MIMO | OP_REPLY_BIT)
 
 
-/*!
- * \brief Marker for last subpacket in packet
+//#define OP_WRITE_REG          xx     // not implemented
+//#define OP_WRITE_REG_MASKED    xx
+//#define OP_READ_REG           xx
+//#define OP_READ_REG_REPLY      xx
+
+/*
+ * All subpackets are a multiple of 4 bytes long.
+ * All subpackets start with an 8-bit opcode, an 8-bit len and an 8-bit rid.
  */
-typedef struct {
-  uint8_t      opcode;
-  uint8_t      len;
-  uint16_t     mbz;
-} op_eop_t;
 
+
 /*!
- * \brief Look for USRP2's
+ * \brief Generic request and reply packet
+ *
+ * Used by:
+ *  OP_EOP, OP_BURN_MAC_ADDR_REPLY, OP_START_RX_STREAMING_REPLY,
+ *  OP_STOP_RX_REPLY
  */
 typedef struct {
   uint8_t      opcode;
   uint8_t      len;
   uint8_t      rid;
-  uint8_t      mbz;
-} op_id_t;
+  uint8_t      ok;             // bool
+} _AL4 op_generic_t;
 
 /*!
  * \brief Reply info from a USRP2
@@ -210,41 +220,30 @@
   uint16_t     hw_rev;
   uint8_t      fpga_md5sum[16];
   uint8_t      sw_md5sum[16];
-} op_id_reply_t;
+} _AL4 op_id_reply_t;
 
 typedef struct {
   uint8_t      opcode;
   uint8_t      len;
-  uint16_t     mbz;
+  uint8_t      rid;
+  uint8_t      mbz;
   uint32_t     items_per_frame;  // # of 32-bit data items; MTU=1500: [9,371]
-} op_start_rx_streaming_t;
+} _AL4 op_start_rx_streaming_t;
 
 typedef struct {
   uint8_t      opcode;
   uint8_t      len;
-  uint16_t     mbz;
-} op_stop_rx_t;
-
-typedef struct {
-  uint8_t      opcode;
-  uint8_t      len;
+  uint8_t      rid;
   u2_mac_addr_t        addr;
-} op_burn_mac_addr_t;
+} _AL4 op_burn_mac_addr_t;
 
 typedef struct {
   uint8_t      opcode;
   uint8_t      len;
   uint8_t      rid;
   uint8_t      mbz;
-} op_read_time_t;
-
-typedef struct {
-  uint8_t      opcode;
-  uint8_t      len;
-  uint8_t      rid;
-  uint8_t      mbz;
   uint32_t     time;
-} op_read_time_reply_t;
+} _AL4 op_read_time_reply_t;
 
 
 /*!
@@ -262,7 +261,7 @@
   uint32_t     freq_lo;        // low  32-bits of 64-bit fxpt_freq (Q44.20)
   uint32_t     decim;          // desired decimation factor (NOT -1)
   uint32_t     scale_iq;       // (scale_i << 16) | scale_q [16.0 format]
-} op_config_rx_v2_t;
+} _AL4 op_config_rx_v2_t;
 
 // bitmask for "valid" field.  If the bit is set, there's
 // meaningful data in the corresonding field.
@@ -294,7 +293,7 @@
   uint32_t     residual_freq_hi;
   uint32_t     residual_freq_lo;
 
-} op_config_rx_reply_v2_t;
+} _AL4 op_config_rx_reply_v2_t;
 
 /*!
  *  \brief Configure transmitter
@@ -312,7 +311,7 @@
   uint32_t     freq_lo;        // low  32-bits of 64-bit fxpt_freq (Q44.20)
   uint32_t     interp;         // desired interpolation factor (NOT -1)
   uint32_t     scale_iq;       // (scale_i << 16) | scale_q [16.0 format]
-} op_config_tx_v2_t;
+} _AL4 op_config_tx_v2_t;
 
 /*!
  * \brief Reply to configure transmitter
@@ -336,7 +335,7 @@
   uint32_t     residual_freq_hi;
   uint32_t     residual_freq_lo;
 
-} op_config_tx_reply_v2_t;
+} _AL4 op_config_tx_reply_v2_t;
 
 /*!
  * \brief Configure MIMO clocking, etc (uses generic reply)
@@ -351,54 +350,22 @@
 
 /*
  * ================================================================
- *                 deprecated subpacket types
- * ================================================================
- */
-
-typedef struct {                   // Deprecated.  Don't use.
-  uint8_t      opcode;
-  uint8_t      len;
-  uint8_t      rx_now;             // 1 -> receive now, 0 -> at rx_time
-  uint8_t      mbz;
-  int32_t      phase_inc;          // 2**32 * desired_freq/100e6
-  uint32_t     scale_iq;           // (scale_i << 16) | scale_q  [16.0 format]
-  uint32_t     decim;              // desired decimation factor (NOT -1)
-  uint32_t     samples_per_frame;  // MTU=1500: [9,372]; MTU=2034: [9,506]
-  uint32_t     total_samples;      // [9, 2^21-1] == [9, 2,097,151]
-  uint32_t     rx_time;            // when to begin receiving
-} op_start_rx_t;
-
-typedef struct {                   // Deprecated.  Don't use
-  uint8_t      opcode;
-  uint8_t      len;
-  uint16_t     mbz;
-  int32_t      phase_inc;          // 2**32 * desired_freq/100e6
-  uint32_t     scale_iq;           // (scale_i << 16) | scale_q  [16.0 format]
-  uint32_t     interp;             // desired interpolation factor (NOT -1)
-} op_config_tx_t;
-
-/*
- * ================================================================
  *             union of all of subpacket types
  * ================================================================
  */
 typedef union {
-  op_eop_t                     op_eop;
-  op_id_t                      op_id;
+
+  op_generic_t                 op_generic;
   op_id_reply_t                        op_id_reply;
   op_start_rx_streaming_t      op_start_rx_streaming;
-  op_stop_rx_t                 op_stop_rx;
   op_burn_mac_addr_t           op_burn_mac_addr;
-  op_read_time_t               op_read_time;
   op_read_time_reply_t         op_read_time_reply;
   op_config_rx_v2_t            op_config_rx_v2;
   op_config_rx_reply_v2_t      op_config_rx_reply_v2;
   op_config_tx_v2_t            op_config_tx_v2;
   op_config_tx_reply_v2_t      op_config_tx_reply_v2;
+  op_config_mimo_t             op_config_mimo;
 
-  op_start_rx_t                        op_start_rx;            // deprecated
-  op_config_tx_t               op_config_tx;           // deprecated
-
 } u2_subpkt_t;
 
 

Modified: usrp2/trunk/firmware/lib/memory_map.h
===================================================================
--- usrp2/trunk/firmware/lib/memory_map.h       2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/firmware/lib/memory_map.h       2008-08-01 20:34:19 UTC (rev 
9142)
@@ -367,6 +367,9 @@
 
 // --- dsp tx regs ---
 
+#define MIN_INTERP     1
+#define        MAX_INTERP    128
+
 typedef struct {
   volatile int32_t     freq;
   volatile uint32_t    scale_iq;       // {scale_i,scale_q}
@@ -381,6 +384,9 @@
 
 #define T_NOW (-1)
 
+#define        MIN_DECIM       1
+#define        MAX_DECIM     128
+
 typedef struct {
   volatile int32_t     freq;
   volatile uint32_t    scale_iq;       // {scale_i,scale_q}

Copied: usrp2/trunk/firmware/lib/usrp2_bytesex.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/firmware/lib/usrp2_bytesex.h)
===================================================================
--- usrp2/trunk/firmware/lib/usrp2_bytesex.h                            (rev 0)
+++ usrp2/trunk/firmware/lib/usrp2_bytesex.h    2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,66 @@
+/* -*- 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_USRP2_BYTESEX_H
+#define INCLUDED_USRP2_BYTESEX_H
+
+// The USRP2 speaks big-endian...
+// Use the standard include files or provide substitutions for
+// htons and friends
+
+#if defined(HAVE_ARPA_INET_H)
+#include <arpa/inet.h>
+#elif defined(HAVE_NETINET_IN_H)
+#include <netinet/in.h>
+#else
+#include <stdint.h>
+
+#ifdef WORDS_BIGENDIAN  // nothing to do...
+
+static inline uint32_t htonl(uint32_t x){ return x; }
+static inline uint16_t htons(uint16_t x){ return x; }
+static inline uint32_t ntohl(uint32_t x){ return x; }
+static inline uint16_t ntohs(uint16_t x){ return x; }
+
+#else
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+
+static inline uint16_t
+bswap_16 (uint16_t x)
+{
+  return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
+}
+
+static inline uint32_t
+bswap_32 (uint32_t x)
+{
+  return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) \
+        | (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24));
+}
+#endif
+
+static inline uint32_t htonl(uint32_t x){ return bswap_32(x); }
+static inline uint16_t htons(uint16_t x){ return bswap_16(x); }
+static inline uint32_t ntohl(uint32_t x){ return bswap_32(x); }
+static inline uint16_t ntohs(uint16_t x){ return bswap_16(x); }
+
+#endif
+#endif
+#endif /* INCLUDED_USRP2_BYTESEX_H */

Modified: usrp2/trunk/firmware/u2_flash_tool
===================================================================
--- usrp2/trunk/firmware/u2_flash_tool  2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/firmware/u2_flash_tool  2008-08-01 20:34:19 UTC (rev 9142)
@@ -52,6 +52,13 @@
                 break
     return False
 
+def read_flash(offset, filename, devname):
+    dev = open(devname, "rb")
+    dev.seek(offset, 0)                 # seek to absolute byte offset
+    dev_data = dev.read(MAX_FILE_SIZE)
+    dev.close()
+    open(filename, "wb").write(dev_data)
+
     
 def main():
     parser = OptionParser(usage="%prog: [options] filename")
@@ -59,6 +66,8 @@
                       help="write FILE to TARGET slot")
     parser.add_option("-v", "--verify",  action="store_const", const="verify", 
dest="mode",
                       help="verify FILE against TARGET slot")
+    parser.add_option("-r", "--read",  action="store_const", const="read", 
dest="mode",
+                      help="read TARGET slot, write to FILE")
     parser.add_option("-t", "--target", type="choice", choices=("fpga", 
"s/w"), default="s/w",
                       help="select TARGET slot from: fpga, s/w 
[default=%default]")
     parser.add_option("", "--dev", default=None,
@@ -73,7 +82,7 @@
     filename = args[0]
 
     if options.mode is None:
-        sys.stderr.write("specify mode with -w or -v\n")
+        sys.stderr.write("specify mode with -w, -v or -r\n")
         parser.print_help()
         raise SystemExit
 
@@ -87,8 +96,12 @@
     if options.mode == "write":
         r = (write_flash(offset, filename, options.dev)
              and verify_flash(offset, filename, options.dev))
+    elif options.mode == "verify":
+        r = verify_flash(offset, filename, options.dev)
+    elif options.mode == "read":
+        r = read_flash(offset, filename, options.dev)
     else:
-        r = verify_flash(offset, filename, options.dev)
+        raise NotImplemented
 
     if not r:
         raise SystemExit, 1

Deleted: usrp2/trunk/host/apps/find_usrps.cc

Deleted: usrp2/trunk/host/apps/gen_2tone.py

Deleted: usrp2/trunk/host/apps/gen_const.cc

Deleted: usrp2/trunk/host/apps/gen_sine.py

Deleted: usrp2/trunk/host/apps/rx_samples.cc

Deleted: usrp2/trunk/host/apps/stdin_int32_fft.py

Deleted: usrp2/trunk/host/apps/streaming_fft.py

Deleted: usrp2/trunk/host/apps/tx_samples.cc

Deleted: usrp2/trunk/host/apps/u2_burn_mac_addr.cc


Property changes on: usrp2/trunk/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
gen_const
find_usrps
cerr
*.sh
tx_samples


Modified: usrp2/trunk/host-ng/apps/Makefile.am
===================================================================
--- usrp2/trunk/host-ng/apps/Makefile.am        2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/apps/Makefile.am        2008-08-01 20:34:19 UTC (rev 
9142)
@@ -17,16 +17,21 @@
 
 include $(top_srcdir)/Makefile.common
 
-AM_CPPFLAGS = -Wall -Werror
-INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES)
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) $(GRUEL_CFLAGS)
 
 LDADD = \
        ../lib/libusrp2ng.la \
-       $(GNURADIO_CORE_LIBS)
+       -lgruel
 
+bin_PROGRAMS = \
+       find_usrps
+
 noinst_PROGRAMS = \
-       test_usrp2
+       gen_const \
+       test2_usrp2 \
+       tx_samples
 
-test_usrp2_SOURCES = \
-       test_usrp2.cc
-
+find_usrps = find_usrps.cc
+test2_usrp2_SOURCES = test2_usrp2.cc
+gen_const_SOURCES = gen_const.cc
+tx_samples_SOURCES = tx_samples.cc

Copied: usrp2/trunk/host-ng/apps/find_usrps.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/find_usrps.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/find_usrps.cc                              (rev 0)
+++ usrp2/trunk/host-ng/apps/find_usrps.cc      2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,70 @@
+/* -*- 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 <iostream>
+#include <getopt.h>
+
+static void
+usage(const char *progname)
+{
+  fprintf(stderr, "usage: %s [-e ethN]\n",
+         progname);
+}
+
+int
+main(int argc, char **argv)
+{
+  int ch;
+  const char *interface = "eth0";
+
+  while ((ch = getopt(argc, argv, "he:")) != EOF){
+    switch (ch){
+    case 'e':
+      interface = optarg;
+      break;
+      
+    case 'h':
+    default:
+      usage(argv[0]);
+      exit(1);
+    }
+  }
+
+  if (argc - optind != 0){
+    usage(argv[0]);
+    exit(1);
+  }
+  
+  usrp2::props_vector_t r = usrp2::find(interface);
+
+  for (size_t i = 0; i < r.size(); i++){
+    std::cout << r[i] << std::endl;
+  }
+
+  if (r.size() == 0){
+    std::cerr << "No USRP2 found.\n";
+    return 1;
+  }
+
+  return 0;
+}

Copied: usrp2/trunk/host-ng/apps/gen_2tone.py (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/gen_2tone.py)
===================================================================
--- usrp2/trunk/host-ng/apps/gen_2tone.py                               (rev 0)
+++ usrp2/trunk/host-ng/apps/gen_2tone.py       2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# 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/>.
+#
+
+from gnuradio import gr, eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+master_clock = 100e6
+
+class my_top_block(gr.top_block):
+
+    def __init__(self):
+        gr.top_block.__init__(self)
+
+        parser = OptionParser(option_class=eng_option)
+        parser.add_option("-f", "--freq1", type="eng_float", default=1e6,
+                          help="set waveform frequency to FREQ 
[default=%default]")
+        parser.add_option("-g", "--freq2", type="eng_float", default=1e6,
+                          help="set waveform frequency to FREQ 
[default=%default]")
+        parser.add_option ("-a", "--amplitude1", type="eng_float", 
default=16e3,
+                           help="set waveform amplitude to AMPLITUDE 
[default=%default]", metavar="AMPL")
+        parser.add_option ("-b", "--amplitude2", type="eng_float", 
default=16e3,
+                           help="set waveform amplitude to AMPLITUDE 
[default=%default]", metavar="AMPL")
+
+        parser.add_option("-i", "--interp", type="int", default=32,
+                          help="assume fgpa interpolation rate is INTERP 
[default=%default]")
+
+        (options, args) = parser.parse_args ()
+        if len(args) != 0:
+            parser.print_help()
+            raise SystemExit, 1
+
+        
+        src0 = gr.sig_source_c(master_clock/options.interp,
+                               gr.GR_SIN_WAVE,
+                               options.freq1,
+                               options.amplitude1)
+        src1 = gr.sig_source_c(master_clock/options.interp,
+                               gr.GR_SIN_WAVE,
+                               options.freq2,
+                               options.amplitude2)
+
+       adder = gr.add_cc()
+
+        
+        c2s = gr.complex_to_interleaved_short()
+
+        stdout_sink = gr.file_descriptor_sink(gr.sizeof_short, 1)
+
+        self.connect(src0, (adder,0))
+        self.connect(src1, (adder,1))
+        self.connect(adder, c2s, stdout_sink)
+
+        
+if __name__ == '__main__':
+    try:
+        my_top_block().run()
+    except KeyboardInterrupt:
+        pass

Copied: usrp2/trunk/host-ng/apps/gen_const.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/gen_const.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/gen_const.cc                               (rev 0)
+++ usrp2/trunk/host-ng/apps/gen_const.cc       2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+  if (argc != 3){
+    fprintf(stderr, "usage: %s i-val q-val\n", argv[0]);
+    return 1;
+  }
+
+  int i_val = strtol(argv[1], 0, 0);
+  int q_val = strtol(argv[2], 0, 0);
+
+  static const int NSAMPLES = 16384;
+
+  uint32_t     sample[NSAMPLES];
+  sample[0] = ((i_val & 0xffff) << 16) | (q_val & 0xffff);
+  for (int i = 1; i < NSAMPLES; i++)
+    sample[i] = sample[0];
+
+  while(1){
+    write(1, sample, sizeof(sample));
+  }
+}

Copied: usrp2/trunk/host-ng/apps/gen_sine.py (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/gen_sine.py)
===================================================================
--- usrp2/trunk/host-ng/apps/gen_sine.py                                (rev 0)
+++ usrp2/trunk/host-ng/apps/gen_sine.py        2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+#
+# 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/>.
+#
+
+from gnuradio import gr, eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+master_clock = 100e6
+
+class my_top_block(gr.top_block):
+
+    def __init__(self):
+        gr.top_block.__init__(self)
+
+        parser = OptionParser(option_class=eng_option)
+        parser.add_option("-f", "--freq", type="eng_float", default=1e6,
+                          help="set waveform frequency to FREQ 
[default=%default]")
+        parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3,
+                           help="set waveform amplitude to AMPLITUDE 
[default=%default]", metavar="AMPL")
+
+        parser.add_option("-i", "--interp", type="int", default=32,
+                          help="assume fgpa interpolation rate is INTERP 
[default=%default]")
+
+        (options, args) = parser.parse_args ()
+        if len(args) != 0:
+            parser.print_help()
+            raise SystemExit, 1
+
+        
+        src0 = gr.sig_source_c(master_clock/options.interp,
+                               gr.GR_SIN_WAVE,
+                               options.freq,
+                               options.amplitude)
+
+        
+        c2s = gr.complex_to_interleaved_short()
+
+        stdout_sink = gr.file_descriptor_sink(gr.sizeof_short, 1)
+
+        self.connect(src0, c2s, stdout_sink)
+
+        
+if __name__ == '__main__':
+    try:
+        my_top_block().run()
+    except KeyboardInterrupt:
+        pass

Copied: usrp2/trunk/host-ng/apps/rx_samples.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/rx_samples.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/rx_samples.cc                              (rev 0)
+++ usrp2/trunk/host-ng/apps/rx_samples.cc      2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,382 @@
+/* -*- 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "usrp2_basic.h"
+#include <iostream>
+#include <complex>
+#include <getopt.h>
+#include <string.h>
+#include "strtod_si.h"
+#include <signal.h>
+#include <stdexcept>
+#include "gri_if_stats.h"
+#include <gr_realtime.h>
+
+
+typedef std::complex<float> fcomplex;
+
+static volatile bool signaled = false;
+
+static void 
+sig_handler(int sig)
+{
+  signaled = true;
+}
+
+static void
+install_sig_handler(int signum,
+                   void (*new_handler)(int))
+{
+  struct sigaction new_action;
+  memset (&new_action, 0, sizeof (new_action));
+
+  new_action.sa_handler = new_handler;
+  sigemptyset (&new_action.sa_mask);
+  new_action.sa_flags = 0;
+
+  if (sigaction (signum, &new_action, 0) < 0){
+    perror ("sigaction (install new)");
+    throw std::runtime_error ("sigaction");
+  }
+}
+
+
+/*
+ * Vectorize me!
+ */
+void
+convert_samples_to_complex(size_t nsamples,
+                          uint32_t *i_samples,
+                          fcomplex *c_samples)
+{
+  uint32_t *p = i_samples;
+  for (size_t i = 0; i < nsamples; i++){
+    int16_t  si = ((int16_t) (p[i] >> 16));
+    int16_t  sq = ((int16_t) (p[i] & 0xffff));
+    c_samples[i] = fcomplex((float) si, (float) sq);
+  }
+}
+
+
+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, "  -o OUTPUT_FILE       set output filename 
[default=NONE]\n");
+  fprintf(stderr, "  -f FREQ              set frequency to FREQ 
[default=0]\n");
+  fprintf(stderr, "  -d DECIM             set decimation rate to DECIM 
[default=32]\n");
+  fprintf(stderr, "  -N NSAMPLES          total number of samples to receive 
[default=2.5e6]\n");
+  fprintf(stderr, "  -F SAMPLES_PER_FRAME number of samples in each frame 
[default=371]\n");
+  fprintf(stderr, "  -S SCALE             fpga scaling factor for I & Q 
[default=1024]\n");
+  fprintf(stderr, "  -M DONT_LOCK|LOCK_TO_SMA|LOCK_TO_MIMO   specify MIMO 
clock source\n");
+  fprintf(stderr, "  -P                   provide clock to MIMO connector\n");
+}
+
+struct pkt_info {
+  int          d_nsamples;
+  int          d_timestamp;
+  unsigned int d_seqno;
+
+  pkt_info(int nsamples, int timestamp, int seqno)
+    : d_nsamples(nsamples),
+      d_timestamp(timestamp),
+      d_seqno(seqno) {}
+};
+
+int
+main(int argc, char **argv)
+{
+
+  // options and their defaults
+  const char *interface = "eth0";
+  const char *mac_addr_str = 0;
+  const char *output_filename = 0;
+  double freq = 0;
+  int32_t decim = 32;
+  int32_t nsamples = static_cast<int32_t>(2.5e6);
+  int32_t samples_per_frame = 371;
+  int32_t scale = 1024;
+  int    mimo_config = MC_WE_DONT_LOCK;
+  bool   provide_clock = false;
+
+  int    ch;
+  double tmp;
+  u2_mac_addr_t mac_addr;
+
+  setvbuf(stdout, 0, _IOFBF, 64 * 1024); // make stdout fully buffered
+
+  while ((ch = getopt(argc, argv, "he:m:o:f:d:N:F:S:M:P")) != EOF){
+    switch (ch){
+
+    case 'e':
+      interface = optarg;
+      break;
+      
+    case 'm':
+      mac_addr_str = optarg;
+      if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
+       std::cerr << "invalid mac addr: " << optarg << std::endl;
+       usage(argv[0]);
+       exit(1);
+      }
+      break;
+
+    case 'o':
+      output_filename = optarg;
+      break;
+      
+    case 'f':
+      if (!strtod_si(optarg, &freq)){
+       std::cerr << "invalid number: " << 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<int32_t>(tmp);
+      break;
+
+    case 'F':
+      samples_per_frame = strtol(optarg, 0, 0);
+      break;
+
+    case 'd':
+      decim = strtol(optarg, 0, 0);
+      break;
+
+    case 'S':
+      if (!strtod_si(optarg, &tmp)){
+       std::cerr << "invalid number: " << optarg << std::endl;
+       usage(argv[0]);
+       exit(1);
+      }
+      scale = static_cast<int32_t>(tmp);
+      break;
+      
+    case 'M':
+      if (strcmp(optarg, "DONT_LOCK") == 0)
+       mimo_config = MC_WE_DONT_LOCK;
+      else if (strcmp(optarg, "LOCK_TO_SMA") == 0)
+       mimo_config = MC_WE_LOCK_TO_SMA;
+      else if (strcmp(optarg, "LOCK_TO_MIMO") == 0)
+       mimo_config = MC_WE_LOCK_TO_MIMO;
+      else {
+       usage(argv[0]);
+       exit(1);
+      }
+      break;
+
+    case 'P':
+      provide_clock = true;
+      break;
+
+    case 'h':
+    default:
+      usage(argv[0]);
+      exit(1);
+    }
+  }
+  
+  if (argc - optind != 0){
+    usage(argv[0]);
+    exit(1);
+  }
+
+  FILE *of = 0;
+  if (output_filename)
+    of = fopen(output_filename, "wb");
+
+  usrp2_basic *u2 = new usrp2_basic();
+
+  if (!u2->open(interface)){
+    std::cerr << "couldn't open " << interface << std::endl;
+    return 0;
+  }
+
+
+  install_sig_handler(SIGINT, sig_handler);
+  if (1){
+    install_sig_handler(SIGALRM, sig_handler);
+    alarm(5);
+  }
+
+  
+  std::vector<op_id_reply_t> r = u2->find_usrps();
+
+  for (size_t i = 0; i < r.size(); i++){
+    std::cout << r[i] << std::endl;
+  }
+
+  if (r.size() == 0){
+    std::cerr << "No USRP2 found.\n";
+    return 1;
+  }
+
+  u2_mac_addr_t which = r[0].addr;     // pick the first one
+
+
+  gr_rt_status_t rt = gr_enable_realtime_scheduling();
+  if (rt != RT_OK)
+    std::cerr << "failed to enable realtime scheduling\n";
+
+  if (provide_clock)
+    mimo_config |= MC_PROVIDE_CLK_TO_MIMO;
+
+  u2->config_mimo(which, mimo_confg);
+  
+
+  gri_if_stats start, stop;
+  gri_get_if_stats(interface, &start);
+
+  if (!u2->start_rx(which, freq, decim, nsamples, samples_per_frame, scale, 
scale)){
+    std::cerr << "start_rx failed\n";
+    return 1;
+  }
+
+
+  std::vector<pkt_info> history;
+  history.reserve(64*1024);            // preallocate 64K entries
+
+  
+  long total_samples_recvd = 0;
+
+  while (!signaled && total_samples_recvd < nsamples){
+    u2_eth_samples_t   pkt;
+    // fcomplex                c_samples[U2_MAX_SAMPLES];
+    
+    // read samples
+    int n = u2->read_samples(which, &pkt);
+    if (n <= 0)
+      break;
+    
+    total_samples_recvd += n;
+
+    history.push_back(pkt_info(n, u2p_timestamp(&pkt.hdrs.fixed), 
pkt.hdrs.thdr.seqno));
+
+    // convert_samples_to_complex(n, pkt.samples, c_samples);
+    // size_t r = fwrite(c_samples, sizeof(fcomplex), n, of);
+
+    if (of){
+      fwrite(pkt.samples, sizeof(uint32_t), n, of);
+      fflush(of);
+    }
+  }
+
+
+  gri_get_if_stats(interface, &stop);
+
+  if (!u2->stop_rx(which)){
+    std::cerr << "stop_rx failed\n";
+    return 1;
+  }
+
+
+  long expected_rx_packets =
+    (nsamples + samples_per_frame - 1)/samples_per_frame;
+
+  long expected_rx_bytes   =
+    expected_rx_packets * sizeof(u2_eth_packet_t) + nsamples * 4;
+
+
+  long total_pkts_recvd = 0;
+  total_samples_recvd = 0;
+
+  int nbad_seqno = 0;
+
+  for (unsigned i = 0; i < history.size(); i++){
+    total_pkts_recvd++;
+    total_samples_recvd += history[i].d_nsamples;
+
+    bool bad_seqno = history[i].d_seqno != (i & 0xff);
+    if (bad_seqno)
+      nbad_seqno++;
+    
+    printf("%3d  %8d  %8ld  %8ld  %3d %s\n",
+          history[i].d_nsamples,
+          history[i].d_timestamp,
+          total_pkts_recvd, total_samples_recvd,
+          history[i].d_seqno,
+          bad_seqno ? "BAD SEQNO" : ""
+          );
+  }
+
+  if (nbad_seqno == 0)
+    printf("\nAll sequence numbers are correct\n");
+  else
+    printf("\n%d sequence numbers were INCORRECT\n", nbad_seqno);
+    
+
+  printf("\nUser space statistics:\n");
+  printf("  rx_samples:  %8ld",     total_samples_recvd);
+  printf("   expected  %8d  %s\n",
+        nsamples,
+        nsamples - total_samples_recvd == 0 ? "OK" : "NOT OK");
+  
+  printf("  rx_packets:  %8ld",     total_pkts_recvd);
+  printf("   expected  %8ld  %s\n",
+        expected_rx_packets,
+        expected_rx_packets - total_pkts_recvd == 0 ? "OK" : "NOT OK");
+  
+
+  fflush(stdout);
+
+  printf("\nKernel interface statistics:\n");
+
+  long long delta;
+  delta = stop.rx_bytes - start.rx_bytes;
+  printf("  rx_bytes:    %8Ld",     delta);
+  printf("   expected  %8ld  %s\n",
+        expected_rx_bytes,
+        expected_rx_bytes - delta == 0 ? "OK" : "NOT OK");
+
+  delta = stop.rx_packets - start.rx_packets;
+  printf("  rx_packets:  %8Ld",     delta);
+  printf("   expected  %8ld  %s\n",
+        expected_rx_packets,
+        expected_rx_packets - delta == 0 ? "OK" : "NOT OK");
+
+  printf("  rx_errs:     %8Ld\n",   stop.rx_errs - start.rx_errs);
+  printf("  rx_drop:     %8Ld\n",   stop.rx_drop - start.rx_drop);
+  printf("  tx_bytes:    %8Ld\n",   stop.tx_bytes - start.tx_bytes);
+  printf("  tx_packets:  %8Ld\n",   stop.tx_packets - start.tx_packets);
+  printf("  tx_errs:     %8Ld\n",   stop.tx_errs - start.tx_errs);
+  printf("  tx_drop:     %8Ld\n",   stop.tx_drop - start.tx_drop);
+
+
+  return 0;
+}

Copied: usrp2/trunk/host-ng/apps/stdin_int32_fft.py (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/stdin_int32_fft.py)
===================================================================
--- usrp2/trunk/host-ng/apps/stdin_int32_fft.py                         (rev 0)
+++ usrp2/trunk/host-ng/apps/stdin_int32_fft.py 2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2005,2007,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 GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+from gnuradio import gr, gru
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, 
form, slider
+from optparse import OptionParser
+import wx
+import sys
+import numpy
+
+
+class app_top_block(stdgui2.std_top_block):
+    def __init__(self, frame, panel, vbox, argv):
+        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
+
+        self.frame = frame
+        self.panel = panel
+        
+        parser = OptionParser(option_class=eng_option)
+        parser.add_option("-d", "--decim", type="int", default=16,
+                          help="set fgpa decimation rate to DECIM 
[default=%default]")
+        parser.add_option("-f", "--freq", type="eng_float", default=None,
+                          help="set frequency to FREQ", metavar="FREQ")
+        parser.add_option("-W", "--waterfall", action="store_true", 
default=False,
+                          help="Enable waterfall display")
+        parser.add_option("-S", "--oscilloscope", action="store_true", 
default=False,
+                          help="Enable oscilloscope display")
+        (options, args) = parser.parse_args()
+        if len(args) != 0:
+            parser.print_help()
+            sys.exit(1)
+       self.options = options
+        self.options.gain = 1.0
+        self.show_debug_info = True
+        
+
+        input_rate = 100e6 / options.decim
+
+        self.src = gr.file_descriptor_source(gr.sizeof_short, 0, False);
+        self.s2c = gr.interleaved_short_to_complex()
+
+        if options.waterfall:
+            self.scope = \
+              waterfallsink2.waterfall_sink_c (panel, fft_size=1024, 
sample_rate=input_rate)
+        elif options.oscilloscope:
+            self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate)
+        else:
+            self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, y_divs=12, 
sample_rate=input_rate,ref_level=110,fft_rate=20)
+
+        self.connect(self.src, self.s2c, self.scope)
+
+        self._build_gui(vbox)
+       self._setup_events()
+       
+        # set initial values
+
+        if options.freq is None:
+            # if no freq was specified, use the mid-point
+            options.freq = 0.0
+
+        if self.show_debug_info:
+            self.myform['decim'].set_value(self.options.decim)
+
+
+    def _set_status_msg(self, msg):
+        self.frame.GetStatusBar().SetStatusText(msg, 0)
+
+    def _build_gui(self, vbox):
+
+        def _form_set_freq(kv):
+            return self.set_freq(kv['freq'])
+            
+        vbox.Add(self.scope.win, 10, wx.EXPAND)
+        
+        # add control area at the bottom
+        self.myform = myform = form.form()
+        hbox = wx.BoxSizer(wx.HORIZONTAL)
+        hbox.Add((5,0), 0, 0)
+        myform['freq'] = form.float_field(
+            parent=self.panel, sizer=hbox, label="Center freq", weight=1,
+            callback=myform.check_input_and_call(_form_set_freq, 
self._set_status_msg))
+
+        hbox.Add((5,0), 0, 0)
+        vbox.Add(hbox, 0, wx.EXPAND)
+
+        self._build_subpanel(vbox)
+
+    def _build_subpanel(self, vbox_arg):
+        # build a secondary information panel (sometimes hidden)
+
+        # FIXME figure out how to have this be a subpanel that is always
+        # created, but has its visibility controlled by foo.Show(True/False)
+        
+        def _form_set_decim(kv):
+            return self.set_decim(kv['decim'])
+
+        if not(self.show_debug_info):
+            return
+
+        panel = self.panel
+        vbox = vbox_arg
+        myform = self.myform
+
+        #panel = wx.Panel(self.panel, -1)
+        #vbox = wx.BoxSizer(wx.VERTICAL)
+
+        hbox = wx.BoxSizer(wx.HORIZONTAL)
+        hbox.Add((5,0), 0)
+
+        myform['decim'] = form.int_field(
+            parent=panel, sizer=hbox, label="Decim",
+            callback=myform.check_input_and_call(_form_set_decim, 
self._set_status_msg))
+
+        hbox.Add((5,0), 0)
+        vbox.Add(hbox, 0, wx.EXPAND)
+
+        
+    def set_freq(self, target_freq):
+        """
+        Set the center frequency we're interested in.
+
+        @param target_freq: frequency in Hz
+        @rypte: bool
+
+        Tuning is a two step process.  First we ask the front-end to
+        tune as close to the desired frequency as it can.  Then we use
+        the result of that operation and our target_frequency to
+        determine the value for the digital down converter.
+        """
+        
+        if True:
+            self.myform['freq'].set_value(target_freq)     # update displayed 
value
+           if not self.options.waterfall and not self.options.oscilloscope:
+               self.scope.win.set_baseband_freq(target_freq)
+           return True
+
+        return False
+
+    def set_gain(self, gain):
+        self.myform['gain'].set_value(gain)     # update displayed value
+
+    def set_decim(self, decim):
+        input_rate = 100e6 / self.options.decim
+        self.scope.set_sample_rate(input_rate)
+        if self.show_debug_info:  # update displayed values
+            self.myform['decim'].set_value(self.u.decim_rate())
+        return ok
+
+    def _setup_events(self):
+       if not self.options.waterfall and not self.options.oscilloscope:
+           self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick)
+           
+    def evt_left_dclick(self, event):
+       (ux, uy) = self.scope.win.GetXY(event)
+       if event.CmdDown():
+           # Re-center on maximum power
+           points = self.scope.win._points
+           if self.scope.win.peak_hold:
+               if self.scope.win.peak_vals is not None:
+                   ind = numpy.argmax(self.scope.win.peak_vals)
+               else:
+                   ind = int(points.shape()[0]/2)
+           else:
+               ind = numpy.argmax(points[:,1])
+            (freq, pwr) = points[ind]
+           target_freq = freq/self.scope.win._scale_factor
+           print ind, freq, pwr
+            self.set_freq(target_freq)            
+       else:
+           # Re-center on clicked frequency
+           target_freq = ux/self.scope.win._scale_factor
+           self.set_freq(target_freq)
+           
+       
+def main ():
+    app = stdgui2.stdapp(app_top_block, "USRP FFT", nstatus=1)
+    app.MainLoop()
+
+if __name__ == '__main__':
+    main ()

Copied: usrp2/trunk/host-ng/apps/streaming_fft.py (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/streaming_fft.py)
===================================================================
--- usrp2/trunk/host-ng/apps/streaming_fft.py                           (rev 0)
+++ usrp2/trunk/host-ng/apps/streaming_fft.py   2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+import os
+import os.path
+import sys
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+def main():
+    parser = OptionParser(option_class=eng_option)
+    parser.add_option("-d", "--decim", type="int", default=16,
+                      help="set fgpa decimation rate to DECIM 
[default=%default]")
+    parser.add_option("-f", "--freq", type="eng_float", default=0.0,
+                      help="set frequency to FREQ", metavar="FREQ")
+    parser.add_option("-g", "--gain", type="string", default=None,
+                      help="set gain to GAIN [default=%default]")
+    parser.add_option("-W", "--waterfall", action="store_true", default=False,
+                      help="Enable waterfall display")
+    parser.add_option("-S", "--oscilloscope", action="store_true", 
default=False,
+                      help="Enable oscilloscope display")
+    parser.add_option("-F", "--samples-per-frame", type="int", default=250,
+                      help="[default=%default]")
+    parser.add_option("-e", "--eth", default="eth0",
+                      help="specify ethernet interface [default=%default]")
+
+    (options, args) = parser.parse_args()
+    if len(args) != 0:
+        parser.print_help()
+        sys.exit(1)
+
+
+    path = os.path.dirname(sys.argv[0])
+    if path == '':
+        path = '.'
+    
+    
+    display_type = ''
+    if options.waterfall:
+        display_type = '-W'
+    if options.oscilloscope:
+        display_type = '-S'
+
+    gain_clause = ''
+    if options.gain:
+        gain_clause = '-g ' + options.gain
+
+    cmd = "sudo %s/rx_streaming_samples -e %s -f %g -d %d -F %d %s -o 
/proc/self/fd/1 | %s/stdin_int32_fft.py %s -f %g -d %d" % (
+        path, options.eth, options.freq, options.decim, 
options.samples_per_frame, gain_clause,
+        path, display_type, options.freq, options.decim)
+
+    print cmd
+    os.system(cmd)
+    
+
+if __name__ == '__main__':
+    main()

Modified: usrp2/trunk/host-ng/apps/test.sh
===================================================================
--- usrp2/trunk/host-ng/apps/test.sh    2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/apps/test.sh    2008-08-01 20:34:19 UTC (rev 9142)
@@ -1,5 +1,5 @@
 #!/bin/sh
 
-sudo ./test_usrp2 1>cerr 2>&1
+sudo ./test_usrp2 -d 4
 
 

Copied: usrp2/trunk/host-ng/apps/test2_usrp2.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/test2_usrp2.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/test2_usrp2.cc                             (rev 0)
+++ usrp2/trunk/host-ng/apps/test2_usrp2.cc     2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,378 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp2/usrp2.h>
+#include <usrp2/strtod_si.h>
+#include <usrp2/copiers.h>
+#include <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/trunk/host-ng/apps/test_usrp2.cc
===================================================================
--- usrp2/trunk/host-ng/apps/test_usrp2.cc      2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/apps/test_usrp2.cc      2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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;
 }

Copied: usrp2/trunk/host-ng/apps/tx_samples.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/tx_samples.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/tx_samples.cc                              (rev 0)
+++ usrp2/trunk/host-ng/apps/tx_samples.cc      2008-08-01 20:34:19 UTC (rev 
9142)
@@ -0,0 +1,231 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <usrp2/usrp2.h>
+#include <usrp2/strtod_si.h>
+#include <iostream>
+#include <complex>
+#include <getopt.h>
+#include <gruel/realtime.h>
+
+typedef std::complex<float> fcomplex;
+
+static const char *
+prettify_progname(const char *progname)                // that's probably 
almost a word ;)
+{
+  const char *p = strrchr(progname, '/');      // drop leading directory path
+  if (p)
+    p++;
+
+  if (strncmp(p, "lt-", 3) == 0)               // drop lt- libtool prefix
+    p += 3;
+
+  return p;
+}
+
+static void
+usage(const char *progname)
+{
+  fprintf(stderr, "Usage: %s [options]\n\n", prettify_progname(progname));
+  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, "  -I INPUT_FILE        set input filename 
[default=stdin]\n");
+  fprintf(stderr, "  -r                   repeat.  When EOF of input file is 
reached, seek to beginning\n");
+  fprintf(stderr, "  -f FREQ              set frequency to FREQ 
[default=0]\n");
+  fprintf(stderr, "  -i INTERP            set interpolation rate to INTERP 
[default=32]\n");
+  fprintf(stderr, "  -g gain              set tx gain\n");
+  fprintf(stderr, "  -S SCALE             fpga scaling factor for I & Q 
[default=256]\n");
+}
+
+#define GAIN_NOT_SET (-1000)
+#define        MAX_SAMPLES (371)
+
+int
+main(int argc, char **argv)
+{
+  const char *interface = "eth0";
+  const char *input_filename = 0;
+  bool repeat = false;
+  const char *mac_addr_str = "";
+  double freq = 0;
+  int32_t interp = 32;
+  int32_t samples_per_frame = MAX_SAMPLES;
+  int32_t scale = 3000;
+  double gain = GAIN_NOT_SET;
+  
+  int    ch;
+  double tmp;
+
+
+  while ((ch = getopt(argc, argv, "he:m:I:rf:i:S:F:g:")) != EOF){
+    switch (ch){
+
+    case 'e':
+      interface = optarg;
+      break;
+      
+    case 'm':
+      mac_addr_str = optarg;
+#if 0
+      if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
+       std::cerr << "invalid mac addr: " << optarg << std::endl;
+       usage(argv[0]);
+       return 1;
+      }
+#endif
+      break;
+
+    case 'I':
+      input_filename = optarg;
+      break;
+      
+    case 'r':
+      repeat = true;
+      break;
+      
+    case 'f':
+      if (!strtod_si(optarg, &freq)){
+       std::cerr << "invalid number: " << optarg << std::endl;
+       usage(argv[0]);
+       return 1;
+      }
+      break;
+
+    case 'F':
+      samples_per_frame = strtol(optarg, 0, 0);
+      break;
+
+    case 'i':
+      interp = strtol(optarg, 0, 0);
+      break;
+
+    case 'S':
+      if (!strtod_si(optarg, &tmp)){
+       std::cerr << "invalid number: " << optarg << std::endl;
+       usage(argv[0]);
+       return 1;
+      }
+      scale = static_cast<int32_t>(tmp);
+      break;
+      
+    case 'h':
+    default:
+      usage(argv[0]);
+      return 1;
+    }
+  }
+
+  
+  if (argc - optind != 0){
+    usage(argv[0]);
+    return 1;
+  }
+  
+  if (samples_per_frame < 9 || samples_per_frame > MAX_SAMPLES){
+    std::cerr << prettify_progname(argv[0])
+             << ": samples_per_frame is out of range.  "
+             << "Must be in [9, " << MAX_SAMPLES << "].\n";
+    usage(argv[0]);
+    return 1;
+  }
+
+
+  FILE *fp = 0;
+  if (input_filename == 0)
+    fp = stdin;
+  else {
+    fp = fopen(input_filename, "rb");
+    if (fp == 0){
+      perror(input_filename);
+      return 1;
+    }
+  }
+
+
+  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);
+  
+  if (gain != GAIN_NOT_SET){
+    if (!u2->set_tx_gain(gain)){
+      std::cerr << "set_tx_gain failed\n";
+      return 1;
+    }
+  }
+
+  usrp2::tune_result tr;
+  if (!u2->set_tx_center_freq(freq, &tr)){
+    fprintf(stderr, "set_tx_center_freq(%g) failed\n", freq);
+    return 1;
+  }
+
+  printf("Daughterboard configuration:\n");
+  printf("  baseband_freq=%f\n", tr.baseband_freq);
+  printf("       duc_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_tx_interp(interp)){
+    fprintf(stderr, "set_tx_interp(%d) failed\n", interp);
+    return 1;
+  }
+
+  if (!u2->set_tx_scale_iq(scale, scale)){
+    std::cerr << "set_tx_scale_iq failed\n";
+    return 1;
+  }
+
+
+  usrp2::tx_metadata   md;
+  md.timestamp = -1;
+  md.start_of_burst = 1;
+  md.send_now = 1;
+
+  while (1){
+
+    std::complex<int16_t> samples[MAX_SAMPLES];
+
+    int r = fread(samples, sizeof(uint32_t), samples_per_frame, fp);
+
+    // fprintf(stderr, "fread -> %d\n", r);
+    
+    if (r == 0){
+      if (!repeat)
+       break;
+      if (fseek(fp, 0, SEEK_SET) == -1)
+       break;
+    }
+
+    // FIXME if r < 9, pad to 9 for minimum packet size constraint
+
+    if (!u2->tx_complex_int16(0, samples, r, &md)){
+      fprintf(stderr, "tx_complex_int16 failed\n");
+      break;
+    }
+  }
+
+  return 0;
+}

Copied: usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/apps/u2_burn_mac_addr.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc                                
(rev 0)
+++ usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc        2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -0,0 +1,114 @@
+/* -*- 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "usrp2_basic.h"
+#include <iostream>
+#include <getopt.h>
+#include <string.h>
+#include <time.h>
+
+
+static void
+usage(const char *progname)
+{
+  fprintf(stderr, "usage: %s [-e ethN] [-m old_mac_addr] new_mac_addr\n",
+         progname);
+  fprintf(stderr, "  old_mac_addr defaults to 00:50:c2:85:3f:ff\n");
+  fprintf(stderr, "  new_mac_address must be HH:HH or HH:HH:HH:HH:HH:HH\n");
+}
+
+int
+main(int argc, char **argv)
+{
+  int ch;
+  const char *interface = "eth0";
+  char *old_mac_addr_str = "00:50:c2:85:3f:ff";
+  char *new_mac_addr_str = 0;
+  u2_mac_addr_t old_mac_addr;
+  u2_mac_addr_t new_mac_addr;
+
+  while ((ch = getopt(argc, argv, "he:m:")) != EOF){
+    switch (ch){
+    case 'e':
+      interface = optarg;
+      break;
+      
+    case 'm':
+      old_mac_addr_str = optarg;
+      break;
+      
+    case 'h':
+    default:
+      usage(argv[0]);
+      exit(1);
+    }
+  }
+
+  if (argc - optind != 1){
+    usage(argv[0]);
+    exit(1);
+  }
+
+  new_mac_addr_str = argv[optind];
+
+  if (!usrp2_basic::parse_mac_addr(old_mac_addr_str, &old_mac_addr)){
+    fprintf(stderr, "invalid mac address: %s\n", old_mac_addr_str);
+    exit(1);
+  }
+  if (!usrp2_basic::parse_mac_addr(new_mac_addr_str, &new_mac_addr)){
+    fprintf(stderr, "invalid mac address: %s\n", new_mac_addr_str);
+    exit(1);
+  }
+  
+
+  usrp2_basic *u2 = new usrp2_basic();
+
+  if (!u2->open(interface)){
+    std::cerr << "couldn't open " << interface << std::endl;
+    return 0;
+  }
+
+  if (!u2->find_usrp_by_mac(old_mac_addr, 0)){
+    std::cerr << "No USRP2 with address "
+             << old_mac_addr << " found.\n";
+    return 1;
+  }
+
+  if (!u2->burn_mac_addr(old_mac_addr, new_mac_addr)){
+    std::cerr << "Failed to burn mac address\n";
+    return 1;
+  }
+
+  // wait 250 ms
+  struct timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = 250000000;
+  nanosleep(&ts, 0);
+
+  // Now see if we can find it using it's new address
+  if (!u2->find_usrp_by_mac(new_mac_addr, 0)){
+    std::cerr << "Failed to find USRP2 using new address "
+             << new_mac_addr << ".\n";
+    return 1;
+  }
+
+  return 0;
+}

Modified: usrp2/trunk/host-ng/configure.ac
===================================================================
--- usrp2/trunk/host-ng/configure.ac    2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/configure.ac    2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/include/usrp2/Makefile.am
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/Makefile.am       2008-08-01 20:25:36 UTC 
(rev 9141)
+++ usrp2/trunk/host-ng/include/usrp2/Makefile.am       2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -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/trunk/host-ng/include/usrp2/copiers.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copiers.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/copiers.h                         (rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/copiers.h 2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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/trunk/host-ng/include/usrp2/copy_handler.h
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/copy_handler.h    2008-08-01 20:25:36 UTC 
(rev 9141)
+++ usrp2/trunk/host-ng/include/usrp2/copy_handler.h    2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -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/trunk/host-ng/include/usrp2/data_handler.h
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/data_handler.h    2008-08-01 20:25:36 UTC 
(rev 9141)
+++ usrp2/trunk/host-ng/include/usrp2/data_handler.h    2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -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/trunk/host-ng/include/usrp2/metadata.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/metadata.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/metadata.h                                
(rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/metadata.h        2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -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/trunk/host-ng/include/usrp2/rx_sample_handler.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/rx_sample_handler.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/rx_sample_handler.h                       
        (rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/rx_sample_handler.h       2008-08-01 
20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/include/usrp2/strtod_si.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/strtod_si.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/strtod_si.h                               
(rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/strtod_si.h       2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -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/trunk/host-ng/include/usrp2/tune_result.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/tune_result.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/tune_result.h                             
(rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/tune_result.h     2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -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/trunk/host-ng/include/usrp2/usrp2.h
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/usrp2.h   2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/include/usrp2/usrp2.h   2008-08-01 20:34:19 UTC (rev 
9142)
@@ -22,131 +22,251 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/utility.hpp>
 #include <vector>
+#include <complex>
+#include <iosfwd>
+#include <usrp2/rx_sample_handler.h>
+#include <usrp2/tune_result.h>
+#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(...);
+
+    /*!
+     * \brief transmit complex<float> samples to USRP2
+     *
+     * \param channel specifies the channel to send them to
+     * \param samples are the samples to transmit
+     * \param nsamples is the number of samples to transmit
+     * \param metadata provides the timestamp and flags
+     */
+    bool tx_complex_float(unsigned int channel,
+                         const std::complex<float> *samples,
+                         size_t nsamples,
+                         const tx_metadata *metadata);
+
+    /*!
+     * \brief transmit complex<int16_t> samples to USRP2
+     *
+     * \param channel specifies the channel to send them to
+     * \param samples are the samples to transmit
+     * \param nsamples is the number of samples to transmit
+     * \param metadata provides the timestamp and flags
+     */
+    bool tx_complex_int16(unsigned int channel,
+                         const std::complex<int16_t> *samples,
+                         size_t nsamples,
+                         const tx_metadata *metadata);
+
+    /*!
+     * \brief transmit raw uint32_t data items to USRP2
+     *
+     * The caller is responsible for ensuring that the items are
+     * formatted appropriately for the USRP2 and its configuration.
+     * This method is used primarily by the system itself.  Users
+     * should call tx_complex_float or tx_complex_16 instead.
+     *
+     * \param channel specifies the channel to send them to
+     * \param items are the data items to transmit
+     * \param nitems is the number of items to transmit
+     * \param metadata provides the timestamp and flags
+     */
+    bool tx_raw(unsigned int channel,
+               const uint32_t *items,
+               size_t nitems,
+               const tx_metadata *metadata);
+
+    // ----------------------------------------------------------------
+
+    /*!
+     * \brief MIMO configuration
+     *
+     * \param flags from usrp2_mimo_config.h
+     *
+     * <pre>
+     *   one of these:
+     *
+     *     MC_WE_DONT_LOCK
+     *     MC_WE_LOCK_TO_SMA
+     *     MC_WE_LOCK_TO_MIMO
+     *
+     *   and optionally this:
+     *
+     *     MC_PROVIDE_CLK_TO_MIMO
+     * </pre>
+     */
+    bool config_mimo(int flags);
+
+
+
+    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;
+  };
 
 };
 
+std::ostream& operator<<(std::ostream &os, const usrp2::props &x);
+
+
 #endif /* INCLUDED_USRP2_H */

Modified: usrp2/trunk/host-ng/lib/Makefile.am
===================================================================
--- usrp2/trunk/host-ng/lib/Makefile.am 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/Makefile.am 2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/control.cc
===================================================================
--- usrp2/trunk/host-ng/lib/control.cc  2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/control.cc  2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/control.h
===================================================================
--- usrp2/trunk/host-ng/lib/control.h   2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/control.h   2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/copiers.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/lib/copiers.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/copiers.cc                          (rev 0)
+++ usrp2/trunk/host-ng/lib/copiers.cc  2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/copy_handler.cc
===================================================================
--- usrp2/trunk/host-ng/lib/copy_handler.cc     2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/lib/copy_handler.cc     2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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/trunk/host-ng/lib/data_handler.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/lib/data_handler.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/data_handler.cc                             (rev 0)
+++ usrp2/trunk/host-ng/lib/data_handler.cc     2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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/trunk/host-ng/lib/eth_buffer.cc
===================================================================
--- usrp2/trunk/host-ng/lib/eth_buffer.cc       2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/lib/eth_buffer.cc       2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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,67 @@
       // 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;
   }
+
+  eth_buffer::result
+  eth_buffer::tx_framev(const eth_iovec *iov, int iovcnt, int 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_packetv(iov, iovcnt);
+    if (res < 0)
+      return EB_ERROR;
+
+    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/trunk/host-ng/lib/eth_buffer.h
===================================================================
--- usrp2/trunk/host-ng/lib/eth_buffer.h        2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/lib/eth_buffer.h        2008-08-01 20:34:19 UTC (rev 
9142)
@@ -22,7 +22,7 @@
 #define INCLUDED_USRP2_ETH_BUFFER_H
 
 #include "pktfilter.h"
-#include "eth_common.h"
+#include <eth_common.h>
 #include <boost/utility.hpp>
 #include <vector>
 #include <stdint.h>
@@ -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/trunk/host-ng/lib/ethernet.cc
===================================================================
--- usrp2/trunk/host-ng/lib/ethernet.cc 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/ethernet.cc 2008-08-01 20:34:19 UTC (rev 9142)
@@ -182,6 +182,25 @@
     }
     return retval;
   }
+
+  int
+  ethernet::write_packetv(const eth_iovec *iov, size_t iovlen)
+  {
+    struct msghdr mh;
+    memset(&mh, 0, sizeof(mh));
+    mh.msg_iov = const_cast<eth_iovec*>(iov);
+    mh.msg_iovlen = iovlen;
+
+    int retval = sendmsg(d_fd, &mh, 0);
+    if (retval < 0){
+      if (errno == EINTR)
+       return write_packetv(iov, iovlen);
+      
+      perror("ethernet:write_packetv: send");
+      return -1;
+    }
+    return retval;
+  }
   
   bool
   ethernet::attach_pktfilter (pktfilter *pf)

Modified: usrp2/trunk/host-ng/lib/ethernet.h
===================================================================
--- usrp2/trunk/host-ng/lib/ethernet.h  2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/ethernet.h  2008-08-01 20:34:19 UTC (rev 9142)
@@ -21,6 +21,7 @@
 
 #include <string>
 #include <vector>
+#include <eth_common.h>
 
 namespace usrp2 {
 
@@ -103,6 +104,19 @@
      * Packet must begin with 14-byte ethhdr, but does not include the FCS.
      */
     int write_packet (const void *buf, int buflen);
+
+    /*
+     * \brief Write ethernet packet to interface.
+     *
+     * \param iov      scatter/gather array
+     * \param iovlen   number of elements in iov
+     *
+     * \returns number of bytes written or -1 if trouble.
+     *
+     * Packet must begin with 14-byte ethhdr, but does not include the FCS.
+     */
+    int write_packetv (const eth_iovec *iov, size_t iovlen);
+
   };
   
 } // namespace usrp2

Modified: usrp2/trunk/host-ng/lib/find.cc
===================================================================
--- usrp2/trunk/host-ng/lib/find.cc     2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/find.cc     2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/ring.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/ring.cc                             (rev 0)
+++ usrp2/trunk/host-ng/lib/ring.cc     2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/ring.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.h)
===================================================================
--- usrp2/trunk/host-ng/lib/ring.h                              (rev 0)
+++ usrp2/trunk/host-ng/lib/ring.h      2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/rx_sample_handler.cc (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/lib/rx_sample_handler.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/rx_sample_handler.cc                                
(rev 0)
+++ usrp2/trunk/host-ng/lib/rx_sample_handler.cc        2008-08-01 20:34:19 UTC 
(rev 9142)
@@ -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/trunk/host-ng/lib/strtod_si.c (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/lib/strtod_si.c)
===================================================================
--- usrp2/trunk/host-ng/lib/strtod_si.c                         (rev 0)
+++ usrp2/trunk/host-ng/lib/strtod_si.c 2008-08-01 20:34:19 UTC (rev 9142)
@@ -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/trunk/host-ng/lib/usrp2.cc
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2.cc    2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/usrp2.cc    2008-08-01 20:34:19 UTC (rev 9142)
@@ -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,98 @@
   }
   
   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);
+  }
+  
+  bool
+  usrp2::tx_complex_float(unsigned int channel,
+                         const std::complex<float> *samples,
+                         size_t nsamples,
+                         const tx_metadata *metadata)
+  {
+    return d_impl->tx_complex_float(channel, samples, nsamples, metadata);
+  }
+
+  bool
+  usrp2::tx_complex_int16(unsigned int channel,
+                         const std::complex<int16_t> *samples,
+                         size_t nsamples,
+                         const tx_metadata *metadata)
+  {
+    return d_impl->tx_complex_int16(channel, samples, nsamples, metadata);
+  }
+
+  bool
+  usrp2::tx_raw(unsigned int channel,
+               const uint32_t *items,
+               size_t nitems,
+               const tx_metadata *metadata)
+  {
+    return d_impl->tx_raw(channel, items, nitems, metadata);
+  }
+
 } // namespace usrp2
+
+
+std::ostream& operator<<(std::ostream &os, const usrp2::props &x)
+{
+  os << x.addr;
+
+  char buf[128];
+  snprintf(buf, sizeof(buf)," hw_rev = 0x%04x", x.hw_rev);
+
+  os << buf;
+  return os;
+}

Copied: usrp2/trunk/host-ng/lib/usrp2_bytesex.h (from rev 9140, 
usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_bytesex.h)
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_bytesex.h                             (rev 0)
+++ usrp2/trunk/host-ng/lib/usrp2_bytesex.h     2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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/trunk/host-ng/lib/usrp2_impl.cc
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_impl.cc       2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/lib/usrp2_impl.cc       2008-08-01 20:34:19 UTC (rev 
9142)
@@ -21,25 +21,36 @@
 #endif
 
 #include <usrp2/usrp2.h>
+#include <usrp2/tune_result.h>
+#include <usrp2/copiers.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 +67,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 +81,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 +198,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;
@@ -156,7 +209,7 @@
                             int word0_flags, int chan, uint32_t timestamp)
   {
     init_et_hdrs(p, dst);
-    u2p_set_word0(&p->fixed, 0, chan);
+    u2p_set_word0(&p->fixed, word0_flags, chan);
     u2p_set_timestamp(&p->fixed, timestamp);
     
     if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
@@ -171,18 +224,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, "S", 1); // 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 +424,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 +444,398 @@
     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;
-    };
+    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::stop_rx_streaming(unsigned int channel)
+  {
+    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);
     
-    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);
+    if (success)
+      d_channel_rings[channel].reset();
+
+    return success;
   }
   
+
   bool
-  usrp2::impl::stop_rx_streaming()
+  usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
   {
-    uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
-    memset(pktbuf, 0, sizeof(pktbuf));
+    if (channel > MAX_CHAN) {
+      std::cerr << "usrp2: invalid channel (" << channel
+                << " )" << std::endl;
+      return false;
+    }
     
-    struct command {
-      u2_eth_packet_t  h;
-      op_id_t          op_stop_rx;
-    };
+    if (channel > 0) {
+      std::cerr << "usrp2: channel " << channel
+                << " not implemented" << std::endl;
+      return false;
+    }
     
-    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)
+    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;
+
+      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;
   }
-  
-  void
-  usrp2::impl::bg_loop()
+
+  // ----------------------------------------------------------------
+  //                           Transmit
+  // ----------------------------------------------------------------
+
+  bool 
+  usrp2::impl::set_tx_gain(double gain)
   {
-    d_bg_running = true;
-    while(d_bg_running) {
-      int res = d_buffer->rx_frames(this, 1000);
-      if (res == -1)
-       break;  
-    }
+    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));
+    
+    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;
   }
   
-  unsigned int
-  usrp2::impl::operator()(const void *base, unsigned int len)
+  bool
+  usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
   {
-    u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
-    int chan = u2p_chan(&pkt->hdrs.fixed);
+    op_config_tx_v2_cmd cmd;
+    op_config_tx_reply_v2_t reply;
 
-    if (chan == CONTROL_CHAN) {                // control packets
-      DEBUG_LOG("C");
-      return handle_control_packet(base, len);
+    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));
+    
+    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);
+    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);
     }
-    else {                             // data packets
-      DEBUG_LOG("D");
-      return handle_data_packet(base, len);
-    }
 
-    // not reached
+    return success;
   }
+  
+  bool
+  usrp2::impl::set_tx_interp(int interpolation_factor)
+  {
+    op_config_tx_v2_cmd cmd;
+    op_config_tx_reply_v2_t reply;
 
-  unsigned int
-  usrp2::impl::handle_control_packet(const void *base, unsigned int len)
-  {
-    // point to beginning of payload (subpackets)
-    unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
+    init_config_tx_v2_cmd(&cmd);
+    cmd.op.valid = htons(CFGV_INTERP_DECIM);
+    cmd.op.interp = htonl(interpolation_factor);
     
-    // FIXME iterate over payload, handling more than a single
-    // subpacket, when (if?) the firmware starts sending them
-    
-    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;
-    }
-
-    // handle command reply here
-    return 0;
+    bool success = (ntohx(reply.ok) == 1);
+    return success;
   }
   
-  unsigned int
-  usrp2::impl::handle_data_packet(const void *base, unsigned int len)
+  bool
+  usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
   {
-    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_SCALE_IQ);
+    cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
     
-    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;
+    bool success = (ntohx(reply.ok) == 1);
+    return success;
+  }
 
-    // enqueue in channel ring here
-    return 0; // will be KEEP, as the channel ring runner will retire packet
+  bool
+  usrp2::impl::tx_complex_float(unsigned int channel,
+                               const std::complex<float> *samples,
+                               size_t nsamples,
+                               const tx_metadata *metadata)
+  {
+    uint32_t items[nsamples];
+    copy_host_complex_float_to_u2_complex_16(nsamples, samples, items);
+    return tx_raw(channel, items, nsamples, metadata);
   }
 
-  void
-  usrp2::impl::stop_bg()
+  bool
+  usrp2::impl::tx_complex_int16(unsigned int channel,
+                               const std::complex<int16_t> *samples,
+                               size_t nsamples,
+                               const tx_metadata *metadata)
   {
-    if (USRP2_IMPL_DEBUG)
-      std::cerr << "usrp2_thread::stop: joining background thread "
-               << this << std::endl;
-    d_bg_running = false;
-    
-    void *dummy_status;
-    d_bg_thread->join(&dummy_status);  
-    
-    if (USRP2_IMPL_DEBUG)
-      std::cerr << "usrp2_thread::stop: join returned" << std::endl;
+#ifdef WORDS_BIGENDIAN
+
+    // Already binary equivalent to 16-bit I/Q on the wire.
+    // No conversion required.
+
+    assert(sizeof(samples[0]) == sizeof(uint32_t));
+    return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
+
+#else
+
+    uint32_t items[nsamples];
+    copy_host_complex_16_to_u2_complex_16(nsamples, samples, items);
+    return tx_raw(channel, items, nsamples, metadata);
+
+#endif
   }
-  
+
+  bool
+  usrp2::impl::tx_raw(unsigned int channel,
+                     const uint32_t *items,
+                     size_t nitems,
+                     const tx_metadata *metadata)
+  {
+    if (nitems == 0)
+      return true;
+
+    // FIXME there's the possibility that we send fewer than 9 items in a 
frame.
+    // That would end up glitching the transmitter, since the ethernet will 
pad to
+    // 64-bytes total (9 items).  We really need some part of the stack to
+    // carry the real length (thdr?).
+
+    // fragment as necessary then fire away
+
+    size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
+    size_t last_frame = nframes - 1;
+    u2_eth_packet_t    hdrs;
+
+    size_t n = 0;
+    for (size_t fn = 0; fn < nframes; fn++){
+      uint32_t timestamp = 0;
+      uint32_t flags = 0;
+
+      if (fn == 0){
+       timestamp = metadata->timestamp;
+       if (metadata->send_now)
+         flags |= U2P_TX_IMMEDIATE;
+       if (metadata->start_of_burst)
+         flags |= U2P_TX_START_OF_BURST;
+      }
+      if (fn > 0){
+       flags |= U2P_TX_IMMEDIATE;
+      }
+      if (fn == last_frame){
+       if (metadata->end_of_burst)
+         flags |= U2P_TX_END_OF_BURST;
+      }
+
+      init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
+
+      size_t i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
+
+      eth_iovec iov[2];
+      iov[0].iov_base = &hdrs;
+      iov[0].iov_len = sizeof(hdrs);
+      iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
+      iov[1].iov_len = i * sizeof(uint32_t);
+
+      if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
+       return false;
+      }
+
+      n += i;
+    }
+
+    return true;
+  }
+
+
 } // namespace usrp2

Modified: usrp2/trunk/host-ng/lib/usrp2_impl.h
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_impl.h        2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/lib/usrp2_impl.h        2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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,95 @@
   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);
+
+    bool tx_complex_float(unsigned int channel,
+                         const std::complex<float> *samples,
+                         size_t nsamples,
+                         const tx_metadata *metadata);
+
+    bool tx_complex_int16(unsigned int channel,
+                         const std::complex<int16_t> *samples,
+                         size_t nsamples,
+                         const tx_metadata *metadata);
+
+    bool tx_raw(unsigned int channel,
+               const uint32_t *items,
+               size_t nitems,
+               const tx_metadata *metadata);
   };
   
 } // namespace usrp2

Modified: usrp2/trunk/host-ng/lib/usrp2_thread.cc
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_thread.cc     2008-08-01 20:25:36 UTC (rev 
9141)
+++ usrp2/trunk/host-ng/lib/usrp2_thread.cc     2008-08-01 20:34:19 UTC (rev 
9142)
@@ -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]