1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-04 12:22:20 +01:00
Files
esphome/esphome/components/ch422g/ch422g.cpp
2025-08-27 19:30:33 +10:00

139 lines
4.6 KiB
C++

#include "ch422g.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ch422g {
static const uint8_t CH422G_REG_MODE = 0x24;
static const uint8_t CH422G_MODE_OUTPUT = 0x01; // enables output mode on 0-7
static const uint8_t CH422G_MODE_OPEN_DRAIN = 0x04; // enables open drain mode on 8-11
static const uint8_t CH422G_REG_IN = 0x26; // read reg for input bits
static const uint8_t CH422G_REG_OUT = 0x38; // write reg for output bits 0-7
static const uint8_t CH422G_REG_OUT_UPPER = 0x23; // write reg for output bits 8-11
static const char *const TAG = "ch422g";
void CH422GComponent::setup() {
// set outputs before mode
this->write_outputs_();
// Set mode and check for errors
if (!this->set_mode_(this->mode_value_) || !this->read_inputs_()) {
ESP_LOGE(TAG, "CH422G not detected at 0x%02X", this->address_);
this->mark_failed();
return;
}
ESP_LOGCONFIG(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(),
this->status_has_error());
}
void CH422GComponent::loop() {
// Clear all the previously read flags.
this->pin_read_flags_ = 0x00;
}
void CH422GComponent::dump_config() {
ESP_LOGCONFIG(TAG, "CH422G:");
LOG_I2C_DEVICE(this)
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) {
if (pin < 8) {
if (flags & gpio::FLAG_OUTPUT) {
this->mode_value_ |= CH422G_MODE_OUTPUT;
}
} else {
if (flags & gpio::FLAG_OPEN_DRAIN) {
this->mode_value_ |= CH422G_MODE_OPEN_DRAIN;
}
}
}
bool CH422GComponent::digital_read(uint8_t pin) {
if (this->pin_read_flags_ == 0 || this->pin_read_flags_ & (1 << pin)) {
// Read values on first access or in case it's being read again in the same loop
this->read_inputs_();
}
this->pin_read_flags_ |= (1 << pin);
return (this->input_bits_ & (1 << pin)) != 0;
}
void CH422GComponent::digital_write(uint8_t pin, bool value) {
if (value) {
this->output_bits_ |= (1 << pin);
} else {
this->output_bits_ &= ~(1 << pin);
}
this->write_outputs_();
}
bool CH422GComponent::read_inputs_() {
if (this->is_failed()) {
return false;
}
uint8_t result;
// reading inputs requires the chip to be in input mode, possibly temporarily.
if (this->mode_value_ & CH422G_MODE_OUTPUT) {
this->set_mode_(this->mode_value_ & ~CH422G_MODE_OUTPUT);
result = this->read_reg_(CH422G_REG_IN);
this->set_mode_(this->mode_value_);
} else {
result = this->read_reg_(CH422G_REG_IN);
}
this->input_bits_ = result;
this->status_clear_warning();
return true;
}
// Write a register. Can't use the standard write_byte() method because there is no single pre-configured i2c address.
bool CH422GComponent::write_reg_(uint8_t reg, uint8_t value) {
auto err = this->bus_->write_readv(reg, &value, 1, nullptr, 0);
if (err != i2c::ERROR_OK) {
this->status_set_warning(str_sprintf("write failed for register 0x%X, error %d", reg, err).c_str());
return false;
}
this->status_clear_warning();
return true;
}
uint8_t CH422GComponent::read_reg_(uint8_t reg) {
uint8_t value;
auto err = this->bus_->write_readv(reg, nullptr, 0, &value, 1);
if (err != i2c::ERROR_OK) {
this->status_set_warning(str_sprintf("read failed for register 0x%X, error %d", reg, err).c_str());
return 0;
}
this->status_clear_warning();
return value;
}
bool CH422GComponent::set_mode_(uint8_t mode) { return this->write_reg_(CH422G_REG_MODE, mode); }
bool CH422GComponent::write_outputs_() {
return this->write_reg_(CH422G_REG_OUT, static_cast<uint8_t>(this->output_bits_)) &&
this->write_reg_(CH422G_REG_OUT_UPPER, static_cast<uint8_t>(this->output_bits_ >> 8));
}
float CH422GComponent::get_setup_priority() const { return setup_priority::IO; }
// Run our loop() method very early in the loop, so that we cache read values
// before other components call our digital_read() method.
float CH422GComponent::get_loop_priority() const { return 9.0f; } // Just after WIFI
void CH422GGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) ^ this->inverted_; }
void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value ^ this->inverted_); }
std::string CH422GGPIOPin::dump_summary() const { return str_sprintf("EXIO%u via CH422G", pin_); }
void CH422GGPIOPin::set_flags(gpio::Flags flags) {
flags_ = flags;
this->parent_->pin_mode(this->pin_, flags);
}
} // namespace ch422g
} // namespace esphome