chassis-psu: New Functions for MultiChassis App

Implemented several functions for monitoring power supplies in
multi-chassis systems. Added a new main function, made minor
modification to the PowerSupply class, and added several functions to
the Chassis and ChassisManager classes.

The following is a summary of each object class new addition or modified
functions:

ChassisManager:
  - initChassisPowerMonitoring(): Loops through all the chassis in the
    system and initializes power monitoring process for each chassis's
    PSUs.

Chassis:
 - initPowerMonitoring(): Subscribe to D-Bus power change and initialize
   power monitoring.
 - supportedConfigurationInterfaceAdded(): Handle addition of supported
   configuration and update missing PSUs.
 - psuInterfaceAdded(): Handle addition of PSUs on D-Bus.
 - validatePsuConfigAndInterfacesProcessed(): Validate the PSU
   configuration and reset validation timer if power is on, supported
   configs and have PSUs.
 - analyzeBrownout(): Analyze PSUs for a brownout failure and log error.
 - syncHistory(): Toggles the GPIO to sync power supply input history
   readings.
 - setInputVoltageRating(): Inform each PSUs to set its PSU input.
 - createError(): Create OpenBMC error.
 - hasRequiredPSUs(): TODO
 - updateMissingPSUs(): Update PSU inventory.
 - getSupportedConfiguration(): Retrieve supported configuration from
   D-BUS and matches chassis ID with the  current chassis id to update
   chassis configuration.
 - saveChassisName(): Save chassis short name in the class.
 - powerStateChanged(): Handle for power state property changes.
 - attemptToCreatePowerConfigGPIO(): Attempt to create GPIO

 PowerSupply:
  - PowerSupply(): Added additional class constructors. The constructors
    have the same parameters as the original, except that the new
    constructor include an extra parameter chassis short name.
 - The PowerSupply class functions implementation remains the same as
   the original, except for minor change in
   PowerSupply::setupInputPowerPeakSensor(), where the sensorPath was
   modified to include chassis name.

Test in simulation:
  - Verified supported configuration added, where it polpulates
    supported properties and updates PSUs changes.
  - Validated some of the brownout functionality using fault injection.
  - Validated the PowerSupply class sets the appropriate input voltage
    for the target chassis PSUs.
  - Verified that the chassis name is included in the PSU power input
    peak sensors on D-bus.

Change-Id: I75a1ab1dd004767f072e35f3ce2c83ff281eb1ca
Signed-off-by: Faisal Awada <faisal@us.ibm.com>
diff --git a/phosphor-power-supply/chassis.hpp b/phosphor-power-supply/chassis.hpp
index e976921..6471f26 100644
--- a/phosphor-power-supply/chassis.hpp
+++ b/phosphor-power-supply/chassis.hpp
@@ -1,6 +1,5 @@
 #pragma once
-
-#include "power_supply.hpp"
+#include "new_power_supply.hpp"
 #include "types.hpp"
 #include "utility.hpp"
 
@@ -13,6 +12,7 @@
 #include <sdeventplus/utility/timer.hpp>
 #include <xyz/openbmc_project/State/Decorator/PowerSystemInputs/server.hpp>
 
+#include <filesystem>
 #include <map>
 #include <string>
 #include <vector>
@@ -25,6 +25,8 @@
 };
 
 using namespace phosphor::power::psu;
