-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
- Loading branch information
1 parent
67771ab
commit 41a6187
Showing
5 changed files
with
263 additions
and
0 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import esphome.codegen as cg | ||
import esphome.config_validation as cv | ||
from esphome.components import i2c | ||
from esphome.const import ( | ||
CONF_ID, | ||
CONF_INPUT, | ||
CONF_INVERTED, | ||
CONF_MODE, | ||
CONF_NUMBER, | ||
CONF_OUTPUT, | ||
) | ||
from esphome import pins | ||
|
||
CONF_XL9535 = "xl9535" | ||
|
||
DEPENDENCIES = ["i2c"] | ||
CODEOWNERS = ["@mreditor97"] | ||
|
||
xl9535_ns = cg.esphome_ns.namespace(CONF_XL9535) | ||
|
||
XL9535Component = xl9535_ns.class_("XL9535Component", cg.Component, i2c.I2CDevice) | ||
XL9535GPIOPin = xl9535_ns.class_("XL9535GPIOPin", cg.GPIOPin) | ||
|
||
MULTI_CONF = True | ||
CONFIG_SCHEMA = ( | ||
cv.Schema({cv.Required(CONF_ID): cv.declare_id(XL9535Component)}) | ||
.extend(cv.COMPONENT_SCHEMA) | ||
.extend(i2c.i2c_device_schema(0x20)) | ||
) | ||
|
||
|
||
async def to_code(config): | ||
var = cg.new_Pvariable(config[CONF_ID]) | ||
await cg.register_component(var, config) | ||
await i2c.register_i2c_device(var, config) | ||
|
||
|
||
def validate_mode(mode): | ||
if not (mode[CONF_INPUT] or mode[CONF_OUTPUT]) or ( | ||
mode[CONF_INPUT] and mode[CONF_OUTPUT] | ||
): | ||
raise cv.Invalid("Mode must be either a input or a output") | ||
return mode | ||
|
||
|
||
XL9535_PIN_SCHEMA = cv.All( | ||
{ | ||
cv.GenerateID(): cv.declare_id(XL9535GPIOPin), | ||
cv.Required(CONF_XL9535): cv.use_id(XL9535Component), | ||
cv.Required(CONF_NUMBER): cv.int_range(min=0, max=15), | ||
cv.Optional(CONF_MODE, default={}): cv.All( | ||
{ | ||
cv.Optional(CONF_INPUT, default=False): cv.boolean, | ||
cv.Optional(CONF_OUTPUT, default=False): cv.boolean, | ||
}, | ||
validate_mode, | ||
), | ||
cv.Optional(CONF_INVERTED, default=False): cv.boolean, | ||
} | ||
) | ||
|
||
|
||
@pins.PIN_SCHEMA_REGISTRY.register(CONF_XL9535, XL9535_PIN_SCHEMA) | ||
async def xl9535_pin_to_code(config): | ||
var = cg.new_Pvariable(config[CONF_ID]) | ||
parent = await cg.get_variable(config[CONF_XL9535]) | ||
|
||
cg.add(var.set_parent(parent)) | ||
cg.add(var.set_pin(config[CONF_NUMBER])) | ||
cg.add(var.set_inverted(config[CONF_INVERTED])) | ||
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) | ||
|
||
return var |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
#include "xl9535.h" | ||
#include "esphome/core/log.h" | ||
|
||
namespace esphome { | ||
namespace xl9535 { | ||
|
||
static const char *const TAG = "xl9535"; | ||
|
||
void XL9535Component::setup() { | ||
ESP_LOGCONFIG(TAG, "Setting up XL9535..."); | ||
|
||
// Check to see if the device can read from the register | ||
uint8_t port = 0; | ||
if (this->read_register(XL9535_INPUT_PORT_0_REGISTER, &port, 1) != i2c::ERROR_OK) { | ||
this->mark_failed(); | ||
return; | ||
} | ||
} | ||
|
||
void XL9535Component::dump_config() { | ||
ESP_LOGCONFIG(TAG, "XL9535:"); | ||
LOG_I2C_DEVICE(this); | ||
|
||
if (this->is_failed()) { | ||
ESP_LOGE(TAG, "Communication with XL9535 failed!"); | ||
} | ||
} | ||
|
||
bool XL9535Component::digital_read(uint8_t pin) { | ||
bool state = false; | ||
uint8_t port = 0; | ||
|
||
if (pin > 7) { | ||
if (this->read_register(XL9535_INPUT_PORT_1_REGISTER, &port, 1) != i2c::ERROR_OK) { | ||
this->status_set_warning(); | ||
return state; | ||
} | ||
|
||
state = (port & (pin - 10)) != 0; | ||
} else { | ||
if (this->read_register(XL9535_INPUT_PORT_0_REGISTER, &port, 1) != i2c::ERROR_OK) { | ||
this->status_set_warning(); | ||
return state; | ||
} | ||
|
||
state = (port & pin) != 0; | ||
} | ||
|
||
this->status_clear_warning(); | ||
return state; | ||
} | ||
|
||
void XL9535Component::digital_write(uint8_t pin, bool value) { | ||
uint8_t port = 0; | ||
uint8_t register_data = 0; | ||
|
||
if (pin > 7) { | ||
if (this->read_register(XL9535_OUTPUT_PORT_1_REGISTER, ®ister_data, 1) != i2c::ERROR_OK) { | ||
this->status_set_warning(); | ||
return; | ||
} | ||
|
||
register_data = register_data & (~(1 << (pin - 10))); | ||
port = register_data | value << (pin - 10); | ||
|
||
if (this->write_register(XL9535_OUTPUT_PORT_1_REGISTER, &port, 1) != i2c::ERROR_OK) { | ||
this->status_set_warning(); | ||
return; | ||
} | ||
} else { | ||
if (this->read_register(XL9535_OUTPUT_PORT_0_REGISTER, ®ister_data, 1) != i2c::ERROR_OK) { | ||
this->status_set_warning(); | ||
return; | ||
} | ||
register_data = register_data & (~(1 << pin)); | ||
port = register_data | value << pin; | ||
|
||
if (this->write_register(XL9535_OUTPUT_PORT_0_REGISTER, &port, 1) != i2c::ERROR_OK) { | ||
this->status_set_warning(); | ||
return; | ||
} | ||
} | ||
|
||
this->status_clear_warning(); | ||
} | ||
|
||
void XL9535Component::pin_mode(uint8_t pin, gpio::Flags mode) { | ||
uint8_t port = 0; | ||
|
||
if (pin > 7) { | ||
this->read_register(XL9535_CONFIG_PORT_1_REGISTER, &port, 1); | ||
|
||
if (mode == gpio::FLAG_INPUT) { | ||
port = port | (1 << (pin - 10)); | ||
} else if (mode == gpio::FLAG_OUTPUT) { | ||
port = port & (~(1 << (pin - 10))); | ||
} | ||
|
||
this->write_register(XL9535_CONFIG_PORT_1_REGISTER, &port, 1); | ||
} else { | ||
this->read_register(XL9535_CONFIG_PORT_0_REGISTER, &port, 1); | ||
|
||
if (mode == gpio::FLAG_INPUT) { | ||
port = port | (1 << pin); | ||
} else if (mode == gpio::FLAG_OUTPUT) { | ||
port = port & (~(1 << pin)); | ||
} | ||
|
||
this->write_register(XL9535_CONFIG_PORT_0_REGISTER, &port, 1); | ||
} | ||
} | ||
|
||
void XL9535GPIOPin::setup() { this->pin_mode(this->flags_); } | ||
|
||
std::string XL9535GPIOPin::dump_summary() const { return str_snprintf("%u via XL9535", 15, this->pin_); } | ||
|
||
void XL9535GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } | ||
bool XL9535GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } | ||
void XL9535GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } | ||
|
||
} // namespace xl9535 | ||
} // namespace esphome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#pragma once | ||
|
||
#include "esphome/core/component.h" | ||
#include "esphome/components/i2c/i2c.h" | ||
#include "esphome/core/hal.h" | ||
|
||
namespace esphome { | ||
namespace xl9535 { | ||
|
||
enum { | ||
XL9535_INPUT_PORT_0_REGISTER = 0x00, | ||
XL9535_INPUT_PORT_1_REGISTER = 0x01, | ||
XL9535_OUTPUT_PORT_0_REGISTER = 0x02, | ||
XL9535_OUTPUT_PORT_1_REGISTER = 0x03, | ||
XL9535_INVERSION_PORT_0_REGISTER = 0x04, | ||
XL9535_INVERSION_PORT_1_REGISTER = 0x05, | ||
XL9535_CONFIG_PORT_0_REGISTER = 0x06, | ||
XL9535_CONFIG_PORT_1_REGISTER = 0x07, | ||
}; | ||
|
||
class XL9535Component : public Component, public i2c::I2CDevice { | ||
public: | ||
bool digital_read(uint8_t pin); | ||
void digital_write(uint8_t pin, bool value); | ||
void pin_mode(uint8_t pin, gpio::Flags mode); | ||
|
||
void setup() override; | ||
void dump_config() override; | ||
float get_setup_priority() const override { return setup_priority::DATA; } | ||
}; | ||
|
||
class XL9535GPIOPin : public GPIOPin { | ||
public: | ||
void set_parent(XL9535Component *parent) { this->parent_ = parent; } | ||
void set_pin(uint8_t pin) { this->pin_ = pin; } | ||
void set_inverted(bool inverted) { this->inverted_ = inverted; } | ||
void set_flags(gpio::Flags flags) { this->flags_ = flags; } | ||
|
||
void setup() override; | ||
std::string dump_summary() const override; | ||
void pin_mode(gpio::Flags flags) override; | ||
bool digital_read() override; | ||
void digital_write(bool value) override; | ||
|
||
protected: | ||
XL9535Component *parent_; | ||
|
||
uint8_t pin_; | ||
bool inverted_; | ||
gpio::Flags flags_; | ||
}; | ||
|
||
} // namespace xl9535 | ||
} // namespace esphome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters