Support numeric effecters in dbus-to-host-effecter

Adds support of the numeric effecter PDR (section `28.11 Numeric
Effecter PDR` DSP0248 V1.3.0) type in dbus-to-host-effecter handler.
This handler will be applied for all PLDM termini but not only host.
The setting for one numeric effecter of one device can be:
{
    "mctp_eid": 20,
    "effecter_info": {
        "effecterPdrType": 9,
        "effecterID": 2,
        "entityType": 32903,
        "entityInstance": 2,
        "containerID": 2,
        "compositeEffecterCount": 1,
        "checkHostState": false
    },
    "effecters": [
        {
            "dbus_info": {
                "object_path": "/xyz/openbmc_project/sensors/power/A",
                "interface": "xyz.openbmc_project.Sensor.Value",
                "property_name": "Value",
                "property_type": "double"
            },
            "effecterDataSize": 5,
            "resolution": 1,
            "offset": 0,
            "unitModifier": 0
        }
    ]
}

Where:
+ effecterPdrType to difference state/numeric effecter type. Default
is state effecter.
+ effecterID should be effecter ID and should not empty.
+ checkHostState can be set to false to bypass checking host state.
+ effecterDataSize, resolution, offset, unitModifier are from numeric
effecter PDR (section `28.11 Numeric Effecter PDR` DSP0248 V1.3.0)

Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I438d7f204643edd4066e8a6ba28d53a97503fc4b
diff --git a/host-bmc/dbus_to_terminus_effecters.hpp b/host-bmc/dbus_to_terminus_effecters.hpp
new file mode 100644
index 0000000..8e4357e
--- /dev/null
+++ b/host-bmc/dbus_to_terminus_effecters.hpp
@@ -0,0 +1,251 @@
+#pragma once
+
+#include "common/instance_id.hpp"
+#include "common/types.hpp"
+#include "common/utils.hpp"
+#include "requester/handler.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+PHOSPHOR_LOG2_USING;
+
+namespace pldm
+{
+
+namespace host_effecters
+{
+
+using DbusChgHostEffecterProps =
+    std::map<dbus::Property, pldm::utils::PropertyValue>;
+
+/** @struct State
+ *  Contains the state set id and the possible states for
+ *  an effecter
+ */
+struct PossibleState
+{
+    uint16_t stateSetId;         //!< State set id
+    std::vector<uint8_t> states; //!< Possible states
+};
+
+/** @struct DBusEffecterMapping
+ *  Contains the D-Bus information for an effecter
+ */
+struct DBusEffecterMapping
+{
+    pldm::utils::DBusMapping dbusMap;
+    std::vector<pldm::utils::PropertyValue>
+        propertyValues;  //!< D-Bus property values
+    PossibleState state; //!< Corresponding effecter states
+};
+
+/** @struct DBusEffecterMapping
+ *  Contains the D-Bus information for an effecter
+ */
+struct DBusNumericEffecterMapping
+{
+    pldm::utils::DBusMapping dbusMap;
+    uint8_t dataSize;     //!< Numeric effecter PDR data size
+    double resolution;    //!< Numeric effecter PDR resolution
+    double offset;        //!< Numeric effecter PDR offset
+    int8_t unitModifier;  //!< Numeric effecter PDR unitModifier
+    double propertyValue; //!< D-Bus property values
+};
+
+/** @struct EffecterInfo
+ *  Contains the effecter information as a whole
+ */
+struct EffecterInfo
+{
+    uint8_t mctpEid;             //!< Host mctp eid
+    uint8_t effecterPdrType;     //!< Effecter PDR type state/numeric
+    uint16_t containerId;        //!< Container Id for host effecter
+    uint16_t entityType;         //!< Entity type for the host effecter
+    uint16_t entityInstance;     //!< Entity instance for the host effecter
+    uint8_t compEffecterCnt;     //!< Composite effecter count
+    bool checkHostState;         //!< Check host state before setting effecter
+    std::vector<DBusEffecterMapping>
+        dbusInfo;                //!< D-Bus information for the effecter id
+    std::vector<DBusNumericEffecterMapping>
+        dbusNumericEffecterInfo; //!< D-Bus information for the effecter id
+};
+
+/** @class HostEffecterParser
+ *
+ *  @brief This class parses the Host Effecter json file and monitors for the
+ *         D-Bus changes for the effecters. Upon change, calls the corresponding
+ *         setStateEffecterStates on the host
+ */
+class HostEffecterParser
+{
+  public:
+    HostEffecterParser() = delete;
+    HostEffecterParser(const HostEffecterParser&) = delete;
+    HostEffecterParser& operator=(const HostEffecterParser&) = delete;
+    HostEffecterParser(HostEffecterParser&&) = delete;
+    HostEffecterParser& operator=(HostEffecterParser&&) = delete;
+    virtual ~HostEffecterParser() = default;
+
+    /** @brief Constructor to create a HostEffecterParser object.
+     *  @param[in] instanceIdDb - PLDM InstanceIdDb object pointer
+     *  @param[in] fd - socket fd to communicate to host
+     *  @param[in] repo -  PLDM PDR repository
+     *  @param[in] dbusHandler - D-bus Handler
+     *  @param[in] jsonPath - path for the json file
+     *  @param[in] handler - PLDM request handler
+     */
+    explicit HostEffecterParser(
+        pldm::InstanceIdDb* instanceIdDb, int fd, const pldm_pdr* repo,
+        pldm::utils::DBusHandler* const dbusHandler,
+        const std::string& jsonPath,
+        pldm::requester::Handler<pldm::requester::Request>* handler) :
+        instanceIdDb(instanceIdDb), sockFd(fd), pdrRepo(repo),
+        dbusHandler(dbusHandler), handler(handler)
+    {
+        try
+        {
+            parseEffecterJson(jsonPath);
+        }
+        catch (const std::exception& e)
+        {
+            error(
+                "The json file '{PATH}' does not exist or malformed, error - '{ERROR}'",
+                "PATH", jsonPath, "ERROR", e);
+        }
+    }
+
+    /* @brief Parses the host effecter json
+     *
+     * @param[in] jsonPath - path for the json file
+     */
+    void parseEffecterJson(const std::string& jsonPath);
+
+    /* @brief Method to take action when the subscribed D-Bus property is
+     *        changed
+     * @param[in] chProperties - list of properties which have changed
+     * @param[in] effecterInfoIndex - index of effecterInfo pointer in
+     *                                hostEffecterInfo
+     * @param[in] dbusInfoIndex - index on dbusInfo pointer in each effecterInfo
+     * @param[in] effecterId - host effecter id
+     * @return - none
+     */
+    void processHostEffecterChangeNotification(
+        const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
+        size_t dbusInfoIndex, uint16_t effecterId);
+
+    /* @brief Method to take action when the subscribed D-Bus property is
+     *        changed
+     * @param[in] chProperties - list of properties which have changed
+     * @param[in] effecterInfoIndex - index of effecterInfo pointer in
+     *                                hostEffecterInfo
+     * @param[in] dbusInfoIndex - index on dbusInfo pointer in each effecterInfo
+
+     * @param[in] effecterId - terminus numeric effecter id
+     * @return - none
+     */
+    void processTerminusNumericEffecterChangeNotification(
+        const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
+        size_t dbusInfoIndex, uint16_t effecterId);
+
+    /* @brief Populate the property values in each dbusInfo from the json
+     *
+     * @param[in] dBusValues - json values
+     * @param[out] propertyValues - dbusInfo property values
+     * @param[in] propertyType - type of the D-Bus property
+     * @return - none
+     */
+    void populatePropVals(
+        const pldm::utils::Json& dBusValues,
+        std::vector<pldm::utils::PropertyValue>& propertyValues,
+        const std::string& propertyType);
+
+    /* @brief Set a host state effecter
+     *
+     * @param[in] effecterInfoIndex - index of effecterInfo pointer in
+     *                                hostEffecterInfo
+     * @param[in] stateField - vector of state fields equal to composite
+     *                         effecter count in number
+     * @param[in] effecterId - host effecter id
+     * @return - PLDM status code
+     */
+    virtual int setHostStateEffecter(
+        size_t effecterInfoIndex,
+        std::vector<set_effecter_state_field>& stateField, uint16_t effecterId);
+
+    /* @brief Set a terminus numeric effecter
+     *
+     * @param[in] effecterInfoIndex - index of effecterInfo pointer in
+     *                                hostEffecterInfo
+     * @param[in] effecterId - host effecter id
+     * @param[in] dataSize - data size
+     * @param[in] rawValue - raw value
+     * @return - PLDM status code
+     */
+    virtual int setTerminusNumericEffecter(size_t effecterInfoIndex,
+                                           uint16_t effecterId,
+                                           uint8_t dataSize, double rawValue);
+
+    /* @brief Fetches the new state value and the index in stateField set which
+     *        needs to be set with the new value in the setStateEffecter call
+     * @param[in] effecterInfoIndex - index of effecterInfo in hostEffecterInfo
+     * @param[in] dbusInfoIndex - index of dbusInfo within effecterInfo
+     * @param[in] propertyValue - the changed D-Bus property value
+     * @return - the new state value
+     */
+    uint8_t findNewStateValue(size_t effecterInfoIndex, size_t dbusInfoIndex,
+                              const pldm::utils::PropertyValue& propertyValue);
+
+    /* @brief Subscribes for D-Bus property change signal on the specified
+     *        object
+     *
+     * @param[in] objectPath - D-Bus object path to look for
+     * @param[in] interface - D-Bus interface
+     * @param[in] effecterInfoIndex - index of effecterInfo pointer in
+     *                                hostEffecterInfo
+     * @param[in] dbusInfoIndex - index of dbusInfo within effecterInfo
+     * @param[in] effecterId - host effecter id
+     */
+    virtual void createHostEffecterMatch(
+        const std::string& objectPath, const std::string& interface,
+        size_t effecterInfoIndex, size_t dbusInfoIndex, uint16_t effecterId);
+
+    /* @brief Adjust the nummeric effecter value base on the effecter
+     *        configurations
+     *
+     * @param[in] value - Raw value
+     * @param[in] offset - offset config
+     * @param[in] resolution - resolution config
+     * @param[in] modify - modify config
+     *
+     * @return - Value of effecter
+     */
+    double adjustValue(double value, double offset, double resolution,
+                       int8_t modify);
+
+  private:
+    /* @brief Verify host On state before configure the host effecters
+     *
+     * @return - true if host is on and false for others cases
+     */
+    bool isHostOn(void);
+
+  protected:
+    pldm::InstanceIdDb* instanceIdDb; //!< Reference to the InstanceIdDb object
+                                      //!< to obtain instance id
+    int sockFd;                       //!< Socket fd to send message to host
+    const pldm_pdr* pdrRepo;          //!< Reference to PDR repo
+    std::vector<EffecterInfo> hostEffecterInfo; //!< Parsed effecter information
+    std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
+        effecterInfoMatch; //!< vector to catch the D-Bus property change
+                           //!< signals for the effecters
+    const pldm::utils::DBusHandler* dbusHandler; //!< D-bus Handler
+    /** @brief PLDM request handler */
+    pldm::requester::Handler<pldm::requester::Request>* handler;
+};
+
+} // namespace host_effecters
+} // namespace pldm