ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
pca6416a.cpp
Go to the documentation of this file.
1#include "pca6416a.h"
3#include "esphome/core/log.h"
4
6
23
24ESPHOME_LOG_TAG(TAG, "pca6416a");
25
27 // Test to see if device exists
28 uint8_t value;
29 if (!this->read_register_(PCA6416A_INPUT0, &value)) {
30 ESP_LOGE(TAG, "PCA6416A not available under 0x%02X", this->address_);
31 this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
32 return;
33 }
34
35 // Test to see if the device supports pull-up resistors
36 if (this->read_register(PCAL6416A_PULL_EN0, &value, 1) == i2c::ERROR_OK) {
37 this->has_pullup_ = true;
38 }
39
40 // No polarity inversion
43 // Set all pins to input
46 // Read current output register state
49
50 ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(),
51 this->status_has_error());
52
54}
55
57 if (this->has_pullup_) {
58 ESP_LOGCONFIG(TAG, "PCAL6416A:");
59 } else {
60 ESP_LOGCONFIG(TAG, "PCA6416A:");
61 }
62 LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
63 LOG_I2C_DEVICE(this)
64}
65
67 uint8_t reg_addr = pin < 8 ? PCA6416A_INPUT0 : PCA6416A_INPUT1;
68 uint8_t value = 0;
69 if (!this->read_register_(reg_addr, &value)) {
70 return false;
71 }
72
73 // Update the appropriate part of input_mask_
74 if (pin < 8) {
75 this->input_mask_ = (this->input_mask_ & 0xFF00) | value;
76 } else {
77 this->input_mask_ = (this->input_mask_ & 0x00FF) | (uint16_t(value) << 8);
78 }
79 return true;
80}
81
82bool PCA6416AComponent::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); }
83
84void PCA6416AComponent::digital_write_hw(uint8_t pin, bool value) {
85 uint8_t reg_addr = pin < 8 ? PCA6416A_OUTPUT0 : PCA6416A_OUTPUT1;
86 this->update_register_(pin, value, reg_addr);
87}
88
90 uint8_t io_dir = pin < 8 ? PCA6416A_CONFIG0 : PCA6416A_CONFIG1;
91 uint8_t pull_en = pin < 8 ? PCAL6416A_PULL_EN0 : PCAL6416A_PULL_EN1;
92 uint8_t pull_dir = pin < 8 ? PCAL6416A_PULL_DIR0 : PCAL6416A_PULL_DIR1;
93 if (flags == gpio::FLAG_INPUT) {
94 this->update_register_(pin, true, io_dir);
95 if (has_pullup_) {
96 this->update_register_(pin, true, pull_dir);
97 this->update_register_(pin, false, pull_en);
98 }
99 } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
100 this->update_register_(pin, true, io_dir);
101 if (has_pullup_) {
102 this->update_register_(pin, true, pull_dir);
103 this->update_register_(pin, true, pull_en);
104 } else {
105 ESP_LOGW(TAG, "Your PCA6416A does not support pull-up resistors");
106 }
107 } else if (flags == gpio::FLAG_OUTPUT) {
108 this->update_register_(pin, false, io_dir);
109 }
111 this->enable_polling_loop_();
112}
113
114bool PCA6416AComponent::read_register_(uint8_t reg, uint8_t *value) {
115 if (this->is_failed()) {
116 ESP_LOGD(TAG, "Device marked failed");
117 return false;
118 }
119
120 this->last_error_ = this->read_register(reg, value, 1);
121 if (!this->status_comm_result(this->last_error_ == i2c::ERROR_OK)) {
122 ESP_LOGE(TAG, "read_register_(): I2C I/O error: %d", (int) this->last_error_);
123 return false;
124 }
125 return true;
126}
127
128bool PCA6416AComponent::write_register_(uint8_t reg, uint8_t value) {
129 if (this->is_failed()) {
130 ESP_LOGD(TAG, "Device marked failed");
131 return false;
132 }
133
134 this->last_error_ = this->write_register(reg, &value, 1);
135 if (!this->status_comm_result(this->last_error_ == i2c::ERROR_OK)) {
136 ESP_LOGE(TAG, "write_register_(): I2C I/O error: %d", (int) this->last_error_);
137 return false;
138 }
139 return true;
140}
141
142void PCA6416AComponent::update_register_(uint8_t pin, bool pin_value, uint8_t reg_addr) {
143 uint8_t bit = pin % 8;
144 uint8_t reg_value = 0;
145 if (reg_addr == PCA6416A_OUTPUT0) {
146 reg_value = this->output_0_;
147 } else if (reg_addr == PCA6416A_OUTPUT1) {
148 reg_value = this->output_1_;
149 } else {
150 this->read_register_(reg_addr, &reg_value);
151 }
152
153 assign_bits(reg_value, 1 << bit, pin_value);
154
155 this->write_register_(reg_addr, reg_value);
156
157 if (reg_addr == PCA6416A_OUTPUT0) {
158 this->output_0_ = reg_value;
159 } else if (reg_addr == PCA6416A_OUTPUT1) {
160 this->output_1_ = reg_value;
161 }
162}
163
164} // namespace esphome::pca6416a
165
166ESPHOME_EXPANDER_PIN_SUMMARY(esphome::pca6416a::PCA6416AComponent, "%u via PCA6416A")
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:274
bool status_comm_result(bool ok)
Clears the warning when ok, else sets it with message (default "Communication failed"); returns ok.
bool status_has_warning() const
Definition component.h:280
bool status_has_error() const
Definition component.h:282
void enable_polling_loop_()
Call from pin_mode() for an input pin: without an interrupt pin the loop polls instead.
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len) const
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:37
uint8_t address_
store the address of the device on the bus
Definition i2c.h:327
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:28
void digital_write_hw(uint8_t pin, bool value) override
Definition pca6416a.cpp:84
bool write_register_(uint8_t reg, uint8_t value)
Definition pca6416a.cpp:128
bool read_register_(uint8_t reg, uint8_t *value)
Definition pca6416a.cpp:114
esphome::i2c::ErrorCode last_error_
Storage for last I2C error seen.
Definition pca6416a.h:38
void update_register_(uint8_t pin, bool pin_value, uint8_t reg_addr)
Definition pca6416a.cpp:142
uint16_t input_mask_
Cache for input values (16-bit combined for both banks)
Definition pca6416a.h:36
bool has_pullup_
Only the PCAL6416A has pull-up resistors.
Definition pca6416a.h:40
void pin_mode(uint8_t pin, gpio::Flags flags)
Helper function to set the pin mode of a pin.
Definition pca6416a.cpp:89
void setup() override
Check i2c availability and setup masks.
Definition pca6416a.cpp:26
bool digital_read_hw(uint8_t pin) override
Definition pca6416a.cpp:66
bool digital_read_cache(uint8_t pin) override
Definition pca6416a.cpp:82
uint8_t output_0_
The mask to write as output state - 1 means HIGH, 0 means LOW.
Definition pca6416a.h:33
uint16_t flags
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:15
ESPHOME_LOG_TAG(TAG, "pca6416a")
ESPHOME_ALWAYS_INLINE constexpr void assign_bits(T &value, std::type_identity_t< T > mask, bool on)
Set the bits of mask in value when on is true, clear them otherwise.
Definition helpers.h:1072