1 #pragma once
2 
3 #include "sol/sol_manager.hpp"
4 
5 #include <systemd/sd-event.h>
6 
7 #include <boost/asio/io_context.hpp>
8 #include <chrono>
9 #include <map>
10 
11 namespace eventloop
12 {
13 
14 /** @struct EventSourceDeleter
15  *
16  *  Custom deleter for the sd_event_source*.
17  */
18 struct EventSourceDeleter
19 {
20     void operator()(sd_event_source* event) const
21     {
22         event = sd_event_source_unref(event);
23     }
24 };
25 
26 using EventSource = std::unique_ptr<sd_event_source, EventSourceDeleter>;
27 using IntervalType = std::chrono::microseconds;
28 
29 /** @enum Timers
30  *
31  *  For SOL functioning, there are two timers involved. The character accumulate
32  *  interval timer is the amount of time that the BMC will wait before
33  *  transmitting a partial SOL packet. The retry interval timer is the time that
34  *  BMC will wait before the first retry and the time between retries when
35  *  sending SOL packets to the remote console.
36  */
37 enum class Timers
38 {
39     ACCUMULATE, /**< Character Accumulate Timer */
40     RETRY,      /**< Retry Interval Timer */
41 };
42 
43 class EventLoop
44 {
45   public:
46     explicit EventLoop(std::shared_ptr<boost::asio::io_context> io) : io(io)
47     {
48     }
49     EventLoop() = delete;
50     ~EventLoop() = default;
51     EventLoop(const EventLoop&) = delete;
52     EventLoop& operator=(const EventLoop&) = delete;
53     EventLoop(EventLoop&&) = delete;
54     EventLoop& operator=(EventLoop&&) = delete;
55 
56     /** @brief Timer Map
57      *
58      *  The key for the timer map is the timer type. There are two types of
59      *  timers, character accumulate timer and retry interval timer. The
60      *  entries in the values is the event source for the timer and the
61      *  interval.
62      */
63     using TimerMap = std::map<Timers, std::tuple<EventSource, IntervalType>>;
64 
65     /** @brief SOL Payload Map.
66      *
67      *  The key for the payload map is the payload instance, the entries in
68      *  the value are a map of timers.
69      */
70     using PayloadMap = std::map<uint8_t, TimerMap>;
71 
72     /** @brief Initialise the event loop and add the handler for incoming
73      *         IPMI packets.
74      *
75      *  @return EXIT_SUCCESS on success and EXIT_FAILURE on failure.
76      */
77     int startEventLoop();
78 
79     /** @brief Add host console I/O event source to the event loop.
80      *
81      *  @param[in] fd - File descriptor for host console socket.
82      */
83     void startHostConsole(const sol::CustomFD& fd);
84 
85     /** @brief Remove host console I/O event source. */
86     void stopHostConsole();
87 
88     /** @brief Initialize the timers for the SOL payload instance
89      *
90      *  This API would add the Character accumulate interval timer event
91      *  source and the retry interval timer event source for the SOL payload
92      *  instance to the event loop.
93      *
94      *  @param[in] payloadInst - SOL payload instance.
95      *  @param[in] accumulateInterval - Character accumulate interval.
96      *  @param[in] retryInterval - Retry interval.
97      */
98     void startSOLPayloadInstance(uint8_t payloadInst,
99                                  IntervalType accumulateInterval,
100                                  IntervalType retryInterval);
101 
102     /** @brief Stop the timers for the SOL payload instance.
103      *
104      *  This would remove the character accumulate interval timer event
105      *  source and the retry interval timer event source from the event
106      *  loop.
107      *
108      *  @param[in] payloadInst - SOL payload instance
109      */
110     void stopSOLPayloadInstance(uint8_t payloadInst);
111 
112     /** @brief Modify the timer event source to enable/disable.
113      *
114      *  When the timer is enabled, the timer it set to fire again at
115      *  timer's interval for the instance added to the event loop iteration
116      *  timestamp. When the timer is disabled, the event source for the
117      *  timer is disabled.
118      *
119      *  @param[in] payloadInst - SOL payload instance.
120      *  @param[in] type -  Timer type.
121      *  @param[in] status - on/off the event source.
122      */
123     void switchTimer(uint8_t payloadInst, Timers type, bool status);
124 
125     /** @brief Modify the retry interval timer event source to enable/
126      *         disable
127      *
128      *  When the timer is enabled, the timer it set to fire again at
129      *  retry interval for the instance added to the event loop iteration
130      *  timestamp. When the timer is disabled the event source for the
131      *  retry interval timer is disabled.
132      *
133      *  @param[in] payloadInst - SOL payload instance.
134      *  @param[in] status - on/off the event source.
135      */
136     void switchRetryTimer(uint8_t payloadInst, bool status);
137 
138     /** @brief Event loop object. */
139     sd_event* event = nullptr;
140 
141   private:
142     /** @brief Event source object for host console. */
143     EventSource hostConsole = nullptr;
144 
145     /** @brief boost::asio io context to run with
146      */
147     std::shared_ptr<boost::asio::io_context> io;
148 
149     /** @brief Event source for the UDP socket listening on IPMI standard
150      *         port.
151      */
152     EventSource udpIPMI = nullptr;
153 
154     /** @brief Map to keep information regarding IPMI payload instance and
155      *         timers for character accumulate interval and retry interval.
156      */
157     PayloadMap payloadInfo;
158 };
159 
160 } // namespace eventloop
161