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