From c7f848ab0da69e54c88ad36bde94b9fe665f386e Mon Sep 17 00:00:00 2001
From: Josh Blum <josh@joshknows.com>
Date: Fri, 17 Jun 2011 06:31:36 +0100
Subject: e100: implemented spi, i2c, messages w/ peek/poke

spi and i2c are done w/ polling, but this is ok,
the transactions always complete by the first check

a gpio is used to wake up poll() and check for messages.
messages are read using poke32, unpacked, and enqueued.
---
 host/lib/usrp/e100/e100_iface.cpp | 129 ++++++++++++++--------
 host/lib/usrp/e100/e100_impl.cpp  |   7 +-
 host/lib/usrp/e100/e100_impl.hpp  |   3 +-
 host/lib/usrp/e100/e100_regs.hpp  |  62 ++++++++++-
 host/lib/usrp/e100/io_impl.cpp    | 218 ++++++++++++++++++++++----------------
 5 files changed, 273 insertions(+), 146 deletions(-)

(limited to 'host/lib/usrp/e100')

diff --git a/host/lib/usrp/e100/e100_iface.cpp b/host/lib/usrp/e100/e100_iface.cpp
index e44e438b0..1bf33ae5b 100644
--- a/host/lib/usrp/e100/e100_iface.cpp
+++ b/host/lib/usrp/e100/e100_iface.cpp
@@ -23,11 +23,10 @@
 #include <fcntl.h> //open, close
 #include <linux/usrp_e.h> //ioctl structures and constants
 #include <boost/thread/thread.hpp> //sleep
-#include <boost/format.hpp>
 #include <boost/thread/mutex.hpp>
+#include <boost/format.hpp>
 #include <linux/i2c-dev.h>
 #include <linux/i2c.h>
-#include <iostream>
 #include <fstream>
 
 using namespace uhd;
@@ -168,6 +167,12 @@ public:
                 "The module build is not compatible with the host code build."
             ) % USRP_E_COMPAT_NUMBER % module_compat_num));
         }
