1 #pragma once
2 #include <sdbusplus/bus/match.hpp>
3 #include "average.hpp"
4 #include "device.hpp"
5 #include "maximum.hpp"
6 #include "names_values.hpp"
7 #include "pmbus.hpp"
8 #include "record_manager.hpp"
9 #include "timer.hpp"
10 
11 namespace witherspoon
12 {
13 namespace power
14 {
15 namespace psu
16 {
17 
18 namespace sdbusRule = sdbusplus::bus::match::rules;
19 
20 constexpr auto FAULT_COUNT = 3;
21 
22 /**
23  * @class PowerSupply
24  * Represents a PMBus power supply device.
25  */
26 class PowerSupply : public Device
27 {
28     public:
29         PowerSupply() = delete;
30         PowerSupply(const PowerSupply&) = delete;
31         PowerSupply(PowerSupply&&) = default;
32         PowerSupply& operator=(const PowerSupply&) = default;
33         PowerSupply& operator=(PowerSupply&&) = default;
34         ~PowerSupply() = default;
35 
36         /**
37          * Constructor
38          *
39          * @param[in] name - the device name
40          * @param[in] inst - the device instance
41          * @param[in] objpath - the path to monitor
42          * @param[in] invpath - the inventory path to use
43          * @param[in] bus - D-Bus bus object
44          * @param[in] e - event object
45          * @param[in] t - time to allow power supply to assert PG#
46          * @param[in] p - time to allow power supply presence state to
47          *                settle/deglitch and allow for application of power
48          *                prior to fault checking
49          */
50         PowerSupply(const std::string& name, size_t inst,
51                     const std::string& objpath,
52                     const std::string& invpath,
53                     sdbusplus::bus::bus& bus,
54                     event::Event& e,
55                     std::chrono::seconds& t,
56                     std::chrono::seconds& p);
57 
58         /**
59          * Power supply specific function to analyze for faults/errors.
60          *
61          * Various PMBus status bits will be checked for fault conditions.
62          * If a certain fault bits are on, the appropriate error will be
63          * committed.
64          */
65         void analyze() override;
66 
67         /**
68          * Write PMBus CLEAR_FAULTS
69          *
70          * This function will be called in various situations in order to clear
71          * any fault status bits that may have been set, in order to start over
72          * with a clean state. Presence changes and power state changes will
73          * want to clear any faults logged.
74          */
75         void clearFaults() override;
76 
77         /**
78          * Mark error for specified callout and message as resolved.
79          *
80          * @param[in] callout - The callout to be resolved (inventory path)
81          * @parma[in] message - The message for the fault to be resolved
82          */
83         void resolveError(const std::string& callout,
84                           const std::string& message);
85 
86         /**
87          * Enables making the input power history available on D-Bus
88          *
89          * @param[in] objectPath - the D-Bus object path to use
90          * @param[in] maxRecords - the number of history records to keep
91          * @param[in] syncGPIOPath - The gpiochip device path to use for
92          *                           sending the sync command
93          * @paramp[in] syncGPIONum - the GPIO number for the sync command
94          */
95         void enableHistory(const std::string& objectPath,
96                            size_t numRecords,
97                            const std::string& syncGPIOPath,
98                            size_t syncGPIONum);
99 
100     private:
101         /**
102          * The path to use for reading various PMBus bits/words.
103          */
104         std::string monitorPath;
105 
106         /**
107          * @brief Pointer to the PMBus interface
108          *
109          * Used to read out of or write to the /sysfs tree(s) containing files
110          * that a device driver monitors the PMBus interface to the power
111          * supplies.
112          */
113         witherspoon::pmbus::PMBus pmbusIntf;
114 
115         /**
116          * @brief D-Bus path to use for this power supply's inventory status.
117          */
118         std::string inventoryPath;
119 
120         /** @brief Connection for sdbusplus bus */
121         sdbusplus::bus::bus& bus;
122 
123         /** @brief True if the power supply is present. */
124         bool present = false;
125 
126         /** @brief Used to subscribe to D-Bus property changes for Present */
127         std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
128 
129         /** @brief The sd_event structure used by the power on and present
130          *  timers. */
131         event::Event& event;
132 
133         /**
134          * @brief Interval for setting present to true.
135          *
136          * The amount of time to wait from not present to present change before
137          * updating the internal present indicator. Allows person servicing
138          * the power supply some time to plug in the cable.
139          */
140         std::chrono::seconds presentInterval;
141 
142         /**
143          * @brief Timer used to delay setting the internal present state.
144          *
145          * The timer used to do the callback after the present property has
146          * changed.
147          */
148         Timer presentTimer;
149 
150         /** @brief True if a fault has already been found and not cleared */
151         bool faultFound = false;
152 
153         /** @brief True if the power is on. */
154         bool powerOn = false;
155 
156         /**
157          * @brief Equal to FAULT_COUNT if power on fault has been
158          * detected.
159          */
160         size_t powerOnFault = 0;
161 
162         /**
163          * @brief Interval to setting powerOn to true.
164          *
165          * The amount of time to wait from power state on to setting the
166          * internal powerOn state to true. The amount of time the power supply
167          * is allowed to delay setting DGood/PG#.
168          */
169         std::chrono::seconds powerOnInterval;
170 
171         /**
172          * @brief Timer used to delay setting the internal powerOn state.
173          *
174          * The timer used to do the callback after the power state has been on
175          * long enough.
176          */
177         Timer powerOnTimer;
178 
179         /** @brief Used to subscribe to D-Bus power on state changes */
180         std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
181 
182         /** @brief Indicates that a read failure has occurred.
183          *
184          * @details This will be incremented each time a read failure is
185          *          encountered. If it is incremented to FAULT_COUNT, an error
186          *          will be logged.
187          */
188         size_t readFail = 0;
189 
190         /** @brief Has a PMBus read failure already been logged? */
191         bool readFailLogged = false;
192 
193         /**
194          * @brief Indicates an input fault or warning if equal to FAULT_COUNT.
195          *
196          * @details This is the "INPUT FAULT OR WARNING" bit in the high byte,
197          *          or the VIN_UV_FAULT bit in the low byte in the STATUS_WORD
198          *          command response. If either of those bits are on, this will
199          *          be incremented.
200          */
201         size_t inputFault = 0;
202 
203         /**
204          * @brief Indicates output over current fault if equal to FAULT_COUNT
205          *
206          * @details This is incremented when the "IOUT_OC_FAULT" bit in the low
207          *          byte from the STATUS_WORD command response is on.
208          */
209         size_t outputOCFault = 0;
210 
211         /**
212          * @brief Indicates output overvoltage fault if equal to FAULT_COUNT.
213          *
214          * @details This is incremented when the "VOUT_OV_FAULT" bit in the
215          *          STATUS_WORD command response is on.
216          */
217         size_t outputOVFault = 0;
218 
219         /**
220          * @brief Indicates a fan fault or warning condition was detected if
221          *        equal to FAULT_COUNT.
222          *
223          * @details This is incremented when the 'FAN_FAULT' bit in the
224          *          STATUS_WORD command response is on.
225          */
226         size_t fanFault = 0;
227 
228         /**
229          * @brief Indicates a temperature fault or warn condition was detected
230          *        if equal to FAULT_COUNT.
231          *
232          * @details This is incremented when the 'TEMPERATURE_FAULT_WARN' bit
233          *          in the STATUS_WORD command response is on, or if the
234          *          'OT_FAULT' bit in the STATUS_TEMPERATURE command response
235          *          is on.
236          */
237         size_t temperatureFault = 0;
238 
239         /**
240          * @brief Class that manages the input power history records.
241          */
242         std::unique_ptr<history::RecordManager> recordManager;
243 
244         /**
245          * @brief The D-Bus object for the average input power history
246          */
247         std::unique_ptr<history::Average> average;
248 
249         /**
250          * @brief The D-Bus object for the maximum input power history
251          */
252         std::unique_ptr<history::Maximum> maximum;
253 
254         /**
255          * @brief The base D-Bus object path to use for the average
256          *        and maximum objects.
257          */
258         std::string historyObjectPath;
259 
260         /**
261          * @brief The GPIO device path to use for sending the 'sync'
262          *        command to the PS.
263          */
264         std::string syncGPIODevPath;
265 
266         /**
267          * @brief The GPIO number to use for sending the 'sync'
268          *        command to the PS.
269          */
270         size_t syncGPIONumber = 0;
271 
272         /**
273          * @brief Callback for inventory property changes
274          *
275          * Process change of Present property for power supply.
276          *
277          * @param[in]  msg - Data associated with Present change signal
278          *
279          */
280         void inventoryChanged(sdbusplus::message::message& msg);
281 
282         /**
283          * Updates the presence status by querying D-Bus
284          *
285          * The D-Bus inventory properties for this power supply will be read to
286          * determine if the power supply is present or not and update this
287          * objects present member variable to reflect current status.
288          */
289         void updatePresence();
290 
291         /**
292          * @brief Updates the poweredOn status by querying D-Bus
293          *
294          * The D-Bus property for the system power state will be read to
295          * determine if the system is powered on or not.
296          */
297         void updatePowerState();
298 
299         /**
300          * @brief Callback for power state property changes
301          *
302          * Process changes to the powered on stat property for the system.
303          *
304          * @param[in] msg - Data associated with the power state signal
305          */
306         void powerStateChanged(sdbusplus::message::message& msg);
307 
308         /**
309          * @brief Wrapper for PMBus::read() and adding metadata
310          *
311          * @param[out] nv - NamesValues instance to store cmd string and value
312          * @param[in] cmd - String for the command to read data from.
313          * @param[in] type - The type of file to read the command from.
314          */
315         void captureCmd(util::NamesValues& nv, const std::string& cmd,
316                         witherspoon::pmbus::Type type);
317 
318         /**
319          * @brief Checks for input voltage faults and logs error if needed.
320          *
321          * Check for voltage input under voltage fault (VIN_UV_FAULT) and/or
322          * input fault or warning (INPUT_FAULT), and logs appropriate error(s).
323          *
324          * @param[in] statusWord  - 2 byte STATUS_WORD value read from sysfs
325          */
326         void checkInputFault(const uint16_t statusWord);
327 
328         /**
329          * @brief Checks for power good negated or unit is off in wrong state
330          *
331          * @param[in] statusWord  - 2 byte STATUS_WORD value read from sysfs
332          */
333         void checkPGOrUnitOffFault(const uint16_t statusWord);
334 
335         /**
336          * @brief Checks for output current over current fault.
337          *
338          * IOUT_OC_FAULT is checked, if on, appropriate error is logged.
339          *
340          * @param[in] statusWord  - 2 byte STATUS_WORD value read from sysfs
341          */
342         void checkCurrentOutOverCurrentFault(const uint16_t statusWord);
343 
344         /**
345          * @brief Checks for output overvoltage fault.
346          *
347          * VOUT_OV_FAULT is checked, if on, appropriate error is logged.
348          *
349          * @param[in] statusWord  - 2 byte STATUS_WORD value read from sysfs
350          */
351         void checkOutputOvervoltageFault(const uint16_t statusWord);
352 
353         /**
354          * @brief Checks for a fan fault or warning condition.
355          *
356          * The high byte of STATUS_WORD is checked to see if the "FAN FAULT OR
357          * WARNING" bit is turned on. If it is on, log an error.
358          *
359          * @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs
360          */
361         void checkFanFault(const uint16_t statusWord);
362 
363         /**
364          * @brief Checks for a temperature fault or warning condition.
365          *
366          * The low byte of STATUS_WORD is checked to see if the "TEMPERATURE
367          * FAULT OR WARNING" bit is turned on. If it is on, log an error,
368          * call out the power supply indicating the fault/warning condition.
369          *
370          * @parma[in] statusWord - 2 byte STATUS_WORD value read from sysfs
371          */
372         void checkTemperatureFault(const uint16_t statusWord);
373 
374         /**
375          * @brief Adds properties to the inventory.
376          *
377          * Reads the values from the device and writes them to the
378          * associated power supply D-Bus inventory object.
379          *
380          * This needs to be done on startup, and each time the presence
381          * state changes.
382          *
383          * Properties added:
384          * - Serial Number
385          * - Part Number
386          * - CCIN (Customer Card Identification Number) - added as the Model
387          * - Firmware version
388          */
389         void updateInventory();
390 
391         /**
392          * @brief Toggles the GPIO to sync power supply input history readings
393          *
394          * This GPIO is connected to all supplies.  This will clear the
395          * previous readings out of the supplies and restart them both at the
396          * same time zero and at record ID 0.  The supplies will return 0
397          * bytes of data for the input history command right after this until
398          * a new entry shows up.
399          *
400          * This will cause the code to delete all previous history data and
401          * start fresh.
402          */
403         void syncHistory();
404 
405         /**
406          * @brief Reads the most recent input history record from the power
407          *        supply and updates the average and maximum properties in
408          *        D-Bus if there is a new reading available.
409          *
410          * This will still run every time analyze() is called so code can
411          * post new data as soon as possible and the timestamp will more
412          * accurately reflect the correct time.
413          *
414          * D-Bus is only updated if there is a change and the oldest record
415          * will be pruned if the property already contains the max number of
416          * records.
417          */
418         void updateHistory();
419 };
420 
421 }
422 }
423 }
424