blob: 478b596cd0487ce40ad64b70385eb32399a57bf3 [file] [log] [blame]
Matt Spinler432efec2020-09-24 13:41:31 -05001#pragma once
2
3#include "sdbusplus.hpp"
4
Matt Spinler432efec2020-09-24 13:41:31 -05005#include <phosphor-logging/log.hpp>
Kumar Thangavel2dd87bd2021-11-24 20:13:16 +05306#include <xyz/openbmc_project/State/Host/server.hpp>
Matt Spinler432efec2020-09-24 13:41:31 -05007
8#include <functional>
9
Kumar Thangavel2dd87bd2021-11-24 20:13:16 +053010using HostState =
11 sdbusplus::xyz::openbmc_project::State::server::Host::HostState;
12
Matt Spinler432efec2020-09-24 13:41:31 -050013namespace phosphor::fan
14{
15
16/**
17 * @class PowerState
18 *
19 * This class provides an interface to check the current power state,
20 * and to register a function that gets called when there is a power
Matt Spinler76e73c22021-04-21 11:03:05 -050021 * state change. A callback can be passed in using the constructor,
22 * or can be added later using addCallback().
Matt Spinler432efec2020-09-24 13:41:31 -050023 *
24 * Different architectures may have different ways of considering
25 * power to be on, such as a pgood property on the
26 * org.openbmc.Control.Power interface, or the CurrentPowerState
27 * property on the State.Chassis interface, so those details will
28 * be in a derived class.
29 */
30class PowerState
31{
32 public:
33 using StateChangeFunc = std::function<void(bool)>;
34
Matt Spinler432efec2020-09-24 13:41:31 -050035 virtual ~PowerState() = default;
36 PowerState(const PowerState&) = delete;
37 PowerState& operator=(const PowerState&) = delete;
38 PowerState(PowerState&&) = delete;
39 PowerState& operator=(PowerState&&) = delete;
40
41 /**
42 * @brief Constructor
43 *
44 * @param[in] bus - The D-Bus bus connection object
45 * @param[in] callback - The function that should be run when
46 * the power state changes
47 */
Patrick Williamscb356d42022-07-22 19:26:53 -050048 PowerState(sdbusplus::bus_t& bus, StateChangeFunc callback) : _bus(bus)
Matt Spinler76e73c22021-04-21 11:03:05 -050049 {
50 _callbacks.emplace("default", std::move(callback));
51 }
52
53 /**
54 * @brief Constructor
55 *
56 * Callbacks can be added with addCallback().
57 */
Patrick Williams61b73292023-05-10 07:50:12 -050058 PowerState() : _bus(util::SDBusPlus::getBus()) {}
Matt Spinler432efec2020-09-24 13:41:31 -050059
60 /**
Matt Spinler76e73c22021-04-21 11:03:05 -050061 * @brief Adds a function to call when the power state changes
62 *
63 * @param[in] - Any unique name, so the callback can be removed later
64 * if desired.
65 * @param[in] callback - The function that should be run when
66 * the power state changes
67 */
68 void addCallback(const std::string& name, StateChangeFunc callback)
69 {
70 _callbacks.emplace(name, std::move(callback));
71 }
72
73 /**
74 * @brief Remove the callback so it is no longer called
75 *
76 * @param[in] name - The name used when it was added.
77 */
78 void deleteCallback(const std::string& name)
79 {
80 _callbacks.erase(name);
81 }
82
83 /**
Matt Spinler432efec2020-09-24 13:41:31 -050084 * @brief Says if power is on
85 *
86 * @return bool - The power state
87 */
88 bool isPowerOn() const
89 {
90 return _powerState;
91 }
92
93 protected:
94 /**
95 * @brief Called by derived classes to set the power state value
96 *
Matt Spinler76e73c22021-04-21 11:03:05 -050097 * Will call the callback functions if the state changed.
Matt Spinler432efec2020-09-24 13:41:31 -050098 *
99 * @param[in] state - The new power state
100 */
101 void setPowerState(bool state)
102 {
103 if (state != _powerState)
104 {
105 _powerState = state;
Matt Spinler76e73c22021-04-21 11:03:05 -0500106 for (const auto& [name, callback] : _callbacks)
107 {
108 callback(_powerState);
109 }
Matt Spinler432efec2020-09-24 13:41:31 -0500110 }
111 }
112
113 /**
114 * @brief Reference to the D-Bus connection object.
115 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500116 sdbusplus::bus_t& _bus;
Matt Spinler432efec2020-09-24 13:41:31 -0500117
118 /**
119 * @brief The power state value
120 */
121 bool _powerState = false;
122
123 private:
124 /**
Matt Spinler76e73c22021-04-21 11:03:05 -0500125 * @brief The callback functions to run when the power state changes
Matt Spinler432efec2020-09-24 13:41:31 -0500126 */
Matt Spinler76e73c22021-04-21 11:03:05 -0500127 std::map<std::string, StateChangeFunc> _callbacks;
Matt Spinler432efec2020-09-24 13:41:31 -0500128};
129
130/**
131 * @class PGoodState
132 *
133 * This class implements the PowerState API by looking at the 'pgood'
134 * property on the org.openbmc.Control.Power interface.
135 */
136class PGoodState : public PowerState
137{
138 public:
Matt Spinler432efec2020-09-24 13:41:31 -0500139 virtual ~PGoodState() = default;
140 PGoodState(const PGoodState&) = delete;
141 PGoodState& operator=(const PGoodState&) = delete;
142 PGoodState(PGoodState&&) = delete;
143 PGoodState& operator=(PGoodState&&) = delete;
144
Matt Spinler76e73c22021-04-21 11:03:05 -0500145 PGoodState() :
146 PowerState(), _match(_bus,
147 sdbusplus::bus::match::rules::propertiesChanged(
148 _pgoodPath, _pgoodInterface),
149 [this](auto& msg) { this->pgoodChanged(msg); })
150 {
151 readPGood();
152 }
153
Matt Spinler432efec2020-09-24 13:41:31 -0500154 /**
155 * @brief Constructor
156 *
157 * @param[in] bus - The D-Bus bus connection object
158 * @param[in] callback - The function that should be run when
159 * the power state changes
160 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500161 PGoodState(sdbusplus::bus_t& bus, StateChangeFunc func) :
Matt Spinler432efec2020-09-24 13:41:31 -0500162 PowerState(bus, func),
163 _match(_bus,
164 sdbusplus::bus::match::rules::propertiesChanged(_pgoodPath,
165 _pgoodInterface),
166 [this](auto& msg) { this->pgoodChanged(msg); })
167 {
Matt Spinler76e73c22021-04-21 11:03:05 -0500168 readPGood();
Matt Spinler432efec2020-09-24 13:41:31 -0500169 }
170
171 /**
172 * @brief PropertiesChanged callback for the PGOOD property.
173 *
174 * Will call the registered callback function if necessary.
175 *
176 * @param[in] msg - The payload of the propertiesChanged signal
177 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500178 void pgoodChanged(sdbusplus::message_t& msg)
Matt Spinler432efec2020-09-24 13:41:31 -0500179 {
180 std::string interface;
181 std::map<std::string, std::variant<int32_t>> properties;
182
183 msg.read(interface, properties);
184
185 auto pgoodProp = properties.find(_pgoodProperty);
186 if (pgoodProp != properties.end())
187 {
188 auto pgood = std::get<int32_t>(pgoodProp->second);
189 setPowerState(pgood);
190 }
191 }
192
193 private:
Matt Spinler76e73c22021-04-21 11:03:05 -0500194 /**
195 * @brief Reads the PGOOD property from D-Bus and saves it.
196 */
197 void readPGood()
198 {
199 try
200 {
201 auto pgood = util::SDBusPlus::getProperty<int32_t>(
202 _bus, _pgoodPath, _pgoodInterface, _pgoodProperty);
203
204 _powerState = static_cast<bool>(pgood);
205 }
Matthew Barthbff172a2021-06-17 11:04:18 -0500206 catch (const util::DBusServiceError& e)
Matt Spinler76e73c22021-04-21 11:03:05 -0500207 {
Matthew Barthbff172a2021-06-17 11:04:18 -0500208 // Wait for propertiesChanged signal when service starts
Matt Spinler76e73c22021-04-21 11:03:05 -0500209 }
210 }
211
Matt Spinler432efec2020-09-24 13:41:31 -0500212 /** @brief D-Bus path constant */
213 const std::string _pgoodPath{"/org/openbmc/control/power0"};
214
215 /** @brief D-Bus interface constant */
216 const std::string _pgoodInterface{"org.openbmc.control.Power"};
217
218 /** @brief D-Bus property constant */
219 const std::string _pgoodProperty{"pgood"};
220
221 /** @brief The propertiesChanged match */
Patrick Williamscb356d42022-07-22 19:26:53 -0500222 sdbusplus::bus::match_t _match;
Matt Spinler432efec2020-09-24 13:41:31 -0500223};
224
Kumar Thangavel2dd87bd2021-11-24 20:13:16 +0530225/**
226 * @class HostPowerState
227 *
228 * This class implements the PowerState API by looking at the 'powerState'
229 * property on the phosphor virtual sensor interface.
230 */
231class HostPowerState : public PowerState
232{
233 public:
234 virtual ~HostPowerState() = default;
235 HostPowerState(const HostPowerState&) = delete;
236 HostPowerState& operator=(const HostPowerState&) = delete;
237 HostPowerState(HostPowerState&&) = delete;
238 HostPowerState& operator=(HostPowerState&&) = delete;
239
240 HostPowerState() :
241 PowerState(),
242 _match(_bus,
243 sdbusplus::bus::match::rules::propertiesChangedNamespace(
244 _hostStatePath, _hostStateInterface),
245 [this](auto& msg) { this->hostStateChanged(msg); })
246 {
247 readHostState();
248 }
249
250 /**
251 * @brief Constructor
252 *
253 * @param[in] bus - The D-Bus bus connection object
254 * @param[in] callback - The function that should be run when
255 * the power state changes
256 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500257 HostPowerState(sdbusplus::bus_t& bus, StateChangeFunc func) :
Kumar Thangavel2dd87bd2021-11-24 20:13:16 +0530258 PowerState(bus, func),
259 _match(_bus,
260 sdbusplus::bus::match::rules::propertiesChangedNamespace(
261 _hostStatePath, _hostStateInterface),
262 [this](auto& msg) { this->hostStateChanged(msg); })
263 {
264 readHostState();
265 }
266
267 /**
268 * @brief PropertiesChanged callback for the CurrentHostState property.
269 *
270 * Will call the registered callback function if necessary.
271 *
272 * @param[in] msg - The payload of the propertiesChanged signal
273 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500274 void hostStateChanged(sdbusplus::message_t& msg)
Kumar Thangavel2dd87bd2021-11-24 20:13:16 +0530275 {
276 std::string interface;
277 std::map<std::string, std::variant<std::string>> properties;
278 std::vector<HostState> hostPowerStates;
279
280 msg.read(interface, properties);
281
282 auto hostStateProp = properties.find(_hostStateProperty);
283 if (hostStateProp != properties.end())
284 {
285 auto currentHostState =
286 sdbusplus::message::convert_from_string<HostState>(
287 std::get<std::string>(hostStateProp->second));
288
289 if (!currentHostState)
290 {
291 throw sdbusplus::exception::InvalidEnumString();
292 }
293 HostState hostState = *currentHostState;
294
295 hostPowerStates.emplace_back(hostState);
296 setHostPowerState(hostPowerStates);
297 }
298 }
299
300 private:
301 void setHostPowerState(std::vector<HostState>& hostPowerStates)
302 {
303 bool powerStateflag = false;
304 for (const auto& powerState : hostPowerStates)
305 {
306 if (powerState == HostState::Standby ||
307 powerState == HostState::Running ||
308 powerState == HostState::TransitioningToRunning ||
309 powerState == HostState::Quiesced ||
310 powerState == HostState::DiagnosticMode)
311 {
312 powerStateflag = true;
313 break;
314 }
315 }
316 setPowerState(powerStateflag);
317 }
318
319 /**
320 * @brief Reads the CurrentHostState property from D-Bus and saves it.
321 */
322 void readHostState()
323 {
Kumar Thangavel2dd87bd2021-11-24 20:13:16 +0530324 std::string hostStatePath;
325 std::string hostStateService;
326 std::string hostService = "xyz.openbmc_project.State.Host";
327 std::vector<HostState> hostPowerStates;
328
329 int32_t depth = 0;
330 const std::string path = "/";
331
332 auto mapperResponse = util::SDBusPlus::getSubTreeRaw(
333 _bus, path, _hostStateInterface, depth);
334
335 for (const auto& path : mapperResponse)
336 {
337 for (const auto& service : path.second)
338 {
339 hostStateService = service.first;
340
341 if (hostStateService.find(hostService) != std::string::npos)
342 {
343 hostStatePath = path.first;
344
345 auto currentHostState =
346 util::SDBusPlus::getProperty<HostState>(
347 hostStateService, hostStatePath,
348 _hostStateInterface, _hostStateProperty);
349
350 hostPowerStates.emplace_back(currentHostState);
351 }
352 }
353 }
354 setHostPowerState(hostPowerStates);
355 }
356
357 const std::string _hostStatePath{"/xyz/openbmc_project/state"};
358
359 /** @brief D-Bus interface constant */
360 const std::string _hostStateInterface{"xyz.openbmc_project.State.Host"};
361
362 /** @brief D-Bus property constant */
363 const std::string _hostStateProperty{"CurrentHostState"};
364
365 /** @brief The propertiesChanged match */
Patrick Williamscb356d42022-07-22 19:26:53 -0500366 sdbusplus::bus::match_t _match;
Kumar Thangavel2dd87bd2021-11-24 20:13:16 +0530367};
368
Matt Spinler432efec2020-09-24 13:41:31 -0500369} // namespace phosphor::fan