| 310 | } |
| 311 | |
| 312 | inline int attach_external_handler(u8 pin, const isr_config_t& config, isr_handle_t* out_handle) FL_NOEXCEPT { |
| 313 | if (!config.handler) { |
| 314 | ESP_LOGW(ESP32_IDF4_ISR_TAG, "attachExternalHandler: handler is null"); |
| 315 | return -1; // Invalid parameter |
| 316 | } |
| 317 | |
| 318 | // Allocate handle data |
| 319 | auto handle_owner = fl::make_unique<esp32_idf4_isr_handle_data>(); |
| 320 | auto* handle_data = handle_owner.get(); |
| 321 | if (!handle_data) { |
| 322 | ESP_LOGW(ESP32_IDF4_ISR_TAG, "attachExternalHandler: failed to allocate handle data"); |
| 323 | return -3; // Out of memory |
| 324 | } |
| 325 | |
| 326 | handle_data->is_timer = false; |
| 327 | handle_data->user_handler = config.handler; |
| 328 | handle_data->user_data = config.user_data; |
| 329 | |
| 330 | // Configure GPIO |
| 331 | gpio_config_t io_conf = {}; |
| 332 | io_conf.pin_bit_mask = (1ULL << pin); |
| 333 | io_conf.mode = GPIO_MODE_INPUT; |
| 334 | io_conf.pull_up_en = GPIO_PULLUP_DISABLE; |
| 335 | io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; |
| 336 | |
| 337 | // Set interrupt type based on flags |
| 338 | if (config.flags & isr::ISR_FLAG_EDGE_RISING) { |
| 339 | io_conf.intr_type = GPIO_INTR_POSEDGE; |
| 340 | } else if (config.flags & isr::ISR_FLAG_EDGE_FALLING) { |
| 341 | io_conf.intr_type = GPIO_INTR_NEGEDGE; |
| 342 | } else if (config.flags & isr::ISR_FLAG_LEVEL_HIGH) { |
| 343 | io_conf.intr_type = GPIO_INTR_HIGH_LEVEL; |
| 344 | } else if (config.flags & isr::ISR_FLAG_LEVEL_LOW) { |
| 345 | io_conf.intr_type = GPIO_INTR_LOW_LEVEL; |
| 346 | } else { |
| 347 | // Default to any edge |
| 348 | io_conf.intr_type = GPIO_INTR_ANYEDGE; |
| 349 | } |
| 350 | |
| 351 | esp_err_t ret = gpio_config(&io_conf); |
| 352 | if (ret != ESP_OK) { |
| 353 | ESP_LOGW(ESP32_IDF4_ISR_TAG, "attachExternalHandler: gpio_config failed: %s", esp_err_to_name(ret)); |
| 354 | return -9; // GPIO config failed |
| 355 | } |
| 356 | |
| 357 | // Install GPIO ISR service if not already installed |
| 358 | // Use critical section for multi-core safety |
| 359 | static bool gpio_isr_service_installed = false; |
| 360 | if (!gpio_isr_service_installed) { |
| 361 | taskENTER_CRITICAL(&gpio_isr_service_mutex_idf4); |
| 362 | // Double-check after acquiring lock (classic double-checked locking pattern) |
| 363 | if (!gpio_isr_service_installed) { |
| 364 | ret = gpio_install_isr_service(0); |
| 365 | if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { |
| 366 | taskEXIT_CRITICAL(&gpio_isr_service_mutex_idf4); |
| 367 | ESP_LOGW(ESP32_IDF4_ISR_TAG, "attachExternalHandler: gpio_install_isr_service failed: %s", esp_err_to_name(ret)); |
| 368 | return -10; // ISR service installation failed |
| 369 | } |
nothing calls this directly
no test coverage detected