forked from espressif/esp-idf
Merge branch 'feature/binary_logging' into 'master'
feat(log): Add binary logging support Closes IDF-6634 See merge request espressif/esp-idf!36595
This commit is contained in:
@@ -50,6 +50,8 @@ menu "Log"
|
||||
default 4 if BOOTLOADER_LOG_LEVEL_DEBUG
|
||||
default 5 if BOOTLOADER_LOG_LEVEL_VERBOSE
|
||||
|
||||
orsource "Kconfig.log.format"
|
||||
rsource "Kconfig.log.format"
|
||||
|
||||
rsource "Kconfig.log.settings"
|
||||
|
||||
endmenu
|
||||
|
39
components/bootloader/Kconfig.log.settings
Normal file
39
components/bootloader/Kconfig.log.settings
Normal file
@@ -0,0 +1,39 @@
|
||||
menu "Settings"
|
||||
|
||||
config BOOTLOADER_LOG_MODE_TEXT_EN
|
||||
bool
|
||||
|
||||
config BOOTLOADER_LOG_MODE_BINARY_EN
|
||||
bool
|
||||
|
||||
choice BOOTLOADER_LOG_MODE
|
||||
prompt "Log Mode"
|
||||
default BOOTLOADER_LOG_MODE_TEXT
|
||||
|
||||
config BOOTLOADER_LOG_MODE_TEXT
|
||||
bool "Text Log Mode"
|
||||
select BOOTLOADER_LOG_MODE_TEXT_EN
|
||||
help
|
||||
Enables text-based logging, where log messages are stored in a human-readable format.
|
||||
This mode is useful for development and debugging, as it allows logs to be easily
|
||||
read and interpreted without additional processing.
|
||||
|
||||
config BOOTLOADER_LOG_MODE_BINARY
|
||||
bool "Binary Log Mode"
|
||||
select BOOTLOADER_LOG_MODE_BINARY_EN
|
||||
help
|
||||
Enables binary logging with host-side format string expansion. In this mode, the
|
||||
format argument of ESP_LOGx, ESP_EARLY_LOG, and ESP_DRAM_LOG macros is stored in a
|
||||
NOLOAD section, not included in the final binary file. This reduces flash usage by
|
||||
approximately 10% - 35%. The esp_log() function uses the binary log handler to output
|
||||
messages. Instead of sending the full log string, the chip transmits only the
|
||||
addresses of these strings (if present in the ELF file). If the format string
|
||||
cannot be found in the ELF file, the chip sends the entire string. The host-side
|
||||
monitor tool, which has access to the ELF file, reconstructs the log message using
|
||||
the format string.
|
||||
This reduces firmware size by eliminating format strings from
|
||||
flash memory and removing the usage of printf-like functions, potentially freeing up
|
||||
a few kilobytes of space. To further reduce firmware size, wrap string data with ESP_LOG_ATTR_STR.
|
||||
|
||||
endchoice
|
||||
endmenu
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -261,4 +261,15 @@ SECTIONS
|
||||
|
||||
.comment 0 : { *(.comment) }
|
||||
.note.GNU-stack 0: { *(.note.GNU-stack) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -272,6 +272,17 @@ SECTIONS
|
||||
* And so forth...
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -273,6 +273,16 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -271,6 +271,16 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -272,6 +272,16 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -271,6 +271,16 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -271,6 +271,16 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -271,6 +271,16 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -272,6 +272,16 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -251,4 +251,14 @@ SECTIONS
|
||||
.comment 0 : { *(.comment) }
|
||||
.note.GNU-stack 0: { *(.note.GNU-stack) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -285,6 +285,16 @@ SECTIONS
|
||||
.comment 0 : { *(.comment) }
|
||||
.note.GNU-stack 0: { *(.note.GNU-stack) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -31,6 +31,9 @@ extern "C" {
|
||||
// Forces data into TCM instead of L2MEM
|
||||
#define TCM_DRAM_ATTR _SECTION_ATTR_IMPL(".tcm.data", __COUNTER__)
|
||||
|
||||
// Forces data to be removed from the final binary but keeps it in the ELF file
|
||||
#define NOLOAD_ATTR _SECTION_ATTR_IMPL(".noload_keep_in_elf", __COUNTER__)
|
||||
|
||||
// IRAM can only be accessed as an 8-bit memory on ESP32, when CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY is set
|
||||
#define IRAM_8BIT_ACCESSIBLE (CONFIG_IDF_TARGET_ESP32 && CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY)
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -15,6 +15,12 @@
|
||||
#include <time.h>
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
int esp_rom_output_tx_one_char(uint8_t c)
|
||||
{
|
||||
putc(c, stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void esp_rom_output_putc(char c)
|
||||
{
|
||||
putc(c, stdout);
|
||||
|
@@ -1,5 +1,17 @@
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
mapping[noload_keep_in_elf]
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
|
@@ -17,13 +17,22 @@ set(srcs "src/${system_target}/log_timestamp.c"
|
||||
"src/buffer/log_buffers.c"
|
||||
"src/${system_target}/util.c"
|
||||
"src/util.c"
|
||||
"src/log_format_text.c"
|
||||
"src/log_print.c"
|
||||
"src/log.c")
|
||||
|
||||
set(priv_requires "")
|
||||
if((NOT non_os_build AND CONFIG_LOG_MODE_TEXT_EN) OR (non_os_build AND CONFIG_BOOTLOADER_LOG_MODE_TEXT_EN))
|
||||
list(APPEND srcs "src/log_format_text.c")
|
||||
endif()
|
||||
|
||||
if((NOT non_os_build AND CONFIG_LOG_MODE_BINARY_EN) OR (non_os_build AND CONFIG_BOOTLOADER_LOG_MODE_BINARY_EN))
|
||||
list(APPEND srcs "src/log_format_binary.c")
|
||||
endif()
|
||||
|
||||
set(priv_requires hal)
|
||||
|
||||
if(NOT non_os_build)
|
||||
list(APPEND priv_requires soc hal esp_hw_support)
|
||||
list(APPEND priv_requires soc esp_hw_support)
|
||||
|
||||
list(APPEND srcs "src/os/log_write.c")
|
||||
|
||||
|
@@ -46,9 +46,11 @@ menu "Log"
|
||||
help
|
||||
This configuration sets the log version number based on the chosen log version.
|
||||
|
||||
orsource "./Kconfig.level"
|
||||
rsource "./Kconfig.level"
|
||||
|
||||
orsource "./Kconfig.format"
|
||||
rsource "./Kconfig.format"
|
||||
|
||||
rsource "./Kconfig.settings"
|
||||
|
||||
config LOG_IN_IRAM
|
||||
bool "Place logging functions in IRAM" if SPI_FLASH_AUTO_SUSPEND
|
||||
|
39
components/log/Kconfig.settings
Normal file
39
components/log/Kconfig.settings
Normal file
@@ -0,0 +1,39 @@
|
||||
menu "Settings"
|
||||
|
||||
config LOG_MODE_TEXT_EN
|
||||
bool
|
||||
|
||||
config LOG_MODE_BINARY_EN
|
||||
bool
|
||||
|
||||
choice LOG_MODE
|
||||
prompt "Log Mode"
|
||||
default LOG_MODE_TEXT
|
||||
|
||||
config LOG_MODE_TEXT
|
||||
bool "Text Log Mode"
|
||||
select LOG_MODE_TEXT_EN
|
||||
help
|
||||
Enables text-based logging, where log messages are stored in a human-readable format.
|
||||
This mode is useful for development and debugging, as it allows logs to be easily
|
||||
read and interpreted without additional processing.
|
||||
|
||||
config LOG_MODE_BINARY
|
||||
bool "Binary Log Mode"
|
||||
select LOG_MODE_BINARY_EN
|
||||
help
|
||||
Enables binary logging with host-side format string expansion. In this mode, the
|
||||
format argument of ESP_LOGx, ESP_EARLY_LOG, and ESP_DRAM_LOG macros is stored in a
|
||||
NOLOAD section, not included in the final binary file. This reduces flash usage by
|
||||
approximately 10% - 35%. The esp_log() function uses the binary log handler to output
|
||||
messages. Instead of sending the full log string, the chip transmits only the
|
||||
addresses of these strings (if present in the ELF file). If the format string
|
||||
cannot be found in the ELF file, the chip sends the entire string. The host-side
|
||||
monitor tool, which has access to the ELF file, reconstructs the log message using
|
||||
the format string.
|
||||
This reduces firmware size by eliminating format strings from
|
||||
flash memory and removing the usage of printf-like functions, potentially freeing up
|
||||
a few kilobytes of space. To further reduce firmware size, wrap string data with ESP_LOG_ATTR_STR.
|
||||
|
||||
endchoice
|
||||
endmenu
|
@@ -427,6 +427,7 @@ TEST_CASE("esp_log with formatting")
|
||||
.require_formatting = true,
|
||||
.dis_color = ESP_LOG_COLOR_DISABLED,
|
||||
.dis_timestamp = ESP_LOG_TIMESTAMP_DISABLED,
|
||||
.binary_mode = false,
|
||||
.reserved = 0,
|
||||
}
|
||||
};
|
||||
@@ -470,6 +471,7 @@ TEST_CASE("esp_log without formatting")
|
||||
.require_formatting = false, // print just text
|
||||
.dis_color = ESP_LOG_COLOR_DISABLED,
|
||||
.dis_timestamp = ESP_LOG_TIMESTAMP_DISABLED,
|
||||
.binary_mode = false,
|
||||
.reserved = 0,
|
||||
}
|
||||
};
|
||||
@@ -507,6 +509,7 @@ TEST_CASE("esp_log TAG can be NULL")
|
||||
.require_formatting = true,
|
||||
.dis_color = ESP_LOG_COLOR_DISABLED,
|
||||
.dis_timestamp = ESP_LOG_TIMESTAMP_DISABLED,
|
||||
.binary_mode = false,
|
||||
.reserved = 0,
|
||||
}
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "esp_log_timestamp.h"
|
||||
#include "esp_log_write.h"
|
||||
#include "esp_log_format.h"
|
||||
#include "esp_log_args.h"
|
||||
#include "esp_log_attr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -176,11 +178,11 @@ void esp_log_va(esp_log_config_t config, const char *tag, const char *format, va
|
||||
#if ESP_LOG_VERSION == 2
|
||||
#if defined(__cplusplus) && (__cplusplus > 201703L)
|
||||
#define ESP_LOG_LEVEL(configs, tag, format, ...) do { \
|
||||
esp_log(ESP_LOG_CONFIG_INIT(configs | ESP_LOG_CONFIGS_DEFAULT), tag, format __VA_OPT__(,) __VA_ARGS__); \
|
||||
esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT), tag, ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); \
|
||||
} while(0)
|
||||
#else // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
#define ESP_LOG_LEVEL(configs, tag, format, ...) do { \
|
||||
esp_log(ESP_LOG_CONFIG_INIT(configs | ESP_LOG_CONFIGS_DEFAULT), tag, format, ##__VA_ARGS__); \
|
||||
esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT), tag, ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); \
|
||||
} while(0)
|
||||
#endif // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
|
||||
@@ -248,14 +250,14 @@ void esp_log_va(esp_log_config_t config, const char *tag, const char *format, va
|
||||
if (ESP_LOG_VERSION == 1) { \
|
||||
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(LOG_FORMAT(log_tag_letter, format), esp_log_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
|
||||
} else { \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT(configs | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV), tag, format __VA_OPT__(,) __VA_ARGS__); } \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV), tag, ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
|
||||
} } while(0)
|
||||
#else // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
#define ESP_LOG_EARLY_IMPL(tag, format, configs, log_tag_letter, ...) do { \
|
||||
if (ESP_LOG_VERSION == 1) { \
|
||||
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(LOG_FORMAT(log_tag_letter, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \
|
||||
} else { \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT(configs | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV), tag, format, ##__VA_ARGS__); } \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV), tag, ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
|
||||
} } while(0)
|
||||
#endif // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
|
||||
@@ -264,14 +266,14 @@ void esp_log_va(esp_log_config_t config, const char *tag, const char *format, va
|
||||
if (ESP_LOG_VERSION == 1) { \
|
||||
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(_ESP_LOG_DRAM_LOG_FORMAT(log_tag_letter, format), tag __VA_OPT__(,) __VA_ARGS__); } \
|
||||
} else { \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT(configs | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV | ESP_LOG_CONFIG_DIS_COLOR | ESP_LOG_CONFIG_DIS_TIMESTAMP), tag, DRAM_STR(format) __VA_OPT__(,) __VA_ARGS__); } \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV | ESP_LOG_CONFIG_DIS_COLOR | ESP_LOG_CONFIG_DIS_TIMESTAMP), tag, ESP_LOG_ATTR_DRAM_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
|
||||
} } while(0)
|
||||
#else // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
#define ESP_DRAM_LOG_IMPL(tag, format, configs, log_tag_letter, ...) do { \
|
||||
if (ESP_LOG_VERSION == 1) { \
|
||||
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(_ESP_LOG_DRAM_LOG_FORMAT(log_tag_letter, format), tag, ##__VA_ARGS__); } \
|
||||
} else { \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT(configs | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV | ESP_LOG_CONFIG_DIS_COLOR | ESP_LOG_CONFIG_DIS_TIMESTAMP), tag, DRAM_STR(format), ##__VA_ARGS__); } \
|
||||
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV | ESP_LOG_CONFIG_DIS_COLOR | ESP_LOG_CONFIG_DIS_TIMESTAMP), tag, ESP_LOG_ATTR_DRAM_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
|
||||
} } while(0)
|
||||
#endif // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
/** @endcond */
|
||||
|
233
components/log/include/esp_log_args.h
Normal file
233
components/log/include/esp_log_args.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "esp_assert.h"
|
||||
#include "esp_macros.h"
|
||||
#include "esp_log_config.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**
|
||||
* @file esp_log_args.h
|
||||
* @brief Macros and utilities for managing argument types in binary logging.
|
||||
*
|
||||
* This header file provides definitions and helper macros for handling
|
||||
* and constructing an array of argument types used in binary logging.
|
||||
* These utilities facilitate efficient logging by encoding argument type
|
||||
* for compact storage.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enumeration of argument types for logging.
|
||||
*
|
||||
* This enumeration defines the types of arguments that can be passed to logging functions.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_LOG_ARGS_TYPE_NONE = 0, /**< Indicates the end of arguments. */
|
||||
ESP_LOG_ARGS_TYPE_32BITS = 1, /**< For variables that are 4 bytes in size, such as int, uint32_t, etc. */
|
||||
ESP_LOG_ARGS_TYPE_64BITS = 2, /**< For variables that are 8 bytes in size, such as uint64_t, double, float, etc. */
|
||||
ESP_LOG_ARGS_TYPE_POINTER = 3, /**< For variables that are pointers to strings or other data, such as const char *, const char [], void *. */
|
||||
} esp_log_args_type_t;
|
||||
|
||||
#define ESP_LOG_ARGS_TYPE_LEN (2) /**< Length of the enumeration of argument types. */
|
||||
#define ESP_LOG_ARGS_TYPE_MASK ((1 << ESP_LOG_ARGS_TYPE_LEN) - 1) /*!< Mask for the enumeration of argument types. */
|
||||
|
||||
/**
|
||||
* @brief Structure to indicate the end of arguments.
|
||||
*
|
||||
* This structure is used to indicate the end of arguments in the logging functions.
|
||||
*
|
||||
* @note This structure is intended for internal use only.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned tmp;
|
||||
} esp_log_args_end_t;
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus > 201703L)
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
#define ESP_LOG_ARGS(...) , ESP_LOG_ARGS_TYPE(__VA_ARGS__) __VA_OPT__(,) __VA_ARGS__
|
||||
#else
|
||||
#define ESP_LOG_ARGS(...) __VA_OPT__(,) __VA_ARGS__
|
||||
#endif
|
||||
#else // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
#define ESP_LOG_ARGS(...) , ESP_LOG_ARGS_TYPE(__VA_ARGS__), ##__VA_ARGS__
|
||||
#else
|
||||
#define ESP_LOG_ARGS(...) , ##__VA_ARGS__
|
||||
#endif
|
||||
#endif // !(defined(__cplusplus) && (__cplusplus > 201703L))
|
||||
|
||||
/**
|
||||
* @brief Defines a static array of argument types for binary logging.
|
||||
*
|
||||
* This macro creates a static array which consists of char elements,
|
||||
* where each char stores up to 4 types of arguments. The array is null-terminated.
|
||||
* The format of the array is as follows:
|
||||
*
|
||||
* - Each element is a packed structure of up to 4 argument types (esp_log_args_t).
|
||||
* - The argument type occupies 2 bits (ESP_LOG_ARGS_TYPE_LEN).
|
||||
* - If fewer than four arguments are provided, the remaining fields are filled
|
||||
* with ESP_LOG_ARGS_TYPE_NONE.
|
||||
* - The array is terminated with a null byte (0) to mark the end of the argument
|
||||
* type list.
|
||||
*
|
||||
* The pointer to this array is passed to esp_log() in front of the user arguments.
|
||||
* This allows the format argument to be excluded from the flash, as esp_log()
|
||||
* will rely on this array to extract the correct type of each user argument from the
|
||||
* va_list.
|
||||
*/
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
#define ESP_LOG_ARGS_TYPE(...) (__extension__({ static const char __c[] = { __VA_OPT__(ESP_LOG_INIT_ARG_TYPE(ESP_VA_NARG(__VA_ARGS__), __VA_ARGS__), ) 0 }; (const char*)&__c; }))
|
||||
#else
|
||||
#define ESP_LOG_ARGS_TYPE(...)
|
||||
#endif
|
||||
|
||||
#define ESP_LOG_INIT_ARG_TYPE_N(n) ESP_LOG_INIT_ARG_TYPE_##n
|
||||
#define ESP_LOG_INIT_ARG_TYPE(n, ...) ESP_LOG_INIT_ARG_TYPE_N(n)(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_1(a) ESP_LOG_PACK_4_TYPES(a, (esp_log_args_end_t){0}, (esp_log_args_end_t){0}, (esp_log_args_end_t){0})
|
||||
#define ESP_LOG_INIT_ARG_TYPE_2(a, b) ESP_LOG_PACK_4_TYPES(a, b, (esp_log_args_end_t){0}, (esp_log_args_end_t){0})
|
||||
#define ESP_LOG_INIT_ARG_TYPE_3(a, b, c) ESP_LOG_PACK_4_TYPES(a, b, c, (esp_log_args_end_t){0})
|
||||
#define ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d) ESP_LOG_PACK_4_TYPES(a, b, c, d)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_5(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_1(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_6(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_2(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_7(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_3(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_8(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_4(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_9(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_5(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_10(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_6(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_11(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_7(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_12(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_8(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_13(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_9(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_14(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_10(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_15(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_11(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_16(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_12(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_17(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_13(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_18(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_14(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_19(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_15(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_20(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_16(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_21(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_17(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_22(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_18(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_23(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_19(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_24(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_20(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_25(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_21(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_26(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_22(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_27(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_23(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_28(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_24(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_29(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_25(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_30(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_26(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_31(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_27(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_32(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_28(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_33(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_29(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_34(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_30(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_35(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_31(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_36(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_32(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_37(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_33(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_38(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_34(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_39(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_35(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_40(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_36(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_41(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_37(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_42(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_38(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_43(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_39(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_44(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_40(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_45(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_41(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_46(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_42(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_47(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_43(__VA_ARGS__)
|
||||
#define ESP_LOG_INIT_ARG_TYPE_48(a, b, c, d, ...) ESP_LOG_INIT_ARG_TYPE_4(a, b, c, d), ESP_LOG_INIT_ARG_TYPE_44(__VA_ARGS__)
|
||||
|
||||
// Pack 4 types into a single byte (8 bits)
|
||||
#define ESP_LOG_PACK_4_TYPES(a, b, c, d) (char) ( \
|
||||
(ESP_LOG_DETECT_TYPE(a) << (0 * ESP_LOG_ARGS_TYPE_LEN)) | \
|
||||
(ESP_LOG_DETECT_TYPE(b) << (1 * ESP_LOG_ARGS_TYPE_LEN)) | \
|
||||
(ESP_LOG_DETECT_TYPE(c) << (2 * ESP_LOG_ARGS_TYPE_LEN)) | \
|
||||
(ESP_LOG_DETECT_TYPE(d) << (3 * ESP_LOG_ARGS_TYPE_LEN))) \
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define ESP_LOG_DETECT_TYPE(arg) ( \
|
||||
_Generic((arg), \
|
||||
esp_log_args_end_t: ESP_LOG_ARGS_TYPE_NONE, \
|
||||
char*: ESP_LOG_ARGS_TYPE_POINTER, \
|
||||
const char*: ESP_LOG_ARGS_TYPE_POINTER, \
|
||||
uint8_t*: ESP_LOG_ARGS_TYPE_POINTER, \
|
||||
const uint8_t*: ESP_LOG_ARGS_TYPE_POINTER, \
|
||||
long long int: ESP_LOG_ARGS_TYPE_64BITS, \
|
||||
long long unsigned int: ESP_LOG_ARGS_TYPE_64BITS, \
|
||||
double: ESP_LOG_ARGS_TYPE_64BITS, \
|
||||
float: ESP_LOG_ARGS_TYPE_64BITS, /* float is a 32 bits var but in va_list it takes 64 bits */ \
|
||||
default: ESP_LOG_ARGS_TYPE_32BITS \
|
||||
))
|
||||
#else // __cplusplus
|
||||
extern "C++" {
|
||||
template <typename T>
|
||||
struct EspLogArgType;
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<esp_log_args_end_t> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_NONE;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<char*> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_POINTER;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<const char*> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_POINTER;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<uint8_t*> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_POINTER;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<const uint8_t*> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_POINTER;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<long long int> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_64BITS;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<long long unsigned int> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_64BITS;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<double> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_64BITS;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EspLogArgType<float> {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_64BITS;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct EspLogArgType {
|
||||
constexpr static unsigned long long log_type = ESP_LOG_ARGS_TYPE_32BITS;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr unsigned long long ESP_LOG_DETECT_TYPE(const T &)
|
||||
{
|
||||
return EspLogArgType<T>::log_type;
|
||||
}
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
26
components/log/include/esp_log_attr.h
Normal file
26
components/log/include/esp_log_attr.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_attr.h"
|
||||
#include "esp_private/log_attr.h"
|
||||
#include "esp_log_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
#define ESP_LOG_ATTR_STR(str) (__builtin_constant_p(str) ? ESP_LOG_NOLOAD_STR(str) : str)
|
||||
#define ESP_LOG_ATTR_DRAM_STR(str) ESP_LOG_NOLOAD_STR(str)
|
||||
#else
|
||||
#define ESP_LOG_ATTR_STR(str) (str)
|
||||
#define ESP_LOG_ATTR_DRAM_STR(str) DRAM_STR(str)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -76,6 +76,33 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** @cond */
|
||||
#if (!BOOTLOADER_BUILD && CONFIG_LOG_MODE_TEXT_EN) || (BOOTLOADER_BUILD && CONFIG_BOOTLOADER_LOG_MODE_TEXT_EN)
|
||||
#define ESP_LOG_MODE_TEXT_EN (1)
|
||||
#else
|
||||
#define ESP_LOG_MODE_TEXT_EN (0)
|
||||
#endif
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* This define helps control log configuration options, specifically whether binary mode will be enabled.
|
||||
* If this define is not set in the user namespace, its value will be determined by Kconfig options.
|
||||
* If the define is set in the user namespace, it will override the default configurations (ESP_LOG_CONFIGS_DEFAULT) for the user's specific file.
|
||||
* This define controls the "binary_mode" flag, which is included in ESP_LOG_CONFIGS_DEFAULT
|
||||
*/
|
||||
#ifndef ESP_LOG_MODE_BINARY_EN
|
||||
#if (!BOOTLOADER_BUILD && CONFIG_LOG_MODE_BINARY_EN) || (BOOTLOADER_BUILD && CONFIG_BOOTLOADER_LOG_MODE_BINARY_EN)
|
||||
#define ESP_LOG_MODE_BINARY_EN (1)
|
||||
#else
|
||||
#define ESP_LOG_MODE_BINARY_EN (0)
|
||||
#endif
|
||||
#elif ESP_LOG_MODE_TEXT_EN == 1 && ESP_LOG_MODE_BINARY_EN == 1
|
||||
// Text logging mode is enabled via CONFIG option, but binary mode is enabled via ESP_LOG_MODE_BINARY_EN define in the user namespace.
|
||||
// Suppressing binary logging mode.
|
||||
#undef ESP_LOG_MODE_BINARY_EN
|
||||
#define ESP_LOG_MODE_BINARY_EN (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This define helps control log configuration options, specifically whether formatting (ex.: color, timestamp) will be appended to log message.
|
||||
* If the define is set in the user namespace, it will override the default configurations (ESP_LOG_CONFIGS_DEFAULT) for the user's specific file.
|
||||
@@ -97,7 +124,8 @@ typedef struct {
|
||||
uint32_t require_formatting: 1; /*!< Flag specifying whether the log message needs additional formatting. If set, esp_log() will add formatting elements like color, timestamp, and tag to the log message. */
|
||||
uint32_t dis_color: 1; /*!< Flag to disable color in log output. If set, log messages will not include color codes. */
|
||||
uint32_t dis_timestamp: 1; /*!< Flag to disable timestamps in log output. If set, log messages will not include timestamps. */
|
||||
uint32_t reserved: 25; /*!< Reserved for future use. Should be initialized to 0. */
|
||||
uint32_t binary_mode : 1; /*!< Flag to indicate binary mode. */
|
||||
uint32_t reserved: 24; /*!< Reserved for future use. Should be initialized to 0. */
|
||||
} opts;
|
||||
uint32_t data; /*!< Raw data representing all options in a 32-bit word. */
|
||||
};
|
||||
@@ -108,6 +136,7 @@ typedef struct {
|
||||
#define ESP_LOG_OFFSET_REQUIRE_FORMATTING (4) /*!< Offset for require_formatting field from esp_log_config_t */
|
||||
#define ESP_LOG_OFFSET_DIS_COLOR_OFFSET (5) /*!< Offset for dis_color field from esp_log_config_t */
|
||||
#define ESP_LOG_OFFSET_DIS_TIMESTAMP (6) /*!< Offset for dis_timestamp field from esp_log_config_t */
|
||||
#define ESP_LOG_OFFSET_BINARY_MODE (7) /*!< Offset for binary_mode field from esp_log_config_t */
|
||||
|
||||
ESP_STATIC_ASSERT(ESP_LOG_OFFSET_CONSTRAINED_ENV == ESP_LOG_LEVEL_LEN, "The log level should not overlap the following fields in esp_log_config_t");
|
||||
/** @endcond */
|
||||
@@ -117,6 +146,7 @@ ESP_STATIC_ASSERT(ESP_LOG_OFFSET_CONSTRAINED_ENV == ESP_LOG_LEVEL_LEN, "The log
|
||||
#define ESP_LOG_CONFIG_REQUIRE_FORMATTING (1 << ESP_LOG_OFFSET_REQUIRE_FORMATTING) /*!< Value for require_formatting field in esp_log_config_t */
|
||||
#define ESP_LOG_CONFIG_DIS_COLOR (1 << ESP_LOG_OFFSET_DIS_COLOR_OFFSET) /*!< Value for dis_color field in esp_log_config_t */
|
||||
#define ESP_LOG_CONFIG_DIS_TIMESTAMP (1 << ESP_LOG_OFFSET_DIS_TIMESTAMP) /*!< Value for dis_timestamp field in esp_log_config_t */
|
||||
#define ESP_LOG_CONFIG_BINARY_MODE (1 << ESP_LOG_OFFSET_BINARY_MODE) /*!< Value for binary_mode field in esp_log_config_t */
|
||||
|
||||
/**
|
||||
* @brief Macro for setting log configurations according to selected Kconfig options.
|
||||
@@ -128,7 +158,8 @@ ESP_STATIC_ASSERT(ESP_LOG_OFFSET_CONSTRAINED_ENV == ESP_LOG_LEVEL_LEN, "The log
|
||||
((ESP_LOG_CONSTRAINED_ENV) ? (ESP_LOG_CONFIG_CONSTRAINED_ENV) : 0) \
|
||||
| ((ESP_LOG_FORMATTING_DISABLED) ? (0) : (ESP_LOG_CONFIG_REQUIRE_FORMATTING)) \
|
||||
| ((ESP_LOG_COLOR_DISABLED) ? (ESP_LOG_CONFIG_DIS_COLOR) : 0) \
|
||||
| ((ESP_LOG_TIMESTAMP_DISABLED) ? (ESP_LOG_CONFIG_DIS_TIMESTAMP) : 0))
|
||||
| ((ESP_LOG_TIMESTAMP_DISABLED) ? (ESP_LOG_CONFIG_DIS_TIMESTAMP) : 0) \
|
||||
| ((ESP_LOG_MODE_BINARY_EN) ? (ESP_LOG_CONFIG_BINARY_MODE) : 0))
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
19
components/log/include/esp_private/log_attr.h
Normal file
19
components/log/include/esp_private/log_attr.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_attr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Forces a string to be removed from the final binary but keeps it in the ELF file
|
||||
#define ESP_LOG_NOLOAD_STR(str) (__extension__({static const NOLOAD_ATTR char __f[] = (str); (const char *)&__f;}))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
33
components/log/include/esp_private/log_format.h
Normal file
33
components/log/include/esp_private/log_format.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_log_config.h"
|
||||
#include "log_message.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Format log message.
|
||||
*
|
||||
* @param message Pointer to log message structure.
|
||||
*/
|
||||
void esp_log_format(esp_log_msg_t *message);
|
||||
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
/**
|
||||
* @brief Format log message in binary mode.
|
||||
*
|
||||
* @param message Pointer to log message structure.
|
||||
*/
|
||||
void esp_log_format_binary(esp_log_msg_t *message);
|
||||
#endif // ESP_LOG_MODE_BINARY_EN
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
30
components/log/include/esp_private/log_message.h
Normal file
30
components/log/include/esp_private/log_message.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdarg.h>
|
||||
#include "esp_log_config.h"
|
||||
#include "esp_log_level.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Structure to hold log message details.
|
||||
*/
|
||||
typedef struct {
|
||||
esp_log_config_t config; /**< Log configuration */
|
||||
const char *tag; /**< Log tag */
|
||||
const char *format; /**< Log format string */
|
||||
uint64_t timestamp; /**< Log timestamp */
|
||||
const char *arg_types; /**< Log argument types */
|
||||
va_list args; /**< Log arguments */
|
||||
} esp_log_msg_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -10,7 +10,11 @@ entries:
|
||||
log_lock (noflash)
|
||||
util (noflash)
|
||||
log_timestamp_common (noflash)
|
||||
log_print (noflash)
|
||||
log (noflash)
|
||||
if LOG_MASTER_LEVEL = y:
|
||||
log_level: esp_log_get_level_master (noflash)
|
||||
if LOG_MODE_TEXT_EN = y:
|
||||
log_print (noflash)
|
||||
log_format_text (noflash)
|
||||
if LOG_MODE_BINARY_EN = y:
|
||||
log_format_binary (noflash)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -38,13 +38,21 @@ static void log_buffer_char_line(uintptr_t orig_buff, const void *ptr_line, char
|
||||
static void log_buffer_hexdump_line(uintptr_t orig_buff, const void *ptr_line, char *output_str, int buff_len);
|
||||
static void print_buffer(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level, char *output_str, print_line_t print_line_func);
|
||||
|
||||
__attribute__((unused)) const char __ESP_BUFFER_HEX_FORMAT__[] = "__ESP_BUFFER_HEX_FORMAT__ len %d, array %s, address %p";
|
||||
__attribute__((unused)) const char __ESP_BUFFER_CHAR_FORMAT__[] = "__ESP_BUFFER_CHAR_FORMAT__ len %d, array %s, address %p";
|
||||
__attribute__((unused)) const char __ESP_BUFFER_HEXDUMP_FORMAT__[] = "__ESP_BUFFER_HEXDUMP_FORMAT__ len %d, array %s, address %p";
|
||||
|
||||
void esp_log_buffer_hex_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level)
|
||||
{
|
||||
// I (954) log_example: 54 68 65 20 77 61 79 20 74 6f 20 67 65 74 20 73
|
||||
// I (962) log_example: 74 61 72 74 65 64 20 69 73 20 74 6f 20 71 75 69
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
esp_log(ESP_LOG_CONFIG_INIT(log_level | ESP_LOG_CONFIGS_DEFAULT), tag, __ESP_BUFFER_HEX_FORMAT__ ESP_LOG_ARGS(buff_len, (const char *)buffer, (void *)buffer));
|
||||
#else
|
||||
char output_str[3 * BYTES_PER_LINE];
|
||||
print_buffer(tag, buffer, buff_len, log_level, output_str, log_buffer_hex_line);
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_log_buffer_char_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level)
|
||||
@@ -52,8 +60,12 @@ void esp_log_buffer_char_internal(const char *tag, const void *buffer, uint16_t
|
||||
// I (980) log_example: The way to get s
|
||||
// I (985) log_example: tarted is to qui
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
esp_log(ESP_LOG_CONFIG_INIT(log_level | ESP_LOG_CONFIGS_DEFAULT), tag, __ESP_BUFFER_CHAR_FORMAT__ ESP_LOG_ARGS(buff_len, (const char *)buffer, (void *)buffer));
|
||||
#else
|
||||
char output_str[BYTES_PER_LINE + 1];
|
||||
print_buffer(tag, buffer, buff_len, log_level, output_str, log_buffer_char_line);
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_log_buffer_hexdump_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level)
|
||||
@@ -61,11 +73,15 @@ void esp_log_buffer_hexdump_internal(const char *tag, const void *buffer, uint16
|
||||
// I (1013) log_example: 0x3ffb5bc0 54 68 65 20 77 61 79 20 74 6f 20 67 65 74 20 73 |The way to get s|
|
||||
// I (1024) log_example: 0x3ffb5bd0 74 61 72 74 65 64 20 69 73 20 74 6f 20 71 75 69 |tarted is to qui|
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
esp_log(ESP_LOG_CONFIG_INIT(log_level | ESP_LOG_CONFIGS_DEFAULT), tag, __ESP_BUFFER_HEXDUMP_FORMAT__ ESP_LOG_ARGS(buff_len, (const char *)buffer, (void *)buffer));
|
||||
#else
|
||||
char output_str[(2 + sizeof(void *) * 2) + 3 + (BYTES_PER_LINE * 3) + 2 + (1 + BYTES_PER_LINE + 1) + 1];
|
||||
print_buffer(tag, buffer, buff_len, log_level, output_str, log_buffer_hexdump_line);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_buffer(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level, char *output_str, print_line_t print_line_func)
|
||||
__attribute__((unused)) static void print_buffer(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level, char *output_str, print_line_t print_line_func)
|
||||
{
|
||||
if (buff_len == 0) {
|
||||
return;
|
||||
@@ -89,7 +105,7 @@ static void print_buffer(const char *tag, const void *buffer, uint16_t buff_len,
|
||||
} while (buff_len);
|
||||
}
|
||||
|
||||
static void log_buffer_hex_line(uintptr_t orig_buff, const void *ptr_line, char *output_str, int buff_len)
|
||||
__attribute__((unused)) static void log_buffer_hex_line(uintptr_t orig_buff, const void *ptr_line, char *output_str, int buff_len)
|
||||
{
|
||||
(void) orig_buff;
|
||||
const unsigned char *ptr = (unsigned char *)ptr_line;
|
||||
@@ -102,7 +118,7 @@ static void log_buffer_hex_line(uintptr_t orig_buff, const void *ptr_line, char
|
||||
*output_str = '\0';
|
||||
}
|
||||
|
||||
static void log_buffer_char_line(uintptr_t orig_buff, const void *ptr_line, char *output_str, int buff_len)
|
||||
__attribute__((unused)) static void log_buffer_char_line(uintptr_t orig_buff, const void *ptr_line, char *output_str, int buff_len)
|
||||
{
|
||||
(void) orig_buff;
|
||||
const char *ptr = (char *)ptr_line;
|
||||
@@ -110,7 +126,7 @@ static void log_buffer_char_line(uintptr_t orig_buff, const void *ptr_line, char
|
||||
output_str[buff_len] = 0;
|
||||
}
|
||||
|
||||
static void log_buffer_hexdump_line(uintptr_t orig_buff, const void *ptr_line, char *output_str, int buff_len)
|
||||
__attribute__((unused)) static void log_buffer_hexdump_line(uintptr_t orig_buff, const void *ptr_line, char *output_str, int buff_len)
|
||||
{
|
||||
const unsigned char *ptr = (unsigned char *)ptr_line;
|
||||
*output_str++ = '0';
|
||||
|
@@ -1,41 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "esp_log_config.h"
|
||||
#include "esp_log_level.h"
|
||||
#include "esp_log_color.h"
|
||||
#include "esp_log_timestamp.h"
|
||||
#include "esp_private/log_level.h"
|
||||
#include "esp_private/log_timestamp.h"
|
||||
#include "esp_private/log_lock.h"
|
||||
#include "esp_private/log_util.h"
|
||||
#include "esp_private/log_print.h"
|
||||
#include "esp_private/log_message.h"
|
||||
#include "esp_private/log_format.h"
|
||||
#include "esp_log_write.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static __attribute__((unused)) const char s_lvl_name[ESP_LOG_MAX] = {
|
||||
'\0', // NONE
|
||||
'E', // ERROR
|
||||
'W', // WARNING
|
||||
'I', // INFO
|
||||
'D', // DEBUG
|
||||
'V', // VERBOSE
|
||||
};
|
||||
|
||||
static __attribute__((unused)) const char s_lvl_color[ESP_LOG_MAX][8] = {
|
||||
"\0", // NONE
|
||||
LOG_ANSI_COLOR_REGULAR(LOG_ANSI_COLOR_RED)"\0", // ERROR
|
||||
LOG_ANSI_COLOR_REGULAR(LOG_ANSI_COLOR_YELLOW)"\0", // WARNING
|
||||
LOG_ANSI_COLOR_REGULAR(LOG_ANSI_COLOR_GREEN)"\0", // INFO
|
||||
"\0", // DEBUG
|
||||
"\0", // VERBOSE
|
||||
};
|
||||
|
||||
static __attribute__((unused)) bool is_level_loggable(esp_log_config_t config)
|
||||
{
|
||||
#if BOOTLOADER_BUILD
|
||||
@@ -69,41 +55,23 @@ void __attribute__((optimize("-O3"))) esp_log_va(esp_log_config_t config, const
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// formatting log
|
||||
if (config.opts.require_formatting) { // 1. print "<color_start><level_name> <(time)> <tag>: "
|
||||
#if !ESP_LOG_CONSTRAINED_ENV
|
||||
if (!config.opts.constrained_env) {
|
||||
// flockfile&funlockfile are used here to prevent other threads
|
||||
// from writing to the same stream simultaneously using printf-like functions.
|
||||
// Below is formatting log, there are multiple calls to vprintf to log a single message.
|
||||
flockfile(stdout);
|
||||
}
|
||||
#endif
|
||||
config.opts.dis_color = !ESP_LOG_SUPPORT_COLOR || config.opts.dis_color || (s_lvl_color[config.opts.log_level][0] == '\0');
|
||||
char timestamp_buffer[32] = { 0 };
|
||||
if (!config.opts.dis_timestamp) {
|
||||
esp_log_timestamp_str(config.opts.constrained_env, timestamp, timestamp_buffer);
|
||||
}
|
||||
esp_log_printf(config, "%s%c %s%s%s%s%s",
|
||||
(!config.opts.dis_color) ? s_lvl_color[config.opts.log_level] : "",
|
||||
s_lvl_name[config.opts.log_level],
|
||||
(!config.opts.dis_timestamp) ? "(" : "",
|
||||
timestamp_buffer,
|
||||
(!config.opts.dis_timestamp) ? ") " : "",
|
||||
(tag) ? tag : "",
|
||||
(tag) ? ": " : "");
|
||||
}
|
||||
|
||||
esp_log_vprintf(config, format, args); // 2. print user message
|
||||
|
||||
if (config.opts.require_formatting) { // 3. print "<color_end><\n>"
|
||||
esp_log_printf(config, "%s", (config.opts.dis_color) ? "\n" : LOG_RESET_COLOR"\n");
|
||||
#if !ESP_LOG_CONSTRAINED_ENV
|
||||
if (!config.opts.constrained_env) {
|
||||
funlockfile(stdout);
|
||||
}
|
||||
#endif
|
||||
esp_log_msg_t message = {
|
||||
.config = config,
|
||||
.tag = tag,
|
||||
.format = format,
|
||||
.timestamp = timestamp,
|
||||
.arg_types = NULL,
|
||||
};
|
||||
va_copy(message.args, args);
|
||||
#if ESP_LOG_MODE_BINARY_EN
|
||||
if (config.opts.binary_mode) {
|
||||
message.arg_types = va_arg(message.args, const char *);
|
||||
}
|
||||
esp_log_format_binary(&message);
|
||||
#else
|
||||
esp_log_format(&message);
|
||||
#endif // ESP_LOG_MODE_BINARY_EN
|
||||
va_end(message.args);
|
||||
}
|
||||
#endif // ESP_LOG_VERSION == 2
|
||||
}
|
||||
|
296
components/log/src/log_format_binary.c
Normal file
296
components/log/src/log_format_binary.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "esp_log_config.h"
|
||||
#include "esp_log_args.h"
|
||||
#include "esp_private/log_lock.h"
|
||||
#include "esp_private/log_message.h"
|
||||
#include "esp_private/log_print.h"
|
||||
#include "esp_private/log_util.h"
|
||||
#include "soc/soc.h"
|
||||
#include "esp_rom_uart.h"
|
||||
|
||||
#if BOOTLOADER_BUILD
|
||||
#define APP_TYPE 0x01
|
||||
#else
|
||||
#define APP_TYPE 0x02
|
||||
#endif
|
||||
|
||||
#define IS_LOCATED_IN_NOLOAD_SECTION(addr) (((addr) & 0xFF000000) == 0x00000000)
|
||||
|
||||
#if CONFIG_IDF_TARGET_LINUX
|
||||
#define PRESENT_IN_ELF(addr) (false)
|
||||
#else // !CONFIG_IDF_TARGET_LINUX
|
||||
#if BOOTLOADER_BUILD
|
||||
#define PRESENT_IN_ELF(addr) ( \
|
||||
IS_LOCATED_IN_NOLOAD_SECTION(addr) \
|
||||
)
|
||||
#else // APP
|
||||
#define PRESENT_IN_ELF(addr) ( \
|
||||
IS_LOCATED_IN_NOLOAD_SECTION(addr) || \
|
||||
(((addr) >= SOC_DROM_LOW) && ((addr) < SOC_DROM_HIGH)) || \
|
||||
(((addr) >= SOC_IROM_LOW) && ((addr) < SOC_IROM_HIGH)) \
|
||||
)
|
||||
#endif // APP
|
||||
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||
|
||||
/**
|
||||
* @brief Packed control structure for binary log formatting.
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint16_t pkg_len: 10; /**< Package length (10 bits). */
|
||||
uint16_t log_level: ESP_LOG_LEVEL_LEN; /**< Log level. */
|
||||
uint16_t time_64bits: 1; /**< Timestamp is 64 bits if 1. */
|
||||
uint16_t version: 2; /**< Control structure version. */
|
||||
} opts;
|
||||
uint16_t data; /**< Raw 16-bit representation. */
|
||||
};
|
||||
uint8_t app_identifier; /**< Identifier byte for application type (see APP_TYPE). Used by the host to select the appropriate ELF file for decoding. */
|
||||
} __attribute__((packed)) control_t;
|
||||
|
||||
_Static_assert(sizeof(control_t) == 3, "control_t must be exactly 24 bits (3 bytes)");
|
||||
|
||||
typedef struct {
|
||||
uint8_t crc;
|
||||
bool buffer_hex_log;
|
||||
bool buffer_char_log;
|
||||
bool buffer_hexdump_log;
|
||||
int buffer_len;
|
||||
bool len_calculation_stage;
|
||||
} pkg_info_t;
|
||||
|
||||
extern const char __ESP_BUFFER_HEX_FORMAT__[];
|
||||
extern const char __ESP_BUFFER_CHAR_FORMAT__[];
|
||||
extern const char __ESP_BUFFER_HEXDUMP_FORMAT__[];
|
||||
|
||||
void update_crc8(uint8_t data, pkg_info_t *pkg_info)
|
||||
{
|
||||
uint8_t crc = pkg_info->crc;
|
||||
crc ^= data;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (crc & 0x80) {
|
||||
crc = (crc << 1) ^ 0x07;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
pkg_info->crc = crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Outputs data in big-endian order and updates CRC8 checksum.
|
||||
*
|
||||
* This function processes the given data in big-endian order, ensuring that
|
||||
* the data is read and transmitted in a forward order. It is particularly
|
||||
* useful for distinguishing between embedded data and address information
|
||||
* while parsing the packet. The first byte is used to differentiate between
|
||||
* data and address:
|
||||
* - 0xFF20ssssssssss: Indicates a negative length (0x20) followed by a string.
|
||||
* - 0x3Fxxxxxx: Represents an address.
|
||||
*
|
||||
* Using big-endian order avoids the need to read strings (data) in a reversed
|
||||
* or "wired" order (0xss20FFssssssss), which would occur if little-endian order were used.
|
||||
*
|
||||
* @param src Pointer to the source data to be output.
|
||||
* @param length Length of the data to be processed.
|
||||
* @param pkg_info Pointer to the package information structure, which includes
|
||||
* the current stage of length calculation and CRC8 checksum data.
|
||||
* @return The length of the processed data.
|
||||
*/
|
||||
static unsigned output(const void *src, unsigned length, pkg_info_t *pkg_info)
|
||||
{
|
||||
for (unsigned i = 0; i < length; i++) {
|
||||
uint8_t data = ((uint8_t *)src)[length - 1 - i];
|
||||
if (pkg_info->len_calculation_stage == false) {
|
||||
esp_rom_output_tx_one_char(data);
|
||||
update_crc8(data, pkg_info);
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static unsigned output_pointer(const char *ptr, pkg_info_t *pkg_info)
|
||||
{
|
||||
unsigned pkg_len = 0;
|
||||
uintptr_t addr = (uintptr_t)ptr;
|
||||
if (PRESENT_IN_ELF(addr) || addr == 0) {
|
||||
pkg_len = output(&addr, sizeof(addr), pkg_info);
|
||||
} else {
|
||||
int len = (pkg_info->buffer_len) ? pkg_info->buffer_len : strlen(ptr);
|
||||
int16_t pkg_str_len = 1 - len;
|
||||
pkg_len = output(&pkg_str_len, sizeof(pkg_str_len), pkg_info);
|
||||
for (unsigned i = 0; i < MAX(len, 2); i++) {
|
||||
pkg_len += output(&ptr[i], sizeof(uint8_t), pkg_info);
|
||||
}
|
||||
}
|
||||
return pkg_len;
|
||||
}
|
||||
|
||||
static esp_log_args_type_t get_arg_type_from_format_string(const char **format_ptr)
|
||||
{
|
||||
if (!format_ptr || !(*format_ptr)) {
|
||||
return ESP_LOG_ARGS_TYPE_NONE;
|
||||
}
|
||||
|
||||
const char *format = *format_ptr;
|
||||
while (*format) {
|
||||
if (*format++ == '%') {
|
||||
if (*format == '%') { // Skip "%%"
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle optional flags, width, and precision
|
||||
while (*format == '-' || *format == '.' || ((*format) >= '0' && (*format) <= '9')) {
|
||||
format++;
|
||||
}
|
||||
|
||||
// Handle length modifiers
|
||||
int is_long_long = 0;
|
||||
while (*format == 'l') {
|
||||
is_long_long++;
|
||||
format++;
|
||||
}
|
||||
while (*format == 'h' || *format == 'z') {
|
||||
format++;
|
||||
}
|
||||
|
||||
switch (*format++) {
|
||||
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
|
||||
*format_ptr = format;
|
||||
return ESP_LOG_ARGS_TYPE_64BITS;
|
||||
case 'c': case 'p': case 'd': case 'i': case 'u': case 'x': case 'X': case 'o':
|
||||
*format_ptr = format;
|
||||
return is_long_long >= 2 ? ESP_LOG_ARGS_TYPE_64BITS : ESP_LOG_ARGS_TYPE_32BITS;
|
||||
case 's': case 'S':
|
||||
*format_ptr = format;
|
||||
return ESP_LOG_ARGS_TYPE_POINTER;
|
||||
default:
|
||||
*format_ptr = format;
|
||||
return ESP_LOG_ARGS_TYPE_32BITS;
|
||||
}
|
||||
}
|
||||
}
|
||||
*format_ptr = format;
|
||||
return ESP_LOG_ARGS_TYPE_NONE;
|
||||
}
|
||||
|
||||
static unsigned output_arguments(esp_log_msg_t *message, va_list args, pkg_info_t *pkg_info)
|
||||
{
|
||||
unsigned pkg_len = 0;
|
||||
unsigned idx_arg = 0;
|
||||
const char *format = message->format;
|
||||
while (1) {
|
||||
esp_log_args_type_t arg_type;
|
||||
if (!message->config.opts.binary_mode) {
|
||||
assert(!IS_LOCATED_IN_NOLOAD_SECTION((uintptr_t)format) && "Misconfiguration: format must be on flash");
|
||||
arg_type = get_arg_type_from_format_string(&format);
|
||||
} else {
|
||||
arg_type = (message->arg_types[idx_arg / 4] >> ((idx_arg % 4) * ESP_LOG_ARGS_TYPE_LEN)) & 0x03;
|
||||
idx_arg++;
|
||||
}
|
||||
switch (arg_type) {
|
||||
case ESP_LOG_ARGS_TYPE_32BITS: {
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
pkg_len += output(&val, sizeof(val), pkg_info);
|
||||
if (pkg_info->buffer_hex_log || pkg_info->buffer_char_log || pkg_info->buffer_hexdump_log) {
|
||||
pkg_info->buffer_len = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_LOG_ARGS_TYPE_64BITS: {
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
pkg_len += output(&val, sizeof(val), pkg_info);
|
||||
break;
|
||||
}
|
||||
case ESP_LOG_ARGS_TYPE_POINTER: {
|
||||
const char *addr = va_arg(args, const char *);
|
||||
pkg_len += output_pointer(addr, pkg_info);
|
||||
break;
|
||||
}
|
||||
case ESP_LOG_ARGS_TYPE_NONE:
|
||||
default:
|
||||
return pkg_len;
|
||||
}
|
||||
}
|
||||
|
||||
return pkg_len;
|
||||
}
|
||||
|
||||
static unsigned calc_pkg_len(esp_log_msg_t *message, pkg_info_t *pkg_info)
|
||||
{
|
||||
unsigned pkg_len = 0;
|
||||
pkg_info->len_calculation_stage = true;
|
||||
pkg_len += sizeof(control_t);
|
||||
pkg_len += output_pointer(message->format, pkg_info);
|
||||
pkg_len += output_pointer(message->tag, pkg_info);
|
||||
pkg_len += (message->timestamp >> 32) != 0 ? sizeof(uint64_t) : sizeof(uint32_t);
|
||||
va_list args;
|
||||
va_copy(args, message->args);
|
||||
pkg_len += output_arguments(message, args, pkg_info);
|
||||
va_end(args);
|
||||
pkg_len += sizeof(uint8_t); // crc8
|
||||
pkg_info->len_calculation_stage = false;
|
||||
return pkg_len;
|
||||
}
|
||||
|
||||
/*
|
||||
[0] - Type of message: 1 - bootloader, 2 - application, ...
|
||||
[1] - Control byte: log level, version.
|
||||
[2] - Length 10 bits, so max is 1023 bytes.
|
||||
[3 - 6] - Format addr if present in ELF or embedded string
|
||||
[7 - 10] - Tag addr if present in ELF or embedded string
|
||||
[11 - 14] - Timestamp (if 32 bits)
|
||||
[15] - crc8
|
||||
|
||||
Embedded string:
|
||||
[0, 1] bytes - (10 bits) negative length of the string = 1 - len(str). 0xFFFC = len is 5, 0xFDD6 = len is 555. Max is 1023.
|
||||
next bytes - string
|
||||
*/
|
||||
void esp_log_format_binary(esp_log_msg_t *message)
|
||||
{
|
||||
assert(message != NULL);
|
||||
|
||||
if (!message->config.opts.constrained_env) {
|
||||
esp_log_impl_lock();
|
||||
}
|
||||
|
||||
pkg_info_t pkg_info = {
|
||||
.crc = 0,
|
||||
.buffer_hex_log = message->format == __ESP_BUFFER_HEX_FORMAT__,
|
||||
.buffer_char_log = message->format == __ESP_BUFFER_CHAR_FORMAT__,
|
||||
.buffer_hexdump_log = message->format == __ESP_BUFFER_HEXDUMP_FORMAT__,
|
||||
.buffer_len = 0,
|
||||
.len_calculation_stage = false,
|
||||
};
|
||||
|
||||
// Output control byte
|
||||
control_t control = {
|
||||
.opts = {
|
||||
.pkg_len = calc_pkg_len(message, &pkg_info),
|
||||
.log_level = message->config.opts.log_level,
|
||||
.time_64bits = (message->timestamp >> 32) != 0,
|
||||
.version = 0,
|
||||
},
|
||||
.app_identifier = APP_TYPE,
|
||||
};
|
||||
output(&control, sizeof(control), &pkg_info);
|
||||
output_pointer(message->format, &pkg_info);
|
||||
output_pointer(message->tag, &pkg_info);
|
||||
output(&message->timestamp, (control.opts.time_64bits) ? sizeof(uint64_t) : sizeof(uint32_t), &pkg_info);
|
||||
output_arguments(message, message->args, &pkg_info);
|
||||
output(&pkg_info.crc, sizeof(pkg_info.crc), &pkg_info);
|
||||
|
||||
if (!message->config.opts.constrained_env) {
|
||||
esp_log_impl_unlock();
|
||||
}
|
||||
}
|
77
components/log/src/log_format_text.c
Normal file
77
components/log/src/log_format_text.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "esp_log_config.h"
|
||||
#include "esp_log_level.h"
|
||||
#include "esp_log_color.h"
|
||||
#include "esp_log_timestamp.h"
|
||||
#include "esp_private/log_level.h"
|
||||
#include "esp_private/log_timestamp.h"
|
||||
#include "esp_private/log_lock.h"
|
||||
#include "esp_private/log_util.h"
|
||||
#include "esp_private/log_print.h"
|
||||
#include "esp_private/log_message.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static __attribute__((unused)) const char s_lvl_name[ESP_LOG_MAX] = {
|
||||
'\0', // NONE
|
||||
'E', // ERROR
|
||||
'W', // WARNING
|
||||
'I', // INFO
|
||||
'D', // DEBUG
|
||||
'V', // VERBOSE
|
||||
};
|
||||
|
||||
static __attribute__((unused)) const char s_lvl_color[ESP_LOG_MAX][8] = {
|
||||
"\0", // NONE
|
||||
LOG_ANSI_COLOR_REGULAR(LOG_ANSI_COLOR_RED)"\0", // ERROR
|
||||
LOG_ANSI_COLOR_REGULAR(LOG_ANSI_COLOR_YELLOW)"\0", // WARNING
|
||||
LOG_ANSI_COLOR_REGULAR(LOG_ANSI_COLOR_GREEN)"\0", // INFO
|
||||
"\0", // DEBUG
|
||||
"\0", // VERBOSE
|
||||
};
|
||||
|
||||
void esp_log_format(esp_log_msg_t *message)
|
||||
{
|
||||
if (message->config.opts.require_formatting) {
|
||||
#if !ESP_LOG_CONSTRAINED_ENV
|
||||
if (!message->config.opts.constrained_env) {
|
||||
#if CONFIG_LIBC_NEWLIB
|
||||
flockfile(stdout);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
message->config.opts.dis_color |= !ESP_LOG_SUPPORT_COLOR || (s_lvl_color[message->config.opts.log_level][0] == '\0');
|
||||
char timestamp_buffer[32] = { 0 };
|
||||
if (!message->config.opts.dis_timestamp) {
|
||||
esp_log_timestamp_str(message->config.opts.constrained_env, message->timestamp, timestamp_buffer);
|
||||
}
|
||||
esp_log_printf(message->config, "%s%c %s%s%s%s%s",
|
||||
(!message->config.opts.dis_color) ? s_lvl_color[message->config.opts.log_level] : "",
|
||||
s_lvl_name[message->config.opts.log_level],
|
||||
(!message->config.opts.dis_timestamp) ? "(" : "",
|
||||
timestamp_buffer,
|
||||
(!message->config.opts.dis_timestamp) ? ") " : "",
|
||||
(message->tag) ? message->tag : "",
|
||||
(message->tag) ? ": " : "");
|
||||
}
|
||||
|
||||
esp_log_vprintf(message->config, message->format, message->args);
|
||||
|
||||
if (message->config.opts.require_formatting) {
|
||||
esp_log_printf(message->config, "%s", (message->config.opts.dis_color) ? "\n" : LOG_RESET_COLOR"\n");
|
||||
#if !ESP_LOG_CONSTRAINED_ENV
|
||||
if (!message->config.opts.constrained_env) {
|
||||
#if CONFIG_LIBC_NEWLIB
|
||||
funlockfile(stdout);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -232,6 +232,11 @@ The following options are applicable only for **Log V2** and are used alongside
|
||||
- If global timestamping (:ref:`CONFIG_LOG_TIMESTAMP_SOURCE`) is disabled, define as ``0`` to enable tick timestamp output for the specified scope.
|
||||
- If global timestamping (:ref:`CONFIG_LOG_TIMESTAMP_SOURCE`) is enabled, define as ``1`` to disable tick timestamp output for the specified scope.
|
||||
|
||||
- **ESP_LOG_MODE_BINARY_EN**: Requires ``CONFIG_LOG_MODE_BINARY`` or ``CONFIG_BOOTLOADER_LOG_MODE_BINARY`` to be enabled.
|
||||
|
||||
- Setting ``ESP_LOG_MODE_BINARY_EN`` to ``0`` does not make sense for regular use because logs will still be sent in binary mode. However, the format string will not be removed from flash, and argument analysis will be performed at runtime. This setting may be useful for specific scenarios such as debugging or testing.
|
||||
- Setting ``ESP_LOG_MODE_BINARY_EN`` to ``1`` when text logging mode is enabled will have no effect. In this case, ``ESP_LOG_MODE_BINARY_EN`` will be suppressed and automatically defined as ``0``.
|
||||
|
||||
Per-Log Formatting
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -402,6 +407,114 @@ The logging system provides macros for logging buffer data. These macros can be
|
||||
|
||||
The number of lines in the output depends on the size of the buffer.
|
||||
|
||||
Binary Logging
|
||||
--------------
|
||||
|
||||
Binary logging is a feature available only in **Log V2**, enabling logs to be transmitted in binary format instead of text. This is configured separately for the **bootloader** (``CONFIG_BOOTLOADER_LOG_MODE_BINARY``) and **application** (``CONFIG_LOG_MODE_BINARY``) via Kconfig options.
|
||||
|
||||
By default, when **Log V2** is enabled, the logging system uses **text mode**. Enabling binary logging reduces flash memory usage by removing log format strings from flash and sending only their addresses instead. Additionally, ``printf`` functions are not used, which reduces both stack usage and flash consumption.
|
||||
|
||||
This feature introduces the :c:macro:`ESP_LOG_ATTR_STR` macro, which relocates format strings to a ``.noload`` section, effectively removing them from the final binary image. Developers can also use this mechanism for assertions or user-defined logging messages to further minimize flash usage.
|
||||
|
||||
Summary of Benefits:
|
||||
|
||||
- Reduces **flash size** by approximately **10% - 35%**, depending on the application. The more extensive the logging in a program, the greater the potential savings.
|
||||
- Minimizes **stack usage** by eliminating the need for the ``vprintf``-like function for log formatting.
|
||||
- Reduces **log transmission overhead** by transmitting compact binary data.
|
||||
|
||||
Binary logging is especially beneficial in **resource-constrained** environments where flash size optimization and efficient logging are critical.
|
||||
|
||||
Binary Logging Workflow
|
||||
-----------------------
|
||||
|
||||
Binary logging consists of two main components:
|
||||
|
||||
1. **Chip Side**: Encodes and transmits log data:
|
||||
|
||||
- Encoding process
|
||||
- Argument type encoding
|
||||
- Runtime argument type encoding
|
||||
|
||||
2. **Host Side**: Receives and decodes data using the `esp-idf-monitor tool <https://github.com/espressif/esp-idf-monitor>`_. The ``idf.py monitor`` command automatically decodes binary logs.
|
||||
|
||||
- Detects binary log packets.
|
||||
- Extracts packet fields (log level, format, tag, timestamp, arguments).
|
||||
- Determines whether addresses reference:
|
||||
|
||||
- **ELF file** (requires lookup)
|
||||
- **Embedded string** (contained in the packet)
|
||||
|
||||
- Decodes arguments using the format string and the given array of arguments.
|
||||
- Reconstructs the final log message by coupling the format string with the decoded arguments.
|
||||
- Applies terminal colorization.
|
||||
|
||||
Chip Side
|
||||
^^^^^^^^^
|
||||
|
||||
Encoding Process
|
||||
""""""""""""""""
|
||||
|
||||
Binary logs are transmitted as structured packets. Strings are sent as addresses if they exist in the ELF file. For runtime-generated strings, an embedded string format is used to transmit the string to the host.
|
||||
|
||||
Packet structure:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
[0] - Message Type (1: bootloader, 2: application, ...)
|
||||
[1] - Control Byte (log level, version, time_64bits flag)
|
||||
[2] - Length (10-bit, max 1023 bytes)
|
||||
[3-6] - Format Address (if present in ELF) or embedded string
|
||||
[7-10] - Tag Address (if present in ELF) or embedded string
|
||||
[11-14] - Timestamp (32-bit if timestamp does not exceed 32 bits. [11-18] - occupied if timestamp takes 64 bits, time_64bits flag is set in Control Byte)
|
||||
[...] - Arguments (optional). It is an array of arguments: 32-bit, 64-bit, pointers, and embedded string/data.
|
||||
[15] - CRC8 checksum
|
||||
|
||||
The embedded string format is used if string is not present in ELF file, it follows this structure:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
[0] - Embedded Identifier (0xFF - 0xFC)
|
||||
[0,1] - (10-bit) Negative Length of the string = 1 - len(str)
|
||||
[...] - String Content
|
||||
|
||||
.. note::
|
||||
|
||||
All multi-byte fields in the packet structure use big-endian encoding.
|
||||
|
||||
Argument Type Encoding
|
||||
""""""""""""""""""""""
|
||||
|
||||
Since the format string is removed from the final binary, the chip must still identify argument types to correctly transmit them to the host. This is achieved using the :c:macro:`ESP_LOG_ARGS_TYPE` macro, which leverages the `_Generic` feature to classify user arguments at compile time into three categories: **32-bit**, **64-bit**, and **pointers**. This macro generates an **argument type array** at runtime, which is passed to ``esp_log`` before the user arguments. This ensures that:
|
||||
|
||||
- The chip transmits data with the correct size and offset.
|
||||
- The host tool reconstructs the log message accurately.
|
||||
|
||||
Runtime Behavior
|
||||
""""""""""""""""
|
||||
|
||||
The ``esp_log`` function first checks if **binary logging** is enabled in the given configuration. If enabled, it extracts the **argument type array** from ``va_list``. However, if the binary log flag is **not** set, no preprocessed argument type array is available. In this case, the binary log handler **extracts argument types** from the format string at runtime.
|
||||
|
||||
This runtime extraction is less efficient than explicitly using ``ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)``, which generates the argument type array at compile time and removes the format string from flash. Nevertheless, this mechanism ensures that even if a **third-party library does not support binary logging**, logs will still be output correctly.
|
||||
|
||||
Special Handling for Buffer Logs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Binary logging supports buffer log functions such as:
|
||||
|
||||
- :c:macro:`ESP_LOG_BUFFER_HEX_LEVEL`
|
||||
- :c:macro:`ESP_LOG_BUFFER_CHAR_LEVEL`
|
||||
- :c:macro:`ESP_LOG_BUFFER_HEXDUMP`
|
||||
|
||||
For these cases, binary log handlers check whether the format address matches predefined constants (e.g., ``ESP_BUFFER_HEX_FORMAT``). Instead of sending a format string, the handler **directly transmits raw buffer data**.
|
||||
|
||||
Host Side (Monitor Tool)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
On the **host side**, the `esp-idf-monitor tool <https://github.com/espressif/esp-idf-monitor>`_ decodes binary logs automatically. It is important that the monitor tool operates with the correct version of ELF files. The **bootloader** and **application** each have their own ELF files, which the tool automatically selects when ``idf.py monitor`` is calling.
|
||||
|
||||
If an **ELF address** is received, the monitor tool **retrieves the string from the ELF file** using the corresponding ``message type`` byte. If the **address starts with 0xFF** (range: ``0xFF - 0xFC``), it indicates an **embedded string**, with its length encoded in **10 bits**.
|
||||
|
||||
Once all components are retrieved, they are formatted and output to the terminal.
|
||||
|
||||
Performance and Measurements
|
||||
----------------------------
|
||||
|
@@ -3,6 +3,7 @@
|
||||
"""
|
||||
Pytest Related Constants. Don't import third-party packages here.
|
||||
"""
|
||||
|
||||
import os
|
||||
import typing as t
|
||||
import warnings
|
||||
@@ -56,6 +57,7 @@ SPECIAL_MARKERS = {
|
||||
'temp_skip': 'temp skip tests for specified targets both in ci and locally',
|
||||
'nightly_run': 'tests should be executed as part of the nightly trigger pipeline',
|
||||
'host_test': 'tests which should not be built at the build stage, and instead built in host_test stage',
|
||||
'require_elf': 'tests which require elf file',
|
||||
}
|
||||
|
||||
ENV_MARKERS = {
|
||||
@@ -97,7 +99,7 @@ ENV_MARKERS = {
|
||||
'wifi_high_traffic': 'wifi high traffic runners',
|
||||
'wifi_wlan': 'wifi runner with a wireless NIC',
|
||||
'wifi_iperf': 'the AP and ESP dut were placed in a shielded box - for iperf test',
|
||||
'Example_ShieldBox': 'multiple shielded APs connected to shielded ESP DUT via RF cable with programmable attenuator',
|
||||
'Example_ShieldBox': 'multiple shielded APs connected to shielded ESP DUT via RF cable with programmable attenuator', # noqa E501
|
||||
'xtal_26mhz': 'runner with 26MHz xtal on board',
|
||||
'xtal_40mhz': 'runner with 40MHz xtal on board',
|
||||
'external_flash': 'external flash memory connected via VSPI (FSPI)',
|
||||
@@ -309,6 +311,8 @@ class PytestCase:
|
||||
return True
|
||||
|
||||
cases_need_elf = ['panic', 'gdbstub_runtime']
|
||||
if 'require_elf' in SPECIAL_MARKERS:
|
||||
return True
|
||||
|
||||
for case in cases_need_elf:
|
||||
if any(case in Path(app.path).parts for app in self.apps):
|
||||
|
@@ -61,6 +61,12 @@ tools/test_apps/system/gdb_loadable_elf:
|
||||
temporary: true
|
||||
reason: target esp32c6, esp32h2 is not supported yet
|
||||
|
||||
tools/test_apps/system/log:
|
||||
disable_test:
|
||||
- if: IDF_TARGET not in ["esp32", "esp32c3"]
|
||||
temporary: true
|
||||
reason: test only on esp32 as other targets are similar
|
||||
|
||||
tools/test_apps/system/longjmp_test:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32", "esp32s2", "esp32s3"]
|
||||
|
8
tools/test_apps/system/log/CMakeLists.txt
Normal file
8
tools/test_apps/system/log/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(log)
|
2
tools/test_apps/system/log/README.md
Normal file
2
tools/test_apps/system/log/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
3
tools/test_apps/system/log/main/CMakeLists.txt
Normal file
3
tools/test_apps/system/log/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS "."
|
||||
WHOLE_ARCHIVE)
|
11
tools/test_apps/system/log/main/Kconfig.projbuild
Normal file
11
tools/test_apps/system/log/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,11 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_USE_TEXT_LOG
|
||||
bool "Use text log mode for main file"
|
||||
default n
|
||||
help
|
||||
Enable this option to compile logs in the main file as text logs
|
||||
even if global binary logging is enabled.
|
||||
Used for testing purposes.
|
||||
|
||||
endmenu
|
184
tools/test_apps/system/log/main/main.c
Normal file
184
tools/test_apps/system/log/main/main.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_TEXT_LOG
|
||||
#define ESP_LOG_MODE_BINARY_EN (0)
|
||||
#endif
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Start");
|
||||
|
||||
char char_var = 'A';
|
||||
ESP_LOGI(TAG, "%s %c 0x%hhx", "char_var", char_var, char_var);
|
||||
|
||||
uint8_t var8 = 240;
|
||||
int8_t var8_2 = -120;
|
||||
ESP_LOGI(TAG, "%s %" PRIu8 " %" PRIi8, "var8", var8, var8_2);
|
||||
|
||||
uint16_t var16 = 65303;
|
||||
int16_t var16_2 = -16954;
|
||||
ESP_LOGI(TAG, "%s %" PRIu16 " %" PRIi16 " 0x%hx", "var16", var16, var16_2, var16);
|
||||
|
||||
ESP_LOGI(TAG, "%s %d", "const int var", -1024);
|
||||
ESP_LOGI(TAG, "%s %" PRIu64, ESP_LOG_ATTR_STR("const long long unsigned var"), 2095ULL);
|
||||
|
||||
const int int_var = 4095;
|
||||
const int sint_var = -4095;
|
||||
ESP_LOGI(TAG, "%s %d %d", "int_var", int_var, sint_var);
|
||||
|
||||
const uint32_t var32 = 9000;
|
||||
const int32_t svar32 = -2000;
|
||||
ESP_LOGI(TAG, "%s %" PRIu32 " %" PRIi32, "var32", var32, svar32);
|
||||
|
||||
const uint64_t var64 = 10700;
|
||||
const int64_t svar64 = -29468;
|
||||
ESP_LOGI(TAG, "%s %" PRIu64 " %" PRIi64, "var64", var64, svar64);
|
||||
uint64_t var64_2 = 10800;
|
||||
ESP_LOGI(TAG, "%s %" PRIu64 " %" PRIu32 " %" PRIu64, "64 32 64 vars", var64, var32, var64_2);
|
||||
|
||||
const size_t var_size = 96843;
|
||||
ESP_LOGI(TAG, "%s %zu %d", "var_size", var_size, sizeof(var_size));
|
||||
|
||||
float float_var = 1.6f;
|
||||
double double_var = -70.2f;
|
||||
ESP_LOGI(TAG, "%s %f", "float var", float_var);
|
||||
ESP_LOGI(TAG, "%s %lf", "double var", double_var);
|
||||
|
||||
ESP_LOGI(TAG, "%s %d %lf %" PRIu32 " %f %f %c", "int, double, var32, float, float, char", int_var, double_var, var32, float_var, float_var, char_var);
|
||||
|
||||
char str_array[] = "str_array";
|
||||
ESP_LOGI(TAG, "%s %p", str_array, (void *)str_array);
|
||||
|
||||
const char *str_ptr = "str_ptr";
|
||||
ESP_LOGI(TAG, "%s %p", str_ptr, (void *)str_ptr);
|
||||
|
||||
char buffer[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
|
||||
};
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(TAG, buffer, sizeof(buffer), ESP_LOG_INFO);
|
||||
ESP_LOGI(TAG, "buffer addr = %p", (void *)buffer);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, sizeof(buffer), ESP_LOG_INFO);
|
||||
|
||||
char txt[] = "Text1:The way to get started is to quit talking and begin doing. - Walt Disney";
|
||||
ESP_LOG_BUFFER_CHAR_LEVEL(TAG, txt, sizeof(txt), ESP_LOG_INFO);
|
||||
|
||||
static const char txt2[] = "Text2:The way to get started is to quit talking and begin doing. - Walt Disney";
|
||||
ESP_LOG_BUFFER_CHAR_LEVEL(TAG, txt2, sizeof(txt2), ESP_LOG_INFO);
|
||||
|
||||
int buffer2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
|
||||
ESP_LOGI(TAG, "buffer2 addr = %p", (void *)buffer2);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer2, sizeof(buffer2), ESP_LOG_INFO);
|
||||
|
||||
uint64_t buffer3[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
ESP_LOGI(TAG, "buffer3 addr = %p", (void *)buffer3);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer3, sizeof(buffer3), ESP_LOG_INFO);
|
||||
|
||||
///////////////////String Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> String Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%s|", "Hello_world");
|
||||
ESP_LOGI(TAG, "|%10s|", "ESP32");
|
||||
ESP_LOGI(TAG, "|%-10s|", "ESP32");
|
||||
ESP_LOGI(TAG, "|%.5s|", "Hello_world");
|
||||
|
||||
///////////////////Character Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> Character Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%c|", 'A');
|
||||
|
||||
///////////////////Integer Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> Integer Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%d|", 123);
|
||||
ESP_LOGI(TAG, "|%5d|", 42);
|
||||
ESP_LOGI(TAG, "|%05d|", 42);
|
||||
ESP_LOGI(TAG, "|%-5d|", 42);
|
||||
ESP_LOGI(TAG, "|%.5d|", 42);
|
||||
ESP_LOGI(TAG, "|%+d|", 42);
|
||||
ESP_LOGI(TAG, "|% d|", 42);
|
||||
ESP_LOGI(TAG, "|%ld|", 123456789L);
|
||||
ESP_LOGI(TAG, "|%lld|", 1234567890123456789LL);
|
||||
ESP_LOGI(TAG, "|%+10d|", 42);
|
||||
ESP_LOGI(TAG, "|% 10d|", 42);
|
||||
ESP_LOGI(TAG, "|%-+10d|", 42);
|
||||
ESP_LOGI(TAG, "|%- 10d|", 42);
|
||||
|
||||
///////////////////Pointer Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> Pointer Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%p|", (void *)0x3ff26523);
|
||||
|
||||
///////////////////Hexadecimal Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> Hexadecimal Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%x|", 255);
|
||||
ESP_LOGI(TAG, "|%X|", 255);
|
||||
ESP_LOGI(TAG, "|%05x|", 255);
|
||||
ESP_LOGI(TAG, "|%.5x|", 255);
|
||||
ESP_LOGI(TAG, "|%-5x|", 255);
|
||||
ESP_LOGI(TAG, "|%hx|", (uint16_t)0xFFFF);
|
||||
ESP_LOGI(TAG, "|%hhx|", (uint8_t)0xFF);
|
||||
ESP_LOGI(TAG, "|%#x|", 42);
|
||||
ESP_LOGI(TAG, "|%#X|", 255);
|
||||
ESP_LOGI(TAG, "|%#10x|", 42);
|
||||
ESP_LOGI(TAG, "|%-#10x|", 42);
|
||||
|
||||
///////////////////Octal Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> Octal Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%o|", 8);
|
||||
ESP_LOGI(TAG, "|%#o|", 8);
|
||||
ESP_LOGI(TAG, "|%ho|", (uint16_t)511);
|
||||
ESP_LOGI(TAG, "|%#ho|", (uint16_t)511);
|
||||
ESP_LOGI(TAG, "|%#10o|", 42);
|
||||
ESP_LOGI(TAG, "|%-#10o|", 42);
|
||||
|
||||
///////////////////Float Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> Float Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%f|", 123.456);
|
||||
ESP_LOGI(TAG, "|%.2f|", 123.456);
|
||||
ESP_LOGI(TAG, "|%.2f|", -123.456);
|
||||
ESP_LOGI(TAG, "|%10.2f|", 3.14159);
|
||||
ESP_LOGI(TAG, "|%-10.2f|", 3.14159);
|
||||
ESP_LOGI(TAG, "|%10.6f|", -123.45678933);
|
||||
ESP_LOGI(TAG, "|%-10.6f|", -123.45678933);
|
||||
|
||||
///////////////////Scientific Float Formatting Tests///////////////////
|
||||
ESP_LOGI(TAG, ">>> Scientific Float Formatting Tests <<<");
|
||||
ESP_LOGI(TAG, "|%F|", 123456.789);
|
||||
ESP_LOGI(TAG, "|%e|", 123456.789);
|
||||
ESP_LOGI(TAG, "|%E|", 123456.789);
|
||||
ESP_LOGI(TAG, "|%g|", 123456.789);
|
||||
ESP_LOGI(TAG, "|%G|", 123456.789);
|
||||
|
||||
///////////////////Literal Percent Sign///////////////////
|
||||
ESP_LOGI(TAG, ">>> Literal Percent Sign Tests <<<");
|
||||
ESP_LOGI(TAG, "|%%|");
|
||||
ESP_LOGI(TAG, "|%%| |%s|", "Hello_world");
|
||||
ESP_LOGI(TAG, "} |%s|", "Hello_world");
|
||||
|
||||
///////////////////Multiple variables in one log///////////////////
|
||||
ESP_LOGI(TAG, ">>> Multiple Variables in One Log <<<");
|
||||
ESP_LOGI(TAG, "%s |%10s| |%-10s| |%.5s|", "string width", "ESP32", "ESP32", "ESP32 Test");
|
||||
ESP_LOGI(TAG, "%s |%hx| |%hhx|", "shorts", (uint16_t)65535, (uint8_t)255);
|
||||
ESP_LOGI(TAG, "%s |% d| |% d|", " flag", 42, -42);
|
||||
ESP_LOGI(TAG, "%s |%+d| |%+d|", "+ flag", 42, -42);
|
||||
ESP_LOGI(TAG, "%s |%#lx| |%#lo|", "# flag long", 1234567890L, 1234567890L);
|
||||
ESP_LOGI(TAG, "%s |%ld| |%lld|", "longs", 1234567890L, 123456789012345LL);
|
||||
ESP_LOGI(TAG, "%s |%10.2f| |%-10.2f| |%.4f|", "float width", 3.14159, 3.14159, 3.14159);
|
||||
ESP_LOGI(TAG, "%s |%10.6lf| |%-10.6lf| |%.2lf|", "double width", -123.456789, -123.456789, -123.456789);
|
||||
|
||||
ESP_LOGI(TAG, "Success");
|
||||
}
|
184
tools/test_apps/system/log/pytest_log.py
Normal file
184
tools/test_apps/system/log/pytest_log.py
Normal file
@@ -0,0 +1,184 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
def check_output(p: Any) -> None:
|
||||
text_mode = isinstance(p, Dut)
|
||||
p.expect_exact('example: Start')
|
||||
p.expect_exact('example: char_var A 0x41')
|
||||
p.expect_exact('example: var8 240 -120')
|
||||
p.expect_exact('example: var16 65303 -16954 0xff17')
|
||||
p.expect_exact('example: const int var -1024')
|
||||
p.expect_exact('example: const long long unsigned var 2095')
|
||||
p.expect_exact('example: int_var 4095 -4095')
|
||||
p.expect_exact('example: var32 9000 -2000')
|
||||
p.expect_exact('example: var64 10700 -29468')
|
||||
p.expect_exact('example: 64 32 64 vars 10700 9000 10800')
|
||||
p.expect_exact('example: var_size 96843 4')
|
||||
p.expect_exact('example: float var 1.600000')
|
||||
p.expect_exact('example: double var -70.199997')
|
||||
p.expect_exact('example: int, double, var32, float, float, char 4095 -70.199997 9000 1.600000 1.600000 A')
|
||||
p.expect(r'example: str_array 0x[0-9a-fA-F]+')
|
||||
|
||||
p.expect(r'example: str_ptr 0x[0-9a-fA-F]+')
|
||||
p.expect_exact('example: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f')
|
||||
p.expect_exact('example: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f')
|
||||
p.expect_exact('example: 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21')
|
||||
p.expect_exact('example: 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35')
|
||||
p.expect_exact('example: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f')
|
||||
p.expect_exact('example: 50 51 52 53 54 55 56 57 58 59')
|
||||
|
||||
match = p.expect(r'example: buffer addr = 0x([0-9a-fA-F]+)')
|
||||
addr = int((match.group(1) if text_mode else p.match.group(1)), 16)
|
||||
p.expect_exact(f'example: {addr + 0:#x} 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|')
|
||||
p.expect_exact(f'example: {addr + 16:#x} 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................|')
|
||||
p.expect_exact(f'example: {addr + 32:#x} 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 | !!!!!!!!!!!!!!!|')
|
||||
p.expect_exact(f'example: {addr + 48:#x} 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 |0123456789012345|')
|
||||
p.expect_exact(f'example: {addr + 64:#x} 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO|')
|
||||
p.expect_exact(f'example: {addr + 80:#x} 50 51 52 53 54 55 56 57 58 59 |PQRSTUVWXY|')
|
||||
p.expect_exact('example: Text1:The way to')
|
||||
p.expect_exact('example: get started is ')
|
||||
p.expect_exact('example: to quit talking ')
|
||||
p.expect_exact('example: and begin doing.')
|
||||
p.expect_exact('example: - Walt Disney')
|
||||
p.expect_exact('example: Text2:The way to')
|
||||
p.expect_exact('example: get started is ')
|
||||
p.expect_exact('example: to quit talking ')
|
||||
p.expect_exact('example: and begin doing.')
|
||||
p.expect_exact('example: - Walt Disney')
|
||||
|
||||
match = p.expect(r'example: buffer2 addr = 0x([0-9a-fA-F]+)')
|
||||
addr = int((match.group(1) if text_mode else p.match.group(1)), 16)
|
||||
p.expect_exact(f'example: {addr + 0:#x} 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 16:#x} 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 32:#x} 08 00 00 00 09 00 00 00 0a 00 00 00 0b 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 48:#x} 0c 00 00 00 0d 00 00 00 0e 00 00 00 0f 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 64:#x} 10 00 00 00 11 00 00 00 12 00 00 00 13 00 00 00 |................|')
|
||||
|
||||
match = p.expect(r'example: buffer3 addr = 0x([0-9a-fA-F]+)')
|
||||
addr = int((match.group(1) if text_mode else p.match.group(1)), 16)
|
||||
p.expect_exact(f'example: {addr + 0:#x} 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 16:#x} 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 32:#x} 04 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 48:#x} 06 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 64:#x} 08 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 |................|')
|
||||
p.expect_exact(f'example: {addr + 80:#x} 0a 00 00 00 00 00 00 00 |........|')
|
||||
p.expect_exact('example: >>> String Formatting Tests <<<')
|
||||
p.expect_exact('example: |Hello_world|')
|
||||
p.expect_exact('example: | ESP32|')
|
||||
p.expect_exact('example: |ESP32 |')
|
||||
p.expect_exact('example: |Hello|')
|
||||
|
||||
p.expect_exact('example: >>> Character Formatting Tests <<<')
|
||||
p.expect_exact('example: |A|')
|
||||
|
||||
p.expect_exact('example: >>> Integer Formatting Tests <<<')
|
||||
p.expect_exact('example: |123|')
|
||||
p.expect_exact('example: | 42|')
|
||||
p.expect_exact('example: |00042|')
|
||||
p.expect_exact('example: |42 |')
|
||||
p.expect_exact('example: |00042|')
|
||||
p.expect_exact('example: |+42|')
|
||||
p.expect_exact('example: | 42|')
|
||||
p.expect_exact('example: |123456789|')
|
||||
p.expect_exact('example: |1234567890123456789|')
|
||||
p.expect_exact('example: | +42|')
|
||||
p.expect_exact('example: | 42|')
|
||||
p.expect_exact('example: |+42 |')
|
||||
p.expect_exact('example: | 42 |')
|
||||
|
||||
p.expect_exact('example: >>> Pointer Formatting Tests <<<')
|
||||
p.expect_exact('example: |0x3ff26523|')
|
||||
|
||||
p.expect_exact('example: >>> Hexadecimal Formatting Tests <<<')
|
||||
p.expect_exact('example: |ff|')
|
||||
p.expect_exact('example: |FF|')
|
||||
p.expect_exact('example: |000ff|')
|
||||
p.expect_exact('example: |000ff|')
|
||||
p.expect_exact('example: |ff |')
|
||||
p.expect_exact('example: |ffff|')
|
||||
p.expect_exact('example: |ff|')
|
||||
p.expect_exact('example: |0x2a|')
|
||||
p.expect_exact('example: |0XFF|')
|
||||
p.expect_exact('example: | 0x2a|')
|
||||
p.expect_exact('example: |0x2a |')
|
||||
|
||||
p.expect_exact('example: >>> Octal Formatting Tests <<<')
|
||||
p.expect_exact('example: |10|')
|
||||
p.expect_exact('example: |010|')
|
||||
p.expect_exact('example: |777|')
|
||||
p.expect_exact('example: |0777|')
|
||||
p.expect_exact('example: | 052|')
|
||||
p.expect_exact('example: |052 |')
|
||||
|
||||
p.expect_exact('example: >>> Float Formatting Tests <<<')
|
||||
p.expect_exact('example: |123.456000|')
|
||||
p.expect_exact('example: |123.46|')
|
||||
p.expect_exact('example: |-123.46|')
|
||||
p.expect_exact('example: | 3.14|')
|
||||
p.expect_exact('example: |3.14 |')
|
||||
p.expect_exact('example: |-123.456789|')
|
||||
p.expect_exact('example: |-123.456789|')
|
||||
|
||||
p.expect_exact('example: >>> Scientific Float Formatting Tests <<<')
|
||||
p.expect_exact('example: |123456.789000|')
|
||||
p.expect_exact('example: |1.234568e+05|')
|
||||
p.expect_exact('example: |1.234568E+05|')
|
||||
p.expect_exact('example: |123457|')
|
||||
p.expect_exact('example: |123457|')
|
||||
|
||||
p.expect_exact('example: >>> Literal Percent Sign Tests <<<')
|
||||
p.expect_exact('example: |%|')
|
||||
p.expect_exact('example: |%| |Hello_world|')
|
||||
p.expect_exact('example: } |Hello_world|')
|
||||
|
||||
p.expect_exact('example: >>> Multiple Variables in One Log <<<')
|
||||
p.expect_exact('example: string width | ESP32| |ESP32 | |ESP32|')
|
||||
p.expect_exact('example: shorts |ffff| |ff|')
|
||||
p.expect_exact('example: flag | 42| |-42|')
|
||||
p.expect_exact('example: + flag |+42| |-42|')
|
||||
p.expect_exact('example: # flag long |0x499602d2| |011145401322|')
|
||||
p.expect_exact('example: longs |1234567890| |123456789012345|')
|
||||
p.expect_exact('example: float width | 3.14| |3.14 | |3.1416|')
|
||||
p.expect_exact('example: double width |-123.456789| |-123.456789| |-123.46|')
|
||||
|
||||
p.expect_exact('example: Success')
|
||||
p.expect_exact('main_task: Returned from app_main()')
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.require_elf
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'v1',
|
||||
'v2_bin',
|
||||
'v2_bin_with_txt',
|
||||
'v2_txt',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target'])
|
||||
def test_log(dut: Dut) -> None:
|
||||
if dut.app.sdkconfig.get('LOG_MODE_BINARY_EN'):
|
||||
time.sleep(3) # Gives time for output logs by dut.
|
||||
dut.serial.close()
|
||||
monitor_cmd = f'{sys.executable} -m esp_idf_monitor --port {dut.serial.port} {dut.serial.app.elf_file}'
|
||||
if dut.app.sdkconfig.get('BOOTLOADER_LOG_MODE_BINARY_EN'):
|
||||
monitor_cmd += ' ' + os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.elf')
|
||||
monitor_log_path = os.path.join(dut.logdir, 'monitor.txt')
|
||||
with open(monitor_log_path, 'w') as log, pexpect.spawn(
|
||||
monitor_cmd, logfile=log, timeout=3, encoding='utf-8', codec_errors='ignore'
|
||||
) as p:
|
||||
check_output(p)
|
||||
else:
|
||||
check_output(dut)
|
1
tools/test_apps/system/log/sdkconfig.ci.v1
Normal file
1
tools/test_apps/system/log/sdkconfig.ci.v1
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_LOG_VERSION_1=y
|
2
tools/test_apps/system/log/sdkconfig.ci.v2_bin
Normal file
2
tools/test_apps/system/log/sdkconfig.ci.v2_bin
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_LOG_VERSION_2=y
|
||||
CONFIG_LOG_MODE_BINARY=y
|
3
tools/test_apps/system/log/sdkconfig.ci.v2_bin_with_txt
Normal file
3
tools/test_apps/system/log/sdkconfig.ci.v2_bin_with_txt
Normal file
@@ -0,0 +1,3 @@
|
||||
CONFIG_LOG_VERSION_2=y
|
||||
CONFIG_LOG_MODE_BINARY=y
|
||||
CONFIG_EXAMPLE_USE_TEXT_LOG=y
|
2
tools/test_apps/system/log/sdkconfig.ci.v2_txt
Normal file
2
tools/test_apps/system/log/sdkconfig.ci.v2_txt
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_LOG_VERSION_2=y
|
||||
CONFIG_LOG_MODE_TEXT=y
|
0
tools/test_apps/system/log/sdkconfig.defaults
Normal file
0
tools/test_apps/system/log/sdkconfig.defaults
Normal file
Reference in New Issue
Block a user