blob: d4b2d1b04315e7f847c27560f8fc679a636268c4 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 NVIDIA
#include "gpio.hpp"
#include "utilities.hpp"
#include <cstring>
#include <filesystem>
#include <format>
#include <iostream>
#include <unordered_map>
static std::unordered_map<std::string, gpiod::line> io;
using namespace std::chrono_literals;
namespace gpio
{
void set(const char* line_name, int value,
std::chrono::milliseconds find_timeout)
{
std::cerr << std::format("{} Request to set to {}\n", line_name, value);
std::chrono::milliseconds polling_time = 10ms;
gpiod::line& line = io[line_name];
if (!line)
{
do
{
line = gpiod::find_line(line_name);
if (!line)
{
std::cerr << std::format(
"{} not found yet, waiting and retrying\n", line_name);
sleep_milliseconds(polling_time);
find_timeout -= polling_time;
}
} while (!line && find_timeout > 0s);
if (!line && find_timeout <= 0s)
{
std::cerr << std::format("{} Unable to find\n", line_name);
return;
}
try
{
line.request({app_name, gpiod::line_request::DIRECTION_OUTPUT, 0},
value);
}
catch (const std::system_error& e)
{
std::cerr << std::format(
"{} unable to set direction and value {}\n", line_name,
e.what());
return;
}
// No need to set if the init did it for us
std::cerr << std::format("{} Set to {}\n", line_name, value);
return;
}
std::cerr << std::format("{} Settingto {}\n", line_name, value);
line.set_value(value);
}
int get(const char* line_name)
{
std::cerr << std::format("{} Request to get\n", line_name);
gpiod::line line = gpiod::find_line(line_name);
if (!line)
{
std::cerr << std::format("{} Set unable to find\n", line_name);
return -1;
}
try
{
line.request({app_name, gpiod::line_request::DIRECTION_INPUT, 0});
}
catch (const std::system_error& e)
{
std::cerr << std::format("{} unable to set {}\n", line_name, e.what());
}
int value = line.get_value();
std::cerr << std::format("{} was {}\n", line_name, value);
return value;
}
Event::Event(const char* line_name_in, int value_in) :
line_name(line_name_in), value(value_in)
{
line = gpiod::find_line(line_name);
if (!line)
{
std::cerr << std::format("{} GpioEvent: Unable to find\n", line_name);
return;
}
int edge = (value != 0) ? ::gpiod::line_request::EVENT_RISING_EDGE
: ::gpiod::line_request::EVENT_FALLING_EDGE;
line.request({app_name, edge, 0});
int val = line.get_value();
if (val == value)
{
std::cerr << std::format("{} GpioEvent is already {}\n", line_name,
val);
}
else
{
std::cerr << std::format("GpioEvent created for {}\n", line_name);
}
}
EventResult Event::wait()
{
if (!line)
{
std::cerr << std::format("Line {} wasn't initialized\n", line_name);
return EventResult::Error;
}
std::cerr << std::format("{} Waiting to go to {}\n", line_name,
(value != 0) ? "assert" : "deassert");
auto events = line.event_wait(std::chrono::seconds(120));
if (!events)
{
std::cerr << std::format("{} Timeout\n", line_name);
return EventResult::Timeout;
}
std::cerr << std::format("{} Asserted\n", line_name);
return EventResult::Asserted;
}
void set_raw(unsigned int chip_num, unsigned int bit_num, int value)
{
std::string syspath = std::format("gpiochip{}", chip_num);
std::cerr << std::format("Setting gpiochip{} bit {} to {}\n", chip_num,
bit_num, value);
try
{
gpiod::chip chip(syspath);
gpiod::line line = chip.get_line(bit_num);
line.request({app_name, gpiod::line_request::DIRECTION_OUTPUT, 0},
value);
std::cerr << std::format("gpiochip{} bit {} set to {}\n", chip_num,
bit_num, value);
}
catch (const std::system_error& e)
{
std::cerr << std::format("Error setting gpiochip{} bit {}: {}\n",
chip_num, bit_num, e.what());
}
}
int find_chip_idx_from_dir(std::string_view device_path)
{
std::string gpio_chip;
for (const auto& entry : std::filesystem::directory_iterator(device_path))
{
std::string path = entry.path().string();
if (path.find("gpiochip") != std::string::npos)
{
gpio_chip =
path.substr(path.find("gpiochip") + std::strlen("gpiochip"));
break;
}
}
if (gpio_chip.empty())
{
std::cerr << "Error: Could not find GPIO chip number\n";
return -ENOENT;
}
std::cerr << "Found GPIO chip: gpiochip" << gpio_chip << "\n";
unsigned int gpiochipint = 0;
std::from_chars_result r =
std::from_chars(&*gpio_chip.begin(), &*gpio_chip.end(), gpiochipint);
if (r.ec != std::error_code() || r.ptr != &*gpio_chip.end())
{
std::cout << "Failed to convert gpiochip\n";
return -EINVAL;
}
return gpiochipint;
}
} // namespace gpio