Implement Liquid Leak Detector
Implement liquid leak detector based on design
https://gerrit.openbmc.org/c/openbmc/docs/+/73152.
Related PRs:
https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/73151
https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/73707
https://gerrit.openbmc.org/c/openbmc/sdbusplus/+/75461
https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/75999
Tested:
```
>> busctl tree xyz.openbmc_project.LeakDetector
└─ /xyz
└─ /xyz/openbmc_project
└─ /xyz/openbmc_project/state
└─ /xyz/openbmc_project/state/leak
└─ /xyz/openbmc_project/state/leak/detector
├─ /xyz/openbmc_project/state/leak/detector/TrayDetector1
└─ /xyz/openbmc_project/state/leak/detector/TrayDetector2
>> echo pull-up > /sys/devices/platform/gpio-sim.0/gpiochip2/sim_gpio0/pull
>> curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/Entries
{
"@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries",
"@odata.type": "#LogEntryCollection.LogEntryCollection",
"Description": "Collection of System Event Log Entries",
"Members": [
...
{
"@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/2",
"@odata.type": "#LogEntry.v1_9_0.LogEntry",
"AdditionalDataURI": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/2/attachment",
"Created": "2024-05-10T06:40:30.423+00:00",
"EntryType": "Event",
"Id": "2",
"Message": "xyz.openbmc_project.State.Leak.Detector.LeakDetectedWarning",
"Modified": "2024-05-10T06:40:30.423+00:00",
"Name": "System Event Log Entry",
"Resolved": false,
"Severity": "Warning"
}
],
"Members@odata.count": 2,
"Name": "System Event Log Entries"
}
>> echo pull-down > /sys/devices/platform/gpio-sim.0/gpiochip2/sim_gpio0/pull
>> curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/Entries
{
"@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries",
"@odata.type": "#LogEntryCollection.LogEntryCollection",
"Description": "Collection of System Event Log Entries",
"Members": [
...
{
"@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/2",
"@odata.type": "#LogEntry.v1_9_0.LogEntry",
"AdditionalDataURI": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/2/attachment",
"Created": "2024-05-10T06:40:30.423+00:00",
"EntryType": "Event",
"Id": "2",
"Message": "xyz.openbmc_project.State.Leak.Detector.LeakDetectedWarning",
"Modified": "2024-05-10T06:42:23.989+00:00",
"Name": "System Event Log Entry",
"Resolved": true,
"Severity": "Warning"
},
{
"@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/3",
"@odata.type": "#LogEntry.v1_9_0.LogEntry",
"AdditionalDataURI": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/3/attachment",
"Created": "2024-05-10T06:42:24.024+00:00",
"EntryType": "Event",
"Id": "3",
"Message": "xyz.openbmc_project.State.Leak.Detector.LeakDetectedNormal",
"Modified": "2024-05-10T06:42:24.024+00:00",
"Name": "System Event Log Entry",
"Resolved": false,
"Severity": "OK"
}
],
"Members@odata.count": 3,
"Name": "System Event Log Entries"
}
```
Change-Id: Id6981deb314ca6852c5e31b932b28e601c2f3976
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/src/GPIOInterface.cpp b/src/GPIOInterface.cpp
new file mode 100644
index 0000000..0bd0f4c
--- /dev/null
+++ b/src/GPIOInterface.cpp
@@ -0,0 +1,94 @@
+#include "GPIOInterface.hpp"
+
+#include <gpiod.hpp>
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/async.hpp>
+
+#include <exception>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+namespace gpio
+{
+
+PHOSPHOR_LOG2_USING;
+
+GPIOInterface::GPIOInterface(sdbusplus::async::context& ctx,
+ const std::string& consumerName,
+ const std::string& pinName, bool activeLow,
+ Callback_t updateStateCallback) :
+ ctx(ctx), pinName(pinName),
+ updateStateCallback(std::move(updateStateCallback))
+{
+ if (!this->updateStateCallback)
+ {
+ throw std::runtime_error("updateStateCallback is not set");
+ }
+ line = gpiod::find_line(pinName);
+ if (!line)
+ {
+ throw std::runtime_error("Failed to find GPIO line for " + pinName);
+ }
+ try
+ {
+ line.request({consumerName, gpiod::line_request::EVENT_BOTH_EDGES,
+ activeLow ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
+ }
+ catch (std::exception& e)
+ {
+ throw std::runtime_error("Failed to request line for " + pinName +
+ " with error " + e.what());
+ }
+
+ int lineFd = line.event_get_fd();
+ if (lineFd < 0)
+ {
+ throw std::runtime_error(
+ "Failed to get event fd for GPIO line " + pinName);
+ }
+
+ fdioInstance = std::make_unique<sdbusplus::async::fdio>(ctx, lineFd);
+}
+
+auto GPIOInterface::start() -> sdbusplus::async::task<>
+{
+ // Start the async read for the GPIO line
+ ctx.spawn(readGPIOAsyncEvent());
+
+ // Read the initial GPIO value
+ co_await readGPIOAsync();
+}
+
+auto GPIOInterface::readGPIOAsync() -> sdbusplus::async::task<>
+{
+ auto lineValue = line.get_value();
+ if (lineValue < 0)
+ {
+ error("Failed to read GPIO line {LINENAME}", "LINENAME", pinName);
+ co_return;
+ }
+ co_await updateStateCallback(lineValue == gpiod::line_event::RISING_EDGE);
+
+ co_return;
+}
+
+auto GPIOInterface::readGPIOAsyncEvent() -> sdbusplus::async::task<>
+{
+ while (!ctx.stop_requested())
+ {
+ // Wait for the fd event for the line to change
+ co_await fdioInstance->next();
+
+ line.event_read();
+ auto lineValue = line.get_value();
+
+ co_await updateStateCallback(
+ lineValue == gpiod::line_event::RISING_EDGE);
+ }
+
+ co_return;
+}
+
+} // namespace gpio