mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
Add the WeiKai SPI/I2C UART/IO Expander components to esphome (#5218)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
f9ce35c894
commit
f8cdb087fc
60 changed files with 2874 additions and 0 deletions
11
CODEOWNERS
11
CODEOWNERS
|
@ -400,10 +400,21 @@ esphome/components/wake_on_lan/* @willwill2will54
|
|||
esphome/components/waveshare_epaper/* @clydebarrow
|
||||
esphome/components/web_server_base/* @OttoWinter
|
||||
esphome/components/web_server_idf/* @dentra
|
||||
esphome/components/weikai/* @DrCoolZic
|
||||
esphome/components/weikai_i2c/* @DrCoolZic
|
||||
esphome/components/weikai_spi/* @DrCoolZic
|
||||
esphome/components/whirlpool/* @glmnet
|
||||
esphome/components/whynter/* @aeonsablaze
|
||||
esphome/components/wiegand/* @ssieb
|
||||
esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard
|
||||
esphome/components/wk2132_i2c/* @DrCoolZic
|
||||
esphome/components/wk2132_spi/* @DrCoolZic
|
||||
esphome/components/wk2168_i2c/* @DrCoolZic
|
||||
esphome/components/wk2168_spi/* @DrCoolZic
|
||||
esphome/components/wk2204_i2c/* @DrCoolZic
|
||||
esphome/components/wk2204_spi/* @DrCoolZic
|
||||
esphome/components/wk2212_i2c/* @DrCoolZic
|
||||
esphome/components/wk2212_spi/* @DrCoolZic
|
||||
esphome/components/wl_134/* @hobbypunk90
|
||||
esphome/components/x9c/* @EtienneMD
|
||||
esphome/components/xgzp68xx/* @gcormier
|
||||
|
|
108
esphome/components/weikai/__init__.py
Normal file
108
esphome/components/weikai/__init__.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import uart
|
||||
from esphome.const import (
|
||||
CONF_BAUD_RATE,
|
||||
CONF_CHANNEL,
|
||||
CONF_ID,
|
||||
CONF_INPUT,
|
||||
CONF_INVERTED,
|
||||
CONF_MODE,
|
||||
CONF_NUMBER,
|
||||
CONF_OUTPUT,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
AUTO_LOAD = ["uart"]
|
||||
|
||||
MULTI_CONF = True
|
||||
CONF_STOP_BITS = "stop_bits"
|
||||
CONF_PARITY = "parity"
|
||||
CONF_CRYSTAL = "crystal"
|
||||
CONF_UART = "uart"
|
||||
CONF_TEST_MODE = "test_mode"
|
||||
|
||||
weikai_ns = cg.esphome_ns.namespace("weikai")
|
||||
WeikaiComponent = weikai_ns.class_("WeikaiComponent", cg.Component)
|
||||
WeikaiChannel = weikai_ns.class_("WeikaiChannel", uart.UARTComponent)
|
||||
|
||||
|
||||
def check_channel_max(value, max):
|
||||
channel_uniq = []
|
||||
channel_dup = []
|
||||
for x in value[CONF_UART]:
|
||||
if x[CONF_CHANNEL] > max - 1:
|
||||
raise cv.Invalid(f"Invalid channel number: {x[CONF_CHANNEL]}")
|
||||
if x[CONF_CHANNEL] not in channel_uniq:
|
||||
channel_uniq.append(x[CONF_CHANNEL])
|
||||
else:
|
||||
channel_dup.append(x[CONF_CHANNEL])
|
||||
if len(channel_dup) > 0:
|
||||
raise cv.Invalid(f"Duplicate channel list: {channel_dup}")
|
||||
return value
|
||||
|
||||
|
||||
def check_channel_max_4(value):
|
||||
return check_channel_max(value, 4)
|
||||
|
||||
|
||||
def check_channel_max_2(value):
|
||||
return check_channel_max(value, 2)
|
||||
|
||||
|
||||
WKBASE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiComponent),
|
||||
cv.Optional(CONF_CRYSTAL, default=14745600): cv.int_,
|
||||
cv.Optional(CONF_TEST_MODE, default=0): cv.int_,
|
||||
cv.Required(CONF_UART): cv.ensure_list(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(WeikaiChannel),
|
||||
cv.Optional(CONF_CHANNEL, default=0): cv.int_range(min=0, max=3),
|
||||
cv.Required(CONF_BAUD_RATE): cv.int_range(min=1),
|
||||
cv.Optional(CONF_STOP_BITS, default=1): cv.one_of(1, 2, int=True),
|
||||
cv.Optional(CONF_PARITY, default="NONE"): cv.enum(
|
||||
uart.UART_PARITY_OPTIONS, upper=True
|
||||
),
|
||||
}
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
async def register_weikai(var, config):
|
||||
"""Register an weikai device with the given config."""
|
||||
cg.add(var.set_crystal(config[CONF_CRYSTAL]))
|
||||
cg.add(var.set_test_mode(config[CONF_TEST_MODE]))
|
||||
await cg.register_component(var, config)
|
||||
for uart_elem in config[CONF_UART]:
|
||||
chan = cg.new_Pvariable(uart_elem[CONF_ID])
|
||||
cg.add(chan.set_channel_name(str(uart_elem[CONF_ID])))
|
||||
cg.add(chan.set_parent(var))
|
||||
cg.add(chan.set_channel(uart_elem[CONF_CHANNEL]))
|
||||
cg.add(chan.set_baud_rate(uart_elem[CONF_BAUD_RATE]))
|
||||
cg.add(chan.set_stop_bits(uart_elem[CONF_STOP_BITS]))
|
||||
cg.add(chan.set_parity(uart_elem[CONF_PARITY]))
|
||||
|
||||
|
||||
def validate_pin_mode(value):
|
||||
"""Checks input/output mode inconsistency"""
|
||||
if not (value[CONF_MODE][CONF_INPUT] or value[CONF_MODE][CONF_OUTPUT]):
|
||||
raise cv.Invalid("Mode must be either input or output")
|
||||
if value[CONF_MODE][CONF_INPUT] and value[CONF_MODE][CONF_OUTPUT]:
|
||||
raise cv.Invalid("Mode must be either input or output")
|
||||
return value
|
||||
|
||||
|
||||
WEIKAI_PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_NUMBER): cv.int_range(min=0, max=7),
|
||||
cv.Optional(CONF_MODE, default={}): cv.All(
|
||||
{
|
||||
cv.Optional(CONF_INPUT, default=False): cv.boolean,
|
||||
cv.Optional(CONF_OUTPUT, default=False): cv.boolean,
|
||||
},
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
}
|
||||
)
|
615
esphome/components/weikai/weikai.cpp
Normal file
615
esphome/components/weikai/weikai.cpp
Normal file
|
@ -0,0 +1,615 @@
|
|||
/// @file weikai.cpp
|
||||
/// @brief WeiKai component family - classes implementation
|
||||
/// @date Last Modified: 2024/04/06 15:13:11
|
||||
/// @details The classes declared in this file can be used by the Weikai family
|
||||
|
||||
#include "weikai.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace weikai {
|
||||
|
||||
/*! @mainpage Weikai source code documentation
|
||||
This documentation provides information about the implementation of the family of WeiKai Components in ESPHome.
|
||||
Here is the class diagram related to Weikai family of components:
|
||||
@image html weikai_class.png
|
||||
|
||||
@section WKRingBuffer_ The WKRingBuffer template class
|
||||
The WKRingBuffer template class has it names implies implement a simple ring buffer helper class. This straightforward
|
||||
container implements FIFO functionality, enabling bytes to be pushed into one side and popped from the other in the
|
||||
order of entry. Implementation is classic and therefore not described in any details.
|
||||
|
||||
@section WeikaiRegister_ The WeikaiRegister class
|
||||
The WeikaiRegister helper class creates objects that act as proxies to the device registers.
|
||||
@details This is an abstract virtual class (interface) that provides all the necessary access to registers while hiding
|
||||
the actual implementation. The access to the registers can be made through an I²C bus in for example for wk2168_i2c
|
||||
component or through a SPI bus for example in the case of the wk2168_spi component. Derived classes will actually
|
||||
performs the specific bus operations.
|
||||
|
||||
@section WeikaiRegisterI2C_ WeikaiRegisterI2C
|
||||
The weikai_i2c::WeikaiRegisterI2C class implements the virtual methods of the WeikaiRegister class for an I2C bus.
|
||||
|
||||
@section WeikaiRegisterSPI_ WeikaiRegisterSPI
|
||||
The weikai_spi::WeikaiRegisterSPI class implements the virtual methods of the WeikaiRegister class for an SPI bus.
|
||||
|
||||
@section WeikaiComponent_ The WeikaiComponent class
|
||||
The WeikaiComponent class stores the information global to a WeiKai family component and provides methods to set/access
|
||||
this information. It also serves as a container for WeikaiChannel instances. This is done by maintaining an array of
|
||||
references these WeikaiChannel instances. This class derives from the esphome::Component classes. This class override
|
||||
esphome::Component::loop() method to facilitate the seamless transfer of accumulated bytes from the receive
|
||||
FIFO into the ring buffer. This process ensures quick access to the stored bytes, enhancing the overall efficiency of
|
||||
the component.
|
||||
|
||||
@section WeikaiComponentI2C_ WeikaiComponentI2C
|
||||
The weikai_i2c::WeikaiComponentI2C class implements the virtual methods of the WeikaiComponent class for an I2C bus.
|
||||
|
||||
@section WeikaiComponentSPI_ WeikaiComponentSPI
|
||||
The weikai_spi::WeikaiComponentSPI class implements the virtual methods of the WeikaiComponent class for an SPI bus.
|
||||
|
||||
@section WeikaiGPIOPin_ WeikaiGPIOPin class
|
||||
The WeikaiGPIOPin class is an helper class to expose the GPIO pins of WK family components as if they were internal
|
||||
GPIO pins. It also provides the setup() and dump_summary() methods.
|
||||
|
||||
@section WeikaiChannel_ The WeikaiChannel class
|
||||
The WeikaiChannel class is used to implement all the virtual methods of the ESPHome uart::UARTComponent class. An
|
||||
individual instance of this class is created for each UART channel. It has a link back to the WeikaiComponent object it
|
||||
belongs to. This class derives from the uart::UARTComponent class. It collaborates through an aggregation with
|
||||
WeikaiComponent. This implies that WeikaiComponent acts as a container, housing several WeikaiChannel instances.
|
||||
Furthermore, the WeikaiChannel class derives from the ESPHome uart::UARTComponent class, it also has an association
|
||||
relationship with the WKRingBuffer and WeikaiRegister helper classes. Consequently, when a WeikaiChannel instance is
|
||||
destroyed, the associated WKRingBuffer instance is also destroyed.
|
||||
|
||||
*/
|
||||
|
||||
static const char *const TAG = "weikai";
|
||||
|
||||
/// @brief convert an int to binary representation as C++ std::string
|
||||
/// @param val integer to convert
|
||||
/// @return a std::string
|
||||
inline std::string i2s(uint8_t val) { return std::bitset<8>(val).to_string(); }
|
||||
/// Convert std::string to C string
|
||||
#define I2S2CS(val) (i2s(val).c_str())
|
||||
|
||||
/// @brief measure the time elapsed between two calls
|
||||
/// @param last_time time of the previous call
|
||||
/// @return the elapsed time in milliseconds
|
||||
uint32_t elapsed_ms(uint32_t &last_time) {
|
||||
uint32_t e = millis() - last_time;
|
||||
last_time = millis();
|
||||
return e;
|
||||
};
|
||||
|
||||
/// @brief Converts the parity enum value to a C string
|
||||
/// @param parity enum
|
||||
/// @return the string
|
||||
const char *p2s(uart::UARTParityOptions parity) {
|
||||
using namespace uart;
|
||||
switch (parity) {
|
||||
case UART_CONFIG_PARITY_NONE:
|
||||
return "NONE";
|
||||
case UART_CONFIG_PARITY_EVEN:
|
||||
return "EVEN";
|
||||
case UART_CONFIG_PARITY_ODD:
|
||||
return "ODD";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Display a buffer in hexadecimal format (32 hex values / line) for debug
|
||||
void print_buffer(const uint8_t *data, size_t length) {
|
||||
char hex_buffer[100];
|
||||
hex_buffer[(3 * 32) + 1] = 0;
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]);
|
||||
if (i % 32 == 31) {
|
||||
ESP_LOGVV(TAG, " %s", hex_buffer);
|
||||
}
|
||||
}
|
||||
if (length % 32) {
|
||||
// null terminate if incomplete line
|
||||
hex_buffer[3 * (length % 32) + 2] = 0;
|
||||
ESP_LOGVV(TAG, " %s", hex_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST", "GMUT", "SPAGE", "SCR", "LCR", "FCR", "SIER",
|
||||
"SIFR", "TFCNT", "RFCNT", "FSR", "LSR", "FDAT", "FWCR", "RS485"};
|
||||
static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL",
|
||||
"TFTL", "FWTH", "FWTL", "XON1", "XOFF1", "SADR", "SAEN", "RTSDLY"};
|
||||
|
||||
// method to print a register value as text: used in the log messages ...
|
||||
const char *reg_to_str(int reg, bool page1) {
|
||||
if (reg == WKREG_GPDAT) {
|
||||
return "GPDAT";
|
||||
} else if (reg == WKREG_GPDIR) {
|
||||
return "GPDIR";
|
||||
} else {
|
||||
return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F];
|
||||
}
|
||||
}
|
||||
|
||||
enum RegType { REG = 0, FIFO = 1 }; ///< Register or FIFO
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiRegister methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
WeikaiRegister &WeikaiRegister::operator=(uint8_t value) {
|
||||
write_reg(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
WeikaiRegister &WeikaiRegister::operator&=(uint8_t value) {
|
||||
value &= read_reg();
|
||||
write_reg(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
WeikaiRegister &WeikaiRegister::operator|=(uint8_t value) {
|
||||
value |= read_reg();
|
||||
write_reg(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiComponent methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void WeikaiComponent::loop() {
|
||||
if ((this->component_state_ & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP)
|
||||
return;
|
||||
|
||||
// If there are some bytes in the receive FIFO we transfers them to the ring buffers
|
||||
size_t transferred = 0;
|
||||
for (auto *child : this->children_) {
|
||||
// we look if some characters has been received in the fifo
|
||||
transferred += child->xfer_fifo_to_buffer_();
|
||||
}
|
||||
if (transferred > 0) {
|
||||
ESP_LOGV(TAG, "we transferred %d bytes from fifo to buffer...", transferred);
|
||||
}
|
||||
|
||||
#ifdef TEST_COMPONENT
|
||||
static uint32_t loop_time = 0;
|
||||
static uint32_t loop_count = 0;
|
||||
uint32_t time = 0;
|
||||
|
||||
if (test_mode_ == 1) { // test component in loopback
|
||||
ESP_LOGI(TAG, "Component loop %" PRIu32 " for %s : %" PRIu32 " ms since last call ...", loop_count++,
|
||||
this->get_name(), millis() - loop_time);
|
||||
loop_time = millis();
|
||||
char message[64];
|
||||
elapsed_ms(time); // set time to now
|
||||
for (int i = 0; i < this->children_.size(); i++) {
|
||||
if (i != ((loop_count - 1) % this->children_.size())) // we do only one per loop
|
||||
continue;
|
||||
snprintf(message, sizeof(message), "%s:%s", this->get_name(), children_[i]->get_channel_name());
|
||||
children_[i]->uart_send_test_(message);
|
||||
uint32_t const start_time = millis();
|
||||
while (children_[i]->tx_fifo_is_not_empty_()) { // wait until buffer empty
|
||||
if (millis() - start_time > 1500) {
|
||||
ESP_LOGE(TAG, "timeout while flushing - %d bytes left in buffer...", children_[i]->tx_in_fifo_());
|
||||
break;
|
||||
}
|
||||
yield(); // reschedule our thread to avoid blocking
|
||||
}
|
||||
bool status = children_[i]->uart_receive_test_(message);
|
||||
ESP_LOGI(TAG, "Test %s => send/received %u bytes %s - execution time %" PRIu32 " ms...", message,
|
||||
RING_BUFFER_SIZE, status ? "correctly" : "with error", elapsed_ms(time));
|
||||
}
|
||||
}
|
||||
|
||||
if (this->test_mode_ == 2) { // test component in echo mode
|
||||
for (auto *child : this->children_) {
|
||||
uint8_t data = 0;
|
||||
if (child->available()) {
|
||||
child->read_byte(&data);
|
||||
ESP_LOGI(TAG, "echo mode: read -> send %02X", data);
|
||||
child->write_byte(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (test_mode_ == 3) {
|
||||
test_gpio_input_();
|
||||
}
|
||||
|
||||
if (test_mode_ == 4) {
|
||||
test_gpio_output_();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TEST_COMPONENT)
|
||||
void WeikaiComponent::test_gpio_input_() {
|
||||
static bool init_input{false};
|
||||
static uint8_t state{0};
|
||||
uint8_t value;
|
||||
if (!init_input) {
|
||||
init_input = true;
|
||||
// set all pins in input mode
|
||||
this->reg(WKREG_GPDIR, 0) = 0x00;
|
||||
ESP_LOGI(TAG, "initializing all pins to input mode");
|
||||
state = this->reg(WKREG_GPDAT, 0);
|
||||
ESP_LOGI(TAG, "initial input data state = %02X (%s)", state, I2S2CS(state));
|
||||
}
|
||||
value = this->reg(WKREG_GPDAT, 0);
|
||||
if (value != state) {
|
||||
ESP_LOGI(TAG, "Input data changed from %02X to %02X (%s)", state, value, I2S2CS(value));
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
||||
void WeikaiComponent::test_gpio_output_() {
|
||||
static bool init_output{false};
|
||||
static uint8_t state{0};
|
||||
if (!init_output) {
|
||||
init_output = true;
|
||||
// set all pins in output mode
|
||||
this->reg(WKREG_GPDIR, 0) = 0xFF;
|
||||
ESP_LOGI(TAG, "initializing all pins to output mode");
|
||||
this->reg(WKREG_GPDAT, 0) = state;
|
||||
ESP_LOGI(TAG, "setting all outputs to 0");
|
||||
}
|
||||
state = ~state;
|
||||
this->reg(WKREG_GPDAT, 0) = state;
|
||||
ESP_LOGI(TAG, "Flipping all outputs to %02X (%s)", state, I2S2CS(state));
|
||||
delay(100); // NOLINT
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiGPIOPin methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool WeikaiComponent::read_pin_val_(uint8_t pin) {
|
||||
this->input_state_ = this->reg(WKREG_GPDAT, 0);
|
||||
ESP_LOGVV(TAG, "reading input pin %u = %u in_state %s", pin, this->input_state_ & (1 << pin), I2S2CS(input_state_));
|
||||
return this->input_state_ & (1 << pin);
|
||||
}
|
||||
|
||||
void WeikaiComponent::write_pin_val_(uint8_t pin, bool value) {
|
||||
if (value) {
|
||||
this->output_state_ |= (1 << pin);
|
||||
} else {
|
||||
this->output_state_ &= ~(1 << pin);
|
||||
}
|
||||
ESP_LOGVV(TAG, "writing output pin %d with %d out_state %s", pin, uint8_t(value), I2S2CS(this->output_state_));
|
||||
this->reg(WKREG_GPDAT, 0) = this->output_state_;
|
||||
}
|
||||
|
||||
void WeikaiComponent::set_pin_direction_(uint8_t pin, gpio::Flags flags) {
|
||||
if (flags == gpio::FLAG_INPUT) {
|
||||
this->pin_config_ &= ~(1 << pin); // clear bit (input mode)
|
||||
} else {
|
||||
if (flags == gpio::FLAG_OUTPUT) {
|
||||
this->pin_config_ |= 1 << pin; // set bit (output mode)
|
||||
} else {
|
||||
ESP_LOGE(TAG, "pin %d direction invalid", pin);
|
||||
}
|
||||
}
|
||||
ESP_LOGVV(TAG, "setting pin %d direction to %d pin_config=%s", pin, flags, I2S2CS(this->pin_config_));
|
||||
this->reg(WKREG_GPDIR, 0) = this->pin_config_; // TODO check ~
|
||||
}
|
||||
|
||||
void WeikaiGPIOPin::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting GPIO pin %d mode to %s", this->pin_,
|
||||
flags_ == gpio::FLAG_INPUT ? "Input"
|
||||
: this->flags_ == gpio::FLAG_OUTPUT ? "Output"
|
||||
: "NOT SPECIFIED");
|
||||
// ESP_LOGCONFIG(TAG, "Setting GPIO pins mode to '%s' %02X", I2S2CS(this->flags_), this->flags_);
|
||||
this->pin_mode(this->flags_);
|
||||
}
|
||||
|
||||
std::string WeikaiGPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via WeiKai %s", this->pin_, this->parent_->get_name());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiChannel methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void WeikaiChannel::setup_channel() {
|
||||
ESP_LOGCONFIG(TAG, " Setting up UART %s:%s ...", this->parent_->get_name(), this->get_channel_name());
|
||||
// we enable transmit and receive on this channel
|
||||
if (this->check_channel_down()) {
|
||||
ESP_LOGCONFIG(TAG, " Error channel %s not working...", this->get_channel_name());
|
||||
}
|
||||
this->reset_fifo_();
|
||||
this->receive_buffer_.clear();
|
||||
this->set_line_param_();
|
||||
this->set_baudrate_();
|
||||
}
|
||||
|
||||
void WeikaiChannel::dump_channel() {
|
||||
ESP_LOGCONFIG(TAG, " UART %s ...", this->get_channel_name());
|
||||
ESP_LOGCONFIG(TAG, " Baud rate: %" PRIu32 " Bd", this->baud_rate_);
|
||||
ESP_LOGCONFIG(TAG, " Data bits: %u", this->data_bits_);
|
||||
ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
|
||||
ESP_LOGCONFIG(TAG, " Parity: %s", p2s(this->parity_));
|
||||
}
|
||||
|
||||
void WeikaiChannel::reset_fifo_() {
|
||||
// enable transmission and reception
|
||||
this->reg(WKREG_SCR) = SCR_RXEN | SCR_TXEN;
|
||||
// we reset and enable transmit and receive FIFO
|
||||
this->reg(WKREG_FCR) = FCR_TFEN | FCR_RFEN | FCR_TFRST | FCR_RFRST;
|
||||
}
|
||||
|
||||
void WeikaiChannel::set_line_param_() {
|
||||
this->data_bits_ = 8; // always equal to 8 for WeiKai (cant be changed)
|
||||
uint8_t lcr = 0;
|
||||
if (this->stop_bits_ == 2)
|
||||
lcr |= LCR_STPL;
|
||||
switch (this->parity_) { // parity selection settings
|
||||
case uart::UART_CONFIG_PARITY_ODD:
|
||||
lcr |= (LCR_PAEN | LCR_PAR_ODD);
|
||||
break;
|
||||
case uart::UART_CONFIG_PARITY_EVEN:
|
||||
lcr |= (LCR_PAEN | LCR_PAR_EVEN);
|
||||
break;
|
||||
default:
|
||||
break; // no parity 000x
|
||||
}
|
||||
this->reg(WKREG_LCR) = lcr; // write LCR
|
||||
ESP_LOGV(TAG, " line config: %d data_bits, %d stop_bits, parity %s register [%s]", this->data_bits_,
|
||||
this->stop_bits_, p2s(this->parity_), I2S2CS(lcr));
|
||||
}
|
||||
|
||||
void WeikaiChannel::set_baudrate_() {
|
||||
if (this->baud_rate_ > this->parent_->crystal_ / 16) {
|
||||
baud_rate_ = this->parent_->crystal_ / 16;
|
||||
ESP_LOGE(TAG, " Requested baudrate too high for crystal=%" PRIu32 " Hz. Has been reduced to %" PRIu32 " Bd",
|
||||
this->parent_->crystal_, this->baud_rate_);
|
||||
};
|
||||
uint16_t const val_int = this->parent_->crystal_ / (this->baud_rate_ * 16) - 1;
|
||||
uint16_t val_dec = (this->parent_->crystal_ % (this->baud_rate_ * 16)) / (this->baud_rate_ * 16);
|
||||
uint8_t const baud_high = (uint8_t) (val_int >> 8);
|
||||
uint8_t const baud_low = (uint8_t) (val_int & 0xFF);
|
||||
while (val_dec > 0x0A)
|
||||
val_dec /= 0x0A;
|
||||
uint8_t const baud_dec = (uint8_t) (val_dec);
|
||||
|
||||
this->parent_->page1_ = true; // switch to page 1
|
||||
this->reg(WKREG_SPAGE) = 1;
|
||||
this->reg(WKREG_BRH) = baud_high;
|
||||
this->reg(WKREG_BRL) = baud_low;
|
||||
this->reg(WKREG_BRD) = baud_dec;
|
||||
this->parent_->page1_ = false; // switch back to page 0
|
||||
this->reg(WKREG_SPAGE) = 0;
|
||||
|
||||
ESP_LOGV(TAG, " Crystal=%d baudrate=%d => registers [%d %d %d]", this->parent_->crystal_, this->baud_rate_,
|
||||
baud_high, baud_low, baud_dec);
|
||||
}
|
||||
|
||||
inline bool WeikaiChannel::tx_fifo_is_not_empty_() { return this->reg(WKREG_FSR) & FSR_TFDAT; }
|
||||
|
||||
size_t WeikaiChannel::tx_in_fifo_() {
|
||||
size_t tfcnt = this->reg(WKREG_TFCNT);
|
||||
if (tfcnt == 0) {
|
||||
uint8_t const fsr = this->reg(WKREG_FSR);
|
||||
if (fsr & FSR_TFFULL) {
|
||||
ESP_LOGVV(TAG, "tx FIFO full FSR=%s", I2S2CS(fsr));
|
||||
tfcnt = FIFO_SIZE;
|
||||
}
|
||||
}
|
||||
ESP_LOGVV(TAG, "tx FIFO contains %d bytes", tfcnt);
|
||||
return tfcnt;
|
||||
}
|
||||
|
||||
size_t WeikaiChannel::rx_in_fifo_() {
|
||||
size_t available = this->reg(WKREG_RFCNT);
|
||||
uint8_t const fsr = this->reg(WKREG_FSR);
|
||||
if (fsr & (FSR_RFOE | FSR_RFLB | FSR_RFFE | FSR_RFPE)) {
|
||||
if (fsr & FSR_RFOE)
|
||||
ESP_LOGE(TAG, "Receive data overflow FSR=%s", I2S2CS(fsr));
|
||||
if (fsr & FSR_RFLB)
|
||||
ESP_LOGE(TAG, "Receive line break FSR=%s", I2S2CS(fsr));
|
||||
if (fsr & FSR_RFFE)
|
||||
ESP_LOGE(TAG, "Receive frame error FSR=%s", I2S2CS(fsr));
|
||||
if (fsr & FSR_RFPE)
|
||||
ESP_LOGE(TAG, "Receive parity error FSR=%s", I2S2CS(fsr));
|
||||
}
|
||||
if ((available == 0) && (fsr & FSR_RFDAT)) {
|
||||
// here we should be very careful because we can have something like this:
|
||||
// - at time t0 we read RFCNT=0 because nothing yet received
|
||||
// - at time t0+delta we might read FIFO not empty because one byte has just been received
|
||||
// - so to be sure we need to do another read of RFCNT and if it is still zero -> buffer full
|
||||
available = this->reg(WKREG_RFCNT);
|
||||
if (available == 0) { // still zero ?
|
||||
ESP_LOGV(TAG, "rx FIFO is full FSR=%s", I2S2CS(fsr));
|
||||
available = FIFO_SIZE;
|
||||
}
|
||||
}
|
||||
ESP_LOGVV(TAG, "rx FIFO contain %d bytes - FSR status=%s", available, I2S2CS(fsr));
|
||||
return available;
|
||||
}
|
||||
|
||||
bool WeikaiChannel::check_channel_down() {
|
||||
// to check if we channel is up we write to the LCR W/R register
|
||||
// note that this will put a break on the tx line for few ms
|
||||
WeikaiRegister &lcr = this->reg(WKREG_LCR);
|
||||
lcr = 0x3F;
|
||||
uint8_t val = lcr;
|
||||
if (val != 0x3F) {
|
||||
ESP_LOGE(TAG, "R/W of register failed expected 0x3F received 0x%02X", val);
|
||||
return true;
|
||||
}
|
||||
lcr = 0;
|
||||
val = lcr;
|
||||
if (val != 0x00) {
|
||||
ESP_LOGE(TAG, "R/W of register failed expected 0x00 received 0x%02X", val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WeikaiChannel::peek_byte(uint8_t *buffer) {
|
||||
auto available = this->receive_buffer_.count();
|
||||
if (!available)
|
||||
xfer_fifo_to_buffer_();
|
||||
return this->receive_buffer_.peek(*buffer);
|
||||
}
|
||||
|
||||
int WeikaiChannel::available() {
|
||||
size_t available = this->receive_buffer_.count();
|
||||
if (!available)
|
||||
available = xfer_fifo_to_buffer_();
|
||||
return available;
|
||||
}
|
||||
|
||||
bool WeikaiChannel::read_array(uint8_t *buffer, size_t length) {
|
||||
bool status = true;
|
||||
auto available = this->receive_buffer_.count();
|
||||
if (length > available) {
|
||||
ESP_LOGW(TAG, "read_array: buffer underflow requested %d bytes only %d bytes available...", length, available);
|
||||
length = available;
|
||||
status = false;
|
||||
}
|
||||
// retrieve the bytes from ring buffer
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
this->receive_buffer_.pop(buffer[i]);
|
||||
}
|
||||
ESP_LOGVV(TAG, "read_array(ch=%d buffer[0]=%02X, length=%d): status %s", this->channel_, *buffer, length,
|
||||
status ? "OK" : "ERROR");
|
||||
return status;
|
||||
}
|
||||
|
||||
void WeikaiChannel::write_array(const uint8_t *buffer, size_t length) {
|
||||
if (length > XFER_MAX_SIZE) {
|
||||
ESP_LOGE(TAG, "Write_array: invalid call - requested %d bytes but max size %d ...", length, XFER_MAX_SIZE);
|
||||
length = XFER_MAX_SIZE;
|
||||
}
|
||||
this->reg(0).write_fifo(const_cast<uint8_t *>(buffer), length);
|
||||
}
|
||||
|
||||
void WeikaiChannel::flush() {
|
||||
uint32_t const start_time = millis();
|
||||
while (this->tx_fifo_is_not_empty_()) { // wait until buffer empty
|
||||
if (millis() - start_time > 200) {
|
||||
ESP_LOGW(TAG, "WARNING flush timeout - still %d bytes not sent after 200 ms...", this->tx_in_fifo_());
|
||||
return;
|
||||
}
|
||||
yield(); // reschedule our thread to avoid blocking
|
||||
}
|
||||
}
|
||||
|
||||
size_t WeikaiChannel::xfer_fifo_to_buffer_() {
|
||||
size_t to_transfer;
|
||||
size_t free;
|
||||
while ((to_transfer = this->rx_in_fifo_()) && (free = this->receive_buffer_.free())) {
|
||||
// while bytes in fifo and some room in the buffer we transfer
|
||||
if (to_transfer > XFER_MAX_SIZE)
|
||||
to_transfer = XFER_MAX_SIZE; // we can only do so much
|
||||
if (to_transfer > free)
|
||||
to_transfer = free; // we'll do the rest next time
|
||||
if (to_transfer) {
|
||||
uint8_t data[to_transfer];
|
||||
this->reg(0).read_fifo(data, to_transfer);
|
||||
for (size_t i = 0; i < to_transfer; i++)
|
||||
this->receive_buffer_.push(data[i]);
|
||||
}
|
||||
} // while work to do
|
||||
return to_transfer;
|
||||
}
|
||||
|
||||
///
|
||||
// TEST COMPONENT
|
||||
//
|
||||
#ifdef TEST_COMPONENT
|
||||
/// @addtogroup test_ Test component information
|
||||
/// @{
|
||||
|
||||
/// @brief An increment "Functor" (i.e. a class object that acts like a method with state!)
|
||||
///
|
||||
/// Functors are objects that can be treated as though they are a function or function pointer.
|
||||
class Increment {
|
||||
public:
|
||||
/// @brief constructor: initialize current value to 0
|
||||
Increment() : i_(0) {}
|
||||
/// @brief overload of the parenthesis operator.
|
||||
/// Returns the current value and auto increment it
|
||||
/// @return the current value.
|
||||
uint8_t operator()() { return i_++; }
|
||||
|
||||
private:
|
||||
uint8_t i_;
|
||||
};
|
||||
|
||||
/// @brief Hex converter to print/display a buffer in hexadecimal format (32 hex values / line).
|
||||
/// @param buffer contains the values to display
|
||||
void print_buffer(std::vector<uint8_t> buffer) {
|
||||
char hex_buffer[100];
|
||||
hex_buffer[(3 * 32) + 1] = 0;
|
||||
for (size_t i = 0; i < buffer.size(); i++) {
|
||||
snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", buffer[i]);
|
||||
if (i % 32 == 31)
|
||||
ESP_LOGI(TAG, " %s", hex_buffer);
|
||||
}
|
||||
if (buffer.size() % 32) {
|
||||
// null terminate if incomplete line
|
||||
hex_buffer[3 * (buffer.size() % 32) + 1] = 0;
|
||||
ESP_LOGI(TAG, " %s", hex_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief test the write_array method
|
||||
void WeikaiChannel::uart_send_test_(char *message) {
|
||||
auto start_exec = micros();
|
||||
std::vector<uint8_t> output_buffer(XFER_MAX_SIZE);
|
||||
generate(output_buffer.begin(), output_buffer.end(), Increment()); // fill with incrementing number
|
||||
size_t to_send = RING_BUFFER_SIZE;
|
||||
while (to_send) {
|
||||
this->write_array(&output_buffer[0], XFER_MAX_SIZE); // we send the buffer
|
||||
this->flush();
|
||||
to_send -= XFER_MAX_SIZE;
|
||||
}
|
||||
ESP_LOGV(TAG, "%s => sent %d bytes - exec time %d µs ...", message, RING_BUFFER_SIZE, micros() - start_exec);
|
||||
}
|
||||
|
||||
/// @brief test read_array method
|
||||
bool WeikaiChannel::uart_receive_test_(char *message) {
|
||||
auto start_exec = micros();
|
||||
bool status = true;
|
||||
size_t received = 0;
|
||||
std::vector<uint8_t> buffer(RING_BUFFER_SIZE);
|
||||
|
||||
// we wait until we have received all the bytes
|
||||
uint32_t const start_time = millis();
|
||||
status = true;
|
||||
while (received < RING_BUFFER_SIZE) {
|
||||
while (XFER_MAX_SIZE > this->available()) {
|
||||
this->xfer_fifo_to_buffer_();
|
||||
if (millis() - start_time > 1500) {
|
||||
ESP_LOGE(TAG, "uart_receive_test_() timeout: only %d bytes received...", this->available());
|
||||
break;
|
||||
}
|
||||
yield(); // reschedule our thread to avoid blocking
|
||||
}
|
||||
status = this->read_array(&buffer[received], XFER_MAX_SIZE) && status;
|
||||
received += XFER_MAX_SIZE;
|
||||
}
|
||||
|
||||
uint8_t peek_value = 0;
|
||||
this->peek_byte(&peek_value);
|
||||
if (peek_value != 0) {
|
||||
ESP_LOGE(TAG, "Peek first byte value error...");
|
||||
status = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < RING_BUFFER_SIZE; i++) {
|
||||
if (buffer[i] != i % XFER_MAX_SIZE) {
|
||||
ESP_LOGE(TAG, "Read buffer contains error...b=%x i=%x", buffer[i], i % XFER_MAX_SIZE);
|
||||
print_buffer(buffer);
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "%s => received %d bytes status %s - exec time %d µs ...", message, received, status ? "OK" : "ERROR",
|
||||
micros() - start_exec);
|
||||
return status;
|
||||
}
|
||||
|
||||
/// @}
|
||||
#endif
|
||||
|
||||
} // namespace weikai
|
||||
} // namespace esphome
|
443
esphome/components/weikai/weikai.h
Normal file
443
esphome/components/weikai/weikai.h
Normal file
|
@ -0,0 +1,443 @@
|
|||
/// @file weikai.h
|
||||
/// @author DrCoolZic
|
||||
/// @brief WeiKai component family - classes declaration
|
||||
/// @date Last Modified: 2024/04/06 14:44:17
|
||||
/// @details The classes declared in this file can be used by the Weikai family
|
||||
/// of UART and GPIO expander components. As of today it provides support for
|
||||
/// wk2124_spi, wk2132_spi, wk2168_spi, wk2204_spi, wk2212_spi,
|
||||
/// wk2132_i2c, wk2168_i2c, wk2204_i2c, wk2212_i2c
|
||||
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include <cinttypes>
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "wk_reg_def.h"
|
||||
|
||||
/// When the TEST_COMPONENT flag is defined we include some auto-test methods. Used to test the software during
|
||||
/// development but can also be used in situ to test if the component is working correctly. For release we do
|
||||
/// not set it by default but you can set it by using the following lines in you configuration file:
|
||||
/// @code
|
||||
/// esphome:
|
||||
/// platformio_options:
|
||||
/// build_flags:
|
||||
/// - -DTEST_COMPONENT
|
||||
/// @endcode
|
||||
// #define TEST_COMPONENT
|
||||
|
||||
namespace esphome {
|
||||
namespace weikai {
|
||||
|
||||
/// @brief XFER_MAX_SIZE defines the maximum number of bytes allowed during one transfer.
|
||||
#if defined(I2C_BUFFER_LENGTH)
|
||||
constexpr size_t XFER_MAX_SIZE = I2C_BUFFER_LENGTH;
|
||||
#else
|
||||
constexpr size_t XFER_MAX_SIZE = 128;
|
||||
#endif
|
||||
|
||||
/// @brief size of the internal WeiKai FIFO
|
||||
constexpr size_t FIFO_SIZE = 256;
|
||||
|
||||
/// @brief size of the ring buffer set to size of the FIFO
|
||||
constexpr size_t RING_BUFFER_SIZE = FIFO_SIZE;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief This is an helper class that provides a simple ring buffers that works as a FIFO
|
||||
/// @details This ring buffer is used to buffer the bytes received in the FIFO of the Weika device. The best way to read
|
||||
/// characters from the device FIFO, is to first check how many bytes were received and then read them all at once.
|
||||
/// Unfortunately in all the code I have reviewed the characters are read one by one in a while loop by checking if
|
||||
/// bytes are available then reading the byte until no more byte available. This is pretty inefficient for two reasons:
|
||||
/// - Fist you need to perform a test for each byte to read
|
||||
/// - and second you call the read byte method for each character.
|
||||
/// .
|
||||
/// Assuming you need to read 100 bytes that results into 200 calls. This is to compare to 2 calls (one to find the
|
||||
/// number of bytes available plus one to read all the bytes) in the best case! If the registers you read are located on
|
||||
/// the micro-controller this is acceptable because the registers can be accessed fast. But when the registers are
|
||||
/// located on a remote device accessing them requires several cycles on a slow bus. As it it not possible to fix this
|
||||
/// problem by asking users to rewrite their code, I have implemented this ring buffer that store the bytes received
|
||||
/// locally.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T, size_t SIZE> class WKRingBuffer {
|
||||
public:
|
||||
/// @brief pushes an item at the tail of the fifo
|
||||
/// @param item item to push
|
||||
/// @return true if item has been pushed, false il item could not pushed (buffer full)
|
||||
bool push(const T item) {
|
||||
if (is_full())
|
||||
return false;
|
||||
this->rb_[this->head_] = item;
|
||||
this->head_ = (this->head_ + 1) % SIZE;
|
||||
this->count_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief return and remove the item at head of the fifo
|
||||
/// @param item item read
|
||||
/// @return true if an item has been retrieved, false il no item available (buffer empty)
|
||||
bool pop(T &item) {
|
||||
if (is_empty())
|
||||
return false;
|
||||
item = this->rb_[this->tail_];
|
||||
this->tail_ = (this->tail_ + 1) % SIZE;
|
||||
this->count_--;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief return the value of the item at fifo's head without removing it
|
||||
/// @param item pointer to item to return
|
||||
/// @return true if item has been retrieved, false il no item available (buffer empty)
|
||||
bool peek(T &item) {
|
||||
if (is_empty())
|
||||
return false;
|
||||
item = this->rb_[this->tail_];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief test is the Ring Buffer is empty ?
|
||||
/// @return true if empty
|
||||
inline bool is_empty() { return (this->count_ == 0); }
|
||||
|
||||
/// @brief test is the ring buffer is full ?
|
||||
/// @return true if full
|
||||
inline bool is_full() { return (this->count_ == SIZE); }
|
||||
|
||||
/// @brief return the number of item in the ring buffer
|
||||
/// @return the number of items
|
||||
inline size_t count() { return this->count_; }
|
||||
|
||||
/// @brief returns the number of free positions in the buffer
|
||||
/// @return how many items can be added
|
||||
inline size_t free() { return SIZE - this->count_; }
|
||||
|
||||
/// @brief clear the buffer content
|
||||
inline void clear() { this->head_ = this->tail_ = this->count_ = 0; }
|
||||
|
||||
protected:
|
||||
std::array<T, SIZE> rb_{0}; ///< the ring buffer
|
||||
int tail_{0}; ///< position of the next element to read
|
||||
int head_{0}; ///< position of the next element to write
|
||||
size_t count_{0}; ///< count number of element in the buffer
|
||||
};
|
||||
|
||||
class WeikaiComponent;
|
||||
// class WeikaiComponentSPI;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief WeikaiRegister objects acts as proxies to access remote register independently of the bus type.
|
||||
/// @details This is an abstract interface class that provides many operations to access to registers while hiding
|
||||
/// the actual implementation. This allow to accesses the registers in the Weikai component abstract class independently
|
||||
/// of the actual bus (I2C, SPI). The derived classes will actually implements the specific bus operations dependant of
|
||||
/// the bus used.
|
||||
/// @n typical usage of WeikaiRegister:
|
||||
/// @code
|
||||
/// WeikaiRegister reg_X {&WeikaiComponent, ADDR_REGISTER_X, CHANNEL_NUM} // declaration
|
||||
/// reg_X |= 0x01; // set bit 0 of the weikai register
|
||||
/// reg_X &= ~0x01; // reset bit 0 of the weikai register
|
||||
/// reg_X = 10; // Set the value of weikai register
|
||||
/// uint val = reg_X; // get the value of weikai register
|
||||
/// @endcode
|
||||
class WeikaiRegister {
|
||||
public:
|
||||
/// @brief WeikaiRegister constructor.
|
||||
/// @param comp our parent WeikaiComponent
|
||||
/// @param reg address of the register
|
||||
/// @param channel the channel of this register
|
||||
WeikaiRegister(WeikaiComponent *const comp, uint8_t reg, uint8_t channel)
|
||||
: comp_(comp), register_(reg), channel_(channel) {}
|
||||
virtual ~WeikaiRegister() {}
|
||||
|
||||
/// @brief overloads the = operator. This is used to set a value into the weikai register
|
||||
/// @param value to be set
|
||||
/// @return this object
|
||||
WeikaiRegister &operator=(uint8_t value);
|
||||
|
||||
/// @brief overloads the compound &= operator. This is often used to reset bits in the weikai register
|
||||
/// @param value performs an & operation with value and store the result
|
||||
/// @return this object
|
||||
WeikaiRegister &operator&=(uint8_t value);
|
||||
|
||||
/// @brief overloads the compound |= operator. This is often used to set bits in the weikai register
|
||||
/// @param value performs an | operation with value and store the result
|
||||
/// @return this object
|
||||
WeikaiRegister &operator|=(uint8_t value);
|
||||
|
||||
/// @brief cast operator that returns the content of the weikai register
|
||||
operator uint8_t() const { return read_reg(); }
|
||||
|
||||
/// @brief reads the register
|
||||
/// @return the value read from the register
|
||||
virtual uint8_t read_reg() const = 0;
|
||||
|
||||
/// @brief writes the register
|
||||
/// @param value to write in the register
|
||||
virtual void write_reg(uint8_t value) = 0;
|
||||
|
||||
/// @brief read an array of bytes from the receiver fifo
|
||||
/// @param data pointer to data buffer
|
||||
/// @param length number of bytes to read
|
||||
virtual void read_fifo(uint8_t *data, size_t length) const = 0;
|
||||
|
||||
/// @brief write an array of bytes to the transmitter fifo
|
||||
/// @param data pointer to data buffer
|
||||
/// @param length number of bytes to write
|
||||
virtual void write_fifo(uint8_t *data, size_t length) = 0;
|
||||
|
||||
WeikaiComponent *const comp_; ///< pointer to our parent (aggregation)
|
||||
uint8_t register_; ///< address of the register
|
||||
uint8_t channel_; ///< channel for this register
|
||||
};
|
||||
|
||||
class WeikaiChannel; // forward declaration
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief The WeikaiComponent class stores the information global to the WeiKai component
|
||||
/// and provides methods to set/access this information. It is also the container of
|
||||
/// the WeikaiChannel children objects. This class is derived from esphome::Component
|
||||
/// class.
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
class WeikaiComponent : public Component {
|
||||
public:
|
||||
/// @brief virtual destructor
|
||||
virtual ~WeikaiComponent() {}
|
||||
|
||||
/// @brief store crystal frequency
|
||||
/// @param crystal frequency
|
||||
void set_crystal(uint32_t crystal) { this->crystal_ = crystal; }
|
||||
|
||||
/// @brief store if the component is in test mode
|
||||
/// @param test_mode 0=normal mode any other values mean component in test mode
|
||||
void set_test_mode(int test_mode) { this->test_mode_ = test_mode; }
|
||||
|
||||
/// @brief store the name for the component
|
||||
/// @param name the name as defined by the python code generator
|
||||
void set_name(std::string name) { this->name_ = std::move(name); }
|
||||
|
||||
/// @brief Get the name of the component
|
||||
/// @return the name
|
||||
const char *get_name() { return this->name_.c_str(); }
|
||||
|
||||
/// @brief override the Component loop()
|
||||
void loop() override;
|
||||
|
||||
bool page1() { return page1_; }
|
||||
|
||||
/// @brief Factory method to create a Register object
|
||||
/// @param reg address of the register
|
||||
/// @param channel channel associated with this register
|
||||
/// @return a reference to WeikaiRegister
|
||||
virtual WeikaiRegister ®(uint8_t reg, uint8_t channel) = 0;
|
||||
|
||||
protected:
|
||||
friend class WeikaiChannel;
|
||||
|
||||
/// @brief Get the priority of the component
|
||||
/// @return the priority
|
||||
/// @details The priority is set below setup_priority::BUS because we use
|
||||
/// the spi/i2c busses (which has a priority of BUS) to communicate and the WeiKai
|
||||
/// therefore it is seen by our client almost as if it was a bus.
|
||||
float get_setup_priority() const override { return setup_priority::BUS - 0.1F; }
|
||||
|
||||
friend class WeikaiGPIOPin;
|
||||
/// Helper method to read the value of a pin.
|
||||
bool read_pin_val_(uint8_t pin);
|
||||
|
||||
/// Helper method to write the value of a pin.
|
||||
void write_pin_val_(uint8_t pin, bool value);
|
||||
|
||||
/// Helper method to set the pin mode of a pin.
|
||||
void set_pin_direction_(uint8_t pin, gpio::Flags flags);
|
||||
|
||||
#ifdef TEST_COMPONENT
|
||||
/// @defgroup test_ Test component information
|
||||
/// @brief Contains information about the auto-tests of the component
|
||||
/// @{
|
||||
void test_gpio_input_();
|
||||
void test_gpio_output_();
|
||||
/// @}
|
||||
#endif
|
||||
|
||||
uint8_t pin_config_{0x00}; ///< pin config mask: 1 means OUTPUT, 0 means INPUT
|
||||
uint8_t output_state_{0x00}; ///< output state: 1 means HIGH, 0 means LOW
|
||||
uint8_t input_state_{0x00}; ///< input pin states: 1 means HIGH, 0 means LOW
|
||||
uint32_t crystal_; ///< crystal value;
|
||||
int test_mode_; ///< test mode value (0 -> no tests)
|
||||
bool page1_{false}; ///< set to true when in "page1 mode"
|
||||
std::vector<WeikaiChannel *> children_{}; ///< the list of WeikaiChannel UART children
|
||||
std::string name_; ///< name of entity
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Helper class to expose a WeiKai family IO pin as an internal GPIO pin.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class WeikaiGPIOPin : public GPIOPin {
|
||||
public:
|
||||
void set_parent(WeikaiComponent *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 { this->parent_->set_pin_direction_(this->pin_, flags); }
|
||||
bool digital_read() override { return this->parent_->read_pin_val_(this->pin_) != this->inverted_; }
|
||||
void digital_write(bool value) override { this->parent_->write_pin_val_(this->pin_, value != this->inverted_); }
|
||||
|
||||
protected:
|
||||
WeikaiComponent *parent_{nullptr};
|
||||
uint8_t pin_;
|
||||
bool inverted_;
|
||||
gpio::Flags flags_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief The WeikaiChannel class is used to implement all the virtual methods of the ESPHome
|
||||
/// uart::UARTComponent virtual class. This class is common to the different members of the Weikai
|
||||
/// components family and therefore avoid code duplication.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class WeikaiChannel : public uart::UARTComponent {
|
||||
public:
|
||||
/// @brief We belongs to this WeikaiComponent
|
||||
/// @param parent pointer to the component we belongs to
|
||||
void set_parent(WeikaiComponent *parent) {
|
||||
this->parent_ = parent;
|
||||
this->parent_->children_.push_back(this); // add ourself to the list (vector)
|
||||
}
|
||||
|
||||
/// @brief Sets the channel number
|
||||
/// @param channel number
|
||||
void set_channel(uint8_t channel) { this->channel_ = channel; }
|
||||
|
||||
/// @brief The name as generated by the Python code generator
|
||||
/// @param name of the channel
|
||||
void set_channel_name(std::string name) { this->name_ = std::move(name); }
|
||||
|
||||
/// @brief Get the channel name
|
||||
/// @return the name
|
||||
const char *get_channel_name() { return this->name_.c_str(); }
|
||||
|
||||
/// @brief Setup the channel
|
||||
void virtual setup_channel();
|
||||
|
||||
/// @brief dump channel information
|
||||
void virtual dump_channel();
|
||||
|
||||
/// @brief Factory method to create a WeikaiRegister proxy object
|
||||
/// @param reg address of the register
|
||||
/// @return a reference to WeikaiRegister
|
||||
WeikaiRegister ®(uint8_t reg) { return this->parent_->reg(reg, channel_); }
|
||||
|
||||
//
|
||||
// we implements/overrides the virtual class from UARTComponent
|
||||
//
|
||||
|
||||
/// @brief Writes a specified number of bytes to a serial port
|
||||
/// @param buffer pointer to the buffer
|
||||
/// @param length number of bytes to write
|
||||
/// @details This method sends 'length' characters from the buffer to the serial line. Unfortunately (unlike the
|
||||
/// Arduino equivalent) this method does not return any flag and therefore it is not possible to know if any/all bytes
|
||||
/// have been transmitted correctly. Another problem is that it is not possible to know ahead of time how many bytes
|
||||
/// we can safely send as there is no tx_available() method provided! To avoid overrun when using the write method you
|
||||
/// can use the flush() method to wait until the transmit fifo is empty.
|
||||
/// @n Typical usage could be:
|
||||
/// @code
|
||||
/// // ...
|
||||
/// uint8_t buffer[128];
|
||||
/// // ...
|
||||
/// write_array(&buffer, length);
|
||||
/// flush();
|
||||
/// // ...
|
||||
/// @endcode
|
||||
void write_array(const uint8_t *buffer, size_t length) override;
|
||||
|
||||
/// @brief Reads a specified number of bytes from a serial port
|
||||
/// @param buffer buffer to store the bytes
|
||||
/// @param length number of bytes to read
|
||||
/// @return true if succeed, false otherwise
|
||||
/// @details Typical usage:
|
||||
/// @code
|
||||
/// // ...
|
||||
/// auto length = available();
|
||||
/// uint8_t buffer[128];
|
||||
/// if (length > 0) {
|
||||
/// auto status = read_array(&buffer, length)
|
||||
/// // test status ...
|
||||
/// }
|
||||
/// @endcode
|
||||
bool read_array(uint8_t *buffer, size_t length) override;
|
||||
|
||||
/// @brief Reads the first byte in FIFO without removing it
|
||||
/// @param buffer pointer to the byte
|
||||
/// @return true if succeed reading one byte, false if no character available
|
||||
/// @details This method returns the next byte from receiving buffer without removing it from the internal fifo. It
|
||||
/// returns true if a character is available and has been read, false otherwise.\n
|
||||
bool peek_byte(uint8_t *buffer) override;
|
||||
|
||||
/// @brief Returns the number of bytes in the receive buffer
|
||||
/// @return the number of bytes available in the receiver fifo
|
||||
int available() override;
|
||||
|
||||
/// @brief Flush the output fifo.
|
||||
/// @details If we refer to Serial.flush() in Arduino it says: ** Waits for the transmission of outgoing serial data
|
||||
/// to complete. (Prior to Arduino 1.0, this the method was removing any buffered incoming serial data.). ** Therefore
|
||||
/// we wait until all bytes are gone with a timeout of 100 ms
|
||||
void flush() override;
|
||||
|
||||
protected:
|
||||
friend class WeikaiComponent;
|
||||
|
||||
/// @brief this cannot happen with external uart therefore we do nothing
|
||||
void check_logger_conflict() override {}
|
||||
|
||||
/// @brief reset the weikai internal FIFO
|
||||
void reset_fifo_();
|
||||
|
||||
/// @brief set the line parameters
|
||||
void set_line_param_();
|
||||
|
||||
/// @brief set the baud rate
|
||||
void set_baudrate_();
|
||||
|
||||
/// @brief Returns the number of bytes in the receive fifo
|
||||
/// @return the number of bytes in the fifo
|
||||
size_t rx_in_fifo_();
|
||||
|
||||
/// @brief Returns the number of bytes in the transmit fifo
|
||||
/// @return the number of bytes in the fifo
|
||||
size_t tx_in_fifo_();
|
||||
|
||||
/// @brief test if transmit buffer is not empty in the status register (optimization)
|
||||
/// @return true if not emptygroup test_
|
||||
bool tx_fifo_is_not_empty_();
|
||||
|
||||
/// @brief transfer bytes from the weikai internal FIFO to the buffer (if any)
|
||||
/// @return number of bytes transferred
|
||||
size_t xfer_fifo_to_buffer_();
|
||||
|
||||
/// @brief check if channel is alive
|
||||
/// @return true if OK
|
||||
bool virtual check_channel_down();
|
||||
|
||||
#ifdef TEST_COMPONENT
|
||||
/// @ingroup test_
|
||||
/// @{
|
||||
|
||||
/// @brief Test the write_array() method
|
||||
/// @param message to display
|
||||
void uart_send_test_(char *message);
|
||||
|
||||
/// @brief Test the read_array() method
|
||||
/// @param message to display
|
||||
/// @return true if success
|
||||
bool uart_receive_test_(char *message);
|
||||
/// @}
|
||||
#endif
|
||||
|
||||
/// @brief the buffer where we store temporarily the bytes received
|
||||
WKRingBuffer<uint8_t, RING_BUFFER_SIZE> receive_buffer_;
|
||||
WeikaiComponent *parent_; ///< our WK2168component parent
|
||||
uint8_t channel_; ///< our Channel number
|
||||
uint8_t data_; ///< a one byte buffer for register read storage
|
||||
std::string name_; ///< name of the entity
|
||||
};
|
||||
|
||||
} // namespace weikai
|
||||
} // namespace esphome
|
304
esphome/components/weikai/wk_reg_def.h
Normal file
304
esphome/components/weikai/wk_reg_def.h
Normal file
|
@ -0,0 +1,304 @@
|
|||
/// @file wk_reg_def.h
|
||||
/// @author DrCoolZic
|
||||
/// @brief WeiKai component family - registers' definition
|
||||
/// @date Last Modified: 2024/02/18 15:49:18
|
||||
#pragma once
|
||||
|
||||
namespace esphome {
|
||||
namespace weikai {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Definition of the WeiKai registers
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup wk2168_gr_ WeiKai Global Registers
|
||||
/// This section groups all **Global Registers**: these registers are global to the
|
||||
/// the WeiKai chip (i.e. independent of the UART channel used)
|
||||
/// @note only registers and parameters used have been fully documented
|
||||
/// @{
|
||||
|
||||
/// @brief Global Control Register - 00 0000
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | M0 | M1 | RSV | C4EN | C3EN | C2EN | C1EN | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | R | R | R | R | W/R | W/R | W/R | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_GENA = 0x00;
|
||||
/// @brief Channel 4 enable clock (0: disable, 1: enable)
|
||||
constexpr uint8_t GENA_C4EN = 1 << 3;
|
||||
/// @brief Channel 3 enable clock (0: disable, 1: enable)
|
||||
constexpr uint8_t GENA_C3EN = 1 << 2;
|
||||
/// @brief Channel 2 enable clock (0: disable, 1: enable)
|
||||
constexpr uint8_t GENA_C2EN = 1 << 1;
|
||||
/// @brief Channel 1 enable clock (0: disable, 1: enable)
|
||||
constexpr uint8_t GENA_C1EN = 1 << 0;
|
||||
|
||||
/// @brief Global Reset Register - 00 0001
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | C4SLEEP| C3SLEEP| C2SLEEP| C1SLEEP| C4RST | C3RST | C2RST | C1RST | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | R | R | R | R | W1/R0 | W1/R0 | W1/R0 | W1/R0 | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_GRST = 0x01;
|
||||
/// @brief Channel 4 soft reset (0: not reset, 1: reset)
|
||||
constexpr uint8_t GRST_C4RST = 1 << 3;
|
||||
/// @brief Channel 3 soft reset (0: not reset, 1: reset)
|
||||
constexpr uint8_t GRST_C3RST = 1 << 2;
|
||||
/// @brief Channel 2 soft reset (0: not reset, 1: reset)
|
||||
constexpr uint8_t GRST_C2RST = 1 << 1;
|
||||
/// @brief Channel 1 soft reset (0: not reset, 1: reset)
|
||||
constexpr uint8_t GRST_C1RST = 1 << 0;
|
||||
|
||||
/// @brief Global Master channel control register (not used) - 000010
|
||||
constexpr uint8_t WKREG_GMUT = 0x02;
|
||||
|
||||
/// Global interrupt register (not used) - 01 0000
|
||||
constexpr uint8_t WKREG_GIER = 0x10;
|
||||
|
||||
/// Global interrupt flag register (not used) 01 0001
|
||||
constexpr uint8_t WKREG_GIFR = 0x11;
|
||||
|
||||
/// @brief Global GPIO direction register - 10 0001
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | PD7 | PD6 | PD5 | PD4 | PD3 | PD2 | PD1 | PD0 | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_GPDIR = 0x21;
|
||||
|
||||
/// @brief Global GPIO data register - 11 0001
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | PV7 | PV6 | PV5 | PV4 | PV3 | PV2 | PV1 | PV0 | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_GPDAT = 0x31;
|
||||
|
||||
/// @}
|
||||
/// @defgroup WeiKai_cr_ WeiKai Channel Registers
|
||||
/// @brief Definition of the register linked to a particular channel
|
||||
/// @details This topic groups all the **Channel Registers**: these registers are specific
|
||||
/// to the a specific channel i.e. each channel has its own set of registers
|
||||
/// @note only registers and parameters used have been documented
|
||||
/// @{
|
||||
|
||||
/// @defgroup cr_p0 Channel registers when SPAGE=0
|
||||
/// @brief Definition of the register linked to a particular channel when SPAGE=0
|
||||
/// @details The channel registers are further splitted into two groups.
|
||||
/// This first group is defined when the Global register WKREG_SPAGE is 0
|
||||
/// @{
|
||||
|
||||
/// @brief Global Page register c0/c1 0011
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | RSV | PAGE | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | R | R | R | R | R | R | R | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_SPAGE = 0x03;
|
||||
|
||||
/// @brief Serial Control Register - c0/c1 0100
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | RSV | SLPEN | TXEN | RXEN | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | R | R | R | R | R | R/W | R/W | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_SCR = 0x04;
|
||||
/// @brief transmission control (0: enable, 1: disable)
|
||||
constexpr uint8_t SCR_TXEN = 1 << 1;
|
||||
/// @brief receiving control (0: enable, 1: disable)
|
||||
constexpr uint8_t SCR_RXEN = 1 << 0;
|
||||
|
||||
/// @brief Line Configuration Register - c0/c1 0101
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | RSV | BREAK | IREN | PAEN | PARITY | STPL | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_LCR = 0x05;
|
||||
/// @brief Parity enable (0: no check, 1: check)
|
||||
constexpr uint8_t LCR_PAEN = 1 << 3;
|
||||
/// @brief Parity force 0
|
||||
constexpr uint8_t LCR_PAR_F0 = 0 << 1;
|
||||
/// @brief Parity odd
|
||||
constexpr uint8_t LCR_PAR_ODD = 1 << 1;
|
||||
/// @brief Parity even
|
||||
constexpr uint8_t LCR_PAR_EVEN = 2 << 1;
|
||||
/// @brief Parity force 1
|
||||
constexpr uint8_t LCR_PAR_F1 = 3 << 1;
|
||||
/// @brief Stop length (0: 1 bit, 1: 2 bits)
|
||||
constexpr uint8_t LCR_STPL = 1 << 0;
|
||||
|
||||
/// @brief FIFO Control Register - c0/c1 0110
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | TFTRIG | RFTRIG | TFEN | RFEN | TFRST | RFRST | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | W/R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_FCR = 0x06;
|
||||
/// @brief Transmitter FIFO enable
|
||||
constexpr uint8_t FCR_TFEN = 1 << 3;
|
||||
/// @brief Receiver FIFO enable
|
||||
constexpr uint8_t FCR_RFEN = 1 << 2;
|
||||
/// @brief Transmitter FIFO reset
|
||||
constexpr uint8_t FCR_TFRST = 1 << 1;
|
||||
/// @brief Receiver FIFO reset
|
||||
constexpr uint8_t FCR_RFRST = 1 << 0;
|
||||
|
||||
/// @brief Serial Interrupt Enable Register (not used) - c0/c1 0111
|
||||
constexpr uint8_t WKREG_SIER = 0x07;
|
||||
|
||||
/// @brief Serial Interrupt Flag Register (not used) - c0/c1 1000
|
||||
constexpr uint8_t WKREG_SIFR = 0x08;
|
||||
|
||||
/// @brief Transmitter FIFO Count - c0/c1 1001
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | NUMBER OF DATA IN TRANSMITTER FIFO |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_TFCNT = 0x09;
|
||||
|
||||
/// @brief Receiver FIFO count - c0/c1 1010
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | NUMBER OF DATA IN RECEIVER FIFO |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_RFCNT = 0x0A;
|
||||
|
||||
/// @brief FIFO Status Register - c0/c1 1011
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | bit
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | RFOE | RFLB | RFFE | RFPE | RFDAT | TFDAT | TFFULL | TBUSY | name
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | R | W/R | W/R | W/R | W/R | W/R | W/R | W/R | type
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | reset
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
/// @warning The received buffer can hold 256 bytes. However, as the RFCNT reg
|
||||
/// is 8 bits, if we have 256 byte in the register this is reported as 0 ! Therefore
|
||||
/// RFCNT=0 can indicate that there are 0 **or** 256 bytes in the buffer. If we
|
||||
/// have RFDAT = 1 and RFCNT = 0 it should be interpreted as 256 bytes in the FIFO.
|
||||
/// @note Note that in case of overflow the RFOE goes to one **but** as soon as you read
|
||||
/// the FSR this bit is cleared. Therefore Overflow can be read only once.
|
||||
/// @n The same problem applies to the transmit buffer but here we have to check the
|
||||
/// TFFULL flag. So if TFFULL is set and TFCNT is 0 this should be interpreted as 256
|
||||
constexpr uint8_t WKREG_FSR = 0x0B;
|
||||
/// @brief Receiver FIFO Overflow Error (0: no OE, 1: OE)
|
||||
constexpr uint8_t FSR_RFOE = 1 << 7;
|
||||
/// @brief Receiver FIFO Line Break (0: no LB, 1: LB)
|
||||
constexpr uint8_t FSR_RFLB = 1 << 6;
|
||||
/// @brief Receiver FIFO Frame Error (0: no FE, 1: FE)
|
||||
constexpr uint8_t FSR_RFFE = 1 << 5;
|
||||
/// @brief Receiver Parity Error (0: no PE, 1: PE)
|
||||
constexpr uint8_t FSR_RFPE = 1 << 4;
|
||||
/// @brief Receiver FIFO count (0: empty, 1: not empty)
|
||||
constexpr uint8_t FSR_RFDAT = 1 << 3;
|
||||
/// @brief Transmitter FIFO count (0: empty, 1: not empty)
|
||||
constexpr uint8_t FSR_TFDAT = 1 << 2;
|
||||
/// @brief Transmitter FIFO full (0: not full, 1: full)
|
||||
constexpr uint8_t FSR_TFFULL = 1 << 1;
|
||||
/// @brief Transmitter busy (0 nothing to transmit, 1: transmitter busy sending)
|
||||
constexpr uint8_t FSR_TBUSY = 1 << 0;
|
||||
|
||||
/// @brief Line Status Register (not used - using FIFO)
|
||||
constexpr uint8_t WKREG_LSR = 0x0C;
|
||||
|
||||
/// @brief FIFO Data Register (not used - does not seems to work)
|
||||
constexpr uint8_t WKREG_FDAT = 0x0D;
|
||||
|
||||
/// @}
|
||||
/// @defgroup cr_p1 Channel registers for SPAGE=1
|
||||
/// @brief Definition of the register linked to a particular channel when SPAGE=1
|
||||
/// @details The channel registers are further splitted into two groups.
|
||||
/// This second group is defined when the Global register WKREG_SPAGE is 1
|
||||
/// @{
|
||||
|
||||
/// @brief Baud rate configuration register: high byte - c0/c1 0100
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | High byte of the baud rate |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_BRH = 0x04;
|
||||
|
||||
/// @brief Baud rate configuration register: low byte - c0/c1 0101
|
||||
/// @details @code
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// | Low byte of the baud rate |
|
||||
/// -------------------------------------------------------------------------
|
||||
/// @endcode
|
||||
constexpr uint8_t WKREG_BRL = 0x05;
|
||||
|
||||
/// @brief Baud rate configuration register decimal part - c0/c1 0110
|
||||
constexpr uint8_t WKREG_BRD = 0x06;
|
||||
|
||||
/// @brief Receive FIFO Interrupt trigger configuration (not used) - c0/c1 0111
|
||||
constexpr uint8_t WKREG_RFI = 0x07;
|
||||
|
||||
/// @brief Transmit FIFO interrupt trigger configuration (not used) - c0/c1 1000
|
||||
constexpr uint8_t WKREG_TFI = 0x08;
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
} // namespace weikai
|
||||
} // namespace esphome
|
1
esphome/components/weikai_i2c/__init__.py
Normal file
1
esphome/components/weikai_i2c/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
CODEOWNERS = ["@DrCoolZic"]
|
177
esphome/components/weikai_i2c/weikai_i2c.cpp
Normal file
177
esphome/components/weikai_i2c/weikai_i2c.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
/// @file weikai_i2c.cpp
|
||||
/// @brief WeiKai component family - classes implementation
|
||||
/// @date Last Modified: 2024/04/06 14:43:31
|
||||
/// @details The classes declared in this file can be used by the Weikai family
|
||||
|
||||
#include "weikai_i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace weikai_i2c {
|
||||
static const char *const TAG = "weikai_i2c";
|
||||
|
||||
/// @brief Display a buffer in hexadecimal format (32 hex values / line).
|
||||
void print_buffer(const uint8_t *data, size_t length) {
|
||||
char hex_buffer[100];
|
||||
hex_buffer[(3 * 32) + 1] = 0;
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]);
|
||||
if (i % 32 == 31) {
|
||||
ESP_LOGVV(TAG, " %s", hex_buffer);
|
||||
}
|
||||
}
|
||||
if (length % 32) {
|
||||
// null terminate if incomplete line
|
||||
hex_buffer[3 * (length % 32) + 2] = 0;
|
||||
ESP_LOGVV(TAG, " %s", hex_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST", "GMUT", "SPAGE", "SCR", "LCR", "FCR", "SIER",
|
||||
"SIFR", "TFCNT", "RFCNT", "FSR", "LSR", "FDAT", "FWCR", "RS485"};
|
||||
static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL",
|
||||
"TFTL", "FWTH", "FWTL", "XON1", "XOFF1", "SADR", "SAEN", "RTSDLY"};
|
||||
using namespace weikai;
|
||||
// method to print a register value as text: used in the log messages ...
|
||||
const char *reg_to_str(int reg, bool page1) {
|
||||
if (reg == WKREG_GPDAT) {
|
||||
return "GPDAT";
|
||||
} else if (reg == WKREG_GPDIR) {
|
||||
return "GPDIR";
|
||||
} else {
|
||||
return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F];
|
||||
}
|
||||
}
|
||||
enum RegType { REG = 0, FIFO = 1 }; ///< Register or FIFO
|
||||
|
||||
/// @brief Computes the I²C bus's address used to access the component
|
||||
/// @param base_address the base address of the component - set by the A1 A0 pins
|
||||
/// @param channel (0-3) the UART channel
|
||||
/// @param fifo (0-1) 0 = access to internal register, 1 = direct access to fifo
|
||||
/// @return the i2c address to use
|
||||
inline uint8_t i2c_address(uint8_t base_address, uint8_t channel, RegType fifo) {
|
||||
// the address of the device is:
|
||||
// +----+----+----+----+----+----+----+----+
|
||||
// | 0 | A1 | A0 | 1 | 0 | C1 | C0 | F |
|
||||
// +----+----+----+----+----+----+----+----+
|
||||
// where:
|
||||
// - A1,A0 is the address read from A1,A0 switch
|
||||
// - C1,C0 is the channel number (in practice only 00 or 01)
|
||||
// - F is: 0 when accessing register, one when accessing FIFO
|
||||
uint8_t const addr = base_address | channel << 1 | fifo << 0;
|
||||
return addr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiRegisterI2C methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
uint8_t WeikaiRegisterI2C::read_reg() const {
|
||||
uint8_t value = 0x00;
|
||||
WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_);
|
||||
uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, REG);
|
||||
comp_i2c->set_i2c_address(address);
|
||||
auto error = comp_i2c->read_register(this->register_, &value, 1);
|
||||
if (error == i2c::NO_ERROR) {
|
||||
this->comp_->status_clear_warning();
|
||||
ESP_LOGVV(TAG, "WeikaiRegisterI2C::read_reg() @%02X reg=%s ch=%u I2C_code:%d, buf=%02X", address,
|
||||
reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value);
|
||||
} else { // error
|
||||
this->comp_->status_set_warning();
|
||||
ESP_LOGE(TAG, "WeikaiRegisterI2C::read_reg() @%02X reg=%s ch=%u I2C_code:%d, buf=%02X", address,
|
||||
reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void WeikaiRegisterI2C::read_fifo(uint8_t *data, size_t length) const {
|
||||
WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_);
|
||||
uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, FIFO);
|
||||
comp_i2c->set_i2c_address(address);
|
||||
auto error = comp_i2c->read(data, length);
|
||||
if (error == i2c::NO_ERROR) {
|
||||
this->comp_->status_clear_warning();
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
ESP_LOGVV(TAG, "WeikaiRegisterI2C::read_fifo() @%02X ch=%d I2C_code:%d len=%d buffer", address, this->channel_,
|
||||
(int) error, length);
|
||||
print_buffer(data, length);
|
||||
#endif
|
||||
} else { // error
|
||||
this->comp_->status_set_warning();
|
||||
ESP_LOGE(TAG, "WeikaiRegisterI2C::read_fifo() @%02X reg=N/A ch=%d I2C_code:%d len=%d buf=%02X...", address,
|
||||
this->channel_, (int) error, length, data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void WeikaiRegisterI2C::write_reg(uint8_t value) {
|
||||
WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_);
|
||||
uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, REG); // update the i2c bus
|
||||
comp_i2c->set_i2c_address(address);
|
||||
auto error = comp_i2c->write_register(this->register_, &value, 1);
|
||||
if (error == i2c::NO_ERROR) {
|
||||
this->comp_->status_clear_warning();
|
||||
ESP_LOGVV(TAG, "WK2168Reg::write_reg() @%02X reg=%s ch=%d I2C_code:%d buf=%02X", address,
|
||||
reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value);
|
||||
} else { // error
|
||||
this->comp_->status_set_warning();
|
||||
ESP_LOGE(TAG, "WK2168Reg::write_reg() @%02X reg=%s ch=%d I2C_code:%d buf=%d", address,
|
||||
reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value);
|
||||
}
|
||||
}
|
||||
|
||||
void WeikaiRegisterI2C::write_fifo(uint8_t *data, size_t length) {
|
||||
WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_);
|
||||
uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, FIFO); // set fifo flag
|
||||
comp_i2c->set_i2c_address(address);
|
||||
auto error = comp_i2c->write(data, length);
|
||||
if (error == i2c::NO_ERROR) {
|
||||
this->comp_->status_clear_warning();
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
ESP_LOGVV(TAG, "WK2168Reg::write_fifo() @%02X ch=%d I2C_code:%d len=%d buffer", address, this->channel_,
|
||||
(int) error, length);
|
||||
print_buffer(data, length);
|
||||
#endif
|
||||
} else { // error
|
||||
this->comp_->status_set_warning();
|
||||
ESP_LOGE(TAG, "WK2168Reg::write_fifo() @%02X reg=N/A, ch=%d I2C_code:%d len=%d, buf=%02X...", address,
|
||||
this->channel_, (int) error, length, data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiComponentI2C methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void WeikaiComponentI2C::setup() {
|
||||
// before any manipulation we store the address to base_address_ for future use
|
||||
this->base_address_ = this->address_;
|
||||
ESP_LOGCONFIG(TAG, "Setting up wk2168_i2c: %s with %d UARTs at @%02X ...", this->get_name(), this->children_.size(),
|
||||
this->base_address_);
|
||||
|
||||
// enable all channels
|
||||
this->reg(WKREG_GENA, 0) = GENA_C1EN | GENA_C2EN | GENA_C3EN | GENA_C4EN;
|
||||
// reset all channels
|
||||
this->reg(WKREG_GRST, 0) = GRST_C1RST | GRST_C2RST | GRST_C3RST | GRST_C4RST;
|
||||
// initialize the spage register to page 0
|
||||
this->reg(WKREG_SPAGE, 0) = 0;
|
||||
this->page1_ = false;
|
||||
|
||||
// we setup our children channels
|
||||
for (auto *child : this->children_) {
|
||||
child->setup_channel();
|
||||
}
|
||||
}
|
||||
|
||||
void WeikaiComponentI2C::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size());
|
||||
ESP_LOGCONFIG(TAG, " Crystal: %" PRIu32, this->crystal_);
|
||||
if (test_mode_)
|
||||
ESP_LOGCONFIG(TAG, " Test mode: %d", test_mode_);
|
||||
ESP_LOGCONFIG(TAG, " Transfer buffer size: %d", XFER_MAX_SIZE);
|
||||
this->address_ = this->base_address_; // we restore the base_address before display (less confusing)
|
||||
LOG_I2C_DEVICE(this);
|
||||
|
||||
for (auto *child : this->children_) {
|
||||
child->dump_channel();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace weikai_i2c
|
||||
} // namespace esphome
|
61
esphome/components/weikai_i2c/weikai_i2c.h
Normal file
61
esphome/components/weikai_i2c/weikai_i2c.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/// @file weikai_i2c.h
|
||||
/// @author DrCoolZic
|
||||
/// @brief WeiKai component family - classes declaration
|
||||
/// @date Last Modified: 2024/03/01 13:31:57
|
||||
/// @details The classes declared in this file can be used by the Weikai family
|
||||
/// wk2132_i2c, wk2168_i2c, wk2204_i2c, wk2212_i2c
|
||||
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/weikai/weikai.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace weikai_i2c {
|
||||
|
||||
class WeikaiComponentI2C;
|
||||
|
||||
// using namespace weikai;
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief WeikaiRegisterI2C objects acts as proxies to access remote register through an I2C Bus
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
class WeikaiRegisterI2C : public weikai::WeikaiRegister {
|
||||
public:
|
||||
uint8_t read_reg() const override;
|
||||
void write_reg(uint8_t value) override;
|
||||
void read_fifo(uint8_t *data, size_t length) const override;
|
||||
void write_fifo(uint8_t *data, size_t length) override;
|
||||
|
||||
protected:
|
||||
friend WeikaiComponentI2C;
|
||||
WeikaiRegisterI2C(weikai::WeikaiComponent *const comp, uint8_t reg, uint8_t channel)
|
||||
: weikai::WeikaiRegister(comp, reg, channel) {}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief The WeikaiComponentI2C class stores the information to the WeiKai component
|
||||
/// connected through an I2C bus.
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
class WeikaiComponentI2C : public weikai::WeikaiComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
weikai::WeikaiRegister ®(uint8_t reg, uint8_t channel) override {
|
||||
reg_i2c_.register_ = reg;
|
||||
reg_i2c_.channel_ = channel;
|
||||
return reg_i2c_;
|
||||
}
|
||||
|
||||
//
|
||||
// override Component methods
|
||||
//
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
uint8_t base_address_; ///< base address of I2C device
|
||||
WeikaiRegisterI2C reg_i2c_{this, 0, 0}; ///< init to this component
|
||||
};
|
||||
|
||||
} // namespace weikai_i2c
|
||||
} // namespace esphome
|
1
esphome/components/weikai_spi/__init__.py
Normal file
1
esphome/components/weikai_spi/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
CODEOWNERS = ["@DrCoolZic"]
|
189
esphome/components/weikai_spi/weikai_spi.cpp
Normal file
189
esphome/components/weikai_spi/weikai_spi.cpp
Normal file
|
@ -0,0 +1,189 @@
|
|||
/// @file weikai_spi.cpp
|
||||
/// @brief WeiKai component family - classes implementation
|
||||
/// @date Last Modified: 2024/04/06 14:46:09
|
||||
/// @details The classes declared in this file can be used by the Weikai family
|
||||
|
||||
#include "weikai_spi.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace weikai_spi {
|
||||
using namespace weikai;
|
||||
static const char *const TAG = "weikai_spi";
|
||||
|
||||
/// @brief convert an int to binary representation as C++ std::string
|
||||
/// @param val integer to convert
|
||||
/// @return a std::string
|
||||
inline std::string i2s(uint8_t val) { return std::bitset<8>(val).to_string(); }
|
||||
/// Convert std::string to C string
|
||||
#define I2S2CS(val) (i2s(val).c_str())
|
||||
|
||||
/// @brief measure the time elapsed between two calls
|
||||
/// @param last_time time of the previous call
|
||||
/// @return the elapsed time in microseconds
|
||||
uint32_t elapsed_ms(uint32_t &last_time) {
|
||||
uint32_t e = millis() - last_time;
|
||||
last_time = millis();
|
||||
return e;
|
||||
};
|
||||
|
||||
/// @brief Converts the parity enum value to a C string
|
||||
/// @param parity enum
|
||||
/// @return the string
|
||||
const char *p2s(uart::UARTParityOptions parity) {
|
||||
using namespace uart;
|
||||
switch (parity) {
|
||||
case UART_CONFIG_PARITY_NONE:
|
||||
return "NONE";
|
||||
case UART_CONFIG_PARITY_EVEN:
|
||||
return "EVEN";
|
||||
case UART_CONFIG_PARITY_ODD:
|
||||
return "ODD";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Display a buffer in hexadecimal format (32 hex values / line).
|
||||
void print_buffer(const uint8_t *data, size_t length) {
|
||||
char hex_buffer[100];
|
||||
hex_buffer[(3 * 32) + 1] = 0;
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]);
|
||||
if (i % 32 == 31) {
|
||||
ESP_LOGVV(TAG, " %s", hex_buffer);
|
||||
}
|
||||
}
|
||||
if (length % 32) {
|
||||
// null terminate if incomplete line
|
||||
hex_buffer[3 * (length % 32) + 2] = 0;
|
||||
ESP_LOGVV(TAG, " %s", hex_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST", "GMUT", "SPAGE", "SCR", "LCR", "FCR", "SIER",
|
||||
"SIFR", "TFCNT", "RFCNT", "FSR", "LSR", "FDAT", "FWCR", "RS485"};
|
||||
static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL",
|
||||
"TFTL", "FWTH", "FWTL", "XON1", "XOFF1", "SADR", "SAEN", "RTSDLY"};
|
||||
|
||||
// method to print a register value as text: used in the log messages ...
|
||||
const char *reg_to_str(int reg, bool page1) {
|
||||
if (reg == WKREG_GPDAT) {
|
||||
return "GPDAT";
|
||||
} else if (reg == WKREG_GPDIR) {
|
||||
return "GPDIR";
|
||||
} else {
|
||||
return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F];
|
||||
}
|
||||
}
|
||||
|
||||
enum RegType { REG = 0, FIFO = 1 }; ///< Register or FIFO
|
||||
enum CmdType { WRITE_CMD = 0, READ_CMD = 1 }; ///< Read or Write transfer
|
||||
|
||||
/// @brief Computes the SPI command byte
|
||||
/// @param transfer_type read or write command
|
||||
/// @param reg (0-15) the address of the register
|
||||
/// @param channel (0-3) the UART channel
|
||||
/// @param fifo (0-1) 0 = access to internal register, 1 = direct access to fifo
|
||||
/// @return the spi command byte
|
||||
/// @details
|
||||
/// +------+------+------+------+------+------+------+------+
|
||||
/// | FIFO | R/W | C1-C0 | A3-A0 |
|
||||
/// +------+------+-------------+---------------------------+
|
||||
/// FIFO: 0 = register, 1 = FIFO
|
||||
/// R/W: 0 = write, 1 = read
|
||||
/// C1-C0: Channel (0-1)
|
||||
/// A3-A0: Address (0-F)
|
||||
inline static uint8_t cmd_byte(RegType fifo, CmdType transfer_type, uint8_t channel, uint8_t reg) {
|
||||
return (fifo << 7 | transfer_type << 6 | channel << 4 | reg << 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiRegisterSPI methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
uint8_t WeikaiRegisterSPI::read_reg() const {
|
||||
auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_);
|
||||
uint8_t cmd = cmd_byte(REG, READ_CMD, this->channel_, this->register_);
|
||||
spi_comp->enable();
|
||||
spi_comp->write_byte(cmd);
|
||||
uint8_t val = spi_comp->read_byte();
|
||||
spi_comp->disable();
|
||||
ESP_LOGVV(TAG, "WeikaiRegisterSPI::read_reg() cmd=%s(%02X) reg=%s ch=%d buf=%02X", I2S2CS(cmd), cmd,
|
||||
reg_to_str(this->register_, this->comp_->page1()), this->channel_, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
void WeikaiRegisterSPI::read_fifo(uint8_t *data, size_t length) const {
|
||||
auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_);
|
||||
uint8_t cmd = cmd_byte(FIFO, READ_CMD, this->channel_, this->register_);
|
||||
spi_comp->enable();
|
||||
spi_comp->write_byte(cmd);
|
||||
spi_comp->read_array(data, length);
|
||||
spi_comp->disable();
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
ESP_LOGVV(TAG, "WeikaiRegisterSPI::read_fifo() cmd=%s(%02X) ch=%d len=%d buffer", I2S2CS(cmd), cmd, this->channel_,
|
||||
length);
|
||||
print_buffer(data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WeikaiRegisterSPI::write_reg(uint8_t value) {
|
||||
auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_);
|
||||
uint8_t buf[2]{cmd_byte(REG, WRITE_CMD, this->channel_, this->register_), value};
|
||||
spi_comp->enable();
|
||||
spi_comp->write_array(buf, 2);
|
||||
spi_comp->disable();
|
||||
ESP_LOGVV(TAG, "WeikaiRegisterSPI::write_reg() cmd=%s(%02X) reg=%s ch=%d buf=%02X", I2S2CS(buf[0]), buf[0],
|
||||
reg_to_str(this->register_, this->comp_->page1()), this->channel_, buf[1]);
|
||||
}
|
||||
|
||||
void WeikaiRegisterSPI::write_fifo(uint8_t *data, size_t length) {
|
||||
auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_);
|
||||
uint8_t cmd = cmd_byte(FIFO, WRITE_CMD, this->channel_, this->register_);
|
||||
spi_comp->enable();
|
||||
spi_comp->write_byte(cmd);
|
||||
spi_comp->write_array(data, length);
|
||||
spi_comp->disable();
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
ESP_LOGVV(TAG, "WeikaiRegisterSPI::write_fifo() cmd=%s(%02X) ch=%d len=%d buffer", I2S2CS(cmd), cmd, this->channel_,
|
||||
length);
|
||||
print_buffer(data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The WeikaiComponentSPI methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void WeikaiComponentSPI::setup() {
|
||||
using namespace weikai;
|
||||
ESP_LOGCONFIG(TAG, "Setting up wk2168_spi: %s with %d UARTs...", this->get_name(), this->children_.size());
|
||||
this->spi_setup();
|
||||
// enable all channels
|
||||
this->reg(WKREG_GENA, 0) = GENA_C1EN | GENA_C2EN | GENA_C3EN | GENA_C4EN;
|
||||
// reset all channels
|
||||
this->reg(WKREG_GRST, 0) = GRST_C1RST | GRST_C2RST | GRST_C3RST | GRST_C4RST;
|
||||
// initialize the spage register to page 0
|
||||
this->reg(WKREG_SPAGE, 0) = 0;
|
||||
this->page1_ = false;
|
||||
|
||||
// we setup our children channels
|
||||
for (auto *child : this->children_) {
|
||||
child->setup_channel();
|
||||
}
|
||||
}
|
||||
|
||||
void WeikaiComponentSPI::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size());
|
||||
ESP_LOGCONFIG(TAG, " Crystal: %" PRIu32 "", this->crystal_);
|
||||
if (test_mode_)
|
||||
ESP_LOGCONFIG(TAG, " Test mode: %d", test_mode_);
|
||||
ESP_LOGCONFIG(TAG, " Transfer buffer size: %d", XFER_MAX_SIZE);
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
|
||||
for (auto *child : this->children_) {
|
||||
child->dump_channel();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace weikai_spi
|
||||
} // namespace esphome
|
54
esphome/components/weikai_spi/weikai_spi.h
Normal file
54
esphome/components/weikai_spi/weikai_spi.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/// @file weikai.h
|
||||
/// @author DrCoolZic
|
||||
/// @brief WeiKai component family - classes declaration
|
||||
/// @date Last Modified: 2024/02/29 17:20:32
|
||||
/// @details The classes declared in this file can be used by the Weikai family
|
||||
/// wk2124_spi, wk2132_spi, wk2168_spi, wk2204_spi, wk2212_spi,
|
||||
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
#include "esphome/components/weikai/weikai.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace weikai_spi {
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief WeikaiRegisterSPI objects acts as proxies to access remote register through an SPI Bus
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
class WeikaiRegisterSPI : public weikai::WeikaiRegister {
|
||||
public:
|
||||
WeikaiRegisterSPI(weikai::WeikaiComponent *const comp, uint8_t reg, uint8_t channel)
|
||||
: weikai::WeikaiRegister(comp, reg, channel) {}
|
||||
|
||||
uint8_t read_reg() const override;
|
||||
void write_reg(uint8_t value) override;
|
||||
void read_fifo(uint8_t *data, size_t length) const override;
|
||||
void write_fifo(uint8_t *data, size_t length) override;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief The WeikaiComponentSPI class stores the information to the WeiKai component
|
||||
/// connected through an SPI bus.
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
class WeikaiComponentSPI : public weikai::WeikaiComponent,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1MHZ> {
|
||||
public:
|
||||
weikai::WeikaiRegister ®(uint8_t reg, uint8_t channel) override {
|
||||
reg_spi_.register_ = reg;
|
||||
reg_spi_.channel_ = channel;
|
||||
return reg_spi_;
|
||||
}
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
WeikaiRegisterSPI reg_spi_{this, 0, 0}; ///< init to this component
|
||||
};
|
||||
|
||||
} // namespace weikai_spi
|
||||
} // namespace esphome
|
30
esphome/components/wk2132_i2c/__init__.py
Normal file
30
esphome/components/wk2132_i2c/__init__.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, weikai
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["weikai", "weikai_i2c"]
|
||||
MULTI_CONF = True
|
||||
|
||||
weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c")
|
||||
WeikaiComponentI2C = weikai_i2c_ns.class_(
|
||||
"WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiComponentI2C),
|
||||
}
|
||||
).extend(i2c.i2c_device_schema(0x2C)),
|
||||
weikai.check_channel_max_2,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
4
esphome/components/wk2132_i2c/wk2132_i2c.cpp
Normal file
4
esphome/components/wk2132_i2c/wk2132_i2c.cpp
Normal file
|
@ -0,0 +1,4 @@
|
|||
/* compiling with esp-idf framework requires a .cpp file for some reason ? */
|
||||
namespace esphome {
|
||||
namespace wk2132_i2c {}
|
||||
} // namespace esphome
|
31
esphome/components/wk2132_spi/__init__.py
Normal file
31
esphome/components/wk2132_spi/__init__.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import spi, weikai
|
||||
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
AUTO_LOAD = ["weikai", "weikai_spi"]
|
||||
MULTI_CONF = True
|
||||
|
||||
weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi")
|
||||
WeikaiComponentSPI = weikai_spi_ns.class_(
|
||||
"WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiComponentSPI),
|
||||
}
|
||||
).extend(spi.spi_device_schema()),
|
||||
weikai.check_channel_max_2,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await spi.register_spi_device(var, config)
|
64
esphome/components/wk2168_i2c/__init__.py
Normal file
64
esphome/components/wk2168_i2c/__init__.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import i2c, weikai
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_INVERTED,
|
||||
CONF_MODE,
|
||||
CONF_NUMBER,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["weikai", "weikai_i2c"]
|
||||
MULTI_CONF = True
|
||||
CONF_WK2168_I2C = "wk2168_i2c"
|
||||
|
||||
weikai_ns = cg.esphome_ns.namespace("weikai")
|
||||
weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c")
|
||||
WeikaiComponentI2C = weikai_i2c_ns.class_(
|
||||
"WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice
|
||||
)
|
||||
WeikaiGPIOPin = weikai_ns.class_(
|
||||
"WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentI2C)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiComponentI2C),
|
||||
}
|
||||
).extend(i2c.i2c_device_schema(0x2C)),
|
||||
weikai.check_channel_max_4,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
|
||||
WK2168_PIN_SCHEMA = cv.All(
|
||||
weikai.WEIKAI_PIN_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiGPIOPin),
|
||||
cv.Required(CONF_WK2168_I2C): cv.use_id(WeikaiComponentI2C),
|
||||
}
|
||||
),
|
||||
weikai.validate_pin_mode,
|
||||
)
|
||||
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_I2C, WK2168_PIN_SCHEMA)
|
||||
async def sc16is75x_pin_to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
parent = await cg.get_variable(config[CONF_WK2168_I2C])
|
||||
cg.add(var.set_parent(parent))
|
||||
num = config[CONF_NUMBER]
|
||||
cg.add(var.set_pin(num))
|
||||
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
||||
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE])))
|
||||
return var
|
62
esphome/components/wk2168_spi/__init__.py
Normal file
62
esphome/components/wk2168_spi/__init__.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import spi, weikai
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_INVERTED,
|
||||
CONF_MODE,
|
||||
CONF_NUMBER,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
AUTO_LOAD = ["weikai", "weikai_spi"]
|
||||
MULTI_CONF = True
|
||||
CONF_WK2168_SPI = "wk2168_spi"
|
||||
|
||||
weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi")
|
||||
weikai_ns = cg.esphome_ns.namespace("weikai")
|
||||
WeikaiComponentSPI = weikai_spi_ns.class_(
|
||||
"WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice
|
||||
)
|
||||
WeikaiGPIOPin = weikai_ns.class_(
|
||||
"WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentSPI)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{cv.GenerateID(): cv.declare_id(WeikaiComponentSPI)}
|
||||
).extend(spi.spi_device_schema()),
|
||||
weikai.check_channel_max_4,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await spi.register_spi_device(var, config)
|
||||
|
||||
|
||||
WK2168_PIN_SCHEMA = cv.All(
|
||||
weikai.WEIKAI_PIN_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiGPIOPin),
|
||||
cv.Required(CONF_WK2168_SPI): cv.use_id(WeikaiComponentSPI),
|
||||
},
|
||||
),
|
||||
weikai.validate_pin_mode,
|
||||
)
|
||||
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_SPI, WK2168_PIN_SCHEMA)
|
||||
async def sc16is75x_pin_to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
parent = await cg.get_variable(config[CONF_WK2168_SPI])
|
||||
cg.add(var.set_parent(parent))
|
||||
num = config[CONF_NUMBER]
|
||||
cg.add(var.set_pin(num))
|
||||
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
||||
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE])))
|
||||
return var
|
30
esphome/components/wk2204_i2c/__init__.py
Normal file
30
esphome/components/wk2204_i2c/__init__.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, weikai
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["weikai", "weikai_i2c"]
|
||||
MULTI_CONF = True
|
||||
|
||||
weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c")
|
||||
WeikaiComponentI2C = weikai_i2c_ns.class_(
|
||||
"WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiComponentI2C),
|
||||
}
|
||||
).extend(i2c.i2c_device_schema(0x2C)),
|
||||
weikai.check_channel_max_4,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
30
esphome/components/wk2204_spi/__init__.py
Normal file
30
esphome/components/wk2204_spi/__init__.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import spi, weikai
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
AUTO_LOAD = ["weikai", "weikai_spi"]
|
||||
MULTI_CONF = True
|
||||
|
||||
weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi")
|
||||
WeikaiComponentSPI = weikai_spi_ns.class_(
|
||||
"WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiComponentSPI),
|
||||
}
|
||||
).extend(spi.spi_device_schema()),
|
||||
weikai.check_channel_max_4,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await spi.register_spi_device(var, config)
|
64
esphome/components/wk2212_i2c/__init__.py
Normal file
64
esphome/components/wk2212_i2c/__init__.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import i2c, weikai
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_INVERTED,
|
||||
CONF_MODE,
|
||||
CONF_NUMBER,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["weikai", "weikai_i2c"]
|
||||
MULTI_CONF = True
|
||||
CONF_WK2212_I2C = "wk2212_i2c"
|
||||
|
||||
weikai_ns = cg.esphome_ns.namespace("weikai")
|
||||
weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c")
|
||||
WeikaiComponentI2C = weikai_i2c_ns.class_(
|
||||
"WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice
|
||||
)
|
||||
WeikaiGPIOPin = weikai_ns.class_(
|
||||
"WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentI2C)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiComponentI2C),
|
||||
}
|
||||
).extend(i2c.i2c_device_schema(0x2C)),
|
||||
weikai.check_channel_max_2,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
|
||||
WK2212_PIN_SCHEMA = cv.All(
|
||||
weikai.WEIKAI_PIN_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiGPIOPin),
|
||||
cv.Required(CONF_WK2212_I2C): cv.use_id(WeikaiComponentI2C),
|
||||
}
|
||||
),
|
||||
weikai.validate_pin_mode,
|
||||
)
|
||||
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_I2C, WK2212_PIN_SCHEMA)
|
||||
async def sc16is75x_pin_to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
parent = await cg.get_variable(config[CONF_WK2212_I2C])
|
||||
cg.add(var.set_parent(parent))
|
||||
num = config[CONF_NUMBER]
|
||||
cg.add(var.set_pin(num))
|
||||
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
||||
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE])))
|
||||
return var
|
62
esphome/components/wk2212_spi/__init__.py
Normal file
62
esphome/components/wk2212_spi/__init__.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import spi, weikai
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_INVERTED,
|
||||
CONF_MODE,
|
||||
CONF_NUMBER,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@DrCoolZic"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
AUTO_LOAD = ["weikai", "weikai_spi"]
|
||||
MULTI_CONF = True
|
||||
CONF_WK2212_SPI = "wk2212_spi"
|
||||
|
||||
weikai_ns = cg.esphome_ns.namespace("weikai")
|
||||
weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi")
|
||||
WeikaiComponentSPI = weikai_spi_ns.class_(
|
||||
"WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice
|
||||
)
|
||||
WeikaiGPIOPin = weikai_ns.class_(
|
||||
"WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentSPI)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
weikai.WKBASE_SCHEMA.extend(
|
||||
{cv.GenerateID(): cv.declare_id(WeikaiComponentSPI)}
|
||||
).extend(spi.spi_device_schema()),
|
||||
weikai.check_channel_max_2,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
cg.add(var.set_name(str(config[CONF_ID])))
|
||||
await weikai.register_weikai(var, config)
|
||||
await spi.register_spi_device(var, config)
|
||||
|
||||
|
||||
WK2212_PIN_SCHEMA = cv.All(
|
||||
weikai.WEIKAI_PIN_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(WeikaiGPIOPin),
|
||||
cv.Required(CONF_WK2212_SPI): cv.use_id(WeikaiComponentSPI),
|
||||
},
|
||||
),
|
||||
weikai.validate_pin_mode,
|
||||
)
|
||||
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_SPI, WK2212_PIN_SCHEMA)
|
||||
async def sc16is75x_pin_to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
parent = await cg.get_variable(config[CONF_WK2212_SPI])
|
||||
cg.add(var.set_parent(parent))
|
||||
num = config[CONF_NUMBER]
|
||||
cg.add(var.set_pin(num))
|
||||
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
||||
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE])))
|
||||
return var
|
20
tests/components/wk2132_i2c/common.yaml
Normal file
20
tests/components/wk2132_i2c/common.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
i2c:
|
||||
id: i2c_bus
|
||||
scl: ${scl_pin}
|
||||
sda: ${sda_pin}
|
||||
scan: true
|
||||
frequency: 600kHz
|
||||
|
||||
wk2132_i2c:
|
||||
- id: wk2132_i2c_id
|
||||
address: 0x70
|
||||
i2c_id: i2c_bus
|
||||
uart:
|
||||
- id: wk2132_id_0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: wk2132_id_1
|
||||
channel: 1
|
||||
baud_rate: 19200
|
5
tests/components/wk2132_i2c/test.esp32-idf.yaml
Normal file
5
tests/components/wk2132_i2c/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2132_i2c/test.esp32-s3-idf.yaml
Normal file
5
tests/components/wk2132_i2c/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2132_i2c/test.esp32-s3.yaml
Normal file
5
tests/components/wk2132_i2c/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2132_i2c/test.esp32.yaml
Normal file
5
tests/components/wk2132_i2c/test.esp32.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
21
tests/components/wk2132_spi/common.yaml
Normal file
21
tests/components/wk2132_spi/common.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
spi:
|
||||
id: spi_bus
|
||||
clk_pin: ${clk_pin}
|
||||
mosi_pin: ${mosi_pin}
|
||||
miso_pin: ${miso_pin}
|
||||
|
||||
wk2132_spi:
|
||||
- id: wk2132_spi_id
|
||||
cs_pin: ${cs_pin}
|
||||
spi_id: spi_bus
|
||||
crystal: 11059200
|
||||
data_rate: 1MHz
|
||||
uart:
|
||||
- id: wk2132_spi_id0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: wk2132_spi_id1
|
||||
channel: 1
|
||||
baud_rate: 921600
|
7
tests/components/wk2132_spi/test.esp32-idf.yaml
Normal file
7
tests/components/wk2132_spi/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2132_spi/test.esp32-s3-idf.yaml
Normal file
7
tests/components/wk2132_spi/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2132_spi/test.esp32-s3.yaml
Normal file
7
tests/components/wk2132_spi/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2132_spi/test.esp32.yaml
Normal file
7
tests/components/wk2132_spi/test.esp32.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
63
tests/components/wk2168_i2c/common.yaml
Normal file
63
tests/components/wk2168_i2c/common.yaml
Normal file
|
@ -0,0 +1,63 @@
|
|||
i2c:
|
||||
id: i2c_bus
|
||||
scl: ${scl_pin}
|
||||
sda: ${sda_pin}
|
||||
scan: true
|
||||
frequency: 600kHz
|
||||
|
||||
# component declaration
|
||||
wk2168_i2c:
|
||||
- id: bridge_i2c
|
||||
i2c_id: i2c_bus
|
||||
address: 0x70
|
||||
uart:
|
||||
- id: id0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: id1
|
||||
channel: 1
|
||||
baud_rate: 115200
|
||||
- id: id2
|
||||
channel: 2
|
||||
baud_rate: 115200
|
||||
- id: id3
|
||||
channel: 3
|
||||
baud_rate: 115200
|
||||
|
||||
# individual binary_sensor inputs
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: "pin_0"
|
||||
pin:
|
||||
wk2168_i2c: bridge_i2c
|
||||
number: 0
|
||||
mode:
|
||||
input: true
|
||||
- platform: gpio
|
||||
name: "pin_1"
|
||||
pin:
|
||||
wk2168_i2c: bridge_i2c
|
||||
number: 1
|
||||
mode:
|
||||
input: true
|
||||
inverted: true
|
||||
|
||||
# Individual binary outputs
|
||||
switch:
|
||||
- platform: gpio
|
||||
name: "pin_2"
|
||||
pin:
|
||||
wk2168_i2c: bridge_i2c
|
||||
number: 2
|
||||
mode:
|
||||
output: true
|
||||
- platform: gpio
|
||||
name: "pin_3"
|
||||
pin:
|
||||
wk2168_i2c: bridge_i2c
|
||||
number: 3
|
||||
mode:
|
||||
output: true
|
||||
inverted: true
|
5
tests/components/wk2168_i2c/test.esp32-idf.yaml
Normal file
5
tests/components/wk2168_i2c/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2168_i2c/test.esp32-s3-idf.yaml
Normal file
5
tests/components/wk2168_i2c/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2168_i2c/test.esp32-s3.yaml
Normal file
5
tests/components/wk2168_i2c/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2168_i2c/test.esp32.yaml
Normal file
5
tests/components/wk2168_i2c/test.esp32.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
63
tests/components/wk2168_spi/common.yaml
Normal file
63
tests/components/wk2168_spi/common.yaml
Normal file
|
@ -0,0 +1,63 @@
|
|||
spi:
|
||||
id: spi_bus
|
||||
clk_pin: ${clk_pin}
|
||||
mosi_pin: ${mosi_pin}
|
||||
miso_pin: ${miso_pin}
|
||||
|
||||
wk2168_spi:
|
||||
- id: bridge_spi
|
||||
cs_pin: ${cs_pin}
|
||||
spi_id: spi_bus
|
||||
crystal: 11059200
|
||||
data_rate: 1MHz
|
||||
uart:
|
||||
- id: id0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: id1
|
||||
channel: 1
|
||||
baud_rate: 115200
|
||||
- id: id2
|
||||
channel: 2
|
||||
baud_rate: 115200
|
||||
- id: id3
|
||||
channel: 3
|
||||
baud_rate: 115200
|
||||
|
||||
# individual binary_sensor inputs
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: "pin_0"
|
||||
pin:
|
||||
wk2168_spi: bridge_spi
|
||||
number: 0
|
||||
mode:
|
||||
input: true
|
||||
- platform: gpio
|
||||
name: "pin_1"
|
||||
pin:
|
||||
wk2168_spi: bridge_spi
|
||||
number: 1
|
||||
mode:
|
||||
input: true
|
||||
inverted: true
|
||||
|
||||
# Individual binary outputs
|
||||
switch:
|
||||
- platform: gpio
|
||||
name: "pin_2"
|
||||
pin:
|
||||
wk2168_spi: bridge_spi
|
||||
number: 2
|
||||
mode:
|
||||
output: true
|
||||
- platform: gpio
|
||||
name: "pin_3"
|
||||
pin:
|
||||
wk2168_spi: bridge_spi
|
||||
number: 3
|
||||
mode:
|
||||
output: true
|
||||
inverted: true
|
7
tests/components/wk2168_spi/test.esp32-idf.yaml
Normal file
7
tests/components/wk2168_spi/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2168_spi/test.esp32-s3-idf.yaml
Normal file
7
tests/components/wk2168_spi/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2168_spi/test.esp32-s3.yaml
Normal file
7
tests/components/wk2168_spi/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2168_spi/test.esp32.yaml
Normal file
7
tests/components/wk2168_spi/test.esp32.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
28
tests/components/wk2204_i2c/common.yaml
Normal file
28
tests/components/wk2204_i2c/common.yaml
Normal file
|
@ -0,0 +1,28 @@
|
|||
i2c:
|
||||
id: i2c_bus
|
||||
scl: ${scl_pin}
|
||||
sda: ${sda_pin}
|
||||
scan: true
|
||||
frequency: 600kHz
|
||||
|
||||
wk2204_i2c:
|
||||
- id: wk2204_i2c_id
|
||||
i2c_id: i2c_bus
|
||||
address: 0x70
|
||||
uart:
|
||||
- id: wk2204_id_0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: wk2204_id_1
|
||||
channel: 1
|
||||
baud_rate: 19200
|
||||
- id: wk2204_id_2
|
||||
channel: 2
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: wk2204_id_3
|
||||
channel: 3
|
||||
baud_rate: 19200
|
5
tests/components/wk2204_i2c/test.esp32-idf.yaml
Normal file
5
tests/components/wk2204_i2c/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2204_i2c/test.esp32-s3-idf.yaml
Normal file
5
tests/components/wk2204_i2c/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2204_i2c/test.esp32-s3.yaml
Normal file
5
tests/components/wk2204_i2c/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2204_i2c/test.esp32.yaml
Normal file
5
tests/components/wk2204_i2c/test.esp32.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
29
tests/components/wk2204_spi/common.yaml
Normal file
29
tests/components/wk2204_spi/common.yaml
Normal file
|
@ -0,0 +1,29 @@
|
|||
spi:
|
||||
id: spi_bus
|
||||
clk_pin: ${clk_pin}
|
||||
mosi_pin: ${mosi_pin}
|
||||
miso_pin: ${miso_pin}
|
||||
|
||||
wk2204_spi:
|
||||
- id: wk2204_spi_id
|
||||
cs_pin: ${cs_pin}
|
||||
spi_id: spi_bus
|
||||
crystal: 11059200
|
||||
data_rate: 1MHz
|
||||
uart:
|
||||
- id: wk2204_spi_id0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: wk2204_spi_id1
|
||||
channel: 1
|
||||
baud_rate: 921600
|
||||
- id: wk2204_spi_id2
|
||||
channel: 2
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: wk2204_spi_id3
|
||||
channel: 3
|
||||
baud_rate: 921600
|
7
tests/components/wk2204_spi/test.esp32-idf.yaml
Normal file
7
tests/components/wk2204_spi/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2204_spi/test.esp32-s3-idf.yaml
Normal file
7
tests/components/wk2204_spi/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2204_spi/test.esp32-s3.yaml
Normal file
7
tests/components/wk2204_spi/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2204_spi/test.esp32.yaml
Normal file
7
tests/components/wk2204_spi/test.esp32.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
59
tests/components/wk2212_i2c/common.yaml
Normal file
59
tests/components/wk2212_i2c/common.yaml
Normal file
|
@ -0,0 +1,59 @@
|
|||
i2c:
|
||||
id: i2c_bus
|
||||
scl: ${scl_pin}
|
||||
sda: ${sda_pin}
|
||||
scan: true
|
||||
frequency: 600kHz
|
||||
|
||||
# component declaration
|
||||
wk2212_i2c:
|
||||
- id: bridge_i2c
|
||||
i2c_id: i2c_bus
|
||||
address: 0x70
|
||||
uart:
|
||||
- id: uart_i2c_id0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: uart_i2c_id1
|
||||
channel: 1
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
|
||||
# individual binary_sensor inputs
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: "pin_0"
|
||||
pin:
|
||||
wk2212_i2c: bridge_i2c
|
||||
number: 0
|
||||
mode:
|
||||
input: true
|
||||
- platform: gpio
|
||||
name: "pin_1"
|
||||
pin:
|
||||
wk2212_i2c: bridge_i2c
|
||||
number: 1
|
||||
mode:
|
||||
input: true
|
||||
inverted: true
|
||||
|
||||
# Individual binary outputs
|
||||
switch:
|
||||
- platform: gpio
|
||||
name: "pin_2"
|
||||
pin:
|
||||
wk2212_i2c: bridge_i2c
|
||||
number: 2
|
||||
mode:
|
||||
output: true
|
||||
- platform: gpio
|
||||
name: "pin_3"
|
||||
pin:
|
||||
wk2212_i2c: bridge_i2c
|
||||
number: 3
|
||||
mode:
|
||||
output: true
|
||||
inverted: true
|
5
tests/components/wk2212_i2c/test.esp32-idf.yaml
Normal file
5
tests/components/wk2212_i2c/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2212_i2c/test.esp32-s3-idf.yaml
Normal file
5
tests/components/wk2212_i2c/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2212_i2c/test.esp32-s3.yaml
Normal file
5
tests/components/wk2212_i2c/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO40
|
||||
sda_pin: GPIO41
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/wk2212_i2c/test.esp32.yaml
Normal file
5
tests/components/wk2212_i2c/test.esp32.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO22
|
||||
sda_pin: GPIO21
|
||||
|
||||
<<: !include common.yaml
|
58
tests/components/wk2212_spi/common.yaml
Normal file
58
tests/components/wk2212_spi/common.yaml
Normal file
|
@ -0,0 +1,58 @@
|
|||
spi:
|
||||
id: spi_bus
|
||||
clk_pin: ${clk_pin}
|
||||
mosi_pin: ${mosi_pin}
|
||||
miso_pin: ${miso_pin}
|
||||
|
||||
wk2212_spi:
|
||||
- id: bridge_spi
|
||||
cs_pin: ${cs_pin}
|
||||
spi_id: spi_bus
|
||||
crystal: 11059200
|
||||
data_rate: 1MHz
|
||||
uart:
|
||||
- id: id0
|
||||
channel: 0
|
||||
baud_rate: 115200
|
||||
stop_bits: 1
|
||||
parity: none
|
||||
- id: id1
|
||||
channel: 1
|
||||
baud_rate: 115200
|
||||
|
||||
# individual binary_sensor inputs
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: "pin_0"
|
||||
pin:
|
||||
wk2212_spi: bridge_spi
|
||||
number: 0
|
||||
mode:
|
||||
input: true
|
||||
- platform: gpio
|
||||
name: "pin_1"
|
||||
pin:
|
||||
wk2212_spi: bridge_spi
|
||||
number: 1
|
||||
mode:
|
||||
input: true
|
||||
inverted: true
|
||||
|
||||
# Individual binary outputs
|
||||
switch:
|
||||
- platform: gpio
|
||||
name: "pin_2"
|
||||
pin:
|
||||
wk2212_spi: bridge_spi
|
||||
number: 2
|
||||
mode:
|
||||
output: true
|
||||
- platform: gpio
|
||||
name: "pin_3"
|
||||
pin:
|
||||
wk2212_spi: bridge_spi
|
||||
number: 3
|
||||
mode:
|
||||
output: true
|
||||
inverted: true
|
||||
|
7
tests/components/wk2212_spi/test.esp32-idf.yaml
Normal file
7
tests/components/wk2212_spi/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2212_spi/test.esp32-s3-idf.yaml
Normal file
7
tests/components/wk2212_spi/test.esp32-s3-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2212_spi/test.esp32-s3.yaml
Normal file
7
tests/components/wk2212_spi/test.esp32-s3.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO40
|
||||
miso_pin: GPIO41
|
||||
mosi_pin: GPIO6
|
||||
cs_pin: GPIO19
|
||||
|
||||
<<: !include common.yaml
|
7
tests/components/wk2212_spi/test.esp32.yaml
Normal file
7
tests/components/wk2212_spi/test.esp32.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
substitutions:
|
||||
clk_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
mosi_pin: GPIO23
|
||||
cs_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
Loading…
Reference in a new issue