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/leakdetector/LeakGPIODetector.cpp b/src/leakdetector/LeakGPIODetector.cpp
new file mode 100644
index 0000000..f21d1b5
--- /dev/null
+++ b/src/leakdetector/LeakGPIODetector.cpp
@@ -0,0 +1,89 @@
+#include "LeakGPIODetector.hpp"
+
+#include "LeakEvents.hpp"
+#include "SystemdInterface.hpp"
+
+#include <sdbusplus/async.hpp>
+#include <sdbusplus/message/native_types.hpp>
+
+#include <array>
+#include <functional>
+#include <string>
+#include <string_view>
+#include <utility>
+
+namespace leak
+{
+
+namespace config
+{
+
+/** @brief Leak level to systemd target service map */
+static constexpr std::array<std::pair<config::DetectorLevel, std::string_view>,
+ 2>
+ leakActionTargets = {{{config::DetectorLevel::warning,
+ "xyz.openbmc_project.leakdetector.warning@"},
+ {config::DetectorLevel::critical,
+ "xyz.openbmc_project.leakdetector.critical@"}}};
+
+} // namespace config
+
+static auto getObjectPath(const std::string& detectorName)
+ -> sdbusplus::message::object_path
+{
+ return (
+ sdbusplus::message::object_path(DetectorIntf::namespace_path::value) /
+ DetectorIntf::namespace_path::detector / detectorName);
+}
+
+GPIODetector::GPIODetector(sdbusplus::async::context& ctx, Events& leakEvents,
+ const config::DetectorConfig& config) :
+ DetectorIntf(ctx, getObjectPath(config.name).str.c_str()), ctx(ctx),
+ leakEvents(leakEvents), config(config),
+ gpioInterface(ctx, config.name, config.pinName,
+ (config.polarity == config::PinPolarity::activeLow),
+ std::bind_front(&GPIODetector::updateGPIOStateAsync, this))
+{
+ pretty_name<false>(config.name);
+ type<false>(config.type);
+
+ ctx.spawn(gpioInterface.start());
+
+ debug("Created leak detector {NAME}", "NAME", config.name);
+}
+
+auto GPIODetector::updateGPIOStateAsync(bool gpioState)
+ -> sdbusplus::async::task<>
+{
+ auto newState = gpioState ? DetectorIntf::DetectorState::Abnormal
+ : DetectorIntf::DetectorState::Normal;
+
+ debug("Updating detector {DETECTOR} state to {STATE}", "DETECTOR",
+ config.name, "STATE", newState);
+
+ if (newState != state_)
+ {
+ state(newState);
+
+ co_await leakEvents.generateLeakEvent(getObjectPath(config.name),
+ state_, config.level);
+ if (state_ != DetectorIntf::DetectorState::Normal)
+ {
+ for (const auto& [level, serviceSuffix] : config::leakActionTargets)
+ {
+ if (config.level == level)
+ {
+ auto target = std::string(serviceSuffix) + config.name +
+ ".service";
+ debug("Starting systemd target {TARGET}", "TARGET", target);
+ co_await systemd::SystemdInterface::startUnit(ctx, target);
+ break;
+ }
+ }
+ }
+ }
+
+ co_return;
+}
+
+} // namespace leak