1 #pragma once 2 3 #include "common/types.hpp" 4 #include "common/utils.hpp" 5 6 #include <libpldm/platform.h> 7 #include <libpldm/pldm.h> 8 9 #include <sdbusplus/server/object.hpp> 10 #include <xyz/openbmc_project/Association/Definitions/server.hpp> 11 #include <xyz/openbmc_project/Inventory/Source/PLDM/Entity/server.hpp> 12 #include <xyz/openbmc_project/Metric/Value/server.hpp> 13 #include <xyz/openbmc_project/Sensor/Threshold/Critical/server.hpp> 14 #include <xyz/openbmc_project/Sensor/Threshold/HardShutdown/server.hpp> 15 #include <xyz/openbmc_project/Sensor/Threshold/Warning/server.hpp> 16 #include <xyz/openbmc_project/Sensor/Value/server.hpp> 17 #include <xyz/openbmc_project/State/Decorator/Availability/server.hpp> 18 #include <xyz/openbmc_project/State/Decorator/OperationalStatus/server.hpp> 19 20 #include <string> 21 22 namespace pldm 23 { 24 namespace platform_mc 25 { 26 27 using SensorUnit = sdbusplus::xyz::openbmc_project::Sensor::server::Value::Unit; 28 using ValueIntf = sdbusplus::server::object_t< 29 sdbusplus::xyz::openbmc_project::Sensor::server::Value>; 30 using MetricUnit = sdbusplus::xyz::openbmc_project::Metric::server::Value::Unit; 31 using MetricIntf = sdbusplus::server::object_t< 32 sdbusplus::xyz::openbmc_project::Metric::server::Value>; 33 using ThresholdWarningIntf = sdbusplus::server::object_t< 34 sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Warning>; 35 using ThresholdCriticalIntf = sdbusplus::server::object_t< 36 sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Critical>; 37 using ThresholdHardShutdownIntf = sdbusplus::server::object_t< 38 sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::HardShutdown>; 39 using OperationalStatusIntf = 40 sdbusplus::server::object_t<sdbusplus::xyz::openbmc_project::State:: 41 Decorator::server::OperationalStatus>; 42 using AvailabilityIntf = sdbusplus::server::object_t< 43 sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability>; 44 using AssociationDefinitionsInft = sdbusplus::server::object_t< 45 sdbusplus::xyz::openbmc_project::Association::server::Definitions>; 46 using EntityIntf = sdbusplus::server::object_t< 47 sdbusplus::xyz::openbmc_project::Inventory::Source::PLDM::server::Entity>; 48 49 /** 50 * @brief NumericSensor 51 * 52 * This class handles sensor reading updated by sensor manager and export 53 * status to D-Bus interface. 54 */ 55 class NumericSensor 56 { 57 public: 58 NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, 59 std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, 60 std::string& sensorName, std::string& associationPath); 61 62 NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, 63 std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr, 64 std::string& sensorName, std::string& associationPath); 65 ~NumericSensor()66 ~NumericSensor() {}; 67 68 /** @brief The function called by Sensor Manager to set sensor to 69 * error status. 70 */ 71 void handleErrGetSensorReading(); 72 73 /** @brief Updating the sensor status to D-Bus interface 74 */ 75 void updateReading(bool available, bool functional, double value = 0); 76 77 /** @brief ConversionFormula is used to convert raw value to the unit 78 * specified in PDR 79 * 80 * @param[in] value - raw value 81 * @return double - converted value 82 */ 83 double conversionFormula(double value); 84 85 /** @brief UnitModifier is used to apply the unit modifier specified in PDR 86 * 87 * @param[in] value - raw value 88 * @return double - converted value 89 */ 90 double unitModifier(double value); 91 92 /** @brief Check if value is over threshold. 93 * 94 * @param[in] alarm - previous alarm state 95 * @param[in] direction - upper or lower threshold checking 96 * @param[in] value - raw value 97 * @param[in] threshold - threshold value 98 * @param[in] hyst - hysteresis value 99 * @return bool - new alarm state 100 */ 101 bool checkThreshold(bool alarm, bool direction, double value, 102 double threshold, double hyst); 103 104 /** @brief Updating the association to D-Bus interface 105 * @param[in] inventoryPath - inventory path of the entity 106 */ setInventoryPath(const std::string & inventoryPath)107 inline void setInventoryPath(const std::string& inventoryPath) 108 { 109 if (associationDefinitionsIntf) 110 { 111 associationDefinitionsIntf->associations( 112 {{"chassis", "all_sensors", inventoryPath}}); 113 } 114 } 115 116 /** @brief Get Upper Critical threshold 117 * 118 * @return double - Upper Critical threshold 119 */ getThresholdUpperCritical()120 double getThresholdUpperCritical() 121 { 122 if (thresholdCriticalIntf) 123 { 124 return thresholdCriticalIntf->criticalHigh(); 125 } 126 else 127 { 128 return std::numeric_limits<double>::quiet_NaN(); 129 } 130 }; 131 132 /** @brief Get Lower Critical threshold 133 * 134 * @return double - Lower Critical threshold 135 */ getThresholdLowerCritical()136 double getThresholdLowerCritical() 137 { 138 if (thresholdCriticalIntf) 139 { 140 return thresholdCriticalIntf->criticalLow(); 141 } 142 else 143 { 144 return std::numeric_limits<double>::quiet_NaN(); 145 } 146 }; 147 148 /** @brief Get Upper Warning threshold 149 * 150 * @return double - Upper Warning threshold 151 */ getThresholdUpperWarning()152 double getThresholdUpperWarning() 153 { 154 if (thresholdWarningIntf) 155 { 156 return thresholdWarningIntf->warningHigh(); 157 } 158 else 159 { 160 return std::numeric_limits<double>::quiet_NaN(); 161 } 162 }; 163 164 /** @brief Get Lower Warning threshold 165 * 166 * @return double - Lower Warning threshold 167 */ getThresholdLowerWarning()168 double getThresholdLowerWarning() 169 { 170 if (thresholdWarningIntf) 171 { 172 return thresholdWarningIntf->warningLow(); 173 } 174 else 175 { 176 return std::numeric_limits<double>::quiet_NaN(); 177 } 178 }; 179 180 /** @brief Get Upper HardShutdown threshold 181 * 182 * @return double - Upper HardShutdown threshold 183 */ getThresholdUpperHardShutdown()184 double getThresholdUpperHardShutdown() 185 { 186 if (thresholdHardShutdownIntf) 187 { 188 return thresholdHardShutdownIntf->hardShutdownHigh(); 189 } 190 else 191 { 192 return std::numeric_limits<double>::quiet_NaN(); 193 } 194 }; 195 196 /** @brief Get Lower HardShutdown threshold 197 * 198 * @return double - Lower HardShutdown threshold 199 */ getThresholdLowerHardShutdown()200 double getThresholdLowerHardShutdown() 201 { 202 if (thresholdHardShutdownIntf) 203 { 204 return thresholdHardShutdownIntf->hardShutdownLow(); 205 } 206 else 207 { 208 return std::numeric_limits<double>::quiet_NaN(); 209 } 210 }; 211 212 /** @brief Get threshold given level and direction 213 * 214 * @param[in] level - The threshold level (WARNING/CRITICAL/etc) 215 * @param[in] direction - The threshold direction (HIGH/LOW) 216 * 217 * @return double - The requested threshold. 218 */ getThreshold(pldm::utils::Level level,pldm::utils::Direction direction)219 double getThreshold(pldm::utils::Level level, 220 pldm::utils::Direction direction) 221 { 222 if (direction != pldm::utils::Direction::HIGH && 223 direction != pldm::utils::Direction::LOW) 224 { 225 return std::numeric_limits<double>::quiet_NaN(); 226 } 227 switch (level) 228 { 229 case pldm::utils::Level::WARNING: 230 return direction == pldm::utils::Direction::HIGH 231 ? getThresholdUpperWarning() 232 : getThresholdLowerWarning(); 233 case pldm::utils::Level::CRITICAL: 234 return direction == pldm::utils::Direction::HIGH 235 ? getThresholdUpperCritical() 236 : getThresholdLowerCritical(); 237 case pldm::utils::Level::HARDSHUTDOWN: 238 return direction == pldm::utils::Direction::HIGH 239 ? getThresholdUpperHardShutdown() 240 : getThresholdLowerHardShutdown(); 241 default: 242 break; 243 } 244 return std::numeric_limits<double>::quiet_NaN(); 245 } 246 247 /* @brief returns true if the given threshold at level/direction is defined. 248 * 249 * @param[in] level - The threshold level (WARNING/CRITICAL/etc) 250 * @param[in] direction - The threshold direction (HIGH/LOW) 251 * 252 * @return true if the threshold is valid 253 */ isThresholdValid(pldm::utils::Level level,pldm::utils::Direction direction)254 bool isThresholdValid(pldm::utils::Level level, 255 pldm::utils::Direction direction) 256 { 257 return std::isfinite(getThreshold(level, direction)); 258 } 259 260 /* @brief Get the alarm status of the given threshold 261 * 262 * @param[in] level - The threshold level (WARNING/CRITICAL/etc) 263 * @param[in] direction - The threshold direction (HIGH/LOW) 264 * 265 * @return true if the current alarm status is asserted. 266 */ getThresholdAlarm(pldm::utils::Level level,pldm::utils::Direction direction)267 bool getThresholdAlarm(pldm::utils::Level level, 268 pldm::utils::Direction direction) 269 { 270 if (!isThresholdValid(level, direction)) 271 { 272 return false; 273 } 274 switch (level) 275 { 276 case pldm::utils::Level::WARNING: 277 return direction == pldm::utils::Direction::HIGH 278 ? thresholdWarningIntf->warningAlarmHigh() 279 : thresholdWarningIntf->warningAlarmLow(); 280 case pldm::utils::Level::CRITICAL: 281 return direction == pldm::utils::Direction::HIGH 282 ? thresholdCriticalIntf->criticalAlarmHigh() 283 : thresholdCriticalIntf->criticalAlarmLow(); 284 case pldm::utils::Level::HARDSHUTDOWN: 285 return direction == pldm::utils::Direction::HIGH 286 ? thresholdHardShutdownIntf->hardShutdownAlarmHigh() 287 : thresholdHardShutdownIntf->hardShutdownAlarmLow(); 288 default: 289 break; 290 } 291 return false; 292 } 293 294 /* @brief Returns true if at least one threshold alarm is set 295 * 296 * @return true if at least one threshold alarm is set 297 */ 298 bool hasThresholdAlarm(); 299 300 /* @brief raises the alarm on the warning threshold 301 * 302 * @param[in] direction - The threshold direction (HIGH/LOW) 303 * @param[in] value - The current numeric sensor reading 304 * @param[in] asserted - true if we want to set the alarm, false 305 * if we want to clear it. 306 * 307 * @return PLDM_SUCCESS or a valid error code. 308 */ 309 void setWarningThresholdAlarm(pldm::utils::Direction direction, 310 double value, bool asserted); 311 312 /* @brief raises the alarm on the critical threshold 313 * 314 * @param[in] direction - The threshold direction (HIGH/LOW) 315 * @param[in] value - The current numeric sensor reading 316 * @param[in] asserted - true if we want to set the alarm, false 317 * if we want to clear it. 318 * 319 * @return PLDM_SUCCESS or a valid error code. 320 */ 321 void setCriticalThresholdAlarm(pldm::utils::Direction direction, 322 double value, bool asserted); 323 324 /* @brief raises the alarm on the hard-shutdown threshold 325 * 326 * @param[in] direction - The threshold direction (HIGH/LOW) 327 * @param[in] value - The current numeric sensor reading 328 * @param[in] asserted - true if we want to set the alarm, false 329 * if we want to clear it. 330 * 331 * @return PLDM_SUCCESS or a valid error code. 332 */ 333 void setHardShutdownThresholdAlarm(pldm::utils::Direction direction, 334 double value, bool asserted); 335 336 /* @brief raises the alarm on the threshold 337 * 338 * @param[in] level - The threshold level (WARNING/CRITICAL/etc) 339 * @param[in] direction - The threshold direction (HIGH/LOW) 340 * @param[in] value - The current numeric sensor reading 341 * @param[in] asserted - true if we want to set the alarm, false 342 * if we want to clear it. 343 * 344 * @return PLDM_SUCCESS or a valid error code. 345 */ 346 int setThresholdAlarm(pldm::utils::Level level, 347 pldm::utils::Direction direction, double value, 348 bool asserted); 349 350 /** @brief Check if value is over threshold. 351 * 352 * @param[in] eventType - event level in pldm::utils::Level 353 * @param[in] direction - direction type in pldm::utils::Direction 354 * @param[in] rawValue - sensor raw value 355 * @param[in] newAlarm - trigger alarm true/false 356 * @param[in] assert - event type asserted/deasserted 357 * 358 * @return PLDM completion code 359 */ 360 int triggerThresholdEvent(pldm::utils::Level eventType, 361 pldm::utils::Direction direction, double rawValue, 362 bool newAlarm, bool assert); 363 364 /** @brief Terminus ID which the sensor belongs to */ 365 pldm_tid_t tid; 366 367 /** @brief Sensor ID */ 368 uint16_t sensorId; 369 370 /** @brief The time stamp since last getSensorReading command in usec */ 371 uint64_t timeStamp; 372 373 /** @brief The time of sensor update interval in usec */ 374 uint64_t updateTime; 375 376 /** @brief sensorName */ 377 std::string sensorName; 378 379 /** @brief sensorNameSpace */ 380 std::string sensorNameSpace; 381 382 /** @brief Sensor Unit */ 383 SensorUnit sensorUnit; 384 385 private: 386 /** 387 * @brief resolve and clear a log entry 388 * 389 * @param[inout] log - dbus path to log entry. The log will be resolve 390 * and the optional reset. 391 */ 392 void clearThresholdLog(std::optional<sdbusplus::message::object_path>& log); 393 394 /** @brief create a log entry that all sensor alarms have cleared and is now 395 * operating in the normal operating range. 396 * 397 * @param[in] value - The current sensor value in normal range. 398 */ 399 void createNormalRangeLog(double value); 400 401 /** 402 * @brief Create a threshold log for the given level/direction tuple. 403 * 404 * @param[in] level - The level of the threshold. 405 * @param[in] direction - The direction of the threshold. 406 * @param[in] value - The current sensor value. 407 */ 408 void createThresholdLog(pldm::utils::Level level, 409 pldm::utils::Direction direction, double value); 410 411 /** 412 * @brief Check sensor reading if any threshold has been crossed and update 413 * Threshold interfaces accordingly 414 */ 415 void updateThresholds(); 416 417 /** 418 * @brief Update the object units based on the PDR baseUnit 419 */ 420 void setSensorUnit(uint8_t baseUnit); 421 422 /** @brief Create the sensor inventory path. 423 * 424 * @param[in] associationPath - sensor association path 425 * @param[in] sensorName - sensor name 426 * @param[in] entityType - sensor PDR entity type 427 * @param[in] entityInstanceNum - sensor PDR entity instance number 428 * @param[in] containerId - sensor PDR entity container ID 429 * 430 * @return True when success otherwise return False 431 */ 432 inline bool createInventoryPath( 433 const std::string& associationPath, const std::string& sensorName, 434 const uint16_t entityType, const uint16_t entityInstanceNum, 435 const uint16_t containerId); 436 437 std::unique_ptr<MetricIntf> metricIntf = nullptr; 438 std::unique_ptr<ValueIntf> valueIntf = nullptr; 439 std::unique_ptr<ThresholdWarningIntf> thresholdWarningIntf = nullptr; 440 std::unique_ptr<ThresholdCriticalIntf> thresholdCriticalIntf = nullptr; 441 std::unique_ptr<ThresholdHardShutdownIntf> thresholdHardShutdownIntf = 442 nullptr; 443 std::unique_ptr<AvailabilityIntf> availabilityIntf = nullptr; 444 std::unique_ptr<OperationalStatusIntf> operationalStatusIntf = nullptr; 445 std::unique_ptr<AssociationDefinitionsInft> associationDefinitionsIntf = 446 nullptr; 447 std::unique_ptr<EntityIntf> entityIntf = nullptr; 448 449 /** @brief Amount of hysteresis associated with the sensor thresholds */ 450 double hysteresis; 451 452 /** @brief The resolution of sensor in Units */ 453 double resolution; 454 455 /** @brief A constant value that is added in as part of conversion process 456 * of converting a raw sensor reading to Units */ 457 double offset; 458 459 /** @brief A power-of-10 multiplier for baseUnit */ 460 int8_t baseUnitModifier; 461 bool useMetricInterface = false; 462 463 /** @brief An internal mapping of thresholds and its associated log 464 * entry. */ 465 std::map<std::tuple<pldm::utils::Level, pldm::utils::Direction>, 466 std::optional<sdbusplus::message::object_path>> 467 assertedLog; 468 }; 469 } // namespace platform_mc 470 } // namespace pldm 471