xref: /openbmc/phosphor-power/phosphor-regulators/src/dbus_sensor.cpp (revision 92261f88729b618b1c31d20f28328a8aff73b83b)
1837ece7cSShawn McCarney /**
2837ece7cSShawn McCarney  * Copyright © 2021 IBM Corporation
3837ece7cSShawn McCarney  *
4837ece7cSShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
5837ece7cSShawn McCarney  * you may not use this file except in compliance with the License.
6837ece7cSShawn McCarney  * You may obtain a copy of the License at
7837ece7cSShawn McCarney  *
8837ece7cSShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
9837ece7cSShawn McCarney  *
10837ece7cSShawn McCarney  * Unless required by applicable law or agreed to in writing, software
11837ece7cSShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
12837ece7cSShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13837ece7cSShawn McCarney  * See the License for the specific language governing permissions and
14837ece7cSShawn McCarney  * limitations under the License.
15837ece7cSShawn McCarney  */
16837ece7cSShawn McCarney 
17837ece7cSShawn McCarney #include "dbus_sensor.hpp"
18837ece7cSShawn McCarney 
19837ece7cSShawn McCarney #include <cmath>
20837ece7cSShawn McCarney #include <limits>
21837ece7cSShawn McCarney #include <utility>
22837ece7cSShawn McCarney 
23837ece7cSShawn McCarney namespace phosphor::power::regulators
24837ece7cSShawn McCarney {
25837ece7cSShawn McCarney 
26837ece7cSShawn McCarney /**
27837ece7cSShawn McCarney  * Constants for current sensors.
28837ece7cSShawn McCarney  *
29837ece7cSShawn McCarney  * Values are in amperes.
30837ece7cSShawn McCarney  */
31837ece7cSShawn McCarney constexpr double currentMinValue = 0.0;
32837ece7cSShawn McCarney constexpr double currentMaxValue = 500.0;
33837ece7cSShawn McCarney constexpr double currentHysteresis = 1.0;
34837ece7cSShawn McCarney constexpr const char* currentNamespace = "current";
35837ece7cSShawn McCarney 
36837ece7cSShawn McCarney /**
37837ece7cSShawn McCarney  * Constants for power sensors.
38837ece7cSShawn McCarney  *
39837ece7cSShawn McCarney  * Values are in watts.
40837ece7cSShawn McCarney  */
41837ece7cSShawn McCarney constexpr double powerMinValue = 0.0;
42837ece7cSShawn McCarney constexpr double powerMaxValue = 1000.0;
43837ece7cSShawn McCarney constexpr double powerHysteresis = 1.0;
44837ece7cSShawn McCarney constexpr const char* powerNamespace = "power";
45837ece7cSShawn McCarney 
46837ece7cSShawn McCarney /**
47837ece7cSShawn McCarney  * Constants for temperature sensors.
48837ece7cSShawn McCarney  *
49837ece7cSShawn McCarney  * Values are in degrees Celsius.
50837ece7cSShawn McCarney  */
51837ece7cSShawn McCarney constexpr double temperatureMinValue = -50.0;
52837ece7cSShawn McCarney constexpr double temperatureMaxValue = 250.0;
53837ece7cSShawn McCarney constexpr double temperatureHysteresis = 1.0;
54837ece7cSShawn McCarney constexpr const char* temperatureNamespace = "temperature";
55837ece7cSShawn McCarney 
56837ece7cSShawn McCarney /**
57837ece7cSShawn McCarney  * Constants for voltage sensors.
58837ece7cSShawn McCarney  *
59837ece7cSShawn McCarney  * Values are in volts.
60837ece7cSShawn McCarney  *
61837ece7cSShawn McCarney  * Note the hysteresis value is very low.  Small voltage changes can have a big
62837ece7cSShawn McCarney  * impact in some systems.  The sensors need to reflect these small changes.
63837ece7cSShawn McCarney  */
64837ece7cSShawn McCarney constexpr double voltageMinValue = -15.0;
65837ece7cSShawn McCarney constexpr double voltageMaxValue = 15.0;
66837ece7cSShawn McCarney constexpr double voltageHysteresis = 0.001;
67837ece7cSShawn McCarney constexpr const char* voltageNamespace = "voltage";
68837ece7cSShawn McCarney 
DBusSensor(sdbusplus::bus_t & bus,const std::string & name,SensorType type,double value,const std::string & rail,const std::string & deviceInventoryPath,const std::string & chassisInventoryPath)697354ce62SPatrick Williams DBusSensor::DBusSensor(sdbusplus::bus_t& bus, const std::string& name,
70837ece7cSShawn McCarney                        SensorType type, double value, const std::string& rail,
71837ece7cSShawn McCarney                        const std::string& deviceInventoryPath,
72837ece7cSShawn McCarney                        const std::string& chassisInventoryPath) :
73f5402197SPatrick Williams     bus{bus}, name{name}, type{type}, rail{rail}
74837ece7cSShawn McCarney {
75837ece7cSShawn McCarney     // Get sensor properties that are based on the sensor type
76837ece7cSShawn McCarney     std::string objectPath;
77837ece7cSShawn McCarney     Unit unit;
78837ece7cSShawn McCarney     double minValue, maxValue;
79837ece7cSShawn McCarney     getTypeBasedProperties(objectPath, unit, minValue, maxValue);
80837ece7cSShawn McCarney 
81837ece7cSShawn McCarney     // Get the D-Bus associations to create for this sensor
82837ece7cSShawn McCarney     std::vector<AssocationTuple> associations =
83837ece7cSShawn McCarney         getAssociations(deviceInventoryPath, chassisInventoryPath);
84837ece7cSShawn McCarney 
85837ece7cSShawn McCarney     // Create the sdbusplus object that implements the D-Bus sensor interfaces.
86837ece7cSShawn McCarney     // Skip emitting D-Bus signals until the object has been fully created.
873fa31a7cSPatrick Williams     dbusObject = std::make_unique<DBusSensorObject>(
883fa31a7cSPatrick Williams         bus, objectPath.c_str(), DBusSensorObject::action::defer_emit);
89837ece7cSShawn McCarney 
90837ece7cSShawn McCarney     // Set properties of the Value interface
913fa31a7cSPatrick Williams     constexpr auto skipSignal = true;
92837ece7cSShawn McCarney     dbusObject->value(value, skipSignal);
93837ece7cSShawn McCarney     dbusObject->maxValue(maxValue, skipSignal);
94837ece7cSShawn McCarney     dbusObject->minValue(minValue, skipSignal);
95837ece7cSShawn McCarney     dbusObject->unit(unit, skipSignal);
96837ece7cSShawn McCarney 
97837ece7cSShawn McCarney     // Set properties of the OperationalStatus interface
98837ece7cSShawn McCarney     dbusObject->functional(true, skipSignal);
99837ece7cSShawn McCarney 
100837ece7cSShawn McCarney     // Set properties of the Availability interface
101837ece7cSShawn McCarney     dbusObject->available(true, skipSignal);
102837ece7cSShawn McCarney 
103837ece7cSShawn McCarney     // Set properties on the Association.Definitions interface
104837ece7cSShawn McCarney     dbusObject->associations(std::move(associations), skipSignal);
105837ece7cSShawn McCarney 
106837ece7cSShawn McCarney     // Now emit signal that object has been created
107837ece7cSShawn McCarney     dbusObject->emit_object_added();
10803a25f1bSShawn McCarney 
10903a25f1bSShawn McCarney     // Set the last update time
11003a25f1bSShawn McCarney     setLastUpdateTime();
111837ece7cSShawn McCarney }
112837ece7cSShawn McCarney 
disable()113837ece7cSShawn McCarney void DBusSensor::disable()
114837ece7cSShawn McCarney {
115837ece7cSShawn McCarney     // Set sensor value to NaN
116837ece7cSShawn McCarney     setValueToNaN();
117837ece7cSShawn McCarney 
118837ece7cSShawn McCarney     // Set the sensor to unavailable since it is disabled
119837ece7cSShawn McCarney     dbusObject->available(false);
12003a25f1bSShawn McCarney 
12103a25f1bSShawn McCarney     // Set the last update time
12203a25f1bSShawn McCarney     setLastUpdateTime();
123837ece7cSShawn McCarney }
124837ece7cSShawn McCarney 
setToErrorState()125837ece7cSShawn McCarney void DBusSensor::setToErrorState()
126837ece7cSShawn McCarney {
127837ece7cSShawn McCarney     // Set sensor value to NaN
128837ece7cSShawn McCarney     setValueToNaN();
129837ece7cSShawn McCarney 
130837ece7cSShawn McCarney     // Set the sensor to non-functional since it could not be read
131837ece7cSShawn McCarney     dbusObject->functional(false);
13203a25f1bSShawn McCarney 
13303a25f1bSShawn McCarney     // Set the last update time
13403a25f1bSShawn McCarney     setLastUpdateTime();
135837ece7cSShawn McCarney }
136837ece7cSShawn McCarney 
setValue(double value)137837ece7cSShawn McCarney void DBusSensor::setValue(double value)
138837ece7cSShawn McCarney {
139837ece7cSShawn McCarney     // Update value on D-Bus if necessary
140837ece7cSShawn McCarney     if (shouldUpdateValue(value))
141837ece7cSShawn McCarney     {
142837ece7cSShawn McCarney         dbusObject->value(value);
143837ece7cSShawn McCarney     }
144837ece7cSShawn McCarney 
145837ece7cSShawn McCarney     // Set the sensor to functional since it has a valid value
146837ece7cSShawn McCarney     dbusObject->functional(true);
147837ece7cSShawn McCarney 
148837ece7cSShawn McCarney     // Set the sensor to available since it is not disabled
149837ece7cSShawn McCarney     dbusObject->available(true);
15003a25f1bSShawn McCarney 
15103a25f1bSShawn McCarney     // Set the last update time
15203a25f1bSShawn McCarney     setLastUpdateTime();
153837ece7cSShawn McCarney }
154837ece7cSShawn McCarney 
getAssociations(const std::string & deviceInventoryPath,const std::string & chassisInventoryPath)155*92261f88SPatrick Williams std::vector<AssocationTuple> DBusSensor::getAssociations(
156*92261f88SPatrick Williams     const std::string& deviceInventoryPath,
157837ece7cSShawn McCarney     const std::string& chassisInventoryPath)
158837ece7cSShawn McCarney {
159837ece7cSShawn McCarney     std::vector<AssocationTuple> associations{};
160837ece7cSShawn McCarney 
161837ece7cSShawn McCarney     // Add an association between the sensor and the chassis.  This is used by
162837ece7cSShawn McCarney     // the Redfish support to find all the sensors in a chassis.
163837ece7cSShawn McCarney     associations.emplace_back(
164837ece7cSShawn McCarney         std::make_tuple("chassis", "all_sensors", chassisInventoryPath));
165837ece7cSShawn McCarney 
166837ece7cSShawn McCarney     // Add an association between the sensor and the voltage regulator device.
167837ece7cSShawn McCarney     // This is used by the Redfish support to find the hardware/inventory item
168837ece7cSShawn McCarney     // associated with a sensor.
169837ece7cSShawn McCarney     associations.emplace_back(
170837ece7cSShawn McCarney         std::make_tuple("inventory", "sensors", deviceInventoryPath));
171837ece7cSShawn McCarney 
172837ece7cSShawn McCarney     return associations;
173837ece7cSShawn McCarney }
174837ece7cSShawn McCarney 
getTypeBasedProperties(std::string & objectPath,Unit & unit,double & minValue,double & maxValue)175837ece7cSShawn McCarney void DBusSensor::getTypeBasedProperties(std::string& objectPath, Unit& unit,
176837ece7cSShawn McCarney                                         double& minValue, double& maxValue)
177837ece7cSShawn McCarney {
178837ece7cSShawn McCarney     const char* typeNamespace{""};
179837ece7cSShawn McCarney     switch (type)
180837ece7cSShawn McCarney     {
181837ece7cSShawn McCarney         case SensorType::iout:
182837ece7cSShawn McCarney             typeNamespace = currentNamespace;
183837ece7cSShawn McCarney             unit = Unit::Amperes;
184837ece7cSShawn McCarney             minValue = currentMinValue;
185837ece7cSShawn McCarney             maxValue = currentMaxValue;
186837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::hysteresis;
187837ece7cSShawn McCarney             hysteresis = currentHysteresis;
188837ece7cSShawn McCarney             break;
189837ece7cSShawn McCarney 
190837ece7cSShawn McCarney         case SensorType::iout_peak:
191837ece7cSShawn McCarney             typeNamespace = currentNamespace;
192837ece7cSShawn McCarney             unit = Unit::Amperes;
193837ece7cSShawn McCarney             minValue = currentMinValue;
194837ece7cSShawn McCarney             maxValue = currentMaxValue;
195837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::highest;
196837ece7cSShawn McCarney             break;
197837ece7cSShawn McCarney 
198837ece7cSShawn McCarney         case SensorType::iout_valley:
199837ece7cSShawn McCarney             typeNamespace = currentNamespace;
200837ece7cSShawn McCarney             unit = Unit::Amperes;
201837ece7cSShawn McCarney             minValue = currentMinValue;
202837ece7cSShawn McCarney             maxValue = currentMaxValue;
203837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::lowest;
204837ece7cSShawn McCarney             break;
205837ece7cSShawn McCarney 
206837ece7cSShawn McCarney         case SensorType::pout:
207837ece7cSShawn McCarney             typeNamespace = powerNamespace;
208837ece7cSShawn McCarney             unit = Unit::Watts;
209837ece7cSShawn McCarney             minValue = powerMinValue;
210837ece7cSShawn McCarney             maxValue = powerMaxValue;
211837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::hysteresis;
212837ece7cSShawn McCarney             hysteresis = powerHysteresis;
213837ece7cSShawn McCarney             break;
214837ece7cSShawn McCarney 
215837ece7cSShawn McCarney         case SensorType::temperature:
216837ece7cSShawn McCarney             typeNamespace = temperatureNamespace;
217837ece7cSShawn McCarney             unit = Unit::DegreesC;
218837ece7cSShawn McCarney             minValue = temperatureMinValue;
219837ece7cSShawn McCarney             maxValue = temperatureMaxValue;
220837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::hysteresis;
221837ece7cSShawn McCarney             hysteresis = temperatureHysteresis;
222837ece7cSShawn McCarney             break;
223837ece7cSShawn McCarney 
224837ece7cSShawn McCarney         case SensorType::temperature_peak:
225837ece7cSShawn McCarney             typeNamespace = temperatureNamespace;
226837ece7cSShawn McCarney             unit = Unit::DegreesC;
227837ece7cSShawn McCarney             minValue = temperatureMinValue;
228837ece7cSShawn McCarney             maxValue = temperatureMaxValue;
229837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::highest;
230837ece7cSShawn McCarney             break;
231837ece7cSShawn McCarney 
232837ece7cSShawn McCarney         case SensorType::vout:
233837ece7cSShawn McCarney             typeNamespace = voltageNamespace;
234837ece7cSShawn McCarney             unit = Unit::Volts;
235837ece7cSShawn McCarney             minValue = voltageMinValue;
236837ece7cSShawn McCarney             maxValue = voltageMaxValue;
237837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::hysteresis;
238837ece7cSShawn McCarney             hysteresis = voltageHysteresis;
239837ece7cSShawn McCarney             break;
240837ece7cSShawn McCarney 
241837ece7cSShawn McCarney         case SensorType::vout_peak:
242837ece7cSShawn McCarney             typeNamespace = voltageNamespace;
243837ece7cSShawn McCarney             unit = Unit::Volts;
244837ece7cSShawn McCarney             minValue = voltageMinValue;
245837ece7cSShawn McCarney             maxValue = voltageMaxValue;
246837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::highest;
247837ece7cSShawn McCarney             break;
248837ece7cSShawn McCarney 
249837ece7cSShawn McCarney         case SensorType::vout_valley:
250837ece7cSShawn McCarney         default:
251837ece7cSShawn McCarney             typeNamespace = voltageNamespace;
252837ece7cSShawn McCarney             unit = Unit::Volts;
253837ece7cSShawn McCarney             minValue = voltageMinValue;
254837ece7cSShawn McCarney             maxValue = voltageMaxValue;
255837ece7cSShawn McCarney             updatePolicy = ValueUpdatePolicy::lowest;
256837ece7cSShawn McCarney             break;
257837ece7cSShawn McCarney     }
258837ece7cSShawn McCarney 
259837ece7cSShawn McCarney     // Build object path
260837ece7cSShawn McCarney     objectPath = sensorsObjectPath;
261837ece7cSShawn McCarney     objectPath += '/';
262837ece7cSShawn McCarney     objectPath += typeNamespace;
263837ece7cSShawn McCarney     objectPath += '/';
264837ece7cSShawn McCarney     objectPath += name;
265837ece7cSShawn McCarney }
266837ece7cSShawn McCarney 
setValueToNaN()267837ece7cSShawn McCarney void DBusSensor::setValueToNaN()
268837ece7cSShawn McCarney {
269837ece7cSShawn McCarney     // Get current value published on D-Bus
270837ece7cSShawn McCarney     double currentValue = dbusObject->value();
271837ece7cSShawn McCarney 
272837ece7cSShawn McCarney     // Check if current value is already NaN.  We want to avoid an unnecessary
273837ece7cSShawn McCarney     // PropertiesChanged signal.  The generated C++ code for the Value interface
274837ece7cSShawn McCarney     // does check whether the new value is different from the old one.  However,
275837ece7cSShawn McCarney     // it uses the equality operator, and NaN always returns false when compared
276837ece7cSShawn McCarney     // to another NaN value.
277837ece7cSShawn McCarney     if (!std::isnan(currentValue))
278837ece7cSShawn McCarney     {
279837ece7cSShawn McCarney         // Set value to NaN
280837ece7cSShawn McCarney         dbusObject->value(std::numeric_limits<double>::quiet_NaN());
281837ece7cSShawn McCarney     }
282837ece7cSShawn McCarney }
283837ece7cSShawn McCarney 
shouldUpdateValue(double value)284837ece7cSShawn McCarney bool DBusSensor::shouldUpdateValue(double value)
285837ece7cSShawn McCarney {
286837ece7cSShawn McCarney     // Initially assume we should update the value
287837ece7cSShawn McCarney     bool shouldUpdate{true};
288837ece7cSShawn McCarney 
289837ece7cSShawn McCarney     // Get current value published on D-Bus
290837ece7cSShawn McCarney     double currentValue = dbusObject->value();
291837ece7cSShawn McCarney 
292837ece7cSShawn McCarney     // Update sensor if the current value is NaN.  This indicates it was
293837ece7cSShawn McCarney     // disabled or in an error state.  Note: you cannot compare a variable to
294837ece7cSShawn McCarney     // NaN directly using the equality operator; it will always return false.
295837ece7cSShawn McCarney     if (std::isnan(currentValue))
296837ece7cSShawn McCarney     {
297837ece7cSShawn McCarney         shouldUpdate = true;
298837ece7cSShawn McCarney     }
299837ece7cSShawn McCarney     else
300837ece7cSShawn McCarney     {
301837ece7cSShawn McCarney         // Determine whether to update based on policy used by this sensor
302837ece7cSShawn McCarney         switch (updatePolicy)
303837ece7cSShawn McCarney         {
304837ece7cSShawn McCarney             case ValueUpdatePolicy::hysteresis:
305837ece7cSShawn McCarney                 shouldUpdate = (std::abs(value - currentValue) >= hysteresis);
306837ece7cSShawn McCarney                 break;
307837ece7cSShawn McCarney             case ValueUpdatePolicy::highest:
308837ece7cSShawn McCarney                 shouldUpdate = (value > currentValue);
309837ece7cSShawn McCarney                 break;
310837ece7cSShawn McCarney             case ValueUpdatePolicy::lowest:
311837ece7cSShawn McCarney                 shouldUpdate = (value < currentValue);
312837ece7cSShawn McCarney                 break;
313837ece7cSShawn McCarney         }
314837ece7cSShawn McCarney     }
315837ece7cSShawn McCarney 
316837ece7cSShawn McCarney     return shouldUpdate;
317837ece7cSShawn McCarney }
318837ece7cSShawn McCarney 
319837ece7cSShawn McCarney } // namespace phosphor::power::regulators
320