Compare commits

...

2 Commits

@ -31,6 +31,13 @@ this will also create the build diretory for you.
```./ked_executable -pin 21 -dir out -set``` ```./ked_executable -pin 21 -dir out -set```
Will set GPIO21 pin (HEADER 40) to High Will set GPIO21 pin (HEADER 40) to High
#Size Difference with version that has no function pointers
```
Size
text data bss dec hex filename
3836 332 16 4184 1058 ked_executable
```

@ -1,6 +1,6 @@
/** /**
* @file gpio_control.c * @file gpio_control.c
* @brief CLI utility to control GPIOs using KED GPIO interface (Linux). * @brief CLI utility to control GPIOs using the KED GPIO interface (Linux).
*/ */
#include "../ked/peripherals/gpio/gpio.h" #include "../ked/peripherals/gpio/gpio.h"
@ -8,64 +8,79 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define GPIOCHIP_DEFAULT "/dev/gpiochip0"
/**
* @brief Print usage message for the CLI tool.
*/
void print_usage(const char* prog_name) {
printf("Usage: %s -pin <number> -set|-reset|-toggle|-read\n", prog_name);
}
/** /**
* @brief Simple command-line tool to test the GPIO API. * @brief Entry point for GPIO control CLI.
*/ */
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if (argc < 4) { if (argc < 4) {
printf("Usage: %s -pin <BCM_number> -[set|reset|toggle|read]\n", argv[0]); print_usage(argv[0]);
return 1; return 1;
} }
unsigned int pin = 0; uint32_t pin = 0;
const char* action = NULL; uint8_t action = 0xFF; // 0=set, 1=reset, 2=toggle, 3=read
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-pin") == 0 && i + 1 < argc) { if (strcmp(argv[i], "-pin") == 0 && i + 1 < argc) {
pin = (unsigned int)atoi(argv[++i]); pin = atoi(argv[++i]);
} else if (strncmp(argv[i], "-", 1) == 0) { } else if (strcmp(argv[i], "-set") == 0) {
action = argv[i] + 1; // skip '-' prefix action = 0;
} else if (strcmp(argv[i], "-reset") == 0) {
action = 1;
} else if (strcmp(argv[i], "-toggle") == 0) {
action = 2;
} else if (strcmp(argv[i], "-read") == 0) {
action = 3;
} }
} }
if (pin == 0 || !action) { if (pin == 0 || action == 0xFF) {
fprintf(stderr, "Invalid usage.\n"); print_usage(argv[0]);
return 1; return 2;
} }
gpio_t gpio; gpio_t gpio_conf = {
gpio_config cfg = {
.chipname = "/dev/gpiochip0", .chipname = "/dev/gpiochip0",
.line_offset = pin, .line_offset = pin,
.mode = GPIO_MODE_DEFAULT, .direction = (action == 3) ? T_GPIO_DIRECTION_INPUT : T_GPIO_DIRECTION_OUTPUT,
.direction = (strcmp(action, "read") == 0) ? GPIO_DIRECTION_INPUT : GPIO_DIRECTION_OUTPUT, .bias = T_GPIO_BIAS_DEFAULT,
.bias = GPIO_BIAS_NONE .mode = T_GPIO_MODE_DEFAULT,
.status = T_GPIO_STATUS_NOT_INIT
}; };
gpio_error_t err = ked_gpio_init(&gpio, &cfg);
if (err != GPIO_OK) { gpio_fn_ptr_t led = {0};
if (gpio.on_error) gpio.on_error(err);
gpio_error_t err = ked_gpio_init(&gpio_conf, &led);
if (err != T_GPIO_ERR_OK) {
if (led.on_error) led.on_error(err);
return 1; return 1;
} }
if (strcmp(action, "set") == 0) { switch (action) {
gpio.set(true); case 0:
//printf("GPIO%u set HIGH\n", pin); if (led.set) led.set(1);
} else if (strcmp(action, "reset") == 0) { break;
gpio.set(false); case 1:
//printf("GPIO%u set LOW\n", pin); if (led.set) led.set(0);
} else if (strcmp(action, "toggle") == 0) { break;
gpio.toggle(); case 2:
//printf("GPIO%u toggled\n", pin); if (led.toggle) led.toggle();
} else if (strcmp(action, "read") == 0) { break;
bool value = gpio.read(); case 3:
printf("%s\n", value ? "1" : "0"); printf("GPIO%u value: %d\n", pin, led.read());
} else { break;
fprintf(stderr, "Unknown action: %s\n", action);
if (gpio.on_error) gpio.on_error(GPIO_ERR_UNKNOWN);
return 1;
} }
gpio.deinit(); // Clean up
return 0; return 0;
} }

