Compare commits

..

9 Commits

Author SHA1 Message Date
J. Nick Koston
325a812202 tidy 2026-01-14 16:20:29 -10:00
J. Nick Koston
d49c06df35 Increase buffer to 128 bytes and improve docstrings 2026-01-14 16:04:22 -10:00
J. Nick Koston
0b676c0daa review 2026-01-14 16:02:42 -10:00
J. Nick Koston
d4bbad9ea2 Merge remote-tracking branch 'upstream/dev' into cse7766_stack_debug 2026-01-14 15:58:14 -10:00
J. Nick Koston
4befd86a96 review 2026-01-14 15:56:32 -10:00
J. Nick Koston
03f3deff41 [lvgl] Use stack buffer for event code formatting, document justified str_sprintf usage (#13220)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2026-01-15 01:24:42 +00:00
J. Nick Koston
e13743a9c3 tidy 2026-01-14 14:45:55 -10:00
J. Nick Koston
d3d96afbba tweak 2026-01-14 14:30:07 -10:00
J. Nick Koston
6e77182523 [cse7766] Use stack buffer for verbose debug logging 2026-01-14 14:04:28 -10:00
4 changed files with 47 additions and 23 deletions

View File

@@ -2,6 +2,7 @@
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <cstdarg>
namespace esphome {
namespace cse7766 {
@@ -9,6 +10,32 @@ namespace cse7766 {
static const char *const TAG = "cse7766";
static constexpr size_t CSE7766_RAW_DATA_SIZE = 24;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
/// @brief Safely append formatted string to buffer.
/// @param buf Destination buffer (must be non-null)
/// @param size Total buffer size in bytes
/// @param pos Current write position (0 to size-1 for valid positions, size means full)
/// @param fmt printf-style format string
/// @return New write position: pos + chars_written, capped at size when buffer is full.
/// Returns size (not size-1) when full because vsnprintf already wrote the null
/// terminator at buf[size-1]. Returning size signals "no room for more content".
/// On encoding error, returns pos unchanged (no write occurred).
__attribute__((format(printf, 4, 5))) static size_t buf_append(char *buf, size_t size, size_t pos, const char *fmt,
...) {
if (pos >= size) {
return size;
}
va_list args;
va_start(args, fmt);
int written = vsnprintf(buf + pos, size - pos, fmt, args);
va_end(args);
if (written < 0) {
return pos; // encoding error
}
return std::min(pos + static_cast<size_t>(written), size);
}
#endif
void CSE7766Component::loop() {
const uint32_t now = App.get_loop_component_start_time();
if (now - this->last_transmission_ >= 500) {
@@ -207,20 +234,23 @@ void CSE7766Component::parse_data_() {
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
{
std::string buf = "Parsed:";
// Buffer: 7 + 15 + 33 + 15 + 25 = 95 chars max + null, rounded to 128 for safety margin.
// Float sizes with %.4f can be up to 11 chars for large values (e.g., 999999.9999).
char buf[128];
size_t pos = buf_append(buf, sizeof(buf), 0, "Parsed:");
if (have_voltage) {
buf += str_sprintf(" V=%fV", voltage);
pos = buf_append(buf, sizeof(buf), pos, " V=%.4fV", voltage);
}
if (have_current) {
buf += str_sprintf(" I=%fmA (~%fmA)", current * 1000.0f, calculated_current * 1000.0f);
pos = buf_append(buf, sizeof(buf), pos, " I=%.4fmA (~%.4fmA)", current * 1000.0f, calculated_current * 1000.0f);
}
if (have_power) {
buf += str_sprintf(" P=%fW", power);
pos = buf_append(buf, sizeof(buf), pos, " P=%.4fW", power);
}
if (energy != 0.0f) {
buf += str_sprintf(" E=%fkWh (%u)", energy, cf_pulses);
buf_append(buf, sizeof(buf), pos, " E=%.4fkWh (%u)", energy, cf_pulses);
}
ESP_LOGVV(TAG, "%s", buf.c_str());
ESP_LOGVV(TAG, "%s", buf);
}
#endif
}

View File

@@ -413,6 +413,7 @@ class TextValidator(LValidator):
str_args = [str(x) for x in value[CONF_ARGS]]
arg_expr = cg.RawExpression(",".join(str_args))
format_str = cpp_string_escape(format_str)
# str_sprintf justified: user-defined format, can't optimize without permanent RAM cost
sprintf_str = f"str_sprintf({format_str}, {arg_expr}).c_str()"
if nanval := value.get(CONF_IF_NAN):
nanval = cpp_string_escape(nanval)

View File

@@ -65,7 +65,10 @@ std::string lv_event_code_name_for(uint8_t event_code) {
if (event_code < sizeof(EVENT_NAMES) / sizeof(EVENT_NAMES[0])) {
return EVENT_NAMES[event_code];
}
return str_sprintf("%2d", event_code);
// max 4 bytes: "%u" with uint8_t (max 255, 3 digits) + null
char buf[4];
snprintf(buf, sizeof(buf), "%u", event_code);
return buf;
}
static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) {

View File

@@ -5,8 +5,6 @@
#include "esphome/core/preferences.h"
#include "esphome/core/log.h"
#include <zephyr/settings/settings.h>
#include <cinttypes>
#include <cstring>
namespace esphome {
namespace zephyr {
@@ -15,9 +13,6 @@ static const char *const TAG = "zephyr.preferences";
#define ESPHOME_SETTINGS_KEY "esphome"
// Buffer size for key: "esphome/" (8) + max hex uint32 (8) + null terminator (1) = 17; use 20 for safety margin
static constexpr size_t KEY_BUFFER_SIZE = 20;
class ZephyrPreferenceBackend : public ESPPreferenceBackend {
public:
ZephyrPreferenceBackend(uint32_t type) { this->type_ = type; }
@@ -32,9 +27,7 @@ class ZephyrPreferenceBackend : public ESPPreferenceBackend {
bool load(uint8_t *data, size_t len) override {
if (len != this->data.size()) {
char key_buf[KEY_BUFFER_SIZE];
this->format_key(key_buf, sizeof(key_buf));
ESP_LOGE(TAG, "size of setting key %s changed, from: %u, to: %u", key_buf, this->data.size(), len);
ESP_LOGE(TAG, "size of setting key %s changed, from: %u, to: %u", get_key().c_str(), this->data.size(), len);
return false;
}
std::memcpy(data, this->data.data(), len);
@@ -43,7 +36,7 @@ class ZephyrPreferenceBackend : public ESPPreferenceBackend {
}
uint32_t get_type() const { return this->type_; }
void format_key(char *buf, size_t size) const { snprintf(buf, size, ESPHOME_SETTINGS_KEY "/%" PRIx32, this->type_); }
std::string get_key() const { return str_sprintf(ESPHOME_SETTINGS_KEY "/%" PRIx32, this->type_); }
std::vector<uint8_t> data;
@@ -92,9 +85,7 @@ class ZephyrPreferences : public ESPPreferences {
}
printf("type %u size %u\n", type, this->backends_.size());
auto *pref = new ZephyrPreferenceBackend(type); // NOLINT(cppcoreguidelines-owning-memory)
char key_buf[KEY_BUFFER_SIZE];
pref->format_key(key_buf, sizeof(key_buf));
ESP_LOGD(TAG, "Add new setting %s.", key_buf);
ESP_LOGD(TAG, "Add new setting %s.", pref->get_key().c_str());
this->backends_.push_back(pref);
return ESPPreferenceObject(pref);
}
@@ -143,10 +134,9 @@ class ZephyrPreferences : public ESPPreferences {
static int export_settings(int (*cb)(const char *name, const void *value, size_t val_len)) {
for (auto *backend : static_cast<ZephyrPreferences *>(global_preferences)->backends_) {
char name[KEY_BUFFER_SIZE];
backend->format_key(name, sizeof(name));
int err = cb(name, backend->data.data(), backend->data.size());
ESP_LOGD(TAG, "save in flash, name %s, len %u, err %d", name, backend->data.size(), err);
auto name = backend->get_key();
int err = cb(name.c_str(), backend->data.data(), backend->data.size());
ESP_LOGD(TAG, "save in flash, name %s, len %u, err %d", name.c_str(), backend->data.size(), err);
}
return 0;
}