blob: d4b2d1b04315e7f847c27560f8fc679a636268c4 [file] [log] [blame]
Marc Olberding1e17db52025-08-27 12:25:28 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 NVIDIA
3
4#include "gpio.hpp"
5
6#include "utilities.hpp"
7
8#include <cstring>
9#include <filesystem>
10#include <format>
11#include <iostream>
12#include <unordered_map>
13
14static std::unordered_map<std::string, gpiod::line> io;
15using namespace std::chrono_literals;
16
17namespace gpio
18{
19
20void set(const char* line_name, int value,
21 std::chrono::milliseconds find_timeout)
22{
23 std::cerr << std::format("{} Request to set to {}\n", line_name, value);
24 std::chrono::milliseconds polling_time = 10ms;
25 gpiod::line& line = io[line_name];
26 if (!line)
27 {
28 do
29 {
30 line = gpiod::find_line(line_name);
31 if (!line)
32 {
33 std::cerr << std::format(
34 "{} not found yet, waiting and retrying\n", line_name);
35
36 sleep_milliseconds(polling_time);
37 find_timeout -= polling_time;
38 }
39 } while (!line && find_timeout > 0s);
40 if (!line && find_timeout <= 0s)
41 {
42 std::cerr << std::format("{} Unable to find\n", line_name);
43 return;
44 }
45 try
46 {
47 line.request({app_name, gpiod::line_request::DIRECTION_OUTPUT, 0},
48 value);
49 }
50 catch (const std::system_error& e)
51 {
52 std::cerr << std::format(
53 "{} unable to set direction and value {}\n", line_name,
54 e.what());
55 return;
56 }
57 // No need to set if the init did it for us
58 std::cerr << std::format("{} Set to {}\n", line_name, value);
59 return;
60 }
61 std::cerr << std::format("{} Settingto {}\n", line_name, value);
62 line.set_value(value);
63}
64
65int get(const char* line_name)
66{
67 std::cerr << std::format("{} Request to get\n", line_name);
68
69 gpiod::line line = gpiod::find_line(line_name);
70 if (!line)
71 {
72 std::cerr << std::format("{} Set unable to find\n", line_name);
73 return -1;
74 }
75 try
76 {
77 line.request({app_name, gpiod::line_request::DIRECTION_INPUT, 0});
78 }
79 catch (const std::system_error& e)
80 {
81 std::cerr << std::format("{} unable to set {}\n", line_name, e.what());
82 }
83
84 int value = line.get_value();
85 std::cerr << std::format("{} was {}\n", line_name, value);
86 return value;
87}
88
89Event::Event(const char* line_name_in, int value_in) :
90 line_name(line_name_in), value(value_in)
91{
92 line = gpiod::find_line(line_name);
93 if (!line)
94 {
95 std::cerr << std::format("{} GpioEvent: Unable to find\n", line_name);
96 return;
97 }
98 int edge = (value != 0) ? ::gpiod::line_request::EVENT_RISING_EDGE
99 : ::gpiod::line_request::EVENT_FALLING_EDGE;
100
101 line.request({app_name, edge, 0});
102
103 int val = line.get_value();
104 if (val == value)
105 {
106 std::cerr << std::format("{} GpioEvent is already {}\n", line_name,
107 val);
108 }
109 else
110 {
111 std::cerr << std::format("GpioEvent created for {}\n", line_name);
112 }
113}
114
115EventResult Event::wait()
116{
117 if (!line)
118 {
119 std::cerr << std::format("Line {} wasn't initialized\n", line_name);
120 return EventResult::Error;
121 }
122 std::cerr << std::format("{} Waiting to go to {}\n", line_name,
123 (value != 0) ? "assert" : "deassert");
124 auto events = line.event_wait(std::chrono::seconds(120));
125 if (!events)
126 {
127 std::cerr << std::format("{} Timeout\n", line_name);
128 return EventResult::Timeout;
129 }
130
131 std::cerr << std::format("{} Asserted\n", line_name);
132
133 return EventResult::Asserted;
134}
135
136void set_raw(unsigned int chip_num, unsigned int bit_num, int value)
137{
138 std::string syspath = std::format("gpiochip{}", chip_num);
139 std::cerr << std::format("Setting gpiochip{} bit {} to {}\n", chip_num,
140 bit_num, value);
141 try
142 {
143 gpiod::chip chip(syspath);
144 gpiod::line line = chip.get_line(bit_num);
145 line.request({app_name, gpiod::line_request::DIRECTION_OUTPUT, 0},
146 value);
147 std::cerr << std::format("gpiochip{} bit {} set to {}\n", chip_num,
148 bit_num, value);
149 }
150 catch (const std::system_error& e)
151 {
152 std::cerr << std::format("Error setting gpiochip{} bit {}: {}\n",
153 chip_num, bit_num, e.what());
154 }
155}
156
157int find_chip_idx_from_dir(std::string_view device_path)
158{
159 std::string gpio_chip;
160 for (const auto& entry : std::filesystem::directory_iterator(device_path))
161 {
162 std::string path = entry.path().string();
163 if (path.find("gpiochip") != std::string::npos)
164 {
165 gpio_chip =
166 path.substr(path.find("gpiochip") + std::strlen("gpiochip"));
167 break;
168 }
169 }
170 if (gpio_chip.empty())
171 {
172 std::cerr << "Error: Could not find GPIO chip number\n";
173 return -ENOENT;
174 }
175
176 std::cerr << "Found GPIO chip: gpiochip" << gpio_chip << "\n";
177 unsigned int gpiochipint = 0;
178 std::from_chars_result r =
179 std::from_chars(&*gpio_chip.begin(), &*gpio_chip.end(), gpiochipint);
180 if (r.ec != std::error_code() || r.ptr != &*gpio_chip.end())
181 {
182 std::cout << "Failed to convert gpiochip\n";
183 return -EINVAL;
184 }
185 return gpiochipint;
186}
187} // namespace gpio