1 #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 11 namespace 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 19 * state change. A callback can be passed in using the constructor, 20 * or can be added later using addCallback(). 21 * 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 */ 28 class PowerState 29 { 30 public: 31 using StateChangeFunc = std::function<void(bool)>; 32 33 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 */ 46 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()) 57 {} 58 59 /** 60 * @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 /** 83 * @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 * 96 * Will call the callback functions if the state changed. 97 * 98 * @param[in] state - The new power state 99 */ 100 void setPowerState(bool state) 101 { 102 if (state != _powerState) 103 { 104 _powerState = state; 105 for (const auto& [name, callback] : _callbacks) 106 { 107 callback(_powerState); 108 } 109 } 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 /** 124 * @brief The callback functions to run when the power state changes 125 */ 126 std::map<std::string, StateChangeFunc> _callbacks; 127 }; 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 */ 135 class PGoodState : public PowerState 136 { 137 public: 138 virtual ~PGoodState() = default; 139 PGoodState(const PGoodState&) = delete; 140 PGoodState& operator=(const PGoodState&) = delete; 141 PGoodState(PGoodState&&) = delete; 142 PGoodState& operator=(PGoodState&&) = delete; 143 144 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 153 /** 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 { 167 readPGood(); 168 } 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: 193 /** 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 } 205 catch (const util::DBusServiceError& e) 206 { 207 // Wait for propertiesChanged signal when service starts 208 } 209 } 210 211 /** @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 225