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