| #include "numeric_sensor.hpp" | |
| #include "common/utils.hpp" | |
| #include "requester/handler.hpp" | |
| #include <libpldm/platform.h> | |
| #include <xyz/openbmc_project/Logging/Entry/client.hpp> | |
| #include <limits> | |
| #include <regex> | |
| #ifdef PLDMD_ENABLE_SHMEM | |
| #include <absl/status/status.h> | |
| #include <absl/strings/str_cat.h> | |
| #include <shared_memory/static_client_impl.h> | |
| #endif | |
| PHOSPHOR_LOG2_USING; | |
| namespace pldm | |
| { | |
| namespace platform_mc | |
| { | |
| // This allows code to cleanly iterate through all supported | |
| // threshold levels and directions. | |
| static const std::array<pldm::utils::Level, 3> allThresholdLevels = { | |
| pldm::utils::Level::WARNING, pldm::utils::Level::CRITICAL, | |
| pldm::utils::Level::HARDSHUTDOWN}; | |
| static const std::array<pldm::utils::Direction, 2> allThresholdDirections = { | |
| pldm::utils::Direction::HIGH, pldm::utils::Direction::LOW}; | |
| inline bool NumericSensor::createInventoryPath( | |
| const std::string& associationPath, const std::string& sensorName, | |
| const uint16_t entityType, const uint16_t entityInstanceNum, | |
| const uint16_t containerId) | |
| { | |
| auto& bus = pldm::utils::DBusHandler::getBus(); | |
| std::string invPath = associationPath + "/" + sensorName; | |
| try | |
| { | |
| entityIntf = std::make_unique<EntityIntf>(bus, invPath.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Entity interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", invPath, "ERROR", e); | |
| return false; | |
| } | |
| entityIntf->entityType(entityType); | |
| entityIntf->entityInstanceNumber(entityInstanceNum); | |
| entityIntf->containerID(containerId); | |
| return true; | |
| } | |
| inline double getSensorDataValue(uint8_t sensor_data_size, | |
| union_sensor_data_size& value) | |
| { | |
| double ret = std::numeric_limits<double>::quiet_NaN(); | |
| switch (sensor_data_size) | |
| { | |
| case PLDM_SENSOR_DATA_SIZE_UINT8: | |
| ret = value.value_u8; | |
| break; | |
| case PLDM_SENSOR_DATA_SIZE_SINT8: | |
| ret = value.value_s8; | |
| break; | |
| case PLDM_SENSOR_DATA_SIZE_UINT16: | |
| ret = value.value_u16; | |
| break; | |
| case PLDM_SENSOR_DATA_SIZE_SINT16: | |
| ret = value.value_s16; | |
| break; | |
| case PLDM_SENSOR_DATA_SIZE_UINT32: | |
| ret = value.value_u32; | |
| break; | |
| case PLDM_SENSOR_DATA_SIZE_SINT32: | |
| ret = value.value_s32; | |
| break; | |
| case PLDM_SENSOR_DATA_SIZE_UINT64: | |
| ret = value.value_u64; | |
| break; | |
| case PLDM_SENSOR_DATA_SIZE_SINT64: | |
| ret = value.value_s64; | |
| break; | |
| } | |
| return ret; | |
| } | |
| inline double getRangeFieldValue(uint8_t range_field_format, | |
| union_range_field_format& value) | |
| { | |
| double ret = std::numeric_limits<double>::quiet_NaN(); | |
| switch (range_field_format) | |
| { | |
| case PLDM_RANGE_FIELD_FORMAT_UINT8: | |
| ret = value.value_u8; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_SINT8: | |
| ret = value.value_s8; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_UINT16: | |
| ret = value.value_u16; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_SINT16: | |
| ret = value.value_s16; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_UINT32: | |
| ret = value.value_u32; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_SINT32: | |
| ret = value.value_s32; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_REAL32: | |
| ret = value.value_f32; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_UINT64: | |
| ret = value.value_u64; | |
| break; | |
| case PLDM_RANGE_FIELD_FORMAT_SINT64: | |
| ret = value.value_s64; | |
| break; | |
| } | |
| return ret; | |
| } | |
| void NumericSensor::setSensorUnit(uint8_t baseUnit) | |
| { | |
| sensorUnit = SensorUnit::DegreesC; | |
| useMetricInterface = false; | |
| switch (baseUnit) | |
| { | |
| case PLDM_SENSOR_UNIT_DEGRESS_C: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/"; | |
| sensorUnit = SensorUnit::DegreesC; | |
| break; | |
| case PLDM_SENSOR_UNIT_VOLTS: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/"; | |
| sensorUnit = SensorUnit::Volts; | |
| break; | |
| case PLDM_SENSOR_UNIT_AMPS: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/current/"; | |
| sensorUnit = SensorUnit::Amperes; | |
| break; | |
| case PLDM_SENSOR_UNIT_RPM: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/"; | |
| sensorUnit = SensorUnit::RPMS; | |
| break; | |
| case PLDM_SENSOR_UNIT_WATTS: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/power/"; | |
| sensorUnit = SensorUnit::Watts; | |
| break; | |
| case PLDM_SENSOR_UNIT_JOULES: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/energy/"; | |
| sensorUnit = SensorUnit::Joules; | |
| break; | |
| case PLDM_SENSOR_UNIT_PERCENTAGE: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/"; | |
| sensorUnit = SensorUnit::Percent; | |
| break; | |
| case PLDM_SENSOR_UNIT_HERTZ: | |
| sensorNameSpace = "/xyz/openbmc_project/sensors/frequency/"; | |
| useMetricInterface = true; | |
| break; | |
| case PLDM_SENSOR_UNIT_COUNTS: | |
| case PLDM_SENSOR_UNIT_CORRECTED_ERRORS: | |
| case PLDM_SENSOR_UNIT_UNCORRECTABLE_ERRORS: | |
| case PLDM_SENSOR_UNIT_BITS: | |
| sensorNameSpace = "/xyz/openbmc_project/metric/count/"; | |
| useMetricInterface = true; | |
| break; | |
| case PLDM_SENSOR_UNIT_OEMUNIT: | |
| sensorNameSpace = "/xyz/openbmc_project/metric/oem/"; | |
| useMetricInterface = true; | |
| break; | |
| default: | |
| lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME", | |
| sensorName, "UNIT", baseUnit); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| break; | |
| } | |
| } | |
| NumericSensor::NumericSensor( | |
| const pldm_tid_t tid, const bool sensorDisabled, | |
| std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, std::string& sensorName, | |
| std::string& associationPath) : tid(tid), sensorName(sensorName) | |
| { | |
| #ifdef PLDMD_ENABLE_SHMEM | |
| sharedMemSensorName = absl::StrCat("sharedmem_", sensorName); | |
| #endif | |
| if (!pdr) | |
| { | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| sensorId = pdr->sensor_id; | |
| std::string path; | |
| MetricUnit metricUnit = MetricUnit::Count; | |
| setSensorUnit(pdr->base_unit); | |
| path = sensorNameSpace + sensorName; | |
| try | |
| { | |
| std::string tmp{}; | |
| std::string interface = ValueIntf::interface; | |
| if (useMetricInterface) | |
| { | |
| interface = MetricIntf::interface; | |
| } | |
| tmp = pldm::utils::DBusHandler().getService(path.c_str(), | |
| interface.c_str()); | |
| if (!tmp.empty()) | |
| { | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| TooManyResources(); | |
| } | |
| } | |
| catch (const std::exception&) | |
| { | |
| /* The sensor object path is not created */ | |
| } | |
| auto& bus = pldm::utils::DBusHandler::getBus(); | |
| try | |
| { | |
| associationDefinitionsIntf = | |
| std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create association interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| if (useMetricInterface) | |
| { | |
| associationDefinitionsIntf->associations( | |
| {{"measuring", "measured_by", associationPath}}); | |
| } | |
| else | |
| { | |
| associationDefinitionsIntf->associations( | |
| {{"chassis", "all_sensors", associationPath}}); | |
| } | |
| double maxValue = | |
| getSensorDataValue(pdr->sensor_data_size, pdr->max_readable); | |
| double minValue = | |
| getSensorDataValue(pdr->sensor_data_size, pdr->min_readable); | |
| hysteresis = getSensorDataValue(pdr->sensor_data_size, pdr->hysteresis); | |
| bool hasCriticalThresholds = false; | |
| bool hasWarningThresholds = false; | |
| bool hasFatalThresholds = false; | |
| double criticalHigh = std::numeric_limits<double>::quiet_NaN(); | |
| double criticalLow = std::numeric_limits<double>::quiet_NaN(); | |
| double warningHigh = std::numeric_limits<double>::quiet_NaN(); | |
| double warningLow = std::numeric_limits<double>::quiet_NaN(); | |
| double fatalHigh = std::numeric_limits<double>::quiet_NaN(); | |
| double fatalLow = std::numeric_limits<double>::quiet_NaN(); | |
| if (pdr->supported_thresholds.bits.bit0) | |
| { | |
| hasWarningThresholds = true; | |
| warningHigh = | |
| getRangeFieldValue(pdr->range_field_format, pdr->warning_high); | |
| } | |
| if (pdr->supported_thresholds.bits.bit3) | |
| { | |
| hasWarningThresholds = true; | |
| warningLow = | |
| getRangeFieldValue(pdr->range_field_format, pdr->warning_low); | |
| } | |
| if (pdr->supported_thresholds.bits.bit1) | |
| { | |
| hasCriticalThresholds = true; | |
| criticalHigh = | |
| getRangeFieldValue(pdr->range_field_format, pdr->critical_high); | |
| } | |
| if (pdr->supported_thresholds.bits.bit4) | |
| { | |
| hasCriticalThresholds = true; | |
| criticalLow = | |
| getRangeFieldValue(pdr->range_field_format, pdr->critical_low); | |
| } | |
| if (pdr->supported_thresholds.bits.bit2) | |
| { | |
| hasFatalThresholds = true; | |
| fatalHigh = | |
| getRangeFieldValue(pdr->range_field_format, pdr->fatal_high); | |
| } | |
| if (pdr->supported_thresholds.bits.bit5) | |
| { | |
| hasFatalThresholds = true; | |
| fatalLow = getRangeFieldValue(pdr->range_field_format, pdr->fatal_low); | |
| } | |
| resolution = pdr->resolution; | |
| offset = pdr->offset; | |
| baseUnitModifier = pdr->unit_modifier; | |
| timeStamp = 0; | |
| /** | |
| * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds | |
| * updateTime is in microseconds | |
| */ | |
| updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); | |
| if (std::isfinite(pdr->update_interval)) | |
| { | |
| updateTime = pdr->update_interval * 1000000; | |
| } | |
| if (!useMetricInterface) | |
| { | |
| try | |
| { | |
| valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); | |
| valueIntf->minValue(unitModifier(conversionFormula(minValue))); | |
| valueIntf->unit(sensorUnit); | |
| } | |
| else | |
| { | |
| try | |
| { | |
| metricIntf = std::make_unique<MetricIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Metric interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| metricIntf->maxValue(unitModifier(conversionFormula(maxValue))); | |
| metricIntf->minValue(unitModifier(conversionFormula(minValue))); | |
| metricIntf->unit(metricUnit); | |
| } | |
| hysteresis = unitModifier(conversionFormula(hysteresis)); | |
| if (!createInventoryPath(associationPath, sensorName, pdr->entity_type, | |
| pdr->entity_instance_num, pdr->container_id)) | |
| { | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| try | |
| { | |
| availabilityIntf = | |
| std::make_unique<AvailabilityIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| availabilityIntf->available(true); | |
| try | |
| { | |
| operationalStatusIntf = | |
| std::make_unique<OperationalStatusIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| operationalStatusIntf->functional(!sensorDisabled); | |
| if (hasWarningThresholds && !useMetricInterface) | |
| { | |
| try | |
| { | |
| thresholdWarningIntf = | |
| std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); | |
| thresholdWarningIntf->warningLow(unitModifier(warningLow)); | |
| } | |
| if (hasCriticalThresholds && !useMetricInterface) | |
| { | |
| try | |
| { | |
| thresholdCriticalIntf = | |
| std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); | |
| thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); | |
| } | |
| if (hasFatalThresholds && !useMetricInterface) | |
| { | |
| try | |
| { | |
| thresholdHardShutdownIntf = | |
| std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh)); | |
| thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow)); | |
| } | |
| } | |
| NumericSensor::NumericSensor( | |
| const pldm_tid_t tid, const bool sensorDisabled, | |
| std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr, | |
| std::string& sensorName, std::string& associationPath) : | |
| tid(tid), sensorName(sensorName) | |
| { | |
| #ifdef PLDMD_ENABLE_SHMEM | |
| sharedMemSensorName = absl::StrCat("sharedmem_", sensorName); | |
| #endif | |
| if (!pdr) | |
| { | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| sensorId = pdr->sensor_id; | |
| std::string path; | |
| MetricUnit metricUnit = MetricUnit::Count; | |
| setSensorUnit(pdr->base_unit); | |
| path = sensorNameSpace + sensorName; | |
| try | |
| { | |
| std::string tmp{}; | |
| std::string interface = ValueIntf::interface; | |
| if (useMetricInterface) | |
| { | |
| interface = MetricIntf::interface; | |
| } | |
| tmp = pldm::utils::DBusHandler().getService(path.c_str(), | |
| interface.c_str()); | |
| if (!tmp.empty()) | |
| { | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| TooManyResources(); | |
| } | |
| } | |
| catch (const std::exception&) | |
| { | |
| /* The sensor object path is not created */ | |
| } | |
| auto& bus = pldm::utils::DBusHandler::getBus(); | |
| try | |
| { | |
| associationDefinitionsIntf = | |
| std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| if (useMetricInterface) | |
| { | |
| associationDefinitionsIntf->associations( | |
| {{"measuring", "measured_by", associationPath.c_str()}}); | |
| } | |
| else | |
| { | |
| associationDefinitionsIntf->associations( | |
| {{"chassis", "all_sensors", associationPath.c_str()}}); | |
| } | |
| double maxValue = std::numeric_limits<double>::quiet_NaN(); | |
| double minValue = std::numeric_limits<double>::quiet_NaN(); | |
| bool hasWarningThresholds = false; | |
| bool hasCriticalThresholds = false; | |
| bool hasFatalThresholds = false; | |
| double criticalHigh = std::numeric_limits<double>::quiet_NaN(); | |
| double criticalLow = std::numeric_limits<double>::quiet_NaN(); | |
| double warningHigh = std::numeric_limits<double>::quiet_NaN(); | |
| double warningLow = std::numeric_limits<double>::quiet_NaN(); | |
| double fatalHigh = std::numeric_limits<double>::quiet_NaN(); | |
| double fatalLow = std::numeric_limits<double>::quiet_NaN(); | |
| if (pdr->range_field_support.bits.bit0) | |
| { | |
| hasWarningThresholds = true; | |
| warningHigh = pdr->warning_high; | |
| } | |
| if (pdr->range_field_support.bits.bit1) | |
| { | |
| hasWarningThresholds = true; | |
| warningLow = pdr->warning_low; | |
| } | |
| if (pdr->range_field_support.bits.bit2) | |
| { | |
| hasCriticalThresholds = true; | |
| criticalHigh = pdr->critical_high; | |
| } | |
| if (pdr->range_field_support.bits.bit3) | |
| { | |
| hasCriticalThresholds = true; | |
| criticalLow = pdr->critical_low; | |
| } | |
| if (pdr->range_field_support.bits.bit4) | |
| { | |
| hasFatalThresholds = true; | |
| fatalHigh = pdr->fatal_high; | |
| } | |
| if (pdr->range_field_support.bits.bit5) | |
| { | |
| hasFatalThresholds = true; | |
| fatalLow = pdr->fatal_low; | |
| } | |
| resolution = std::numeric_limits<double>::quiet_NaN(); | |
| offset = std::numeric_limits<double>::quiet_NaN(); | |
| baseUnitModifier = pdr->unit_modifier; | |
| timeStamp = 0; | |
| hysteresis = 0; | |
| /** | |
| * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds | |
| * updateTime is in microseconds | |
| */ | |
| updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); | |
| if (!useMetricInterface) | |
| { | |
| try | |
| { | |
| valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); | |
| valueIntf->minValue(unitModifier(conversionFormula(minValue))); | |
| valueIntf->unit(sensorUnit); | |
| } | |
| else | |
| { | |
| try | |
| { | |
| metricIntf = std::make_unique<MetricIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| metricIntf->maxValue(unitModifier(conversionFormula(maxValue))); | |
| metricIntf->minValue(unitModifier(conversionFormula(minValue))); | |
| metricIntf->unit(metricUnit); | |
| } | |
| hysteresis = unitModifier(conversionFormula(hysteresis)); | |
| if (!createInventoryPath(associationPath, sensorName, pdr->entity_type, | |
| pdr->entity_instance, pdr->container_id)) | |
| { | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| try | |
| { | |
| availabilityIntf = | |
| std::make_unique<AvailabilityIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| availabilityIntf->available(true); | |
| try | |
| { | |
| operationalStatusIntf = | |
| std::make_unique<OperationalStatusIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); | |
| } | |
| operationalStatusIntf->functional(!sensorDisabled); | |
| if (hasWarningThresholds && !useMetricInterface) | |
| { | |
| try | |
| { | |
| thresholdWarningIntf = | |
| std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); | |
| thresholdWarningIntf->warningLow(unitModifier(warningLow)); | |
| } | |
| if (hasCriticalThresholds && !useMetricInterface) | |
| { | |
| try | |
| { | |
| thresholdCriticalIntf = | |
| std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); | |
| thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); | |
| } | |
| if (hasFatalThresholds && !useMetricInterface) | |
| { | |
| try | |
| { | |
| thresholdHardShutdownIntf = | |
| std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str()); | |
| } | |
| catch (const sdbusplus::exception_t& e) | |
| { | |
| lg2::error( | |
| "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}", | |
| "PATH", path, "ERROR", e); | |
| throw sdbusplus::xyz::openbmc_project::Common::Error:: | |
| InvalidArgument(); | |
| } | |
| thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh)); | |
| thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow)); | |
| } | |
| } | |
| double NumericSensor::conversionFormula(double value) | |
| { | |
| double convertedValue = value; | |
| if (std::isfinite(resolution)) | |
| { | |
| convertedValue *= resolution; | |
| } | |
| if (std::isfinite(offset)) | |
| { | |
| convertedValue += offset; | |
| } | |
| return convertedValue; | |
| } | |
| double NumericSensor::unitModifier(double value) | |
| { | |
| if (!std::isfinite(value)) | |
| { | |
| return value; | |
| } | |
| return value * std::pow(10, baseUnitModifier); | |
| } | |
| void NumericSensor::updateReading(bool available, bool functional, double value) | |
| { | |
| if (!availabilityIntf || !operationalStatusIntf || | |
| (!useMetricInterface && !valueIntf) || | |
| (useMetricInterface && !metricIntf)) | |
| { | |
| lg2::error( | |
| "Failed to update sensor {NAME} D-Bus interface don't exist.", | |
| "NAME", sensorName); | |
| return; | |
| } | |
| availabilityIntf->available(available); | |
| operationalStatusIntf->functional(functional); | |
| double curValue = 0; | |
| if (!useMetricInterface) | |
| { | |
| curValue = valueIntf->value(); | |
| } | |
| else | |
| { | |
| curValue = metricIntf->value(); | |
| } | |
| double newValue = std::numeric_limits<double>::quiet_NaN(); | |
| if (functional && available) | |
| { | |
| newValue = unitModifier(conversionFormula(value)); | |
| if (std::isfinite(newValue) || std::isfinite(curValue)) | |
| { | |
| if (!useMetricInterface) | |
| { | |
| valueIntf->value(newValue); | |
| updateThresholds(); | |
| } | |
| else | |
| { | |
| metricIntf->value(newValue); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if (newValue != curValue && | |
| (std::isfinite(newValue) || std::isfinite(curValue))) | |
| { | |
| if (!useMetricInterface) | |
| { | |
| valueIntf->value(std::numeric_limits<double>::quiet_NaN()); | |
| } | |
| else | |
| { | |
| metricIntf->value(std::numeric_limits<double>::quiet_NaN()); | |
| } | |
| } | |
| } | |
| #ifdef PLDMD_ENABLE_SHMEM | |
| updateSharedMemory(newValue); | |
| #endif | |
| } | |
| void NumericSensor::handleErrGetSensorReading() | |
| { | |
| if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) || | |
| (useMetricInterface && !metricIntf)) | |
| { | |
| lg2::error( | |
| "Failed to update sensor {NAME} D-Bus interfaces don't exist.", | |
| "NAME", sensorName); | |
| return; | |
| } | |
| operationalStatusIntf->functional(false); | |
| if (!useMetricInterface) | |
| { | |
| valueIntf->value(std::numeric_limits<double>::quiet_NaN()); | |
| } | |
| else | |
| { | |
| metricIntf->value(std::numeric_limits<double>::quiet_NaN()); | |
| } | |
| #ifdef PLDMD_ENABLE_SHMEM | |
| updateSharedMemory(std::numeric_limits<double>::quiet_NaN()); | |
| #endif | |
| } | |
| #ifdef PLDMD_ENABLE_SHMEM | |
| void NumericSensor::updateSharedMemory(double value) | |
| { | |
| milotic_tlbmc::IpcClient* shmClientPtr = | |
| &milotic_tlbmc::StaticSharedMemoryClient::GetInstance(); | |
| if (shmClientPtr != nullptr) | |
| { | |
| if (!shmClientPtr->IsSensorSupported(sharedMemSensorName)) | |
| { | |
| return; | |
| } | |
| absl::Status status = | |
| shmClientPtr->UpdateSensorValue(sharedMemSensorName, value); | |
| if (!status.ok()) | |
| { | |
| lg2::error( | |
| "Failed to publish sensor value to shared memory for {SENSOR_NAME}: {STATUS}", | |
| "SENSOR_NAME", sharedMemSensorName, "STATUS", | |
| status.ToString()); | |
| } | |
| } | |
| else | |
| { | |
| lg2::error("shmClientPtr is null, cannot update shared memory"); | |
| } | |
| } | |
| #endif | |
| bool NumericSensor::checkThreshold(bool alarm, bool direction, double value, | |
| double threshold, double hyst) | |
| { | |
| if (direction) | |
| { | |
| if (value >= threshold) | |
| { | |
| return true; | |
| } | |
| if (value < (threshold - hyst)) | |
| { | |
| return false; | |
| } | |
| } | |
| else | |
| { | |
| if (value <= threshold) | |
| { | |
| return true; | |
| } | |
| if (value > (threshold + hyst)) | |
| { | |
| return false; | |
| } | |
| } | |
| return alarm; | |
| } | |
| bool NumericSensor::hasThresholdAlarm() | |
| { | |
| bool alarm = false; | |
| for (auto level : allThresholdLevels) | |
| { | |
| for (auto direction : allThresholdDirections) | |
| { | |
| alarm |= getThresholdAlarm(level, direction); | |
| } | |
| } | |
| return alarm; | |
| } | |
| void NumericSensor::setWarningThresholdAlarm(pldm::utils::Direction direction, | |
| double value, bool newAlarm) | |
| { | |
| if (direction == pldm::utils::Direction::HIGH) | |
| { | |
| thresholdWarningIntf->warningAlarmHigh(newAlarm); | |
| if (newAlarm) | |
| { | |
| thresholdWarningIntf->warningHighAlarmAsserted(value); | |
| } | |
| else | |
| { | |
| thresholdWarningIntf->warningHighAlarmDeasserted(value); | |
| } | |
| } | |
| else | |
| { | |
| thresholdWarningIntf->warningAlarmLow(newAlarm); | |
| if (newAlarm) | |
| { | |
| thresholdWarningIntf->warningLowAlarmAsserted(value); | |
| } | |
| else | |
| { | |
| thresholdWarningIntf->warningLowAlarmDeasserted(value); | |
| } | |
| } | |
| } | |
| void NumericSensor::setCriticalThresholdAlarm(pldm::utils::Direction direction, | |
| double value, bool newAlarm) | |
| { | |
| if (direction == pldm::utils::Direction::HIGH) | |
| { | |
| thresholdCriticalIntf->criticalAlarmHigh(newAlarm); | |
| if (newAlarm) | |
| { | |
| thresholdCriticalIntf->criticalHighAlarmAsserted(value); | |
| } | |
| else | |
| { | |
| thresholdCriticalIntf->criticalHighAlarmDeasserted(value); | |
| } | |
| } | |
| else | |
| { | |
| thresholdCriticalIntf->criticalAlarmLow(newAlarm); | |
| if (newAlarm) | |
| { | |
| thresholdCriticalIntf->criticalLowAlarmAsserted(value); | |
| } | |
| else | |
| { | |
| thresholdCriticalIntf->criticalLowAlarmDeasserted(value); | |
| } | |
| } | |
| } | |
| void NumericSensor::setHardShutdownThresholdAlarm( | |
| pldm::utils::Direction direction, double value, bool newAlarm) | |
| { | |
| if (direction == pldm::utils::Direction::HIGH) | |
| { | |
| thresholdHardShutdownIntf->hardShutdownAlarmHigh(newAlarm); | |
| if (newAlarm) | |
| { | |
| thresholdHardShutdownIntf->hardShutdownHighAlarmAsserted(value); | |
| } | |
| else | |
| { | |
| thresholdHardShutdownIntf->hardShutdownHighAlarmDeasserted(value); | |
| } | |
| } | |
| else | |
| { | |
| thresholdHardShutdownIntf->hardShutdownAlarmLow(newAlarm); | |
| if (newAlarm) | |
| { | |
| thresholdHardShutdownIntf->hardShutdownLowAlarmAsserted(value); | |
| } | |
| else | |
| { | |
| thresholdHardShutdownIntf->hardShutdownLowAlarmDeasserted(value); | |
| } | |
| } | |
| } | |
| int NumericSensor::setThresholdAlarm(pldm::utils::Level level, | |
| pldm::utils::Direction direction, | |
| double value, bool newAlarm) | |
| { | |
| if (!isThresholdValid(level, direction)) | |
| { | |
| lg2::error( | |
| "Error:Trigger sensor warning event for non warning threshold sensors {NAME}", | |
| "NAME", sensorName); | |
| return PLDM_ERROR; | |
| } | |
| auto alarm = getThresholdAlarm(level, direction); | |
| if (alarm == newAlarm) | |
| { | |
| return PLDM_SUCCESS; | |
| } | |
| switch (level) | |
| { | |
| case pldm::utils::Level::WARNING: | |
| setWarningThresholdAlarm(direction, value, newAlarm); | |
| break; | |
| case pldm::utils::Level::CRITICAL: | |
| setCriticalThresholdAlarm(direction, value, newAlarm); | |
| break; | |
| case pldm::utils::Level::HARDSHUTDOWN: | |
| setHardShutdownThresholdAlarm(direction, value, newAlarm); | |
| break; | |
| default: | |
| return PLDM_ERROR; | |
| } | |
| if (newAlarm) | |
| { | |
| createThresholdLog(level, direction, value); | |
| } | |
| else | |
| { | |
| auto& log = assertedLog[{level, direction}]; | |
| if (log.has_value()) | |
| { | |
| clearThresholdLog(log); | |
| } | |
| // If all alarms have cleared. Log normal range. | |
| if (!hasThresholdAlarm()) | |
| { | |
| createNormalRangeLog(value); | |
| } | |
| } | |
| return PLDM_SUCCESS; | |
| } | |
| void NumericSensor::clearThresholdLog( | |
| std::optional<sdbusplus::message::object_path>& log) | |
| { | |
| log.reset(); | |
| } | |
| /** @brief helper function template to create a threshold log | |
| * | |
| * @tparam[in] errorObj - The error object of the log we want to create. | |
| * @param[in] sensorObjPath - The object path of the sensor. | |
| * @param[in] value - The current value of the sensor. | |
| * @param[in] sensorUnit - The units of the sensor. | |
| * @param[in] threshold - The threshold value. | |
| * | |
| * @return optional object holding the object path of the created | |
| * log entry. If the log entry is being filtered, we would return | |
| * a optional holding an empty string in the object path. This ensures | |
| * we follow our state machine properly even if the log is being filtered. | |
| */ | |
| void NumericSensor::createThresholdLog( | |
| pldm::utils::Level level, pldm::utils::Direction direction, double value) | |
| { | |
| (void)level; | |
| (void)direction; | |
| (void)value; | |
| } | |
| void NumericSensor::createNormalRangeLog(double value) | |
| { | |
| std::string objPath = sensorNameSpace + sensorName; | |
| lg2::info("Sensor {OBJPATH} reading returned to normal range: {VALUE}", | |
| "OBJPATH", objPath, "VALUE", value); | |
| } | |
| void NumericSensor::updateThresholds() | |
| { | |
| double value = std::numeric_limits<double>::quiet_NaN(); | |
| if ((!useMetricInterface && !valueIntf) || | |
| (useMetricInterface && !metricIntf)) | |
| { | |
| lg2::error( | |
| "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.", | |
| "NAME", sensorName); | |
| return; | |
| } | |
| if (!useMetricInterface) | |
| { | |
| value = valueIntf->value(); | |
| } | |
| else | |
| { | |
| value = metricIntf->value(); | |
| } | |
| for (auto level : allThresholdLevels) | |
| { | |
| for (auto direction : allThresholdDirections) | |
| { | |
| auto threshold = getThreshold(level, direction); | |
| if (!std::isfinite(threshold)) | |
| { | |
| continue; | |
| } | |
| auto alarm = getThresholdAlarm(level, direction); | |
| auto newAlarm = | |
| checkThreshold(alarm, direction == pldm::utils::Direction::HIGH, | |
| value, threshold, hysteresis); | |
| setThresholdAlarm(level, direction, value, newAlarm); | |
| } | |
| } | |
| } | |
| int NumericSensor::triggerThresholdEvent( | |
| pldm::utils::Level eventType, pldm::utils::Direction direction, | |
| double rawValue, bool newAlarm, bool assert) | |
| { | |
| if (!valueIntf) | |
| { | |
| lg2::error( | |
| "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.", | |
| "NAME", sensorName); | |
| return PLDM_ERROR; | |
| } | |
| auto value = unitModifier(conversionFormula(rawValue)); | |
| lg2::error( | |
| "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}", | |
| "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm, | |
| "ESTATE", assert); | |
| return setThresholdAlarm(eventType, direction, value, newAlarm); | |
| } | |
| } // namespace platform_mc | |
| } // namespace pldm |