From f9306ab2da3b847e67ca5dc739d856f7d78094c9 Mon Sep 17 00:00:00 2001 From: Sander Speetjens Date: Thu, 10 Apr 2025 11:27:51 +0200 Subject: [PATCH] Add gpio class --- server/gpio/gpio.cpp | 176 +++++++++++++++++++++++++++++++++++++++++++ server/gpio/gpio.hpp | 55 ++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 server/gpio/gpio.cpp create mode 100644 server/gpio/gpio.hpp diff --git a/server/gpio/gpio.cpp b/server/gpio/gpio.cpp new file mode 100644 index 0000000..e2ffff1 --- /dev/null +++ b/server/gpio/gpio.cpp @@ -0,0 +1,176 @@ +#include "gpio.hpp" +#include "spdlog/spdlog.h" +#include +#if __aarch64__ +#else +struct gpiod_chip *gpiod_chip_open(const char *path){return NULL;} +struct gpiod_line_settings *gpiod_line_settings_new(void){} +int gpiod_line_settings_set_direction(struct gpiod_line_settings *settings, + enum gpiod_line_direction direction){return 0;} +int gpiod_line_settings_set_output_value(struct gpiod_line_settings *settings, + enum gpiod_line_value value){return 0;} +struct gpiod_line_config *gpiod_line_config_new(void){return NULL;} +int gpiod_line_config_add_line_settings(struct gpiod_line_config *config, + const unsigned int *offsets, + size_t num_offsets, + struct gpiod_line_settings *settings){return 0;} +struct gpiod_request_config *gpiod_request_config_new(void){} +void gpiod_request_config_set_consumer(struct gpiod_request_config *config, + const char *consumer){} +struct gpiod_line_request * + gpiod_chip_request_lines(struct gpiod_chip *chip, + struct gpiod_request_config *req_cfg, + struct gpiod_line_config *line_cfg){return NULL;} +int gpiod_line_request_set_value(struct gpiod_line_request *request, + unsigned int offset, + enum gpiod_line_value value){} +enum gpiod_line_value +gpiod_line_request_get_value(struct gpiod_line_request *request, + unsigned int offset) {} +void gpiod_request_config_free(struct gpiod_request_config *config){} +void gpiod_line_config_free(struct gpiod_line_config *config){} +void gpiod_line_settings_free(struct gpiod_line_settings *settings){} +void gpiod_chip_close(struct gpiod_chip *chip){} +#endif + +GPIO::GPIO(Direction dir, uint8_t gpio, bool state, QObject* parent) + : QObject(parent), m_offset(gpio) +{ + if (dir == Direction::Output) + { + m_request = request_output_line("/dev/gpiochip0", gpio, (enum gpiod_line_value)state, "Consumer"); + if (!m_request) { + SPDLOG_ERROR("failed to request line: {}", + strerror(errno)); + } + return; + } + if (dir == Direction::Input) + { + m_request = request_input_line("/dev/gpiochip0", gpio, "get-line-value"); + if (!m_request) { + fprintf(stderr, "failed to request line: %s\n", + strerror(errno)); + } + } +} + +void GPIO::set_value(bool value) +{ + gpiod_line_request_set_value(m_request, m_offset, (enum gpiod_line_value)value); +} + +bool GPIO::value() +{ + return (bool)gpiod_line_request_get_value(m_request, m_offset); +} + +struct gpiod_line_request * +GPIO::request_output_line(const char *chip_path, unsigned int offset, + enum gpiod_line_value value, const char *consumer) +{ + struct gpiod_request_config *req_cfg = NULL; + struct gpiod_line_request *request = NULL; + struct gpiod_line_settings *settings; + struct gpiod_line_config *line_cfg; + struct gpiod_chip *chip; + int ret; + + chip = gpiod_chip_open(chip_path); + if (!chip) + return NULL; + + settings = gpiod_line_settings_new(); + if (!settings) + goto close_chip; + + gpiod_line_settings_set_direction(settings, + GPIOD_LINE_DIRECTION_OUTPUT); + gpiod_line_settings_set_output_value(settings, value); + + line_cfg = gpiod_line_config_new(); + if (!line_cfg) + goto free_settings; + + ret = gpiod_line_config_add_line_settings(line_cfg, &offset, 1, + settings); + if (ret) + goto free_line_config; + + if (consumer) { + req_cfg = gpiod_request_config_new(); + if (!req_cfg) + goto free_line_config; + + gpiod_request_config_set_consumer(req_cfg, consumer); + } + + request = gpiod_chip_request_lines(chip, req_cfg, line_cfg); + + gpiod_request_config_free(req_cfg); + +free_line_config: + gpiod_line_config_free(line_cfg); + +free_settings: + gpiod_line_settings_free(settings); + +close_chip: + gpiod_chip_close(chip); + + return request; +} + +struct gpiod_line_request *GPIO::request_input_line(const char *chip_path, + unsigned int offset, + const char *consumer) +{ + struct gpiod_request_config *req_cfg = NULL; + struct gpiod_line_request *request = NULL; + struct gpiod_line_settings *settings; + struct gpiod_line_config *line_cfg; + struct gpiod_chip *chip; + int ret; + + chip = gpiod_chip_open(chip_path); + if (!chip) + return NULL; + + settings = gpiod_line_settings_new(); + if (!settings) + goto close_chip; + + gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT); + + line_cfg = gpiod_line_config_new(); + if (!line_cfg) + goto free_settings; + + ret = gpiod_line_config_add_line_settings(line_cfg, &offset, 1, + settings); + if (ret) + goto free_line_config; + + if (consumer) { + req_cfg = gpiod_request_config_new(); + if (!req_cfg) + goto free_line_config; + + gpiod_request_config_set_consumer(req_cfg, consumer); + } + + request = gpiod_chip_request_lines(chip, req_cfg, line_cfg); + + gpiod_request_config_free(req_cfg); + +free_line_config: + gpiod_line_config_free(line_cfg); + +free_settings: + gpiod_line_settings_free(settings); + +close_chip: + gpiod_chip_close(chip); + + return request; +} diff --git a/server/gpio/gpio.hpp b/server/gpio/gpio.hpp new file mode 100644 index 0000000..67a3038 --- /dev/null +++ b/server/gpio/gpio.hpp @@ -0,0 +1,55 @@ +#ifndef GPIO_HPP +#define GPIO_HPP + +#include +#ifdef __aarch64__ +#include +#else +struct gpiod_line_request{}; +struct gpiod_request_config{}; +struct gpiod_line_settings{}; +struct gpiod_line_config{}; +struct gpiod_chip{}; +enum gpiod_line_value { + GPIOD_LINE_VALUE_ERROR = -1, + /**< Returned to indicate an error when reading the value. */ + GPIOD_LINE_VALUE_INACTIVE = 0, + /**< Line is logically inactive. */ + GPIOD_LINE_VALUE_ACTIVE = 1, + /**< Line is logically active. */ +}; +enum gpiod_line_direction { + GPIOD_LINE_DIRECTION_AS_IS = 1, + /**< Request the line(s), but don't change direction. */ + GPIOD_LINE_DIRECTION_INPUT, + /**< Direction is input - for reading the value of an externally driven + * GPIO line. */ + GPIOD_LINE_DIRECTION_OUTPUT, + /**< Direction is output - for driving the GPIO line. */ +}; +#endif + +class GPIO : public QObject { + Q_OBJECT + public: + enum Direction { + Input, + Output + }; + explicit GPIO(Direction dir, uint8_t gpio, bool state = false, QObject* parent = nullptr); + void set_value(bool val); + bool value(); + + private: + struct gpiod_line_request * + request_output_line(const char *chip_path, unsigned int offset, + enum gpiod_line_value value, const char *consumer); + struct gpiod_line_request *request_input_line(const char *chip_path, + unsigned int offset, + const char *consumer); + + struct gpiod_line_request *m_request; + unsigned int m_offset; +}; + +#endif // GPIO_HPP