diff --git a/esphome/components/ld2410/ld2410.cpp b/esphome/components/ld2410/ld2410.cpp index a3c2193d672..f8f782f804a 100644 --- a/esphome/components/ld2410/ld2410.cpp +++ b/esphome/components/ld2410/ld2410.cpp @@ -601,28 +601,11 @@ void LD2410Component::readline_(int readch) { return; // No data available } - // Frame header synchronization: verify first 4 bytes match a known frame header. - // This prevents the parser from getting stuck in an overflow loop after losing sync - // (e.g. after module restart or UART noise). - if (this->buffer_pos_ < HEADER_FOOTER_SIZE) { - const uint8_t byte = static_cast(readch); - // Verify header bytes match the frame type established by byte 0 - if (this->buffer_pos_ > 0) { - const uint8_t *expected = (this->buffer_data_[0] == DATA_FRAME_HEADER[0]) ? DATA_FRAME_HEADER : CMD_FRAME_HEADER; - if (byte != expected[this->buffer_pos_]) { - this->buffer_pos_ = 0; // Reset and fall through to check if this byte starts a new frame - } - } - // First byte must match start of a data or command frame header - if (this->buffer_pos_ == 0 && byte != DATA_FRAME_HEADER[0] && byte != CMD_FRAME_HEADER[0]) { - return; - } - } - if (this->buffer_pos_ < MAX_LINE_LENGTH - 1) { this->buffer_data_[this->buffer_pos_++] = readch; this->buffer_data_[this->buffer_pos_] = 0; } else { + // We should never get here, but just in case... ESP_LOGW(TAG, "Max command length exceeded; ignoring"); this->buffer_pos_ = 0; return; diff --git a/esphome/components/ld2420/ld2420.h b/esphome/components/ld2420/ld2420.h index 02250c59114..358793fe64f 100644 --- a/esphome/components/ld2420/ld2420.h +++ b/esphome/components/ld2420/ld2420.h @@ -21,7 +21,9 @@ namespace esphome::ld2420 { static constexpr uint8_t CALIBRATE_SAMPLES = 64; -static constexpr uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer +// Energy frame is 45 bytes; +1 for null terminator, +4 so that a frame footer always lands +// inside the buffer during footer-based resynchronization after losing sync. +static constexpr uint8_t MAX_LINE_LENGTH = 50; static constexpr uint8_t TOTAL_GATES = 16; enum OpMode : uint8_t { diff --git a/esphome/components/ld2450/ld2450.cpp b/esphome/components/ld2450/ld2450.cpp index 2af45235a39..d30c1647695 100644 --- a/esphome/components/ld2450/ld2450.cpp +++ b/esphome/components/ld2450/ld2450.cpp @@ -769,28 +769,11 @@ void LD2450Component::readline_(int readch) { return; // No data available } - // Frame header synchronization: verify first 4 bytes match a known frame header. - // This prevents the parser from accumulating mid-frame data after losing sync - // (e.g. after module restart or UART noise). - if (this->buffer_pos_ < HEADER_FOOTER_SIZE) { - const uint8_t byte = static_cast(readch); - // Verify header bytes match the frame type established by byte 0 - if (this->buffer_pos_ > 0) { - const uint8_t *expected = (this->buffer_data_[0] == DATA_FRAME_HEADER[0]) ? DATA_FRAME_HEADER : CMD_FRAME_HEADER; - if (byte != expected[this->buffer_pos_]) { - this->buffer_pos_ = 0; // Reset and fall through to check if this byte starts a new frame - } - } - // First byte must match start of a data or command frame header - if (this->buffer_pos_ == 0 && byte != DATA_FRAME_HEADER[0] && byte != CMD_FRAME_HEADER[0]) { - return; - } - } - if (this->buffer_pos_ < MAX_LINE_LENGTH - 1) { this->buffer_data_[this->buffer_pos_++] = readch; this->buffer_data_[this->buffer_pos_] = 0; } else { + // We should never get here, but just in case... ESP_LOGW(TAG, "Max command length exceeded; ignoring"); this->buffer_pos_ = 0; return; diff --git a/tests/components/ld2450/ld2450_readline.cpp b/tests/components/ld2450/ld2450_readline.cpp index 66dec7a36b4..cb97f633bfb 100644 --- a/tests/components/ld2450/ld2450_readline.cpp +++ b/tests/components/ld2450/ld2450_readline.cpp @@ -93,10 +93,7 @@ TEST_F(LD2450ReadlineTest, CmdFooterInGarbageResyncs) { TEST_F(LD2450ReadlineTest, OverflowResetsBuffer) { // Fill the buffer to capacity with filler that won't match any footer. // MAX_LINE_LENGTH is 45, usable is 44. The 45th byte triggers overflow. - std::vector overflow_data; - for (int i = 0; i < MAX_LINE_LENGTH; i++) { - overflow_data.push_back(0x11); // Filler that won't match any footer - } + std::vector overflow_data(MAX_LINE_LENGTH, 0x11); this->ld2450_.feed(overflow_data); // After overflow, buffer_pos_ resets to 0 (via the < 4 early return path) EXPECT_LT(this->ld2450_.buffer_pos_, 4); @@ -104,10 +101,7 @@ TEST_F(LD2450ReadlineTest, OverflowResetsBuffer) { TEST_F(LD2450ReadlineTest, OverflowThenValidFrame) { // Overflow, then a valid frame should be processed. - std::vector overflow_data; - for (int i = 0; i < MAX_LINE_LENGTH; i++) { - overflow_data.push_back(0x11); - } + std::vector overflow_data(MAX_LINE_LENGTH, 0x11); this->ld2450_.feed(overflow_data); auto frame = make_periodic_frame(); @@ -119,11 +113,7 @@ TEST_F(LD2450ReadlineTest, BufferLargeEnoughForDesyncedFooter) { // The key fix: the buffer (45) is large enough that a desynced periodic frame's // footer (at most 30 bytes into the stream) will land inside the buffer before overflow. // Simulate starting 10 bytes into a periodic frame, then a full frame follows. - std::vector mid_frame; - // 10 bytes of "mid-frame" data (no footer match) - for (int i = 0; i < 10; i++) { - mid_frame.push_back(0x30 + i); - } + std::vector mid_frame = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}; // Then a complete periodic frame whose footer will land at position 40 (10 + 30), // well within the buffer size of 45. auto frame = make_periodic_frame();