@ -1,6 +1,6 @@
/** /**
************************************************************************************************** **************************************************************************************************
* @file pin.h * @file gpio.h
* @author Kerem Yollu & Edwin Koch * @author Kerem Yollu & Edwin Koch
* @date 24.04.2025 * @date 24.04.2025
* @version 0.0.1 * @version 0.0.1
@ -12,166 +12,144 @@
* that allows unified control of digital I/O pins across different platforms, * that allows unified control of digital I/O pins across different platforms,
* such as microcontrollers or embedded Linux systems (e.g., Raspberry Pi). * such as microcontrollers or embedded Linux systems (e.g., Raspberry Pi).
* *
* The interface provides a driver table through which initialization, * The implementation uses a centralized internal function pointer table to map
* read/write, and toggle operations can be performed in a platform-agnostic way. * platform-specific logic (e.g., Linux or STM32) to a unified interface.
* Platform-specific implementations must define and populate the `KED_GPIO` * Application code can use `ked_gpio_set()`, `ked_gpio_read()` etc. without dealing with callbacks.
* driver table with appropriate function pointers.
*
* Usage Example:
* @code
* gpio_t* pin = KED_GPIO.init(&config);
* KED_GPIO.set(pin, true);
* bool state = KED_GPIO.read(pin);
* KED_GPIO.toggle(pin);
* @endcode
*
* @todo
* - 24.04.2025: Implement more function pointer to enhance available gpio operations
* - 24.04.2025: Implement Defined States, Errors, Configuration Options
************************************************************************************************** **************************************************************************************************
*/ */
#ifndef KED_PERIPHERALS_GPIO_GPIO_H_
#define KED_PERIPHERALS_GPIO_GPIO_H_
#include <stdbool.h> #ifndef KED_PERIPHERALS_GPIO_H_
#define KED_PERIPHERALS_GPIO_H_
/** #include <stdint.h>
* @brief Enumeration for GPIO functional modes.
*/
typedef enum {
GPIO_MODE_DEFAULT,
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_ANALOG,
GPIO_MODE_ALTERNATE
} gpio_mode_t;
/** #ifdef __cplusplus
* @brief Enumeration for GPIO direction settings. extern "C" {
*/ #endif
/** GPIO Mode Types */
typedef enum { typedef enum {
GPIO_DIRECTION_INPUT, T_GPIO_MODE_DEFAULT,
GPIO_DIRECTION_OUTPUT T_GPIO_MODE_INPUT,
T_GPIO_MODE_OUTPUT,
T_GPIO_MODE_ANALOG,
T_GPIO_MODE_ALTERNATE
} gpio_function_t;
/** GPIO Direction (explicit) */
typedef enum {
T_GPIO_DIRECTION_INPUT,
T_GPIO_DIRECTION_OUTPUT
} gpio_direction_t; } gpio_direction_t;
/** /** Drive types for output pins */
* @brief Enumeration for GPIO drive configurations.
*/
typedef enum { typedef enum {
GPIO_DRIVE_DEFAULT, T_GPIO_DRIVE_DEFAULT,
GPIO_DRIVE_PUSH_PULL, T_GPIO_DRIVE_PUSH_PULL,
GPIO_DRIVE_OPEN_DRAIN T_GPIO_DRIVE_OPEN_DRAIN
} gpio_drive_t; } gpio_drive_t;
/** /** Pull-up/pull-down configurations */
* @brief Enumeration for internal bias resistor settings.
*/
typedef enum { typedef enum {
GPIO_BIAS_NONE, T_GPIO_BIAS_DEFAULT,
GPIO_BIAS_DISABLE, T_GPIO_BIAS_DISABLE,
GPIO_BIAS_PULL_UP, T_GPIO_BIAS_PULL_UP,
GPIO_BIAS_PULL_DOWN T_GPIO_BIAS_PULL_DOWN
} gpio_bias_t; } gpio_bias_t;
/** /** Optional pin speed enumeration */
* @brief Enumeration for GPIO speed settings.
*/
typedef enum { typedef enum {
GPIO_SPEED_DEFAULT, T_GPIO_SPEED_DEFAULT,
GPIO_SPEED_LOW, T_GPIO_SPEED_LOW,
GPIO_SPEED_MEDIUM, T_GPIO_SPEED_MEDIUM,
GPIO_SPEED_HIGH, T_GPIO_SPEED_HIGH,
GPIO_SPEED_VERY_HIGH T_GPIO_SPEED_VERY_HIGH
} gpio_speed_t; } gpio_speed_t;
/** /** Enable/disable pin interrupt */
* @brief Enumeration for enabling or disabling GPIO interrupts.
*/
typedef enum { typedef enum {
GPIO_IRQ_DISABLED, T_GPIO_IRQ_DISABLED,
GPIO_IRQ_ENABLED T_GPIO_IRQ_ENABLED
} gpio_irq_t; } gpio_irq_t;
/** /** GPIO Status */
* @brief GPIO error status codes. typedef enum {
*/ T_GPIO_STATUS_NOT_INIT, /**< GPIO is not initialized */
T_GPIO_STATUS_READY, /**< GPIO is ready for use */
T_GPIO_STATUS_BUSY, /**< GPIO is currently in use */
T_GPIO_STATUS_ERROR, /**< GPIO encountered an error */
T_GPIO_STATUS_UPDATING /**< GPIO is currently being reconfigured */
} gpio_status_t;
/** GPIO error status codes */
typedef enum { typedef enum {
GPIO_OK, T_GPIO_ERR_OK, /*!< Suscess flag for the Init Function */
GPIO_ERR_UNSUPPORTED_MODE, T_GPIO_ERR_UNSUPPORTED_MODE, /*!< Mode is either not valid orsupported by **Hardwaware** */
GPIO_ERR_LINE_BUSY, T_GPIO_ERR_UNSUPPORTED_ALTERNATE, /*!< Alternateive mode is unvalid */
GPIO_ERR_NOT_AVAILABLE, T_GPIO_ERR_BUS_BUSY, /*!< The chosen GPIO BUS is already in Use */
GPIO_ERR_NO_PULL, T_GPIO_ERR_NOT_AVAILABLE, /*!< Pin does Not aloow GPIO functionalities or does not Exists */
GPIO_ERR_NOT_ANALOG, T_GPIO_ERR_NOT_BIASABLE, /*!< No Pull-Up or Pull-Down Option are awailable */
GPIO_ERR_UNKNOWN T_GPIO_ERR_NO_INTERRUPT_SUPPORT, /*!< This GPIO Doesn't allow interrupts */
T_GPIO_ERR_UNSUPPORTED_DRIVE, /*!< This gate griving option is Unsupported (Pushpull, open drain etc..) */
T_GPIO_ERR_UNSUPPORTED_SPEED, /*!< The choosen bus speed is not supported */
T_GPIO_ERR_UNKNOWN /*!< Goal Would be To never be Used, but can be helpful during Developpment */
} gpio_error_t; } gpio_error_t;
/** /* === Function pointer types (used internally only) === */
* @brief Function pointer type for writing a logic level.
*/
typedef void (*gpio_write_fn)(bool value);
/** typedef void (*fn_ptr_gpio_write)(uint8_t value);
* @brief Function pointer type for reading a logic level. typedef uint8_t (*fn_ptr_gpio_read)(void);
*/ typedef void (*fn_ptr_gpio_toggle)(void);
typedef bool (*gpio_read_fn)(void); typedef void (*fn_ptr_gpio_error)(gpio_error_t);
typedef gpio_error_t (*fn_ptr_gpio_update)(void);
/**
* @brief Function pointer type for toggling a GPIO pin.
*/
typedef void (*gpio_toggle_fn)(void);
/**
* @brief Function pointer type for GPIO deinitialization.
*/
typedef void (*gpio_deinit_fn)(void);
/**
* @brief Abstract GPIO handle with callback operations.
*/
typedef void (*gpio_error_fn)(gpio_error_t);
/** /**
* @brief Abstract GPIO handle with callback operations. * @brief Internal function pointer table used by platform implementations.
*/ */
typedef struct { typedef struct {
gpio_write_fn set; fn_ptr_gpio_write set;
gpio_read_fn read; fn_ptr_gpio_read read;
gpio_toggle_fn toggle; fn_ptr_gpio_toggle toggle;
gpio_deinit_fn deinit; /**< Deinitialization function pointer */ fn_ptr_gpio_update update;
gpio_error_fn on_error; /**< Error handling callback */ fn_ptr_gpio_error on_error;
} gpio_t; } gpio_fn_ptr_t;
/** /* === Platform-specific types === */
* @brief Function pointer type for platform-specific GPIO initialization. typedef struct gpio_s gpio_t;
*/
typedef gpio_error_t (*gpio_init_fn)(gpio_t* gpio, const void* config);
#ifdef KED_USES_LINUX #ifdef KED_USES_LINUX
/** /** GPIO configuration structure for Linux */
* @brief Platform-specific GPIO configuration structure for Linux. struct gpio_s {
*/
typedef struct {
const char* chipname; const char* chipname;
unsigned int line_offset; unsigned int line_offset;
gpio_mode_t mode; gpio_function_t mode;
gpio_direction_t direction; gpio_direction_t direction;
gpio_bias_t bias; gpio_bias_t bias;
} gpio_config; gpio_status_t status;
};
#endif #endif
/* === Public API === */
/** /**
* @brief Initialize a GPIO using the specified configuration. * @brief Initialize a GPIO using the specified configuration.
* *
* @param gpio Pointer to target gpio_t handle * @param gpio Pointer to target gpio_t handle
* @param config Platform-specific GPIO configuration struct
* @return GPIO_OK on success, or an appropriate gpio_error_t * @return GPIO_OK on success, or an appropriate gpio_error_t
*/ */
gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_config* config); gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_fn_ptr_t* callbacks);
/** /**
* @brief Deinitialize and release resources associated with a GPIO pin. * @brief Deinitialize and release resources associated with a GPIO pin.
*
* @param gpio Pointer to GPIO object
*/ */
void ked_gpio_deinit(gpio_t* gpio); void ked_gpio_deinit(gpio_t* gpio, const gpio_fn_ptr_t* callbacks);
/* === Platform-agnostic GPIO control interface === */
#ifdef __cplusplus
}
#endif
#endif /* KED_PERIPHERALS_GPIO_GPIO_H_ */ #endif /* KED_PERIPHERALS_GPIO_H_ */

