Add CPLD CRC Error Monitor

This adds a new signal monitor for the CPLD CRC Error that
relies on CPU presence to determine if an error should be
logged.

Tested:
Used the GPIO mockup driver to manually trigger both CPLD CRC
Monitors and confirm that the Redfish event is logged correctly.
Details on the GPIO mockup driver can be found here:
https://www.kernel.org/doc/html/latest/admin-guide/gpio/gpio-mockup.html

Change-Id: I17f651277ce0960d52c837c97529f3c5c70d2199
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
diff --git a/include/error_monitors/cpld_crc_monitor.hpp b/include/error_monitors/cpld_crc_monitor.hpp
new file mode 100644
index 0000000..4f93bbd
--- /dev/null
+++ b/include/error_monitors/cpld_crc_monitor.hpp
@@ -0,0 +1,110 @@
+/*
+// Copyright (c) 2021 Intel 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.
+*/
+#pragma once
+#include <systemd/sd-journal.h>
+
+#include <error_monitors/base_gpio_monitor.hpp>
+#include <host_error_monitor.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+namespace host_error_monitor::cpld_crc_monitor
+{
+class CPLDCRCMonitor :
+    public host_error_monitor::base_gpio_monitor::BaseGPIOMonitor
+{
+    const static host_error_monitor::base_gpio_monitor::AssertValue
+        assertValue =
+            host_error_monitor::base_gpio_monitor::AssertValue::highAssert;
+    size_t cpuNum;
+    bool cpuPresent;
+
+    void logEvent() override
+    {
+        std::string cpuNumber = "CPU " + std::to_string(cpuNum);
+        std::string msg = cpuNumber + " CPLD CRC error.";
+
+        sd_journal_send("MESSAGE=HostError: %s", msg.c_str(), "PRIORITY=%i",
+                        LOG_INFO, "REDFISH_MESSAGE_ID=%s",
+                        "OpenBMC.0.1.CPUError", "REDFISH_MESSAGE_ARGS=%s",
+                        msg.c_str(), NULL);
+    }
+
+    bool getCPUPresence(const std::string& cpuPresenceName)
+    {
+        // Find the GPIO line
+        gpiod::line cpuPresenceLine = gpiod::find_line(cpuPresenceName);
+        if (!cpuPresenceLine)
+        {
+            std::cerr << "Failed to find the " << cpuPresenceName << " line.\n";
+            return false;
+        }
+
+        // Request GPIO input
+        try
+        {
+            cpuPresenceLine.request(
+                {"host-error-monitor", gpiod::line_request::DIRECTION_INPUT});
+        }
+        catch (std::exception&)
+        {
+            std::cerr << "Failed to request " << cpuPresenceName << " input\n";
+            return false;
+        }
+
+        // CPU presence is low-assert
+        cpuPresent = !cpuPresenceLine.get_value();
+
+        return true;
+    }
+
+    void assertHandler() override
+    {
+        // Ignore this if the CPU is not present
+        if (cpuPresent)
+        {
+            host_error_monitor::base_gpio_monitor::BaseGPIOMonitor::
+                assertHandler();
+        }
+    }
+
+    /** @brief Constructor to create a CPLD CRC signal monitor
+     *  @param[in] io - ASIO io_service
+     *  @param[in] conn - ASIO connection
+     *  @param[in] signalName - GPIO name of the signal to monitor
+     *  @param[in] cpuNum - CPU number associated with the signal
+     *  @param[in] cpuPresenceName - Name of the GPIO that can be read to check
+     *                               if the CPU is present
+     */
+  public:
+    CPLDCRCMonitor(boost::asio::io_service& io,
+                   std::shared_ptr<sdbusplus::asio::connection> conn,
+                   const std::string& signalName, const size_t cpuNum,
+                   const std::string& cpuPresenceName) :
+        BaseGPIOMonitor(io, conn, signalName, assertValue),
+        cpuNum(cpuNum)
+    {
+        if (!getCPUPresence(cpuPresenceName))
+        {
+            valid = false;
+        }
+
+        if (valid)
+        {
+            startMonitoring();
+        }
+    }
+};
+} // namespace host_error_monitor::cpld_crc_monitor