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