Add gpio-presence-sensor

This is to implement the gpio based hw inventory design [1].

There is a new meson option 'gpio-presence' to enable/disable the
daemon.

Summary of the functionality:

- fetch configuration from EM, according to the configuration interface
- the D-Bus interface is
  xyz.openbmc_project.Configuration.GPIODeviceDetect
- the configuration represents devices for which presence can be
  detected based on gpio values.
- watch gpios for changes
- add/remove the xyz.openbmc_project.Inventory.Source.DevicePresence
  interface on the object path based on gpio values.

References:
[1] https://github.com/openbmc/docs/blob/master/designs/inventory/gpio-based-hardware-inventory.md
[2] https://www.kernel.org/doc/html/latest/admin-guide/gpio/gpio-sim.html

Tested: using linux gpio-sim facility, see below

1. create a fake gpio via [2]
2. configure gpio-presence-sensor as per [1]
3. run the gpio-presence-sensor
4. change the value of the gpio previously configured
5. there should be log output (at debug level)
6. the dbus interfaces exposed should appear/disappear as per [1]

Change-Id: I4cf039b583247581aa5c6c6c59e7fc41ced0bb85
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
diff --git a/src/gpio-presence/gpio_presence_manager.hpp b/src/gpio-presence/gpio_presence_manager.hpp
new file mode 100644
index 0000000..d490fe3
--- /dev/null
+++ b/src/gpio-presence/gpio_presence_manager.hpp
@@ -0,0 +1,92 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2024. All rights
+ * reserved. SPDX-License-Identifier: Apache-2.0
+ */
+#pragma once
+
+#include "config_provider.hpp"
+#include "device_presence.hpp"
+#include "sdbusplus/async/fdio.hpp"
+
+#include <gpiod.hpp>
+
+#include <string>
+#include <unordered_map>
+
+namespace gpio_presence
+{
+
+constexpr auto service = "xyz.openbmc_project.gpiopresence";
+
+class GPIOPresenceManager
+{
+  public:
+    explicit GPIOPresenceManager(sdbusplus::async::context& ctx);
+
+    // spawns the initialization function
+    auto start() -> void;
+
+    // @param[in] name       name of device, e.g. 'cable0'
+    // @returns              true if present
+    auto getPresence(const std::string& name) -> bool;
+
+    // request our dbus name
+    // @returns         our dbus name
+    auto setupBusName() const -> std::string;
+
+    // add the configuration for object at path 'obj'
+    // @param[in] obj       object path for the new config
+    // @param[in] config    configuration for the new object
+    auto addConfig(const sdbusplus::message::object_path& obj,
+                   std::unique_ptr<DevicePresence> config) -> void;
+
+    // update presence information based on new gpio state
+    // @param[in] gpioLine       name of the gpio line
+    // @param[in] state          new state of the gpio line
+    auto updatePresence(const std::string& gpioLine, bool state) -> void;
+
+    // maps gpio names to cached gpio state
+    // true <=> High
+    std::unordered_map<std::string, bool> gpioState;
+
+  private:
+    // fetch our configuration from dbus
+    // @param[in] obj object path of the configuration
+    auto addConfigFromDbusAsync(sdbusplus::message::object_path obj)
+        -> sdbusplus::async::task<void>;
+
+    // delete our configuration for the object at 'objPath'
+    // @param[in] objPath         path of the object we want to forget
+    auto removeConfig(const std::string& objPath) -> void;
+
+    // fetch configuration from dbus via object mapper
+    // and register dbus matches for configuration
+    auto initialize() -> sdbusplus::async::task<void>;
+
+    // handle config interface added
+    // @param[in] obj    object path of the configuration
+    auto addConfigHandler(sdbusplus::message::object_path obj) -> void;
+
+    // async block on fdio gpio event and handle it
+    // @param[in] gpioLine     name of the gpio to watch for events
+    auto readGPIOAsyncEvent(std::string gpioLine)
+        -> sdbusplus::async::task<void>;
+
+    // maps dbus object paths to configurations
+    // e.g. /xyz/openbmc_project/inventory/system/board/My_Baseboard/cable0
+    std::unordered_map<std::string, std::unique_ptr<DevicePresence>>
+        presenceMap;
+
+    // maps gpio names to fdios
+    std::unordered_map<std::string, std::unique_ptr<sdbusplus::async::fdio>>
+        fdios;
+    // maps gpio names to libgpiod lines
+    std::unordered_map<std::string, ::gpiod::line> gpioLines;
+
+    sdbusplus::async::context& ctx;
+    sdbusplus::server::manager_t manager;
+
+    ConfigProvider configProvider;
+};
+
+} // namespace gpio_presence