aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/register_iface.hpp40
-rw-r--r--host/lib/rfnoc/ctrlport_endpoint.cpp33
-rw-r--r--host/lib/rfnoc/register_iface_holder.cpp5
-rw-r--r--host/tests/rfnoc_mock_reg_iface.hpp5
4 files changed, 76 insertions, 7 deletions
diff --git a/host/include/uhd/rfnoc/register_iface.hpp b/host/include/uhd/rfnoc/register_iface.hpp
index 3344b7c5e..23f24b242 100644
--- a/host/include/uhd/rfnoc/register_iface.hpp
+++ b/host/include/uhd/rfnoc/register_iface.hpp
@@ -32,11 +32,26 @@ public:
virtual ~register_iface() = default;
- /*! Callback function for an asynchronous message.
+ /*! Callback function for validating an asynchronous message.
+ *
* When a block in the FPGA sends an asynchronous message to the software,
- * the async message callback function is called. An async message can be
+ * the async message validator function is called. An async message can be
* modelled as a simple register write (key-value pair with addr/data) that
* is initiated by the FPGA.
+ * If this message returns true, the message is considered valid.
+ */
+ using async_msg_validator_t =
+ std::function<bool(uint32_t addr, const std::vector<uint32_t>& data)>;
+
+ /*! Callback function for acting upon an asynchronous message.
+ *
+ * When a block in the FPGA sends an asynchronous message to the software,
+ * and it has been validated, the async message callback function is called.
+ * An async message can be modelled as a simple register write (key-value
+ * pair with addr/data) that is initiated by the FPGA.
+ *
+ * When this message is called, the async message was previously verified
+ * by calling the async message validator callback.
*/
using async_msg_callback_t = std::function<void(
uint32_t addr, const std::vector<uint32_t>& data, boost::optional<uint64_t>)>;
@@ -245,6 +260,27 @@ public:
*/
virtual void sleep(time_spec_t duration, bool ack = false) = 0;
+ /*! Register a callback function to validate a received async message
+ *
+ * The purpose of this callback is to provide a method to the framework to
+ * make sure a received async message is valid. If this callback is
+ * provided, the framework will first pass the message to the validator for
+ * validation. If the validator returns true, the async message is ACK'd
+ * with a ctrl_status_t::CMD_OKAY response, and then the async message is
+ * executed. If the validator returns false, then the async message is ACK'd
+ * with a ctrl_status_t::CMD_CMDERR, and the async message handler is not
+ * excecuted.
+ *
+ * This callback may not communicate with the device, it can only look at
+ * the data and make a valid/not valid decision.
+ *
+ * Only one callback function can be registered. When calling this multiple
+ * times, only the last callback will be accepted.
+ *
+ * \param callback_f The function to call when an asynchronous message is received.
+ */
+ virtual void register_async_msg_validator(async_msg_validator_t callback_f) = 0;
+
/*! Register a callback function for when an async message is received
*
* Only one callback function can be registered. When calling this multiple
diff --git a/host/lib/rfnoc/ctrlport_endpoint.cpp b/host/lib/rfnoc/ctrlport_endpoint.cpp
index 5c0deca1d..3374a707b 100644
--- a/host/lib/rfnoc/ctrlport_endpoint.cpp
+++ b/host/lib/rfnoc/ctrlport_endpoint.cpp
@@ -191,6 +191,12 @@ public:
}
}
+ virtual void register_async_msg_validator(async_msg_validator_t callback_f)
+ {
+ std::unique_lock<std::mutex> lock(_mutex);
+ _validate_async_msg = callback_f;
+ }
+
virtual void register_async_msg_handler(async_msg_callback_t callback_f)
{
std::unique_lock<std::mutex> lock(_mutex);
@@ -274,12 +280,12 @@ public:
UHD_LOG_ERROR(
"CTRLEP", "Malformed async message request: Invalid num_data");
} else {
- try {
- _handle_async_msg(
- rx_ctrl.address, rx_ctrl.data_vtr, rx_ctrl.timestamp);
+ if (!_validate_async_msg(rx_ctrl.address, rx_ctrl.data_vtr)) {
+ UHD_LOG_ERROR("CTRLEP",
+ "Malformed async message request: Async message was not "
+ "validated by block controller!");
+ } else {
status = CMD_OKAY;
- } catch (...) {
- UHD_LOG_ERROR("CTRLEP", "Async message handler threw an exception");
}
}
try {
@@ -298,6 +304,19 @@ public:
} catch (...) {
UHD_LOG_ERROR("CTRLEP",
"Encountered an error sending a response for an async message");
+ return;
+ }
+ if (status == CMD_OKAY) {
+ try {
+ _handle_async_msg(
+ rx_ctrl.address, rx_ctrl.data_vtr, rx_ctrl.timestamp);
+ } catch (const std::exception& ex) {
+ UHD_LOG_ERROR("CTRLEP",
+ "Caught exception during async message handling: " << ex.what());
+ } catch (...) {
+ UHD_LOG_ERROR("CTRLEP",
+ "Caught unknown exception during async message handling!");
+ }
}
}
}
@@ -463,6 +482,10 @@ private:
//! The clock that drives the timing logic for the ctrlport endpoint
const clock_iface& _timebase_clk;
+ //! The function to call to validate an async message (by default, all async
+ // messages are considered valid)
+ async_msg_validator_t _validate_async_msg =
+ [](uint32_t, const std::vector<uint32_t>&) { return true; };
//! The function to call to handle an async message
async_msg_callback_t _handle_async_msg = async_msg_callback_t();
//! The current control sequence number of outgoing packets
diff --git a/host/lib/rfnoc/register_iface_holder.cpp b/host/lib/rfnoc/register_iface_holder.cpp
index ea5bf0149..d3a0e82e5 100644
--- a/host/lib/rfnoc/register_iface_holder.cpp
+++ b/host/lib/rfnoc/register_iface_holder.cpp
@@ -64,6 +64,11 @@ public:
UHD_LOG_ERROR("REGS", "Attempting to use invalidated register interface!");
}
+ void register_async_msg_validator(async_msg_validator_t)
+ {
+ UHD_LOG_ERROR("REGS", "Attempting to use invalidated register interface!");
+ }
+
void set_policy(const std::string&, const uhd::device_addr_t&)
{
UHD_LOG_ERROR("REGS", "Attempting to use invalidated register interface!");
diff --git a/host/tests/rfnoc_mock_reg_iface.hpp b/host/tests/rfnoc_mock_reg_iface.hpp
index b43317237..a6e85b790 100644
--- a/host/tests/rfnoc_mock_reg_iface.hpp
+++ b/host/tests/rfnoc_mock_reg_iface.hpp
@@ -95,6 +95,11 @@ public:
// nop
}
+ void register_async_msg_validator(async_msg_validator_t /*callback_f*/)
+ {
+ // nop
+ }
+
void register_async_msg_handler(async_msg_callback_t /*callback_f*/)
{
// nop