diff options
author | Martin Braun <martin.braun@ettus.com> | 2019-08-01 14:49:12 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:34 -0800 |
commit | b89c53c0691c6d70fb24561243a930bbcc32363b (patch) | |
tree | f98c821b5a86daff0addd79eaf9bc6c812f38946 /host | |
parent | 595fba47d534634432d4e114d31bbfa42cc00812 (diff) | |
download | uhd-b89c53c0691c6d70fb24561243a930bbcc32363b.tar.gz uhd-b89c53c0691c6d70fb24561243a930bbcc32363b.tar.bz2 uhd-b89c53c0691c6d70fb24561243a930bbcc32363b.zip |
rfnoc: ctrlport: Separately validate and handle async messages
This introduces the concept of an async message validator, an optional
callback for functions to check if an async message has a valid payload.
After validation, the async message is ack'd. Then, the async message
handler is executed.
This makes sure that an async message is ack'd as soon as possible,
rather than after the async message handling, which can itself have all
sorts of communication going on to the device.
Diffstat (limited to 'host')
-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 |