From 951ed739f718c9c0415aa719d42443ef459c31c4 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 21 Nov 2019 18:42:46 +0100 Subject: [PATCH 1/2] soc/cpu: add non-xtensa-specific replacement of xthal_get_ccount --- components/soc/esp32/include/soc/cpu.h | 9 +++++++++ components/soc/esp32s2beta/include/soc/cpu.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/components/soc/esp32/include/soc/cpu.h b/components/soc/esp32/include/soc/cpu.h index 57ccd6e17..5e1eca273 100644 --- a/components/soc/esp32/include/soc/cpu.h +++ b/components/soc/esp32/include/soc/cpu.h @@ -131,4 +131,13 @@ static inline uint32_t esp_cpu_process_stack_pc(uint32_t pc) return pc - 3; } +typedef uint32_t esp_cpu_ccount_t; + +static inline esp_cpu_ccount_t esp_cpu_get_ccount(void) +{ + uint32_t result; + RSR(CCOUNT, result); + return result; +} + #endif diff --git a/components/soc/esp32s2beta/include/soc/cpu.h b/components/soc/esp32s2beta/include/soc/cpu.h index fdde8c91a..420350cdb 100644 --- a/components/soc/esp32s2beta/include/soc/cpu.h +++ b/components/soc/esp32s2beta/include/soc/cpu.h @@ -129,4 +129,13 @@ static inline uint32_t esp_cpu_process_stack_pc(uint32_t pc) return pc - 3; } +typedef uint32_t esp_cpu_ccount_t; + +static inline esp_cpu_ccount_t esp_cpu_get_ccount(void) +{ + uint32_t result; + RSR(CCOUNT, result); + return result; +} + #endif From 676b5e0deb237a3c73aa890d28703bf09a6b141c Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 21 Nov 2019 18:40:59 +0100 Subject: [PATCH 2/2] log: refactoring to make compatible with no-FreeRTOS builds --- components/log/CMakeLists.txt | 14 +- components/log/component.mk | 9 + components/log/esp_log_private.h | 6 + components/log/linker.lf | 9 + components/log/log.c | 324 +++++-------------------------- components/log/log_buffers.c | 147 ++++++++++++++ components/log/log_freertos.c | 110 +++++++++++ components/log/log_noos.c | 46 +++++ 8 files changed, 390 insertions(+), 275 deletions(-) create mode 100644 components/log/esp_log_private.h create mode 100644 components/log/linker.lf create mode 100644 components/log/log_buffers.c create mode 100644 components/log/log_freertos.c create mode 100644 components/log/log_noos.c diff --git a/components/log/CMakeLists.txt b/components/log/CMakeLists.txt index 4ca3c1a54..85a58ad1f 100644 --- a/components/log/CMakeLists.txt +++ b/components/log/CMakeLists.txt @@ -1,3 +1,15 @@ -idf_component_register(SRCS "log.c" +list(APPEND srcs "log.c" + "log_buffers.c") + +idf_component_register(SRCS ${srcs} INCLUDE_DIRS "include" + LDFRAGMENTS linker.lf PRIV_REQUIRES soc) + +idf_build_get_property(build_components BUILD_COMPONENTS) +# Ideally, FreeRTOS shouldn't be included into bootloader build, so the 2nd check should be unnecessary +if(freertos IN_LIST BUILD_COMPONENTS AND NOT BOOTLOADER_BUILD) + target_sources(${COMPONENT_TARGET} PRIVATE log_freertos.c) +else() + target_sources(${COMPONENT_TARGET} PRIVATE log_noos.c) +endif() diff --git a/components/log/component.mk b/components/log/component.mk index c2c4c03a1..94e53506e 100644 --- a/components/log/component.mk +++ b/components/log/component.mk @@ -3,3 +3,12 @@ # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +# Simpler condition than in CMakeLists.txt; +# We assume that FreeRTOS is always included into the build with GNU Make. +ifndef IS_BOOTLOADER_BUILD +COMPONENT_OBJEXCLUDE := log_noos.o +else +COMPONENT_OBJEXCLUDE := log_freertos.o +endif + +COMPONENT_ADD_LDFRAGMENTS += linker.lf diff --git a/components/log/esp_log_private.h b/components/log/esp_log_private.h new file mode 100644 index 000000000..68b6c852b --- /dev/null +++ b/components/log/esp_log_private.h @@ -0,0 +1,6 @@ +#pragma once +#include + +void esp_log_impl_lock(void); +bool esp_log_impl_lock_timeout(void); +void esp_log_impl_unlock(void); diff --git a/components/log/linker.lf b/components/log/linker.lf new file mode 100644 index 000000000..9e7ed2a48 --- /dev/null +++ b/components/log/linker.lf @@ -0,0 +1,9 @@ +[mapping:log] +archive: liblog.a +entries: + log:esp_log_write (noflash) + log_freertos:esp_log_timestamp (noflash) + log_freertos:esp_log_early_timestamp (noflash) + log_freertos:esp_log_impl_lock (noflash) + log_freertos:esp_log_impl_lock_timeout (noflash) + log_freertos:esp_log_impl_unlock (noflash) diff --git a/components/log/log.c b/components/log/log.c index 6c71d1a07..289fdf3dc 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -1,9 +1,9 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 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 @@ -36,73 +36,54 @@ * */ -#ifndef BOOTLOADER_BUILD -#include -#include -#include -#include -#endif - -#include "esp_attr.h" -#include "xtensa/hal.h" -#include "soc/soc.h" #include #include #include #include #include #include -#include -#include -#include - #include "esp_log.h" +#include "esp_log_private.h" + +#ifndef NDEBUG +// Enable built-in checks in queue.h in debug builds +#define INVARIANTS +// Enable consistency checks and cache statistics in this file. +#define LOG_BUILTIN_CHECKS +#endif #include "sys/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 - -#ifndef BOOTLOADER_BUILD // Number of tags to be cached. Must be 2**n - 1, n >= 2. #define TAG_CACHE_SIZE 31 -// Maximum time to wait for the mutex in a logging statement. -#define MAX_MUTEX_WAIT_MS 10 -#define MAX_MUTEX_WAIT_TICKS ((MAX_MUTEX_WAIT_MS + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS) - -// Uncomment this to enable consistency checks and cache statistics in this file. -// #define LOG_BUILTIN_CHECKS - typedef struct { - const char* tag; + const char *tag; uint32_t level : 3; uint32_t generation : 29; } cached_tag_entry_t; -typedef struct uncached_tag_entry_{ - SLIST_ENTRY(uncached_tag_entry_) entries; +typedef struct uncached_tag_entry_ { + SLIST_ENTRY(uncached_tag_entry_) entries; uint8_t level; // esp_log_level_t as uint8_t char tag[0]; // beginning of a zero-terminated string } uncached_tag_entry_t; static esp_log_level_t s_log_default_level = ESP_LOG_VERBOSE; -static SLIST_HEAD(log_tags_head , uncached_tag_entry_) s_log_tags = SLIST_HEAD_INITIALIZER(s_log_tags); +static SLIST_HEAD(log_tags_head, uncached_tag_entry_) s_log_tags = SLIST_HEAD_INITIALIZER(s_log_tags); static cached_tag_entry_t s_log_cache[TAG_CACHE_SIZE]; static uint32_t s_log_cache_max_generation = 0; static uint32_t s_log_cache_entry_count = 0; static vprintf_like_t s_log_print_func = &vprintf; -static SemaphoreHandle_t s_log_mutex = NULL; #ifdef LOG_BUILTIN_CHECKS static uint32_t s_log_cache_misses = 0; #endif -static inline bool get_cached_log_level(const char* tag, esp_log_level_t* level); -static inline bool get_uncached_log_level(const char* tag, esp_log_level_t* level); -static inline void add_to_cache(const char* tag, esp_log_level_t level); + +static inline bool get_cached_log_level(const char *tag, esp_log_level_t *level); +static inline bool get_uncached_log_level(const char *tag, esp_log_level_t *level); +static inline void add_to_cache(const char *tag, esp_log_level_t level); static void heap_bubble_down(int index); static inline void heap_swap(int i, int j); static inline bool should_output(esp_log_level_t level_for_message, esp_log_level_t level_for_tag); @@ -110,75 +91,68 @@ static inline void clear_log_level_list(void); vprintf_like_t esp_log_set_vprintf(vprintf_like_t func) { - if (!s_log_mutex) { - s_log_mutex = xSemaphoreCreateMutex(); - } - xSemaphoreTake(s_log_mutex, portMAX_DELAY); - + esp_log_impl_lock(); vprintf_like_t orig_func = s_log_print_func; s_log_print_func = func; - - xSemaphoreGive(s_log_mutex); + esp_log_impl_unlock(); return orig_func; } -void esp_log_level_set(const char* tag, esp_log_level_t level) +void esp_log_level_set(const char *tag, esp_log_level_t level) { - if (!s_log_mutex) { - s_log_mutex = xSemaphoreCreateMutex(); - } - xSemaphoreTake(s_log_mutex, portMAX_DELAY); + esp_log_impl_lock(); // for wildcard tag, remove all linked list items and clear the cache if (strcmp(tag, "*") == 0) { s_log_default_level = level; clear_log_level_list(); - xSemaphoreGive(s_log_mutex); + esp_log_impl_unlock(); return; } - //searching exist tag + // search for existing tag uncached_tag_entry_t *it = NULL; - SLIST_FOREACH( it, &s_log_tags, entries ) { - if ( strcmp(it->tag, tag)==0 ) { - //one tag in the linked list match, update the level + SLIST_FOREACH(it, &s_log_tags, entries) { + if (strcmp(it->tag, tag) == 0) { + // one tag in the linked list matched, update the level it->level = level; - //quit with it != NULL + // quit with it != NULL break; } } - //no exist tag, append new one - if ( it == NULL ) { + // no existing tag, append new one + if (it == NULL) { // allocate new linked list entry and append it to the head of the list - size_t entry_size = offsetof(uncached_tag_entry_t, tag) + strlen(tag) + 1; - uncached_tag_entry_t* new_entry = (uncached_tag_entry_t*) malloc(entry_size); + size_t tag_len = strlen(tag) + 1; + size_t entry_size = offsetof(uncached_tag_entry_t, tag) + tag_len; + uncached_tag_entry_t *new_entry = (uncached_tag_entry_t *) malloc(entry_size); if (!new_entry) { - xSemaphoreGive(s_log_mutex); + esp_log_impl_unlock(); return; } new_entry->level = (uint8_t) level; - strcpy(new_entry->tag, tag); - SLIST_INSERT_HEAD( &s_log_tags, new_entry, entries ); + strlcpy(new_entry->tag, tag, tag_len); + SLIST_INSERT_HEAD(&s_log_tags, new_entry, entries); } - //search in the cache and update it if exist + // search in the cache and update the entry it if exists for (int i = 0; i < s_log_cache_entry_count; ++i) { #ifdef LOG_BUILTIN_CHECKS assert(i == 0 || s_log_cache[(i - 1) / 2].generation < s_log_cache[i].generation); #endif - if (strcmp(s_log_cache[i].tag,tag) == 0) { + if (strcmp(s_log_cache[i].tag, tag) == 0) { s_log_cache[i].level = level; break; } } - xSemaphoreGive(s_log_mutex); + esp_log_impl_unlock(); } void clear_log_level_list(void) { uncached_tag_entry_t *it; - while((it = SLIST_FIRST(&s_log_tags)) != NULL) { - SLIST_REMOVE_HEAD(&s_log_tags, entries ); + while ((it = SLIST_FIRST(&s_log_tags)) != NULL) { + SLIST_REMOVE_HEAD(&s_log_tags, entries); free(it); } s_log_cache_entry_count = 0; @@ -188,14 +162,11 @@ void clear_log_level_list(void) #endif } -void IRAM_ATTR esp_log_write(esp_log_level_t level, - const char* tag, - const char* format, ...) +void esp_log_write(esp_log_level_t level, + const char *tag, + const char *format, ...) { - if (!s_log_mutex) { - s_log_mutex = xSemaphoreCreateMutex(); - } - if (xSemaphoreTake(s_log_mutex, MAX_MUTEX_WAIT_TICKS) == pdFALSE) { + if (!esp_log_impl_lock_timeout()) { return; } esp_log_level_t level_for_tag; @@ -209,7 +180,7 @@ void IRAM_ATTR esp_log_write(esp_log_level_t level, ++s_log_cache_misses; #endif } - xSemaphoreGive(s_log_mutex); + esp_log_impl_unlock(); if (!should_output(level, level_for_tag)) { return; } @@ -220,7 +191,7 @@ void IRAM_ATTR esp_log_write(esp_log_level_t level, va_end(list); } -static inline bool get_cached_log_level(const char* tag, esp_log_level_t* level) +static inline bool get_cached_log_level(const char *tag, esp_log_level_t *level) { // Look for `tag` in cache int i; @@ -251,7 +222,7 @@ static inline bool get_cached_log_level(const char* tag, esp_log_level_t* level) return true; } -static inline void add_to_cache(const char* tag, esp_log_level_t level) +static inline void add_to_cache(const char *tag, esp_log_level_t level) { uint32_t generation = s_log_cache_max_generation++; // First consider the case when cache is not filled yet. @@ -278,12 +249,12 @@ static inline void add_to_cache(const char* tag, esp_log_level_t level) heap_bubble_down(0); } -static inline bool get_uncached_log_level(const char* tag, esp_log_level_t* level) +static inline bool get_uncached_log_level(const char *tag, esp_log_level_t *level) { // Walk the linked list of all tags and see if given tag is present in the list. // This is slow because tags are compared as strings. uncached_tag_entry_t *it; - SLIST_FOREACH( it, &s_log_tags, entries ) { + SLIST_FOREACH(it, &s_log_tags, entries) { if (strcmp(tag, it->tag) == 0) { *level = it->level; return true; @@ -314,198 +285,3 @@ static inline void heap_swap(int i, int j) s_log_cache[i] = s_log_cache[j]; s_log_cache[j] = tmp; } -#endif //BOOTLOADER_BUILD - - -#ifndef BOOTLOADER_BUILD -#define ATTR IRAM_ATTR -#else -#define ATTR -#endif // BOOTLOADER_BUILD - -//the variable defined in ROM is the cpu frequency in MHz. -//as a workaround before the interface for this variable -extern uint32_t g_ticks_per_us_pro; - -uint32_t ATTR esp_log_early_timestamp(void) -{ - return xthal_get_ccount() / (g_ticks_per_us_pro * 1000); -} - -#ifndef BOOTLOADER_BUILD - -char* IRAM_ATTR esp_log_system_timestamp(void) -{ - static char buffer[18] = {0}; - static _lock_t bufferLock = 0; - - if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { - uint32_t timestamp = esp_log_early_timestamp(); - for (uint8_t i = 0; i < sizeof(buffer); i++) { - if ((timestamp > 0) || (i == 0)) { - for (uint8_t j = sizeof(buffer) - 1; j > 0; j--) { - buffer[j] = buffer[j - 1]; - } - buffer[0] = (char) (timestamp % 10) + '0'; - timestamp /= 10; - } else { - buffer[i] = 0; - break; - } - } - return buffer; - } else { - struct timeval tv; - struct tm timeinfo; - - gettimeofday(&tv, NULL); - localtime_r(&tv.tv_sec, &timeinfo); - - _lock_acquire(&bufferLock); - snprintf(buffer, sizeof(buffer), - "%02d:%02d:%02d.%03ld", - timeinfo.tm_hour, - timeinfo.tm_min, - timeinfo.tm_sec, - tv.tv_usec / 1000); - _lock_release(&bufferLock); - - return buffer; - } -} - -uint32_t IRAM_ATTR esp_log_timestamp(void) -{ - if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { - return esp_log_early_timestamp(); - } - static uint32_t base = 0; - if (base == 0 && xPortGetCoreID() == 0) { - base = esp_log_early_timestamp(); - } - return base + xTaskGetTickCount() * (1000 / configTICK_RATE_HZ); -} - -#else - -uint32_t esp_log_timestamp(void) __attribute__((alias("esp_log_early_timestamp"))); - -#endif //BOOTLOADER_BUILD - -void esp_log_buffer_hex_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 - 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_accessible(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_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 - 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_accessible(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+3+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_accessible(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/log/log_buffers.c b/components/log/log_buffers.c new file mode 100644 index 000000000..2ac00373f --- /dev/null +++ b/components/log/log_buffers.c @@ -0,0 +1,147 @@ +// Copyright 2015-2019 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. + +#include +#include +#include +#include "esp_log.h" +#include "soc/soc_memory_layout.h" // for esp_ptr_byte_accessible + + +//print number of bytes per line for esp_log_buffer_char and esp_log_buffer_hex +#define BYTES_PER_LINE 16 + +void esp_log_buffer_hex_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 + 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_accessible(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_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 + 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_accessible(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 + 3 + 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_accessible(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/log/log_freertos.c b/components/log/log_freertos.c new file mode 100644 index 000000000..74d2fc540 --- /dev/null +++ b/components/log/log_freertos.c @@ -0,0 +1,110 @@ +// Copyright 2015-2019 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. + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "soc/cpu.h" // for esp_cpu_get_ccount() +#include "esp_log.h" +#include "esp_log_private.h" + + +// Maximum time to wait for the mutex in a logging statement. +#define MAX_MUTEX_WAIT_MS 10 +#define MAX_MUTEX_WAIT_TICKS ((MAX_MUTEX_WAIT_MS + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS) + +static SemaphoreHandle_t s_log_mutex = NULL; + +void esp_log_impl_lock(void) +{ + if (!s_log_mutex) { + s_log_mutex = xSemaphoreCreateMutex(); + } + xSemaphoreTake(s_log_mutex, portMAX_DELAY); +} + +bool esp_log_impl_lock_timeout(void) +{ + if (!s_log_mutex) { + s_log_mutex = xSemaphoreCreateMutex(); + } + return xSemaphoreTake(s_log_mutex, MAX_MUTEX_WAIT_TICKS) == pdTRUE; +} + +void esp_log_impl_unlock(void) +{ + xSemaphoreGive(s_log_mutex); +} + +char *esp_log_system_timestamp(void) +{ + static char buffer[18] = {0}; + static _lock_t bufferLock = 0; + + if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { + uint32_t timestamp = esp_log_early_timestamp(); + for (uint8_t i = 0; i < sizeof(buffer); i++) { + if ((timestamp > 0) || (i == 0)) { + for (uint8_t j = sizeof(buffer) - 1; j > 0; j--) { + buffer[j] = buffer[j - 1]; + } + buffer[0] = (char)(timestamp % 10) + '0'; + timestamp /= 10; + } else { + buffer[i] = 0; + break; + } + } + return buffer; + } else { + struct timeval tv; + struct tm timeinfo; + + gettimeofday(&tv, NULL); + localtime_r(&tv.tv_sec, &timeinfo); + + _lock_acquire(&bufferLock); + snprintf(buffer, sizeof(buffer), + "%02d:%02d:%02d.%03ld", + timeinfo.tm_hour, + timeinfo.tm_min, + timeinfo.tm_sec, + tv.tv_usec / 1000); + _lock_release(&bufferLock); + + return buffer; + } +} + +uint32_t esp_log_timestamp(void) +{ + if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { + return esp_log_early_timestamp(); + } + static uint32_t base = 0; + if (base == 0 && xPortGetCoreID() == 0) { + base = esp_log_early_timestamp(); + } + return base + xTaskGetTickCount() * (1000 / configTICK_RATE_HZ); +} + +/* FIXME: define an API for getting the timestamp in soc/hal */ +uint32_t esp_log_early_timestamp(void) +{ + extern uint32_t g_ticks_per_us_pro; + return esp_cpu_get_ccount() / (g_ticks_per_us_pro * 1000); +} diff --git a/components/log/log_noos.c b/components/log/log_noos.c new file mode 100644 index 000000000..cf755839b --- /dev/null +++ b/components/log/log_noos.c @@ -0,0 +1,46 @@ +// Copyright 2019 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. + +#include +#include "esp_log_private.h" +#include "soc/cpu.h" // for esp_cpu_get_ccount() + +static int s_lock = 0; + +void esp_log_impl_lock(void) +{ + assert(s_lock == 0); + s_lock = 1; +} + +bool esp_log_lock_impl_timeout(void) +{ + esp_log_impl_lock(); + return true; +} + +void esp_log_impl_unlock(void) +{ + assert(s_lock == 1); + s_lock = 0; +} + +/* FIXME: define an API for getting the timestamp in soc/hal */ +uint32_t esp_log_early_timestamp(void) +{ + extern uint32_t g_ticks_per_us_pro; + return esp_cpu_get_ccount() / (g_ticks_per_us_pro * 1000); +} + +uint32_t esp_log_timestamp(void) __attribute__((alias("esp_log_early_timestamp")));