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