From 8244fa95fe30d9524d7b10c6469ff273e16dffe4 Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 21 Aug 2017 22:03:53 +0800 Subject: [PATCH] feat(log): add new function to log buffer with level and hex dump. --- components/log/include/esp_log.h | 100 ++++++++++++- components/log/include/esp_log_internal.h | 24 ++++ components/log/log.c | 136 +++++++++++++++--- components/soc/esp32/include/soc/soc.h | 8 +- .../soc/include/soc/soc_memory_layout.h | 6 + 5 files changed, 248 insertions(+), 26 deletions(-) create mode 100644 components/log/include/esp_log_internal.h diff --git a/components/log/include/esp_log.h b/components/log/include/esp_log.h index 734c80fe78..085970c51e 100644 --- a/components/log/include/esp_log.h +++ b/components/log/include/esp_log.h @@ -95,6 +95,62 @@ uint32_t esp_log_early_timestamp(void); */ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4))); +#include "esp_log_internal.h" + +/** + * @brief Log a buffer of hex bytes at specified level, seprated into 16 bytes each line. + * + * @param tag description tag + * + * @param buffer Pointer to the buffer array + * + * @param buff_len length of buffer in bytes + * + * @param level level of the log + * + */ +#define ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, level ) do {\ + if ( LOG_LOCAL_LEVEL >= level ) esp_log_buffer_hex_internal( tag, buffer, buff_len, level ); } while(0) + +/** + * @brief Log a buffer of characters at specified level, seprated into 16 bytes each line. Buffer should contain only printable characters. + * + * @param tag description tag + * + * @param buffer Pointer to the buffer array + * + * @param buff_len length of buffer in bytes + * + * @param level level of the log + * + */ +#define ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, level ) do {\ + if ( LOG_LOCAL_LEVEL >= level ) esp_log_buffer_char_internal( tag, buffer, buff_len, level ); } while(0) + +/** + * @brief Dump a buffer to the log at specified level. + * + * The dump log shows just like the one below: + * + * W (195) log_example: 0x3ffb4280 45 53 50 33 32 20 69 73 20 67 72 65 61 74 2c 20 |ESP32 is great, | + * W (195) log_example: 0x3ffb4290 77 6f 72 6b 69 6e 67 20 61 6c 6f 6e 67 20 77 69 |working along wi| + * W (205) log_example: 0x3ffb42a0 74 68 20 74 68 65 20 49 44 46 2e 00 |th the IDF..| + * + * It is highly recommend to use terminals with over 102 text width. + * + * @param tag description tag + * + * @param buffer Pointer to the buffer array + * + * @param buff_len length of buffer in bytes + * + * @param level level of the log + */ +#define ESP_LOG_BUFFER_HEXDUMP( tag, buffer, buff_len, level ) do {\ + if ( LOG_LOCAL_LEVEL >= level ) esp_log_buffer_hexdump_internal( tag, buffer, buff_len, level); } while(0) + + +#if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) /** * @brief Log a buffer of hex bytes at Info level * @@ -104,8 +160,10 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, . * * @param buff_len length of buffer in bytes * + * @see ``esp_log_buffer_hex_level`` + * */ -void esp_log_buffer_hex(const char *tag, const void *buffer, uint16_t buff_len); +#define ESP_LOG_BUFFER_HEX(tag, buffer, buff_len) ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ) /** * @brief Log a buffer of characters at Info level. Buffer should contain only printable characters. @@ -116,8 +174,20 @@ void esp_log_buffer_hex(const char *tag, const void *buffer, uint16_t buff_len); * * @param buff_len length of buffer in bytes * + * @see ``esp_log_buffer_char_level`` + * */ -void esp_log_buffer_char(const char *tag, const void *buffer, uint16_t buff_len); +#define ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len) ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ) + +#else +#define ESP_LOG_BUFFER_HEX(tag, buffer, buff_len) {} +#define ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len) {} +#endif + +//to be back compatible +#define esp_log_buffer_hex ESP_LOG_BUFFER_HEX +#define esp_log_buffer_char ESP_LOG_BUFFER_CHAR + #if CONFIG_LOG_COLORS #define LOG_COLOR_BLACK "30" @@ -190,6 +260,32 @@ void esp_log_buffer_char(const char *tag, const void *buffer, uint16_t buff_len) #define ESP_LOGV( tag, format, ... ) ESP_EARLY_LOGV(tag, format, ##__VA_ARGS__) #endif // BOOTLOADER_BUILD +/** runtime macro to output logs at a speicfied level. + * + * @param tag tag of the log, which can be used to change the log level by ``esp_log_level_set`` at runtime. + * + * @param level level of the output log. + * + * @param format format of the output log. see ``printf`` + * + * @param ... variables to be replaced into the log. see ``printf`` + * + * @see ``printf`` + */ +#define ESP_LOG_LEVEL(level, tag, format, ...) do {\ + if (level==ESP_LOG_ERROR ) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }\ + else if (level==ESP_LOG_WARN ) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }\ + else if (level==ESP_LOG_DEBUG ) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }\ + else if (level==ESP_LOG_VERBOSE ) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }\ + else { esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }}while(0) + +/** runtime macro to output logs at a speicfied level. Also check the level with ``LOG_LOCAL_LEVEL``. + * + * @see ``printf``, ``ESP_LOG_LEVEL`` + */ +#define ESP_LOG_LEVEL_LOCAL(level, tag, format, ...) do {\ + if ( LOG_LOCAL_LEVEL >= level ) ESP_LOG_LEVEL(level, tag, format, ##__VA_ARGS__); } while(0); + #ifdef __cplusplus } #endif diff --git a/components/log/include/esp_log_internal.h b/components/log/include/esp_log_internal.h new file mode 100644 index 0000000000..a41243881e --- /dev/null +++ b/components/log/include/esp_log_internal.h @@ -0,0 +1,24 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_LOG_INTERNAL_H__ +#define __ESP_LOG_INTERNAL_H__ + +//these two functions do not check level versus ESP_LOCAL_LEVEL, this should be done in esp_log.h +void esp_log_buffer_hex_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t level); +void esp_log_buffer_char_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t level); +void esp_log_buffer_hexdump_internal( const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level); + +#endif + diff --git a/components/log/log.c b/components/log/log.c index 33ebc2da41..c43df97e48 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -52,8 +52,12 @@ #include #include #include +#include + #include "esp_log.h" + #include "rom/queue.h" +#include "soc/soc_memory_layout.h" //print number of bytes per line for esp_log_buffer_char and esp_log_buffer_hex #define BYTES_PER_LINE 16 @@ -332,32 +336,120 @@ uint32_t esp_log_timestamp() __attribute__((alias("esp_log_early_timestamp"))); #endif //BOOTLOADER_BUILD -void esp_log_buffer_hex(const char *tag, const void *buffer, uint16_t buff_len) +void esp_log_buffer_hex_internal(const char *tag, const void *buffer, uint16_t buff_len, + esp_log_level_t log_level) { - const char *as_bytes = (const char *)buffer; - char temp_buffer[3*BYTES_PER_LINE + 1]= {0}; - int line_len = 0; - for (int i = 0; i < buff_len; i++) { - line_len += sprintf(temp_buffer+line_len, "%02x ", as_bytes[i]); - if (((i + 1) % BYTES_PER_LINE == 0) || (i == buff_len - 1)) { - ESP_LOGI(tag, "%s", temp_buffer); - line_len = 0; - temp_buffer[0] = 0; + if ( buff_len == 0 ) return; + char temp_buffer[BYTES_PER_LINE+3]; //for not-byte-accessible memory + char hex_buffer[3*BYTES_PER_LINE+1]; + const char *ptr_line; + int bytes_cur_line; + + do { + if ( buff_len > BYTES_PER_LINE ) { + bytes_cur_line = BYTES_PER_LINE; + } else { + bytes_cur_line = buff_len; } - } + if ( !esp_ptr_byte_accesible(buffer) ) { + //use memcpy to get around alignment issue + memcpy( temp_buffer, buffer, (bytes_cur_line+3)/4*4 ); + ptr_line = temp_buffer; + } else { + ptr_line = buffer; + } + + for( int i = 0; i < bytes_cur_line; i ++ ) { + sprintf( hex_buffer + 3*i, "%02x ", ptr_line[i] ); + } + ESP_LOG_LEVEL( log_level, tag, "%s", hex_buffer ); + buffer += bytes_cur_line; + buff_len -= bytes_cur_line; + } while( buff_len ); } -void esp_log_buffer_char(const char *tag, const void *buffer, uint16_t buff_len) +void esp_log_buffer_char_internal(const char *tag, const void *buffer, uint16_t buff_len, + esp_log_level_t log_level) { - const char *as_bytes = (const char *)buffer; - char temp_buffer[BYTES_PER_LINE + 1] = {0}; - int line_len = 0; - for (int i = 0; i < buff_len; i++) { - line_len += sprintf(temp_buffer+line_len, "%c", as_bytes[i]); - if (((i + 1) % BYTES_PER_LINE == 0) || (i == buff_len - 1)) { - ESP_LOGI(tag, "%s", temp_buffer); - line_len = 0; - temp_buffer[0] = 0; + if ( buff_len == 0 ) return; + char temp_buffer[BYTES_PER_LINE+3]; //for not-byte-accessible memory + char char_buffer[BYTES_PER_LINE+1]; + const char *ptr_line; + int bytes_cur_line; + + do { + if ( buff_len > BYTES_PER_LINE ) { + bytes_cur_line = BYTES_PER_LINE; + } else { + bytes_cur_line = buff_len; } - } + if ( !esp_ptr_byte_accesible(buffer) ) { + //use memcpy to get around alignment issue + memcpy( temp_buffer, buffer, (bytes_cur_line+3)/4*4 ); + ptr_line = temp_buffer; + } else { + ptr_line = buffer; + } + + for( int i = 0; i < bytes_cur_line; i ++ ) { + sprintf( char_buffer + i, "%c", ptr_line[i] ); + } + ESP_LOG_LEVEL( log_level, tag, "%s", char_buffer ); + buffer += bytes_cur_line; + buff_len -= bytes_cur_line; + } while( buff_len ); +} + +void esp_log_buffer_hexdump_internal( const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level) +{ + + if ( buff_len == 0 ) return; + char temp_buffer[BYTES_PER_LINE+3]; //for not-byte-accessible memory + const char *ptr_line; + //format: field[length] + // ADDR[10]+" "+DATA_HEX[8*3]+" "+DATA_HEX[8*3]+" |"+DATA_CHAR[8]+"|" + char hd_buffer[10+2+BYTES_PER_LINE*3+3+BYTES_PER_LINE+1+1]; + char *ptr_hd; + int bytes_cur_line; + + do { + if ( buff_len > BYTES_PER_LINE ) { + bytes_cur_line = BYTES_PER_LINE; + } else { + bytes_cur_line = buff_len; + } + if ( !esp_ptr_byte_accesible(buffer) ) { + //use memcpy to get around alignment issue + memcpy( temp_buffer, buffer, (bytes_cur_line+3)/4*4 ); + ptr_line = temp_buffer; + } else { + ptr_line = buffer; + } + ptr_hd = hd_buffer; + + ptr_hd += sprintf( ptr_hd, "%p ", buffer ); + for( int i = 0; i < BYTES_PER_LINE; i ++ ) { + if ( (i&7)==0 ) { + ptr_hd += sprintf( ptr_hd, " " ); + } + if ( i < bytes_cur_line ) { + ptr_hd += sprintf( ptr_hd, " %02x", ptr_line[i] ); + } else { + ptr_hd += sprintf( ptr_hd, " " ); + } + } + ptr_hd += sprintf( ptr_hd, " |" ); + for( int i = 0; i < bytes_cur_line; i ++ ) { + if ( isprint((int)ptr_line[i]) ) { + ptr_hd += sprintf( ptr_hd, "%c", ptr_line[i] ); + } else { + ptr_hd += sprintf( ptr_hd, "." ); + } + } + ptr_hd += sprintf( ptr_hd, "|" ); + + ESP_LOG_LEVEL( log_level, tag, "%s", hd_buffer ); + buffer += bytes_cur_line; + buff_len -= bytes_cur_line; + } while( buff_len ); } diff --git a/components/soc/esp32/include/soc/soc.h b/components/soc/esp32/include/soc/soc.h index 5d5cf3b7db..b889f5fa56 100644 --- a/components/soc/esp32/include/soc/soc.h +++ b/components/soc/esp32/include/soc/soc.h @@ -274,12 +274,12 @@ //}} /* Overall memory map */ +#define SOC_DROM_LOW 0x3F400000 +#define SOC_DROM_HIGH 0x3F800000 #define SOC_IROM_LOW 0x400D0000 #define SOC_IROM_HIGH 0x40400000 #define SOC_IRAM_LOW 0x40080000 #define SOC_IRAM_HIGH 0x400A0000 -#define SOC_DROM_LOW 0x3F400000 -#define SOC_DROM_HIGH 0x3F800000 #define SOC_RTC_IRAM_LOW 0x400C0000 #define SOC_RTC_IRAM_HIGH 0x400C2000 #define SOC_RTC_DATA_LOW 0x50000000 @@ -295,6 +295,10 @@ #define SOC_DMA_LOW 0x3FFAE000 #define SOC_DMA_HIGH 0x40000000 +// Region of memory that is byte-accessible. See esp_ptr_byte_accesible(). +#define SOC_BYTE_ACCESSIBLE_LOW 0x3FFAE000 +#define SOC_BYTE_ACCESSIBLE_HIGH 0x40000000 + //Interrupt hardware source table //This table is decided by hardware, don't touch this. #define ETS_WIFI_MAC_INTR_SOURCE 0/**< interrupt of WiFi MAC, level*/ diff --git a/components/soc/include/soc/soc_memory_layout.h b/components/soc/include/soc/soc_memory_layout.h index 74fc2d1524..0a282062e5 100644 --- a/components/soc/include/soc/soc_memory_layout.h +++ b/components/soc/include/soc/soc_memory_layout.h @@ -70,3 +70,9 @@ inline static bool esp_ptr_executable(const void *p) || (ip >= SOC_IRAM_LOW && ip < SOC_IRAM_HIGH) || (ip >= SOC_RTC_IRAM_LOW && ip < SOC_RTC_IRAM_HIGH); } + +inline bool esp_ptr_byte_accesible(const void *p) +{ + //currently only support DRAM, add PSRAM region in the future + return (intptr_t)p >= SOC_BYTE_ACCESSIBLE_LOW && (intptr_t)p < SOC_BYTE_ACCESSIBLE_HIGH; +}