#pragma once #include "common/types.hpp" #include "common/utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace pldm { namespace platform_mc { constexpr const char* SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value"; constexpr const char* METRIC_VALUE_INTF = "xyz.openbmc_project.Metric.Value"; using SensorUnit = sdbusplus::xyz::openbmc_project::Sensor::server::Value::Unit; using ValueIntf = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Sensor::server::Value>; using MetricUnit = sdbusplus::xyz::openbmc_project::Metric::server::Value::Unit; using MetricIntf = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Metric::server::Value>; using ThresholdWarningIntf = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Warning>; using ThresholdCriticalIntf = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Critical>; using ThresholdHardShutdownIntf = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::HardShutdown>; using OperationalStatusIntf = sdbusplus::server::object_t; using AvailabilityIntf = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability>; using AssociationDefinitionsInft = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Association::server::Definitions>; using EntityIntf = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Inventory::Source::PLDM::server::Entity>; /** * @brief NumericSensor * * This class handles sensor reading updated by sensor manager and export * status to D-Bus interface. */ class NumericSensor { public: NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, std::shared_ptr pdr, std::string& sensorName, std::string& associationPath); NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, std::shared_ptr pdr, std::string& sensorName, std::string& associationPath); ~NumericSensor() {}; /** @brief The function called by Sensor Manager to set sensor to * error status. */ void handleErrGetSensorReading(); /** @brief Updating the sensor status to D-Bus interface */ void updateReading(bool available, bool functional, double value = 0); /** @brief ConversionFormula is used to convert raw value to the unit * specified in PDR * * @param[in] value - raw value * @return double - converted value */ double conversionFormula(double value); /** @brief UnitModifier is used to apply the unit modifier specified in PDR * * @param[in] value - raw value * @return double - converted value */ double unitModifier(double value); /** @brief Check if value is over threshold. * * @param[in] alarm - previous alarm state * @param[in] direction - upper or lower threshold checking * @param[in] value - raw value * @param[in] threshold - threshold value * @param[in] hyst - hysteresis value * @return bool - new alarm state */ bool checkThreshold(bool alarm, bool direction, double value, double threshold, double hyst); /** @brief Updating the association to D-Bus interface * @param[in] inventoryPath - inventory path of the entity */ inline void setInventoryPath(const std::string& inventoryPath) { if (associationDefinitionsIntf) { associationDefinitionsIntf->associations( {{"chassis", "all_sensors", inventoryPath}}); } } /** @brief Get Upper Critical threshold * * @return double - Upper Critical threshold */ double getThresholdUpperCritical() { if (thresholdCriticalIntf) { return thresholdCriticalIntf->criticalHigh(); } else { return std::numeric_limits::quiet_NaN(); } }; /** @brief Get Lower Critical threshold * * @return double - Lower Critical threshold */ double getThresholdLowerCritical() { if (thresholdCriticalIntf) { return thresholdCriticalIntf->criticalLow(); } else { return std::numeric_limits::quiet_NaN(); } }; /** @brief Get Upper Warning threshold * * @return double - Upper Warning threshold */ double getThresholdUpperWarning() { if (thresholdWarningIntf) { return thresholdWarningIntf->warningHigh(); } else { return std::numeric_limits::quiet_NaN(); } }; /** @brief Get Lower Warning threshold * * @return double - Lower Warning threshold */ double getThresholdLowerWarning() { if (thresholdWarningIntf) { return thresholdWarningIntf->warningLow(); } else { return std::numeric_limits::quiet_NaN(); } }; /** @brief Get Upper HardShutdown threshold * * @return double - Upper HardShutdown threshold */ double getThresholdUpperHardShutdown() { if (thresholdHardShutdownIntf) { return thresholdHardShutdownIntf->hardShutdownHigh(); } else { return std::numeric_limits::quiet_NaN(); } }; /** @brief Get Lower HardShutdown threshold * * @return double - Lower HardShutdown threshold */ double getThresholdLowerHardShutdown() { if (thresholdHardShutdownIntf) { return thresholdHardShutdownIntf->hardShutdownLow(); } else { return std::numeric_limits::quiet_NaN(); } }; /** @brief Get threshold given level and direction * * @param[in] level - The threshold level (WARNING/CRITICAL/etc) * @param[in] direction - The threshold direction (HIGH/LOW) * * @return double - The requested threshold. */ double getThreshold(pldm::utils::Level level, pldm::utils::Direction direction) { if (direction != pldm::utils::Direction::HIGH && direction != pldm::utils::Direction::LOW) { return std::numeric_limits::quiet_NaN(); } switch (level) { case pldm::utils::Level::WARNING: return direction == pldm::utils::Direction::HIGH ? getThresholdUpperWarning() : getThresholdLowerWarning(); case pldm::utils::Level::CRITICAL: return direction == pldm::utils::Direction::HIGH ? getThresholdUpperCritical() : getThresholdLowerCritical(); case pldm::utils::Level::HARDSHUTDOWN: return direction == pldm::utils::Direction::HIGH ? getThresholdUpperHardShutdown() : getThresholdLowerHardShutdown(); default: break; } return std::numeric_limits::quiet_NaN(); } /* @brief returns true if the given threshold at level/direction is defined. * * @param[in] level - The threshold level (WARNING/CRITICAL/etc) * @param[in] direction - The threshold direction (HIGH/LOW) * * @return true if the threshold is valid */ bool isThresholdValid(pldm::utils::Level level, pldm::utils::Direction direction) { return std::isfinite(getThreshold(level, direction)); } /* @brief Get the alarm status of the given threshold * * @param[in] level - The threshold level (WARNING/CRITICAL/etc) * @param[in] direction - The threshold direction (HIGH/LOW) * * @return true if the current alarm status is asserted. */ bool getThresholdAlarm(pldm::utils::Level level, pldm::utils::Direction direction) { if (!isThresholdValid(level, direction)) { return false; } switch (level) { case pldm::utils::Level::WARNING: return direction == pldm::utils::Direction::HIGH ? thresholdWarningIntf->warningAlarmHigh() : thresholdWarningIntf->warningAlarmLow(); case pldm::utils::Level::CRITICAL: return direction == pldm::utils::Direction::HIGH ? thresholdCriticalIntf->criticalAlarmHigh() : thresholdCriticalIntf->criticalAlarmLow(); case pldm::utils::Level::HARDSHUTDOWN: return direction == pldm::utils::Direction::HIGH ? thresholdHardShutdownIntf->hardShutdownAlarmHigh() : thresholdHardShutdownIntf->hardShutdownAlarmLow(); default: break; } return false; } /* @brief Returns true if at least one threshold alarm is set * * @return true if at least one threshold alarm is set */ bool hasThresholdAlarm(); /* @brief raises the alarm on the warning threshold * * @param[in] direction - The threshold direction (HIGH/LOW) * @param[in] value - The current numeric sensor reading * @param[in] asserted - true if we want to set the alarm, false * if we want to clear it. * * @return PLDM_SUCCESS or a valid error code. */ void setWarningThresholdAlarm(pldm::utils::Direction direction, double value, bool asserted); /* @brief raises the alarm on the critical threshold * * @param[in] direction - The threshold direction (HIGH/LOW) * @param[in] value - The current numeric sensor reading * @param[in] asserted - true if we want to set the alarm, false * if we want to clear it. * * @return PLDM_SUCCESS or a valid error code. */ void setCriticalThresholdAlarm(pldm::utils::Direction direction, double value, bool asserted); /* @brief raises the alarm on the hard-shutdown threshold * * @param[in] direction - The threshold direction (HIGH/LOW) * @param[in] value - The current numeric sensor reading * @param[in] asserted - true if we want to set the alarm, false * if we want to clear it. * * @return PLDM_SUCCESS or a valid error code. */ void setHardShutdownThresholdAlarm(pldm::utils::Direction direction, double value, bool asserted); /* @brief raises the alarm on the threshold * * @param[in] level - The threshold level (WARNING/CRITICAL/etc) * @param[in] direction - The threshold direction (HIGH/LOW) * @param[in] value - The current numeric sensor reading * @param[in] asserted - true if we want to set the alarm, false * if we want to clear it. * * @return PLDM_SUCCESS or a valid error code. */ int setThresholdAlarm(pldm::utils::Level level, pldm::utils::Direction direction, double value, bool asserted); /** @brief Check if value is over threshold. * * @param[in] eventType - event level in pldm::utils::Level * @param[in] direction - direction type in pldm::utils::Direction * @param[in] rawValue - sensor raw value * @param[in] newAlarm - trigger alarm true/false * @param[in] assert - event type asserted/deasserted * * @return PLDM completion code */ int triggerThresholdEvent(pldm::utils::Level eventType, pldm::utils::Direction direction, double rawValue, bool newAlarm, bool assert); /** @brief Terminus ID which the sensor belongs to */ pldm_tid_t tid; /** @brief Sensor ID */ uint16_t sensorId; /** @brief The time stamp since last getSensorReading command in usec */ uint64_t timeStamp; /** @brief The time of sensor update interval in usec */ uint64_t updateTime; /** @brief sensorName */ std::string sensorName; /** @brief sensorNameSpace */ std::string sensorNameSpace; /** @brief Sensor Unit */ SensorUnit sensorUnit; private: /** * @brief resolve and clear a log entry * * @param[inout] log - dbus path to log entry. The log will be resolve * and the optional reset. */ void clearThresholdLog(std::optional& log); /** @brief create a log entry that all sensor alarms have cleared and is now * operating in the normal operating range. * * @param[in] value - The current sensor value in normal range. */ void createNormalRangeLog(double value); /** * @brief Create a threshold log for the given level/direction tuple. * * @param[in] level - The level of the threshold. * @param[in] direction - The direction of the threshold. * @param[in] value - The current sensor value. */ void createThresholdLog(pldm::utils::Level level, pldm::utils::Direction direction, double value); /** * @brief Check sensor reading if any threshold has been crossed and update * Threshold interfaces accordingly */ void updateThresholds(); /** * @brief Update the object units based on the PDR baseUnit */ void setSensorUnit(uint8_t baseUnit); /** @brief Create the sensor inventory path. * * @param[in] associationPath - sensor association path * @param[in] sensorName - sensor name * @param[in] entityType - sensor PDR entity type * @param[in] entityInstanceNum - sensor PDR entity instance number * @param[in] containerId - sensor PDR entity container ID * * @return True when success otherwise return False */ inline bool createInventoryPath( const std::string& associationPath, const std::string& sensorName, const uint16_t entityType, const uint16_t entityInstanceNum, const uint16_t containerId); std::unique_ptr metricIntf = nullptr; std::unique_ptr valueIntf = nullptr; std::unique_ptr thresholdWarningIntf = nullptr; std::unique_ptr thresholdCriticalIntf = nullptr; std::unique_ptr thresholdHardShutdownIntf = nullptr; std::unique_ptr availabilityIntf = nullptr; std::unique_ptr operationalStatusIntf = nullptr; std::unique_ptr associationDefinitionsIntf = nullptr; std::unique_ptr entityIntf = nullptr; /** @brief Amount of hysteresis associated with the sensor thresholds */ double hysteresis; /** @brief The resolution of sensor in Units */ double resolution; /** @brief A constant value that is added in as part of conversion process * of converting a raw sensor reading to Units */ double offset; /** @brief A power-of-10 multiplier for baseUnit */ int8_t baseUnitModifier; bool useMetricInterface = false; /** @brief An internal mapping of thresholds and its associated log * entry. */ std::map, std::optional> assertedLog; }; } // namespace platform_mc } // namespace pldm