mirror of
https://github.com/esphome/esphome.git
synced 2025-07-29 14:46:40 +00:00
[uart] Add packet_transport platform (#8214)
Co-authored-by: Faidon Liambotis <paravoid@debian.org> Co-authored-by: clydeps <U5yx99dok9> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
ad99d7fb45
commit
e7a2b395fd
@ -468,6 +468,7 @@ esphome/components/tuya/switch/* @jesserockz
|
|||||||
esphome/components/tuya/text_sensor/* @dentra
|
esphome/components/tuya/text_sensor/* @dentra
|
||||||
esphome/components/uart/* @esphome/core
|
esphome/components/uart/* @esphome/core
|
||||||
esphome/components/uart/button/* @ssieb
|
esphome/components/uart/button/* @ssieb
|
||||||
|
esphome/components/uart/packet_transport/* @clydebarrow
|
||||||
esphome/components/udp/* @clydebarrow
|
esphome/components/udp/* @clydebarrow
|
||||||
esphome/components/ufire_ec/* @pvizeli
|
esphome/components/ufire_ec/* @pvizeli
|
||||||
esphome/components/ufire_ise/* @pvizeli
|
esphome/components/ufire_ise/* @pvizeli
|
||||||
|
20
esphome/components/uart/packet_transport/__init__.py
Normal file
20
esphome/components/uart/packet_transport/__init__.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from esphome.components.packet_transport import (
|
||||||
|
PacketTransport,
|
||||||
|
new_packet_transport,
|
||||||
|
transport_schema,
|
||||||
|
)
|
||||||
|
from esphome.cpp_types import PollingComponent
|
||||||
|
|
||||||
|
from .. import UART_DEVICE_SCHEMA, register_uart_device, uart_ns
|
||||||
|
|
||||||
|
CODEOWNERS = ["@clydebarrow"]
|
||||||
|
DEPENDENCIES = ["uart"]
|
||||||
|
|
||||||
|
UARTTransport = uart_ns.class_("UARTTransport", PacketTransport, PollingComponent)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = transport_schema(UARTTransport).extend(UART_DEVICE_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var, _ = await new_packet_transport(config)
|
||||||
|
await register_uart_device(var, config)
|
88
esphome/components/uart/packet_transport/uart_transport.cpp
Normal file
88
esphome/components/uart/packet_transport/uart_transport.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
#include "uart_transport.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uart {
|
||||||
|
|
||||||
|
static const char *const TAG = "uart_transport";
|
||||||
|
|
||||||
|
void UARTTransport::loop() {
|
||||||
|
PacketTransport::loop();
|
||||||
|
|
||||||
|
while (this->parent_->available()) {
|
||||||
|
uint8_t byte;
|
||||||
|
if (!this->parent_->read_byte(&byte)) {
|
||||||
|
ESP_LOGW(TAG, "Failed to read byte from UART");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (byte == FLAG_BYTE) {
|
||||||
|
if (this->rx_started_ && this->receive_buffer_.size() > 6) {
|
||||||
|
auto len = this->receive_buffer_.size();
|
||||||
|
auto crc = crc16(this->receive_buffer_.data(), len - 2);
|
||||||
|
if (crc != (this->receive_buffer_[len - 2] | (this->receive_buffer_[len - 1] << 8))) {
|
||||||
|
ESP_LOGD(TAG, "CRC mismatch, discarding packet");
|
||||||
|
this->rx_started_ = false;
|
||||||
|
this->receive_buffer_.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this->receive_buffer_.resize(len - 2);
|
||||||
|
this->process_(this->receive_buffer_);
|
||||||
|
this->rx_started_ = false;
|
||||||
|
} else {
|
||||||
|
this->rx_started_ = true;
|
||||||
|
}
|
||||||
|
this->receive_buffer_.clear();
|
||||||
|
this->rx_control_ = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!this->rx_started_)
|
||||||
|
continue;
|
||||||
|
if (byte == CONTROL_BYTE) {
|
||||||
|
this->rx_control_ = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this->rx_control_) {
|
||||||
|
byte ^= 0x20;
|
||||||
|
this->rx_control_ = false;
|
||||||
|
}
|
||||||
|
if (this->receive_buffer_.size() == MAX_PACKET_SIZE) {
|
||||||
|
ESP_LOGD(TAG, "Packet too large, discarding");
|
||||||
|
this->rx_started_ = false;
|
||||||
|
this->receive_buffer_.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this->receive_buffer_.push_back(byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UARTTransport::update() {
|
||||||
|
this->updated_ = true;
|
||||||
|
this->resend_data_ = true;
|
||||||
|
PacketTransport::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a byte to the UART bus. If the byte is a flag or control byte, it will be escaped.
|
||||||
|
* @param byte The byte to write.
|
||||||
|
*/
|
||||||
|
void UARTTransport::write_byte_(uint8_t byte) const {
|
||||||
|
if (byte == FLAG_BYTE || byte == CONTROL_BYTE) {
|
||||||
|
this->parent_->write_byte(CONTROL_BYTE);
|
||||||
|
byte ^= 0x20;
|
||||||
|
}
|
||||||
|
this->parent_->write_byte(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UARTTransport::send_packet(std::vector<uint8_t> &buf) const {
|
||||||
|
this->parent_->write_byte(FLAG_BYTE);
|
||||||
|
for (uint8_t byte : buf) {
|
||||||
|
this->write_byte_(byte);
|
||||||
|
}
|
||||||
|
auto crc = crc16(buf.data(), buf.size());
|
||||||
|
this->write_byte_(crc & 0xFF);
|
||||||
|
this->write_byte_(crc >> 8);
|
||||||
|
this->parent_->write_byte(FLAG_BYTE);
|
||||||
|
}
|
||||||
|
} // namespace uart
|
||||||
|
} // namespace esphome
|
41
esphome/components/uart/packet_transport/uart_transport.h
Normal file
41
esphome/components/uart/packet_transport/uart_transport.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/packet_transport/packet_transport.h"
|
||||||
|
#include <vector>
|
||||||
|
#include "../uart.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A transport protocol for sending and receiving packets over a UART connection.
|
||||||
|
* The protocol is based on Asynchronous HDLC framing. (https://en.wikipedia.org/wiki/High-Level_Data_Link_Control)
|
||||||
|
* There are two special bytes: FLAG_BYTE and CONTROL_BYTE.
|
||||||
|
* A 16-bit CRC is appended to the packet, then
|
||||||
|
* the protocol wraps the resulting data between FLAG_BYTEs.
|
||||||
|
* Any occurrence of FLAG_BYTE or CONTROL_BYTE in the data is escaped by emitting CONTROL_BYTE followed by the byte
|
||||||
|
* XORed with 0x20.
|
||||||
|
*/
|
||||||
|
static const uint16_t MAX_PACKET_SIZE = 508;
|
||||||
|
static const uint8_t FLAG_BYTE = 0x7E;
|
||||||
|
static const uint8_t CONTROL_BYTE = 0x7D;
|
||||||
|
|
||||||
|
class UARTTransport : public packet_transport::PacketTransport, public UARTDevice {
|
||||||
|
public:
|
||||||
|
void loop() override;
|
||||||
|
void update() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::PROCESSOR; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_byte_(uint8_t byte) const;
|
||||||
|
void send_packet(std::vector<uint8_t> &buf) const override;
|
||||||
|
bool should_send() override { return true; };
|
||||||
|
size_t get_max_packet_size() override { return MAX_PACKET_SIZE; }
|
||||||
|
std::vector<uint8_t> receive_buffer_{};
|
||||||
|
bool rx_started_{};
|
||||||
|
bool rx_control_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uart
|
||||||
|
} // namespace esphome
|
@ -13,3 +13,6 @@ uart:
|
|||||||
rx_buffer_size: 512
|
rx_buffer_size: 512
|
||||||
parity: EVEN
|
parity: EVEN
|
||||||
stop_bits: 2
|
stop_bits: 2
|
||||||
|
|
||||||
|
packet_transport:
|
||||||
|
- platform: uart
|
||||||
|
Loading…
x
Reference in New Issue
Block a user