1 /**
2  * Copyright © 2021 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include "sensors.hpp"
19 
20 #include <sdbusplus/bus.hpp>
21 #include <sdbusplus/server/object.hpp>
22 #include <xyz/openbmc_project/Association/Definitions/server.hpp>
23 #include <xyz/openbmc_project/Sensor/Value/server.hpp>
24 #include <xyz/openbmc_project/State/Decorator/Availability/server.hpp>
25 #include <xyz/openbmc_project/State/Decorator/OperationalStatus/server.hpp>
26 
27 #include <chrono>
28 #include <memory>
29 #include <string>
30 #include <tuple>
31 #include <vector>
32 
33 namespace phosphor::power::regulators
34 {
35 
36 /**
37  * Define simple name for the generated C++ class that implements the
38  * xyz.openbmc_project.Sensor.Value interface.
39  */
40 using ValueInterface = sdbusplus::xyz::openbmc_project::Sensor::server::Value;
41 
42 /**
43  * Define simple name for the generated C++ class that implements the
44  * xyz.openbmc_project.State.Decorator.OperationalStatus interface.
45  */
46 using OperationalStatusInterface = sdbusplus::xyz::openbmc_project::State::
47     Decorator::server::OperationalStatus;
48 
49 /**
50  * Define simple name for the generated C++ class that implements the
51  * xyz.openbmc_project.State.Decorator.Availability interface.
52  */
53 using AvailabilityInterface =
54     sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability;
55 
56 /**
57  * Define simple name for the generated C++ class that implements the
58  * xyz.openbmc_project.Association.Definitions interface.
59  */
60 using AssociationDefinitionsInterface =
61     sdbusplus::xyz::openbmc_project::Association::server::Definitions;
62 
63 /**
64  * Define simple name for the sdbusplus object_t class that implements all
65  * the necessary D-Bus interfaces via templates/multiple inheritance.
66  */
67 using DBusSensorObject = sdbusplus::server::object_t<
68     ValueInterface, OperationalStatusInterface, AvailabilityInterface,
69     AssociationDefinitionsInterface>;
70 
71 /**
72  * Define simple name for the generated C++ enum that implements the
73  * valid sensor Unit values on D-Bus.
74  */
75 using Unit = sdbusplus::xyz::openbmc_project::Sensor::server::Value::Unit;
76 
77 /**
78  * Define simple name for the tuple used to create D-Bus associations.
79  */
80 using AssocationTuple = std::tuple<std::string, std::string, std::string>;
81 
82 /**
83  * Root object path for sensors.
84  */
85 constexpr const char* sensorsObjectPath = "/xyz/openbmc_project/sensors";
86 
87 /**
88  * @class DBusSensor
89  *
90  * This class represents a voltage regulator sensor on D-Bus.
91  *
92  * Each voltage rail in the system may provide multiple types of sensor data,
93  * such as temperature, output voltage, and output current.  A DBusSensor tracks
94  * one of these data types for a voltage rail.
95  */
96 class DBusSensor
97 {
98   public:
99     // Specify which compiler-generated methods we want
100     DBusSensor() = delete;
101     DBusSensor(const DBusSensor&) = delete;
102     DBusSensor(DBusSensor&&) = delete;
103     DBusSensor& operator=(const DBusSensor&) = delete;
104     DBusSensor& operator=(DBusSensor&&) = delete;
105     virtual ~DBusSensor() = default;
106 
107     /**
108      * Constructor.
109      *
110      * Throws an exception if an error occurs.
111      *
112      * @param bus D-Bus bus object
113      * @param name sensor name
114      * @param type sensor type
115      * @param value sensor value
116      * @param rail voltage rail associated with this sensor
117      * @param deviceInventoryPath D-Bus inventory path of the voltage regulator
118      *                            device that produces the rail
119      * @param chassisInventoryPath D-Bus inventory path of the chassis that
120      *                             contains the voltage regulator device
121      */
122     explicit DBusSensor(sdbusplus::bus_t& bus, const std::string& name,
123                         SensorType type, double value, const std::string& rail,
124                         const std::string& deviceInventoryPath,
125                         const std::string& chassisInventoryPath);
126 
127     /**
128      * Disable this sensor.
129      *
130      * Updates the sensor properties on D-Bus to indicate it is no longer
131      * receiving value updates.
132      *
133      * This method is normally called when the system is being powered off.
134      * Sensors are not read when the system is powered off.
135      */
136     void disable();
137 
138     /**
139      * Return the last time this sensor was updated.
140      *
141      * @return last update time
142      */
getLastUpdateTime() const143     const std::chrono::system_clock::time_point& getLastUpdateTime() const
144     {
145         return lastUpdateTime;
146     }
147 
148     /**
149      * Return the sensor name.
150      *
151      * @return sensor name
152      */
getName() const153     const std::string& getName() const
154     {
155         return name;
156     }
157 
158     /**
159      * Return the voltage regulator rail associated with this sensor.
160      *
161      * @return rail
162      */
getRail() const163     const std::string& getRail() const
164     {
165         return rail;
166     }
167 
168     /**
169      * Return the sensor type.
170      *
171      * @return sensor type
172      */
getType() const173     SensorType getType() const
174     {
175         return type;
176     }
177 
178     /**
179      * Set this sensor to the error state.
180      *
181      * Updates the sensor properties on D-Bus to indicate an error occurred and
182      * the sensor value could not be read.
183      */
184     void setToErrorState();
185 
186     /**
187      * Set the value of this sensor.
188      *
189      * Do not specify the value NaN.  This special value is used internally to
190      * indicate the sensor has been disabled or is in the error state.  Call the
191      * disable() or setToErrorState() method instead so that all affected D-Bus
192      * interfaces are updated correctly.
193      *
194      * @param value new sensor value
195      */
196     void setValue(double value);
197 
198   private:
199     /**
200      * Sensor value update policy.
201      *
202      * Determines whether a new sensor value should replace the current value on
203      * D-Bus.
204      */
205     enum class ValueUpdatePolicy : unsigned char
206     {
207         /**
208          * Hysteresis value update policy.
209          *
210          * The sensor value will only be updated if the new value differs from
211          * the current value by at least the hysteresis amount.  This avoids
212          * constant D-Bus traffic due to insignificant value changes.
213          */
214         hysteresis,
215 
216         /**
217          * Highest value update policy.
218          *
219          * The sensor value will only be updated if the new value is higher than
220          * the current value.
221          *
222          * Some sensors contain the highest value observed by the voltage
223          * regulator, such as the highest temperature or highest output voltage.
224          * The regulator internally calculates this value since it can poll the
225          * value very quickly and can catch transient events.
226          *
227          * When the sensor is read from the regulator, the regulator will often
228          * clear its internal value.  It will begin calculating a new highest
229          * value.  For this reason, the D-Bus sensor value is set to the highest
230          * value that has been read across all monitoring cycles.
231          *
232          * The D-Bus sensor value is cleared when the sensor is disabled.  This
233          * normally occurs when the system is powered off.  Thus, the D-Bus
234          * sensor value is normally the highest value read since the system was
235          * powered on.
236          */
237         highest,
238 
239         /**
240          * Lowest value update policy.
241          *
242          * The sensor value will only be updated if the new value is lower than
243          * the current value.
244          *
245          * Some sensors contain the lowest value observed by the voltage
246          * regulator, such as the lowest output current or lowest output
247          * voltage.  The regulator internally calculates this value since it can
248          * poll the value very quickly and can catch transient events.
249          *
250          * When the sensor is read from the regulator, the regulator will often
251          * clear its internal value.  It will begin calculating a new lowest
252          * value.  For this reason, the D-Bus sensor value is set to the lowest
253          * value that has been read across all monitoring cycles.
254          *
255          * The D-Bus sensor value is cleared when the sensor is disabled.  This
256          * normally occurs when the system is powered off.  Thus, the D-Bus
257          * sensor value is normally the lowest value read since the system was
258          * powered on.
259          */
260         lowest
261     };
262 
263     /**
264      * Get the D-Bus associations to create for this sensor.
265      *
266      * @param deviceInventoryPath D-Bus inventory path of the voltage regulator
267      *                            device that produces the rail
268      * @param chassisInventoryPath D-Bus inventory path of the chassis that
269      *                             contains the voltage regulator device
270      */
271     std::vector<AssocationTuple>
272         getAssociations(const std::string& deviceInventoryPath,
273                         const std::string& chassisInventoryPath);
274 
275     /**
276      * Get sensor properties that are based on the sensor type.
277      *
278      * The properties are returned in output parameters.
279      *
280      * Also initializes some data members whose value is based on the sensor
281      * type.
282      *
283      * @param objectPath returns the object path of this sensor
284      * @param unit returns the D-Bus unit for the sensor value
285      * @param minValue returns the minimum sensor value
286      * @param maxValue returns the maximum sensor value
287      */
288     void getTypeBasedProperties(std::string& objectPath, Unit& unit,
289                                 double& minValue, double& maxValue);
290 
291     /**
292      * Set the last time this sensor was updated.
293      */
setLastUpdateTime()294     void setLastUpdateTime()
295     {
296         lastUpdateTime = std::chrono::system_clock::now();
297     }
298 
299     /**
300      * Set the sensor value on D-Bus to NaN.
301      */
302     void setValueToNaN();
303 
304     /**
305      * Returns whether to update the sensor value on D-Bus with the specified
306      * new value.
307      *
308      * @param value new sensor value
309      * @return true if value should be updated on D-Bus, false otherwise
310      */
311     bool shouldUpdateValue(double value);
312 
313     /**
314      * D-Bus bus object.
315      */
316     sdbusplus::bus_t& bus;
317 
318     /**
319      * Sensor name.
320      */
321     std::string name{};
322 
323     /**
324      * Sensor type.
325      */
326     SensorType type;
327 
328     /**
329      * Voltage regulator rail associated with this sensor.
330      */
331     std::string rail{};
332 
333     /**
334      * Sensor value update policy.
335      */
336     ValueUpdatePolicy updatePolicy{ValueUpdatePolicy::hysteresis};
337 
338     /**
339      * Hysteresis value.
340      *
341      * Only used when updatePolicy is hysteresis.
342      */
343     double hysteresis{0.0};
344 
345     /**
346      * sdbusplus object_t class that implements all the necessary D-Bus
347      * interfaces via templates and multiple inheritance.
348      */
349     std::unique_ptr<DBusSensorObject> dbusObject{};
350 
351     /**
352      * Last time this sensor was updated.
353      */
354     std::chrono::system_clock::time_point lastUpdateTime{};
355 };
356 
357 } // namespace phosphor::power::regulators
358