summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2011-06-17 06:31:36 +0100
committerJosh Blum <josh@joshknows.com>2011-06-17 06:31:36 +0100
commitc7f848ab0da69e54c88ad36bde94b9fe665f386e (patch)
tree7ec77f5194be8b2dcbe6a649bcad5f8c3f23a8f2
parent5bbc3c6282bb73db72d3dd1738aa906a89a6f772 (diff)
downloaduhd-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.cpp36
-rw-r--r--host/lib/usrp/e100/e100_iface.cpp129
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp7
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp3
-rw-r--r--host/lib/usrp/e100/e100_regs.hpp62
-rw-r--r--host/lib/usrp/e100/io_impl.cpp218
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);