+using namespace phosphor::power::util;
+using namespace sdeventplus;
 
 namespace phosphor::power::chassis
 {
@@ -42,6 +44,18 @@
 constexpr auto validationTimeout = std::chrono::seconds(30);
 
 /**
+ * @class PowerSystemInputs
+ * @brief A concrete implementation for the PowerSystemInputs interface.
+ */
+class PowerSystemInputs : public PowerSystemInputsObject
+{
+  public:
+    PowerSystemInputs(sdbusplus::bus_t& bus, const std::string& path) :
+        PowerSystemInputsObject(bus, path.c_str())
+    {}
+};
+
+/**
  * @class Chassis
  *
  * @brief This class will create an object used to manage and monitor a list of
@@ -91,6 +105,47 @@
         return powerOn;
     }
 
+    /**
+     * @brief Initialize power monitoring infrastructure for Chassis.
+     * Sets up configuration validation timer, attempts to create GPIO,
+     * subscribe to D-Bus power state change events.
+     */
+    void initPowerMonitoring();
+
+    /**
+     * @brief Handles addition of the SupportedConfiguration interface.
+     * This function triggered when the SupportedConfiguration interface added
+     * to a D-Bus object. The function  calls populateSupportedConfiguration()
+     * and updateMissingPSUs() to processes the provided properties.
+     *
+     * @param properties A map of D-Bus properties associated with the
+     * SupportedConfiguration interface.
+     */
+    void supportedConfigurationInterfaceAdded(
+        const util::DbusPropertyMap& properties);
+
+    /**
+     * @brief Handle the addition of PSU interface.
+     * This function is called when a Power Supply interface added to a D-Bus.
+     * This function calls getPSUProperties() and updateMissingPSUs().
+     *
+     * @param properties A map of D-Bus properties for the PSU interface.
+     */
+    void psuInterfaceAdded(util::DbusPropertyMap& properties);
+
+    /**
+     * @brief Call to validate the psu configuration if the power is on and both
+     * the IBMCFFPSConnector and SupportedConfiguration interfaces have been
+     * processed
+     */
+    void validatePsuConfigAndInterfacesProcessed()
+    {
+        if (powerOn && !psus.empty() && !supportedConfigs.empty())
+        {
+            validationTimer->restartOnce(validationTimeout);
+        }
+    };
+
   private:
     /**
      * @brief The D-Bus object
@@ -108,6 +163,20 @@
     /** @brief True if the power is on. */
     bool powerOn = false;
 
+    /** @brief True if power control is in the window between chassis pgood loss
+     * and power off.
+     */
+    bool powerFaultOccurring = false;
+
+    /** @brief True if an error for a brownout has already been logged. */
+    bool brownoutLogged = false;
+
+    /** @brief Used as part of subscribing to power on state changes*/
+    std::string powerService;
+
+    /** @brief Used to subscribe to D-Bus power on state changes */
+    std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
+
     /** @brief Used to subscribe to D-Bus power supply presence changes */
     std::vector<std::unique_ptr<sdbusplus::bus::match_t>> presenceMatches;
 
@@ -136,22 +205,44 @@
     std::string driverName;
 
     /**
+     * @brief The libgpiod object for setting the power supply config
+     */
+    std::unique_ptr<GPIOInterfaceBase> powerConfigGPIO = nullptr;
+
+    /**
      * @brief Chassis D-Bus object path
      */
     std::string chassisPath;
 
     /**
+     * @brief Chassis name;
+     */
+    std::string chassisShortName;
+
+    /**
      * @brief The Chassis path unique ID
+     *
+     * Note: chassisPathUniqueId must be declared before powerSystemInputs.
      */
     uint64_t chassisPathUniqueId = invalidObjectPathUniqueId;
 
     /**
+     * @brief PowerSystemInputs object
+     */
+    PowerSystemInputs powerSystemInputs;
+
+    /**
      * @brief Declares a constant reference to an sdeventplus::Event to manage
      * async processing.
      */
     const sdeventplus::Event& eventLoop;
 
     /**
+     * @brief GPIO to toggle to 'sync' power supply input history.
+     */
+    std::unique_ptr<GPIOInterfaceBase> syncHistoryGPIO = nullptr;
+
+    /**
      * @brief Get PSU properties from D-Bus, use that to build a power supply
      * object.
      *
@@ -165,9 +256,9 @@
     void getPSUConfiguration();
 
     /**
-     * @brief Initialize the chassis's supported configuration from the
-     * Supported Configuration D-Bus object provided by the Entity
-     * Manager.
+     * @brief Queries D-Bus for chassis configuration provided by the Entity
+     * Manager. Matches the object against the current chassis unique ID. Upon
+     * finding a match calls populateSupportedConfiguration().
      */
     void getSupportedConfiguration();
 
@@ -209,6 +300,99 @@
      * @return uint64_t - Chassis path unique ID.
      */
     uint64_t getChassisPathUniqueId(const std::string& path);
+
+    /**
+     * @brief Initializes the chassis.
+     *
+     */
+    void initialize() {}; // TODO
+
+    /**
+     * @brief Perform power supply configuration validation.
+     * @details Validates if the existing power supply properties are a
+     * supported configuration, and acts on its findings such as logging
+     * errors.
+     */
+    void validateConfig();
+
+    /**
+     * @brief Analyze the set of the power supplies for a brownout failure. Log
+     * error when necessary, clear brownout condition when window has passed.
+     */
+    void analyzeBrownout();
+
+    /**
+     * @brief Toggles the GPIO to sync power supply input history readings
+     * @details 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 Tells each PSU to set its power supply input
+     * voltage rating D-Bus property.
+     */
+    inline void setInputVoltageRating()
+    {
+        for (auto& psu : psus)
+        {
+            psu->setInputVoltageRating();
+        }
+    }
+
+    /**
+     * Create an error
+     *
+     * @param[in] faultName - 'name' message for the BMC error log entry
+     * @param[in,out] additionalData - The AdditionalData property for the error
+     */
+    void createError(const std::string& faultName,
+                     std::map<std::string, std::string>& additionalData);
+
+    /**
+     * @brief Check that all PSUs have the same model name and that the system
+     * has the required number of PSUs present as specified in the Supported
+     * Configuration interface.
+     *
+     * @param[out] additionalData - Contains debug information on why the check
+     *             might have failed. Can be used to fill in error logs.
+     * @return true if all the required PSUs are present, false otherwise.
+     */
+    bool hasRequiredPSUs(std::map<std::string, std::string>& additionalData);
+
+    /**
+     * @brief Update inventory for missing required power supplies
+     */
+    void updateMissingPSUs();
+
+    /**
+     * @brief Assign chassis short name.
+     */
+    void saveChassisName()
+    {
+        std::filesystem::path path(chassisPath);
+        chassisShortName = path.filename();
+    }
+
+    /**
+     * @brief Callback for power state property changes
+     *
+     * Process changes to the powered on state property for the chassis.
+     *
+     * @param[in] msg - Data associated with the power state signal
+     */
+    void powerStateChanged(sdbusplus::message_t& msg);
+
+    /**
+     * @breif Attempt to create GPIO
+     */
+    void attemptToCreatePowerConfigGPIO();
 };
 
 } // namespace phosphor::power::chassis