1 /** 2 * Copyright © 2021 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 #pragma once 17 18 #include "sensors.hpp" 19 20 #include <sdbusplus/bus.hpp> 21 #include <sdbusplus/server/object.hpp> 22 #include <xyz/openbmc_project/Association/Definitions/server.hpp> 23 #include <xyz/openbmc_project/Sensor/Value/server.hpp> 24 #include <xyz/openbmc_project/State/Decorator/Availability/server.hpp> 25 #include <xyz/openbmc_project/State/Decorator/OperationalStatus/server.hpp> 26 27 #include <chrono> 28 #include <memory> 29 #include <string> 30 #include <tuple> 31 #include <vector> 32 33 namespace phosphor::power::regulators 34 { 35 36 /** 37 * Define simple name for the generated C++ class that implements the 38 * xyz.openbmc_project.Sensor.Value interface. 39 */ 40 using ValueInterface = sdbusplus::xyz::openbmc_project::Sensor::server::Value; 41 42 /** 43 * Define simple name for the generated C++ class that implements the 44 * xyz.openbmc_project.State.Decorator.OperationalStatus interface. 45 */ 46 using OperationalStatusInterface = sdbusplus::xyz::openbmc_project::State:: 47 Decorator::server::OperationalStatus; 48 49 /** 50 * Define simple name for the generated C++ class that implements the 51 * xyz.openbmc_project.State.Decorator.Availability interface. 52 */ 53 using AvailabilityInterface = 54 sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability; 55 56 /** 57 * Define simple name for the generated C++ class that implements the 58 * xyz.openbmc_project.Association.Definitions interface. 59 */ 60 using AssociationDefinitionsInterface = 61 sdbusplus::xyz::openbmc_project::Association::server::Definitions; 62 63 /** 64 * Define simple name for the sdbusplus object_t class that implements all 65 * the necessary D-Bus interfaces via templates/multiple inheritance. 66 */ 67 using DBusSensorObject = sdbusplus::server::object_t< 68 ValueInterface, OperationalStatusInterface, AvailabilityInterface, 69 AssociationDefinitionsInterface>; 70 71 /** 72 * Define simple name for the generated C++ enum that implements the 73 * valid sensor Unit values on D-Bus. 74 */ 75 using Unit = sdbusplus::xyz::openbmc_project::Sensor::server::Value::Unit; 76 77 /** 78 * Define simple name for the tuple used to create D-Bus associations. 79 */ 80 using AssocationTuple = std::tuple<std::string, std::string, std::string>; 81 82 /** 83 * Root object path for sensors. 84 */ 85 constexpr const char* sensorsObjectPath = "/xyz/openbmc_project/sensors"; 86 87 /** 88 * @class DBusSensor 89 * 90 * This class represents a voltage regulator sensor on D-Bus. 91 * 92 * Each voltage rail in the system may provide multiple types of sensor data, 93 * such as temperature, output voltage, and output current. A DBusSensor tracks 94 * one of these data types for a voltage rail. 95 */ 96 class DBusSensor 97 { 98 public: 99 // Specify which compiler-generated methods we want 100 DBusSensor() = delete; 101 DBusSensor(const DBusSensor&) = delete; 102 DBusSensor(DBusSensor&&) = delete; 103 DBusSensor& operator=(const DBusSensor&) = delete; 104 DBusSensor& operator=(DBusSensor&&) = delete; 105 virtual ~DBusSensor() = default; 106 107 /** 108 * Constructor. 109 * 110 * Throws an exception if an error occurs. 111 * 112 * @param bus D-Bus bus object 113 * @param name sensor name 114 * @param type sensor type 115 * @param value sensor value 116 * @param rail voltage rail associated with this sensor 117 * @param deviceInventoryPath D-Bus inventory path of the voltage regulator 118 * device that produces the rail 119 * @param chassisInventoryPath D-Bus inventory path of the chassis that 120 * contains the voltage regulator device 121 */ 122 explicit DBusSensor(sdbusplus::bus_t& bus, const std::string& name, 123 SensorType type, double value, const std::string& rail, 124 const std::string& deviceInventoryPath, 125 const std::string& chassisInventoryPath); 126 127 /** 128 * Disable this sensor. 129 * 130 * Updates the sensor properties on D-Bus to indicate it is no longer 131 * receiving value updates. 132 * 133 * This method is normally called when the system is being powered off. 134 * Sensors are not read when the system is powered off. 135 */ 136 void disable(); 137 138 /** 139 * Return the last time this sensor was updated. 140 * 141 * @return last update time 142 */ getLastUpdateTime() const143 const std::chrono::system_clock::time_point& getLastUpdateTime() const 144 { 145 return lastUpdateTime; 146 } 147 148 /** 149 * Return the sensor name. 150 * 151 * @return sensor name 152 */ getName() const153 const std::string& getName() const 154 { 155 return name; 156 } 157 158 /** 159 * Return the voltage regulator rail associated with this sensor. 160 * 161 * @return rail 162 */ getRail() const163 const std::string& getRail() const 164 { 165 return rail; 166 } 167 168 /** 169 * Return the sensor type. 170 * 171 * @return sensor type 172 */ getType() const173 SensorType getType() const 174 { 175 return type; 176 } 177 178 /** 179 * Set this sensor to the error state. 180 * 181 * Updates the sensor properties on D-Bus to indicate an error occurred and 182 * the sensor value could not be read. 183 */ 184 void setToErrorState(); 185 186 /** 187 * Set the value of this sensor. 188 * 189 * Do not specify the value NaN. This special value is used internally to 190 * indicate the sensor has been disabled or is in the error state. Call the 191 * disable() or setToErrorState() method instead so that all affected D-Bus 192 * interfaces are updated correctly. 193 * 194 * @param value new sensor value 195 */ 196 void setValue(double value); 197 198 private: 199 /** 200 * Sensor value update policy. 201 * 202 * Determines whether a new sensor value should replace the current value on 203 * D-Bus. 204 */ 205 enum class ValueUpdatePolicy : unsigned char 206 { 207 /** 208 * Hysteresis value update policy. 209 * 210 * The sensor value will only be updated if the new value differs from 211 * the current value by at least the hysteresis amount. This avoids 212 * constant D-Bus traffic due to insignificant value changes. 213 */ 214 hysteresis, 215 216 /** 217 * Highest value update policy. 218 * 219 * The sensor value will only be updated if the new value is higher than 220 * the current value. 221 * 222 * Some sensors contain the highest value observed by the voltage 223 * regulator, such as the highest temperature or highest output voltage. 224 * The regulator internally calculates this value since it can poll the 225 * value very quickly and can catch transient events. 226 * 227 * When the sensor is read from the regulator, the regulator will often 228 * clear its internal value. It will begin calculating a new highest 229 * value. For this reason, the D-Bus sensor value is set to the highest 230 * value that has been read across all monitoring cycles. 231 * 232 * The D-Bus sensor value is cleared when the sensor is disabled. This 233 * normally occurs when the system is powered off. Thus, the D-Bus 234 * sensor value is normally the highest value read since the system was 235 * powered on. 236 */ 237 highest, 238 239 /** 240 * Lowest value update policy. 241 * 242 * The sensor value will only be updated if the new value is lower than 243 * the current value. 244 * 245 * Some sensors contain the lowest value observed by the voltage 246 * regulator, such as the lowest output current or lowest output 247 * voltage. The regulator internally calculates this value since it can 248 * poll the value very quickly and can catch transient events. 249 * 250 * When the sensor is read from the regulator, the regulator will often 251 * clear its internal value. It will begin calculating a new lowest 252 * value. For this reason, the D-Bus sensor value is set to the lowest 253 * value that has been read across all monitoring cycles. 254 * 255 * The D-Bus sensor value is cleared when the sensor is disabled. This 256 * normally occurs when the system is powered off. Thus, the D-Bus 257 * sensor value is normally the lowest value read since the system was 258 * powered on. 259 */ 260 lowest 261 }; 262 263 /** 264 * Get the D-Bus associations to create for this sensor. 265 * 266 * @param deviceInventoryPath D-Bus inventory path of the voltage regulator 267 * device that produces the rail 268 * @param chassisInventoryPath D-Bus inventory path of the chassis that 269 * contains the voltage regulator device 270 */ 271 std::vector<AssocationTuple> 272 getAssociations(const std::string& deviceInventoryPath, 273 const std::string& chassisInventoryPath); 274 275 /** 276 * Get sensor properties that are based on the sensor type. 277 * 278 * The properties are returned in output parameters. 279 * 280 * Also initializes some data members whose value is based on the sensor 281 * type. 282 * 283 * @param objectPath returns the object path of this sensor 284 * @param unit returns the D-Bus unit for the sensor value 285 * @param minValue returns the minimum sensor value 286 * @param maxValue returns the maximum sensor value 287 */ 288 void getTypeBasedProperties(std::string& objectPath, Unit& unit, 289 double& minValue, double& maxValue); 290 291 /** 292 * Set the last time this sensor was updated. 293 */ setLastUpdateTime()294 void setLastUpdateTime() 295 { 296 lastUpdateTime = std::chrono::system_clock::now(); 297 } 298 299 /** 300 * Set the sensor value on D-Bus to NaN. 301 */ 302 void setValueToNaN(); 303 304 /** 305 * Returns whether to update the sensor value on D-Bus with the specified 306 * new value. 307 * 308 * @param value new sensor value 309 * @return true if value should be updated on D-Bus, false otherwise 310 */ 311 bool shouldUpdateValue(double value); 312 313 /** 314 * D-Bus bus object. 315 */ 316 sdbusplus::bus_t& bus; 317 318 /** 319 * Sensor name. 320 */ 321 std::string name{}; 322 323 /** 324 * Sensor type. 325 */ 326 SensorType type; 327 328 /** 329 * Voltage regulator rail associated with this sensor. 330 */ 331 std::string rail{}; 332 333 /** 334 * Sensor value update policy. 335 */ 336 ValueUpdatePolicy updatePolicy{ValueUpdatePolicy::hysteresis}; 337 338 /** 339 * Hysteresis value. 340 * 341 * Only used when updatePolicy is hysteresis. 342 */ 343 double hysteresis{0.0}; 344 345 /** 346 * sdbusplus object_t class that implements all the necessary D-Bus 347 * interfaces via templates and multiple inheritance. 348 */ 349 std::unique_ptr<DBusSensorObject> dbusObject{}; 350 351 /** 352 * Last time this sensor was updated. 353 */ 354 std::chrono::system_clock::time_point lastUpdateTime{}; 355 }; 356 357 } // namespace phosphor::power::regulators 358