1 #pragma once 2 3 #include "data_interface.hpp" 4 5 #include <stdint.h> 6 7 #include <chrono> 8 #include <functional> 9 #include <phosphor-logging/log.hpp> 10 #include <sdeventplus/event.hpp> 11 #include <sdeventplus/source/io.hpp> 12 13 namespace openpower 14 { 15 namespace pels 16 { 17 18 /** 19 * @brief Return codes from sending a command 20 */ 21 enum class CmdStatus 22 { 23 success, 24 failure 25 }; 26 27 /** 28 * @brief Return codes from the command response 29 */ 30 enum class ResponseStatus 31 { 32 success, 33 failure 34 }; 35 36 /** 37 * @class HostInterface 38 * 39 * An abstract base class for sending the 'New PEL available' command 40 * to the host. Used so that the PLDM interfaces can be mocked for 41 * testing the HostNotifier code. The response to this command is 42 * asynchronous, with the intent that other code registers a callback 43 * function to run when the response is received. 44 */ 45 class HostInterface 46 { 47 public: 48 HostInterface() = delete; 49 virtual ~HostInterface() = default; 50 HostInterface(const HostInterface&) = default; 51 HostInterface& operator=(const HostInterface&) = default; 52 HostInterface(HostInterface&&) = default; 53 HostInterface& operator=(HostInterface&&) = default; 54 55 /** 56 * @brief Constructor 57 * 58 * @param[in] event - The sd_event object pointer 59 * @param[in] dataIface - The DataInterface object 60 */ 61 HostInterface(sd_event* event, DataInterfaceBase& dataIface) : 62 _event(event), _dataIface(dataIface) 63 { 64 } 65 66 /** 67 * @brief Pure virtual function for sending the 'new PEL available' 68 * asynchronous command to the host. 69 * 70 * @param[in] id - The ID of the new PEL 71 * @param[in] size - The size of the new PEL 72 * 73 * @return CmdStatus - If the send was successful or not 74 */ 75 virtual CmdStatus sendNewLogCmd(uint32_t id, uint32_t size) = 0; 76 77 /** 78 * @brief Returns the amount of time to wait before retrying after 79 * a failed send command. 80 * 81 * @return milliseconds - The amount of time to wait 82 */ 83 virtual std::chrono::milliseconds getSendRetryDelay() const 84 { 85 return _defaultSendRetryDelay; 86 } 87 88 /** 89 * @brief Returns the amount of time to wait before retrying after 90 * a command receive. 91 * 92 * @return milliseconds - The amount of time to wait 93 */ 94 virtual std::chrono::milliseconds getReceiveRetryDelay() const 95 { 96 return _defaultReceiveRetryDelay; 97 } 98 99 /** 100 * @brief Returns the amount of time to wait before retrying if the 101 * host firmware's PEL storage was full and it can't store 102 * any more logs until it is freed up somehow. 103 * 104 * In this class to help with mocking. 105 * 106 * @return milliseconds - The amount of time to wait 107 */ 108 virtual std::chrono::milliseconds getHostFullRetryDelay() const 109 { 110 return _defaultHostFullRetryDelay; 111 } 112 113 using ResponseFunction = std::function<void(ResponseStatus)>; 114 115 /** 116 * @brief Sets the function to call on the command receive. 117 * 118 * The success/failure status is passed to the function. 119 * 120 * @param[in] func - The callback function 121 */ 122 void setResponseFunction(ResponseFunction func) 123 { 124 _responseFunc = std::move(func); 125 } 126 127 /** 128 * @brief Call the response function 129 * 130 * @param[in] status - The status given to the function 131 */ 132 void callResponseFunc(ResponseStatus status) 133 { 134 if (_responseFunc) 135 { 136 try 137 { 138 (*_responseFunc)(status); 139 } 140 catch (const std::exception& e) 141 { 142 using namespace phosphor::logging; 143 log<level::ERR>( 144 "Host iface response callback threw an exception", 145 entry("ERROR=%s", e.what())); 146 } 147 } 148 } 149 150 /** 151 * @brief Returns the event object in use 152 * 153 * @return sdeventplus::Event& - The event object 154 */ 155 sdeventplus::Event& getEvent() 156 { 157 return _event; 158 } 159 160 /** 161 * @brief Pure virtual function to cancel an in-progress command 162 * 163 * 'In progress' means after the send but before the receive 164 */ 165 virtual void cancelCmd() = 0; 166 167 /** 168 * @brief Says if the command is in progress (after send/before receive) 169 * 170 * @return bool - If command is in progress 171 */ 172 bool cmdInProgress() const 173 { 174 return _inProgress; 175 } 176 177 protected: 178 /** 179 * @brief Pure virtual function for implementing the asynchronous 180 * command response callback. 181 * 182 * @param[in] io - The sdeventplus IO object that the callback is 183 * invoked from. 184 * @param[in] fd - The file descriptor being used 185 * @param[in] revents - The event status bits 186 */ 187 virtual void receive(sdeventplus::source::IO& io, int fd, 188 uint32_t revents) = 0; 189 190 /** 191 * @brief An optional function to call on a successful command response. 192 */ 193 std::optional<ResponseFunction> _responseFunc; 194 195 /** 196 * @brief The sd_event wrapper object needed for response callbacks 197 */ 198 sdeventplus::Event _event; 199 200 /** 201 * @brief The DataInterface object 202 */ 203 DataInterfaceBase& _dataIface; 204 205 /** 206 * @brief Tracks status of after a command is sent and before the 207 * response is received. 208 */ 209 bool _inProgress = false; 210 211 private: 212 /** 213 * @brief The default amount of time to wait before retrying 214 * a failed send. 215 */ 216 const std::chrono::milliseconds _defaultSendRetryDelay{1000}; 217 218 /** 219 * @brief The default amount of time to wait 220 * before retrying after a failed receive. 221 */ 222 const std::chrono::milliseconds _defaultReceiveRetryDelay{1000}; 223 224 /** 225 * @brief The default amount of time to wait when the host said it 226 * was full before sending the PEL again. 227 */ 228 const std::chrono::milliseconds _defaultHostFullRetryDelay{60000}; 229 }; 230 231 } // namespace pels 232 } // namespace openpower 233