1 #pragma once
2 
3 #include "average.hpp"
4 #include "maximum.hpp"
5 #include "pmbus.hpp"
6 #include "record_manager.hpp"
7 #include "types.hpp"
8 #include "util.hpp"
9 #include "utility.hpp"
10 
11 #include <gpiod.hpp>
12 #include <sdbusplus/bus/match.hpp>
13 
14 #include <filesystem>
15 #include <stdexcept>
16 
17 namespace phosphor::power::psu
18 {
19 
20 #if IBM_VPD
21 // PMBus device driver "file name" to read for CCIN value.
22 constexpr auto CCIN = "ccin";
23 constexpr auto PART_NUMBER = "part_number";
24 constexpr auto FRU_NUMBER = "fru";
25 constexpr auto SERIAL_HEADER = "header";
26 constexpr auto SERIAL_NUMBER = "serial_number";
27 constexpr auto FW_VERSION = "fw_version";
28 
29 // The D-Bus property name to update with the CCIN value.
30 constexpr auto MODEL_PROP = "Model";
31 constexpr auto PN_PROP = "PartNumber";
32 constexpr auto SPARE_PN_PROP = "SparePartNumber";
33 constexpr auto SN_PROP = "SerialNumber";
34 constexpr auto VERSION_PROP = "Version";
35 
36 // ipzVPD Keyword sizes
37 static constexpr auto FL_KW_SIZE = 20;
38 #endif
39 
40 constexpr auto LOG_LIMIT = 3;
41 constexpr auto DEGLITCH_LIMIT = 3;
42 constexpr auto PGOOD_DEGLITCH_LIMIT = 5;
43 
44 /**
45  * @class PowerSupply
46  * Represents a PMBus power supply device.
47  */
48 class PowerSupply
49 {
50   public:
51     PowerSupply() = delete;
52     PowerSupply(const PowerSupply&) = delete;
53     PowerSupply(PowerSupply&&) = delete;
54     PowerSupply& operator=(const PowerSupply&) = delete;
55     PowerSupply& operator=(PowerSupply&&) = delete;
56     ~PowerSupply() = default;
57 
58     /**
59      * @param[in] invpath - String for inventory path to use
60      * @param[in] i2cbus - The bus number this power supply is on
61      * @param[in] i2caddr - The 16-bit I2C address of the power supply
62      * @param[in] driver - i2c driver name for power supply
63      * @param[in] gpioLineName - The gpio-line-name to read for presence. See
64      * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md
65      */
66     PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
67                 std::uint8_t i2cbus, const std::uint16_t i2caddr,
68                 const std::string& driver, const std::string& gpioLineName);
69 
70     phosphor::pmbus::PMBusBase& getPMBus()
71     {
72         return *pmbusIntf;
73     }
74 
75     GPIOInterfaceBase* getPresenceGPIO()
76     {
77         return presenceGPIO.get();
78     }
79 
80     std::string getPresenceGPIOName() const
81     {
82         if (presenceGPIO != nullptr)
83         {
84             return presenceGPIO->getName();
85         }
86         else
87         {
88             return std::string();
89         }
90     }
91 
92     /**
93      * Power supply specific function to analyze for faults/errors.
94      *
95      * Various PMBus status bits will be checked for fault conditions.
96      * If a certain fault bits are on, the appropriate error will be
97      * committed.
98      */
99     void analyze();
100 
101     /**
102      * Write PMBus ON_OFF_CONFIG
103      *
104      * This function will be called to cause the PMBus device driver to send the
105      * ON_OFF_CONFIG command. Takes one byte of data.
106      *
107      * @param[in] data - The ON_OFF_CONFIG data byte mask.
108      */
109     void onOffConfig(uint8_t data);
110 
111     /**
112      * Clears all the member variables that indicate if a fault bit was seen as
113      * on in the STATUS_WORD or STATUS_MFR_SPECIFIC response.
114      */
115     void clearFaultFlags()
116     {
117         inputFault = 0;
118         mfrFault = 0;
119         statusMFR = 0;
120         vinUVFault = 0;
121         cmlFault = 0;
122         voutOVFault = 0;
123         ioutOCFault = 0;
124         voutUVFault = 0;
125         fanFault = 0;
126         tempFault = 0;
127         pgoodFault = 0;
128         psKillFault = 0;
129         ps12VcsFault = 0;
130         psCS12VFault = 0;
131         faultLogged = false;
132     }
133 
134     /**
135      * @brief Function to specifically clear VIN_UV/OFF fault(s).
136      *
137      * The PMBus HWMON device driver has various alarm "files" to read out of
138      * sysfs. Reading those files will indicate if various alarms are active or
139      * not, and then specifically clear those faults that go with that alarm.
140      *
141      * The VIN_UV fault, indicated in STATUS_INPUT, goes with in1_lcrit_alarm.
142      * When a VIN_UV fault occurs, the "Unit Off For Insufficient Input Voltage"
143      * may also be active. Reading in1_lcrit_alarm should clear both fault bits,
144      * resulting in the corresponding fault bits in STATUS_WORD also clearing.
145      *
146      * See: https://www.kernel.org/doc/html/latest/hwmon/pmbus.html
147      */
148     void clearVinUVFault();
149 
150     /**
151      * Write PMBus CLEAR_FAULTS
152      *
153      * This function will be called in various situations in order to clear
154      * any fault status bits that may have been set, in order to start over
155      * with a clean state. Presence changes and power state changes will
156      * want to clear any faults logged.
157      */
158     void clearFaults();
159 
160     /**
161      * @brief Adds properties to the inventory.
162      *
163      * Reads the values from the device and writes them to the
164      * associated power supply D-Bus inventory object.
165      *
166      * This needs to be done on startup, and each time the presence
167      * state changes.
168      *
169      * Properties added:
170      * - Serial Number
171      * - Part Number
172      * - CCIN (Customer Card Identification Number) - added as the Model
173      * - Firmware version
174      */
175     void updateInventory();
176 
177     /**
178      * @brief Accessor function to indicate present status
179      */
180     bool isPresent() const
181     {
182         return present;
183     }
184 
185     /**
186      * @brief Returns the last read value from STATUS_WORD.
187      */
188     uint64_t getStatusWord() const
189     {
190         return statusWord;
191     }
192 
193     /**
194      * @brief Returns the last read value from STATUS_INPUT.
195      */
196     uint64_t getStatusInput() const
197     {
198         return statusInput;
199     }
200 
201     /**
202      * @brief Returns the last read value from STATUS_MFR.
203      */
204     uint64_t getMFRFault() const
205     {
206         return statusMFR;
207     }
208 
209     /**
210      * @brief Returns the last read value from STATUS_CML.
211      */
212     uint64_t getStatusCML() const
213     {
214         return statusCML;
215     }
216 
217     /**
218      * @brief Returns the last read value from STATUS_VOUT.
219      */
220     uint64_t getStatusVout() const
221     {
222         return statusVout;
223     }
224 
225     /**
226      * @brief Returns the last value read from STATUS_IOUT.
227      */
228     uint64_t getStatusIout() const
229     {
230         return statusIout;
231     }
232 
233     /**
234      * @brief Returns the last value read from STATUS_FANS_1_2.
235      */
236     uint64_t getStatusFans12() const
237     {
238         return statusFans12;
239     }
240 
241     /**
242      * @brief Returns the last value read from STATUS_TEMPERATURE.
243      */
244     uint64_t getStatusTemperature() const
245     {
246         return statusTemperature;
247     }
248 
249     /**
250      * @brief Returns true if a fault was found.
251      */
252     bool isFaulted() const
253     {
254         return (hasCommFault() || (vinUVFault >= DEGLITCH_LIMIT) ||
255                 (inputFault >= DEGLITCH_LIMIT) ||
256                 (voutOVFault >= DEGLITCH_LIMIT) ||
257                 (ioutOCFault >= DEGLITCH_LIMIT) ||
258                 (voutUVFault >= DEGLITCH_LIMIT) ||
259                 (fanFault >= DEGLITCH_LIMIT) || (tempFault >= DEGLITCH_LIMIT) ||
260                 (pgoodFault >= PGOOD_DEGLITCH_LIMIT) ||
261                 (mfrFault >= DEGLITCH_LIMIT));
262     }
263 
264     /**
265      * @brief Return whether a fault has been logged for this power supply
266      */
267     bool isFaultLogged() const
268     {
269         return faultLogged;
270     }
271 
272     /**
273      * @brief Called when a fault for this power supply has been logged.
274      */
275     void setFaultLogged()
276     {
277         faultLogged = true;
278     }
279 
280     /**
281      * @brief Returns true if INPUT fault occurred.
282      */
283     bool hasInputFault() const
284     {
285         return (inputFault >= DEGLITCH_LIMIT);
286     }
287 
288     /**
289      * @brief Returns true if MFRSPECIFIC occurred.
290      */
291     bool hasMFRFault() const
292     {
293         return (mfrFault >= DEGLITCH_LIMIT);
294     }
295 
296     /**
297      * @brief Returns true if VIN_UV_FAULT occurred.
298      */
299     bool hasVINUVFault() const
300     {
301         return (vinUVFault >= DEGLITCH_LIMIT);
302     }
303 
304     /**
305      * @brief Returns true if VOUT_OV_FAULT occurred.
306      */
307     bool hasVoutOVFault() const
308     {
309         return (voutOVFault >= DEGLITCH_LIMIT);
310     }
311 
312     /**
313      * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE).
314      */
315     bool hasIoutOCFault() const
316     {
317         return (ioutOCFault >= DEGLITCH_LIMIT);
318     }
319 
320     /**
321      * @brief Returns true if VOUT_UV_FAULT occurred.
322      */
323     bool hasVoutUVFault() const
324     {
325         return (voutUVFault >= DEGLITCH_LIMIT);
326     }
327 
328     /**
329      *@brief Returns true if fan fault occurred.
330      */
331     bool hasFanFault() const
332     {
333         return (fanFault >= DEGLITCH_LIMIT);
334     }
335 
336     /**
337      * @brief Returns true if TEMPERATURE fault occurred.
338      */
339     bool hasTempFault() const
340     {
341         return (tempFault >= DEGLITCH_LIMIT);
342     }
343 
344     /**
345      * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF
346      * bit on).
347      */
348     bool hasPgoodFault() const
349     {
350         return (pgoodFault >= PGOOD_DEGLITCH_LIMIT);
351     }
352 
353     /**
354      * @brief Return true if there is a PS_Kill fault.
355      */
356     bool hasPSKillFault() const
357     {
358         return (psKillFault >= DEGLITCH_LIMIT);
359     }
360 
361     /**
362      * @brief Returns true if there is a 12Vcs (standy power) fault.
363      */
364     bool hasPS12VcsFault() const
365     {
366         return (ps12VcsFault >= DEGLITCH_LIMIT);
367     }
368 
369     /**
370      * @brief Returns true if there is a 12V current-share fault.
371      */
372     bool hasPSCS12VFault() const
373     {
374         return (psCS12VFault >= DEGLITCH_LIMIT);
375     }
376 
377     /**
378      * @brief Returns the device path
379      *
380      * This can be used for error call outs.
381      * Example: /sys/bus/i2c/devices/3-0068
382      */
383     const std::string getDevicePath() const
384     {
385         return pmbusIntf->path();
386     }
387 
388     /**
389      * @brief Returns this power supply's inventory path.
390      *
391      * This can be used for error call outs.
392      * Example:
393      * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
394      */
395     const std::string& getInventoryPath() const
396     {
397         return inventoryPath;
398     }
399 
400     /**
401      * @brief Returns the short name (last part of inventoryPath).
402      */
403     const std::string& getShortName() const
404     {
405         return shortName;
406     }
407 
408     /**
409      * @brief Returns the firmware revision version read from the power supply
410      */
411     const std::string& getFWVersion() const
412     {
413         return fwVersion;
414     }
415 
416     /**
417      * @brief Returns the model name of the power supply
418      */
419     const std::string& getModelName() const
420     {
421         return modelName;
422     }
423 
424     /** @brief Returns true if the number of failed reads exceeds limit
425      * TODO: or CML bit on.
426      */
427     bool hasCommFault() const
428     {
429         return ((readFail >= LOG_LIMIT) || (cmlFault >= DEGLITCH_LIMIT));
430     }
431 
432     /**
433      * @brief Reads the pmbus input voltage and returns that actual voltage
434      *        reading and the calculated input voltage based on thresholds.
435      * @param[out] actualInputVoltage - The actual voltage reading, in Volts.
436      * @param[out] inputVoltage - A rounded up/down value of the actual input
437      *             voltage based on thresholds, in Volts.
438      */
439     void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const;
440 
441     /**
442      * @brief Check if the PS is considered to be available or not
443      *
444      * It is unavailable if any of:
445      * - not present
446      * - input fault active
447      * - Vin UV fault active
448      * - PS KILL fault active
449      * - Iout OC fault active
450      *
451      * Other faults will, through creating error logs with callouts, already
452      * be setting the Functional property to false.
453      *
454      * On changes, the Available property is updated in the inventory.
455      */
456     void checkAvailability();
457 
458     /**
459      * @brief Setup for power supply input history.
460      *
461      * This will setup the variables and interfaces needed to get the power
462      * supply input history data over to D-Bus. The only known support for this
463      * at this time is the INPUT_HISTORY command implemented by the IBM Common
464      * Form Factor Power Suppplies (ibm-cffps). The INPUT_HISTORY command for
465      * ibm-cffps is implemented via a manufacturing specific PMBus command.
466      */
467     void setupInputHistory();
468 
469     /**
470      * @brief Returns true if this power supply has input history (supported).
471      */
472     bool hasInputHistory() const
473     {
474         return inputHistorySupported;
475     }
476 
477     /**
478      * @brief Returns the number of input history records
479      *
480      * PowerSupply wrapper to getNumRecords() from RecordManager.
481      */
482     size_t getNumInputHistoryRecords() const
483     {
484         if (recordManager)
485         {
486             return recordManager->getNumRecords();
487         }
488         else
489         {
490             return 0;
491         }
492     }
493 
494     /**
495      * @brief Returns true when INPUT_HISTORY sync is required.
496      */
497     bool isSyncHistoryRequired() const
498     {
499         return syncHistoryRequired;
500     }
501 
502     /**
503      * @brief Clears the indicator that sync required for INPUT_HISTORY.
504      *
505      * Sets variable to false to indicate that the sync is no longer required.
506      * This can be used after the PSUManager has reacted to the need for the
507      * INPUT_HISTORY data to be synchronized.
508      */
509     void clearSyncHistoryRequired()
510     {
511         syncHistoryRequired = false;
512     }
513 
514   private:
515     /** @brief systemd bus member */
516     sdbusplus::bus::bus& bus;
517 
518     /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/
519     uint64_t statusWord = 0;
520 
521     /** @brief Will be set to the last read value of STATUS_WORD. */
522     uint64_t statusWordOld = 0;
523 
524     /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/
525     uint64_t statusInput = 0;
526 
527     /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/
528     uint64_t statusMFR = 0;
529 
530     /** @brief Will be updated to the latest/last value read from STATUS_CML.*/
531     uint64_t statusCML = 0;
532 
533     /** @brief Will be updated to the latest/last value read from STATUS_VOUT.*/
534     uint64_t statusVout = 0;
535 
536     /** @brief Will be updated to the latest/last value read from STATUS_IOUT.*/
537     uint64_t statusIout = 0;
538 
539     /** @brief Will be updated to the latest/last value read from
540      * STATUS_FANS_1_2. */
541     uint64_t statusFans12 = 0;
542 
543     /** @brief Will be updated to the latest/last value read from
544      * STATUS_TEMPERATURE.*/
545     uint64_t statusTemperature = 0;
546 
547     /** @brief Will be updated with latest converted value read from READ_VIN */
548     int inputVoltage = phosphor::pmbus::in_input::VIN_VOLTAGE_0;
549 
550     /** @brief Will be updated with the actual voltage last read from READ_VIN
551      */
552     double actualInputVoltage = 0;
553 
554     /** @brief True if an error for a fault has already been logged. */
555     bool faultLogged = false;
556 
557     /** @brief Incremented if bit 1 of STATUS_WORD low byte is on.
558      *
559      * Considered faulted if reaches DEGLITCH_LIMIT.
560      */
561     size_t cmlFault = 0;
562 
563     /** @brief Incremented if bit 5 of STATUS_WORD high byte is on.
564      *
565      * Considered faulted if reaches DEGLITCH_LIMIT.
566      */
567     size_t inputFault = 0;
568 
569     /** @brief Incremented if bit 4 of STATUS_WORD high byte is on.
570      *
571      * Considered faulted if reaches DEGLITCH_LIMIT.
572      */
573     size_t mfrFault = 0;
574 
575     /** @brief Incremented if bit 3 of STATUS_WORD low byte is on.
576      *
577      * Considered faulted if reaches DEGLITCH_LIMIT.
578      */
579     size_t vinUVFault = 0;
580 
581     /** @brief Incremented if bit 5 of STATUS_WORD low byte is on.
582      *
583      * Considered faulted if reaches DEGLITCH_LIMIT.
584      */
585     size_t voutOVFault = 0;
586 
587     /** @brief Incremented if bit 4 of STATUS_WORD low byte is on.
588      *
589      * Considered faulted if reaches DEGLITCH_LIMIT.
590      */
591     size_t ioutOCFault = 0;
592 
593     /** @brief Incremented if bit 7 of STATUS_WORD high byte is on and bit 5
594      * (VOUT_OV) of low byte is off.
595      *
596      * Considered faulted if reaches DEGLITCH_LIMIT.
597      */
598     size_t voutUVFault = 0;
599 
600     /** @brief Incremented if FANS fault/warn bit on in STATUS_WORD.
601      *
602      * Considered faulted if reaches DEGLITCH_LIMIT.
603      */
604     size_t fanFault = 0;
605 
606     /** @brief Incremented if bit 2 of STATUS_WORD low byte is on.
607      *
608      * Considered faulted if reaches DEGLITCH_LIMIT. */
609     size_t tempFault = 0;
610 
611     /**
612      * @brief Incremented if bit 11 or 6 of STATUS_WORD is on. PGOOD# is
613      * inactive, or the unit is off.
614      *
615      * Considered faulted if reaches DEGLITCH_LIMIT.
616      */
617     size_t pgoodFault = 0;
618 
619     /**
620      * @brief Power Supply Kill fault.
621      *
622      * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
623      * bit 4 to indicate this fault. Considered faulted if it reaches
624      * DEGLITCH_LIMIT.
625      */
626     size_t psKillFault = 0;
627 
628     /**
629      * @brief Power Supply 12Vcs fault (standby power).
630      *
631      * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
632      * bit 6 to indicate this fault. Considered faulted if it reaches
633      * DEGLITCH_LIMIT.
634      */
635     size_t ps12VcsFault = 0;
636 
637     /**
638      * @brief Power Supply Current-Share fault in 12V domain.
639      *
640      * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
641      * bit 7 to indicate this fault. Considered faulted if it reaches
642      * DEGLITCH_LIMIT.
643      */
644     size_t psCS12VFault = 0;
645 
646     /** @brief Count of the number of read failures. */
647     size_t readFail = 0;
648 
649     /**
650      * @brief Examine STATUS_WORD for CML (communication, memory, logic fault).
651      */
652     void analyzeCMLFault();
653 
654     /**
655      * @brief Examine STATUS_WORD for INPUT bit on.
656      *
657      * "An input voltage, input current, or input power fault or warning has
658      * occurred."
659      */
660     void analyzeInputFault();
661 
662     /**
663      * @brief Examine STATUS_WORD for VOUT being set.
664      *
665      * If VOUT is on, "An output voltage fault or warning has occurred.", and
666      * VOUT_OV_FAULT is on, there is an output over-voltage fault.
667      */
668     void analyzeVoutOVFault();
669 
670     /*
671      * @brief Examine STATUS_WORD value read for IOUT_OC_FAULT.
672      *
673      * "An output overcurrent fault has occurred." If it is on, and fault not
674      * set, trace STATUS_WORD, STATUS_MFR_SPECIFIC, and STATUS_IOUT values.
675      */
676     void analyzeIoutOCFault();
677 
678     /**
679      * @brief Examines STATUS_WORD value read to see if there is a UV fault.
680      *
681      * Checks if the VOUT bit is on, indicating "An output voltage fault or
682      * warning has occurred", if it is on, but VOUT_OV_FAULT is off, it is
683      * determined to be an indication of an output under-voltage fault.
684      */
685     void analyzeVoutUVFault();
686 
687     /**
688      * @brief Examine STATUS_WORD for the fan fault/warning bit.
689      *
690      * If fanFault is not on, trace that the bit now came on, include
691      * STATUS_WORD, STATUS_MFR_SPECIFIC, and STATUS_FANS_1_2 values as well, to
692      * help with understanding what may have caused it to be set.
693      */
694     void analyzeFanFault();
695 
696     /**
697      * @brief Examine STATUS_WORD for temperature fault.
698      */
699     void analyzeTemperatureFault();
700 
701     /**
702      * @brief Examine STATUS_WORD for pgood or unit off faults.
703      */
704     void analyzePgoodFault();
705 
706     /**
707      * @brief Determine possible manufacturer-specific faults from bits in
708      * STATUS_MFR.
709      *
710      * The bits in the STATUS_MFR_SPECIFIC command response have "Manufacturer
711      * Defined" meanings. Determine which faults, if any, are present based on
712      * the power supply (device driver) type.
713      */
714     void determineMFRFault();
715 
716     /**
717      * @brief Examine STATUS_WORD value read for MFRSPECIFIC bit on.
718      *
719      * "A manufacturer specific fault or warning has occurred."
720      *
721      * If it is on, call the determineMFRFault() helper function to examine the
722      * value read from STATUS_MFR_SPECIFIC.
723      */
724     void analyzeMFRFault();
725 
726     /**
727      * @brief Analyzes the STATUS_WORD for a VIN_UV_FAULT indicator.
728      */
729     void analyzeVinUVFault();
730 
731     /**
732      * @brief D-Bus path to use for this power supply's inventory status.
733      **/
734     std::string inventoryPath;
735 
736     /**
737      * @brief Store the short name to avoid string processing.
738      *
739      * The short name will be something like powersupply1, the last part of the
740      * inventoryPath.
741      */
742     std::string shortName;
743 
744     /**
745      * @brief Given a full inventory path, returns the last node of the path as
746      * the "short name"
747      */
748     std::string findShortName(const std::string& invPath)
749     {
750         auto const lastSlashPos = invPath.find_last_of('/');
751 
752         if ((lastSlashPos == std::string::npos) ||
753             ((lastSlashPos + 1) == invPath.size()))
754         {
755             return invPath;
756         }
757         else
758         {
759             return invPath.substr(lastSlashPos + 1);
760         }
761     }
762 
763     /**
764      * @brief The libgpiod object for monitoring PSU presence
765      */
766     std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr;
767 
768     /** @brief True if the power supply is present. */
769     bool present = false;
770 
771     /** @brief Power supply model name. */
772     std::string modelName;
773 
774     /** @brief D-Bus match variable used to subscribe to Present property
775      * changes.
776      **/
777     std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
778 
779     /** @brief D-Bus match variable used to subscribe for Present property
780      * interface added.
781      */
782     std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
783 
784     /**
785      * @brief Pointer to the PMBus interface
786      *
787      * Used to read or write to/from PMBus power supply devices.
788      */
789     std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr;
790 
791     /** @brief Stored copy of the firmware version/revision string */
792     std::string fwVersion;
793 
794     /**
795      * @brief The file system path used for binding the device driver.
796      */
797     const std::filesystem::path bindPath;
798 
799     /* @brief The string to pass in for binding the device driver. */
800     std::string bindDevice;
801 
802     /**
803      * @brief The result of the most recent availability check
804      *
805      * Saved on the object so changes can be detected.
806      */
807     bool available = false;
808 
809     /**
810      * @brief Binds or unbinds the power supply device driver
811      *
812      * Called when a presence change is detected to either bind the device
813      * driver for the power supply when it is installed, or unbind the device
814      * driver when the power supply is removed.
815      *
816      * Writes <device> to <path>/bind (or unbind)
817      *
818      * @param present - when true, will bind the device driver
819      *                  when false, will unbind the device driver
820      */
821     void bindOrUnbindDriver(bool present);
822 
823     /**
824      *  @brief Updates the presence status by querying D-Bus
825      *
826      * The D-Bus inventory properties for this power supply will be read to
827      * determine if the power supply is present or not and update this
828      * object's present member variable to reflect current status.
829      **/
830     void updatePresence();
831 
832     /**
833      * @brief Updates the power supply presence by reading the GPIO line.
834      */
835     void updatePresenceGPIO();
836 
837     /**
838      * @brief Callback for inventory property changes
839      *
840      * Process change of Present property for power supply.
841      *
842      * This is used if we are watching the D-Bus properties instead of reading
843      * the GPIO presence line ourselves.
844      *
845      * @param[in]  msg - Data associated with Present change signal
846      **/
847     void inventoryChanged(sdbusplus::message::message& msg);
848 
849     /**
850      * @brief Callback for inventory property added.
851      *
852      * Process add of the interface with the Present property for power supply.
853      *
854      * This is used if we are watching the D-Bus properties instead of reading
855      * the GPIO presence line ourselves.
856      *
857      * @param[in]  msg - Data associated with Present add signal
858      **/
859     void inventoryAdded(sdbusplus::message::message& msg);
860 
861     /**
862      * @brief Reads the pmbus MFR_POUT_MAX value.
863      *
864      * "The MFR_POUT_MAX command sets or retrieves the maximum rated output
865      * power, in watts, that the unit is rated to supply."
866      *
867      * @return max_power_out value converted from string.
868      */
869     auto getMaxPowerOut() const;
870 
871     /**
872      * @brief Reads the most recent input history record from the power supply
873      * and updates the average and maximum properties in D-Bus if there is a new
874      * reading available.
875      *
876      * This will still run every time analyze() is called so code can post new
877      * data as soon as possible and the timestamp will more accurately reflect
878      * the correct time.
879      *
880      * D-Bus is only updated if there is a change and the oldest record will be
881      * pruned if the property already contains the max number of records.
882      */
883     void updateHistory();
884 
885     /**
886      * @brief Set to true if INPUT_HISTORY command supported.
887      *
888      * Not all power supplies will support the INPUT_HISTORY command. The IBM
889      * Common Form Factor power supplies do support this command.
890      */
891     bool inputHistorySupported{false};
892 
893     /**
894      * @brief Set to true when INPUT_HISTORY sync is required.
895      *
896      * A power supply will need to synchronize its INPUT_HISTORY data with the
897      * other power supplies installed in the system when it goes from missing to
898      * present.
899      */
900     bool syncHistoryRequired{false};
901 
902     /**
903      * @brief Class that manages the input power history records.
904      **/
905     std::unique_ptr<history::RecordManager> recordManager;
906 
907     /**
908      * @brief The D-Bus object for the average input power history
909      **/
910     std::unique_ptr<history::Average> average;
911 
912     /**
913      * @brief The D-Bus object for the maximum input power history
914      **/
915     std::unique_ptr<history::Maximum> maximum;
916 
917     /**
918      * @brief The base D-Bus object path to use for the average and maximum
919      * objects.
920      **/
921     std::string historyObjectPath;
922 };
923 
924 } // namespace phosphor::power::psu
925