ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
pi4ioe5v6408.cpp
Go to the documentation of this file.
1#include "pi4ioe5v6408.h"
2#include "esphome/core/log.h"
3
5
6static const uint8_t PI4IOE5V6408_REGISTER_DEVICE_ID = 0x01;
7static const uint8_t PI4IOE5V6408_REGISTER_IO_DIR = 0x03;
8static const uint8_t PI4IOE5V6408_REGISTER_OUT_SET = 0x05;
9static const uint8_t PI4IOE5V6408_REGISTER_OUT_HIGH_IMPEDENCE = 0x07;
10static const uint8_t PI4IOE5V6408_REGISTER_IN_DEFAULT_STATE = 0x09;
11static const uint8_t PI4IOE5V6408_REGISTER_PULL_ENABLE = 0x0B;
12static const uint8_t PI4IOE5V6408_REGISTER_PULL_SELECT = 0x0D;
13static const uint8_t PI4IOE5V6408_REGISTER_IN_STATE = 0x0F;
14static const uint8_t PI4IOE5V6408_REGISTER_INTERRUPT_ENABLE_MASK = 0x11;
15static const uint8_t PI4IOE5V6408_REGISTER_INTERRUPT_STATUS = 0x13;
16
17static const char *const TAG = "pi4ioe5v6408";
18
20 if (this->reset_) {
21 this->reg(PI4IOE5V6408_REGISTER_DEVICE_ID) |= 0b00000001;
22 this->reg(PI4IOE5V6408_REGISTER_OUT_HIGH_IMPEDENCE) = 0b00000000;
23 } else {
24 if (!this->read_gpio_modes_()) {
25 this->mark_failed();
26 ESP_LOGE(TAG, "Failed to read GPIO modes");
27 return;
28 }
29 if (!this->read_gpio_outputs_()) {
30 this->mark_failed();
31 ESP_LOGE(TAG, "Failed to read GPIO outputs");
32 return;
33 }
34 }
35
36 // No need to clear latched interrupts before attaching the ISR — if INT is
37 // already low the ISR fires immediately, loop runs, cache invalidates, and
38 // the read clears the latch. One harmless extra read at most.
39 if (this->interrupt_pin_ != nullptr) {
40 this->interrupt_pin_->setup();
42 this->set_invalidate_on_read_(false);
43 }
44 // Disable loop until an input pin is configured via pin_mode()
45 // For interrupt-driven mode, loop is re-enabled by the ISR
46 // For polling mode, loop is re-enabled when pin_mode() registers an input pin
47 this->disable_loop();
48}
51 ESP_LOGCONFIG(TAG, "PI4IOE5V6408:");
52 LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
53 LOG_I2C_DEVICE(this)
54 if (this->is_failed()) {
55 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
56 }
57}
60 // Set mode mask bit
61 this->mode_mask_ |= 1 << pin;
62 } else if (flags & gpio::FLAG_INPUT) {
63 // Clear mode mask bit
64 this->mode_mask_ &= ~(1 << pin);
66 this->pull_up_down_mask_ |= 1 << pin;
67 this->pull_enable_mask_ |= 1 << pin;
68 } else if (flags & gpio::FLAG_PULLDOWN) {
69 this->pull_up_down_mask_ &= ~(1 << pin);
70 this->pull_enable_mask_ |= 1 << pin;
71 }
72 // Enable polling loop for input pins (not needed for interrupt-driven mode
73 // where the ISR handles re-enabling loop)
74 if (this->interrupt_pin_ == nullptr) {
75 this->enable_loop();
76 }
77 }
78 // Write GPIO to enable input mode
79 this->write_gpio_modes_();
80}
81
83 this->reset_pin_cache_();
84 // Only disable the loop once INT has actually gone HIGH. Input transitions that straddle the
85 // I2C read leave INT asserted without re-firing a falling edge, which would strand us with
86 // stale state forever; keep looping until the line is released so we self-heal.
87 if (this->interrupt_pin_ != nullptr && this->interrupt_pin_->digital_read()) {
88 this->disable_loop();
89 }
90}
91
93 if (this->is_failed())
94 return false;
95
96 uint8_t data;
97 if (!this->read_byte(PI4IOE5V6408_REGISTER_OUT_SET, &data)) {
98 this->status_set_warning(LOG_STR("Failed to read output register"));
99 return false;
100 }
101 this->output_mask_ = data;
102 this->status_clear_warning();
103 return true;
104}
105
107 if (this->is_failed())
108 return false;
109
110 uint8_t data;
111 if (!this->read_byte(PI4IOE5V6408_REGISTER_IO_DIR, &data)) {
112 this->status_set_warning(LOG_STR("Failed to read GPIO modes"));
113 return false;
114 }
115#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
116 ESP_LOGV(TAG, "Read GPIO modes: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(data));
117#endif
118 this->mode_mask_ = data;
119 this->status_clear_warning();
120 return true;
121}
122
124 if (this->is_failed())
125 return false;
126
127 uint8_t data;
128 if (!this->read_byte(PI4IOE5V6408_REGISTER_IN_STATE, &data)) {
129 this->status_set_warning(LOG_STR("Failed to read GPIO state"));
130 return false;
131 }
132 this->input_mask_ = data;
133 this->status_clear_warning();
134 return true;
135}
136
137void PI4IOE5V6408Component::digital_write_hw(uint8_t pin, bool value) {
138 if (this->is_failed())
139 return;
140
141 if (value) {
142 this->output_mask_ |= (1 << pin);
143 } else {
144 this->output_mask_ &= ~(1 << pin);
145 }
146 if (!this->write_byte(PI4IOE5V6408_REGISTER_OUT_SET, this->output_mask_)) {
147 this->status_set_warning(LOG_STR("Failed to write output register"));
148 return;
149 }
150#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
151 ESP_LOGV(TAG, "Wrote GPIO output: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(this->output_mask_));
152#endif
153 this->status_clear_warning();
154}
155
157 if (this->is_failed())
158 return false;
159
160 if (!this->write_byte(PI4IOE5V6408_REGISTER_IO_DIR, this->mode_mask_)) {
161 this->status_set_warning(LOG_STR("Failed to write GPIO modes"));
162 return false;
163 }
164 if (!this->write_byte(PI4IOE5V6408_REGISTER_PULL_SELECT, this->pull_up_down_mask_)) {
165 this->status_set_warning(LOG_STR("Failed to write GPIO pullup/pulldown"));
166 return false;
167 }
168 if (!this->write_byte(PI4IOE5V6408_REGISTER_PULL_ENABLE, this->pull_enable_mask_)) {
169 this->status_set_warning(LOG_STR("Failed to write GPIO pull enable"));
170 return false;
171 }
172 // Enable interrupts for input pins when interrupt pin is configured
173 // (input pins have mode_mask_ bit cleared)
174 if (this->interrupt_pin_ != nullptr &&
175 !this->write_byte(PI4IOE5V6408_REGISTER_INTERRUPT_ENABLE_MASK, static_cast<uint8_t>(~this->mode_mask_))) {
176 this->status_set_warning(LOG_STR("Failed to write interrupt enable mask"));
177 return false;
178 }
179#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
180 ESP_LOGV(TAG,
181 "Wrote GPIO config:\n"
182 " modes: 0b" BYTE_TO_BINARY_PATTERN "\n"
183 " pullup/pulldown: 0b" BYTE_TO_BINARY_PATTERN "\n"
184 " pull enable: 0b" BYTE_TO_BINARY_PATTERN,
185 BYTE_TO_BINARY(this->mode_mask_), BYTE_TO_BINARY(this->pull_up_down_mask_),
186 BYTE_TO_BINARY(this->pull_enable_mask_));
187#endif
188 this->status_clear_warning();
189 return true;
190}
191
192bool PI4IOE5V6408Component::digital_read_cache(uint8_t pin) { return (this->input_mask_ & (1 << pin)); }
193
195
197void PI4IOE5V6408GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
198bool PI4IOE5V6408GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
200 this->parent_->digital_write(this->pin_, value != this->inverted_);
201}
202size_t PI4IOE5V6408GPIOPin::dump_summary(char *buffer, size_t len) const {
203 return buf_append_printf(buffer, len, 0, "%u via PI4IOE5V6408", this->pin_);
204}
205
206} // namespace esphome::pi4ioe5v6408
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:272
void enable_loop_soon_any_context()
Thread and ISR-safe version of enable_loop() that can be called from any context.
void enable_loop()
Enable this component's loop.
Definition component.h:246
void disable_loop()
Disable this component's loop.
void status_clear_warning()
Definition component.h:289
virtual void setup()=0
virtual bool digital_read()=0
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
Definition gpio.h:107
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:265
bool read_byte(uint8_t a_register, uint8_t *data)
Definition i2c.h:240
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:152
static void IRAM_ATTR gpio_intr(PI4IOE5V6408Component *arg)
uint8_t pull_enable_mask_
The mask to write as input buffer state - 1 means enabled, 0 means disabled.
uint8_t output_mask_
The mask to write as output state - 1 means HIGH, 0 means LOW.
uint8_t pull_up_down_mask_
The mask to write as pullup state - 1 means pullup, 0 means pulldown.
bool digital_read_cache(uint8_t pin) override
void digital_write_hw(uint8_t pin, bool value) override
uint8_t input_mask_
The state read in digital_read_hw - 1 means HIGH, 0 means LOW.
uint8_t mode_mask_
Mask for the pin mode - 1 means output, 0 means input.
void pin_mode(uint8_t pin, gpio::Flags flags)
void pin_mode(gpio::Flags flags) override
size_t dump_summary(char *buffer, size_t len) const override
uint16_t flags
@ INTERRUPT_FALLING_EDGE
Definition gpio.h:51
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_PULLUP
Definition gpio.h:30
@ FLAG_INPUT
Definition gpio.h:27
@ FLAG_PULLDOWN
Definition gpio.h:31
constexpr float IO
For components that represent GPIO pins like PCF8573.
Definition component.h:39
const void size_t len
Definition hal.h:64