diff options
-rw-r--r-- | host/include/uhd/rfnoc/register_iface.hpp | 40 | ||||
-rw-r--r-- | host/lib/rfnoc/ctrlport_endpoint.cpp | 33 | ||||
-rw-r--r-- | host/lib/rfnoc/register_iface_holder.cpp | 5 | ||||
-rw-r--r-- | host/tests/rfnoc_mock_reg_iface.hpp | 5 |
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 |