#include #include #include // 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; }