1 #pragma once
2 
3 #include "data_interface.hpp"
4 
5 #include <stdint.h>
6 
7 #include <phosphor-logging/log.hpp>
8 #include <sdeventplus/event.hpp>
9 #include <sdeventplus/source/io.hpp>
10 
11 #include <chrono>
12 #include <functional>
13 
14 namespace openpower
15 {
16 namespace pels
17 {
18 
19 /**
20  * @brief Return codes from sending a command
21  */
22 enum class CmdStatus
23 {
24     success,
25     failure
26 };
27 
28 /**
29  * @brief Return codes from the command response
30  */
31 enum class ResponseStatus
32 {
33     success,
34     failure
35 };
36 
37 /**
38  * @class HostInterface
39  *
40  * An abstract base class for sending the 'New PEL available' command
41  * to the host.  Used so that the PLDM interfaces can be mocked for
42  * testing the HostNotifier code.  The response to this command is
43  * asynchronous, with the intent that other code registers a callback
44  * function to run when the response is received.
45  */
46 class HostInterface
47 {
48   public:
49     HostInterface() = delete;
50     virtual ~HostInterface() = default;
51     HostInterface(const HostInterface&) = default;
52     HostInterface& operator=(const HostInterface&) = default;
53     HostInterface(HostInterface&&) = default;
54     HostInterface& operator=(HostInterface&&) = default;
55 
56     /**
57      * @brief Constructor
58      *
59      * @param[in] event - The sd_event object pointer
60      * @param[in] dataIface - The DataInterface object
61      */
62     HostInterface(sd_event* event, DataInterfaceBase& dataIface) :
63         _event(event), _dataIface(dataIface)
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     /**
114      * @brief Returns the amount of time to wait after the host is up
115      *        before sending commands.
116      *
117      * In this class to help with mocking.
118      *
119      * @return milliseconds - The amount of time to wait
120      */
121     virtual std::chrono::milliseconds getHostUpDelay() const
122     {
123         return _defaultHostUpDelay;
124     }
125 
126     using ResponseFunction = std::function<void(ResponseStatus)>;
127 
128     /**
129      * @brief Sets the function to call on the command receive.
130      *
131      * The success/failure status is passed to the function.
132      *
133      * @param[in] func - The callback function
134      */
135     void setResponseFunction(ResponseFunction func)
136     {
137         _responseFunc = std::move(func);
138     }
139 
140     /**
141      * @brief Call the response function
142      *
143      * @param[in] status - The status given to the function
144      */
145     void callResponseFunc(ResponseStatus status)
146     {
147         if (_responseFunc)
148         {
149             try
150             {
151                 (*_responseFunc)(status);
152             }
153             catch (const std::exception& e)
154             {
155                 using namespace phosphor::logging;
156                 log<level::ERR>(
157                     "Host iface response callback threw an exception",
158                     entry("ERROR=%s", e.what()));
159             }
160         }
161     }
162 
163     /**
164      * @brief Returns the event object in use
165      *
166      * @return sdeventplus::Event& - The event object
167      */
168     sdeventplus::Event& getEvent()
169     {
170         return _event;
171     }
172 
173     /**
174      * @brief Pure virtual function to cancel an in-progress command
175      *
176      * 'In progress' means after the send but before the receive
177      */
178     virtual void cancelCmd() = 0;
179 
180     /**
181      * @brief Says if the command is in progress (after send/before receive)
182      *
183      * @return bool - If command is in progress
184      */
185     bool cmdInProgress() const
186     {
187         return _inProgress;
188     }
189 
190   protected:
191     /**
192      * @brief Pure virtual function for implementing the asynchronous
193      *        command response callback.
194      *
195      * @param[in] io - The sdeventplus IO object that the callback is
196      *                 invoked from.
197      * @param[in] fd - The file descriptor being used
198      * @param[in] revents - The event status bits
199      */
200     virtual void receive(sdeventplus::source::IO& io, int fd,
201                          uint32_t revents) = 0;
202 
203     /**
204      * @brief An optional function to call on a successful command response.
205      */
206     std::optional<ResponseFunction> _responseFunc;
207 
208     /**
209      * @brief The sd_event wrapper object needed for response callbacks
210      */
211     sdeventplus::Event _event;
212 
213     /**
214      * @brief The DataInterface object
215      */
216     DataInterfaceBase& _dataIface;
217 
218     /**
219      * @brief Tracks status of after a command is sent and before the
220      *        response is received.
221      */
222     bool _inProgress = false;
223 
224   private:
225     /**
226      * @brief The default amount of time to wait before retrying
227      *        a failed send.
228      */
229     const std::chrono::milliseconds _defaultSendRetryDelay{1000};
230 
231     /**
232      * @brief The default amount of time to wait
233      *        before retrying after a failed receive.
234      */
235     const std::chrono::milliseconds _defaultReceiveRetryDelay{1000};
236 
237     /**
238      * @brief The default amount of time to wait when the host said it
239      *        was full before sending the PEL again.
240      */
241     const std::chrono::milliseconds _defaultHostFullRetryDelay{60000};
242 
243     /**
244      * @brief The default amount of time to wait after the host is up
245      *        before sending up the PELs.
246      */
247     const std::chrono::milliseconds _defaultHostUpDelay{60000};
248 };
249 
250 } // namespace pels
251 } // namespace openpower
252