+
+        //perform a global reset after opening
+        this->poke32(E100_REG_GLOBAL_RESET, 0);
+
+        //and now is a good time to init the i2c
+        this->i2c_init();
     }
 
     void close(void){
@@ -193,7 +198,7 @@ public:
      * IOCTL: provides the communication base for all other calls
      ******************************************************************/
     void ioctl(int request, void *mem){
-        boost::mutex::scoped_lock lock(_ctrl_mutex);
+        boost::mutex::scoped_lock lock(_ioctl_mutex);
 
         if (::ioctl(_node_fd, request, mem) < 0){
             throw uhd::os_error(str(
@@ -261,46 +266,84 @@ public:
     /*******************************************************************
      * I2C
      ******************************************************************/
-    static const size_t max_i2c_data_bytes = 10;
+    static const boost::uint32_t i2c_datarate = 400000;
+    static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else
+
+    void i2c_init(void) {
+        //init I2C FPGA interface.
+        poke16(E100_REG_I2C_CTRL, 0x0000);
+        //set prescalers to operate at 400kHz: WB_CLK is 64MHz...
+        boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1;
+        poke16(E100_REG_I2C_PRESCALER_LO, prescaler & 0xFF);
+        poke16(E100_REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF);
+        poke16(E100_REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core
+    }
+
+    void i2c_wait(void){
+        for (size_t i = 0; i < 100; i++){
+            if ((this->peek16(E100_REG_I2C_CMD_STATUS) & I2C_ST_TIP) == 0) return;
+            boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+        }
+        UHD_MSG(error) << "i2c_wait: timeout" << std::endl;
+    }
+
+    bool wait_chk_ack(void){
+        i2c_wait();
+        return (this->peek16(E100_REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0;
+    }
 
     void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
-        //allocate some memory for this transaction
-        UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes);
-        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
+        poke16(E100_REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0)
+        poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
 
-        //load the data struct
-        usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
-        data->addr = addr;
-        data->len = bytes.size();
-        std::copy(bytes.begin(), bytes.end(), data->data);
+        //wait for previous transfer to complete
+        if(!wait_chk_ack()) {
+            poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+            return;
+        }
 
-        //call the spi ioctl
-        this->ioctl(USRP_E_I2C_WRITE, data);
+        for(size_t i = 0; i < bytes.size(); i++) {
+            poke16(E100_REG_I2C_DATA, bytes[i]);
+            poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
+            if(!wait_chk_ack()) {
+                poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+                return;
+            }
+        }
     }
 
     byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
-        //allocate some memory for this transaction
-        UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes);
-        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
-
-        //load the data struct
-        usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
-        data->addr = addr;
-        data->len = num_bytes;
+        byte_vector_t bytes;
+        if(num_bytes == 0) return bytes;
 
-        //call the spi ioctl
-        this->ioctl(USRP_E_I2C_READ, data);
+        while (peek16(E100_REG_I2C_CMD_STATUS) & I2C_ST_BUSY);
 
-        //unload the data
-        byte_vector_t bytes(data->len);
-        UHD_ASSERT_THROW(bytes.size() == num_bytes);
-        std::copy(data->data, data->data+bytes.size(), bytes.begin());
+        poke16(E100_REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1)
+        poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START);
+        //wait for previous transfer to complete
+        if(!wait_chk_ack()) {
+            poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+        }
+        for(; num_bytes > 0; num_bytes--) {
+            poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == 1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
+            i2c_wait();
+            boost::uint8_t readback = peek16(E100_REG_I2C_DATA) & 0xFF;
+            bytes.push_back(readback);
+        }
         return bytes;
     }
 
     /*******************************************************************
      * SPI
      ******************************************************************/
+    void spi_wait(void) {
+        for (size_t i = 0; i < 100; i++){
+            if ((this->peek16(E100_REG_SPI_CTRL) & SPI_CTRL_GO_BSY) == 0) return;
+            boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+        }
+        UHD_MSG(error) << "spi_wait: timeout" << std::endl;
+    }
+
     boost::uint32_t transact_spi(
         int which_slave,
         const spi_config_t &config,
@@ -312,23 +355,23 @@ public:
             bits, num_bits, readback
         );
 
-        //load data struct
-        usrp_e_spi data;
-        data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY;
-        data.slave = which_slave;
-        data.length = num_bits;
-        data.data = bits;
+        UHD_ASSERT_THROW(num_bits <= 32 and (num_bits % 8) == 0);
 
-        //load the flags
-        data.flags = 0;
-        data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL;
-        data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL  : UE_SPI_PUSH_RISE;
+        int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) |
+                         ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG)
+                         ;
+        boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags;
 
-        //call the spi ioctl
-        this->ioctl(USRP_E_SPI, &data);
+        spi_wait();
+        poke16(E100_REG_SPI_DIV, 0x0001); // = fpga_clk / 4
+        poke32(E100_REG_SPI_SS, which_slave & 0xFFFF);
+        poke32(E100_REG_SPI_TXRX0, bits);
+        poke16(E100_REG_SPI_CTRL, ctrl);
+        poke16(E100_REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY);
 
-        //unload the data
-        return data.data;
+        if (not readback) return 0;
+        spi_wait();
+        return peek32(E100_REG_SPI_TXRX0);
     }
 
     boost::uint32_t bitbang_spi(
@@ -369,7 +412,7 @@ public:
 private:
     int _node_fd;
     i2c_dev_iface _i2c_dev_iface;
-    boost::mutex _ctrl_mutex;
+    boost::mutex _ioctl_mutex;
     iface_gpios_type::sptr _gpios;
 };
 
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
index 40ae20eaa..aa87b87dd 100644
--- a/host/lib/usrp/e100/e100_impl.cpp
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -23,6 +23,7 @@
 #include <uhd/exception.hpp>
 #include <uhd/utils/static.hpp>
 #include <uhd/utils/images.hpp>
+#include <boost/bind.hpp>
 #include <boost/format.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/functional/hash.hpp>
