mirror of
https://github.com/esphome/esphome.git
synced 2026-10-21 13:34:12 +00:00
[tcp] Keep the receive buffer in static memory
Code generation declares the TCP link's receive buffer as a static array of max_packet_size bytes, so it is not allocated at run time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b8795fcd33
commit
8edaf1f53c
@@ -8,6 +8,7 @@ from esphome.components.const import (
|
||||
CONF_ROLE,
|
||||
)
|
||||
from esphome.components.packet_interface import (
|
||||
CONF_MAX_PACKET_SIZE,
|
||||
new_packet_interface,
|
||||
packet_interface_schema,
|
||||
)
|
||||
@@ -81,7 +82,12 @@ CONFIG_SCHEMA = cv.typed_schema(
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = await 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 new_packet_interface(config, cg.RawExpression(rx_buffer))
|
||||
if config[CONF_ROLE] == "server":
|
||||
socket.require_tcp_listener()
|
||||
cg.add(var.set_server(True))
|
||||
|
||||
@@ -15,13 +15,12 @@ static constexpr size_t LENGTH_SIZE = 2;
|
||||
// The peer is gone when nothing has been received for this many keep-alive intervals
|
||||
static constexpr uint32_t KEEP_ALIVE_MISSES = 3;
|
||||
|
||||
TcpPacketInterface::TcpPacketInterface() {
|
||||
TcpPacketInterface::TcpPacketInterface(uint8_t *rx_buffer) : rx_buffer_(rx_buffer) {
|
||||
this->capabilities_ = packet_interface::CAPABILITY_RELIABILITY | packet_interface::CAPABILITY_SESSION |
|
||||
packet_interface::CAPABILITY_ADDRESSING;
|
||||
}
|
||||
|
||||
void TcpPacketInterface::setup() {
|
||||
this->rx_buffer_ = std::make_unique<uint8_t[]>(this->max_packet_size_);
|
||||
this->link_.begin(TAG);
|
||||
#ifdef USE_SOCKET_TCP_LISTENER
|
||||
this->listener_.begin(TAG);
|
||||
@@ -108,7 +107,7 @@ void TcpPacketInterface::read_() {
|
||||
if (this->rx_have_ < LENGTH_SIZE) {
|
||||
count = this->link_.read(this->rx_header_ + this->rx_have_, LENGTH_SIZE - this->rx_have_);
|
||||
} else {
|
||||
count = this->link_.read(this->rx_buffer_.get() + this->rx_have_ - LENGTH_SIZE,
|
||||
count = this->link_.read(this->rx_buffer_ + this->rx_have_ - LENGTH_SIZE,
|
||||
this->rx_length_ + LENGTH_SIZE - this->rx_have_);
|
||||
}
|
||||
// Nothing more for now; a dropped link is seen on the next loop
|
||||
@@ -134,7 +133,7 @@ void TcpPacketInterface::read_() {
|
||||
this->rx_have_ = 0;
|
||||
// A zero length packet is a keep-alive
|
||||
if (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_), {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "esphome/components/packet_interface/packet_interface.h"
|
||||
#include "esphome/components/socket/tcp_client_link.h"
|
||||
@@ -31,7 +30,8 @@ namespace esphome::tcp {
|
||||
*/
|
||||
class TcpPacketInterface : public packet_interface::PacketInterface {
|
||||
public:
|
||||
TcpPacketInterface();
|
||||
/// @param rx_buffer Holds max_packet_size bytes of the packet being received; must outlive the link
|
||||
explicit TcpPacketInterface(uint8_t *rx_buffer);
|
||||
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
@@ -69,8 +69,7 @@ class TcpPacketInterface : public packet_interface::PacketInterface {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
binary_sensor::BinarySensor *connected_sensor_{nullptr};
|
||||
#endif
|
||||
// The packet being received, allocated in setup()
|
||||
std::unique_ptr<uint8_t[]> rx_buffer_;
|
||||
uint8_t *const rx_buffer_;
|
||||
uint32_t keep_alive_ms_{10000};
|
||||
uint32_t last_rx_ms_{0};
|
||||
uint32_t last_tx_ms_{0};
|
||||
|
||||
@@ -27,12 +27,15 @@ using Packet = std::vector<uint8_t>;
|
||||
|
||||
class TestTcp : public TcpPacketInterface {
|
||||
public:
|
||||
TestTcp() {
|
||||
TestTcp() : TcpPacketInterface(this->rx_buffer_storage) {
|
||||
this->set_max_packet_size(64);
|
||||
this->set_host("peer");
|
||||
this->set_port(1);
|
||||
}
|
||||
socket::TcpClientLink &link() { return this->link_; }
|
||||
|
||||
// The base class only keeps the pointer, so the storage can be a member set up after it
|
||||
uint8_t rx_buffer_storage[64]{};
|
||||
};
|
||||
|
||||
// A layer stacked on the link, to check that the session state reaches it
|
||||
|
||||
Reference in New Issue
Block a user