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  | 
