13c5486d4SThu Nguyen #include "numeric_sensor.hpp" 23c5486d4SThu Nguyen 33c5486d4SThu Nguyen #include "libpldm/platform.h" 43c5486d4SThu Nguyen 53c5486d4SThu Nguyen #include "common/utils.hpp" 63c5486d4SThu Nguyen #include "requester/handler.hpp" 73c5486d4SThu Nguyen 83c5486d4SThu Nguyen #include <limits> 93c5486d4SThu Nguyen #include <regex> 103c5486d4SThu Nguyen 113c5486d4SThu Nguyen PHOSPHOR_LOG2_USING; 123c5486d4SThu Nguyen 133c5486d4SThu Nguyen namespace pldm 143c5486d4SThu Nguyen { 153c5486d4SThu Nguyen namespace platform_mc 163c5486d4SThu Nguyen { 173c5486d4SThu Nguyen 183c5486d4SThu Nguyen NumericSensor::NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, 193c5486d4SThu Nguyen std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, 203c5486d4SThu Nguyen std::string& sensorName, 213c5486d4SThu Nguyen std::string& associationPath) : 22*16c2a0a0SPatrick Williams tid(tid), sensorName(sensorName), isPriority(false) 233c5486d4SThu Nguyen { 243c5486d4SThu Nguyen if (!pdr) 253c5486d4SThu Nguyen { 263c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 273c5486d4SThu Nguyen } 283c5486d4SThu Nguyen 293c5486d4SThu Nguyen sensorId = pdr->sensor_id; 303c5486d4SThu Nguyen std::string path; 313c5486d4SThu Nguyen SensorUnit sensorUnit = SensorUnit::DegreesC; 323c5486d4SThu Nguyen 333c5486d4SThu Nguyen switch (pdr->base_unit) 343c5486d4SThu Nguyen { 353c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_DEGRESS_C: 363c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/"; 373c5486d4SThu Nguyen sensorUnit = SensorUnit::DegreesC; 383c5486d4SThu Nguyen break; 393c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_VOLTS: 403c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/"; 413c5486d4SThu Nguyen sensorUnit = SensorUnit::Volts; 423c5486d4SThu Nguyen break; 433c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_AMPS: 443c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/current/"; 453c5486d4SThu Nguyen sensorUnit = SensorUnit::Amperes; 463c5486d4SThu Nguyen break; 473c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_RPM: 483c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/"; 493c5486d4SThu Nguyen sensorUnit = SensorUnit::RPMS; 503c5486d4SThu Nguyen break; 513c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_WATTS: 523c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/power/"; 533c5486d4SThu Nguyen sensorUnit = SensorUnit::Watts; 543c5486d4SThu Nguyen break; 553c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_JOULES: 563c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/energy/"; 573c5486d4SThu Nguyen sensorUnit = SensorUnit::Joules; 583c5486d4SThu Nguyen break; 593c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_PERCENTAGE: 603c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/"; 613c5486d4SThu Nguyen sensorUnit = SensorUnit::Percent; 623c5486d4SThu Nguyen break; 633c5486d4SThu Nguyen default: 643c5486d4SThu Nguyen lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME", 653c5486d4SThu Nguyen sensorName, "UNIT", pdr->base_unit); 663c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 673c5486d4SThu Nguyen InvalidArgument(); 683c5486d4SThu Nguyen break; 693c5486d4SThu Nguyen } 703c5486d4SThu Nguyen 713c5486d4SThu Nguyen path = sensorNameSpace + sensorName; 723c5486d4SThu Nguyen try 733c5486d4SThu Nguyen { 743c5486d4SThu Nguyen auto service = pldm::utils::DBusHandler().getService( 753c5486d4SThu Nguyen path.c_str(), "xyz.openbmc_project.Sensor.Value"); 763c5486d4SThu Nguyen if (!service.empty()) 773c5486d4SThu Nguyen { 783c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 793c5486d4SThu Nguyen TooManyResources(); 803c5486d4SThu Nguyen } 813c5486d4SThu Nguyen } 823c5486d4SThu Nguyen catch (const std::exception&) 833c5486d4SThu Nguyen { 843c5486d4SThu Nguyen /* The sensor object path is not created */ 853c5486d4SThu Nguyen } 863c5486d4SThu Nguyen 873c5486d4SThu Nguyen auto& bus = pldm::utils::DBusHandler::getBus(); 883c5486d4SThu Nguyen try 893c5486d4SThu Nguyen { 903c5486d4SThu Nguyen associationDefinitionsIntf = 913c5486d4SThu Nguyen std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); 923c5486d4SThu Nguyen } 933c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 943c5486d4SThu Nguyen { 953c5486d4SThu Nguyen lg2::error( 963c5486d4SThu Nguyen "Failed to create association interface for numeric sensor {PATH} error - {ERROR}", 973c5486d4SThu Nguyen "PATH", path, "ERROR", e); 983c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 993c5486d4SThu Nguyen } 1003c5486d4SThu Nguyen 1013c5486d4SThu Nguyen associationDefinitionsIntf->associations( 1023c5486d4SThu Nguyen {{"chassis", "all_sensors", associationPath}}); 1033c5486d4SThu Nguyen 1043c5486d4SThu Nguyen double maxValue = std::numeric_limits<double>::quiet_NaN(); 1053c5486d4SThu Nguyen double minValue = std::numeric_limits<double>::quiet_NaN(); 1063c5486d4SThu Nguyen 1073c5486d4SThu Nguyen switch (pdr->sensor_data_size) 1083c5486d4SThu Nguyen { 1093c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_UINT8: 1103c5486d4SThu Nguyen maxValue = pdr->max_readable.value_u8; 1113c5486d4SThu Nguyen minValue = pdr->min_readable.value_u8; 1123c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_u8; 1133c5486d4SThu Nguyen break; 1143c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_SINT8: 1153c5486d4SThu Nguyen maxValue = pdr->max_readable.value_s8; 1163c5486d4SThu Nguyen minValue = pdr->min_readable.value_s8; 1173c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_s8; 1183c5486d4SThu Nguyen break; 1193c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_UINT16: 1203c5486d4SThu Nguyen maxValue = pdr->max_readable.value_u16; 1213c5486d4SThu Nguyen minValue = pdr->min_readable.value_u16; 1223c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_u16; 1233c5486d4SThu Nguyen break; 1243c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_SINT16: 1253c5486d4SThu Nguyen maxValue = pdr->max_readable.value_s16; 1263c5486d4SThu Nguyen minValue = pdr->min_readable.value_s16; 1273c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_s16; 1283c5486d4SThu Nguyen break; 1293c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_UINT32: 1303c5486d4SThu Nguyen maxValue = pdr->max_readable.value_u32; 1313c5486d4SThu Nguyen minValue = pdr->min_readable.value_u32; 1323c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_u32; 1333c5486d4SThu Nguyen break; 1343c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_SINT32: 1353c5486d4SThu Nguyen maxValue = pdr->max_readable.value_s32; 1363c5486d4SThu Nguyen minValue = pdr->min_readable.value_s32; 1373c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_s32; 1383c5486d4SThu Nguyen break; 1393c5486d4SThu Nguyen } 1403c5486d4SThu Nguyen 1413c5486d4SThu Nguyen bool hasCriticalThresholds = false; 1423c5486d4SThu Nguyen bool hasWarningThresholds = false; 1433c5486d4SThu Nguyen double criticalHigh = std::numeric_limits<double>::quiet_NaN(); 1443c5486d4SThu Nguyen double criticalLow = std::numeric_limits<double>::quiet_NaN(); 1453c5486d4SThu Nguyen double warningHigh = std::numeric_limits<double>::quiet_NaN(); 1463c5486d4SThu Nguyen double warningLow = std::numeric_limits<double>::quiet_NaN(); 1473c5486d4SThu Nguyen 1483c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit0) 1493c5486d4SThu Nguyen { 1503c5486d4SThu Nguyen hasWarningThresholds = true; 1513c5486d4SThu Nguyen switch (pdr->range_field_format) 1523c5486d4SThu Nguyen { 1533c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 1543c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_u8; 1553c5486d4SThu Nguyen break; 1563c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 1573c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_s8; 1583c5486d4SThu Nguyen break; 1593c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 1603c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_u16; 1613c5486d4SThu Nguyen break; 1623c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 1633c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_s16; 1643c5486d4SThu Nguyen break; 1653c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 1663c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_u32; 1673c5486d4SThu Nguyen break; 1683c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 1693c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_s32; 1703c5486d4SThu Nguyen break; 1713c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 1723c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_f32; 1733c5486d4SThu Nguyen break; 1743c5486d4SThu Nguyen } 1753c5486d4SThu Nguyen } 1763c5486d4SThu Nguyen 1773c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit3) 1783c5486d4SThu Nguyen { 1793c5486d4SThu Nguyen hasWarningThresholds = true; 1803c5486d4SThu Nguyen switch (pdr->range_field_format) 1813c5486d4SThu Nguyen { 1823c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 1833c5486d4SThu Nguyen warningLow = pdr->warning_low.value_u8; 1843c5486d4SThu Nguyen break; 1853c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 1863c5486d4SThu Nguyen warningLow = pdr->warning_low.value_s8; 1873c5486d4SThu Nguyen break; 1883c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 1893c5486d4SThu Nguyen warningLow = pdr->warning_low.value_u16; 1903c5486d4SThu Nguyen break; 1913c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 1923c5486d4SThu Nguyen warningLow = pdr->warning_low.value_s16; 1933c5486d4SThu Nguyen break; 1943c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 1953c5486d4SThu Nguyen warningLow = pdr->warning_low.value_u32; 1963c5486d4SThu Nguyen break; 1973c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 1983c5486d4SThu Nguyen warningLow = pdr->warning_low.value_s32; 1993c5486d4SThu Nguyen break; 2003c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 2013c5486d4SThu Nguyen warningLow = pdr->warning_low.value_f32; 2023c5486d4SThu Nguyen break; 2033c5486d4SThu Nguyen } 2043c5486d4SThu Nguyen } 2053c5486d4SThu Nguyen 2063c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit1) 2073c5486d4SThu Nguyen { 2083c5486d4SThu Nguyen hasCriticalThresholds = true; 2093c5486d4SThu Nguyen switch (pdr->range_field_format) 2103c5486d4SThu Nguyen { 2113c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 2123c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_u8; 2133c5486d4SThu Nguyen break; 2143c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 2153c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_s8; 2163c5486d4SThu Nguyen break; 2173c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 2183c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_u16; 2193c5486d4SThu Nguyen break; 2203c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 2213c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_s16; 2223c5486d4SThu Nguyen break; 2233c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 2243c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_u32; 2253c5486d4SThu Nguyen break; 2263c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 2273c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_s32; 2283c5486d4SThu Nguyen break; 2293c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 2303c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_f32; 2313c5486d4SThu Nguyen break; 2323c5486d4SThu Nguyen } 2333c5486d4SThu Nguyen } 2343c5486d4SThu Nguyen 2353c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit4) 2363c5486d4SThu Nguyen { 2373c5486d4SThu Nguyen hasCriticalThresholds = true; 2383c5486d4SThu Nguyen switch (pdr->range_field_format) 2393c5486d4SThu Nguyen { 2403c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 2413c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_u8; 2423c5486d4SThu Nguyen break; 2433c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 2443c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_s8; 2453c5486d4SThu Nguyen break; 2463c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 2473c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_u16; 2483c5486d4SThu Nguyen break; 2493c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 2503c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_s16; 2513c5486d4SThu Nguyen break; 2523c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 2533c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_u32; 2543c5486d4SThu Nguyen break; 2553c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 2563c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_s32; 2573c5486d4SThu Nguyen break; 2583c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 2593c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_f32; 2603c5486d4SThu Nguyen break; 2613c5486d4SThu Nguyen } 2623c5486d4SThu Nguyen } 2633c5486d4SThu Nguyen 2643c5486d4SThu Nguyen resolution = pdr->resolution; 2653c5486d4SThu Nguyen offset = pdr->offset; 2663c5486d4SThu Nguyen baseUnitModifier = pdr->unit_modifier; 2673c5486d4SThu Nguyen 2683c5486d4SThu Nguyen /** 2693c5486d4SThu Nguyen * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds 2703c5486d4SThu Nguyen * updateTime is in microseconds 2713c5486d4SThu Nguyen */ 2723c5486d4SThu Nguyen updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); 2733c5486d4SThu Nguyen if (!std::isnan(pdr->update_interval)) 2743c5486d4SThu Nguyen { 2753c5486d4SThu Nguyen updateTime = pdr->update_interval * 1000000; 2763c5486d4SThu Nguyen } 2773c5486d4SThu Nguyen 2783c5486d4SThu Nguyen try 2793c5486d4SThu Nguyen { 2803c5486d4SThu Nguyen valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); 2813c5486d4SThu Nguyen } 2823c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 2833c5486d4SThu Nguyen { 2843c5486d4SThu Nguyen lg2::error( 2853c5486d4SThu Nguyen "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}", 2863c5486d4SThu Nguyen "PATH", path, "ERROR", e); 2873c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 2883c5486d4SThu Nguyen } 2893c5486d4SThu Nguyen valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); 2903c5486d4SThu Nguyen valueIntf->minValue(unitModifier(conversionFormula(minValue))); 2913c5486d4SThu Nguyen hysteresis = unitModifier(conversionFormula(hysteresis)); 2923c5486d4SThu Nguyen valueIntf->unit(sensorUnit); 2933c5486d4SThu Nguyen 2943c5486d4SThu Nguyen try 2953c5486d4SThu Nguyen { 296*16c2a0a0SPatrick Williams availabilityIntf = 297*16c2a0a0SPatrick Williams std::make_unique<AvailabilityIntf>(bus, path.c_str()); 2983c5486d4SThu Nguyen } 2993c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 3003c5486d4SThu Nguyen { 3013c5486d4SThu Nguyen lg2::error( 3023c5486d4SThu Nguyen "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}", 3033c5486d4SThu Nguyen "PATH", path, "ERROR", e); 3043c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 3053c5486d4SThu Nguyen } 3063c5486d4SThu Nguyen availabilityIntf->available(true); 3073c5486d4SThu Nguyen 3083c5486d4SThu Nguyen try 3093c5486d4SThu Nguyen { 3103c5486d4SThu Nguyen operationalStatusIntf = 3113c5486d4SThu Nguyen std::make_unique<OperationalStatusIntf>(bus, path.c_str()); 3123c5486d4SThu Nguyen } 3133c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 3143c5486d4SThu Nguyen { 3153c5486d4SThu Nguyen lg2::error( 3163c5486d4SThu Nguyen "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}", 3173c5486d4SThu Nguyen "PATH", path, "ERROR", e); 3183c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 3193c5486d4SThu Nguyen } 3203c5486d4SThu Nguyen operationalStatusIntf->functional(!sensorDisabled); 3213c5486d4SThu Nguyen 3223c5486d4SThu Nguyen if (hasWarningThresholds) 3233c5486d4SThu Nguyen { 3243c5486d4SThu Nguyen try 3253c5486d4SThu Nguyen { 3263c5486d4SThu Nguyen thresholdWarningIntf = 3273c5486d4SThu Nguyen std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); 3283c5486d4SThu Nguyen } 3293c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 3303c5486d4SThu Nguyen { 3313c5486d4SThu Nguyen lg2::error( 3323c5486d4SThu Nguyen "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}", 3333c5486d4SThu Nguyen "PATH", path, "ERROR", e); 3343c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 3353c5486d4SThu Nguyen InvalidArgument(); 3363c5486d4SThu Nguyen } 3373c5486d4SThu Nguyen thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); 3383c5486d4SThu Nguyen thresholdWarningIntf->warningLow(unitModifier(warningLow)); 3393c5486d4SThu Nguyen } 3403c5486d4SThu Nguyen 3413c5486d4SThu Nguyen if (hasCriticalThresholds) 3423c5486d4SThu Nguyen { 3433c5486d4SThu Nguyen try 3443c5486d4SThu Nguyen { 3453c5486d4SThu Nguyen thresholdCriticalIntf = 3463c5486d4SThu Nguyen std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); 3473c5486d4SThu Nguyen } 3483c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 3493c5486d4SThu Nguyen { 3503c5486d4SThu Nguyen lg2::error( 3513c5486d4SThu Nguyen "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}", 3523c5486d4SThu Nguyen "PATH", path, "ERROR", e); 3533c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 3543c5486d4SThu Nguyen InvalidArgument(); 3553c5486d4SThu Nguyen } 3563c5486d4SThu Nguyen thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); 3573c5486d4SThu Nguyen thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); 3583c5486d4SThu Nguyen } 3593c5486d4SThu Nguyen } 3603c5486d4SThu Nguyen 3613c5486d4SThu Nguyen NumericSensor::NumericSensor( 3623c5486d4SThu Nguyen const pldm_tid_t tid, const bool sensorDisabled, 3633c5486d4SThu Nguyen std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr, 3643c5486d4SThu Nguyen std::string& sensorName, std::string& associationPath) : 365*16c2a0a0SPatrick Williams tid(tid), sensorName(sensorName), isPriority(false) 3663c5486d4SThu Nguyen { 3673c5486d4SThu Nguyen if (!pdr) 3683c5486d4SThu Nguyen { 3693c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 3703c5486d4SThu Nguyen } 3713c5486d4SThu Nguyen 3723c5486d4SThu Nguyen sensorId = pdr->sensor_id; 3733c5486d4SThu Nguyen std::string path; 3743c5486d4SThu Nguyen SensorUnit sensorUnit = SensorUnit::DegreesC; 3753c5486d4SThu Nguyen 3763c5486d4SThu Nguyen switch (pdr->base_unit) 3773c5486d4SThu Nguyen { 3783c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_DEGRESS_C: 3793c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/"; 3803c5486d4SThu Nguyen sensorUnit = SensorUnit::DegreesC; 3813c5486d4SThu Nguyen break; 3823c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_VOLTS: 3833c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/"; 3843c5486d4SThu Nguyen sensorUnit = SensorUnit::Volts; 3853c5486d4SThu Nguyen break; 3863c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_AMPS: 3873c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/current/"; 3883c5486d4SThu Nguyen sensorUnit = SensorUnit::Amperes; 3893c5486d4SThu Nguyen break; 3903c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_RPM: 3913c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/"; 3923c5486d4SThu Nguyen sensorUnit = SensorUnit::RPMS; 3933c5486d4SThu Nguyen break; 3943c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_WATTS: 3953c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/power/"; 3963c5486d4SThu Nguyen sensorUnit = SensorUnit::Watts; 3973c5486d4SThu Nguyen break; 3983c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_JOULES: 3993c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/energy/"; 4003c5486d4SThu Nguyen sensorUnit = SensorUnit::Joules; 4013c5486d4SThu Nguyen break; 4023c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_PERCENTAGE: 4033c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/"; 4043c5486d4SThu Nguyen sensorUnit = SensorUnit::Percent; 4053c5486d4SThu Nguyen break; 4063c5486d4SThu Nguyen default: 4073c5486d4SThu Nguyen lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME", 4083c5486d4SThu Nguyen sensorName, "UNIT", pdr->base_unit); 4093c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 4103c5486d4SThu Nguyen InvalidArgument(); 4113c5486d4SThu Nguyen break; 4123c5486d4SThu Nguyen } 4133c5486d4SThu Nguyen 4143c5486d4SThu Nguyen path = sensorNameSpace + sensorName; 4153c5486d4SThu Nguyen try 4163c5486d4SThu Nguyen { 4173c5486d4SThu Nguyen auto service = pldm::utils::DBusHandler().getService( 4183c5486d4SThu Nguyen path.c_str(), "xyz.openbmc_project.Sensor.Value"); 4193c5486d4SThu Nguyen if (!service.empty()) 4203c5486d4SThu Nguyen { 4213c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 4223c5486d4SThu Nguyen TooManyResources(); 4233c5486d4SThu Nguyen } 4243c5486d4SThu Nguyen } 4253c5486d4SThu Nguyen catch (const std::exception&) 4263c5486d4SThu Nguyen { 4273c5486d4SThu Nguyen /* The sensor object path is not created */ 4283c5486d4SThu Nguyen } 4293c5486d4SThu Nguyen 4303c5486d4SThu Nguyen auto& bus = pldm::utils::DBusHandler::getBus(); 4313c5486d4SThu Nguyen try 4323c5486d4SThu Nguyen { 4333c5486d4SThu Nguyen associationDefinitionsIntf = 4343c5486d4SThu Nguyen std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); 4353c5486d4SThu Nguyen } 4363c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 4373c5486d4SThu Nguyen { 4383c5486d4SThu Nguyen lg2::error( 4393c5486d4SThu Nguyen "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}", 4403c5486d4SThu Nguyen "PATH", path, "ERROR", e); 4413c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 4423c5486d4SThu Nguyen } 4433c5486d4SThu Nguyen associationDefinitionsIntf->associations( 4443c5486d4SThu Nguyen {{"chassis", "all_sensors", associationPath.c_str()}}); 4453c5486d4SThu Nguyen 4463c5486d4SThu Nguyen double maxValue = std::numeric_limits<double>::quiet_NaN(); 4473c5486d4SThu Nguyen double minValue = std::numeric_limits<double>::quiet_NaN(); 4483c5486d4SThu Nguyen bool hasWarningThresholds = false; 4493c5486d4SThu Nguyen bool hasCriticalThresholds = false; 4503c5486d4SThu Nguyen double criticalHigh = std::numeric_limits<double>::quiet_NaN(); 4513c5486d4SThu Nguyen double criticalLow = std::numeric_limits<double>::quiet_NaN(); 4523c5486d4SThu Nguyen double warningHigh = std::numeric_limits<double>::quiet_NaN(); 4533c5486d4SThu Nguyen double warningLow = std::numeric_limits<double>::quiet_NaN(); 4543c5486d4SThu Nguyen 4553c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit0) 4563c5486d4SThu Nguyen { 4573c5486d4SThu Nguyen hasWarningThresholds = true; 4583c5486d4SThu Nguyen warningHigh = pdr->warning_high; 4593c5486d4SThu Nguyen } 4603c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit1) 4613c5486d4SThu Nguyen { 4623c5486d4SThu Nguyen hasWarningThresholds = true; 4633c5486d4SThu Nguyen warningLow = pdr->warning_low; 4643c5486d4SThu Nguyen } 4653c5486d4SThu Nguyen 4663c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit2) 4673c5486d4SThu Nguyen { 4683c5486d4SThu Nguyen hasCriticalThresholds = true; 4693c5486d4SThu Nguyen criticalHigh = pdr->critical_high; 4703c5486d4SThu Nguyen } 4713c5486d4SThu Nguyen 4723c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit3) 4733c5486d4SThu Nguyen { 4743c5486d4SThu Nguyen hasCriticalThresholds = true; 4753c5486d4SThu Nguyen criticalLow = pdr->critical_low; 4763c5486d4SThu Nguyen } 4773c5486d4SThu Nguyen 4783c5486d4SThu Nguyen resolution = std::numeric_limits<double>::quiet_NaN(); 4793c5486d4SThu Nguyen offset = std::numeric_limits<double>::quiet_NaN(); 4803c5486d4SThu Nguyen baseUnitModifier = pdr->unit_modifier; 4813c5486d4SThu Nguyen 4823c5486d4SThu Nguyen /** 4833c5486d4SThu Nguyen * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds 4843c5486d4SThu Nguyen * updateTime is in microseconds 4853c5486d4SThu Nguyen */ 4863c5486d4SThu Nguyen updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); 4873c5486d4SThu Nguyen try 4883c5486d4SThu Nguyen { 4893c5486d4SThu Nguyen valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); 4903c5486d4SThu Nguyen } 4913c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 4923c5486d4SThu Nguyen { 4933c5486d4SThu Nguyen lg2::error( 4943c5486d4SThu Nguyen "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}", 4953c5486d4SThu Nguyen "PATH", path, "ERROR", e); 4963c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 4973c5486d4SThu Nguyen } 4983c5486d4SThu Nguyen valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); 4993c5486d4SThu Nguyen valueIntf->minValue(unitModifier(conversionFormula(minValue))); 5003c5486d4SThu Nguyen hysteresis = unitModifier(conversionFormula(hysteresis)); 5013c5486d4SThu Nguyen valueIntf->unit(sensorUnit); 5023c5486d4SThu Nguyen 5033c5486d4SThu Nguyen try 5043c5486d4SThu Nguyen { 505*16c2a0a0SPatrick Williams availabilityIntf = 506*16c2a0a0SPatrick Williams std::make_unique<AvailabilityIntf>(bus, path.c_str()); 5073c5486d4SThu Nguyen } 5083c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 5093c5486d4SThu Nguyen { 5103c5486d4SThu Nguyen lg2::error( 5113c5486d4SThu Nguyen "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}", 5123c5486d4SThu Nguyen "PATH", path, "ERROR", e); 5133c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 5143c5486d4SThu Nguyen } 5153c5486d4SThu Nguyen availabilityIntf->available(true); 5163c5486d4SThu Nguyen 5173c5486d4SThu Nguyen try 5183c5486d4SThu Nguyen { 5193c5486d4SThu Nguyen operationalStatusIntf = 5203c5486d4SThu Nguyen std::make_unique<OperationalStatusIntf>(bus, path.c_str()); 5213c5486d4SThu Nguyen } 5223c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 5233c5486d4SThu Nguyen { 5243c5486d4SThu Nguyen lg2::error( 5253c5486d4SThu Nguyen "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}", 5263c5486d4SThu Nguyen "PATH", path, "ERROR", e); 5273c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 5283c5486d4SThu Nguyen } 5293c5486d4SThu Nguyen operationalStatusIntf->functional(!sensorDisabled); 5303c5486d4SThu Nguyen 5313c5486d4SThu Nguyen if (hasWarningThresholds) 5323c5486d4SThu Nguyen { 5333c5486d4SThu Nguyen try 5343c5486d4SThu Nguyen { 5353c5486d4SThu Nguyen thresholdWarningIntf = 5363c5486d4SThu Nguyen std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); 5373c5486d4SThu Nguyen } 5383c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 5393c5486d4SThu Nguyen { 5403c5486d4SThu Nguyen lg2::error( 5413c5486d4SThu Nguyen "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}", 5423c5486d4SThu Nguyen "PATH", path, "ERROR", e); 5433c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 5443c5486d4SThu Nguyen InvalidArgument(); 5453c5486d4SThu Nguyen } 5463c5486d4SThu Nguyen thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); 5473c5486d4SThu Nguyen thresholdWarningIntf->warningLow(unitModifier(warningLow)); 5483c5486d4SThu Nguyen } 5493c5486d4SThu Nguyen 5503c5486d4SThu Nguyen if (hasCriticalThresholds) 5513c5486d4SThu Nguyen { 5523c5486d4SThu Nguyen try 5533c5486d4SThu Nguyen { 5543c5486d4SThu Nguyen thresholdCriticalIntf = 5553c5486d4SThu Nguyen std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); 5563c5486d4SThu Nguyen } 5573c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 5583c5486d4SThu Nguyen { 5593c5486d4SThu Nguyen lg2::error( 5603c5486d4SThu Nguyen "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}", 5613c5486d4SThu Nguyen "PATH", path, "ERROR", e); 5623c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 5633c5486d4SThu Nguyen InvalidArgument(); 5643c5486d4SThu Nguyen } 5653c5486d4SThu Nguyen thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); 5663c5486d4SThu Nguyen thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); 5673c5486d4SThu Nguyen } 5683c5486d4SThu Nguyen } 5693c5486d4SThu Nguyen 5703c5486d4SThu Nguyen double NumericSensor::conversionFormula(double value) 5713c5486d4SThu Nguyen { 5723c5486d4SThu Nguyen double convertedValue = value; 5733c5486d4SThu Nguyen convertedValue *= std::isnan(resolution) ? 1 : resolution; 5743c5486d4SThu Nguyen convertedValue += std::isnan(offset) ? 0 : offset; 5753c5486d4SThu Nguyen return convertedValue; 5763c5486d4SThu Nguyen } 5773c5486d4SThu Nguyen 5783c5486d4SThu Nguyen double NumericSensor::unitModifier(double value) 5793c5486d4SThu Nguyen { 5803c5486d4SThu Nguyen return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier); 5813c5486d4SThu Nguyen } 5823c5486d4SThu Nguyen } // namespace platform_mc 5833c5486d4SThu Nguyen } // namespace pldm 584