1 #pragma once
2 
3 #include "data_interface.hpp"
4 
5 #include <stdint.h>
6 
7 #include <phosphor-logging/lg2.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                 lg2::error(
156                     "Host iface response callback threw an exception: {EX}",
157                     "EX", e);
158             }
159         }
160     }
161 
162     /**
163      * @brief Returns the event object in use
164      *
165      * @return sdeventplus::Event& - The event object
166      */
167     sdeventplus::Event& getEvent()
168     {
169         return _event;
170     }
171 
172     /**
173      * @brief Pure virtual function to cancel an in-progress command
174      *
175      * 'In progress' means after the send but before the receive
176      */
177     virtual void cancelCmd() = 0;
178 
179     /**
180      * @brief Says if the command is in progress (after send/before receive)
181      *
182      * @return bool - If command is in progress
183      */
184     bool cmdInProgress() const
185     {
186         return _inProgress;
187     }
188 
189   protected:
190     /**
191      * @brief Pure virtual function for implementing the asynchronous
192      *        command response callback.
193      *
194      * @param[in] io - The sdeventplus IO object that the callback is
195      *                 invoked from.
196      * @param[in] fd - The file descriptor being used
197      * @param[in] revents - The event status bits
198      */
199     virtual void receive(sdeventplus::source::IO& io, int fd,
200                          uint32_t revents) = 0;
201 
202     /**
203      * @brief An optional function to call on a successful command response.
204      */
205     std::optional<ResponseFunction> _responseFunc;
206 
207     /**
208      * @brief The sd_event wrapper object needed for response callbacks
209      */
210     sdeventplus::Event _event;
211 
212     /**
213      * @brief The DataInterface object
214      */
215     DataInterfaceBase& _dataIface;
216 
217     /**
218      * @brief Tracks status of after a command is sent and before the
219      *        response is received.
220      */
221     bool _inProgress = false;
222 
223   private:
224     /**
225      * @brief The default amount of time to wait before retrying
226      *        a failed send.
227      */
228     const std::chrono::milliseconds _defaultSendRetryDelay{1000};
229 
230     /**
231      * @brief The default amount of time to wait
232      *        before retrying after a failed receive.
233      */
234     const std::chrono::milliseconds _defaultReceiveRetryDelay{1000};
235 
236     /**
237      * @brief The default amount of time to wait when the host said it
238      *        was full before sending the PEL again.
239      */
240     const std::chrono::milliseconds _defaultHostFullRetryDelay{60000};
241 
242     /**
243      * @brief The default amount of time to wait after the host is up
244      *        before sending up the PELs.
245      */
246     const std::chrono::milliseconds _defaultHostUpDelay{60000};
247 };
248 
249 } // namespace pels
250 } // namespace openpower
251