diff options
| author | Josh Blum <josh@joshknows.com> | 2011-06-17 06:31:36 +0100 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2011-06-17 06:31:36 +0100 | 
| commit | c7f848ab0da69e54c88ad36bde94b9fe665f386e (patch) | |
| tree | 7ec77f5194be8b2dcbe6a649bcad5f8c3f23a8f2 | |
| parent | 5bbc3c6282bb73db72d3dd1738aa906a89a6f772 (diff) | |
| download | uhd-c7f848ab0da69e54c88ad36bde94b9fe665f386e.tar.gz uhd-c7f848ab0da69e54c88ad36bde94b9fe665f386e.tar.bz2 uhd-c7f848ab0da69e54c88ad36bde94b9fe665f386e.zip | |
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.
| -rw-r--r-- | host/examples/benchmark_rate.cpp | 36 | ||||
| -rw-r--r-- | host/lib/usrp/e100/e100_iface.cpp | 129 | ||||
| -rw-r--r-- | host/lib/usrp/e100/e100_impl.cpp | 7 | ||||
| -rw-r--r-- | host/lib/usrp/e100/e100_impl.hpp | 3 | ||||
| -rw-r--r-- | host/lib/usrp/e100/e100_regs.hpp | 62 | ||||
| -rw-r--r-- | host/lib/usrp/e100/io_impl.cpp | 218 | 
6 files changed, 293 insertions, 162 deletions
| diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp index 6927b512b..688cd797a 100644 --- a/host/examples/benchmark_rate.cpp +++ b/host/examples/benchmark_rate.cpp @@ -27,11 +27,15 @@  namespace po = boost::program_options; +/*********************************************************************** + * Test result variables + **********************************************************************/  unsigned long long num_overflows = 0;  unsigned long long num_underflows = 0;  unsigned long long num_rx_samps = 0;  unsigned long long num_tx_samps = 0;  unsigned long long num_dropped_samps = 0; +unsigned long long num_seq_errors = 0;  /***********************************************************************   * Benchmark RX Rate @@ -77,11 +81,11 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp){          default:              std::cerr << "Error code: " << md.error_code << std::endl; -            std::cerr << "Unexpected error on recv, exit test..." << std::endl; -            goto loop_done; +            std::cerr << "Unexpected error on recv, continuing..." << std::endl; +            break;          } -    } loop_done: +    }      usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);  } @@ -122,11 +126,9 @@ void benchmark_tx_rate_async_helper(uhd::usrp::multi_usrp::sptr usrp){      //setup variables and allocate buffer      uhd::async_metadata_t async_md; -    while (true){ +    while (not boost::this_thread::interruption_requested()){ -        if (not usrp->get_device()->recv_async_msg(async_md)){ -            if (boost::this_thread::interruption_requested()) return; -        } +        if (not usrp->get_device()->recv_async_msg(async_md)) continue;          //handle the error codes          switch(async_md.event_code){ @@ -138,10 +140,15 @@ void benchmark_tx_rate_async_helper(uhd::usrp::multi_usrp::sptr usrp){              num_underflows++;              break; +        case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR: +        case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST: +            num_seq_errors++; +            break; +          default:              std::cerr << "Event code: " << async_md.event_code << std::endl; -            std::cerr << "Unexpected event on async recv, exit test..." << std::endl; -            return; +            std::cerr << "Unexpected event on async recv, continuing..." << std::endl; +            break;          }      }  } @@ -183,16 +190,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //create a usrp device      std::cout << std::endl;      uhd::device_addrs_t device_addrs = uhd::device::find(args); -    if (device_addrs.empty()){ -        std::cerr << "Could not find any devices for: " << args << std::endl; -        return ~0; -    } -    if (device_addrs.at(0).get("type", "") == "usrp1"){ +    if (not device_addrs.empty() and device_addrs.at(0).get("type", "") == "usrp1"){          std::cerr << "*** Warning! ***" << std::endl;          std::cerr << "Benchmark results will be inaccurate on USRP1 due to insufficient features.\n" << std::endl;      }      std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; -    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(device_addrs.at(0)); +    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);      std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;      boost::thread_group thread_group; @@ -226,8 +229,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          "  Num dropped samples:     %u\n"          "  Num overflows detected:  %u\n"          "  Num transmitted samples: %u\n" +        "  Num sequence errors:     %u\n"          "  Num underflows detected: %u\n" -    ) % num_rx_samps % num_dropped_samps % num_overflows % num_tx_samps % num_underflows << std::endl; +    ) % num_rx_samps % num_dropped_samps % num_overflows % num_tx_samps % num_seq_errors % num_underflows << std::endl;      //finished      std::cout << std::endl << "Done!" << std::endl << std::endl; 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,32 +30,16 @@  #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   * - bounded buffer @@ -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); | 
