#ifdef USE_ESP32_FRAMEWORK_ESP_IDF #include "gpio_idf.h" #include "esphome/core/log.h" namespace esphome { namespace esp32 { static const char *const TAG = "esp32"; bool IDFInternalGPIOPin::isr_service_installed = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) struct ISRPinArg { gpio_num_t pin; bool inverted; }; ISRInternalGPIOPin IDFInternalGPIOPin::to_isr() const { auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory) arg->pin = pin_; arg->inverted = inverted_; return ISRInternalGPIOPin((void *) arg); } void IDFInternalGPIOPin::setup() { pin_mode(flags_); gpio_set_drive_capability(pin_, drive_strength_); } void IDFInternalGPIOPin::pin_mode(gpio::Flags flags) { gpio_config_t conf{}; conf.pin_bit_mask = 1ULL << static_cast(pin_); conf.mode = flags_to_mode(flags); conf.pull_up_en = flags & gpio::FLAG_PULLUP ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; conf.pull_down_en = flags & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; conf.intr_type = GPIO_INTR_DISABLE; gpio_config(&conf); } bool IDFInternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; } void IDFInternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); } gpio_mode_t IDFInternalGPIOPin::flags_to_mode(gpio::Flags flags) { flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)); if (flags == gpio::FLAG_NONE) { return GPIO_MODE_DISABLE; } else if (flags == gpio::FLAG_INPUT) { return GPIO_MODE_INPUT; } else if (flags == gpio::FLAG_OUTPUT) { return GPIO_MODE_OUTPUT; } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { return GPIO_MODE_OUTPUT_OD; } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { return GPIO_MODE_INPUT_OUTPUT_OD; } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT)) { return GPIO_MODE_INPUT_OUTPUT; } else { // unsupported return GPIO_MODE_DISABLE; } } void IDFInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const { gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE; switch (type) { case gpio::INTERRUPT_RISING_EDGE: idf_type = inverted_ ? GPIO_INTR_NEGEDGE : GPIO_INTR_POSEDGE; break; case gpio::INTERRUPT_FALLING_EDGE: idf_type = inverted_ ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE; break; case gpio::INTERRUPT_ANY_EDGE: idf_type = GPIO_INTR_ANYEDGE; break; case gpio::INTERRUPT_LOW_LEVEL: idf_type = inverted_ ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL; break; case gpio::INTERRUPT_HIGH_LEVEL: idf_type = inverted_ ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL; break; } gpio_set_intr_type(pin_, idf_type); gpio_intr_enable(pin_); if (!isr_service_installed) { auto res = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); if (res != ESP_OK) { ESP_LOGE(TAG, "attach_interrupt(): call to gpio_install_isr_service() failed, error code: %d", res); return; } isr_service_installed = true; } gpio_isr_handler_add(pin_, func, arg); } std::string IDFInternalGPIOPin::dump_summary() const { char buffer[32]; snprintf(buffer, sizeof(buffer), "GPIO%u", static_cast(pin_)); return buffer; } } // namespace esp32 using namespace esp32; bool IRAM_ATTR ISRInternalGPIOPin::digital_read() { auto *arg = reinterpret_cast(arg_); return bool(gpio_get_level(arg->pin)) != arg->inverted; } void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) { auto *arg = reinterpret_cast(arg_); gpio_set_level(arg->pin, value != arg->inverted ? 1 : 0); } void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { // not supported } } // namespace esphome #endif // USE_ESP32_FRAMEWORK_ESP_IDF