From 8a6ea593dbd2751f9e3212714d5b2e11a9df455d Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:34:45 +0100 Subject: [PATCH] Update tca6408.h --- components/TCA6408/tca6408.h | 94 +++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/components/TCA6408/tca6408.h b/components/TCA6408/tca6408.h index 875c7d4..565a916 100644 --- a/components/TCA6408/tca6408.h +++ b/components/TCA6408/tca6408.h @@ -1,51 +1,65 @@ -#include "tca6408.h" -#include "esphome/core/log.h" +#pragma once + +#include "esphome/components/gpio_expander/cached_gpio.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" namespace esphome { namespace tca6408 { -static const char *const TAG = "tca6408"; +class TCA6408Component : public Component, + public i2c::I2CDevice, + public gpio_expander::CachedGpioExpander { + public: + void setup() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::IO; } -static const uint8_t TCA6408_INPUT_PORT = 0x00; -static const uint8_t TCA6408_OUTPUT_PORT = 0x01; -static const uint8_t TCA6408_POLARITY_PORT = 0x02; -static const uint8_t TCA6408_CONFIG_PORT = 0x03; + void set_address(uint8_t address) { this->address_ = address; } + void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } -void TCA6408Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up TCA6408..."); + void set_polarity_inversion(uint8_t pin, bool inverted); - // Initialize all registers - if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK || - this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK || - !this->read_gpio_outputs_()) { - this->mark_failed(); - return; - } + protected: + static void IRAM_ATTR gpio_intr(TCA6408Component *arg); - if (this->interrupt_pin_ != nullptr) { - this->interrupt_pin_->setup(); - this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); - this->set_invalidate_on_read_(false); - ESP_LOGCONFIG(TAG, " Interrupt mode enabled (active-low)"); - } else { - this->enable_loop(); - ESP_LOGCONFIG(TAG, " Polling mode enabled"); - } -} + bool digital_read_hw(uint8_t pin) override; + bool digital_read_cache(uint8_t pin) override; + void digital_write_hw(uint8_t pin, bool value) override; + void pin_mode(uint8_t pin, gpio::Flags flags) override; -// ... (gpio_intr, loop, dump_config stay the same) + uint8_t mode_mask_{0xFF}; // 1 = input, 0 = output + uint8_t output_mask_{0x00}; + uint8_t input_mask_{0x00}; + uint8_t polarity_mask_{0x00}; // 1 = inverted (for inputs) -bool TCA6408Component::read_gpio_outputs_() { - if (this->is_failed()) return false; - uint8_t data; - if (this->read_register(TCA6408_OUTPUT_PORT, &data) != i2c::ERROR_OK) { - this->status_set_warning(); - return false; - } - this->output_mask_ = data; - this->status_clear_warning(); - return true; -} + InternalGPIOPin *interrupt_pin_{nullptr}; + bool interrupt_triggered_{false}; -// Rest of the file remains the same as you have it... + private: + bool read_gpio_outputs_(); +}; + +class TCA6408GPIOPin : public gpio::GPIOPin, public Parented { + public: + void setup() override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + size_t dump_summary(char *buffer, size_t len) const override; + + void set_pin(uint8_t pin) { pin_ = pin; } + void set_inverted(bool inverted); + void set_flags(gpio::Flags flags) { flags_ = flags; } + gpio::Flags get_flags() const override { return flags_; } + + protected: + uint8_t pin_{0}; + bool inverted_{false}; + gpio::Flags flags_{0}; +}; + +} // namespace tca6408 +} // namespace esphome