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