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