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