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