@ -1,139 +1,163 @@
/** /**
* @file gpio_linux.c * @file gpio_linux.c
* @brief GPIO implementation for Linux using libgpiod and KED callback injection. * @brief GPIO implementation for Linux using libgpiod and KED function pointer injection.
*/ */
#include "../../ked/peripherals/gpio/gpio.h" #include "../../ked/peripherals/gpio/gpio.h"
#include <gpiod.h> #include <gpiod.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
/** /**
* @brief Internal Linux GPIO context. * @brief Internal Linux GPIO context.
* *
* Holds pointers to the open GPIO chip and the requested line. * Holds the active chip and line handles.
* This implementation assumes one active GPIO at a time (can be extended to multiple if needed).
*/ */
typedef struct { typedef struct {
struct gpiod_chip* chip; /**< File descriptor to the opened GPIO chip */ struct gpiod_chip* chip;
struct gpiod_line* line; /**< Reference to the requested GPIO line */ struct gpiod_line* line;
} gpio_linux_ctx_t; } gpio_linux_ctx_t;
static gpio_linux_ctx_t gpio_ctx; static gpio_linux_ctx_t gpio_ctx;
/* === Centralized Error Handling === */
/** /**
* @brief Set the output level of the GPIO line. * @brief Centralized error handler for GPIO-related failures.
*
* Logs the error to stderr and can be extended to trigger hooks or diagnostics.
* *
* @param value Logic level to set (true for HIGH, false for LOW). * @param err The GPIO error code encountered.
*/ */
static void gpio_linux_set(bool value) { static void gpio_linux_handle_error(gpio_error_t err) {
gpiod_line_set_value(gpio_ctx.line, value); fprintf(stderr, "[GPIO/Linux] ERROR: %d\n", err);
// Future: report to diagnostic logger or panic handler
} }
/* === GPIO Operation Implementations === */
/** /**
* @brief Read the current logic level of the GPIO line. * @brief Set the output level of the GPIO line.
* *
* @return Logic level (true for HIGH, false for LOW). * @param value 1 = HIGH, 0 = LOW
*/ */
static bool gpio_linux_read(void) { static void gpio_linux_set(uint8_t value) {
return gpiod_line_get_value(gpio_ctx.line); if (gpio_ctx.line) {
gpiod_line_set_value(gpio_ctx.line, value);
} else {
gpio_linux_handle_error(T_GPIO_ERR_NOT_AVAILABLE);
}
} }
/** /**
* @brief Toggle the current state of the GPIO output. * @brief Read the current logic level of the GPIO line.
*
* @return Logic level (1 = HIGH, 0 = LOW)
*/ */
static void gpio_linux_toggle(void) { static uint8_t gpio_linux_read(void) {
int current = gpiod_line_get_value(gpio_ctx.line); if (!gpio_ctx.line) {
gpiod_line_set_value(gpio_ctx.line, !current); gpio_linux_handle_error(T_GPIO_ERR_NOT_AVAILABLE);
return 0;
}
return (uint8_t)gpiod_line_get_value(gpio_ctx.line);
} }
/** /**
* @brief Release the GPIO line and chip. * @brief Toggle the current logic level of the GPIO line.
*
* Called during deinitialization to free resources.
*/ */
static void gpio_linux_deinit(void) { static void gpio_linux_toggle(void) {
if (gpio_ctx.line) { if (!gpio_ctx.line) {
gpiod_line_release(gpio_ctx.line); gpio_linux_handle_error(T_GPIO_ERR_NOT_AVAILABLE);
gpio_ctx.line = NULL; return;
}
if (gpio_ctx.chip) {
gpiod_chip_close(gpio_ctx.chip);
gpio_ctx.chip = NULL;
} }
uint8_t current = (uint8_t)gpiod_line_get_value(gpio_ctx.line);
gpiod_line_set_value(gpio_ctx.line, !current);
} }
/** /**
* @brief Default error handling function. * @brief Update GPIO configuration dynamically.
* *
* @param err The GPIO error code to report. * Currently not supported on Linux placeholder only.
*/ */
static void gpio_linux_handle_error(gpio_error_t err) { static gpio_error_t gpio_linux_update(void) {
fprintf(stderr, "[GPIO ERROR] Code: %d\n", err); // TODO: implement runtime reconfiguration if needed
return T_GPIO_ERR_UNSUPPORTED_MODE;
} }
/* === Public API Implementation === */
/** /**
* @brief Initialize a GPIO using a Linux-specific gpio_config. * @brief Initialize the GPIO using the given Linux gpio_t config and callback struct.
* *
* Sets the direction and bias of the line according to the config. * This sets direction, bias, and binds callbacks to the gpio_fn_ptr_t table.
* *
* @param gpio Pointer to a gpio_t handle to be configured. * @param gpio Pointer to GPIO configuration structure
* @param config Pointer to a Linux-specific gpio_config structure. * @param callbacks Optional pointer to gpio_fn_ptr_t to receive platform-specific handlers
* @return GPIO_OK on success or an appropriate gpio_error_t on failure. * @return T_GPIO_ERR_OK on success, or appropriate error code
*/ */
gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_config* config) { gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_fn_ptr_t* callbacks) {
gpio_ctx.chip = gpiod_chip_open(config->chipname); gpio_ctx.chip = gpiod_chip_open(gpio->chipname);
if (!gpio_ctx.chip) { if (!gpio_ctx.chip) {
gpio->on_error(GPIO_ERR_NOT_AVAILABLE); gpio_linux_handle_error(T_GPIO_ERR_NOT_AVAILABLE);
return GPIO_ERR_NOT_AVAILABLE; return T_GPIO_ERR_NOT_AVAILABLE;
} }
gpio_ctx.line = gpiod_chip_get_line(gpio_ctx.chip, config->line_offset); gpio_ctx.line = gpiod_chip_get_line(gpio_ctx.chip, gpio->line_offset);
if (!gpio_ctx.line) { if (!gpio_ctx.line) {
gpiod_chip_close(gpio_ctx.chip); gpiod_chip_close(gpio_ctx.chip);
gpio->on_error(GPIO_ERR_NOT_AVAILABLE); gpio_linux_handle_error(T_GPIO_ERR_NOT_AVAILABLE);
return GPIO_ERR_NOT_AVAILABLE; return T_GPIO_ERR_NOT_AVAILABLE;
} }
struct gpiod_line_request_config req_cfg = { struct gpiod_line_request_config req_cfg = {
.consumer = "ked", .consumer = "ked_gpio",
.request_type = (config->direction == GPIO_DIRECTION_OUTPUT) .request_type = (gpio->direction == T_GPIO_DIRECTION_OUTPUT)
? GPIOD_LINE_REQUEST_DIRECTION_OUTPUT ? GPIOD_LINE_REQUEST_DIRECTION_OUTPUT
: GPIOD_LINE_REQUEST_DIRECTION_INPUT, : GPIOD_LINE_REQUEST_DIRECTION_INPUT,
.flags = 0 .flags = 0
}; };
if (config->bias == GPIO_BIAS_PULL_UP) { if (gpio->bias == T_GPIO_BIAS_PULL_UP)
req_cfg.flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP; req_cfg.flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
} else if (config->bias == GPIO_BIAS_PULL_DOWN) { else if (gpio->bias == T_GPIO_BIAS_PULL_DOWN)
req_cfg.flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN; req_cfg.flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
} else if (config->bias == GPIO_BIAS_DISABLE) { else if (gpio->bias == T_GPIO_BIAS_DISABLE)
req_cfg.flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; req_cfg.flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
} else if (config->bias == GPIO_BIAS_NONE) { else if (gpio->bias == T_GPIO_BIAS_DEFAULT)
req_cfg.request_type = GPIOD_LINE_REQUEST_DIRECTION_AS_IS; req_cfg.request_type = GPIOD_LINE_REQUEST_DIRECTION_AS_IS;
}
if (gpiod_line_request(gpio_ctx.line, &req_cfg, 0) < 0) { if (gpiod_line_request(gpio_ctx.line, &req_cfg, 0) < 0) {
gpiod_chip_close(gpio_ctx.chip); gpiod_chip_close(gpio_ctx.chip);
gpio->on_error(GPIO_ERR_LINE_BUSY); gpio_linux_handle_error(T_GPIO_ERR_BUS_BUSY);
return GPIO_ERR_LINE_BUSY; return T_GPIO_ERR_BUS_BUSY;
} }
gpio->set = gpio_linux_set; if (callbacks) {
gpio->read = gpio_linux_read; ((gpio_fn_ptr_t*)callbacks)->set = gpio_linux_set;
gpio->toggle = gpio_linux_toggle; ((gpio_fn_ptr_t*)callbacks)->read = gpio_linux_read;
gpio->deinit = gpio_linux_deinit; ((gpio_fn_ptr_t*)callbacks)->toggle = gpio_linux_toggle;
gpio->on_error = gpio_linux_handle_error; ((gpio_fn_ptr_t*)callbacks)->update = gpio_linux_update;
((gpio_fn_ptr_t*)callbacks)->on_error = gpio_linux_handle_error;
}
return GPIO_OK; return T_GPIO_ERR_OK;
} }
/** /**
* @brief Generic GPIO deinitialization entry point. * @brief Deinitialize GPIO from platform and free resources.
* *
* @param gpio Pointer to the gpio_t structure with deinit function populated. * @param gpio Unused in this implementation
* @param callbacks Pointer to callback table that includes `deinit`
*/ */
void ked_gpio_deinit(gpio_t* gpio) { void ked_gpio_deinit(gpio_t* gpio, const gpio_fn_ptr_t* callbacks) {
if (gpio && gpio->deinit) { if (gpio_ctx.line) {
gpio->deinit(); gpiod_line_release(gpio_ctx.line);
gpio_ctx.line = NULL;
}
if (gpio_ctx.chip) {
gpiod_chip_close(gpio_ctx.chip);
gpio_ctx.chip = NULL;
} }
} }

Loading…
Cancel
Save