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.cpp b/extensions/openpower-pels/service_indicators.cpp
new file mode 100644
index 0000000..97eb3fe
--- /dev/null
+++ b/extensions/openpower-pels/service_indicators.cpp
@@ -0,0 +1,97 @@
+/**
+ * Copyright © 2020 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "service_indicators.hpp"
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower::pels::service_indicators
+{
+
+using namespace phosphor::logging;
+
+std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
+{
+    // At the moment there is just one type of policy.
+    return std::make_unique<LightPath>(dataIface);
+}
+
+bool LightPath::ignore(const PEL& pel) const
+{
+    // TODO
+    return false;
+}
+
+void LightPath::activate(const PEL& pel)
+{
+    if (ignore(pel))
+    {
+        return;
+    }
+
+    // Now that we've gotten this far, we'll need to turn on
+    // the system attention indicator if we don't find other
+    // indicators to turn on.
+    bool sai = true;
+    auto src = pel.primarySRC();
+    const auto& calloutsObj = (*src)->callouts();
+
+    if (calloutsObj && !calloutsObj->callouts().empty())
+    {
+        const auto& callouts = calloutsObj->callouts();
+
+        // From the callouts, find the location codes whose
+        // LEDs need to be turned on.
+        auto locCodes = getLocationCodes(callouts);
+        if (!locCodes.empty())
+        {
+            // Find the LED groups for those location codes.
+            auto ledPaths = getLEDGroupPaths(locCodes);
+            if (!ledPaths.empty())
+            {
+                // Tell the LED groups to assert their LEDs.
+                assertLEDs(ledPaths);
+                sai = false;
+            }
+        }
+    }
+
+    if (sai)
+    {
+        log<level::INFO>("The System Attention Indicator needs to be turned "
+                         "on, when available");
+    }
+}
+
+std::vector<std::string> LightPath::getLocationCodes(
+    const std::vector<std::unique_ptr<src::Callout>>& callouts) const
+{
+    // TODO
+    return {};
+}
+
+std::vector<std::string> LightPath::getLEDGroupPaths(
+    const std::vector<std::string>& locationCodes) const
+{
+    // TODO
+    return {};
+}
+
+void LightPath::assertLEDs(const std::vector<std::string>& ledGroups) const
+{
+    // TODO
+}
+
+} // namespace openpower::pels::service_indicators