From dbfd008f1dba89ac3bed7211f88545ecd0039b5f Mon Sep 17 00:00:00 2001 From: kerem Date: Sat, 26 Apr 2025 12:16:21 +0200 Subject: [PATCH] Still identical to the one wihtout pointers, but this version is optimised to use a const pointers. So that when we generate more than one pin they all use the same pointer registers without recreating them. --- README.md | 2 +- examples/pin_control.c | 29 +++++++++++++++-------------- ked/peripherals/gpio/gpio.h | 5 +++-- peripherals/gpio/gpio.c | 28 +++++++++++++++++++--------- 4 files changed, 38 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 8ada57f..cad03c1 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Will set GPIO21 pin (HEADER 40) to High ``` Size text data bss dec hex filename -3836 332 16 4184 1058 ked_executable +3696 332 16 4044 fcc ked_executable ``` diff --git a/examples/pin_control.c b/examples/pin_control.c index 813f00f..9fee0d8 100644 --- a/examples/pin_control.c +++ b/examples/pin_control.c @@ -21,13 +21,15 @@ void print_usage(const char* prog_name) { * @brief Entry point for GPIO control CLI. */ int main(int argc, char* argv[]) { - if (argc < 4) { + + uint32_t pin = 0; + uint8_t action = 0xFF; // 0=set, 1=reset, 2=toggle, 3=read + + if (argc < 4) { print_usage(argv[0]); return 1; } - uint32_t pin = 0; - uint8_t action = 0xFF; // 0=set, 1=reset, 2=toggle, 3=read for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-pin") == 0 && i + 1 < argc) { @@ -47,37 +49,36 @@ int main(int argc, char* argv[]) { print_usage(argv[0]); return 2; } - - gpio_t gpio_conf = { + + gpio_t led = { .chipname = "/dev/gpiochip0", .line_offset = pin, .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 + .status = T_GPIO_STATUS_NOT_INIT, + .func = NULL }; - gpio_fn_ptr_t led = {0}; - - gpio_error_t err = ked_gpio_init(&gpio_conf, &led); + gpio_error_t err = ked_gpio_init(&led); if (err != T_GPIO_ERR_OK) { - if (led.on_error) led.on_error(err); + led.func->on_error(err); return 1; } switch (action) { case 0: - if (led.set) led.set(1); + led.func->set(1); break; case 1: - if (led.set) led.set(0); + led.func->set(0); break; case 2: - if (led.toggle) led.toggle(); + led.func->toggle(); break; case 3: - printf("GPIO%u value: %d\n", pin, led.read()); + printf("GPIO%u value: %d\n", pin, led.func->read()); break; } diff --git a/ked/peripherals/gpio/gpio.h b/ked/peripherals/gpio/gpio.h index c84bc56..9747932 100644 --- a/ked/peripherals/gpio/gpio.h +++ b/ked/peripherals/gpio/gpio.h @@ -126,6 +126,7 @@ struct gpio_s { gpio_direction_t direction; gpio_bias_t bias; gpio_status_t status; + const gpio_fn_ptr_t* func; }; #endif @@ -137,14 +138,14 @@ struct gpio_s { * @param gpio Pointer to target gpio_t handle * @return GPIO_OK on success, or an appropriate gpio_error_t */ -gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_fn_ptr_t* callbacks); +gpio_error_t ked_gpio_init(gpio_t* gpio); /** * @brief Deinitialize and release resources associated with a GPIO pin. * * @param gpio Pointer to GPIO object */ -void ked_gpio_deinit(gpio_t* gpio, const gpio_fn_ptr_t* callbacks); +void ked_gpio_deinit(gpio_t* gpio); /* === Platform-agnostic GPIO control interface === */ diff --git a/peripherals/gpio/gpio.c b/peripherals/gpio/gpio.c index f4306fa..030b767 100644 --- a/peripherals/gpio/gpio.c +++ b/peripherals/gpio/gpio.c @@ -86,6 +86,22 @@ static gpio_error_t gpio_linux_update(void) { return T_GPIO_ERR_UNSUPPORTED_MODE; } +/* === Static GPIO Function Table Instance === */ + +/** + * @brief Shared Linux GPIO function table for all gpio_t instances. + * + * Each GPIO object holds a pointer to this table via its `vtable` field. + * This avoids redundant copies of function pointers per object. + */ +static const gpio_fn_ptr_t gpio_linux_fn = { + .set = gpio_linux_set, + .read = gpio_linux_read, + .toggle = gpio_linux_toggle, + .update = gpio_linux_update, + .on_error = gpio_linux_handle_error +}; + /* === Public API Implementation === */ /** @@ -97,7 +113,7 @@ static gpio_error_t gpio_linux_update(void) { * @param callbacks Optional pointer to gpio_fn_ptr_t to receive platform-specific handlers * @return T_GPIO_ERR_OK on success, or appropriate error code */ -gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_fn_ptr_t* callbacks) { +gpio_error_t ked_gpio_init(gpio_t* gpio) { gpio_ctx.chip = gpiod_chip_open(gpio->chipname); if (!gpio_ctx.chip) { gpio_linux_handle_error(T_GPIO_ERR_NOT_AVAILABLE); @@ -134,13 +150,7 @@ gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_fn_ptr_t* callbacks) { return T_GPIO_ERR_BUS_BUSY; } - if (callbacks) { - ((gpio_fn_ptr_t*)callbacks)->set = gpio_linux_set; - ((gpio_fn_ptr_t*)callbacks)->read = gpio_linux_read; - ((gpio_fn_ptr_t*)callbacks)->toggle = gpio_linux_toggle; - ((gpio_fn_ptr_t*)callbacks)->update = gpio_linux_update; - ((gpio_fn_ptr_t*)callbacks)->on_error = gpio_linux_handle_error; - } + gpio->func = &gpio_linux_fn; return T_GPIO_ERR_OK; } @@ -151,7 +161,7 @@ gpio_error_t ked_gpio_init(gpio_t* gpio, const gpio_fn_ptr_t* callbacks) { * @param gpio Unused in this implementation * @param callbacks Pointer to callback table that includes `deinit` */ -void ked_gpio_deinit(gpio_t* gpio, const gpio_fn_ptr_t* callbacks) { +void ked_gpio_deinit(gpio_t* gpio) { if (gpio_ctx.line) { gpiod_line_release(gpio_ctx.line); gpio_ctx.line = NULL;