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