[packet_interface] Keep the UART receive buffer in static memory, fix clang-tidy

- Code generation declares the UART link's receive buffer as a static
  array of max_packet_size bytes, so it is not allocated at run time
- Move the increment out of the condition in note_received_()
- Initialise the UART transmit copy buffer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
clydebarrow
2026-10-19 14:40:08 +11:00
co-authored by Claude Opus 5.5
parent bfb4b3ddfe
commit 574e9f4687
5 changed files with 29 additions and 15 deletions
@@ -28,9 +28,12 @@ void PacketInterface::on_receive_from_interface_(const PacketBuffer &data, const
void PacketInterface::note_received_(bool understood) {
if (understood) {
this->not_understood_count_ = 0;
} else if (this->not_understood_count_ < MISMATCH_COUNT && ++this->not_understood_count_ == MISMATCH_COUNT) {
ESP_LOGW(TAG, "%s: %u packets in a row could not be understood; check that both ends have the same layers",
this->name_, MISMATCH_COUNT);
} else if (this->not_understood_count_ < MISMATCH_COUNT) {
this->not_understood_count_++;
if (this->not_understood_count_ == MISMATCH_COUNT) {
ESP_LOGW(TAG, "%s: %u packets in a row could not be understood; check that both ends have the same layers",
this->name_, MISMATCH_COUNT);
}
}
}
} // namespace esphome::packet_interface
@@ -1,5 +1,10 @@
import esphome.codegen as cg
from esphome.components import packet_interface, uart
from esphome.components.packet_interface import packet_interface_schema
from esphome.components.packet_interface import (
CONF_MAX_PACKET_SIZE,
packet_interface_schema,
)
from esphome.const import CONF_ID
from esphome.types import ConfigType
from .. import uart_ns
@@ -20,5 +25,12 @@ CONFIG_SCHEMA = packet_interface_schema(UartPacketInterface, 508).extend(
async def to_code(config: ConfigType) -> None:
var = await packet_interface.new_packet_interface(config)
# The receive buffer's size is known here, so it is a static array rather than allocated at run time
rx_buffer = f"{config[CONF_ID].id}__rx_buffer"
cg.add_global(
cg.RawStatement(f"static uint8_t {rx_buffer}[{config[CONF_MAX_PACKET_SIZE]}];")
)
var = await packet_interface.new_packet_interface(
config, cg.RawExpression(rx_buffer)
)
await uart.register_uart_device(var, config)
@@ -14,8 +14,6 @@ static constexpr uint8_t ESCAPE_XOR = 0x20;
// Raw bytes escaped and written per UART write
static constexpr size_t TX_CHUNK_SIZE = 32;
void UartPacketInterface::setup() { this->rx_buffer_ = std::make_unique<uint8_t[]>(this->max_packet_size_); }
void UartPacketInterface::loop() {
while (this->available()) {
uint8_t byte;
@@ -26,7 +24,7 @@ void UartPacketInterface::loop() {
if (byte == FLAG_BYTE) {
// A flag that ends a frame also starts the next, so an unfinished frame cannot hide the one after it
if (this->rx_started_ && this->rx_length_ != 0)
this->on_receive_from_interface_(PacketBuffer(this->rx_buffer_.get(), this->rx_length_), {});
this->on_receive_from_interface_(PacketBuffer(this->rx_buffer_, this->rx_length_), {});
this->rx_started_ = true;
this->rx_length_ = 0;
this->rx_control_ = false;
@@ -60,7 +58,7 @@ bool UartPacketInterface::send_to_interface(const PacketBuffer &data, const Pack
ESP_LOGW(TAG, "Packet of %zu bytes is larger than %zu", size, this->max_packet_size_);
return false;
}
uint8_t raw[TX_CHUNK_SIZE];
uint8_t raw[TX_CHUNK_SIZE]{};
// Every byte may be escaped, plus a flag byte at each end
uint8_t out[TX_CHUNK_SIZE * 2 + 2];
size_t out_len = 0;
@@ -1,7 +1,5 @@
#pragma once
#include <memory>
#include "esphome/components/packet_interface/packet_interface.h"
#include "esphome/components/uart/uart.h"
@@ -16,14 +14,15 @@ namespace esphome::uart {
*/
class UartPacketInterface : public packet_interface::PacketInterface, public UARTDevice {
public:
void setup() override;
/// @param rx_buffer Holds max_packet_size bytes of unescaped received data; must outlive the link
explicit UartPacketInterface(uint8_t *rx_buffer) : rx_buffer_(rx_buffer) {}
void loop() override;
bool send_to_interface(const packet_interface::PacketBuffer &data,
const packet_interface::PacketMetaData &meta_data) override;
protected:
// Holds max_packet_size_ bytes of unescaped received data
std::unique_ptr<uint8_t[]> rx_buffer_;
uint8_t *const rx_buffer_;
size_t rx_length_{0};
bool rx_started_{};
bool rx_control_{};
@@ -16,7 +16,9 @@ using packet_interface::PacketMetaData;
class UartPacketInterfaceTest : public ::testing::Test {
protected:
MockUARTComponent uart_{};
UartPacketInterface interface_{};
// As large as the default max_packet_size; tests only make it smaller
uint8_t rx_buffer_[512]{};
UartPacketInterface interface_{this->rx_buffer_};
std::vector<std::vector<uint8_t>> received_packets_;
void SetUp() override {