aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp17
-rw-r--r--host/lib/rfnoc/radio_control_impl.cpp116
2 files changed, 119 insertions, 14 deletions
diff --git a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
index c5e990343..9c3288164 100644
--- a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
+++ b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
@@ -233,6 +233,21 @@ public:
static const uint32_t PERIPH_BASE = 0x80000;
static const uint32_t PERIPH_REG_OFFSET = 8;
+
+ static const uint32_t SWREG_TX_ERR = 0x0000;
+ static const uint32_t SWREG_RX_ERR = 0x1000;
+ static const uint32_t SWREG_CHAN_OFFSET = 64;
+ };
+
+ struct err_codes
+ {
+ static const uint32_t ERR_RX_LATE_CMD =
+ 1; // Late command (arrived after indicated time)
+ static const uint32_t ERR_RX_OVERRUN = 2; // FIFO overflow
+ static const uint32_t ERR_TX_UNDERRUN =
+ 1; // Data underflow (data not available when needed)
+ static const uint32_t ERR_TX_LATE_DATA =
+ 2; // Late data (arrived after indicated time)
};
//! Tree path to the dboard-specific properties
@@ -284,6 +299,8 @@ private:
std::unordered_map<size_t, double> _rx_gain;
std::unordered_map<size_t, double> _tx_bandwidth;
std::unordered_map<size_t, double> _rx_bandwidth;
+
+ std::vector<uhd::stream_cmd_t> _last_stream_cmd;
};
}} // namespace uhd::rfnoc
diff --git a/host/lib/rfnoc/radio_control_impl.cpp b/host/lib/rfnoc/radio_control_impl.cpp
index d58016b4d..205185247 100644
--- a/host/lib/rfnoc/radio_control_impl.cpp
+++ b/host/lib/rfnoc/radio_control_impl.cpp
@@ -72,6 +72,8 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
, _radio_width(regs().peek32(regmap::REG_RADIO_WIDTH))
, _samp_width(_radio_width >> 16)
, _spc(_radio_width & 0xFFFF)
+ , _last_stream_cmd(
+ get_num_output_ports(), uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS)
{
uhd::assert_fpga_compat(MAJOR_COMPAT,
MINOR_COMPAT,
@@ -85,10 +87,6 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
<< ", num_outputs=" << get_num_output_ports());
set_prop_forwarding_policy(forwarding_policy_t::DROP);
set_action_forwarding_policy(forwarding_policy_t::DROP);
- regs().register_async_msg_handler(
- [this](uint32_t addr, const std::vector<uint32_t>& data) {
- this->async_message_handler(addr, data);
- });
register_action_handler(ACTION_KEY_STREAM_CMD,
[this](const res_source_info& src, action_info::sptr action) {
stream_cmd_action_info::sptr stream_cmd_action =
@@ -173,7 +171,43 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
{&_type_out.back()},
[& type_out = _type_out.back()]() { type_out.set(IO_TYPE_SC16); });
}
-}
+ // Enable async messages coming from the radio
+ const uint32_t xbar_port = 1; // FIXME: Find a better way to figure this out
+ RFNOC_LOG_TRACE("Sending async messages to EPID "
+ << regs().get_src_epid() << ", remote port " << regs().get_port_num()
+ << ", xbar port " << xbar_port);
+ for (size_t tx_chan = 0; tx_chan < get_num_output_ports(); tx_chan++) {
+ // Set the EPID and port of our regs() object (all async messages go to
+ // the same location)
+ regs().poke32(
+ get_addr(regmap::REG_TX_ERR_REM_EPID, tx_chan), regs().get_src_epid());
+ regs().poke32(
+ get_addr(regmap::REG_TX_ERR_REM_PORT, tx_chan), regs().get_port_num());
+ // Set the crossbar port for the async packet routing
+ regs().poke32(get_addr(regmap::REG_TX_ERR_PORT, tx_chan), xbar_port);
+ // Set the async message address
+ regs().poke32(get_addr(regmap::REG_TX_ERR_ADDR, tx_chan),
+ regmap::SWREG_TX_ERR + regmap::SWREG_CHAN_OFFSET * tx_chan);
+ }
+ for (size_t rx_chan = 0; rx_chan < get_num_input_ports(); rx_chan++) {
+ // Set the EPID and port of our regs() object (all async messages go to
+ // the same location)
+ regs().poke32(
+ get_addr(regmap::REG_RX_ERR_REM_EPID, rx_chan), regs().get_src_epid());
+ regs().poke32(
+ get_addr(regmap::REG_RX_ERR_REM_PORT, rx_chan), regs().get_port_num());
+ // Set the crossbar port for the async packet routing
+ regs().poke32(get_addr(regmap::REG_RX_ERR_PORT, rx_chan), xbar_port);
+ // Set the async message address
+ regs().poke32(get_addr(regmap::REG_RX_ERR_ADDR, rx_chan),
+ regmap::SWREG_RX_ERR + regmap::SWREG_CHAN_OFFSET * rx_chan);
+ }
+ // Now register a function to receive the async messages
+ regs().register_async_msg_handler(
+ [this](uint32_t addr, const std::vector<uint32_t>& data) {
+ this->async_message_handler(addr, data);
+ });
+} /* ctor */
/******************************************************************************
* Rate-Related API Calls
@@ -375,11 +409,6 @@ double radio_control_impl::set_rx_bandwidth(const double bandwidth, const size_t
return _rx_bandwidth[chan] = bandwidth;
}
-//void radio_control_impl::set_time_sync(const uhd::time_spec_t& time)
-//{
- //// FIXME
-//}
-
std::string radio_control_impl::get_tx_antenna(const size_t chan) const
{
std::lock_guard<std::mutex> l(_cache_mutex);
@@ -709,8 +738,7 @@ void radio_control_impl::issue_stream_cmd(
// std::lock_guard<std::mutex> lock(_mutex);
RFNOC_LOG_TRACE("radio_control_impl::issue_stream_cmd(chan="
<< chan << ", mode=" << char(stream_cmd.stream_mode) << ")");
- //_continuous_streaming[chan] =
- //(stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ _last_stream_cmd[chan] = stream_cmd;
// calculate the command word
const std::unordered_map<stream_cmd_t::stream_mode_t, uint32_t, std::hash<size_t>>
@@ -765,7 +793,67 @@ void radio_control_impl::issue_stream_cmd(
void radio_control_impl::async_message_handler(
uint32_t addr, const std::vector<uint32_t>& data)
{
+ if (data.empty()) {
+ RFNOC_LOG_WARNING(
+ str(boost::format("Received async message with invalid length %d!")
+ % data.size()));
+ return;
+ }
+ if (data.size() > 1) {
+ RFNOC_LOG_WARNING(
+ str(boost::format("Received async message with extra data, length %d!")
+ % data.size()));
+ }
+ // Reminder: The address is calculated as:
+ // BASE + 64 * chan + addr_offset
+ // BASE == 0x0000 for RX, 0x1000 for TX
+ const uint32_t addr_base = (addr >= regmap::SWREG_RX_ERR) ? regmap::SWREG_RX_ERR
+ : regmap::SWREG_TX_ERR;
+ const uint32_t chan = (addr - addr_base) / regmap::SWREG_CHAN_OFFSET;
+ const uint32_t addr_offset = addr % regmap::SWREG_CHAN_OFFSET;
+ const uint32_t code = data[0];
RFNOC_LOG_TRACE(
- str(boost::format("Received async message to addr 0x%08X, data length %d words.")
- % addr % data.size()));
+ str(boost::format("Received async message to addr 0x%08X, data length %d words, "
+ "%s channel %d, addr_offset %d")
+ % addr % data.size() % (addr_base == regmap::SWREG_TX_ERR ? "TX" : "RX")
+ % chan % addr_offset));
+ switch (addr_base + addr_offset) {
+ case regmap::SWREG_TX_ERR: {
+ switch (code) {
+ case err_codes::ERR_TX_UNDERRUN:
+ UHD_LOG_FASTPATH("U");
+ break;
+ case err_codes::ERR_TX_LATE_DATA:
+ UHD_LOG_FASTPATH("L");
+ break;
+ }
+ break;
+ }
+ case regmap::SWREG_RX_ERR: {
+ switch (code) {
+ case err_codes::ERR_RX_OVERRUN: {
+ UHD_LOG_FASTPATH("O");
+ auto rx_event_action = rx_event_action_info::make();
+ rx_event_action->error_code = uhd::rx_metadata_t::ERROR_CODE_OVERFLOW;
+ RFNOC_LOG_TRACE("Posting overrun event action message.");
+ post_action(res_source_info{res_source_info::OUTPUT_EDGE, chan},
+ rx_event_action);
+ break;
+ }
+ case err_codes::ERR_RX_LATE_CMD:
+ UHD_LOG_FASTPATH("L");
+ break;
+ }
+ break;
+ }
+ case regmap::SWREG_TX_ERR + 8:
+ case regmap::SWREG_TX_ERR + 12:
+ case regmap::SWREG_RX_ERR + 8:
+ case regmap::SWREG_RX_ERR + 12:
+ RFNOC_LOG_TRACE("Dropping timestamp info for async message.");
+ break;
+ default:
+ RFNOC_LOG_WARNING(str(
+ boost::format("Received async message to invalid addr 0x%08X!") % addr));
+ }
}