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