fault-monitor: Add OperationalStatus Functional monitoring

Currently, the default way is to update the Asserted property of
the LedManager by monitoring the `/xyz/openbmc_project/logging`
object path.

The intent behind this commit is to add another way to monitor the
`xyz.openbmc_project.State.Decorator.OperationalStatus` interface
of the Inventory D-Bus object, and check whether the Inventory
D-Bus object is associated with the LED group D-Bus object, and
then update the Asserted property of the LedManager.

Since both these methods handle the faults differently,
Only ONE of these 2 methods can be enabled and NOT both.

The first way is supported by default. To turn OFF the default way
AND turn ON this second way, Enable monitor-operational-status.

Tested:
- enable `monitor-operational-status` in bbappend file, built successfully.

- Before changing the `OperationalStatus` interface:
  busctl get-property xyz.openbmc_project.Inventory.Manager
  /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
  xyz.openbmc_project.State.Decorator.OperationalStatus Functional
  b true

  busctl get-property xyz.openbmc_project.LED.GroupManager
  /xyz/openbmc_project/led/groups/powersupply1_fault
  xyz.openbmc_project.Led.Group Asserted
  b false

  busctl get-property xyz.openbmc_project.LED.Controller.front_psu
  /xyz/openbmc_project/led/physical/front_psu xyz.openbmc_project.Led.Physical State
  s "xyz.openbmc_project.Led.Physical.Action.Off"

- After changing the `OperationalStatus` interface:
  busctl set-property xyz.openbmc_project.Inventory.
  /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
  xyz.openbmc_project.State.Decorator.OperationalStatus Functional b false

  busctl get-property xyz.openbmc_project.Inventory.Manager
  /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
  xyz.openbmc_project.State.Decorator.OperationalStatus Functional
  b false

  (
	If we have more than 1 LED Group D-Bus object:
	Like: The system/chassis/motherboard/powersupply1 path contains
	      two sets of LEDGroup
	{
        "types":
        {
            "rType": "fru",
            "fType": "fault_led_group"
        },
        "paths":
        [
            "/xyz/openbmc_project/led/groups/powersupply0_fault",
            "/xyz/openbmc_project/led/groups/powersupply1_fault"
        ]
    }
  busctl get-property xyz.openbmc_project.LED.GroupManager
  /xyz/openbmc_project/led/groups/powersupply0_fault xyz.openbmc_project.Led.Group Asserted
  b true
  )

  busctl get-property xyz.openbmc_project.LED.GroupManager
  /xyz/openbmc_project/led/groups/powersupply1_fault xyz.openbmc_project.Led.Group Asserted
  b true

  busctl get-property xyz.openbmc_project.LED.Controller.front_psu
  /xyz/openbmc_project/led/physical/front_psu xyz.openbmc_project.Led.Physical State
  s "xyz.openbmc_project.Led.Physical.Action.Blink"

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I36c47198168028ea2b55804cf66d0285847afbd4
diff --git a/fault-monitor/operational-status-monitor.hpp b/fault-monitor/operational-status-monitor.hpp
new file mode 100644
index 0000000..ccf65a5
--- /dev/null
+++ b/fault-monitor/operational-status-monitor.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include "../utils.hpp"
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server.hpp>
+
+namespace phosphor
+{
+namespace led
+{
+namespace Operational
+{
+namespace status
+{
+namespace monitor
+{
+using namespace phosphor::led::utils;
+
+/** @class Monitor
+ *  @brief Implementation of LED handling during the change of the Functional
+ *         property of the OperationalStatus interface
+ *
+ *  @details This implements methods for watching OperationalStatus interface of
+ *           Inventory D-Bus object and then assert corresponding LED Group
+ *           D-Bus objects.
+ */
+class Monitor
+{
+  public:
+    Monitor() = delete;
+    ~Monitor() = default;
+    Monitor(const Monitor&) = delete;
+    Monitor& operator=(const Monitor&) = delete;
+    Monitor(Monitor&&) = default;
+    Monitor& operator=(Monitor&&) = default;
+
+    /** @brief Add a watch for OperationalStatus.
+     *
+     *  @param[in] bus -  D-Bus object
+     */
+    Monitor(sdbusplus::bus::bus& bus) :
+        bus(bus),
+        matchSignal(bus,
+                    "type='signal',member='PropertiesChanged', "
+                    "interface='org.freedesktop.DBus.Properties', "
+                    "sender='xyz.openbmc_project.Inventory.Manager', "
+                    "arg0namespace='xyz.openbmc_project.State.Decorator."
+                    "OperationalStatus'",
+                    std::bind(std::mem_fn(&Monitor::matchHandler), this,
+                              std::placeholders::_1))
+
+    {}
+
+  private:
+    /** @brief sdbusplus D-Bus connection. */
+    sdbusplus::bus::bus& bus;
+
+    /** @brief sdbusplus signal matches for Monitor */
+    sdbusplus::bus::match_t matchSignal;
+
+    /** DBusHandler class handles the D-Bus operations */
+    DBusHandler dBusHandler;
+
+    /**
+     * @brief Callback handler that gets invoked when the PropertiesChanged
+     *        signal is caught by this app. Message is scanned for Inventory
+     *        D-Bus object path and if OperationalStatus::Functional is changed,
+     *        then corresponding LED Group D-Bus object is called to assert.
+     *
+     * @param[in] msg - The D-Bus message contents
+     */
+    void matchHandler(sdbusplus::message::message& msg);
+
+    /**
+     * @brief From the Inventory D-Bus object, obtains the associated LED group
+     *        D-Bus object, where the association name is "fault_led_group"
+     *
+     * @param[in] inventoryPath         - Inventory D-Bus object path
+     *
+     * @return std::vector<std::string> - Vector of LED Group D-Bus object paths
+     */
+    const std::vector<std::string>
+        getLedGroupPaths(const std::string& inventoryPath) const;
+
+    /**
+     * @brief Update the Asserted property of the LED Group Manager.
+     *
+     * @param[in] ledGroupPaths   - LED Group D-Bus object Paths
+     * @param[in] value           - The Asserted property value, True / False
+     */
+    void updateAssertedProperty(const std::vector<std::string>& ledGroupPaths,
+                                bool value);
+};
+} // namespace monitor
+} // namespace status
+} // namespace Operational
+} // namespace led
+} // namespace phosphor