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