1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef __ESP_LOG_H__
8 #define __ESP_LOG_H__
9 
10 #include <stdint.h>
11 #include <stdarg.h>
12 #include "sdkconfig.h"
13 #include "esp_rom_sys.h"
14 #if CONFIG_IDF_TARGET_ESP32
15 #include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
16 #elif CONFIG_IDF_TARGET_ESP32S2
17 #include "esp32s2/rom/ets_sys.h"
18 #elif CONFIG_IDF_TARGET_ESP32S3
19 #include "esp32s3/rom/ets_sys.h"
20 #elif CONFIG_IDF_TARGET_ESP32C3
21 #include "esp32c3/rom/ets_sys.h"
22 #elif CONFIG_IDF_TARGET_ESP32H2
23 #include "esp32h2/rom/ets_sys.h"
24 #endif
25 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
30 /**
31  * @brief Log level
32  *
33  */
34 typedef enum {
35     ESP_LOG_NONE,       /*!< No log output */
36     ESP_LOG_ERROR,      /*!< Critical errors, software module can not recover on its own */
37     ESP_LOG_WARN,       /*!< Error conditions from which recovery measures have been taken */
38     ESP_LOG_INFO,       /*!< Information messages which describe normal flow of events */
39     ESP_LOG_DEBUG,      /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
40     ESP_LOG_VERBOSE     /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
41 } esp_log_level_t;
42 
43 typedef int (*vprintf_like_t)(const char *, va_list);
44 
45 /**
46  * @brief Default log level
47  *
48  * This is used by the definition of ESP_EARLY_LOGx macros. It is not
49  * recommended to set this directly, call esp_log_level_set("*", level)
50  * instead.
51  */
52 extern esp_log_level_t esp_log_default_level;
53 
54 /**
55  * @brief Set log level for given tag
56  *
57  * If logging for given component has already been enabled, changes previous setting.
58  *
59  * Note that this function can not raise log level above the level set using
60  * CONFIG_LOG_MAXIMUM_LEVEL setting in menuconfig.
61  *
62  * To raise log level above the default one for a given file, define
63  * LOG_LOCAL_LEVEL to one of the ESP_LOG_* values, before including
64  * esp_log.h in this file.
65  *
66  * @param tag Tag of the log entries to enable. Must be a non-NULL zero terminated string.
67  *            Value "*" resets log level for all tags to the given value.
68  *
69  * @param level  Selects log level to enable. Only logs at this and lower verbosity
70  * levels will be shown.
71  */
72 void esp_log_level_set(const char* tag, esp_log_level_t level);
73 
74 /**
75  * @brief Get log level for given tag, can be used to avoid expensive log statements
76  *
77  * @param tag Tag of the log to query current level. Must be a non-NULL zero terminated
78  *            string.
79  *
80  * @return The current log level for the given tag
81  */
82 esp_log_level_t esp_log_level_get(const char* tag);
83 
84 /**
85  * @brief Set function used to output log entries
86  *
87  * By default, log output goes to UART0. This function can be used to redirect log
88  * output to some other destination, such as file or network. Returns the original
89  * log handler, which may be necessary to return output to the previous destination.
90  *
91  * @note Please note that function callback here must be re-entrant as it can be
92  * invoked in parallel from multiple thread context.
93  *
94  * @param func new Function used for output. Must have same signature as vprintf.
95  *
96  * @return func old Function used for output.
97  */
98 vprintf_like_t esp_log_set_vprintf(vprintf_like_t func);
99 
100 /**
101  * @brief Function which returns timestamp to be used in log output
102  *
103  * This function is used in expansion of ESP_LOGx macros.
104  * In the 2nd stage bootloader, and at early application startup stage
105  * this function uses CPU cycle counter as time source. Later when
106  * FreeRTOS scheduler start running, it switches to FreeRTOS tick count.
107  *
108  * For now, we ignore millisecond counter overflow.
109  *
110  * @return timestamp, in milliseconds
111  */
112 uint32_t esp_log_timestamp(void);
113 
114 /**
115  * @brief Function which returns system timestamp to be used in log output
116  *
117  * This function is used in expansion of ESP_LOGx macros to print
118  * the system time as "HH:MM:SS.sss". The system time is initialized to
119  * 0 on startup, this can be set to the correct time with an SNTP sync,
120  * or manually with standard POSIX time functions.
121  *
122  * Currently this will not get used in logging from binary blobs
123  * (i.e WiFi & Bluetooth libraries), these will still print the RTOS tick time.
124  *
125  * @return timestamp, in "HH:MM:SS.sss"
126  */
127 char* esp_log_system_timestamp(void);
128 
129 /**
130  * @brief Function which returns timestamp to be used in log output
131  *
132  * This function uses HW cycle counter and does not depend on OS,
133  * so it can be safely used after application crash.
134  *
135  * @return timestamp, in milliseconds
136  */
137 uint32_t esp_log_early_timestamp(void);
138 
139 /**
140  * @brief Write message into the log
141  *
142  * This function is not intended to be used directly. Instead, use one of
143  * ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros.
144  *
145  * This function or these macros should not be used from an interrupt.
146  */
147 void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
148 
149 /**
150  * @brief Write message into the log, va_list variant
151  * @see esp_log_write()
152  *
153  * This function is provided to ease integration toward other logging framework,
154  * so that esp_log can be used as a log sink.
155  */
156 void esp_log_writev(esp_log_level_t level, const char* tag, const char* format, va_list args);
157 
158 /** @cond */
159 
160 #include "esp_log_internal.h"
161 
162 #ifndef LOG_LOCAL_LEVEL
163 #ifndef BOOTLOADER_BUILD
164 #define LOG_LOCAL_LEVEL  CONFIG_BOOTLOADER_LOG_LEVEL
165 #else
166 #define LOG_LOCAL_LEVEL  CONFIG_BOOTLOADER_LOG_LEVEL
167 #endif
168 #endif
169 
170 /** @endcond */
171 
172 /**
173  * @brief Log a buffer of hex bytes at specified level, separated into 16 bytes each line.
174  *
175  * @param  tag      description tag
176  * @param  buffer   Pointer to the buffer array
177  * @param  buff_len length of buffer in bytes
178  * @param  level    level of the log
179  *
180  */
181 #define ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, level ) \
182     do {\
183         if ( LOG_LOCAL_LEVEL >= (level) ) { \
184             esp_log_buffer_hex_internal( tag, buffer, buff_len, level ); \
185         } \
186     } while(0)
187 
188 /**
189  * @brief Log a buffer of characters at specified level, separated into 16 bytes each line. Buffer should contain only printable characters.
190  *
191  * @param  tag      description tag
192  * @param  buffer   Pointer to the buffer array
193  * @param  buff_len length of buffer in bytes
194  * @param  level    level of the log
195  *
196  */
197 #define ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, level ) \
198     do {\
199         if ( LOG_LOCAL_LEVEL >= (level) ) { \
200             esp_log_buffer_char_internal( tag, buffer, buff_len, level ); \
201         } \
202     } while(0)
203 
204 /**
205  * @brief Dump a buffer to the log at specified level.
206  *
207  * The dump log shows just like the one below:
208  *
209  *      W (195) log_example: 0x3ffb4280   45 53 50 33 32 20 69 73  20 67 72 65 61 74 2c 20  |ESP32 is great, |
210  *      W (195) log_example: 0x3ffb4290   77 6f 72 6b 69 6e 67 20  61 6c 6f 6e 67 20 77 69  |working along wi|
211  *      W (205) log_example: 0x3ffb42a0   74 68 20 74 68 65 20 49  44 46 2e 00              |th the IDF..|
212  *
213  * It is highly recommend to use terminals with over 102 text width.
214  *
215  * @param tag description tag
216  * @param buffer Pointer to the buffer array
217  * @param buff_len length of buffer in bytes
218  * @param level level of the log
219  */
220 #define ESP_LOG_BUFFER_HEXDUMP( tag, buffer, buff_len, level ) \
221     do { \
222         if ( LOG_LOCAL_LEVEL >= (level) ) { \
223             esp_log_buffer_hexdump_internal( tag, buffer, buff_len, level); \
224         } \
225     } while(0)
226 
227 /**
228  * @brief Log a buffer of hex bytes at Info level
229  *
230  * @param  tag      description tag
231  * @param  buffer   Pointer to the buffer array
232  * @param  buff_len length of buffer in bytes
233  *
234  * @see ``esp_log_buffer_hex_level``
235  *
236  */
237 #define ESP_LOG_BUFFER_HEX(tag, buffer, buff_len) \
238     do { \
239         if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { \
240             ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ); \
241         }\
242     } while(0)
243 
244 /**
245  * @brief Log a buffer of characters at Info level. Buffer should contain only printable characters.
246  *
247  * @param  tag      description tag
248  * @param  buffer   Pointer to the buffer array
249  * @param  buff_len length of buffer in bytes
250  *
251  * @see ``esp_log_buffer_char_level``
252  *
253  */
254 #define ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len) \
255     do { \
256         if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { \
257             ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ); \
258         }\
259     } while(0)
260 
261 /** @cond */
262 
263 //to be back compatible
264 #define esp_log_buffer_hex      ESP_LOG_BUFFER_HEX
265 #define esp_log_buffer_char     ESP_LOG_BUFFER_CHAR
266 
267 
268 #if CONFIG_LOG_COLORS
269 #define LOG_COLOR_BLACK   "30"
270 #define LOG_COLOR_RED     "31"
271 #define LOG_COLOR_GREEN   "32"
272 #define LOG_COLOR_BROWN   "33"
273 #define LOG_COLOR_BLUE    "34"
274 #define LOG_COLOR_PURPLE  "35"
275 #define LOG_COLOR_CYAN    "36"
276 #define LOG_COLOR(COLOR)  "\033[0;" COLOR "m"
277 #define LOG_BOLD(COLOR)   "\033[1;" COLOR "m"
278 #define LOG_RESET_COLOR   "\033[0m"
279 #define LOG_COLOR_E       LOG_COLOR(LOG_COLOR_RED)
280 #define LOG_COLOR_W       LOG_COLOR(LOG_COLOR_BROWN)
281 #define LOG_COLOR_I       LOG_COLOR(LOG_COLOR_GREEN)
282 #define LOG_COLOR_D
283 #define LOG_COLOR_V
284 #else //CONFIG_LOG_COLORS
285 #define LOG_COLOR_E
286 #define LOG_COLOR_W
287 #define LOG_COLOR_I
288 #define LOG_COLOR_D
289 #define LOG_COLOR_V
290 #define LOG_RESET_COLOR
291 #endif //CONFIG_LOG_COLORS
292 
293 #define LOG_FORMAT(letter, format)  LOG_COLOR_ ## letter #letter " (%u) %s: " format LOG_RESET_COLOR "\n"
294 #define LOG_SYSTEM_TIME_FORMAT(letter, format)  LOG_COLOR_ ## letter #letter " (%s) %s: " format LOG_RESET_COLOR "\n"
295 
296 /** @endcond */
297 
298 /// macro to output logs in startup code, before heap allocator and syscalls have been initialized. log at ``ESP_LOG_ERROR`` level. @see ``printf``,``ESP_LOGE``,``ESP_DRAM_LOGE``
299 #define portGET_ARGUMENT_COUNT_INNER(zero, one, count, ...) count
300 
301 /**
302  * In the future, we want to switch to C++20. We also want to become compatible with clang.
303  * Hence, we provide two versions of the following macros which are using variadic arguments.
304  * The first one is using the GNU extension \#\#__VA_ARGS__. The second one is using the C++20 feature __VA_OPT__(,).
305  * This allows users to compile their code with standard C++20 enabled instead of the GNU extension.
306  * Below C++20, we haven't found any good alternative to using \#\#__VA_ARGS__.
307  */
308 #if defined(__cplusplus) && (__cplusplus >  201703L)
309 #define ESP_EARLY_LOGE( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_ERROR,   E __VA_OPT__(,) __VA_ARGS__)
310 /// macro to output logs in startup code at ``ESP_LOG_WARN`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
311 #define ESP_EARLY_LOGW( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_WARN,    W __VA_OPT__(,) __VA_ARGS__)
312 /// macro to output logs in startup code at ``ESP_LOG_INFO`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
313 #define ESP_EARLY_LOGI( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_INFO,    I __VA_OPT__(,) __VA_ARGS__)
314 /// macro to output logs in startup code at ``ESP_LOG_DEBUG`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
315 #define ESP_EARLY_LOGD( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_DEBUG,   D __VA_OPT__(,) __VA_ARGS__)
316 /// macro to output logs in startup code at ``ESP_LOG_VERBOSE`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
317 #define ESP_EARLY_LOGV( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_VERBOSE, V __VA_OPT__(,) __VA_ARGS__)
318 #else // !(defined(__cplusplus) && (__cplusplus >  201703L))
319 #define ESP_EARLY_LOGE( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_ERROR,   E, ##__VA_ARGS__)
320 /// macro to output logs in startup code at ``ESP_LOG_WARN`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
321 #define ESP_EARLY_LOGW( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_WARN,    W, ##__VA_ARGS__)
322 /// macro to output logs in startup code at ``ESP_LOG_INFO`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
323 #define ESP_EARLY_LOGI( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_INFO,    I, ##__VA_ARGS__)
324 /// macro to output logs in startup code at ``ESP_LOG_DEBUG`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
325 #define ESP_EARLY_LOGD( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_DEBUG,   D, ##__VA_ARGS__)
326 /// macro to output logs in startup code at ``ESP_LOG_VERBOSE`` level.  @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf``
327 #define ESP_EARLY_LOGV( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_VERBOSE, V, ##__VA_ARGS__)
328 #endif // !(defined(__cplusplus) && (__cplusplus >  201703L))
329 
330 #ifdef BOOTLOADER_BUILD
331 #define _ESP_LOG_EARLY_ENABLED(log_level) (LOG_LOCAL_LEVEL >= (log_level))
332 #else
333 /* For early log, there is no log tag filtering. So we want to log only if both the LOG_LOCAL_LEVEL and the
334    currently configured min log level are higher than the log level */
335 #define _ESP_LOG_EARLY_ENABLED(log_level) (LOG_LOCAL_LEVEL >= (log_level) && esp_log_default_level >= (log_level))
336 #endif
337 
338 #define ESP_LOG_EARLY_IMPL(tag, format, log_level, log_tag_letter, ...) do {                             \
339         if (_ESP_LOG_EARLY_ENABLED(log_level)) {                                                         \
340             esp_rom_printf(LOG_FORMAT(log_tag_letter, format), esp_log_timestamp(), tag, ##__VA_ARGS__); \
341         }} while(0)
342 
343 #ifndef BOOTLOADER_BUILD
344 #if defined(__cplusplus) && (__cplusplus >  201703L)
345 #define ESP_LOGE( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR,   tag, format __VA_OPT__(,) __VA_ARGS__)
346 #define ESP_LOGW( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN,    tag, format __VA_OPT__(,) __VA_ARGS__)
347 #define ESP_LOGI( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO,    tag, format __VA_OPT__(,) __VA_ARGS__)
348 #define ESP_LOGD( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG,   tag, format __VA_OPT__(,) __VA_ARGS__)
349 #define ESP_LOGV( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, tag, format __VA_OPT__(,) __VA_ARGS__)
350 #else // !(defined(__cplusplus) && (__cplusplus >  201703L))
351 #define ESP_LOGE( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR,   tag, format, ##__VA_ARGS__)
352 #define ESP_LOGW( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN,    tag, format, ##__VA_ARGS__)
353 #define ESP_LOGI( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO,    tag, format, ##__VA_ARGS__)
354 #define ESP_LOGD( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG,   tag, format, ##__VA_ARGS__)
355 #define ESP_LOGV( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, tag, format, ##__VA_ARGS__)
356 #endif // !(defined(__cplusplus) && (__cplusplus >  201703L))
357 #else
358 
359 /**
360  * Macro to output logs at ESP_LOG_ERROR level.
361  *
362  * @note This macro cannot be used when interrupts are disabled or inside an ISR. @see ``ESP_DRAM_LOGE``.
363  *
364  * @param tag tag of the log, which can be used to change the log level by ``esp_log_level_set`` at runtime.
365  *
366  * @see ``printf``
367  */
368 #if defined(__cplusplus) && (__cplusplus >  201703L)
369 #define ESP_LOGE( tag, format, ... )  ESP_EARLY_LOGE(tag, format __VA_OPT__(,) __VA_ARGS__)
370 /// macro to output logs at ``ESP_LOG_WARN`` level.  @see ``ESP_LOGE``
371 #define ESP_LOGW( tag, format, ... )  ESP_EARLY_LOGW(tag, format __VA_OPT__(,) __VA_ARGS__)
372 /// macro to output logs at ``ESP_LOG_INFO`` level.  @see ``ESP_LOGE``
373 #define ESP_LOGI( tag, format, ... )  ESP_EARLY_LOGI(tag, format __VA_OPT__(,) __VA_ARGS__)
374 /// macro to output logs at ``ESP_LOG_DEBUG`` level.  @see ``ESP_LOGE``
375 #define ESP_LOGD( tag, format, ... )  ESP_EARLY_LOGD(tag, format __VA_OPT__(,) __VA_ARGS__)
376 /// macro to output logs at ``ESP_LOG_VERBOSE`` level.  @see ``ESP_LOGE``
377 #define ESP_LOGV( tag, format, ... )  ESP_EARLY_LOGV(tag, format __VA_OPT__(,) __VA_ARGS__)
378 #else // !(defined(__cplusplus) && (__cplusplus >  201703L))
379 #define ESP_LOGE( tag, format, ... )  ESP_EARLY_LOGE(tag, format, ##__VA_ARGS__)
380 /// macro to output logs at ``ESP_LOG_WARN`` level.  @see ``ESP_LOGE``
381 #define ESP_LOGW( tag, format, ... )  ESP_EARLY_LOGW(tag, format, ##__VA_ARGS__)
382 /// macro to output logs at ``ESP_LOG_INFO`` level.  @see ``ESP_LOGE``
383 #define ESP_LOGI( tag, format, ... )  ESP_EARLY_LOGI(tag, format, ##__VA_ARGS__)
384 /// macro to output logs at ``ESP_LOG_DEBUG`` level.  @see ``ESP_LOGE``
385 #define ESP_LOGD( tag, format, ... )  ESP_EARLY_LOGD(tag, format, ##__VA_ARGS__)
386 /// macro to output logs at ``ESP_LOG_VERBOSE`` level.  @see ``ESP_LOGE``
387 #define ESP_LOGV( tag, format, ... )  ESP_EARLY_LOGV(tag, format, ##__VA_ARGS__)
388 #endif // !(defined(__cplusplus) && (__cplusplus >  201703L))
389 #endif  // BOOTLOADER_BUILD
390 
391 /** runtime macro to output logs at a specified level.
392  *
393  * @param tag tag of the log, which can be used to change the log level by ``esp_log_level_set`` at runtime.
394  * @param level level of the output log.
395  * @param format format of the output log. see ``printf``
396  * @param ... variables to be replaced into the log. see ``printf``
397  *
398  * @see ``printf``
399  */
400 /* Zephyr: remove ESP_LOG */
401 #define ESP_LOG_LEVEL(level, tag, format, ...)
402 
403 /*
404         else if (level==ESP_LOG_WARN )      { esp_log_write(ESP_LOG_WARN,       tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
405         else if (level==ESP_LOG_DEBUG )     { esp_log_write(ESP_LOG_DEBUG,      tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
406         else if (level==ESP_LOG_VERBOSE )   { esp_log_write(ESP_LOG_VERBOSE,    tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
407         else                                { esp_log_write(ESP_LOG_INFO,       tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
408     } while(0)
409 #elif CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM
410 #define ESP_LOG_LEVEL(level, tag, format, ...) do {                     \
411         if (level==ESP_LOG_ERROR )          { esp_log_write(ESP_LOG_ERROR,      tag, LOG_SYSTEM_TIME_FORMAT(E, format), esp_log_system_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
412         else if (level==ESP_LOG_WARN )      { esp_log_write(ESP_LOG_WARN,       tag, LOG_SYSTEM_TIME_FORMAT(W, format), esp_log_system_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
413         else if (level==ESP_LOG_DEBUG )     { esp_log_write(ESP_LOG_DEBUG,      tag, LOG_SYSTEM_TIME_FORMAT(D, format), esp_log_system_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
414         else if (level==ESP_LOG_VERBOSE )   { esp_log_write(ESP_LOG_VERBOSE,    tag, LOG_SYSTEM_TIME_FORMAT(V, format), esp_log_system_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
415         else                                { esp_log_write(ESP_LOG_INFO,       tag, LOG_SYSTEM_TIME_FORMAT(I, format), esp_log_system_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
416     } while(0)
417 #endif //CONFIG_LOG_TIMESTAMP_SOURCE_xxx
418 #else // !(defined(__cplusplus) && (__cplusplus >  201703L))
419 #if CONFIG_LOG_TIMESTAMP_SOURCE_RTOS
420 #define ESP_LOG_LEVEL(level, tag, format, ...) do {                     \
421         if (level==ESP_LOG_ERROR )          { esp_log_write(ESP_LOG_ERROR,      tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \
422         else if (level==ESP_LOG_WARN )      { esp_log_write(ESP_LOG_WARN,       tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \
423         else if (level==ESP_LOG_DEBUG )     { esp_log_write(ESP_LOG_DEBUG,      tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \
424         else if (level==ESP_LOG_VERBOSE )   { esp_log_write(ESP_LOG_VERBOSE,    tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \
425         else                                { esp_log_write(ESP_LOG_INFO,       tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \
426     } while(0)
427 #elif CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM
428 #define ESP_LOG_LEVEL(level, tag, format, ...) do {                     \
429         if (level==ESP_LOG_ERROR )          { esp_log_write(ESP_LOG_ERROR,      tag, LOG_SYSTEM_TIME_FORMAT(E, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \
430         else if (level==ESP_LOG_WARN )      { esp_log_write(ESP_LOG_WARN,       tag, LOG_SYSTEM_TIME_FORMAT(W, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \
431         else if (level==ESP_LOG_DEBUG )     { esp_log_write(ESP_LOG_DEBUG,      tag, LOG_SYSTEM_TIME_FORMAT(D, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \
432         else if (level==ESP_LOG_VERBOSE )   { esp_log_write(ESP_LOG_VERBOSE,    tag, LOG_SYSTEM_TIME_FORMAT(V, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \
433         else                                { esp_log_write(ESP_LOG_INFO,       tag, LOG_SYSTEM_TIME_FORMAT(I, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \
434     } while(0)
435 #endif //CONFIG_LOG_TIMESTAMP_SOURCE_xxx
436 #endif // !(defined(__cplusplus) && (__cplusplus >  201703L))
437 */
438 
439 /** runtime macro to output logs at a specified level. Also check the level with ``LOG_LOCAL_LEVEL``.
440  *
441  * @see ``printf``, ``ESP_LOG_LEVEL``
442  */
443 #define ESP_LOG_LEVEL_LOCAL(level, tag, format, ...) do {               \
444         if ( LOG_LOCAL_LEVEL >= level ) ESP_LOG_LEVEL(level, tag, format, ##__VA_ARGS__); \
445     } while(0)
446 
447 
448 /**
449  * @brief Macro to output logs when the cache is disabled. log at ``ESP_LOG_ERROR`` level.
450  *
451  * @note Unlike normal logging macros, it's possible to use this macro when interrupts are
452  * disabled or inside an ISR.
453  *
454  * Similar to @see ``ESP_EARLY_LOGE``, the log level cannot be changed per-tag, however
455  * esp_log_level_set("*", level) will set the default level which controls these log lines also.
456  *
457  * Usage: `ESP_DRAM_LOGE(DRAM_STR("my_tag"), "format", or `ESP_DRAM_LOGE(TAG, "format", ...)`,
458  * where TAG is a char* that points to a str in the DRAM.
459  *
460  * @note Placing log strings in DRAM reduces available DRAM, so only use when absolutely essential.
461  *
462  * @see ``esp_rom_printf``,``ESP_LOGE``
463  */
464 #if defined(__cplusplus) && (__cplusplus >  201703L)
465 #define ESP_DRAM_LOGE( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_ERROR,   E __VA_OPT__(,) __VA_ARGS__)
466 /// macro to output logs when the cache is disabled at ``ESP_LOG_WARN`` level.  @see ``ESP_DRAM_LOGW``,``ESP_LOGW``, ``esp_rom_printf``
467 #define ESP_DRAM_LOGW( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_WARN,    W __VA_OPT__(,) __VA_ARGS__)
468 /// macro to output logs when the cache is disabled at ``ESP_LOG_INFO`` level.  @see ``ESP_DRAM_LOGI``,``ESP_LOGI``, ``esp_rom_printf``
469 #define ESP_DRAM_LOGI( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_INFO,    I __VA_OPT__(,) __VA_ARGS__)
470 /// macro to output logs when the cache is disabled at ``ESP_LOG_DEBUG`` level.  @see ``ESP_DRAM_LOGD``,``ESP_LOGD``, ``esp_rom_printf``
471 #define ESP_DRAM_LOGD( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_DEBUG,   D __VA_OPT__(,) __VA_ARGS__)
472 /// macro to output logs when the cache is disabled at ``ESP_LOG_VERBOSE`` level.  @see ``ESP_DRAM_LOGV``,``ESP_LOGV``, ``esp_rom_printf``
473 #define ESP_DRAM_LOGV( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_VERBOSE, V __VA_OPT__(,) __VA_ARGS__)
474 #else // !(defined(__cplusplus) && (__cplusplus >  201703L))
475 #define ESP_DRAM_LOGE( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_ERROR,   E, ##__VA_ARGS__)
476 /// macro to output logs when the cache is disabled at ``ESP_LOG_WARN`` level.  @see ``ESP_DRAM_LOGW``,``ESP_LOGW``, ``esp_rom_printf``
477 #define ESP_DRAM_LOGW( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_WARN,    W, ##__VA_ARGS__)
478 /// macro to output logs when the cache is disabled at ``ESP_LOG_INFO`` level.  @see ``ESP_DRAM_LOGI``,``ESP_LOGI``, ``esp_rom_printf``
479 #define ESP_DRAM_LOGI( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_INFO,    I, ##__VA_ARGS__)
480 /// macro to output logs when the cache is disabled at ``ESP_LOG_DEBUG`` level.  @see ``ESP_DRAM_LOGD``,``ESP_LOGD``, ``esp_rom_printf``
481 #define ESP_DRAM_LOGD( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_DEBUG,   D, ##__VA_ARGS__)
482 /// macro to output logs when the cache is disabled at ``ESP_LOG_VERBOSE`` level.  @see ``ESP_DRAM_LOGV``,``ESP_LOGV``, ``esp_rom_printf``
483 #define ESP_DRAM_LOGV( tag, format, ... ) ESP_DRAM_LOG_IMPL(tag, format, ESP_LOG_VERBOSE, V, ##__VA_ARGS__)
484 #endif // !(defined(__cplusplus) && (__cplusplus >  201703L))
485 
486 /** @cond */
487 #define _ESP_LOG_DRAM_LOG_FORMAT(letter, format)  DRAM_STR(#letter " %s: " format "\n")
488 
489 #if defined(__cplusplus) && (__cplusplus >  201703L)
490 #define ESP_DRAM_LOG_IMPL(tag, format, log_level, log_tag_letter, ...) do {                                  \
491         if (_ESP_LOG_EARLY_ENABLED(log_level)) {                                                             \
492             esp_rom_printf(_ESP_LOG_DRAM_LOG_FORMAT(log_tag_letter, format), tag __VA_OPT__(,) __VA_ARGS__); \
493         }} while(0)
494 #else // !(defined(__cplusplus) && (__cplusplus >  201703L))
495 #define ESP_DRAM_LOG_IMPL(tag, format, log_level, log_tag_letter, ...) do {                       \
496         if (_ESP_LOG_EARLY_ENABLED(log_level)) {                                                  \
497             esp_rom_printf(_ESP_LOG_DRAM_LOG_FORMAT(log_tag_letter, format), tag, ##__VA_ARGS__); \
498         }} while(0)
499 #endif // !(defined(__cplusplus) && (__cplusplus >  201703L))
500 /** @endcond */
501 
502 #ifdef __cplusplus
503 }
504 #endif
505 
506 
507 #endif /* __ESP_LOG_H__ */
508