blob: 4e5bc26745efd58ac24f329f9b8efe2c05c14eed [file] [log] [blame]
#include "tlbmc/collector/gpio_collector.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "g3/macros.h"
#include "thread/thread.h"
#include "nlohmann/json.hpp"
#include "gpio_config.pb.h"
#include "tlbmc/hal/gpio/gpio.h"
#include "tlbmc/hal/gpio/gpio_monitor.h"
namespace milotic_tlbmc {
absl::Status GpioCollector::SetGpio(absl::string_view gpio_name, bool value) {
auto it = output_gpios_.find(gpio_name);
if (it == output_gpios_.end()) {
return absl::NotFoundError(absl::StrCat("GPIO not found: ", gpio_name));
}
return it->second->SetValue(value);
}
absl::StatusOr<std::unique_ptr<GpioCollector>> GpioCollector::Create(
const Params& params) {
std::shared_ptr<boost::asio::io_context> io_context =
std::make_shared<boost::asio::io_context>();
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
work_guard(boost::asio::make_work_guard(*io_context));
absl::flat_hash_map<std::string, std::unique_ptr<Gpio>> input_gpios;
absl::flat_hash_map<std::string, std::unique_ptr<Gpio>> output_gpios;
absl::flat_hash_map<std::string, std::unique_ptr<GpioMonitor>> gpio_monitors;
for (const auto& gpio_config : params.gpio_configs.gpio_configs()) {
switch (gpio_config.request_type_case()) {
case GpioConfig::kGpioDirection: {
ECCLESIA_ASSIGN_OR_RETURN(std::unique_ptr<Gpio> gpio,
Gpio::Create(gpio_config));
switch (gpio_config.gpio_direction()) {
case GPIO_DIRECTION_INPUT:
input_gpios[gpio->GetGpioName()] = std::move(gpio);
break;
case GPIO_DIRECTION_OUTPUT:
output_gpios[gpio->GetGpioName()] = std::move(gpio);
break;
default:
return absl::InvalidArgumentError(absl::StrCat(
"Unsupported GPIO direction: ", gpio_config.gpio_direction()));
}
break;
}
case GpioConfig::kGpioEventConfig: {
ECCLESIA_ASSIGN_OR_RETURN(std::unique_ptr<GpioMonitor> gpio_monitor,
GpioMonitor::Create(gpio_config, io_context));
gpio_monitors[gpio_monitor->GetGpioName()] = std::move(gpio_monitor);
break;
}
default:
return absl::InvalidArgumentError(
absl::StrCat("Unsupported GPIO request type: ",
gpio_config.request_type_case()));
}
}
// io_context should start running after all gpio_monitors are created.
auto thread_manager = std::make_unique<GpioThreadManager>(params.clock);
thread_manager->threads.push_back(
params.thread_factory->New([io_context]() { io_context->run(); }));
thread_manager->work_guards.push_back(std::move(work_guard));
thread_manager->io_contexts.push_back(std::move(io_context));
return absl::WrapUnique(
new GpioCollector(std::move(thread_manager), std::move(input_gpios),
std::move(output_gpios), std::move(gpio_monitors)));
}
nlohmann::json GpioCollector::ToJson() const {
nlohmann::json::object_t response;
nlohmann::json::array_t input_gpios;
nlohmann::json::array_t output_gpios;
nlohmann::json::array_t monitored_gpios;
for (const auto& [name, input_gpio] : input_gpios_) {
nlohmann::json::object_t gpio_json;
absl::StatusOr<bool> gpio_value = input_gpio->GetValue();
gpio_json["Name"] = name;
if (gpio_value.ok()) {
gpio_json["Value"] = *gpio_value;
} else {
LOG(ERROR) << "Failed to get GPIO value for " << name << " : "
<< gpio_value.status();
gpio_json["Value"] = nullptr;
}
input_gpios.push_back(gpio_json);
}
for (const auto& [name, output_gpio] : output_gpios_) {
nlohmann::json::object_t gpio_json;
gpio_json["Name"] = name;
output_gpios.push_back(gpio_json);
}
for (const auto& [name, gpio_monitor] : gpio_monitors_) {
nlohmann::json::object_t gpio_json;
absl::StatusOr<bool> gpio_value = gpio_monitor->GetGpioValue();
gpio_json["Name"] = name;
if (gpio_value.ok()) {
gpio_json["Value"] = *gpio_value;
} else {
LOG(ERROR) << "Failed to get GPIO value for " << name << " : "
<< gpio_value.status();
gpio_json["Value"] = nullptr;
}
monitored_gpios.push_back(gpio_json);
}
response["Input"] = input_gpios;
response["Output"] = output_gpios;
response["Monitoring"] = monitored_gpios;
return response;
}
nlohmann::json EmptyGpioCollector::GetSchedulerStats() const {
return nlohmann::json::parse("{\"Warning\": \"EmptyGpioCollector used.\"}");
}
nlohmann::json EmptyGpioCollector::ToJson() const {
return nlohmann::json::parse("{\"Warning\": \"EmptyGpioCollector used.\"}");
}
std::unique_ptr<EmptyGpioCollector> EmptyGpioCollector::Create() {
return std::make_unique<EmptyGpioCollector>();
}
GpioThreadManager::~GpioThreadManager() {
// Stop the scheduler first.
task_scheduler->Stop();
// Finally join all threads.
for (const std::shared_ptr<boost::asio::io_context>& io_context :
io_contexts) {
io_context->stop();
}
for (const std::unique_ptr<ecclesia::ThreadInterface>& thread : threads) {
thread->Join();
}
}
} // namespace milotic_tlbmc