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