aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/examples/benchmark_rx_rate.cpp2
-rw-r--r--host/include/uhd/device.hpp11
-rw-r--r--host/include/uhd/types/metadata.hpp48
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp35
-rw-r--r--host/lib/types.cpp12
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp41
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp1
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp9
9 files changed, 123 insertions, 43 deletions
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
index 752facb0d..8fae813cf 100644
--- a/host/examples/benchmark_rx_rate.cpp
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -66,7 +66,7 @@ static inline void test_device(
//handle the error codes
switch(md.error_code){
case uhd::rx_metadata_t::ERROR_CODE_NONE:
- case uhd::rx_metadata_t::ERROR_CODE_OVERRUN:
+ case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
break;
default:
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
index ee297ec8a..78bb83c66 100644
--- a/host/include/uhd/device.hpp
+++ b/host/include/uhd/device.hpp
@@ -219,6 +219,17 @@ public:
*/
virtual size_t get_max_recv_samps_per_packet(void) const = 0;
+ /*!
+ * Receive and asynchronous message from the device.
+ * \param async_metadata the metadata to be filled in
+ * \param timeout_ms the timeout in milliseconds to wait for a message
+ * \return true when the async_metadata is valid, false for timeout
+ */
+ virtual bool recv_async_msg(
+ async_metadata_t &async_metadata,
+ size_t timeout_ms = default_recv_timeout_ms
+ ) = 0;
+
};
} //namespace uhd
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 039196250..65952941c 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -26,7 +26,7 @@ namespace uhd{
/*!
* RX metadata structure for describing sent IF data.
- * Includes stream ID, time specification, and fragmentation flags.
+ * Includes time specification, fragmentation flags, burst flags, and error codes.
* The receive routines will convert IF data headers into metadata.
*/
struct UHD_API rx_metadata_t{
@@ -62,7 +62,7 @@ namespace uhd{
* - timeout: no packet received, underlying code timed-out
* - late command: a stream command was issued in the past
* - broken chain: expected another stream command
- * - overrun: an internal receive buffer has overrun
+ * - overflow: an internal receive buffer has filled
* - bad packet: the buffer was unrecognizable as a vrt packet
*
* Note: When an overrun occurs in continuous streaming mode,
@@ -74,27 +74,21 @@ namespace uhd{
* - none
* - late command
* - broken chain
- * - overrun
+ * - overflow
*/
enum error_code_t {
ERROR_CODE_NONE = 0x0,
ERROR_CODE_TIMEOUT = 0x1,
ERROR_CODE_LATE_COMMAND = 0x2,
ERROR_CODE_BROKEN_CHAIN = 0x4,
- ERROR_CODE_OVERRUN = 0x8,
+ ERROR_CODE_OVERFLOW = 0x8,
ERROR_CODE_BAD_PACKET = 0xf
} error_code;
-
- /*!
- * The default constructor:
- * Sets the fields to default values (flags set to false).
- */
- rx_metadata_t(void);
};
/*!
* TX metadata structure for describing received IF data.
- * Includes stream ID, time specification, and burst flags.
+ * Includes time specification, and start and stop burst flags.
* The send routines will convert the metadata to IF data headers.
*/
struct UHD_API tx_metadata_t{
@@ -121,6 +115,38 @@ namespace uhd{
tx_metadata_t(void);
};
+ /*!
+ * Async metadata structure for describing transmit related events.
+ */
+ struct UHD_API async_metadata_t{
+ //! The channel number in a mimo configuration
+ size_t channel;
+
+ /*!
+ * Time specification: when the async event occurred.
+ */
+ bool has_time_spec;
+ time_spec_t time_spec;
+
+ /*!
+ * Event codes:
+ * - success: a packet was successfully transmitted
+ * - underflow: an internal send buffer has emptied
+ * - sequence error: packet loss between host and device
+ * - time error: packet had time that was late (or too early)
+ * - underflow in packet: underflow occurred inside a packet
+ * - sequence error in burst: packet loss within a burst
+ */
+ enum event_code_t {
+ EVENT_CODE_SUCCESS = 0x1,
+ EVENT_CODE_UNDERFLOW = 0x2,
+ EVENT_CODE_SEQ_ERROR = 0x4,
+ EVENT_CODE_TIME_ERROR = 0x8,
+ EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10,
+ EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20
+ } event_code;
+ };
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_METADATA_HPP */
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
index cf9d649dd..7e0588f03 100644
--- a/host/lib/transport/vrt_packet_handler.hpp
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -35,15 +35,25 @@
namespace vrt_packet_handler{
+template <typename T> UHD_INLINE T get_context_code(
+ const boost::uint32_t *vrt_hdr,
+ const uhd::transport::vrt::if_packet_info_t &if_packet_info
+){
+ //extract the context word (we dont know the endianness so mirror the bytes)
+ boost::uint32_t word0 = vrt_hdr[if_packet_info.num_header_words32] |
+ uhd::byteswap(vrt_hdr[if_packet_info.num_header_words32]);
+ return T(word0 & 0xff);
+}
+
/***********************************************************************
* vrt packet handler for recv
**********************************************************************/
typedef std::vector<uhd::transport::managed_recv_buffer::sptr> managed_recv_buffs_t;
typedef boost::function<bool(managed_recv_buffs_t &)> get_recv_buffs_t;
- typedef boost::function<void(size_t /*which channel*/)> handle_overrun_t;
+ typedef boost::function<void(size_t /*which channel*/)> handle_overflow_t;
typedef boost::function<void(const boost::uint32_t *, uhd::transport::vrt::if_packet_info_t &)> vrt_unpacker_t;
- static inline void handle_overrun_nop(size_t){}
+ static inline void handle_overflow_nop(size_t){}
struct recv_state{
//width of the receiver in channels
@@ -75,7 +85,7 @@ namespace vrt_packet_handler{
uhd::rx_metadata_t &metadata,
double tick_rate,
const vrt_unpacker_t &vrt_unpacker,
- const handle_overrun_t &handle_overrun,
+ const handle_overflow_t &handle_overflow,
size_t vrt_header_offset_words32
){
//vrt unpack each managed buffer
@@ -92,22 +102,19 @@ namespace vrt_packet_handler{
const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast<const boost::uint32_t *>() + vrt_header_offset_words32;
if_packet_info.num_packet_words32 = num_packet_words32 - vrt_header_offset_words32;
vrt_unpacker(vrt_hdr, if_packet_info);
- const boost::uint32_t *vrt_data = vrt_hdr + if_packet_info.num_header_words32;
//handle the non-data packet case and parse its contents
if (if_packet_info.packet_type != uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA){
- //extract the context word (we dont know the endianness so mirror the bytes)
- boost::uint32_t word0 = vrt_data[0] | uhd::byteswap(vrt_data[0]);
- if (word0 & uhd::rx_metadata_t::ERROR_CODE_OVERRUN) handle_overrun(i);
- metadata.error_code = uhd::rx_metadata_t::error_code_t(word0 & 0xf);
+ metadata.error_code = get_context_code<uhd::rx_metadata_t::error_code_t>(vrt_hdr, if_packet_info);
+ if (metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) handle_overflow(i);
//break to exit loop and store metadata below
state.size_of_copy_buffs = 0; break;
}
//setup the buffer to point to the data
- state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_data);
+ state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_hdr + if_packet_info.num_header_words32);
//store the minimum payload length into the copy buffer length
size_t num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t);
@@ -142,7 +149,7 @@ namespace vrt_packet_handler{
double tick_rate,
const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
- const handle_overrun_t &handle_overrun,
+ const handle_overflow_t &handle_overflow,
size_t vrt_header_offset_words32
){
metadata.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE;
@@ -157,7 +164,7 @@ namespace vrt_packet_handler{
try{
_recv1_helper(
state, metadata, tick_rate,
- vrt_unpacker, handle_overrun,
+ vrt_unpacker, handle_overflow,
vrt_header_offset_words32
);
}catch(const std::exception &e){
@@ -216,7 +223,7 @@ namespace vrt_packet_handler{
double tick_rate,
const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
- const handle_overrun_t &handle_overrun = &handle_overrun_nop,
+ const handle_overflow_t &handle_overflow = &handle_overflow_nop,
size_t vrt_header_offset_words32 = 0
){
switch(recv_mode){
@@ -233,7 +240,7 @@ namespace vrt_packet_handler{
tick_rate,
vrt_unpacker,
get_recv_buffs,
- handle_overrun,
+ handle_overflow,
vrt_header_offset_words32
);
}
@@ -253,7 +260,7 @@ namespace vrt_packet_handler{
tick_rate,
vrt_unpacker,
get_recv_buffs,
- handle_overrun,
+ handle_overflow,
vrt_header_offset_words32
);
if (num_samps == 0) break; //had a recv timeout or error, break loop
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index fdc435fef..1cfe84832 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -98,18 +98,6 @@ stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):
/***********************************************************************
* metadata
**********************************************************************/
-rx_metadata_t::rx_metadata_t(void):
- has_time_spec(false),
- time_spec(time_spec_t()),
- more_fragments(false),
- fragment_offset(0),
- start_of_burst(false),
- end_of_burst(false),
- error_code(ERROR_CODE_NONE)
-{
- /* NOP */
-}
-
tx_metadata_t::tx_metadata_t(void):
has_time_spec(false),
time_spec(time_spec_t()),
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 7e7ce40a2..aa6d15783 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -32,6 +32,8 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
+static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET;
+
/***********************************************************************
* io impl details (internal to this file)
* - pirate crew
@@ -44,7 +46,8 @@ struct usrp2_impl::io_impl{
io_impl(size_t num_frames, size_t width):
packet_handler_recv_state(width),
- recv_pirate_booty(alignment_buffer_type::make(num_frames, width))
+ recv_pirate_booty(alignment_buffer_type::make(num_frames, width)),
+ async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))
{
/* NOP */
}
@@ -69,6 +72,7 @@ struct usrp2_impl::io_impl{
boost::thread_group recv_pirate_crew;
bool recv_pirate_crew_raiding;
alignment_buffer_type::sptr recv_pirate_booty;
+ bounded_buffer<async_metadata_t>::sptr async_msg_fifo;
};
/***********************************************************************
@@ -93,12 +97,31 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//extract the vrt header packet info
vrt::if_packet_info_t if_packet_info;
if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
- vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), if_packet_info);
+ const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
+ vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
+
+ //handle a tx async report message
+ if (if_packet_info.sid == 1 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 = index;
+ 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), size_t(if_packet_info.tsf), mboard->get_master_clock_freq()
+ );
+ metadata.event_code = vrt_packet_handler::get_context_code<async_metadata_t::event_code_t>(vrt_hdr, if_packet_info);
+
+ //print the famous U, and push the metadata into the message queue
+ if (metadata.event_code & underflow_flags) std::cerr << "U";
+ async_msg_fifo->push_with_pop_on_full(metadata);
+ continue;
+ }
//handle the packet count / sequence number
if (if_packet_info.packet_count != next_packet_seq){
//std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16;
- std::cerr << "O"; //report overrun (drops in the kernel)
+ std::cerr << "O"; //report overflow (drops in the kernel)
}
next_packet_seq = (if_packet_info.packet_count+1)%16;
@@ -150,6 +173,18 @@ void usrp2_impl::io_init(void){
}
/***********************************************************************
+ * Async Data
+ **********************************************************************/
+bool usrp2_impl::recv_async_msg(
+ async_metadata_t &async_metadata, size_t timeout_ms
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _io_impl->async_msg_fifo->pop_with_timed_wait(
+ async_metadata, boost::posix_time::milliseconds(timeout_ms)
+ );
+}
+
+/***********************************************************************
* Send Data
**********************************************************************/
bool get_send_buffs(
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 7518d3114..b3b03c11c 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -67,7 +67,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_allowed_decim_and_interp_rates.push_back(i);
}
- //setup the vrt rx registers
+ //init the rx control registers
_iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet());
_iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1);
_iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset
@@ -81,6 +81,11 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0);
_iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq()));
+ //init the tx control registers
+ _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0); //1 channel
+ _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset
+ _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, 1); //sid 1 (different from rx)
+
//init the ddc
init_ddc_config();
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index cae1b21d6..2eaf12350 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -235,6 +235,7 @@ public:
uhd::rx_metadata_t &, const uhd::io_type_t &,
uhd::device::recv_mode_t, size_t
);
+ bool recv_async_msg(uhd::async_metadata_t &, size_t);
private:
//device properties interface
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 1a5864c85..aa8bd860f 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -226,7 +226,7 @@
#define U2_REG_ATR_FULL_RXSIDE U2_REG_ATR_BASE + 14
///////////////////////////////////////////////////
-// VITA RX CTRL regs
+// RX CTRL regs
///////////////////////////////////////////////////
// The following 3 are logically a single command register.
// They are clocked into the underlying fifo when time_ticks is written.
@@ -241,4 +241,11 @@
#define U2_REG_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7)
#define U2_REG_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources
+///////////////////////////////////////////////////
+// TX CTRL regs
+///////////////////////////////////////////////////
+#define U2_REG_TX_CTRL_NUM_CHAN _SR_ADDR(SR_TX_CTRL + 0)
+#define U2_REG_TX_CTRL_CLEAR_STATE _SR_ADDR(SR_TX_CTRL + 1)
+#define U2_REG_TX_CTRL_REPORT_SID _SR_ADDR(SR_TX_CTRL + 2)
+
#endif /* INCLUDED_USRP2_REGS_HPP */