PEL: Activate service indicators on new PEL

A service indicator is a device used to add the user during system
service actions.  In the case of PELs, service indicators are always
LEDs.

When a new PEL is created or received from the host, code will check the
service indicator policy to see if any indicators need to be set at that
time based on the PEL callouts.

There is a specific policy named LightPath that is the default, and it
is currently the only supported policy.  This policy has a set of rules
to say which called out location codes need their indicators activated.

After it determines the location codes, it looks up the corresponding
D-Bus inventory paths for them, and then looks up the LED group objects
to assert based on those inventory paths.

If, for any reason, the code can't get a complete list of FRU LEDs to
turn on, then it will turn on the System Attention Indicator LED.  It is
still TBD how that is actually done.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I771258a8957fb0944ec1f8787086123e068bc6cc
diff --git a/extensions/openpower-pels/service_indicators.hpp b/extensions/openpower-pels/service_indicators.hpp
new file mode 100644
index 0000000..36eacf8
--- /dev/null
+++ b/extensions/openpower-pels/service_indicators.hpp
@@ -0,0 +1,131 @@
+#pragma once
+
+#include "data_interface.hpp"
+#include "pel.hpp"
+
+namespace openpower::pels::service_indicators
+{
+
+/**
+ * @class Policy
+ *
+ * The base class for service indicator policies.
+ */
+class Policy
+{
+  public:
+    Policy() = delete;
+    virtual ~Policy() = default;
+    Policy(const Policy&) = default;
+    Policy& operator=(const Policy&) = default;
+    Policy(Policy&&) = default;
+    Policy& operator=(Policy&&) = default;
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] dataIface - The DataInterface object
+     */
+    explicit Policy(const DataInterfaceBase& dataIface) : _dataIface(dataIface)
+    {
+    }
+
+    /**
+     * @brief Pure virtual function for activating service indicators
+     *        based on PEL contents.
+     *
+     * @param[in] pel - The PEL
+     */
+    virtual void activate(const PEL& pel) = 0;
+
+  protected:
+    /**
+     * @brief Reference to the DataInterface object
+     */
+    const DataInterfaceBase& _dataIface;
+};
+
+/**
+ * @class LightPath
+ *
+ * This class implements the 'LightPath' IBM policy for
+ * activating LEDs.  It has a set of rules to use to choose
+ * which callouts inside PELs should have their LEDs asserted,
+ * and then activates them by writing the Assert property on
+ * LED group D-Bus objects.
+ */
+class LightPath : public Policy
+{
+  public:
+    LightPath() = delete;
+    virtual ~LightPath() = default;
+    LightPath(const LightPath&) = default;
+    LightPath& operator=(const LightPath&) = default;
+    LightPath(LightPath&&) = default;
+    LightPath& operator=(LightPath&&) = default;
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] dataIface - The DataInterface object
+     */
+    explicit LightPath(const DataInterfaceBase& dataIface) : Policy(dataIface)
+    {
+    }
+
+    /**
+     * @brief Turns on LEDs for certain FRUs called out in the PEL.
+     *
+     * First it selectively chooses location codes listed in the FRU
+     * callout section that it wants to turn on LEDs for.  Next it
+     * looks up the inventory D-Bus paths for the FRU represented by
+     * those location codes, and then looks for associations to the
+     * LED group objects for those inventory paths.  After it has
+     * the LED group object, it sets the Asserted property on it.
+     *
+     * It only does the above for PELs that were created by the BMC
+     * or hostboot and have the Serviceable action flag set.
+     *
+     * If there are problems looking up any inventory path or LED
+     * group, then it will stop and not activate any LEDs at all.
+     *
+     * @param[in] pel - The PEL
+     */
+    void activate(const PEL& pel) override;
+
+    /**
+     * @brief Description TODO
+     */
+    std::vector<std::string> getLocationCodes(
+        const std::vector<std::unique_ptr<src::Callout>>& callouts) const;
+
+    /**
+     * @brief Description TODO
+     */
+    bool ignore(const PEL& pel) const;
+
+  private:
+    /**
+     * @brief Description TODO
+     */
+    std::vector<std::string>
+        getLEDGroupPaths(const std::vector<std::string>& locationCodes) const;
+
+    /**
+     * @brief Description TODO
+     */
+    void assertLEDs(const std::vector<std::string>& ledGroups) const;
+};
+
+/**
+ * @brief Returns the object for the service indicator policy
+ *        implemented on the system.
+ *
+ * @param[in] dataIface - The DataInterface object
+ *
+ * @return std::unique_ptr<Policy> - The policy object
+ *
+ */
+std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface);
+
+} // namespace openpower::pels::service_indicators