@@ -155,9 +156,9 @@ e100_impl::e100_impl(
     _iface(iface),
     _clock_ctrl(clock_ctrl),
     _codec_ctrl(e100_codec_ctrl::make(_iface)),
-    _data_xport(e100_make_mmap_zero_copy(_iface)),
-    _recv_frame_size(std::min(_data_xport->get_recv_frame_size(), size_t(device_addr.cast<double>("recv_frame_size", 1e9)))),
-    _send_frame_size(std::min(_data_xport->get_send_frame_size(), size_t(device_addr.cast<double>("send_frame_size", 1e9))))
+    _data_transport(e100_make_mmap_zero_copy(_iface)),
+    _recv_frame_size(std::min(_data_transport->get_recv_frame_size(), size_t(device_addr.cast<double>("recv_frame_size", 1e9)))),
+    _send_frame_size(std::min(_data_transport->get_send_frame_size(), size_t(device_addr.cast<double>("send_frame_size", 1e9))))
 {
 
     //setup otw types
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
index 1390559a0..a38c3b5a1 100644
--- a/host/lib/usrp/e100/e100_impl.hpp
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -113,11 +113,12 @@ private:
     e100_codec_ctrl::sptr _codec_ctrl;
 
     //handle io stuff
-    uhd::transport::zero_copy_if::sptr _data_xport;
+    uhd::transport::zero_copy_if::sptr _data_transport;
     UHD_PIMPL_DECL(io_impl) _io_impl;
     size_t _recv_frame_size, _send_frame_size;
     uhd::otw_type_t _send_otw_type, _recv_otw_type;
     void io_init(void);
+    void handle_irq(void);
     void handle_overrun(size_t);
     void update_xport_channel_mapping(void);
 
diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp
index 5be607389..d5e61f45f 100644
--- a/host/lib/usrp/e100/e100_regs.hpp
+++ b/host/lib/usrp/e100/e100_regs.hpp
@@ -47,10 +47,16 @@
 
 /////////////////////////////////////////////////////
 // Slave 2 -- SPI Core
-//   This should be accessed through the IOCTL
-//   Users should not touch directly
-
+//these are 32-bit registers mapped onto the 16-bit Wishbone bus.
+//Using peek32/poke32 should allow transparent use of these registers.
 #define E100_REG_SPI_BASE E100_REG_SLAVE(2)
+#define E100_REG_SPI_TXRX0 E100_REG_SPI_BASE + 0
+#define E100_REG_SPI_TXRX1 E100_REG_SPI_BASE + 4
+#define E100_REG_SPI_TXRX2 E100_REG_SPI_BASE + 8
+#define E100_REG_SPI_TXRX3 E100_REG_SPI_BASE + 12
+#define E100_REG_SPI_CTRL  E100_REG_SPI_BASE + 16
+#define E100_REG_SPI_DIV   E100_REG_SPI_BASE + 20
+#define E100_REG_SPI_SS    E100_REG_SPI_BASE + 24
 
 //spi slave constants
 #define UE_SPI_SS_AD9522    (1 << 3)
@@ -58,13 +64,56 @@
 #define UE_SPI_SS_TX_DB     (1 << 1)
 #define UE_SPI_SS_RX_DB     (1 << 0)
 
+//spi ctrl register bit definitions
+#define SPI_CTRL_ASS      (1<<13)
+#define SPI_CTRL_IE       (1<<12)
+#define SPI_CTRL_LSB      (1<<11)
+#define SPI_CTRL_TXNEG    (1<<10) //mosi edge, push on falling edge when 1
+#define SPI_CTRL_RXNEG    (1<< 9) //miso edge, latch on falling edge when 1
+#define SPI_CTRL_GO_BSY   (1<< 8)
+#define SPI_CTRL_CHAR_LEN_MASK 0x7F
+
 ////////////////////////////////////////////////
 // Slave 3 -- I2C Core
-//   This should be accessed through the IOCTL
-//   Users should not touch directly
 
 #define E100_REG_I2C_BASE E100_REG_SLAVE(3)
+#define E100_REG_I2C_PRESCALER_LO E100_REG_I2C_BASE + 0
+#define E100_REG_I2C_PRESCALER_HI E100_REG_I2C_BASE + 2
+#define E100_REG_I2C_CTRL         E100_REG_I2C_BASE + 4
+#define E100_REG_I2C_DATA         E100_REG_I2C_BASE + 6
+#define E100_REG_I2C_CMD_STATUS   E100_REG_I2C_BASE + 8
+
+//and while we're here...
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+
+#define	I2C_CTRL_EN	(1 << 7)	// core enable
+#define	I2C_CTRL_IE	(1 << 6)	// interrupt enable
+
+#define	I2C_CMD_START	(1 << 7)	// generate (repeated) start condition
+#define I2C_CMD_STOP	(1 << 6)	// generate stop condition
+#define	I2C_CMD_RD	(1 << 5)	// read from slave
+#define I2C_CMD_WR	(1 << 4)	// write to slave
+#define	I2C_CMD_NACK	(1 << 3)	// when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2	(1 << 2)	// reserved
+#define	I2C_CMD_RSVD_1	(1 << 1)	// reserved
+#define I2C_CMD_IACK	(1 << 0)	// set to clear pending interrupt
+
+#define I2C_ST_RXACK	(1 << 7)	// Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define	I2C_ST_BUSY	(1 << 6)	// 1 after START signal detected; 0 after STOP signal detected
+#define	I2C_ST_AL	(1 << 5)	// Arbitration lost.  1 when core lost arbitration
+#define	I2C_ST_RSVD_4	(1 << 4)	// reserved
+#define	I2C_ST_RSVD_3	(1 << 3)	// reserved
+#define	I2C_ST_RSVD_2	(1 << 2)	// reserved
+#define I2C_ST_TIP	(1 << 1)	// Transfer-in-progress
+#define	I2C_ST_IP	(1 << 0)	// Interrupt pending
+
+////////////////////////////////////////////////
+// Slave 5 -- Error messages buffer
 
+#define E100_REG_ERR_BUFF E100_REG_SLAVE(5)
 
 ////////////////////////////////////////////////
 // Slave 4 -- GPIO
@@ -113,6 +162,7 @@
 #define E100_REG_RB_TIME_PPS_SECS   E100_REG_RB_MUX_32_BASE + 8
 #define E100_REG_RB_TIME_PPS_TICKS  E100_REG_RB_MUX_32_BASE + 12
 #define E100_REG_RB_MISC_TEST32     E100_REG_RB_MUX_32_BASE + 16
+#define E100_REG_RB_ERR_STATUS      E100_REG_RB_MUX_32_BASE + 20
 
 ////////////////////////////////////////////////////
 // Slave 8 -- Settings Bus
@@ -126,6 +176,7 @@
 #define UE_SR_RX_DSP0 10       // 4 regs (+0 to +3)
 #define UE_SR_RX_CTRL1 16      // 9 regs (+0 to +8)
 #define UE_SR_RX_DSP1 26       // 4 regs (+0 to +3)
+#define UE_SR_ERR_CTRL 30      // 1 reg
 #define UE_SR_TX_CTRL 32       // 4 regs (+0 to +3)
 #define UE_SR_TX_DSP 38        // 3 regs (+0 to +2)
 
@@ -141,6 +192,7 @@
 #define E100_REG_SR_ADDR(n) (E100_REG_SLAVE(8) + (4*(n)))
 
 #define E100_REG_SR_MISC_TEST32        E100_REG_SR_ADDR(UE_SR_REG_TEST32)
+#define E100_REG_SR_ERR_CTRL           E100_REG_SR_ADDR(UE_SR_ERR_CTRL)
 
 /////////////////////////////////////////////////
 // Magic reset regs
diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp
index dc0d959fa..a8d3ad015 100644
--- a/host/lib/usrp/e100/io_impl.cpp
+++ b/host/lib/usrp/e100/io_impl.cpp
@@ -17,6 +17,7 @@
 
 #include "../../transport/super_recv_packet_handler.hpp"
 #include "../../transport/super_send_packet_handler.hpp"
+#include <linux/usrp_e.h> //ioctl structures and constants
 #include "e100_impl.hpp"
 #include "e100_regs.hpp"
 #include <uhd/utils/msg.hpp>
@@ -29,31 +30,15 @@
 #include <boost/format.hpp>
 #include <boost/thread/thread.hpp>
 #include <boost/thread/barrier.hpp>
+#include <poll.h> //poll
+#include <fcntl.h> //open, close
 #include <sstream>
+#include <fstream>
 
 using namespace uhd;
 using namespace uhd::usrp;
 using namespace uhd::transport;
 
-/***********************************************************************
- * Helpers
- **********************************************************************/
-#if 1
-#  define debug_print_buff(...)
-#else
-static void debug_print_buff(const std::string &what, managed_recv_buffer::sptr buff){
-    std::ostringstream ss;
-    ss << boost::format(
-        "This is a %s packet, %u bytes.\n"
-    ) % what % buff->size();
-    for (size_t i = 0; i < 9; i++){
-        ss << boost::format("    buff[%u] = 0x%08x\n") % i % buff->cast<const boost::uint32_t *>()[i];
-    }
-    ss << std::endl << std::endl;
-    UHD_MSG(status) << ss.str();
-}
-#endif
-
 /***********************************************************************
  * io impl details (internal to this file)
  * - pirate crew of 1
@@ -63,34 +48,52 @@ static void debug_print_buff(const std::string &what, managed_recv_buffer::sptr
  **********************************************************************/
 struct e100_impl::io_impl{
     io_impl(zero_copy_if::sptr &xport):
-        data_xport(xport),
+        data_transport(xport),
         async_msg_fifo(100/*messages deep*/)
     {
         for (size_t i = 0; i < E100_NUM_RX_DSPS; i++){
-            typedef bounded_buffer<managed_recv_buffer::sptr> booty_type;
-            recv_pirate_booty.push_back(new booty_type(data_xport->get_num_recv_frames()));
+            typedef bounded_buffer<managed_recv_buffer::sptr> buffs_queue_type;
+            _buffs_queue.push_back(new buffs_queue_type(data_transport->get_num_recv_frames()));
         }
     }
 
     ~io_impl(void){
         recv_pirate_crew.interrupt_all();
         recv_pirate_crew.join_all();
-        for (size_t i = 0; i < recv_pirate_booty.size(); i++){
-            delete recv_pirate_booty[i];
+        for (size_t i = 0; i < _buffs_queue.size(); i++){
+            delete _buffs_queue[i];
         }
     }
 
-    managed_recv_buffer::sptr get_recv_buff(const size_t index, double timeout){
-        boost::this_thread::disable_interruption di; //disable because the wait can throw
-        managed_recv_buffer::sptr buff;
-        recv_pirate_booty[index]->pop_with_timed_wait(buff, timeout);
-        return buff; //ASSUME buff == NULL when pop times-out
+    std::vector<bounded_buffer<managed_recv_buffer::sptr> *> _buffs_queue;
+
+    //gets buffer, determines if its the requested index,
+    //and either queues the buffer or returns the buffer
+    managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout){
+        while (true){
+            managed_recv_buffer::sptr buff;
+
+            //attempt to pop a buffer from the queue
+            if (_buffs_queue[index]->pop_with_haste(buff)) return buff;
+
+            //otherwise, call into the transport
+            buff = data_transport->get_recv_buff(timeout);
+            if (buff.get() == NULL) return buff; //timeout
+
+            //check the stream id to know which channel
+            const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
+            const size_t rx_index = uhd::wtohx(vrt_hdr[1]) - E100_DSP_SID_BASE;
+            if (rx_index == index) return buff; //got expected message
+
+            //otherwise queue and try again
+            if (rx_index < E100_NUM_RX_DSPS) _buffs_queue[rx_index]->push_with_pop_on_full(buff);
+            else UHD_MSG(error) << "Got a data packet with known SID " << uhd::wtohx(vrt_hdr[1]) << std::endl;
+        }
     }
 
     //The data transport is listed first so that it is deconstructed last,
     //which is after the states and booty which may hold managed buffers.
-    //This comment is invalid because its now a reference and not stored here.
-    zero_copy_if::sptr &data_xport;
+    zero_copy_if::sptr data_transport;
 
     //state management for the vrt packet handler code
     sph::recv_packet_handler recv_handler;
@@ -98,72 +101,35 @@ struct e100_impl::io_impl{
     bool continuous_streaming;
 
     //a pirate's life is the life for me!
-    void recv_pirate_loop(boost::barrier &, e100_clock_ctrl::sptr);
-    std::vector<bounded_buffer<managed_recv_buffer::sptr> *> recv_pirate_booty;
-    bounded_buffer<async_metadata_t> async_msg_fifo;
-    boost::thread_group recv_pirate_crew;
-};
+    void recv_pirate_loop(
+        boost::barrier &spawn_barrier,
+        const boost::function<void(void)> &handle,
+        e100_iface::sptr //keep a sptr to iface which shares gpio145
+    ){
+        spawn_barrier.wait();
+        UHD_LOG << "pirate loop spawned" << std::endl;
 
-/***********************************************************************
- * Receive Pirate Loop
- * - while raiding, loot for recv buffers
- * - put booty into the alignment buffer
- **********************************************************************/
-void e100_impl::io_impl::recv_pirate_loop(
-    boost::barrier &spawn_barrier, e100_clock_ctrl::sptr clock_ctrl
-){
-    spawn_barrier.wait();
-    set_thread_priority_safe();
-
-    while (not boost::this_thread::interruption_requested()){
-        managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff();
-        if (buff.get() == NULL) continue; //ignore timeout buffers
-
-        //handle an rx data packet or inline message
-        const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
-        const size_t rx_index = uhd::wtohx(vrt_hdr[1]) - E100_DSP_SID_BASE;
-        if (rx_index < E100_NUM_RX_DSPS){
-            debug_print_buff("data", buff);
-            recv_pirate_booty[rx_index]->push_with_wait(buff);
-            continue;
-        }
+        //open the GPIO and set it up for an IRQ
+        std::ofstream edge_file("/sys/class/gpio/gpio145/edge");
+        edge_file << "rising" << std::endl << std::flush;
+        edge_file.close();
+        int fd = ::open("/sys/class/gpio/gpio145/value", O_RDONLY);
 
-        //otherwise, unpack the vrt header and process below...
-        vrt::if_packet_info_t if_packet_info;
-        if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
-        try{vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info);}
-        catch(const std::exception &e){
-            UHD_MSG(error) << "Error unpacking vrt header:\n" << e.what() << std::endl;
-            continue;
+        while (not boost::this_thread::interruption_requested()){
+            pollfd pfd;
+            pfd.fd = fd;
+            pfd.events = POLLPRI | POLLERR;
+            ssize_t ret = ::poll(&pfd, 1, 100/*ms*/);
+            if (ret > 0) handle();
         }
 
-        //handle a tx async report message
-        if (if_packet_info.sid == E100_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
-            debug_print_buff("async", buff);
-
-            //fill in the async metadata
-            async_metadata_t metadata;
-            metadata.channel = 0;
-            metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
-            metadata.time_spec = time_spec_t(
-                time_t(if_packet_info.tsi), long(if_packet_info.tsf), clock_ctrl->get_fpga_clock_rate()
-            );
-            metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
-            async_msg_fifo.push_with_pop_on_full(metadata);
-            if (metadata.event_code &
-                ( async_metadata_t::EVENT_CODE_UNDERFLOW 
-                | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
-            ) UHD_MSG(fastpath) << "U";
-            else if (metadata.event_code &
-                ( async_metadata_t::EVENT_CODE_SEQ_ERROR
-                | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
-            ) UHD_MSG(fastpath) << "S";
-            continue;
-        }
+        ::close(fd);
 
-        debug_print_buff("unknown", buff);
+        UHD_LOG << "pirate loop done" << std::endl;
     }
-}
+    bounded_buffer<async_metadata_t> async_msg_fifo;
+    boost::thread_group recv_pirate_crew;
+};
 
 /***********************************************************************
  * Helper Functions
@@ -171,23 +137,87 @@ void e100_impl::io_impl::recv_pirate_loop(
 void e100_impl::io_init(void){
 
     //setup before the registers (transport called to calculate max spp)
-    _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_xport));
+    _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
 
     //clear state machines
     _iface->poke32(E100_REG_CLEAR_RX, 0);
     _iface->poke32(E100_REG_CLEAR_TX, 0);
 
+    //prepare the async msg buffer for incoming messages
+    _iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear
+    while ((_iface->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle
+    _iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start
+
     //spawn a pirate, yarrr!
     boost::barrier spawn_barrier(2);
+    boost::function<void(void)> handle_irq_cb = boost::bind(&e100_impl::handle_irq, this);
     _io_impl->recv_pirate_crew.create_thread(boost::bind(
         &e100_impl::io_impl::recv_pirate_loop, _io_impl.get(),
-        boost::ref(spawn_barrier), _clock_ctrl
+        boost::ref(spawn_barrier), handle_irq_cb, _iface
     ));
     spawn_barrier.wait();
     //update mapping here since it didnt b4 when io init not called first
     update_xport_channel_mapping();
 }
 
+void e100_impl::handle_irq(void){
+    //check the status of the async msg buffer
+    const boost::uint32_t status = _iface->peek32(E100_REG_RB_ERR_STATUS);
+    if ((status & 0x3) == 0) return; //not done or error
+    //std::cout << boost::format("status: 0x%x") % status << std::endl;
+
+    //load the data struct and call the ioctl
+    usrp_e_ctl32 data;
+    data.offset = E100_REG_ERR_BUFF;
+    data.count = status >> 16;
+    //FIXME ioctl reads words32 incorrectly _iface->ioctl(USRP_E_READ_CTL32, &data);
+    for (size_t i = 0; i < data.count; i++){
+        data.buf[i] = _iface->peek32(E100_REG_ERR_BUFF + i*sizeof(boost::uint32_t));
+        //std::cout << boost::format("    buff[%u] = 0x%08x\n") % i % data.buf[i];
+    }
+
+    //unpack the vrt header and process below...
+    vrt::if_packet_info_t if_packet_info;
+    if_packet_info.num_packet_words32 = data.count;
+    try{vrt::if_hdr_unpack_le(data.buf, if_packet_info);}
+    catch(const std::exception &e){
+        UHD_MSG(error) << "Error unpacking vrt header:\n" << e.what() << std::endl;
+        goto prepare;
+    }
+
+    //handle a tx async report message
+    if (if_packet_info.sid == E100_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+
+        //fill in the async metadata
+        async_metadata_t metadata;
+        metadata.channel = 0;
+        metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
+        metadata.time_spec = time_spec_t(
+            time_t(if_packet_info.tsi), long(if_packet_info.tsf), _clock_ctrl->get_fpga_clock_rate()
+        );
+        metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(data.buf, if_packet_info));
+
+        //push the message onto the queue
+        _io_impl->async_msg_fifo.push_with_pop_on_full(metadata);
+
+        //print some fastpath messages
+        if (metadata.event_code &
+            ( async_metadata_t::EVENT_CODE_UNDERFLOW
+            | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
+        ) UHD_MSG(fastpath) << "U";
+        else if (metadata.event_code &
+            ( async_metadata_t::EVENT_CODE_SEQ_ERROR
+            | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
+        ) UHD_MSG(fastpath) << "S";
+    }
+
+    //prepare for the next round
+    prepare:
+    _iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear
+    while ((_iface->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle
+    _iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start
+}
+
 void e100_impl::update_xport_channel_mapping(void){
     if (_io_impl.get() == NULL) return; //not inited yet
 
@@ -217,7 +247,7 @@ void e100_impl::update_xport_channel_mapping(void){
     _io_impl->send_handler.set_samp_rate(_tx_dsp_proxies[_tx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as<double>());
     for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){
         _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind(
-            &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_xport, _1
+            &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_transport, _1
         ));
     }
     _io_impl->send_handler.set_converter(_send_otw_type);
-- 
cgit v1.2.3