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.

linux_test
Kynsight 2 months ago
parent a8e5cff8e6
commit dbfd008f1d

@ -36,7 +36,7 @@ Will set GPIO21 pin (HEADER 40) to High
``` ```
Size Size
text data bss dec hex filename text data bss dec hex filename
3836 332 16 4184 1058 ked_executable 3696 332 16 4044 fcc ked_executable
``` ```

@ -21,13 +21,15 @@ void print_usage(const char* prog_name) {
* @brief Entry point for GPIO control CLI. * @brief Entry point for GPIO control CLI.
*/ */
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
uint32_t pin = 0;
uint8_t action = 0xFF; // 0=set, 1=reset, 2=toggle, 3=read
if (argc < 4) { if (argc < 4) {
print_usage(argv[0]); print_usage(argv[0]);
return 1; 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) { 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) {
@ -48,36 +50,35 @@ int main(int argc, char* argv[]) {
return 2; return 2;
} }
gpio_t gpio_conf = { gpio_t led = {
.chipname = "/dev/gpiochip0", .chipname = "/dev/gpiochip0",
.line_offset = pin, .line_offset = pin,
.direction = (action == 3) ? T_GPIO_DIRECTION_INPUT : T_GPIO_DIRECTION_OUTPUT, .direction = (action == 3) ? T_GPIO_DIRECTION_INPUT : T_GPIO_DIRECTION_OUTPUT,
.bias = T_GPIO_BIAS_DEFAULT, .bias = T_GPIO_BIAS_DEFAULT,
.mode = T_GPIO_MODE_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(&led);
gpio_error_t err = ked_gpio_init(&gpio_conf, &led);
if (err != T_GPIO_ERR_OK) { if (err != T_GPIO_ERR_OK) {
if (led.on_error) led.on_error(err); led.func->on_error(err);
return 1; return 1;
} }
switch (action) { switch (action) {
case 0: case 0:
if (led.set) led.set(1); led.func->set(1);
break; break;
case 1: case 1:
if (led.set) led.set(0); led.func->set(0);
break; break;
case 2: case 2:
if (led.toggle) led.toggle(); led.func->toggle();
break; break;
case 3: case 3:
printf("GPIO%u value: %d\n", pin, led.read()); printf("GPIO%u value: %d\n", pin, led.func->read());
break; break;
} }

@ -126,6 +126,7 @@ struct gpio_s {
gpio_direction_t direction; gpio_direction_t direction;
gpio_bias_t bias; gpio_bias_t bias;
gpio_status_t status; gpio_status_t status;
const gpio_fn_ptr_t* func;
}; };
#endif #endif
@ -137,14 +138,14 @@ struct gpio_s {
* @param gpio Pointer to target gpio_t handle * @param gpio Pointer to target gpio_t handle
* @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_fn_ptr_t* callbacks); gpio_error_t ked_gpio_init(gpio_t* gpio);
/** /**
* @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 * @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 === */ /* === Platform-agnostic GPIO control interface === */

@ -86,6 +86,22 @@ static gpio_error_t gpio_linux_update(void) {
return T_GPIO_ERR_UNSUPPORTED_MODE; 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 === */ /* === 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 * @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 * @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); gpio_ctx.chip = gpiod_chip_open(gpio->chipname);
if (!gpio_ctx.chip) { if (!gpio_ctx.chip) {
gpio_linux_handle_error(T_GPIO_ERR_NOT_AVAILABLE); 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; return T_GPIO_ERR_BUS_BUSY;
} }
if (callbacks) { gpio->func = &gpio_linux_fn;
((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;
}
return T_GPIO_ERR_OK; 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 gpio Unused in this implementation
* @param callbacks Pointer to callback table that includes `deinit` * @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) { if (gpio_ctx.line) {
gpiod_line_release(gpio_ctx.line); gpiod_line_release(gpio_ctx.line);
gpio_ctx.line = NULL; gpio_ctx.line = NULL;

Loading…
Cancel
Save