1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 16:51:52 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
J. Nick Koston
836bfc625d restore original byte-at-a-time read in send_cmd_from_array ack loop
The ack polling loop has a tight timing requirement with
delay_microseconds_safe(1450) between iterations. Snapshotting
available() once could leave partial ack response bytes unread
until after the delay, potentially breaking cold boot timing
on some ld2420 units. Keep batch reads only in loop().
2026-02-07 01:01:03 +01:00
J. Nick Koston
26c98a1e25 [ld2420] Batch UART reads to reduce loop overhead 2026-02-06 23:54:52 +01:00
3 changed files with 61 additions and 35 deletions

View File

@@ -1,7 +1,6 @@
#include "debug_component.h"
#ifdef USE_ESP8266
#include "esphome/core/log.h"
#include "esphome/core/progmem.h"
#include <Esp.h>
extern "C" {
@@ -20,38 +19,27 @@ namespace debug {
static const char *const TAG = "debug";
// PROGMEM string table for reset reasons, indexed by reason code (0-6), with "Unknown" as fallback
// clang-format off
PROGMEM_STRING_TABLE(ResetReasonStrings,
"Power On", // 0 = REASON_DEFAULT_RST
"Hardware Watchdog", // 1 = REASON_WDT_RST
"Exception", // 2 = REASON_EXCEPTION_RST
"Software Watchdog", // 3 = REASON_SOFT_WDT_RST
"Software/System restart", // 4 = REASON_SOFT_RESTART
"Deep-Sleep Wake", // 5 = REASON_DEEP_SLEEP_AWAKE
"External System", // 6 = REASON_EXT_SYS_RST
"Unknown" // 7 = fallback
);
// clang-format on
static_assert(REASON_DEFAULT_RST == 0, "Reset reason enum values must match table indices");
static_assert(REASON_WDT_RST == 1, "Reset reason enum values must match table indices");
static_assert(REASON_EXCEPTION_RST == 2, "Reset reason enum values must match table indices");
static_assert(REASON_SOFT_WDT_RST == 3, "Reset reason enum values must match table indices");
static_assert(REASON_SOFT_RESTART == 4, "Reset reason enum values must match table indices");
static_assert(REASON_DEEP_SLEEP_AWAKE == 5, "Reset reason enum values must match table indices");
static_assert(REASON_EXT_SYS_RST == 6, "Reset reason enum values must match table indices");
// PROGMEM string table for flash chip modes, indexed by mode code (0-3), with "UNKNOWN" as fallback
PROGMEM_STRING_TABLE(FlashModeStrings, "QIO", "QOUT", "DIO", "DOUT", "UNKNOWN");
static_assert(FM_QIO == 0, "Flash mode enum values must match table indices");
static_assert(FM_QOUT == 1, "Flash mode enum values must match table indices");
static_assert(FM_DIO == 2, "Flash mode enum values must match table indices");
static_assert(FM_DOUT == 3, "Flash mode enum values must match table indices");
// Get reset reason string from reason code (no heap allocation)
// Returns LogString* pointing to flash (PROGMEM) on ESP8266
static const LogString *get_reset_reason_str(uint32_t reason) {
return ResetReasonStrings::get_log_str(static_cast<uint8_t>(reason), ResetReasonStrings::LAST_INDEX);
switch (reason) {
case REASON_DEFAULT_RST:
return LOG_STR("Power On");
case REASON_WDT_RST:
return LOG_STR("Hardware Watchdog");
case REASON_EXCEPTION_RST:
return LOG_STR("Exception");
case REASON_SOFT_WDT_RST:
return LOG_STR("Software Watchdog");
case REASON_SOFT_RESTART:
return LOG_STR("Software/System restart");
case REASON_DEEP_SLEEP_AWAKE:
return LOG_STR("Deep-Sleep Wake");
case REASON_EXT_SYS_RST:
return LOG_STR("External System");
default:
return LOG_STR("Unknown");
}
}
// Size for core version hex buffer
@@ -104,9 +92,23 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
constexpr size_t size = DEVICE_INFO_BUFFER_SIZE;
char *buf = buffer.data();
const LogString *flash_mode = FlashModeStrings::get_log_str(
static_cast<uint8_t>(ESP.getFlashChipMode()), // NOLINT(readability-static-accessed-through-instance)
FlashModeStrings::LAST_INDEX);
const LogString *flash_mode;
switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
case FM_QIO:
flash_mode = LOG_STR("QIO");
break;
case FM_QOUT:
flash_mode = LOG_STR("QOUT");
break;
case FM_DIO:
flash_mode = LOG_STR("DIO");
break;
case FM_DOUT:
flash_mode = LOG_STR("DOUT");
break;
default:
flash_mode = LOG_STR("UNKNOWN");
}
uint32_t flash_size = ESP.getFlashChipSize() / 1024; // NOLINT(readability-static-accessed-through-instance)
uint32_t flash_speed = ESP.getFlashChipSpeed() / 1000000; // NOLINT(readability-static-accessed-through-instance)
ESP_LOGD(TAG, "Flash Chip: Size=%" PRIu32 "kB Speed=%" PRIu32 "MHz Mode=%s", flash_size, flash_speed,

View File

@@ -335,9 +335,10 @@ void LD2420Component::revert_config_action() {
void LD2420Component::loop() {
// If there is a active send command do not process it here, the send command call will handle it.
while (!this->cmd_active_ && this->available()) {
this->readline_(this->read(), this->buffer_data_, MAX_LINE_LENGTH);
if (this->cmd_active_) {
return;
}
this->read_batch_(this->buffer_data_);
}
void LD2420Component::update_radar_data(uint16_t const *gate_energy, uint8_t sample_number) {
@@ -539,6 +540,27 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) {
}
}
void LD2420Component::read_batch_(std::span<uint8_t, MAX_LINE_LENGTH> buffer) {
int avail = this->available();
if (avail == 0) {
return;
}
// Read all available bytes in batches to reduce UART call overhead.
uint8_t buf[MAX_LINE_LENGTH];
while (avail > 0) {
size_t to_read = std::min(static_cast<size_t>(avail), sizeof(buf));
if (!this->read_array(buf, to_read)) {
break;
}
avail -= to_read;
for (size_t i = 0; i < to_read; i++) {
this->readline_(buf[i], buffer.data(), buffer.size());
}
}
}
void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) {
this->cmd_reply_.command = buffer[CMD_FRAME_COMMAND];
this->cmd_reply_.length = buffer[CMD_FRAME_DATA_LENGTH];

View File

@@ -4,6 +4,7 @@
#include "esphome/components/uart/uart.h"
#include "esphome/core/automation.h"
#include "esphome/core/helpers.h"
#include <span>
#ifdef USE_TEXT_SENSOR
#include "esphome/components/text_sensor/text_sensor.h"
#endif
@@ -165,6 +166,7 @@ class LD2420Component : public Component, public uart::UARTDevice {
void handle_energy_mode_(uint8_t *buffer, int len);
void handle_ack_data_(uint8_t *buffer, int len);
void readline_(int rx_data, uint8_t *buffer, int len);
void read_batch_(std::span<uint8_t, MAX_LINE_LENGTH> buffer);
void set_calibration_(bool state) { this->calibration_ = state; };
bool get_calibration_() { return this->calibration_; };