blob: 9ef133b2dc073d221eeeff418424bfa1e87e7236 [file]
#include "LeakGPIODetector.hpp"
#include "LeakEvents.hpp"
#include "SystemdInterface.hpp"
#include <sdbusplus/async.hpp>
#include <sdbusplus/message/native_types.hpp>
#include <xyz/openbmc_project/Association/Definitions/aserver.hpp>
#include <xyz/openbmc_project/State/Leak/Detector/aserver.hpp>
#include <array>
#include <functional>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
namespace leak
{
namespace config
{
/** @brief Leak level to systemd target service map */
static constexpr auto leakActionTargets = std::to_array<
std::tuple<config::DetectorLevel, std::string_view, std::string_view>>(
{{config::DetectorLevel::warning, "assert",
"xyz.openbmc_project.leakdetector.warning.assert@"},
{config::DetectorLevel::warning, "deassert",
"xyz.openbmc_project.leakdetector.warning.deassert@"},
{config::DetectorLevel::critical, "assert",
"xyz.openbmc_project.leakdetector.critical.assert@"},
{config::DetectorLevel::critical, "deassert",
"xyz.openbmc_project.leakdetector.critical.deassert@"}});
} // namespace config
static auto getObjectPath(const std::string& detectorName)
-> sdbusplus::object_path
{
return (sdbusplus::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),
DetectorIntf::Definitions::properties_t{},
DetectorIntf::Detector::properties_t{
config.name, DetectorState::Normal, config.type},
DetectorIntf::signal_action::defer_emit),
ctx(ctx), leakEvents(leakEvents), config(config),
gpioInterface(ctx, config.name, config.pinName,
(config.polarity == config::PinPolarity::activeLow),
std::bind_front(&GPIODetector::updateGPIOStateAsync, this))
{
createAssociations();
DetectorIntf::emit_object_added();
ctx.spawn(gpioInterface.start());
debug("Created leak detector {NAME}", "NAME", config.name);
}
auto GPIODetector::createAssociations() -> void
{
using association_t = std::tuple<std::string, std::string, std::string>;
using association_list_t = std::vector<association_t>;
association_list_t associationList;
association_t association = {"monitoring", "monitored_by",
config.parentInventoryPath};
associationList.emplace_back(association);
associations(associationList);
}
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);
std::string action = (state() == DetectorIntf::DetectorState::Normal)
? "deassert"
: "assert";
for (const auto& [level, action_str, serviceSuffix] :
config::leakActionTargets)
{
if (config.level == level && action_str == action)
{
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