Implement GPIO interrupts

This commit is contained in:
Ken Van Hoeylandt 2026-02-18 21:38:34 +01:00
parent d2048e01b6
commit ec0c5ae496
3 changed files with 145 additions and 4 deletions

View File

@ -12,7 +12,12 @@
#define TAG "esp32_gpio"
struct Esp32GpioInternal {
uint8_t isr_service_ref_count = 0;
};
#define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config)
#define GET_INTERNAL(device) ((struct Esp32GpioInternal*)device->internal)
extern "C" {
@ -97,15 +102,59 @@ static error_t get_native_pin_number(GpioDescriptor* descriptor, void* pin_numbe
return ERROR_NONE;
}
static error_t add_callback(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg) {
auto esp_error = gpio_isr_handler_add(static_cast<gpio_num_t>(descriptor->pin), callback, arg);
return esp_err_to_error(esp_error);
}
static error_t remove_callback(struct GpioDescriptor* descriptor) {
auto esp_error = gpio_isr_handler_remove(static_cast<gpio_num_t>(descriptor->pin));
return esp_err_to_error(esp_error);
}
static error_t enable_interrupt(struct GpioDescriptor* descriptor) {
auto* internal = GET_INTERNAL(descriptor->controller);
if (internal->isr_service_ref_count == 0) {
auto esp_error = gpio_install_isr_service(0);
if (esp_error != ESP_OK && esp_error != ESP_ERR_INVALID_STATE) {
return esp_err_to_error(esp_error);
}
}
auto esp_error = gpio_intr_enable(static_cast<gpio_num_t>(descriptor->pin));
if (esp_error == ESP_OK) {
internal->isr_service_ref_count++;
}
return esp_err_to_error(esp_error);
}
static error_t disable_interrupt(struct GpioDescriptor* descriptor) {
auto* internal = GET_INTERNAL(descriptor->controller);
auto esp_error = gpio_intr_disable(static_cast<gpio_num_t>(descriptor->pin));
if (esp_error == ESP_OK && internal->isr_service_ref_count > 0) {
internal->isr_service_ref_count--;
if (internal->isr_service_ref_count == 0) {
gpio_uninstall_isr_service();
}
}
return esp_err_to_error(esp_error);
}
static error_t start(Device* device) {
ESP_LOGI(TAG, "start %s", device->name);
auto pin_count = GET_CONFIG(device)->gpioCount;
return gpio_controller_init_descriptors(device, pin_count, nullptr);
const Esp32GpioConfig* config = GET_CONFIG(device);
device_set_driver_data(device, new Esp32GpioInternal());
return gpio_controller_init_descriptors(device, config->gpioCount, nullptr);
}
static error_t stop(Device* device) {
ESP_LOGI(TAG, "stop %s", device->name);
return gpio_controller_deinit_descriptors(device);
auto* internal = GET_INTERNAL(device);
if (internal->isr_service_ref_count > 0) {
gpio_uninstall_isr_service();
}
check(gpio_controller_deinit_descriptors(device) == ERROR_NONE);
delete internal;
return ERROR_NONE;
}
const static GpioControllerApi esp32_gpio_api = {
@ -113,7 +162,11 @@ const static GpioControllerApi esp32_gpio_api = {
.get_level = get_level,
.set_flags = set_flags,
.get_flags = get_flags,
.get_native_pin_number = get_native_pin_number
.get_native_pin_number = get_native_pin_number,
.add_callback = add_callback,
.remove_callback = remove_callback,
.enable_interrupt = enable_interrupt,
.disable_interrupt = disable_interrupt
};
extern struct Module platform_esp32_module;

View File

@ -52,6 +52,36 @@ struct GpioControllerApi {
* @return ERROR_NONE if successful
*/
error_t (*get_native_pin_number)(struct GpioDescriptor* descriptor, void* pin_number);
/**
* @brief Adds a callback to be called when a GPIO interrupt occurs.
* @param[in] descriptor the pin descriptor
* @param[in] callback the callback function
* @param[in] arg the argument to pass to the callback
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t (*add_callback)(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg);
/**
* @brief Removes a callback from a GPIO interrupt.
* @param[in] descriptor the pin descriptor
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t (*remove_callback)(struct GpioDescriptor* descriptor);
/**
* @brief Enables the interrupt for a GPIO pin.
* @param[in] descriptor the pin descriptor
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t (*enable_interrupt)(struct GpioDescriptor* descriptor);
/**
* @brief Disables the interrupt for a GPIO pin.
* @param[in] descriptor the pin descriptor
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t (*disable_interrupt)(struct GpioDescriptor* descriptor);
};
struct GpioDescriptor* gpio_descriptor_acquire(
@ -118,6 +148,36 @@ error_t gpio_descriptor_get_flags(struct GpioDescriptor* descriptor, gpio_flags_
*/
error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor, void* pin_number);
/**
* @brief Adds a callback to be called when a GPIO interrupt occurs.
* @param[in] descriptor the pin descriptor
* @param[in] callback the callback function
* @param[in] arg the argument to pass to the callback
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t gpio_descriptor_add_callback(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg);
/**
* @brief Removes a callback from a GPIO interrupt.
* @param[in] descriptor the pin descriptor
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t gpio_descriptor_remove_callback(struct GpioDescriptor* descriptor);
/**
* @brief Enables the interrupt for a GPIO pin.
* @param[in] descriptor the pin descriptor
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t gpio_descriptor_enable_interrupt(struct GpioDescriptor* descriptor);
/**
* @brief Disables the interrupt for a GPIO pin.
* @param[in] descriptor the pin descriptor
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
*/
error_t gpio_descriptor_disable_interrupt(struct GpioDescriptor* descriptor);
/**
* @brief Gets the number of pins supported by the controller.
* @param[in] device the GPIO controller device

View File

@ -130,6 +130,34 @@ error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor,
return GPIO_INTERNAL_API(driver)->get_native_pin_number(descriptor, pin_number);
}
error_t gpio_descriptor_add_callback(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg) {
const auto* driver = device_get_driver(descriptor->controller);
auto* api = GPIO_INTERNAL_API(driver);
if (!api->add_callback) return ERROR_NOT_SUPPORTED;
return api->add_callback(descriptor, callback, arg);
}
error_t gpio_descriptor_remove_callback(struct GpioDescriptor* descriptor) {
const auto* driver = device_get_driver(descriptor->controller);
auto* api = GPIO_INTERNAL_API(driver);
if (!api->remove_callback) return ERROR_NOT_SUPPORTED;
return api->remove_callback(descriptor);
}
error_t gpio_descriptor_enable_interrupt(struct GpioDescriptor* descriptor) {
const auto* driver = device_get_driver(descriptor->controller);
auto* api = GPIO_INTERNAL_API(driver);
if (!api->enable_interrupt) return ERROR_NOT_SUPPORTED;
return api->enable_interrupt(descriptor);
}
error_t gpio_descriptor_disable_interrupt(struct GpioDescriptor* descriptor) {
const auto* driver = device_get_driver(descriptor->controller);
auto* api = GPIO_INTERNAL_API(driver);
if (!api->disable_interrupt) return ERROR_NOT_SUPPORTED;
return api->disable_interrupt(descriptor);
}
error_t gpio_descriptor_get_owner_type(struct GpioDescriptor* descriptor, GpioOwnerType* owner_type) {
*owner_type = descriptor->owner_type;
return ERROR_NONE;