xref: /openbmc/phosphor-pid-control/hoststatemonitor.hpp (revision e1fa85942c66533699a3b785990d95e9c89b6050)
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