1432efeccSMatt Spinler #pragma once 2432efeccSMatt Spinler 3432efeccSMatt Spinler #include "sdbusplus.hpp" 4432efeccSMatt Spinler 5432efeccSMatt Spinler #include <phosphor-logging/log.hpp> 62dd87bd1SKumar Thangavel #include <xyz/openbmc_project/State/Host/server.hpp> 7432efeccSMatt Spinler 8432efeccSMatt Spinler #include <functional> 9432efeccSMatt Spinler 102dd87bd1SKumar Thangavel using HostState = 112dd87bd1SKumar Thangavel sdbusplus::xyz::openbmc_project::State::server::Host::HostState; 122dd87bd1SKumar Thangavel 13432efeccSMatt Spinler namespace phosphor::fan 14432efeccSMatt Spinler { 15432efeccSMatt Spinler 16432efeccSMatt Spinler /** 17432efeccSMatt Spinler * @class PowerState 18432efeccSMatt Spinler * 19432efeccSMatt Spinler * This class provides an interface to check the current power state, 20432efeccSMatt Spinler * and to register a function that gets called when there is a power 2176e73c2aSMatt Spinler * state change. A callback can be passed in using the constructor, 2276e73c2aSMatt Spinler * or can be added later using addCallback(). 23432efeccSMatt Spinler * 24432efeccSMatt Spinler * Different architectures may have different ways of considering 25432efeccSMatt Spinler * power to be on, such as a pgood property on the 26432efeccSMatt Spinler * org.openbmc.Control.Power interface, or the CurrentPowerState 27432efeccSMatt Spinler * property on the State.Chassis interface, so those details will 28432efeccSMatt Spinler * be in a derived class. 29432efeccSMatt Spinler */ 30432efeccSMatt Spinler class PowerState 31432efeccSMatt Spinler { 32432efeccSMatt Spinler public: 33432efeccSMatt Spinler using StateChangeFunc = std::function<void(bool)>; 34432efeccSMatt Spinler 35432efeccSMatt Spinler virtual ~PowerState() = default; 36432efeccSMatt Spinler PowerState(const PowerState&) = delete; 37432efeccSMatt Spinler PowerState& operator=(const PowerState&) = delete; 38432efeccSMatt Spinler PowerState(PowerState&&) = delete; 39432efeccSMatt Spinler PowerState& operator=(PowerState&&) = delete; 40432efeccSMatt Spinler 41432efeccSMatt Spinler /** 42432efeccSMatt Spinler * @brief Constructor 43432efeccSMatt Spinler * 44432efeccSMatt Spinler * @param[in] bus - The D-Bus bus connection object 45432efeccSMatt Spinler * @param[in] callback - The function that should be run when 46432efeccSMatt Spinler * the power state changes 47432efeccSMatt Spinler */ PowerState(sdbusplus::bus_t & bus,StateChangeFunc callback)48cb356d48SPatrick Williams PowerState(sdbusplus::bus_t& bus, StateChangeFunc callback) : _bus(bus) 4976e73c2aSMatt Spinler { 5076e73c2aSMatt Spinler _callbacks.emplace("default", std::move(callback)); 5176e73c2aSMatt Spinler } 5276e73c2aSMatt Spinler 5376e73c2aSMatt Spinler /** 5476e73c2aSMatt Spinler * @brief Constructor 5576e73c2aSMatt Spinler * 5676e73c2aSMatt Spinler * Callbacks can be added with addCallback(). 5776e73c2aSMatt Spinler */ PowerState()5861b73296SPatrick Williams PowerState() : _bus(util::SDBusPlus::getBus()) {} 59432efeccSMatt Spinler 60432efeccSMatt Spinler /** 6176e73c2aSMatt Spinler * @brief Adds a function to call when the power state changes 6276e73c2aSMatt Spinler * 6376e73c2aSMatt Spinler * @param[in] - Any unique name, so the callback can be removed later 6476e73c2aSMatt Spinler * if desired. 6576e73c2aSMatt Spinler * @param[in] callback - The function that should be run when 6676e73c2aSMatt Spinler * the power state changes 6776e73c2aSMatt Spinler */ addCallback(const std::string & name,StateChangeFunc callback)6876e73c2aSMatt Spinler void addCallback(const std::string& name, StateChangeFunc callback) 6976e73c2aSMatt Spinler { 7076e73c2aSMatt Spinler _callbacks.emplace(name, std::move(callback)); 7176e73c2aSMatt Spinler } 7276e73c2aSMatt Spinler 7376e73c2aSMatt Spinler /** 7476e73c2aSMatt Spinler * @brief Remove the callback so it is no longer called 7576e73c2aSMatt Spinler * 7676e73c2aSMatt Spinler * @param[in] name - The name used when it was added. 7776e73c2aSMatt Spinler */ deleteCallback(const std::string & name)7876e73c2aSMatt Spinler void deleteCallback(const std::string& name) 7976e73c2aSMatt Spinler { 8076e73c2aSMatt Spinler _callbacks.erase(name); 8176e73c2aSMatt Spinler } 8276e73c2aSMatt Spinler 8376e73c2aSMatt Spinler /** 84432efeccSMatt Spinler * @brief Says if power is on 85432efeccSMatt Spinler * 86432efeccSMatt Spinler * @return bool - The power state 87432efeccSMatt Spinler */ isPowerOn() const88432efeccSMatt Spinler bool isPowerOn() const 89432efeccSMatt Spinler { 90432efeccSMatt Spinler return _powerState; 91432efeccSMatt Spinler } 92432efeccSMatt Spinler 93432efeccSMatt Spinler protected: 94432efeccSMatt Spinler /** 95432efeccSMatt Spinler * @brief Called by derived classes to set the power state value 96432efeccSMatt Spinler * 9776e73c2aSMatt Spinler * Will call the callback functions if the state changed. 98432efeccSMatt Spinler * 99432efeccSMatt Spinler * @param[in] state - The new power state 100432efeccSMatt Spinler */ setPowerState(bool state)101432efeccSMatt Spinler void setPowerState(bool state) 102432efeccSMatt Spinler { 103432efeccSMatt Spinler if (state != _powerState) 104432efeccSMatt Spinler { 105432efeccSMatt Spinler _powerState = state; 10676e73c2aSMatt Spinler for (const auto& [name, callback] : _callbacks) 10776e73c2aSMatt Spinler { 10876e73c2aSMatt Spinler callback(_powerState); 10976e73c2aSMatt Spinler } 110432efeccSMatt Spinler } 111432efeccSMatt Spinler } 112432efeccSMatt Spinler 113432efeccSMatt Spinler /** 114432efeccSMatt Spinler * @brief Reference to the D-Bus connection object. 115432efeccSMatt Spinler */ 116cb356d48SPatrick Williams sdbusplus::bus_t& _bus; 117432efeccSMatt Spinler 118432efeccSMatt Spinler /** 119432efeccSMatt Spinler * @brief The power state value 120432efeccSMatt Spinler */ 121432efeccSMatt Spinler bool _powerState = false; 122432efeccSMatt Spinler 123432efeccSMatt Spinler private: 124432efeccSMatt Spinler /** 12576e73c2aSMatt Spinler * @brief The callback functions to run when the power state changes 126432efeccSMatt Spinler */ 12776e73c2aSMatt Spinler std::map<std::string, StateChangeFunc> _callbacks; 128432efeccSMatt Spinler }; 129432efeccSMatt Spinler 130432efeccSMatt Spinler /** 131432efeccSMatt Spinler * @class PGoodState 132432efeccSMatt Spinler * 133432efeccSMatt Spinler * This class implements the PowerState API by looking at the 'pgood' 134432efeccSMatt Spinler * property on the org.openbmc.Control.Power interface. 135432efeccSMatt Spinler */ 136432efeccSMatt Spinler class PGoodState : public PowerState 137432efeccSMatt Spinler { 138432efeccSMatt Spinler public: 139432efeccSMatt Spinler virtual ~PGoodState() = default; 140432efeccSMatt Spinler PGoodState(const PGoodState&) = delete; 141432efeccSMatt Spinler PGoodState& operator=(const PGoodState&) = delete; 142432efeccSMatt Spinler PGoodState(PGoodState&&) = delete; 143432efeccSMatt Spinler PGoodState& operator=(PGoodState&&) = delete; 144432efeccSMatt Spinler PGoodState()14576e73c2aSMatt Spinler PGoodState() : 146*dfddd648SPatrick Williams PowerState(), 147*dfddd648SPatrick Williams _match(_bus, 148*dfddd648SPatrick Williams sdbusplus::bus::match::rules::propertiesChanged(_pgoodPath, 149*dfddd648SPatrick Williams _pgoodInterface), 15076e73c2aSMatt Spinler [this](auto& msg) { this->pgoodChanged(msg); }) 15176e73c2aSMatt Spinler { 15276e73c2aSMatt Spinler readPGood(); 15376e73c2aSMatt Spinler } 15476e73c2aSMatt Spinler 155432efeccSMatt Spinler /** 156432efeccSMatt Spinler * @brief Constructor 157432efeccSMatt Spinler * 158432efeccSMatt Spinler * @param[in] bus - The D-Bus bus connection object 159432efeccSMatt Spinler * @param[in] callback - The function that should be run when 160432efeccSMatt Spinler * the power state changes 161432efeccSMatt Spinler */ PGoodState(sdbusplus::bus_t & bus,StateChangeFunc func)162cb356d48SPatrick Williams PGoodState(sdbusplus::bus_t& bus, StateChangeFunc func) : 163432efeccSMatt Spinler PowerState(bus, func), 164432efeccSMatt Spinler _match(_bus, 165432efeccSMatt Spinler sdbusplus::bus::match::rules::propertiesChanged(_pgoodPath, 166432efeccSMatt Spinler _pgoodInterface), 167432efeccSMatt Spinler [this](auto& msg) { this->pgoodChanged(msg); }) 168432efeccSMatt Spinler { 16976e73c2aSMatt Spinler readPGood(); 170432efeccSMatt Spinler } 171432efeccSMatt Spinler 172432efeccSMatt Spinler /** 173432efeccSMatt Spinler * @brief PropertiesChanged callback for the PGOOD property. 174432efeccSMatt Spinler * 175432efeccSMatt Spinler * Will call the registered callback function if necessary. 176432efeccSMatt Spinler * 177432efeccSMatt Spinler * @param[in] msg - The payload of the propertiesChanged signal 178432efeccSMatt Spinler */ pgoodChanged(sdbusplus::message_t & msg)179cb356d48SPatrick Williams void pgoodChanged(sdbusplus::message_t& msg) 180432efeccSMatt Spinler { 181432efeccSMatt Spinler std::string interface; 182432efeccSMatt Spinler std::map<std::string, std::variant<int32_t>> properties; 183432efeccSMatt Spinler 184432efeccSMatt Spinler msg.read(interface, properties); 185432efeccSMatt Spinler 186432efeccSMatt Spinler auto pgoodProp = properties.find(_pgoodProperty); 187432efeccSMatt Spinler if (pgoodProp != properties.end()) 188432efeccSMatt Spinler { 189432efeccSMatt Spinler auto pgood = std::get<int32_t>(pgoodProp->second); 190432efeccSMatt Spinler setPowerState(pgood); 191432efeccSMatt Spinler } 192432efeccSMatt Spinler } 193432efeccSMatt Spinler 194432efeccSMatt Spinler private: 19576e73c2aSMatt Spinler /** 19676e73c2aSMatt Spinler * @brief Reads the PGOOD property from D-Bus and saves it. 19776e73c2aSMatt Spinler */ readPGood()19876e73c2aSMatt Spinler void readPGood() 19976e73c2aSMatt Spinler { 20076e73c2aSMatt Spinler try 20176e73c2aSMatt Spinler { 20276e73c2aSMatt Spinler auto pgood = util::SDBusPlus::getProperty<int32_t>( 20376e73c2aSMatt Spinler _bus, _pgoodPath, _pgoodInterface, _pgoodProperty); 20476e73c2aSMatt Spinler 20576e73c2aSMatt Spinler _powerState = static_cast<bool>(pgood); 20676e73c2aSMatt Spinler } 207bff172aaSMatthew Barth catch (const util::DBusServiceError& e) 20876e73c2aSMatt Spinler { 209bff172aaSMatthew Barth // Wait for propertiesChanged signal when service starts 21076e73c2aSMatt Spinler } 21176e73c2aSMatt Spinler } 21276e73c2aSMatt Spinler 213432efeccSMatt Spinler /** @brief D-Bus path constant */ 214432efeccSMatt Spinler const std::string _pgoodPath{"/org/openbmc/control/power0"}; 215432efeccSMatt Spinler 216432efeccSMatt Spinler /** @brief D-Bus interface constant */ 217432efeccSMatt Spinler const std::string _pgoodInterface{"org.openbmc.control.Power"}; 218432efeccSMatt Spinler 219432efeccSMatt Spinler /** @brief D-Bus property constant */ 220432efeccSMatt Spinler const std::string _pgoodProperty{"pgood"}; 221432efeccSMatt Spinler 222432efeccSMatt Spinler /** @brief The propertiesChanged match */ 223cb356d48SPatrick Williams sdbusplus::bus::match_t _match; 224432efeccSMatt Spinler }; 225432efeccSMatt Spinler 2262dd87bd1SKumar Thangavel /** 2272dd87bd1SKumar Thangavel * @class HostPowerState 2282dd87bd1SKumar Thangavel * 2292dd87bd1SKumar Thangavel * This class implements the PowerState API by looking at the 'powerState' 2302dd87bd1SKumar Thangavel * property on the phosphor virtual sensor interface. 2312dd87bd1SKumar Thangavel */ 2322dd87bd1SKumar Thangavel class HostPowerState : public PowerState 2332dd87bd1SKumar Thangavel { 2342dd87bd1SKumar Thangavel public: 2352dd87bd1SKumar Thangavel virtual ~HostPowerState() = default; 2362dd87bd1SKumar Thangavel HostPowerState(const HostPowerState&) = delete; 2372dd87bd1SKumar Thangavel HostPowerState& operator=(const HostPowerState&) = delete; 2382dd87bd1SKumar Thangavel HostPowerState(HostPowerState&&) = delete; 2392dd87bd1SKumar Thangavel HostPowerState& operator=(HostPowerState&&) = delete; 2402dd87bd1SKumar Thangavel HostPowerState()2412dd87bd1SKumar Thangavel HostPowerState() : 2422dd87bd1SKumar Thangavel PowerState(), 2432dd87bd1SKumar Thangavel _match(_bus, 2442dd87bd1SKumar Thangavel sdbusplus::bus::match::rules::propertiesChangedNamespace( 2452dd87bd1SKumar Thangavel _hostStatePath, _hostStateInterface), 2462dd87bd1SKumar Thangavel [this](auto& msg) { this->hostStateChanged(msg); }) 2472dd87bd1SKumar Thangavel { 2482dd87bd1SKumar Thangavel readHostState(); 2492dd87bd1SKumar Thangavel } 2502dd87bd1SKumar Thangavel 2512dd87bd1SKumar Thangavel /** 2522dd87bd1SKumar Thangavel * @brief Constructor 2532dd87bd1SKumar Thangavel * 2542dd87bd1SKumar Thangavel * @param[in] bus - The D-Bus bus connection object 2552dd87bd1SKumar Thangavel * @param[in] callback - The function that should be run when 2562dd87bd1SKumar Thangavel * the power state changes 2572dd87bd1SKumar Thangavel */ HostPowerState(sdbusplus::bus_t & bus,StateChangeFunc func)258cb356d48SPatrick Williams HostPowerState(sdbusplus::bus_t& bus, StateChangeFunc func) : 2592dd87bd1SKumar Thangavel PowerState(bus, func), 2602dd87bd1SKumar Thangavel _match(_bus, 2612dd87bd1SKumar Thangavel sdbusplus::bus::match::rules::propertiesChangedNamespace( 2622dd87bd1SKumar Thangavel _hostStatePath, _hostStateInterface), 2632dd87bd1SKumar Thangavel [this](auto& msg) { this->hostStateChanged(msg); }) 2642dd87bd1SKumar Thangavel { 2652dd87bd1SKumar Thangavel readHostState(); 2662dd87bd1SKumar Thangavel } 2672dd87bd1SKumar Thangavel 2682dd87bd1SKumar Thangavel /** 2692dd87bd1SKumar Thangavel * @brief PropertiesChanged callback for the CurrentHostState property. 2702dd87bd1SKumar Thangavel * 2712dd87bd1SKumar Thangavel * Will call the registered callback function if necessary. 2722dd87bd1SKumar Thangavel * 2732dd87bd1SKumar Thangavel * @param[in] msg - The payload of the propertiesChanged signal 2742dd87bd1SKumar Thangavel */ hostStateChanged(sdbusplus::message_t & msg)275cb356d48SPatrick Williams void hostStateChanged(sdbusplus::message_t& msg) 2762dd87bd1SKumar Thangavel { 2772dd87bd1SKumar Thangavel std::string interface; 2782dd87bd1SKumar Thangavel std::map<std::string, std::variant<std::string>> properties; 2792dd87bd1SKumar Thangavel std::vector<HostState> hostPowerStates; 2802dd87bd1SKumar Thangavel 2812dd87bd1SKumar Thangavel msg.read(interface, properties); 2822dd87bd1SKumar Thangavel 2832dd87bd1SKumar Thangavel auto hostStateProp = properties.find(_hostStateProperty); 2842dd87bd1SKumar Thangavel if (hostStateProp != properties.end()) 2852dd87bd1SKumar Thangavel { 2862dd87bd1SKumar Thangavel auto currentHostState = 2872dd87bd1SKumar Thangavel sdbusplus::message::convert_from_string<HostState>( 2882dd87bd1SKumar Thangavel std::get<std::string>(hostStateProp->second)); 2892dd87bd1SKumar Thangavel 2902dd87bd1SKumar Thangavel if (!currentHostState) 2912dd87bd1SKumar Thangavel { 2922dd87bd1SKumar Thangavel throw sdbusplus::exception::InvalidEnumString(); 2932dd87bd1SKumar Thangavel } 2942dd87bd1SKumar Thangavel HostState hostState = *currentHostState; 2952dd87bd1SKumar Thangavel 2962dd87bd1SKumar Thangavel hostPowerStates.emplace_back(hostState); 2970cff4ea6SChau Ly setHostPowerState(hostPowerStates, true); 2982dd87bd1SKumar Thangavel } 2992dd87bd1SKumar Thangavel } 3002dd87bd1SKumar Thangavel 3012dd87bd1SKumar Thangavel private: setHostPowerState(std::vector<HostState> & hostPowerStates,bool callFromStateChange)3020cff4ea6SChau Ly void setHostPowerState(std::vector<HostState>& hostPowerStates, 3030cff4ea6SChau Ly bool callFromStateChange) 3042dd87bd1SKumar Thangavel { 3052dd87bd1SKumar Thangavel bool powerStateflag = false; 3062dd87bd1SKumar Thangavel for (const auto& powerState : hostPowerStates) 3072dd87bd1SKumar Thangavel { 3082dd87bd1SKumar Thangavel if (powerState == HostState::Standby || 3092dd87bd1SKumar Thangavel powerState == HostState::Running || 3102dd87bd1SKumar Thangavel powerState == HostState::TransitioningToRunning || 3112dd87bd1SKumar Thangavel powerState == HostState::Quiesced || 3122dd87bd1SKumar Thangavel powerState == HostState::DiagnosticMode) 3132dd87bd1SKumar Thangavel { 3142dd87bd1SKumar Thangavel powerStateflag = true; 3152dd87bd1SKumar Thangavel break; 3162dd87bd1SKumar Thangavel } 3172dd87bd1SKumar Thangavel } 3180cff4ea6SChau Ly if (callFromStateChange) 3190cff4ea6SChau Ly { 3202dd87bd1SKumar Thangavel setPowerState(powerStateflag); 3212dd87bd1SKumar Thangavel } 3220cff4ea6SChau Ly else 3230cff4ea6SChau Ly { 3240cff4ea6SChau Ly // This won't call callbacks (if exists) during the constructor of 3250cff4ea6SChau Ly // the class when the first read for this flag is true which is 3260cff4ea6SChau Ly // different from the init value of _powerState. 3270cff4ea6SChau Ly // Daemon that wants to do anything when the initial power state 3280cff4ea6SChau Ly // is true can check isPowerOn() and do it. 3290cff4ea6SChau Ly _powerState = powerStateflag; 3300cff4ea6SChau Ly } 3310cff4ea6SChau Ly } 3322dd87bd1SKumar Thangavel 3332dd87bd1SKumar Thangavel /** 3342dd87bd1SKumar Thangavel * @brief Reads the CurrentHostState property from D-Bus and saves it. 3352dd87bd1SKumar Thangavel */ readHostState()3362dd87bd1SKumar Thangavel void readHostState() 3372dd87bd1SKumar Thangavel { 3382dd87bd1SKumar Thangavel std::string hostStatePath; 3392dd87bd1SKumar Thangavel std::string hostStateService; 3402dd87bd1SKumar Thangavel std::string hostService = "xyz.openbmc_project.State.Host"; 3412dd87bd1SKumar Thangavel std::vector<HostState> hostPowerStates; 3422dd87bd1SKumar Thangavel 3432dd87bd1SKumar Thangavel int32_t depth = 0; 3442dd87bd1SKumar Thangavel const std::string path = "/"; 3452dd87bd1SKumar Thangavel 3462dd87bd1SKumar Thangavel auto mapperResponse = util::SDBusPlus::getSubTreeRaw( 3472dd87bd1SKumar Thangavel _bus, path, _hostStateInterface, depth); 3482dd87bd1SKumar Thangavel 3492dd87bd1SKumar Thangavel for (const auto& path : mapperResponse) 3502dd87bd1SKumar Thangavel { 3512dd87bd1SKumar Thangavel for (const auto& service : path.second) 3522dd87bd1SKumar Thangavel { 3532dd87bd1SKumar Thangavel hostStateService = service.first; 3542dd87bd1SKumar Thangavel 3552dd87bd1SKumar Thangavel if (hostStateService.find(hostService) != std::string::npos) 3562dd87bd1SKumar Thangavel { 3572dd87bd1SKumar Thangavel hostStatePath = path.first; 3582dd87bd1SKumar Thangavel 3592dd87bd1SKumar Thangavel auto currentHostState = 3602dd87bd1SKumar Thangavel util::SDBusPlus::getProperty<HostState>( 3612dd87bd1SKumar Thangavel hostStateService, hostStatePath, 3622dd87bd1SKumar Thangavel _hostStateInterface, _hostStateProperty); 3632dd87bd1SKumar Thangavel 3642dd87bd1SKumar Thangavel hostPowerStates.emplace_back(currentHostState); 3652dd87bd1SKumar Thangavel } 3662dd87bd1SKumar Thangavel } 3672dd87bd1SKumar Thangavel } 3680cff4ea6SChau Ly setHostPowerState(hostPowerStates, false); 3692dd87bd1SKumar Thangavel } 3702dd87bd1SKumar Thangavel 3712dd87bd1SKumar Thangavel const std::string _hostStatePath{"/xyz/openbmc_project/state"}; 3722dd87bd1SKumar Thangavel 3732dd87bd1SKumar Thangavel /** @brief D-Bus interface constant */ 3742dd87bd1SKumar Thangavel const std::string _hostStateInterface{"xyz.openbmc_project.State.Host"}; 3752dd87bd1SKumar Thangavel 3762dd87bd1SKumar Thangavel /** @brief D-Bus property constant */ 3772dd87bd1SKumar Thangavel const std::string _hostStateProperty{"CurrentHostState"}; 3782dd87bd1SKumar Thangavel 3792dd87bd1SKumar Thangavel /** @brief The propertiesChanged match */ 380cb356d48SPatrick Williams sdbusplus::bus::match_t _match; 3812dd87bd1SKumar Thangavel }; 3822dd87bd1SKumar Thangavel 383432efeccSMatt Spinler } // namespace phosphor::fan 384