triviOS/pin_control/lib/pin_control.c
2023-09-13 10:42:07 -06:00

157 lines
3.7 KiB
C

#include <stdio.h>
#include <gpiod.h>
#include <pin_control.h>
// https://docs.kernel.org/driver-api/gpio/using-gpio.html
#define GPIO_CHIP "gpiochip0"
struct gpiod_chip *chip;
int init_gpio() {
cleanup_gpio();
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_chip_open_by_name.html
chip = gpiod_chip_open_by_name(GPIO_CHIP);
if (!chip) {
perror("[pin_control] gpiod_chip_open_by_name(\"" GPIO_CHIP "\")");
return -1;
}
return 0;
}
void cleanup_gpio() {
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_chip_close.html
if (chip) {
gpiod_chip_close(chip);
chip = NULL;
}
}
static int set_pin_state(int pin, int state) {
int ret = -1;
if (!chip) {
perror("[pin_control] attempt to set GPIO line for invalid chip");
goto exit;
}
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_chip_get_line.html
struct gpiod_line *line = gpiod_chip_get_line(chip, pin); // this may need an offset
if (!line) {
perror("[pin_control] gpiod_chip_get_line()");
goto exit;
}
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_request_output.html
if (gpiod_line_request_output(line, "house-leds", state) < 0) {
perror("[pin_control] gpiod_line_request_output()");
goto exit_line;
}
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_set_value.html
if (gpiod_line_set_value(line, state) < 0) {
perror("[pin_control] gpiod_line_set_value()");
goto exit_line;
}
ret = 0;
exit_line:
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_release.html
gpiod_line_release(line);
exit:
return ret;
}
int turn_on_pin(int pin) {
return set_pin_state(pin, 1);
}
int turn_off_pin(int pin) {
return set_pin_state(pin, 0);
}
int probe_pin(int pin) {
int ret = -1;
if (!chip) {
perror("[pin_control] attempt to read GPIO line for invalid chip");
goto exit;
}
struct gpiod_line *line = gpiod_chip_get_line(chip, pin);
if (!line) {
perror("[pin_control] gpiod_chip_get_line()");
goto exit;
} else if (gpiod_line_request_input(line, "house-leds") < 0) {
perror("[pin_control] gpiod_line_request_input()");
goto exit_line;
}
ret = gpiod_line_get_value(line);
if (ret < 0) {
perror("[pin_control] gpiod_line_get_value()");
goto exit_line;
}
exit_line:
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_release.html
gpiod_line_release(line);
exit:
return ret;
}
int turn_on_all_pins() {
for (int pin = 0; pin <= 5; pin++)
if (turn_on_pin(pin) < 0)
return -1;
return 0;
}
int turn_off_all_pins() {
for (int pin = 0; pin <= 5; pin++) {
if (turn_off_pin(pin) < 0)
return -1;
}
return 0;
}
static int button_presssed(int event, unsigned int pin, const struct timespec * timestamp, void *data) {
(void) event;
(void) timestamp;
* (int *) data = (int) pin;
return GPIOD_CTXLESS_EVENT_POLL_RET_STOP;
}
int wait_for_button_press(const unsigned pins[static 5]) {
// https://www.lane-fu.com/linuxmirror/libgpiod/doc/html/group______high__level____.html#ga3ac28eb59bbd31b8b2298f76047d377d
int pressed_pin = -1;
struct timespec ts = {
.tv_sec = 3600,
.tv_nsec = 0,
};
int ret = gpiod_ctxless_event_monitor_multiple(
GPIO_CHIP,
GPIOD_CTXLESS_EVENT_FALLING_EDGE,
pins,
5,
true,
"house-leds",
&ts, // big timout
NULL,
button_presssed,
&pressed_pin);
if (ret < 0) {
perror("[pin_control] gpiod_ctxless_event_monitor_multiple()");
return -1;
}
return pressed_pin;
}