1*3c5486d4SThu Nguyen #include "numeric_sensor.hpp" 2*3c5486d4SThu Nguyen 3*3c5486d4SThu Nguyen #include "libpldm/platform.h" 4*3c5486d4SThu Nguyen 5*3c5486d4SThu Nguyen #include "common/utils.hpp" 6*3c5486d4SThu Nguyen #include "requester/handler.hpp" 7*3c5486d4SThu Nguyen 8*3c5486d4SThu Nguyen #include <limits> 9*3c5486d4SThu Nguyen #include <regex> 10*3c5486d4SThu Nguyen 11*3c5486d4SThu Nguyen PHOSPHOR_LOG2_USING; 12*3c5486d4SThu Nguyen 13*3c5486d4SThu Nguyen namespace pldm 14*3c5486d4SThu Nguyen { 15*3c5486d4SThu Nguyen namespace platform_mc 16*3c5486d4SThu Nguyen { 17*3c5486d4SThu Nguyen 18*3c5486d4SThu Nguyen NumericSensor::NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, 19*3c5486d4SThu Nguyen std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, 20*3c5486d4SThu Nguyen std::string& sensorName, 21*3c5486d4SThu Nguyen std::string& associationPath) : 22*3c5486d4SThu Nguyen tid(tid), 23*3c5486d4SThu Nguyen sensorName(sensorName), isPriority(false) 24*3c5486d4SThu Nguyen { 25*3c5486d4SThu Nguyen if (!pdr) 26*3c5486d4SThu Nguyen { 27*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 28*3c5486d4SThu Nguyen } 29*3c5486d4SThu Nguyen 30*3c5486d4SThu Nguyen sensorId = pdr->sensor_id; 31*3c5486d4SThu Nguyen std::string path; 32*3c5486d4SThu Nguyen SensorUnit sensorUnit = SensorUnit::DegreesC; 33*3c5486d4SThu Nguyen 34*3c5486d4SThu Nguyen switch (pdr->base_unit) 35*3c5486d4SThu Nguyen { 36*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_DEGRESS_C: 37*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/"; 38*3c5486d4SThu Nguyen sensorUnit = SensorUnit::DegreesC; 39*3c5486d4SThu Nguyen break; 40*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_VOLTS: 41*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/"; 42*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Volts; 43*3c5486d4SThu Nguyen break; 44*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_AMPS: 45*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/current/"; 46*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Amperes; 47*3c5486d4SThu Nguyen break; 48*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_RPM: 49*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/"; 50*3c5486d4SThu Nguyen sensorUnit = SensorUnit::RPMS; 51*3c5486d4SThu Nguyen break; 52*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_WATTS: 53*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/power/"; 54*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Watts; 55*3c5486d4SThu Nguyen break; 56*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_JOULES: 57*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/energy/"; 58*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Joules; 59*3c5486d4SThu Nguyen break; 60*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_PERCENTAGE: 61*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/"; 62*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Percent; 63*3c5486d4SThu Nguyen break; 64*3c5486d4SThu Nguyen default: 65*3c5486d4SThu Nguyen lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME", 66*3c5486d4SThu Nguyen sensorName, "UNIT", pdr->base_unit); 67*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 68*3c5486d4SThu Nguyen InvalidArgument(); 69*3c5486d4SThu Nguyen break; 70*3c5486d4SThu Nguyen } 71*3c5486d4SThu Nguyen 72*3c5486d4SThu Nguyen path = sensorNameSpace + sensorName; 73*3c5486d4SThu Nguyen try 74*3c5486d4SThu Nguyen { 75*3c5486d4SThu Nguyen auto service = pldm::utils::DBusHandler().getService( 76*3c5486d4SThu Nguyen path.c_str(), "xyz.openbmc_project.Sensor.Value"); 77*3c5486d4SThu Nguyen if (!service.empty()) 78*3c5486d4SThu Nguyen { 79*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 80*3c5486d4SThu Nguyen TooManyResources(); 81*3c5486d4SThu Nguyen } 82*3c5486d4SThu Nguyen } 83*3c5486d4SThu Nguyen catch (const std::exception&) 84*3c5486d4SThu Nguyen { 85*3c5486d4SThu Nguyen /* The sensor object path is not created */ 86*3c5486d4SThu Nguyen } 87*3c5486d4SThu Nguyen 88*3c5486d4SThu Nguyen auto& bus = pldm::utils::DBusHandler::getBus(); 89*3c5486d4SThu Nguyen try 90*3c5486d4SThu Nguyen { 91*3c5486d4SThu Nguyen associationDefinitionsIntf = 92*3c5486d4SThu Nguyen std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); 93*3c5486d4SThu Nguyen } 94*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 95*3c5486d4SThu Nguyen { 96*3c5486d4SThu Nguyen lg2::error( 97*3c5486d4SThu Nguyen "Failed to create association interface for numeric sensor {PATH} error - {ERROR}", 98*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 99*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 100*3c5486d4SThu Nguyen } 101*3c5486d4SThu Nguyen 102*3c5486d4SThu Nguyen associationDefinitionsIntf->associations( 103*3c5486d4SThu Nguyen {{"chassis", "all_sensors", associationPath}}); 104*3c5486d4SThu Nguyen 105*3c5486d4SThu Nguyen double maxValue = std::numeric_limits<double>::quiet_NaN(); 106*3c5486d4SThu Nguyen double minValue = std::numeric_limits<double>::quiet_NaN(); 107*3c5486d4SThu Nguyen 108*3c5486d4SThu Nguyen switch (pdr->sensor_data_size) 109*3c5486d4SThu Nguyen { 110*3c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_UINT8: 111*3c5486d4SThu Nguyen maxValue = pdr->max_readable.value_u8; 112*3c5486d4SThu Nguyen minValue = pdr->min_readable.value_u8; 113*3c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_u8; 114*3c5486d4SThu Nguyen break; 115*3c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_SINT8: 116*3c5486d4SThu Nguyen maxValue = pdr->max_readable.value_s8; 117*3c5486d4SThu Nguyen minValue = pdr->min_readable.value_s8; 118*3c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_s8; 119*3c5486d4SThu Nguyen break; 120*3c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_UINT16: 121*3c5486d4SThu Nguyen maxValue = pdr->max_readable.value_u16; 122*3c5486d4SThu Nguyen minValue = pdr->min_readable.value_u16; 123*3c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_u16; 124*3c5486d4SThu Nguyen break; 125*3c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_SINT16: 126*3c5486d4SThu Nguyen maxValue = pdr->max_readable.value_s16; 127*3c5486d4SThu Nguyen minValue = pdr->min_readable.value_s16; 128*3c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_s16; 129*3c5486d4SThu Nguyen break; 130*3c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_UINT32: 131*3c5486d4SThu Nguyen maxValue = pdr->max_readable.value_u32; 132*3c5486d4SThu Nguyen minValue = pdr->min_readable.value_u32; 133*3c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_u32; 134*3c5486d4SThu Nguyen break; 135*3c5486d4SThu Nguyen case PLDM_SENSOR_DATA_SIZE_SINT32: 136*3c5486d4SThu Nguyen maxValue = pdr->max_readable.value_s32; 137*3c5486d4SThu Nguyen minValue = pdr->min_readable.value_s32; 138*3c5486d4SThu Nguyen hysteresis = pdr->hysteresis.value_s32; 139*3c5486d4SThu Nguyen break; 140*3c5486d4SThu Nguyen } 141*3c5486d4SThu Nguyen 142*3c5486d4SThu Nguyen bool hasCriticalThresholds = false; 143*3c5486d4SThu Nguyen bool hasWarningThresholds = false; 144*3c5486d4SThu Nguyen double criticalHigh = std::numeric_limits<double>::quiet_NaN(); 145*3c5486d4SThu Nguyen double criticalLow = std::numeric_limits<double>::quiet_NaN(); 146*3c5486d4SThu Nguyen double warningHigh = std::numeric_limits<double>::quiet_NaN(); 147*3c5486d4SThu Nguyen double warningLow = std::numeric_limits<double>::quiet_NaN(); 148*3c5486d4SThu Nguyen 149*3c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit0) 150*3c5486d4SThu Nguyen { 151*3c5486d4SThu Nguyen hasWarningThresholds = true; 152*3c5486d4SThu Nguyen switch (pdr->range_field_format) 153*3c5486d4SThu Nguyen { 154*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 155*3c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_u8; 156*3c5486d4SThu Nguyen break; 157*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 158*3c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_s8; 159*3c5486d4SThu Nguyen break; 160*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 161*3c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_u16; 162*3c5486d4SThu Nguyen break; 163*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 164*3c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_s16; 165*3c5486d4SThu Nguyen break; 166*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 167*3c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_u32; 168*3c5486d4SThu Nguyen break; 169*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 170*3c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_s32; 171*3c5486d4SThu Nguyen break; 172*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 173*3c5486d4SThu Nguyen warningHigh = pdr->warning_high.value_f32; 174*3c5486d4SThu Nguyen break; 175*3c5486d4SThu Nguyen } 176*3c5486d4SThu Nguyen } 177*3c5486d4SThu Nguyen 178*3c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit3) 179*3c5486d4SThu Nguyen { 180*3c5486d4SThu Nguyen hasWarningThresholds = true; 181*3c5486d4SThu Nguyen switch (pdr->range_field_format) 182*3c5486d4SThu Nguyen { 183*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 184*3c5486d4SThu Nguyen warningLow = pdr->warning_low.value_u8; 185*3c5486d4SThu Nguyen break; 186*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 187*3c5486d4SThu Nguyen warningLow = pdr->warning_low.value_s8; 188*3c5486d4SThu Nguyen break; 189*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 190*3c5486d4SThu Nguyen warningLow = pdr->warning_low.value_u16; 191*3c5486d4SThu Nguyen break; 192*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 193*3c5486d4SThu Nguyen warningLow = pdr->warning_low.value_s16; 194*3c5486d4SThu Nguyen break; 195*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 196*3c5486d4SThu Nguyen warningLow = pdr->warning_low.value_u32; 197*3c5486d4SThu Nguyen break; 198*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 199*3c5486d4SThu Nguyen warningLow = pdr->warning_low.value_s32; 200*3c5486d4SThu Nguyen break; 201*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 202*3c5486d4SThu Nguyen warningLow = pdr->warning_low.value_f32; 203*3c5486d4SThu Nguyen break; 204*3c5486d4SThu Nguyen } 205*3c5486d4SThu Nguyen } 206*3c5486d4SThu Nguyen 207*3c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit1) 208*3c5486d4SThu Nguyen { 209*3c5486d4SThu Nguyen hasCriticalThresholds = true; 210*3c5486d4SThu Nguyen switch (pdr->range_field_format) 211*3c5486d4SThu Nguyen { 212*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 213*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_u8; 214*3c5486d4SThu Nguyen break; 215*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 216*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_s8; 217*3c5486d4SThu Nguyen break; 218*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 219*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_u16; 220*3c5486d4SThu Nguyen break; 221*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 222*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_s16; 223*3c5486d4SThu Nguyen break; 224*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 225*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_u32; 226*3c5486d4SThu Nguyen break; 227*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 228*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_s32; 229*3c5486d4SThu Nguyen break; 230*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 231*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high.value_f32; 232*3c5486d4SThu Nguyen break; 233*3c5486d4SThu Nguyen } 234*3c5486d4SThu Nguyen } 235*3c5486d4SThu Nguyen 236*3c5486d4SThu Nguyen if (pdr->supported_thresholds.bits.bit4) 237*3c5486d4SThu Nguyen { 238*3c5486d4SThu Nguyen hasCriticalThresholds = true; 239*3c5486d4SThu Nguyen switch (pdr->range_field_format) 240*3c5486d4SThu Nguyen { 241*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT8: 242*3c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_u8; 243*3c5486d4SThu Nguyen break; 244*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT8: 245*3c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_s8; 246*3c5486d4SThu Nguyen break; 247*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT16: 248*3c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_u16; 249*3c5486d4SThu Nguyen break; 250*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT16: 251*3c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_s16; 252*3c5486d4SThu Nguyen break; 253*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_UINT32: 254*3c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_u32; 255*3c5486d4SThu Nguyen break; 256*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_SINT32: 257*3c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_s32; 258*3c5486d4SThu Nguyen break; 259*3c5486d4SThu Nguyen case PLDM_RANGE_FIELD_FORMAT_REAL32: 260*3c5486d4SThu Nguyen criticalLow = pdr->critical_low.value_f32; 261*3c5486d4SThu Nguyen break; 262*3c5486d4SThu Nguyen } 263*3c5486d4SThu Nguyen } 264*3c5486d4SThu Nguyen 265*3c5486d4SThu Nguyen resolution = pdr->resolution; 266*3c5486d4SThu Nguyen offset = pdr->offset; 267*3c5486d4SThu Nguyen baseUnitModifier = pdr->unit_modifier; 268*3c5486d4SThu Nguyen 269*3c5486d4SThu Nguyen /** 270*3c5486d4SThu Nguyen * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds 271*3c5486d4SThu Nguyen * updateTime is in microseconds 272*3c5486d4SThu Nguyen */ 273*3c5486d4SThu Nguyen updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); 274*3c5486d4SThu Nguyen if (!std::isnan(pdr->update_interval)) 275*3c5486d4SThu Nguyen { 276*3c5486d4SThu Nguyen updateTime = pdr->update_interval * 1000000; 277*3c5486d4SThu Nguyen } 278*3c5486d4SThu Nguyen 279*3c5486d4SThu Nguyen try 280*3c5486d4SThu Nguyen { 281*3c5486d4SThu Nguyen valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); 282*3c5486d4SThu Nguyen } 283*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 284*3c5486d4SThu Nguyen { 285*3c5486d4SThu Nguyen lg2::error( 286*3c5486d4SThu Nguyen "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}", 287*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 288*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 289*3c5486d4SThu Nguyen } 290*3c5486d4SThu Nguyen valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); 291*3c5486d4SThu Nguyen valueIntf->minValue(unitModifier(conversionFormula(minValue))); 292*3c5486d4SThu Nguyen hysteresis = unitModifier(conversionFormula(hysteresis)); 293*3c5486d4SThu Nguyen valueIntf->unit(sensorUnit); 294*3c5486d4SThu Nguyen 295*3c5486d4SThu Nguyen try 296*3c5486d4SThu Nguyen { 297*3c5486d4SThu Nguyen availabilityIntf = std::make_unique<AvailabilityIntf>(bus, 298*3c5486d4SThu Nguyen path.c_str()); 299*3c5486d4SThu Nguyen } 300*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 301*3c5486d4SThu Nguyen { 302*3c5486d4SThu Nguyen lg2::error( 303*3c5486d4SThu Nguyen "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}", 304*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 305*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 306*3c5486d4SThu Nguyen } 307*3c5486d4SThu Nguyen availabilityIntf->available(true); 308*3c5486d4SThu Nguyen 309*3c5486d4SThu Nguyen try 310*3c5486d4SThu Nguyen { 311*3c5486d4SThu Nguyen operationalStatusIntf = 312*3c5486d4SThu Nguyen std::make_unique<OperationalStatusIntf>(bus, path.c_str()); 313*3c5486d4SThu Nguyen } 314*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 315*3c5486d4SThu Nguyen { 316*3c5486d4SThu Nguyen lg2::error( 317*3c5486d4SThu Nguyen "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}", 318*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 319*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 320*3c5486d4SThu Nguyen } 321*3c5486d4SThu Nguyen operationalStatusIntf->functional(!sensorDisabled); 322*3c5486d4SThu Nguyen 323*3c5486d4SThu Nguyen if (hasWarningThresholds) 324*3c5486d4SThu Nguyen { 325*3c5486d4SThu Nguyen try 326*3c5486d4SThu Nguyen { 327*3c5486d4SThu Nguyen thresholdWarningIntf = 328*3c5486d4SThu Nguyen std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); 329*3c5486d4SThu Nguyen } 330*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 331*3c5486d4SThu Nguyen { 332*3c5486d4SThu Nguyen lg2::error( 333*3c5486d4SThu Nguyen "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}", 334*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 335*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 336*3c5486d4SThu Nguyen InvalidArgument(); 337*3c5486d4SThu Nguyen } 338*3c5486d4SThu Nguyen thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); 339*3c5486d4SThu Nguyen thresholdWarningIntf->warningLow(unitModifier(warningLow)); 340*3c5486d4SThu Nguyen } 341*3c5486d4SThu Nguyen 342*3c5486d4SThu Nguyen if (hasCriticalThresholds) 343*3c5486d4SThu Nguyen { 344*3c5486d4SThu Nguyen try 345*3c5486d4SThu Nguyen { 346*3c5486d4SThu Nguyen thresholdCriticalIntf = 347*3c5486d4SThu Nguyen std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); 348*3c5486d4SThu Nguyen } 349*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 350*3c5486d4SThu Nguyen { 351*3c5486d4SThu Nguyen lg2::error( 352*3c5486d4SThu Nguyen "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}", 353*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 354*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 355*3c5486d4SThu Nguyen InvalidArgument(); 356*3c5486d4SThu Nguyen } 357*3c5486d4SThu Nguyen thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); 358*3c5486d4SThu Nguyen thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); 359*3c5486d4SThu Nguyen } 360*3c5486d4SThu Nguyen } 361*3c5486d4SThu Nguyen 362*3c5486d4SThu Nguyen NumericSensor::NumericSensor( 363*3c5486d4SThu Nguyen const pldm_tid_t tid, const bool sensorDisabled, 364*3c5486d4SThu Nguyen std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr, 365*3c5486d4SThu Nguyen std::string& sensorName, std::string& associationPath) : 366*3c5486d4SThu Nguyen tid(tid), 367*3c5486d4SThu Nguyen sensorName(sensorName), isPriority(false) 368*3c5486d4SThu Nguyen { 369*3c5486d4SThu Nguyen if (!pdr) 370*3c5486d4SThu Nguyen { 371*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 372*3c5486d4SThu Nguyen } 373*3c5486d4SThu Nguyen 374*3c5486d4SThu Nguyen sensorId = pdr->sensor_id; 375*3c5486d4SThu Nguyen std::string path; 376*3c5486d4SThu Nguyen SensorUnit sensorUnit = SensorUnit::DegreesC; 377*3c5486d4SThu Nguyen 378*3c5486d4SThu Nguyen switch (pdr->base_unit) 379*3c5486d4SThu Nguyen { 380*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_DEGRESS_C: 381*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/"; 382*3c5486d4SThu Nguyen sensorUnit = SensorUnit::DegreesC; 383*3c5486d4SThu Nguyen break; 384*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_VOLTS: 385*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/"; 386*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Volts; 387*3c5486d4SThu Nguyen break; 388*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_AMPS: 389*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/current/"; 390*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Amperes; 391*3c5486d4SThu Nguyen break; 392*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_RPM: 393*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/"; 394*3c5486d4SThu Nguyen sensorUnit = SensorUnit::RPMS; 395*3c5486d4SThu Nguyen break; 396*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_WATTS: 397*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/power/"; 398*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Watts; 399*3c5486d4SThu Nguyen break; 400*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_JOULES: 401*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/energy/"; 402*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Joules; 403*3c5486d4SThu Nguyen break; 404*3c5486d4SThu Nguyen case PLDM_SENSOR_UNIT_PERCENTAGE: 405*3c5486d4SThu Nguyen sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/"; 406*3c5486d4SThu Nguyen sensorUnit = SensorUnit::Percent; 407*3c5486d4SThu Nguyen break; 408*3c5486d4SThu Nguyen default: 409*3c5486d4SThu Nguyen lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME", 410*3c5486d4SThu Nguyen sensorName, "UNIT", pdr->base_unit); 411*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 412*3c5486d4SThu Nguyen InvalidArgument(); 413*3c5486d4SThu Nguyen break; 414*3c5486d4SThu Nguyen } 415*3c5486d4SThu Nguyen 416*3c5486d4SThu Nguyen path = sensorNameSpace + sensorName; 417*3c5486d4SThu Nguyen try 418*3c5486d4SThu Nguyen { 419*3c5486d4SThu Nguyen auto service = pldm::utils::DBusHandler().getService( 420*3c5486d4SThu Nguyen path.c_str(), "xyz.openbmc_project.Sensor.Value"); 421*3c5486d4SThu Nguyen if (!service.empty()) 422*3c5486d4SThu Nguyen { 423*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 424*3c5486d4SThu Nguyen TooManyResources(); 425*3c5486d4SThu Nguyen } 426*3c5486d4SThu Nguyen } 427*3c5486d4SThu Nguyen catch (const std::exception&) 428*3c5486d4SThu Nguyen { 429*3c5486d4SThu Nguyen /* The sensor object path is not created */ 430*3c5486d4SThu Nguyen } 431*3c5486d4SThu Nguyen 432*3c5486d4SThu Nguyen auto& bus = pldm::utils::DBusHandler::getBus(); 433*3c5486d4SThu Nguyen try 434*3c5486d4SThu Nguyen { 435*3c5486d4SThu Nguyen associationDefinitionsIntf = 436*3c5486d4SThu Nguyen std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); 437*3c5486d4SThu Nguyen } 438*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 439*3c5486d4SThu Nguyen { 440*3c5486d4SThu Nguyen lg2::error( 441*3c5486d4SThu Nguyen "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}", 442*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 443*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 444*3c5486d4SThu Nguyen } 445*3c5486d4SThu Nguyen associationDefinitionsIntf->associations( 446*3c5486d4SThu Nguyen {{"chassis", "all_sensors", associationPath.c_str()}}); 447*3c5486d4SThu Nguyen 448*3c5486d4SThu Nguyen double maxValue = std::numeric_limits<double>::quiet_NaN(); 449*3c5486d4SThu Nguyen double minValue = std::numeric_limits<double>::quiet_NaN(); 450*3c5486d4SThu Nguyen bool hasWarningThresholds = false; 451*3c5486d4SThu Nguyen bool hasCriticalThresholds = false; 452*3c5486d4SThu Nguyen double criticalHigh = std::numeric_limits<double>::quiet_NaN(); 453*3c5486d4SThu Nguyen double criticalLow = std::numeric_limits<double>::quiet_NaN(); 454*3c5486d4SThu Nguyen double warningHigh = std::numeric_limits<double>::quiet_NaN(); 455*3c5486d4SThu Nguyen double warningLow = std::numeric_limits<double>::quiet_NaN(); 456*3c5486d4SThu Nguyen 457*3c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit0) 458*3c5486d4SThu Nguyen { 459*3c5486d4SThu Nguyen hasWarningThresholds = true; 460*3c5486d4SThu Nguyen warningHigh = pdr->warning_high; 461*3c5486d4SThu Nguyen } 462*3c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit1) 463*3c5486d4SThu Nguyen { 464*3c5486d4SThu Nguyen hasWarningThresholds = true; 465*3c5486d4SThu Nguyen warningLow = pdr->warning_low; 466*3c5486d4SThu Nguyen } 467*3c5486d4SThu Nguyen 468*3c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit2) 469*3c5486d4SThu Nguyen { 470*3c5486d4SThu Nguyen hasCriticalThresholds = true; 471*3c5486d4SThu Nguyen criticalHigh = pdr->critical_high; 472*3c5486d4SThu Nguyen } 473*3c5486d4SThu Nguyen 474*3c5486d4SThu Nguyen if (pdr->range_field_support.bits.bit3) 475*3c5486d4SThu Nguyen { 476*3c5486d4SThu Nguyen hasCriticalThresholds = true; 477*3c5486d4SThu Nguyen criticalLow = pdr->critical_low; 478*3c5486d4SThu Nguyen } 479*3c5486d4SThu Nguyen 480*3c5486d4SThu Nguyen resolution = std::numeric_limits<double>::quiet_NaN(); 481*3c5486d4SThu Nguyen offset = std::numeric_limits<double>::quiet_NaN(); 482*3c5486d4SThu Nguyen baseUnitModifier = pdr->unit_modifier; 483*3c5486d4SThu Nguyen 484*3c5486d4SThu Nguyen /** 485*3c5486d4SThu Nguyen * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds 486*3c5486d4SThu Nguyen * updateTime is in microseconds 487*3c5486d4SThu Nguyen */ 488*3c5486d4SThu Nguyen updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); 489*3c5486d4SThu Nguyen try 490*3c5486d4SThu Nguyen { 491*3c5486d4SThu Nguyen valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); 492*3c5486d4SThu Nguyen } 493*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 494*3c5486d4SThu Nguyen { 495*3c5486d4SThu Nguyen lg2::error( 496*3c5486d4SThu Nguyen "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}", 497*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 498*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 499*3c5486d4SThu Nguyen } 500*3c5486d4SThu Nguyen valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); 501*3c5486d4SThu Nguyen valueIntf->minValue(unitModifier(conversionFormula(minValue))); 502*3c5486d4SThu Nguyen hysteresis = unitModifier(conversionFormula(hysteresis)); 503*3c5486d4SThu Nguyen valueIntf->unit(sensorUnit); 504*3c5486d4SThu Nguyen 505*3c5486d4SThu Nguyen try 506*3c5486d4SThu Nguyen { 507*3c5486d4SThu Nguyen availabilityIntf = std::make_unique<AvailabilityIntf>(bus, 508*3c5486d4SThu Nguyen path.c_str()); 509*3c5486d4SThu Nguyen } 510*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 511*3c5486d4SThu Nguyen { 512*3c5486d4SThu Nguyen lg2::error( 513*3c5486d4SThu Nguyen "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}", 514*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 515*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 516*3c5486d4SThu Nguyen } 517*3c5486d4SThu Nguyen availabilityIntf->available(true); 518*3c5486d4SThu Nguyen 519*3c5486d4SThu Nguyen try 520*3c5486d4SThu Nguyen { 521*3c5486d4SThu Nguyen operationalStatusIntf = 522*3c5486d4SThu Nguyen std::make_unique<OperationalStatusIntf>(bus, path.c_str()); 523*3c5486d4SThu Nguyen } 524*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 525*3c5486d4SThu Nguyen { 526*3c5486d4SThu Nguyen lg2::error( 527*3c5486d4SThu Nguyen "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}", 528*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 529*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 530*3c5486d4SThu Nguyen } 531*3c5486d4SThu Nguyen operationalStatusIntf->functional(!sensorDisabled); 532*3c5486d4SThu Nguyen 533*3c5486d4SThu Nguyen if (hasWarningThresholds) 534*3c5486d4SThu Nguyen { 535*3c5486d4SThu Nguyen try 536*3c5486d4SThu Nguyen { 537*3c5486d4SThu Nguyen thresholdWarningIntf = 538*3c5486d4SThu Nguyen std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); 539*3c5486d4SThu Nguyen } 540*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 541*3c5486d4SThu Nguyen { 542*3c5486d4SThu Nguyen lg2::error( 543*3c5486d4SThu Nguyen "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}", 544*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 545*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 546*3c5486d4SThu Nguyen InvalidArgument(); 547*3c5486d4SThu Nguyen } 548*3c5486d4SThu Nguyen thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); 549*3c5486d4SThu Nguyen thresholdWarningIntf->warningLow(unitModifier(warningLow)); 550*3c5486d4SThu Nguyen } 551*3c5486d4SThu Nguyen 552*3c5486d4SThu Nguyen if (hasCriticalThresholds) 553*3c5486d4SThu Nguyen { 554*3c5486d4SThu Nguyen try 555*3c5486d4SThu Nguyen { 556*3c5486d4SThu Nguyen thresholdCriticalIntf = 557*3c5486d4SThu Nguyen std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); 558*3c5486d4SThu Nguyen } 559*3c5486d4SThu Nguyen catch (const sdbusplus::exception_t& e) 560*3c5486d4SThu Nguyen { 561*3c5486d4SThu Nguyen lg2::error( 562*3c5486d4SThu Nguyen "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}", 563*3c5486d4SThu Nguyen "PATH", path, "ERROR", e); 564*3c5486d4SThu Nguyen throw sdbusplus::xyz::openbmc_project::Common::Error:: 565*3c5486d4SThu Nguyen InvalidArgument(); 566*3c5486d4SThu Nguyen } 567*3c5486d4SThu Nguyen thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); 568*3c5486d4SThu Nguyen thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); 569*3c5486d4SThu Nguyen } 570*3c5486d4SThu Nguyen } 571*3c5486d4SThu Nguyen 572*3c5486d4SThu Nguyen double NumericSensor::conversionFormula(double value) 573*3c5486d4SThu Nguyen { 574*3c5486d4SThu Nguyen double convertedValue = value; 575*3c5486d4SThu Nguyen convertedValue *= std::isnan(resolution) ? 1 : resolution; 576*3c5486d4SThu Nguyen convertedValue += std::isnan(offset) ? 0 : offset; 577*3c5486d4SThu Nguyen return convertedValue; 578*3c5486d4SThu Nguyen } 579*3c5486d4SThu Nguyen 580*3c5486d4SThu Nguyen double NumericSensor::unitModifier(double value) 581*3c5486d4SThu Nguyen { 582*3c5486d4SThu Nguyen return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier); 583*3c5486d4SThu Nguyen } 584*3c5486d4SThu Nguyen } // namespace platform_mc 585*3c5486d4SThu Nguyen } // namespace pldm 586