diff --git a/README.md b/README.md index 24f3af5..c630347 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,31 @@ ``` sudo apt install libgpiod-dev ``` # To Compile from root of project + ## Prepeare for MAKE + ```cmake -S ked -B build -DMAIN_FILE=examples/pin_control.c``` this will also create the build diretory for you. ## MAKE + ```cd build``` + ```make``` ## RUN ```./ked_executable -pin 21 -dir out -set``` Will set GPIO21 pin (HEADER 40) to High +#Size Difference with Pointers, don't forget tha tin an MCU envoiroment it will also execute faster. + +``` +With Pointers +text data bss dec hex filename +3812 340 16 4168 1048 ked_executable +Without Pointer +text data bss dec hex filename +3692 332 16 4040 fc8 ked_executable ``` diff --git a/examples/pin_control.c b/examples/pin_control.c index 2f6541f..92b3ed8 100644 --- a/examples/pin_control.c +++ b/examples/pin_control.c @@ -1,6 +1,6 @@ /** * @file gpio_control.c - * @brief CLI utility to control GPIOs using KED GPIO interface (Linux). + * @brief CLI utility to control GPIO pins using KED GPIO API on Linux. */ #include "../ked/peripherals/gpio/gpio.h" @@ -9,63 +9,72 @@ #include /** - * @brief Simple command-line tool to test the GPIO API. + * @brief Print usage message for the CLI tool. + */ +void print_usage(const char* prog_name) { + printf("Usage: %s -pin -set|-reset|-toggle|-read\n", prog_name); +} + +/** + * @brief Entry point for GPIO control CLI. */ int main(int argc, char* argv[]) { if (argc < 4) { - printf("Usage: %s -pin -[set|reset|toggle|read]\n", argv[0]); + print_usage(argv[0]); return 1; } - unsigned int pin = 0; - const char* action = NULL; + uint32_t pin = 0; + 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) { - pin = (unsigned int)atoi(argv[++i]); - } else if (strncmp(argv[i], "-", 1) == 0) { - action = argv[i] + 1; // skip '-' prefix + pin = atoi(argv[++i]); + } else if (strcmp(argv[i], "-set") == 0) { + 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) { - fprintf(stderr, "Invalid usage.\n"); - return 1; + if (pin == 0 || action == 0xFF) { + print_usage(argv[0]); + return 2; } - gpio_t gpio; - gpio_config cfg = { + gpio_t gpio = { .chipname = "/dev/gpiochip0", .line_offset = pin, - .mode = GPIO_MODE_DEFAULT, - .direction = (strcmp(action, "read") == 0) ? GPIO_DIRECTION_INPUT : GPIO_DIRECTION_OUTPUT, - .bias = GPIO_BIAS_NONE + .direction = (action == 3) ? T_GPIO_DIRECTION_INPUT : T_GPIO_DIRECTION_OUTPUT, + .bias = T_GPIO_BIAS_DEFAULT, + .mode = T_GPIO_MODE_DEFAULT, + .status = T_GPIO_STATUS_NOT_INIT }; - gpio_error_t err = ked_gpio_init(&gpio, &cfg); - if (err != GPIO_OK) { - if (gpio.on_error) gpio.on_error(err); - return 1; + if (ked_gpio_init(&gpio) != T_GPIO_ERR_OK) { + fprintf(stderr, "Failed to initialize GPIO%u\n", pin); + return 3; } - if (strcmp(action, "set") == 0) { - gpio.set(true); - //printf("GPIO%u set HIGH\n", pin); - } else if (strcmp(action, "reset") == 0) { - gpio.set(false); - //printf("GPIO%u set LOW\n", pin); - } else if (strcmp(action, "toggle") == 0) { - gpio.toggle(); - //printf("GPIO%u toggled\n", pin); - } else if (strcmp(action, "read") == 0) { - bool value = gpio.read(); - printf("%s\n", value ? "1" : "0"); - } else { - fprintf(stderr, "Unknown action: %s\n", action); - if (gpio.on_error) gpio.on_error(GPIO_ERR_UNKNOWN); - return 1; + switch (action) { + case 0: + ked_gpio_set(&gpio, 1); + break; + case 1: + ked_gpio_set(&gpio, 0); + break; + case 2: + ked_gpio_toggle(&gpio); + break; + case 3: + printf("GPIO%u value: %d\n", pin, ked_gpio_read(&gpio)); + break; } - gpio.deinit(); + ked_gpio_deinit(&gpio); return 0; } diff --git a/ked/peripherals/gpio/gpio.h b/ked/peripherals/gpio/gpio.h index 7aaddf5..f9f3ccb 100644 --- a/ked/peripherals/gpio/gpio.h +++ b/ked/peripherals/gpio/gpio.h @@ -5,7 +5,7 @@ * @date 24.04.2025 * @version 0.0.1 ************************************************************************************************** - * @brief Platform-independent GPIO interface for the KED library. + * @brief Platform-independent GPIO interface for the KED library. For more details, see [KED Wiki - GPIO](https://wiki.kynsight.com/bin/view/Kynsight/Projects/KED/Peripherals/GPIO/). * * **Detailed Description :** * This header defines a hardware abstraction layer (HAL) for General Purpose I/O (GPIO) @@ -19,10 +19,12 @@ * * 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); + * gpio_config cfg = { ... }; + * gpio_t pin = ked_gpio_init(&cfg); + * ked_gpio_set(&pin, true); + * bool state = ked_gpio_read(&pin); + * ked_gpio_toggle(&pin); + * ked_gpio_deinit(&pin); * @endcode * * @todo @@ -30,148 +32,146 @@ * - 24.04.2025: Implement Defined States, Errors, Configuration Options ************************************************************************************************** */ -#ifndef KED_PERIPHERALS_GPIO_GPIO_H_ -#define KED_PERIPHERALS_GPIO_GPIO_H_ +#ifndef KED_PERIPHERALS_GPIO_H_ +#define KED_PERIPHERALS_GPIO_H_ -#include +#include -/** - * @brief Enumeration for GPIO functional modes. - */ +/** GPIO Mode Types */ typedef enum { - GPIO_MODE_DEFAULT, - GPIO_MODE_INPUT, - GPIO_MODE_OUTPUT, - GPIO_MODE_ANALOG, - GPIO_MODE_ALTERNATE -} gpio_mode_t; - -/** - * @brief Enumeration for GPIO direction settings. - */ + T_GPIO_MODE_DEFAULT, + T_GPIO_MODE_INPUT, + T_GPIO_MODE_OUTPUT, + T_GPIO_MODE_ANALOG, + T_GPIO_MODE_ALTERNATE +} gpio_function_t; + +/** GPIO Direction (explicit) */ typedef enum { - GPIO_DIRECTION_INPUT, - GPIO_DIRECTION_OUTPUT + T_GPIO_DIRECTION_INPUT, + T_GPIO_DIRECTION_OUTPUT } gpio_direction_t; -/** - * @brief Enumeration for GPIO drive configurations. - */ +/** Drive types for output pins */ typedef enum { - GPIO_DRIVE_DEFAULT, - GPIO_DRIVE_PUSH_PULL, - GPIO_DRIVE_OPEN_DRAIN + T_GPIO_DRIVE_DEFAULT, + T_GPIO_DRIVE_PUSH_PULL, + T_GPIO_DRIVE_OPEN_DRAIN } gpio_drive_t; -/** - * @brief Enumeration for internal bias resistor settings. - */ +/** Pull-up/pull-down configurations */ typedef enum { - GPIO_BIAS_NONE, - GPIO_BIAS_DISABLE, - GPIO_BIAS_PULL_UP, - GPIO_BIAS_PULL_DOWN + T_GPIO_BIAS_DEFAULT, + T_GPIO_BIAS_DISABLE, + T_GPIO_BIAS_PULL_UP, + T_GPIO_BIAS_PULL_DOWN } gpio_bias_t; -/** - * @brief Enumeration for GPIO speed settings. - */ +/** Optional pin speed enumeration */ typedef enum { - GPIO_SPEED_DEFAULT, - GPIO_SPEED_LOW, - GPIO_SPEED_MEDIUM, - GPIO_SPEED_HIGH, - GPIO_SPEED_VERY_HIGH + T_GPIO_SPEED_DEFAULT, + T_GPIO_SPEED_LOW, + T_GPIO_SPEED_MEDIUM, + T_GPIO_SPEED_HIGH, + T_GPIO_SPEED_VERY_HIGH } gpio_speed_t; -/** - * @brief Enumeration for enabling or disabling GPIO interrupts. - */ +/** Enable/disable pin interrupt */ typedef enum { - GPIO_IRQ_DISABLED, - GPIO_IRQ_ENABLED + T_GPIO_IRQ_DISABLED, + T_GPIO_IRQ_ENABLED } gpio_irq_t; -/** - * @brief GPIO error status codes. - */ +/** GPIO Status */ +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 { - GPIO_OK, - GPIO_ERR_UNSUPPORTED_MODE, - GPIO_ERR_LINE_BUSY, - GPIO_ERR_NOT_AVAILABLE, - GPIO_ERR_NO_PULL, - GPIO_ERR_NOT_ANALOG, - GPIO_ERR_UNKNOWN + T_GPIO_ERR_OK, /*!< Suscess flag for the Init Function */ + T_GPIO_ERR_UNSUPPORTED_MODE, /*!< Mode is either not valid orsupported by **Hardwaware** */ + T_GPIO_ERR_UNSUPPORTED_ALTERNATE, /*!< Alternateive mode is unvalid */ + T_GPIO_ERR_BUS_BUSY, /*!< The chosen GPIO BUS is already in Use */ + T_GPIO_ERR_NOT_AVAILABLE, /*!< Pin does Not aloow GPIO functionalities or does not Exists */ + T_GPIO_ERR_NOT_BIASABLE, /*!< No Pull-Up or Pull-Down Option are awailable */ + 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; -/** - * @brief Function pointer type for writing a logic level. - */ -typedef void (*gpio_write_fn)(bool value); - -/** - * @brief Function pointer type for reading a logic level. - */ -typedef bool (*gpio_read_fn)(void); -/** - * @brief Function pointer type for toggling a GPIO pin. - */ -typedef void (*gpio_toggle_fn)(void); +/** GPIO configuration structure for Linux */ +#ifdef KED_USES_LINUX +typedef struct { + const char* chipname; + unsigned int line_offset; + gpio_function_t mode; + gpio_direction_t direction; + gpio_bias_t bias; + gpio_status_t status; +} gpio_t; +#endif +#ifdef __cplusplus +extern "C" { +#endif /** - * @brief Function pointer type for GPIO deinitialization. + * @brief Initialize a GPIO pin. + * @param gpio Pointer to target gpio_t object + * @param config Pointer to configuration structure + * @return gpio_error_t status */ -typedef void (*gpio_deinit_fn)(void); +gpio_error_t ked_gpio_init(const gpio_t* gpio); /** - * @brief Abstract GPIO handle with callback operations. + * @brief Update configuration of an already initialized GPIO. + * + * This function allows changing selected configuration parameters such as direction, + * bias, or other runtime-reconfigurable options without a full re-init. + * + * @param gpio Pointer to initialized gpio object + * @param config Pointer to new configuration structure + * @return gpio_error_t indicating success or failure of update */ -typedef void (*gpio_error_fn)(gpio_error_t); +gpio_error_t ked_gpio_update(gpio_t* gpio); /** - * @brief Abstract GPIO handle with callback operations. + * @brief Deinitialize and release GPIO + * @param gpio Pointer to initialized gpio object */ -typedef struct { - gpio_write_fn set; - gpio_read_fn read; - gpio_toggle_fn toggle; - gpio_deinit_fn deinit; /**< Deinitialization function pointer */ - gpio_error_fn on_error; /**< Error handling callback */ -} gpio_t; +void ked_gpio_deinit(gpio_t* gpio); /** - * @brief Function pointer type for platform-specific GPIO initialization. + * @brief Set GPIO output logic level + * @param gpio Pointer to initialized gpio object + * @param value True for HIGH, false for LOW */ -typedef gpio_error_t (*gpio_init_fn)(gpio_t* gpio, const void* config); +void ked_gpio_set(gpio_t* gpio, uint8_t value); -#ifdef KED_USES_LINUX /** - * @brief Platform-specific GPIO configuration structure for Linux. + * @brief Read the GPIO logic level + * @param gpio Pointer to initialized gpio object + * @return Logic level (true or false) */ -typedef struct { - const char* chipname; - unsigned int line_offset; - gpio_mode_t mode; - gpio_direction_t direction; - gpio_bias_t bias; -} gpio_config; -#endif +uint8_t ked_gpio_read(gpio_t* gpio); /** - * @brief Initialize a GPIO using the specified configuration. - * - * @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 + * @brief Toggle GPIO output state + * @param gpio Pointer to initialized gpio object */ -gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_config* config); +void ked_gpio_toggle(gpio_t* gpio); -/** - * @brief Deinitialize and release resources associated with a GPIO pin. - */ -void ked_gpio_deinit(gpio_t* gpio); +void ked_gpio_handle_error(gpio_error_t err); + +#ifdef __cplusplus +} +#endif #endif /* KED_PERIPHERALS_GPIO_GPIO_H_ */ diff --git a/peripherals/gpio/gpio.c b/peripherals/gpio/gpio.c index 2001873..3e9b0f7 100644 --- a/peripherals/gpio/gpio.c +++ b/peripherals/gpio/gpio.c @@ -1,6 +1,6 @@ /** * @file gpio_linux.c - * @brief GPIO implementation for Linux using libgpiod and KED callback injection. + * @brief GPIO implementation for Linux using libgpiod and internal context management. */ #include "../../ked/peripherals/gpio/gpio.h" @@ -10,48 +10,28 @@ /** * @brief Internal Linux GPIO context. - * - * Holds pointers to the open GPIO chip and the requested line. */ typedef struct { - struct gpiod_chip* chip; /**< File descriptor to the opened GPIO chip */ - struct gpiod_line* line; /**< Reference to the requested GPIO line */ + struct gpiod_chip* chip; + struct gpiod_line* line; } gpio_linux_ctx_t; static gpio_linux_ctx_t gpio_ctx; -/** - * @brief Set the output level of the GPIO line. - * - * @param value Logic level to set (true for HIGH, false for LOW). - */ -static void gpio_linux_set(bool value) { +void ked_gpio_set(gpio_t* gpio, uint8_t value) { gpiod_line_set_value(gpio_ctx.line, value); } -/** - * @brief Read the current logic level of the GPIO line. - * - * @return Logic level (true for HIGH, false for LOW). - */ -static bool gpio_linux_read(void) { - return gpiod_line_get_value(gpio_ctx.line); +uint8_t ked_gpio_read(gpio_t* gpio) { + return (uint8_t)gpiod_line_get_value(gpio_ctx.line); } -/** - * @brief Toggle the current state of the GPIO output. - */ -static void gpio_linux_toggle(void) { - int current = gpiod_line_get_value(gpio_ctx.line); +void ked_gpio_toggle(gpio_t* gpio) { + uint8_t current = (uint8_t)gpiod_line_get_value(gpio_ctx.line); gpiod_line_set_value(gpio_ctx.line, !current); } -/** - * @brief Release the GPIO line and chip. - * - * Called during deinitialization to free resources. - */ -static void gpio_linux_deinit(void) { +void gpio_linux_deinit(gpio_t* gpio) { if (gpio_ctx.line) { gpiod_line_release(gpio_ctx.line); gpio_ctx.line = NULL; @@ -62,78 +42,63 @@ static void gpio_linux_deinit(void) { } } -/** - * @brief Default error handling function. - * - * @param err The GPIO error code to report. - */ -static void gpio_linux_handle_error(gpio_error_t err) { +void ked_gpio_handle_error(gpio_error_t err) { fprintf(stderr, "[GPIO ERROR] Code: %d\n", err); } -/** - * @brief Initialize a GPIO using a Linux-specific gpio_config. - * - * Sets the direction and bias of the line according to the config. - * - * @param gpio Pointer to a gpio_t handle to be configured. - * @param config Pointer to a Linux-specific gpio_config structure. - * @return GPIO_OK on success or an appropriate gpio_error_t on failure. - */ -gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_config* config) { - gpio_ctx.chip = gpiod_chip_open(config->chipname); +gpio_error_t ked_gpio_init(const gpio_t* gpio) { + gpio_ctx.chip = gpiod_chip_open(gpio->chipname); if (!gpio_ctx.chip) { - gpio->on_error(GPIO_ERR_NOT_AVAILABLE); - return GPIO_ERR_NOT_AVAILABLE; + ked_gpio_handle_error(T_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) { gpiod_chip_close(gpio_ctx.chip); - gpio->on_error(GPIO_ERR_NOT_AVAILABLE); - return GPIO_ERR_NOT_AVAILABLE; + ked_gpio_handle_error(T_GPIO_ERR_NOT_AVAILABLE); + return T_GPIO_ERR_NOT_AVAILABLE; } struct gpiod_line_request_config req_cfg = { - .consumer = "ked", - .request_type = (config->direction == GPIO_DIRECTION_OUTPUT) + .consumer = "ked_gpio", + .request_type = (gpio->direction == T_GPIO_DIRECTION_OUTPUT) ? GPIOD_LINE_REQUEST_DIRECTION_OUTPUT : GPIOD_LINE_REQUEST_DIRECTION_INPUT, .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; - } 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; - } else if (config->bias == GPIO_BIAS_DISABLE) { + else if (gpio->bias == T_GPIO_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; - } if (gpiod_line_request(gpio_ctx.line, &req_cfg, 0) < 0) { gpiod_chip_close(gpio_ctx.chip); - gpio->on_error(GPIO_ERR_LINE_BUSY); - return GPIO_ERR_LINE_BUSY; + ked_gpio_handle_error(T_GPIO_ERR_BUS_BUSY); + return T_GPIO_ERR_BUS_BUSY; } - gpio->set = gpio_linux_set; - gpio->read = gpio_linux_read; - gpio->toggle = gpio_linux_toggle; - gpio->deinit = gpio_linux_deinit; - gpio->on_error = gpio_linux_handle_error; - - return GPIO_OK; } -/** - * @brief Generic GPIO deinitialization entry point. - * - * @param gpio Pointer to the gpio_t structure with deinit function populated. - */ +//3812 340 16 4168 1048 ked_executable +//3816 340 16 4172 104c ked_executable +//3692 332 16 4040 fc8 ked_executable + void ked_gpio_deinit(gpio_t* gpio) { - if (gpio && gpio->deinit) { +/* + if (gpio && gpio->deinit) { gpio->deinit(); - } + gpio->status = T_GPIO_STATUS_NOT_INIT; + }*/ } + +gpio_error_t ked_gpio_update(gpio_t* gpio) { + ked_gpio_deinit(gpio); + return ked_gpio_init(gpio); +} +