blob: a56e2e24542678b40754d2ab55cf2e8dff01e282 [file] [log] [blame]
#pragma once
#include <sdbusplus/bus/match.hpp>
#include <sdeventplus/clock.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/utility/timer.hpp>
#include "average.hpp"
#include "device.hpp"
#include "maximum.hpp"
#include "names_values.hpp"
#include "pmbus.hpp"
#include "record_manager.hpp"
namespace witherspoon
{
namespace power
{
namespace psu
{
namespace sdbusRule = sdbusplus::bus::match::rules;
constexpr auto FAULT_COUNT = 3;
/**
* @class PowerSupply
* Represents a PMBus power supply device.
*/
class PowerSupply : public Device
{
public:
PowerSupply() = delete;
PowerSupply(const PowerSupply&) = delete;
PowerSupply(PowerSupply&&) = default;
PowerSupply& operator=(const PowerSupply&) = default;
PowerSupply& operator=(PowerSupply&&) = default;
~PowerSupply() = default;
/**
* Constructor
*
* @param[in] name - the device name
* @param[in] inst - the device instance
* @param[in] objpath - the path to monitor
* @param[in] invpath - the inventory path to use
* @param[in] bus - D-Bus bus object
* @param[in] e - event object
* @param[in] t - time to allow power supply to assert PG#
* @param[in] p - time to allow power supply presence state to
* settle/deglitch and allow for application of power
* prior to fault checking
*/
PowerSupply(const std::string& name, size_t inst,
const std::string& objpath,
const std::string& invpath,
sdbusplus::bus::bus& bus,
const sdeventplus::Event& e,
std::chrono::seconds& t,
std::chrono::seconds& p);
/**
* Power supply specific function to analyze for faults/errors.
*
* Various PMBus status bits will be checked for fault conditions.
* If a certain fault bits are on, the appropriate error will be
* committed.
*/
void analyze() override;
/**
* Write PMBus CLEAR_FAULTS
*
* This function will be called in various situations in order to clear
* any fault status bits that may have been set, in order to start over
* with a clean state. Presence changes and power state changes will
* want to clear any faults logged.
*/
void clearFaults() override;
/**
* Mark error for specified callout and message as resolved.
*
* @param[in] callout - The callout to be resolved (inventory path)
* @parma[in] message - The message for the fault to be resolved
*/
void resolveError(const std::string& callout,
const std::string& message);
/**
* Enables making the input power history available on D-Bus
*
* @param[in] objectPath - the D-Bus object path to use
* @param[in] maxRecords - the number of history records to keep
* @param[in] syncGPIOPath - The gpiochip device path to use for
* sending the sync command
* @paramp[in] syncGPIONum - the GPIO number for the sync command
*/
void enableHistory(const std::string& objectPath,
size_t numRecords,
const std::string& syncGPIOPath,
size_t syncGPIONum);
private:
/**
* The path to use for reading various PMBus bits/words.
*/
std::string monitorPath;
/**
* @brief Pointer to the PMBus interface
*
* Used to read out of or write to the /sysfs tree(s) containing files
* that a device driver monitors the PMBus interface to the power
* supplies.
*/
witherspoon::pmbus::PMBus pmbusIntf;
/**
* @brief D-Bus path to use for this power supply's inventory status.
*/
std::string inventoryPath;
/** @brief Connection for sdbusplus bus */
sdbusplus::bus::bus& bus;
/** @brief True if the power supply is present. */
bool present = false;
/** @brief Used to subscribe to D-Bus property changes for Present */
std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
/**
* @brief Interval for setting present to true.
*
* The amount of time to wait from not present to present change before
* updating the internal present indicator. Allows person servicing
* the power supply some time to plug in the cable.
*/
std::chrono::seconds presentInterval;
/**
* @brief Timer used to delay setting the internal present state.
*
* The timer used to do the callback after the present property has
* changed.
*/
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> presentTimer;
/** @brief True if a fault has already been found and not cleared */
bool faultFound = false;
/** @brief True if the power is on. */
bool powerOn = false;
/**
* @brief Equal to FAULT_COUNT if power on fault has been
* detected.
*/
size_t powerOnFault = 0;
/**
* @brief Interval to setting powerOn to true.
*
* The amount of time to wait from power state on to setting the
* internal powerOn state to true. The amount of time the power supply
* is allowed to delay setting DGood/PG#.
*/
std::chrono::seconds powerOnInterval;
/**
* @brief Timer used to delay setting the internal powerOn state.
*
* The timer used to do the callback after the power state has been on
* long enough.
*/
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> powerOnTimer;
/** @brief Used to subscribe to D-Bus power on state changes */
std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
/** @brief Indicates that a read failure has occurred.
*
* @details This will be incremented each time a read failure is
* encountered. If it is incremented to FAULT_COUNT, an error
* will be logged.
*/
size_t readFail = 0;
/** @brief Has a PMBus read failure already been logged? */
bool readFailLogged = false;
/**
* @brief Indicates an input fault or warning if equal to FAULT_COUNT.
*
* @details This is the "INPUT FAULT OR WARNING" bit in the high byte,
* or the VIN_UV_FAULT bit in the low byte in the STATUS_WORD
* command response. If either of those bits are on, this will
* be incremented.
*/
size_t inputFault = 0;
/**
* @brief Indicates output over current fault if equal to FAULT_COUNT
*
* @details This is incremented when the "IOUT_OC_FAULT" bit in the low
* byte from the STATUS_WORD command response is on.
*/
size_t outputOCFault = 0;
/**
* @brief Indicates output overvoltage fault if equal to FAULT_COUNT.
*
* @details This is incremented when the "VOUT_OV_FAULT" bit in the
* STATUS_WORD command response is on.
*/
size_t outputOVFault = 0;
/**
* @brief Indicates a fan fault or warning condition was detected if
* equal to FAULT_COUNT.
*
* @details This is incremented when the 'FAN_FAULT' bit in the
* STATUS_WORD command response is on.
*/
size_t fanFault = 0;
/**
* @brief Indicates a temperature fault or warn condition was detected
* if equal to FAULT_COUNT.
*
* @details This is incremented when the 'TEMPERATURE_FAULT_WARN' bit
* in the STATUS_WORD command response is on, or if the
* 'OT_FAULT' bit in the STATUS_TEMPERATURE command response
* is on.
*/
size_t temperatureFault = 0;
/**
* @brief Class that manages the input power history records.
*/
std::unique_ptr<history::RecordManager> recordManager;
/**
* @brief The D-Bus object for the average input power history
*/
std::unique_ptr<history::Average> average;
/**
* @brief The D-Bus object for the maximum input power history
*/
std::unique_ptr<history::Maximum> maximum;
/**
* @brief The base D-Bus object path to use for the average
* and maximum objects.
*/
std::string historyObjectPath;
/**
* @brief The GPIO device path to use for sending the 'sync'
* command to the PS.
*/
std::string syncGPIODevPath;
/**
* @brief The GPIO number to use for sending the 'sync'
* command to the PS.
*/
size_t syncGPIONumber = 0;
/**
* @brief Callback for inventory property changes
*
* Process change of Present property for power supply.
*
* @param[in] msg - Data associated with Present change signal
*
*/
void inventoryChanged(sdbusplus::message::message& msg);
/**
* Updates the presence status by querying D-Bus
*
* The D-Bus inventory properties for this power supply will be read to
* determine if the power supply is present or not and update this
* objects present member variable to reflect current status.
*/
void updatePresence();
/**
* @brief Updates the poweredOn status by querying D-Bus
*
* The D-Bus property for the system power state will be read to
* determine if the system is powered on or not.
*/
void updatePowerState();
/**
* @brief Callback for power state property changes
*
* Process changes to the powered on stat property for the system.
*
* @param[in] msg - Data associated with the power state signal
*/
void powerStateChanged(sdbusplus::message::message& msg);
/**
* @brief Wrapper for PMBus::read() and adding metadata
*
* @param[out] nv - NamesValues instance to store cmd string and value
* @param[in] cmd - String for the command to read data from.
* @param[in] type - The type of file to read the command from.
*/
void captureCmd(util::NamesValues& nv, const std::string& cmd,
witherspoon::pmbus::Type type);
/**
* @brief Checks for input voltage faults and logs error if needed.
*
* Check for voltage input under voltage fault (VIN_UV_FAULT) and/or
* input fault or warning (INPUT_FAULT), and logs appropriate error(s).
*
* @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs
*/
void checkInputFault(const uint16_t statusWord);
/**
* @brief Checks for power good negated or unit is off in wrong state
*
* @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs
*/
void checkPGOrUnitOffFault(const uint16_t statusWord);
/**
* @brief Checks for output current over current fault.
*
* IOUT_OC_FAULT is checked, if on, appropriate error is logged.
*
* @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs
*/
void checkCurrentOutOverCurrentFault(const uint16_t statusWord);
/**
* @brief Checks for output overvoltage fault.
*
* VOUT_OV_FAULT is checked, if on, appropriate error is logged.
*
* @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs
*/
void checkOutputOvervoltageFault(const uint16_t statusWord);
/**
* @brief Checks for a fan fault or warning condition.
*
* The high byte of STATUS_WORD is checked to see if the "FAN FAULT OR
* WARNING" bit is turned on. If it is on, log an error.
*
* @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs
*/
void checkFanFault(const uint16_t statusWord);
/**
* @brief Checks for a temperature fault or warning condition.
*
* The low byte of STATUS_WORD is checked to see if the "TEMPERATURE
* FAULT OR WARNING" bit is turned on. If it is on, log an error,
* call out the power supply indicating the fault/warning condition.
*
* @parma[in] statusWord - 2 byte STATUS_WORD value read from sysfs
*/
void checkTemperatureFault(const uint16_t statusWord);
/**
* @brief Adds properties to the inventory.
*
* Reads the values from the device and writes them to the
* associated power supply D-Bus inventory object.
*
* This needs to be done on startup, and each time the presence
* state changes.
*
* Properties added:
* - Serial Number
* - Part Number
* - CCIN (Customer Card Identification Number) - added as the Model
* - Firmware version
*/
void updateInventory();
/**
* @brief Toggles the GPIO to sync power supply input history readings
*
* This GPIO is connected to all supplies. This will clear the
* previous readings out of the supplies and restart them both at the
* same time zero and at record ID 0. The supplies will return 0
* bytes of data for the input history command right after this until
* a new entry shows up.
*
* This will cause the code to delete all previous history data and
* start fresh.
*/
void syncHistory();
/**
* @brief Reads the most recent input history record from the power
* supply and updates the average and maximum properties in
* D-Bus if there is a new reading available.
*
* This will still run every time analyze() is called so code can
* post new data as soon as possible and the timestamp will more
* accurately reflect the correct time.
*
* D-Bus is only updated if there is a change and the oldest record
* will be pruned if the property already contains the max number of
* records.
*/
void updateHistory();
};
}
}
}