blob: dc7470740d29d95c1caf3af037ebdbb7572867dc [file] [log] [blame]
Matt Spinler432efec2020-09-24 13:41:31 -05001#pragma once
2
3#include "sdbusplus.hpp"
4
5#include <fmt/format.h>
6
7#include <phosphor-logging/log.hpp>
8
9#include <functional>
10
11namespace phosphor::fan
12{
13
14/**
15 * @class PowerState
16 *
17 * This class provides an interface to check the current power state,
18 * and to register a function that gets called when there is a power
Matt Spinler76e73c22021-04-21 11:03:05 -050019 * state change. A callback can be passed in using the constructor,
20 * or can be added later using addCallback().
Matt Spinler432efec2020-09-24 13:41:31 -050021 *
22 * Different architectures may have different ways of considering
23 * power to be on, such as a pgood property on the
24 * org.openbmc.Control.Power interface, or the CurrentPowerState
25 * property on the State.Chassis interface, so those details will
26 * be in a derived class.
27 */
28class PowerState
29{
30 public:
31 using StateChangeFunc = std::function<void(bool)>;
32
Matt Spinler432efec2020-09-24 13:41:31 -050033 virtual ~PowerState() = default;
34 PowerState(const PowerState&) = delete;
35 PowerState& operator=(const PowerState&) = delete;
36 PowerState(PowerState&&) = delete;
37 PowerState& operator=(PowerState&&) = delete;
38
39 /**
40 * @brief Constructor
41 *
42 * @param[in] bus - The D-Bus bus connection object
43 * @param[in] callback - The function that should be run when
44 * the power state changes
45 */
Matt Spinler76e73c22021-04-21 11:03:05 -050046 PowerState(sdbusplus::bus::bus& bus, StateChangeFunc callback) : _bus(bus)
47 {
48 _callbacks.emplace("default", std::move(callback));
49 }
50
51 /**
52 * @brief Constructor
53 *
54 * Callbacks can be added with addCallback().
55 */
56 PowerState() : _bus(util::SDBusPlus::getBus())
Matt Spinler432efec2020-09-24 13:41:31 -050057 {}
58
59 /**
Matt Spinler76e73c22021-04-21 11:03:05 -050060 * @brief Adds a function to call when the power state changes
61 *
62 * @param[in] - Any unique name, so the callback can be removed later
63 * if desired.
64 * @param[in] callback - The function that should be run when
65 * the power state changes
66 */
67 void addCallback(const std::string& name, StateChangeFunc callback)
68 {
69 _callbacks.emplace(name, std::move(callback));
70 }
71
72 /**
73 * @brief Remove the callback so it is no longer called
74 *
75 * @param[in] name - The name used when it was added.
76 */
77 void deleteCallback(const std::string& name)
78 {
79 _callbacks.erase(name);
80 }
81
82 /**
Matt Spinler432efec2020-09-24 13:41:31 -050083 * @brief Says if power is on
84 *
85 * @return bool - The power state
86 */
87 bool isPowerOn() const
88 {
89 return _powerState;
90 }
91
92 protected:
93 /**
94 * @brief Called by derived classes to set the power state value
95 *
Matt Spinler76e73c22021-04-21 11:03:05 -050096 * Will call the callback functions if the state changed.
Matt Spinler432efec2020-09-24 13:41:31 -050097 *
98 * @param[in] state - The new power state
99 */
100 void setPowerState(bool state)
101 {
102 if (state != _powerState)
103 {
104 _powerState = state;
Matt Spinler76e73c22021-04-21 11:03:05 -0500105 for (const auto& [name, callback] : _callbacks)
106 {
107 callback(_powerState);
108 }
Matt Spinler432efec2020-09-24 13:41:31 -0500109 }
110 }
111
112 /**
113 * @brief Reference to the D-Bus connection object.
114 */
115 sdbusplus::bus::bus& _bus;
116
117 /**
118 * @brief The power state value
119 */
120 bool _powerState = false;
121
122 private:
123 /**
Matt Spinler76e73c22021-04-21 11:03:05 -0500124 * @brief The callback functions to run when the power state changes
Matt Spinler432efec2020-09-24 13:41:31 -0500125 */
Matt Spinler76e73c22021-04-21 11:03:05 -0500126 std::map<std::string, StateChangeFunc> _callbacks;
Matt Spinler432efec2020-09-24 13:41:31 -0500127};
128
129/**
130 * @class PGoodState
131 *
132 * This class implements the PowerState API by looking at the 'pgood'
133 * property on the org.openbmc.Control.Power interface.
134 */
135class PGoodState : public PowerState
136{
137 public:
Matt Spinler432efec2020-09-24 13:41:31 -0500138 virtual ~PGoodState() = default;
139 PGoodState(const PGoodState&) = delete;
140 PGoodState& operator=(const PGoodState&) = delete;
141 PGoodState(PGoodState&&) = delete;
142 PGoodState& operator=(PGoodState&&) = delete;
143
Matt Spinler76e73c22021-04-21 11:03:05 -0500144 PGoodState() :
145 PowerState(), _match(_bus,
146 sdbusplus::bus::match::rules::propertiesChanged(
147 _pgoodPath, _pgoodInterface),
148 [this](auto& msg) { this->pgoodChanged(msg); })
149 {
150 readPGood();
151 }
152
Matt Spinler432efec2020-09-24 13:41:31 -0500153 /**
154 * @brief Constructor
155 *
156 * @param[in] bus - The D-Bus bus connection object
157 * @param[in] callback - The function that should be run when
158 * the power state changes
159 */
160 PGoodState(sdbusplus::bus::bus& bus, StateChangeFunc func) :
161 PowerState(bus, func),
162 _match(_bus,
163 sdbusplus::bus::match::rules::propertiesChanged(_pgoodPath,
164 _pgoodInterface),
165 [this](auto& msg) { this->pgoodChanged(msg); })
166 {
Matt Spinler76e73c22021-04-21 11:03:05 -0500167 readPGood();
Matt Spinler432efec2020-09-24 13:41:31 -0500168 }
169
170 /**
171 * @brief PropertiesChanged callback for the PGOOD property.
172 *
173 * Will call the registered callback function if necessary.
174 *
175 * @param[in] msg - The payload of the propertiesChanged signal
176 */
177 void pgoodChanged(sdbusplus::message::message& msg)
178 {
179 std::string interface;
180 std::map<std::string, std::variant<int32_t>> properties;
181
182 msg.read(interface, properties);
183
184 auto pgoodProp = properties.find(_pgoodProperty);
185 if (pgoodProp != properties.end())
186 {
187 auto pgood = std::get<int32_t>(pgoodProp->second);
188 setPowerState(pgood);
189 }
190 }
191
192 private:
Matt Spinler76e73c22021-04-21 11:03:05 -0500193 /**
194 * @brief Reads the PGOOD property from D-Bus and saves it.
195 */
196 void readPGood()
197 {
198 try
199 {
200 auto pgood = util::SDBusPlus::getProperty<int32_t>(
201 _bus, _pgoodPath, _pgoodInterface, _pgoodProperty);
202
203 _powerState = static_cast<bool>(pgood);
204 }
Matthew Barthbff172a2021-06-17 11:04:18 -0500205 catch (const util::DBusServiceError& e)
Matt Spinler76e73c22021-04-21 11:03:05 -0500206 {
Matthew Barthbff172a2021-06-17 11:04:18 -0500207 // Wait for propertiesChanged signal when service starts
Matt Spinler76e73c22021-04-21 11:03:05 -0500208 }
209 }
210
Matt Spinler432efec2020-09-24 13:41:31 -0500211 /** @brief D-Bus path constant */
212 const std::string _pgoodPath{"/org/openbmc/control/power0"};
213
214 /** @brief D-Bus interface constant */
215 const std::string _pgoodInterface{"org.openbmc.control.Power"};
216
217 /** @brief D-Bus property constant */
218 const std::string _pgoodProperty{"pgood"};
219
220 /** @brief The propertiesChanged match */
221 sdbusplus::bus::match::match _match;
222};
223
224} // namespace phosphor::fan