1*e1fa8594SPotin Lai #pragma once
2*e1fa8594SPotin Lai
3*e1fa8594SPotin Lai #include <boost/container/flat_map.hpp>
4*e1fa8594SPotin Lai #include <sdbusplus/bus.hpp>
5*e1fa8594SPotin Lai #include <sdbusplus/bus/match.hpp>
6*e1fa8594SPotin Lai #include <sdbusplus/message.hpp>
7*e1fa8594SPotin Lai
8*e1fa8594SPotin Lai #include <functional>
9*e1fa8594SPotin Lai #include <iostream>
10*e1fa8594SPotin Lai #include <memory>
11*e1fa8594SPotin Lai #include <string>
12*e1fa8594SPotin Lai #include <variant>
13*e1fa8594SPotin Lai
14*e1fa8594SPotin Lai constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
15*e1fa8594SPotin Lai constexpr const char* HOST_STATE_BUSNAME = "xyz.openbmc_project.State.Host0";
16*e1fa8594SPotin Lai constexpr const char* HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
17*e1fa8594SPotin Lai constexpr const char* HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
18*e1fa8594SPotin Lai constexpr const char* CURRENT_HOST_STATE_PROPERTY = "CurrentHostState";
19*e1fa8594SPotin Lai
20*e1fa8594SPotin Lai class HostStateMonitor
21*e1fa8594SPotin Lai {
22*e1fa8594SPotin Lai public:
23*e1fa8594SPotin Lai static HostStateMonitor& getInstance();
24*e1fa8594SPotin Lai static HostStateMonitor& getInstance(sdbusplus::bus_t& bus);
25*e1fa8594SPotin Lai
26*e1fa8594SPotin Lai ~HostStateMonitor() = default;
27*e1fa8594SPotin Lai
28*e1fa8594SPotin Lai // Delete copy constructor and assignment operator
29*e1fa8594SPotin Lai HostStateMonitor(const HostStateMonitor&) = delete;
30*e1fa8594SPotin Lai HostStateMonitor& operator=(const HostStateMonitor&) = delete;
31*e1fa8594SPotin Lai
32*e1fa8594SPotin Lai // Delete move constructor and assignment operator for singleton
33*e1fa8594SPotin Lai HostStateMonitor(HostStateMonitor&&) = delete;
34*e1fa8594SPotin Lai HostStateMonitor& operator=(HostStateMonitor&&) = delete;
35*e1fa8594SPotin Lai
36*e1fa8594SPotin Lai void startMonitoring();
37*e1fa8594SPotin Lai void stopMonitoring();
isPowerOn() const38*e1fa8594SPotin Lai bool isPowerOn() const
39*e1fa8594SPotin Lai {
40*e1fa8594SPotin Lai return powerStatusOn;
41*e1fa8594SPotin Lai }
42*e1fa8594SPotin Lai
43*e1fa8594SPotin Lai private:
44*e1fa8594SPotin Lai explicit HostStateMonitor(sdbusplus::bus_t& bus);
45*e1fa8594SPotin Lai
46*e1fa8594SPotin Lai void handleStateChange(sdbusplus::message_t& message);
47*e1fa8594SPotin Lai void getInitialState();
48*e1fa8594SPotin Lai
49*e1fa8594SPotin Lai sdbusplus::bus_t& bus;
50*e1fa8594SPotin Lai bool powerStatusOn;
51*e1fa8594SPotin Lai std::unique_ptr<sdbusplus::bus::match_t> hostStateMatch;
52*e1fa8594SPotin Lai };
53*e1fa8594SPotin Lai
54*e1fa8594SPotin Lai // Implementation
getInstance()55*e1fa8594SPotin Lai inline HostStateMonitor& HostStateMonitor::getInstance()
56*e1fa8594SPotin Lai {
57*e1fa8594SPotin Lai static sdbusplus::bus_t defaultBus = sdbusplus::bus::new_default();
58*e1fa8594SPotin Lai return getInstance(defaultBus);
59*e1fa8594SPotin Lai }
60*e1fa8594SPotin Lai
getInstance(sdbusplus::bus_t & bus)61*e1fa8594SPotin Lai inline HostStateMonitor& HostStateMonitor::getInstance(sdbusplus::bus_t& bus)
62*e1fa8594SPotin Lai {
63*e1fa8594SPotin Lai static HostStateMonitor instance(bus);
64*e1fa8594SPotin Lai return instance;
65*e1fa8594SPotin Lai }
66*e1fa8594SPotin Lai
HostStateMonitor(sdbusplus::bus_t & bus)67*e1fa8594SPotin Lai inline HostStateMonitor::HostStateMonitor(sdbusplus::bus_t& bus) :
68*e1fa8594SPotin Lai bus(bus), powerStatusOn(false), hostStateMatch(nullptr)
69*e1fa8594SPotin Lai {
70*e1fa8594SPotin Lai getInitialState();
71*e1fa8594SPotin Lai }
72*e1fa8594SPotin Lai
startMonitoring()73*e1fa8594SPotin Lai inline void HostStateMonitor::startMonitoring()
74*e1fa8594SPotin Lai {
75*e1fa8594SPotin Lai if (hostStateMatch == nullptr)
76*e1fa8594SPotin Lai {
77*e1fa8594SPotin Lai using namespace sdbusplus::bus::match::rules;
78*e1fa8594SPotin Lai
79*e1fa8594SPotin Lai hostStateMatch = std::make_unique<sdbusplus::bus::match_t>(
80*e1fa8594SPotin Lai bus,
81*e1fa8594SPotin Lai propertiesChangedNamespace(HOST_STATE_PATH, HOST_STATE_INTERFACE),
82*e1fa8594SPotin Lai [this](sdbusplus::message_t& message) {
83*e1fa8594SPotin Lai handleStateChange(message);
84*e1fa8594SPotin Lai });
85*e1fa8594SPotin Lai }
86*e1fa8594SPotin Lai }
87*e1fa8594SPotin Lai
stopMonitoring()88*e1fa8594SPotin Lai inline void HostStateMonitor::stopMonitoring()
89*e1fa8594SPotin Lai {
90*e1fa8594SPotin Lai hostStateMatch.reset();
91*e1fa8594SPotin Lai }
92*e1fa8594SPotin Lai
handleStateChange(sdbusplus::message_t & message)93*e1fa8594SPotin Lai inline void HostStateMonitor::handleStateChange(sdbusplus::message_t& message)
94*e1fa8594SPotin Lai {
95*e1fa8594SPotin Lai std::string objectName;
96*e1fa8594SPotin Lai boost::container::flat_map<std::string, std::variant<std::string>> values;
97*e1fa8594SPotin Lai
98*e1fa8594SPotin Lai try
99*e1fa8594SPotin Lai {
100*e1fa8594SPotin Lai message.read(objectName, values);
101*e1fa8594SPotin Lai
102*e1fa8594SPotin Lai auto findState = values.find(CURRENT_HOST_STATE_PROPERTY);
103*e1fa8594SPotin Lai if (findState != values.end())
104*e1fa8594SPotin Lai {
105*e1fa8594SPotin Lai const std::string& stateValue =
106*e1fa8594SPotin Lai std::get<std::string>(findState->second);
107*e1fa8594SPotin Lai bool newPowerStatus = stateValue.ends_with(".Running");
108*e1fa8594SPotin Lai
109*e1fa8594SPotin Lai if (newPowerStatus != powerStatusOn)
110*e1fa8594SPotin Lai {
111*e1fa8594SPotin Lai powerStatusOn = newPowerStatus;
112*e1fa8594SPotin Lai }
113*e1fa8594SPotin Lai }
114*e1fa8594SPotin Lai }
115*e1fa8594SPotin Lai catch (const std::exception& e)
116*e1fa8594SPotin Lai {
117*e1fa8594SPotin Lai std::cerr << "Failed to handle host state change: " << e.what()
118*e1fa8594SPotin Lai << std::endl;
119*e1fa8594SPotin Lai }
120*e1fa8594SPotin Lai }
121*e1fa8594SPotin Lai
getInitialState()122*e1fa8594SPotin Lai inline void HostStateMonitor::getInitialState()
123*e1fa8594SPotin Lai {
124*e1fa8594SPotin Lai try
125*e1fa8594SPotin Lai {
126*e1fa8594SPotin Lai auto method = bus.new_method_call(HOST_STATE_BUSNAME, HOST_STATE_PATH,
127*e1fa8594SPotin Lai PROPERTIES_INTERFACE, "Get");
128*e1fa8594SPotin Lai method.append(HOST_STATE_INTERFACE, CURRENT_HOST_STATE_PROPERTY);
129*e1fa8594SPotin Lai
130*e1fa8594SPotin Lai auto reply = bus.call(method);
131*e1fa8594SPotin Lai std::variant<std::string> currentState;
132*e1fa8594SPotin Lai reply.read(currentState);
133*e1fa8594SPotin Lai
134*e1fa8594SPotin Lai const std::string& stateValue = std::get<std::string>(currentState);
135*e1fa8594SPotin Lai powerStatusOn = stateValue.ends_with(".Running");
136*e1fa8594SPotin Lai }
137*e1fa8594SPotin Lai catch (const std::exception& e)
138*e1fa8594SPotin Lai {
139*e1fa8594SPotin Lai powerStatusOn = false;
140*e1fa8594SPotin Lai }
141*e1fa8594SPotin Lai }
142