xref: /openbmc/phosphor-power/chassis_status_monitor.cpp (revision b0f94e07b98fba012040c311c6e2789c6141c028)
1 /**
2  * Copyright © 2025 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "chassis_status_monitor.hpp"
18 
19 #include "types.hpp"
20 
21 #include <format>
22 
23 namespace phosphor::power::util
24 {
25 
26 constexpr auto INVENTORY_MGR_SERVICE = "xyz.openbmc_project.Inventory.Manager";
27 constexpr auto POWER_SEQUENCER_SERVICE = "org.openbmc.control.Power";
28 constexpr auto CHASSIS_INPUT_POWER_SERVICE =
29     "xyz.openbmc_project.Power.Chassis";
30 constexpr auto POWER_SUPPLY_SERVICE = "xyz.openbmc_project.Power.PSUMonitor";
31 
32 constexpr auto CHASSIS_POWER_PATH = "/org/openbmc/control/power{}";
33 constexpr auto CHASSIS_INPUT_POWER_STATUS_PATH =
34     "/xyz/openbmc_project/power/chassis/chassis{}";
35 constexpr auto POWER_SUPPLIES_STATUS_PATH =
36     "/xyz/openbmc_project/power/power_supplies/chassis{}/psus";
37 
38 BMCChassisStatusMonitor::BMCChassisStatusMonitor(
39     sdbusplus::bus_t& bus, size_t number, const std::string& inventoryPath,
40     const ChassisStatusMonitorOptions& options) :
41     bus{bus}, number{number}, inventoryPath{inventoryPath}, options{options}
42 {
43     chassisPowerPath = std::format(CHASSIS_POWER_PATH, number);
44     chassisInputPowerStatusPath =
45         std::format(CHASSIS_INPUT_POWER_STATUS_PATH, number);
46     powerSuppliesStatusPath = std::format(POWER_SUPPLIES_STATUS_PATH, number);
47     addMatches();
48     getAllProperties();
49 }
50 
51 void BMCChassisStatusMonitor::addMatches()
52 {
53     if (options.isPresentMonitored || options.isAvailableMonitored ||
54         options.isEnabledMonitored)
55     {
56         addNameOwnerChangedMatch(INVENTORY_MGR_SERVICE);
57         addInterfacesAddedMatch(inventoryPath);
58         if (options.isPresentMonitored)
59         {
60             addPropertiesChangedMatch(inventoryPath, INVENTORY_IFACE);
61         }
62         if (options.isAvailableMonitored)
63         {
64             addPropertiesChangedMatch(inventoryPath, AVAILABILITY_IFACE);
65         }
66         if (options.isEnabledMonitored)
67         {
68             addPropertiesChangedMatch(inventoryPath, ENABLE_IFACE);
69         }
70     }
71 
72     if (options.isPowerStateMonitored || options.isPowerGoodMonitored)
73     {
74         addNameOwnerChangedMatch(POWER_SEQUENCER_SERVICE);
75         addInterfacesAddedMatch(chassisPowerPath);
76         addPropertiesChangedMatch(chassisPowerPath, POWER_IFACE);
77     }
78 
79     if (options.isInputPowerStatusMonitored)
80     {
81         addNameOwnerChangedMatch(CHASSIS_INPUT_POWER_SERVICE);
82         addInterfacesAddedMatch(chassisInputPowerStatusPath);
83         addPropertiesChangedMatch(chassisInputPowerStatusPath,
84                                   POWER_SYSTEM_INPUTS_IFACE);
85     }
86 
87     if (options.isPowerSuppliesStatusMonitored)
88     {
89         addNameOwnerChangedMatch(POWER_SUPPLY_SERVICE);
90         addInterfacesAddedMatch(powerSuppliesStatusPath);
91         addPropertiesChangedMatch(powerSuppliesStatusPath,
92                                   POWER_SYSTEM_INPUTS_IFACE);
93     }
94 }
95 
96 template <typename T>
97 void BMCChassisStatusMonitor::getProperty(
98     const std::string& service, const std::string& path,
99     const std::string& interface, const std::string& propertyName,
100     std::optional<T>& optionalValue)
101 {
102     try
103     {
104         T value;
105         util::getProperty(interface, propertyName, path, service, bus, value);
106         optionalValue = value;
107     }
108     catch (...)
109     {}
110 }
111 
112 void BMCChassisStatusMonitor::getInventoryManagerProperties()
113 {
114     if (options.isPresentMonitored)
115     {
116         getProperty(INVENTORY_MGR_SERVICE, inventoryPath, INVENTORY_IFACE,
117                     PRESENT_PROP, isPresentValue);
118     }
119 
120     if (options.isAvailableMonitored)
121     {
122         getProperty(INVENTORY_MGR_SERVICE, inventoryPath, AVAILABILITY_IFACE,
123                     AVAILABLE_PROP, isAvailableValue);
124     }
125 
126     if (options.isEnabledMonitored)
127     {
128         getProperty(INVENTORY_MGR_SERVICE, inventoryPath, ENABLE_IFACE,
129                     ENABLED_PROP, isEnabledValue);
130     }
131 }
132 
133 void BMCChassisStatusMonitor::getPowerSequencerProperties()
134 {
135     if (options.isPowerStateMonitored)
136     {
137         getProperty(POWER_SEQUENCER_SERVICE, chassisPowerPath, POWER_IFACE,
138                     POWER_STATE_PROP, powerStateValue);
139     }
140 
141     if (options.isPowerGoodMonitored)
142     {
143         getProperty(POWER_SEQUENCER_SERVICE, chassisPowerPath, POWER_IFACE,
144                     POWER_GOOD_PROP, powerGoodValue);
145     }
146 }
147 
148 void BMCChassisStatusMonitor::getChassisInputPowerProperties()
149 {
150     if (options.isInputPowerStatusMonitored)
151     {
152         getProperty(CHASSIS_INPUT_POWER_SERVICE, chassisInputPowerStatusPath,
153                     POWER_SYSTEM_INPUTS_IFACE, STATUS_PROP,
154                     inputPowerStatusValue);
155     }
156 }
157 
158 void BMCChassisStatusMonitor::getPowerSupplyProperties()
159 {
160     if (options.isPowerSuppliesStatusMonitored)
161     {
162         getProperty(POWER_SUPPLY_SERVICE, powerSuppliesStatusPath,
163                     POWER_SYSTEM_INPUTS_IFACE, STATUS_PROP,
164                     powerSuppliesStatusValue);
165     }
166 }
167 
168 template <typename T>
169 void BMCChassisStatusMonitor::storeProperty(const DbusPropertyMap& properties,
170                                             const std::string& propertyName,
171                                             std::optional<T>& optionalValue)
172 {
173     try
174     {
175         auto it = properties.find(propertyName);
176         if (it != properties.end())
177         {
178             optionalValue = std::get<T>(it->second);
179         }
180     }
181     catch (...)
182     {}
183 }
184 
185 void BMCChassisStatusMonitor::storeProperties(const DbusPropertyMap& properties,
186                                               const std::string& path,
187                                               const std::string& interface)
188 {
189     try
190     {
191         if (interface == INVENTORY_IFACE)
192         {
193             storeProperty(properties, PRESENT_PROP, isPresentValue);
194         }
195         else if (interface == AVAILABILITY_IFACE)
196         {
197             storeProperty(properties, AVAILABLE_PROP, isAvailableValue);
198         }
199         else if (interface == ENABLE_IFACE)
200         {
201             storeProperty(properties, ENABLED_PROP, isEnabledValue);
202         }
203         else if (interface == POWER_IFACE)
204         {
205             storeProperty(properties, POWER_STATE_PROP, powerStateValue);
206             storeProperty(properties, POWER_GOOD_PROP, powerGoodValue);
207         }
208         else if (interface == POWER_SYSTEM_INPUTS_IFACE)
209         {
210             if (path == chassisInputPowerStatusPath)
211             {
212                 storeProperty(properties, STATUS_PROP, inputPowerStatusValue);
213             }
214             else if (path == powerSuppliesStatusPath)
215             {
216                 storeProperty(properties, STATUS_PROP,
217                               powerSuppliesStatusValue);
218             }
219         }
220     }
221     catch (...)
222     {}
223 }
224 
225 void BMCChassisStatusMonitor::nameOwnerChangedCallback(
226     sdbusplus::message_t& message)
227 {
228     try
229     {
230         std::string name, oldOwner, newOwner;
231         message.read(name, oldOwner, newOwner);
232         if (!newOwner.empty())
233         {
234             if (name == INVENTORY_MGR_SERVICE)
235             {
236                 getInventoryManagerProperties();
237             }
238             else if (name == POWER_SEQUENCER_SERVICE)
239             {
240                 getPowerSequencerProperties();
241             }
242             else if (name == CHASSIS_INPUT_POWER_SERVICE)
243             {
244                 getChassisInputPowerProperties();
245             }
246             else if (name == POWER_SUPPLY_SERVICE)
247             {
248                 getPowerSupplyProperties();
249             }
250         }
251     }
252     catch (...)
253     {}
254 }
255 
256 void BMCChassisStatusMonitor::interfacesAddedCallback(
257     sdbusplus::message_t& message)
258 {
259     try
260     {
261         sdbusplus::message::object_path path;
262         std::map<std::string, DbusPropertyMap> interfaces;
263         message.read(path, interfaces);
264         for (const auto& [interface, properties] : interfaces)
265         {
266             storeProperties(properties, path, interface);
267         }
268     }
269     catch (...)
270     {}
271 }
272 
273 void BMCChassisStatusMonitor::propertiesChangedCallback(
274     sdbusplus::message_t& message)
275 {
276     try
277     {
278         std::string interface;
279         DbusPropertyMap changedProperties;
280         std::vector<std::string> invalidatedProperties;
281         message.read(interface, changedProperties, invalidatedProperties);
282         storeProperties(changedProperties, message.get_path(), interface);
283     }
284     catch (...)
285     {}
286 }
287 
288 } // namespace phosphor::power::util
289