[core] Add ESP_LOGV_HEX, ESP_LOGVV_HEX and ESP_LOGD_HEX (#20931)

This commit is contained in:
J. Nick Koston
2026-10-16 15:55:28 -10:00
committed by GitHub
parent b8afcdfb3c
commit 298bd5ec72
2 changed files with 99 additions and 0 deletions
+32
View File
@@ -160,6 +160,38 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
#define ESP_LOGV(tag, ...) esph_log_v(tag, __VA_ARGS__)
#define ESP_LOGVV(tag, ...) esph_log_vv(tag, __VA_ARGS__)
// Log \p format with up to \p max_bytes of \p data as colon separated hex appended as its last %s argument.
// The stack buffer exists only when the level is compiled in. Needs esphome/core/helpers.h.
#define ESPHOME_LOG_HEX_(log_macro, tag, data, len, max_bytes, format, ...) \
do { \
char esph_log_hex_buf_[::esphome::format_hex_pretty_size(max_bytes)]; \
log_macro(tag, format, __VA_ARGS__ __VA_OPT__(, )::esphome::format_hex_pretty_to(esph_log_hex_buf_, data, len)); \
} while (0)
#ifdef ESPHOME_LOG_HAS_DEBUG
#define ESP_LOGD_HEX(tag, data, len, max_bytes, format, ...) \
ESPHOME_LOG_HEX_(ESP_LOGD, tag, data, len, max_bytes, format, __VA_ARGS__)
#else
#define ESP_LOGD_HEX(tag, data, len, max_bytes, format, ...) \
do { \
} while (0)
#endif
#ifdef ESPHOME_LOG_HAS_VERBOSE
#define ESP_LOGV_HEX(tag, data, len, max_bytes, format, ...) \
ESPHOME_LOG_HEX_(ESP_LOGV, tag, data, len, max_bytes, format, __VA_ARGS__)
#else
#define ESP_LOGV_HEX(tag, data, len, max_bytes, format, ...) \
do { \
} while (0)
#endif
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
#define ESP_LOGVV_HEX(tag, data, len, max_bytes, format, ...) \
ESPHOME_LOG_HEX_(ESP_LOGVV, tag, data, len, max_bytes, format, __VA_ARGS__)
#else
#define ESP_LOGVV_HEX(tag, data, len, max_bytes, format, ...) \
do { \
} while (0)
#endif
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
((byte) &0x80 ? '1' : '0'), ((byte) &0x40 ? '1' : '0'), ((byte) &0x20 ? '1' : '0'), ((byte) &0x10 ? '1' : '0'), \
+67
View File
@@ -0,0 +1,67 @@
#include <gtest/gtest.h>
#include <cstdio>
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::testing {
static const char *const TAG = "log_hex_test";
TEST(LogHexTest, EvaluatesArgumentsOnlyWhenTheLevelIsCompiledIn) {
static constexpr uint8_t DATA[] = {0x01, 0xAB, 0xFF};
int debug_calls = 0;
int verbose_calls = 0;
int very_verbose_calls = 0;
auto count = [](int &calls) {
calls++;
return sizeof(DATA);
};
ESP_LOGD_HEX(TAG, DATA, count(debug_calls), sizeof(DATA), "Data: %s");
ESP_LOGV_HEX(TAG, DATA, count(verbose_calls), sizeof(DATA), "Frame %u: %s", 7u);
ESP_LOGVV_HEX(TAG, DATA, count(very_verbose_calls), 2, "Type %02X %s: %s", 0x10, "truncated");
#ifdef ESPHOME_LOG_HAS_DEBUG
EXPECT_EQ(debug_calls, 1);
#else
EXPECT_EQ(debug_calls, 0);
#endif
#ifdef ESPHOME_LOG_HAS_VERBOSE
EXPECT_EQ(verbose_calls, 1);
#else
EXPECT_EQ(verbose_calls, 0);
#endif
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
EXPECT_EQ(very_verbose_calls, 1);
#else
EXPECT_EQ(very_verbose_calls, 0);
#endif
}
TEST(LogHexTest, IsASingleStatement) {
static constexpr uint8_t DATA[] = {0x12, 0x34};
bool other_branch = false;
if (DATA[0] == 0x12) // NOLINT(readability-braces-around-statements)
ESP_LOGV_HEX(TAG, DATA, sizeof(DATA), sizeof(DATA), "Data: %s");
else // NOLINT(readability-braces-around-statements)
other_branch = true;
EXPECT_FALSE(other_branch);
}
// Stands in for a log macro so the expansion can be checked without the logger backend
static char captured[64]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#define CAPTURE_LOG(tag, ...) snprintf(captured, sizeof(captured), __VA_ARGS__)
TEST(LogHexTest, HexTextIsTheLastArgument) {
static constexpr uint8_t DATA[] = {0x01, 0xAB, 0xFF};
ESPHOME_LOG_HEX_(CAPTURE_LOG, TAG, DATA, sizeof(DATA), sizeof(DATA), "Data: %s");
EXPECT_STREQ(captured, "Data: 01:AB:FF");
}
TEST(LogHexTest, ExtraArgumentsComeFirstAndLongDataIsCut) {
static constexpr uint8_t DATA[] = {0x01, 0xAB, 0xFF};
ESPHOME_LOG_HEX_(CAPTURE_LOG, TAG, DATA, sizeof(DATA), 2, "Type %02X %s: %s", 0x10, "truncated");
EXPECT_STREQ(captured, "Type 10 truncated: 01:AB");
}
} // namespace esphome::testing