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