// Copyright 2020-2021 Beken // // 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 "bk_uart.h" #include #include #include #include "printf_impl.h" #if CONFIG_SHELL_ASYNCLOG #include "bk_api_cli.h" #endif #include #if CONFIG_SMP_SYNC_PRINTF #include "FreeRTOS.h" #include "spinlock.h" volatile spinlock_t printf_spin_lock = SPIN_LOCK_INIT; /*temporarily addressed the issue of printing in process context, and in the interrupt context it cannot*/ #define MULTI_CORE_PRINTF_LOCK() spin_lock(&printf_spin_lock) #define MULTI_CORE_PRINTF_UNLOCK() spin_unlock(&printf_spin_lock) #else #define MULTI_CORE_PRINTF_LOCK() #define MULTI_CORE_PRINTF_UNLOCK() #endif #ifndef CONFIG_PRINTF_BUF_SIZE #define CONFIG_PRINTF_BUF_SIZE (136) #endif static uint8_t s_printf_enable = 1; #if CONFIG_SHELL_ASYNCLOG static volatile uint8_t s_printf_sync = 0; typedef struct { char mod_name[11]; u8 disabled; } __bk_packed mod_disable_list_t; static mod_disable_list_t mod_tag_list[6]; static u8 whitelist_enabled = 0; #endif int printf_lock_init(void) { #if CONFIG_SHELL_ASYNCLOG memset(&mod_tag_list[0], 0, sizeof(mod_tag_list)); shell_set_log_level(LOG_LEVEL); #endif return BK_OK; } int printf_lock_deinit(void) { return BK_OK; } static void bk_printf_sync_port(char *prefix, const char *fmt, va_list args) { if(!printf_is_init()) return; char string[CONFIG_PRINTF_BUF_SIZE]; os_snprintf(&string[0], CONFIG_PRINTF_BUF_SIZE, "[SYNC]:%s", prefix); string[CONFIG_PRINTF_BUF_SIZE - 1] = 0; int data_len = strlen(string); vsnprintf(&string[data_len], CONFIG_PRINTF_BUF_SIZE - data_len, fmt, args); string[CONFIG_PRINTF_BUF_SIZE - 1] = 0; uart_write_string(bk_get_printf_port(), string); } static void bk_printf_raw_sync(const char *fmt, va_list args) { if(!printf_is_init()) return; char string[CONFIG_PRINTF_BUF_SIZE]; vsnprintf(&string[0], sizeof(string), fmt, args); string[CONFIG_PRINTF_BUF_SIZE - 1] = 0; uart_write_string(bk_get_printf_port(), string); } static const char * level_format[] = { "(%d):", "E(%d):", "W(%d):", "I(%d):", "D(%d):", "V(%d):", }; static void bk_printf_port_ext_internel(int block_mode, int level, char *tag, const char *fmt, va_list args) { #define CPU_STR_LEN 4 #define MAX_TAG_LEN 8 #define MAX_INFO_LEN 14 /* 13 + 1(:) */ /* "cpux" + ":" "Tag12345" + ":" "X(1234567890)" + ":" */ char prefix_str[(CPU_STR_LEN + 1) + (MAX_TAG_LEN + 1) + (MAX_INFO_LEN) + 1]; int data_len = 0; #if CONFIG_SHELL_ASYNCLOG int cpu_id = shell_get_cpu_id(); #else int cpu_id = rtos_get_core_id(); #endif prefix_str[0] = 0; if(cpu_id >= 0) { os_snprintf(&prefix_str[data_len], CPU_STR_LEN + 1, "cpu%d", cpu_id); data_len += CPU_STR_LEN; prefix_str[data_len++] = ':'; prefix_str[data_len] = 0; } if((tag != NULL) && (tag[0] != 0)) { strncpy(&prefix_str[data_len], tag, MAX_TAG_LEN); prefix_str[MAX_TAG_LEN + data_len] = 0; data_len = strlen(prefix_str); prefix_str[data_len] = ':'; data_len++; prefix_str[data_len] = 0; } os_snprintf(&prefix_str[data_len], MAX_INFO_LEN + 1, level_format[level], rtos_get_time()); #if CONFIG_SHELL_ASYNCLOG if(s_printf_sync == 0) { shell_log_out_port(block_mode, level, prefix_str, fmt, args); } else { bk_printf_sync_port(prefix_str, fmt, args); } #else bk_printf_sync_port(prefix_str, fmt, args); #endif // #if CONFIG_SHELL_ASYNCLOG } static void bk_printf_port_ext(int level, char *tag, const char *fmt, va_list args) { bk_printf_port_ext_internel(LOG_COMMON_MODE, level, tag, fmt, args); } static void bk_printf_raw_port(int block_mode, int level, const char *fmt, va_list args) { #if CONFIG_SHELL_ASYNCLOG if(s_printf_sync == 0) { shell_log_out_port(block_mode, level, NULL, fmt, args); } else { bk_printf_raw_sync(fmt, args); } #else bk_printf_raw_sync(fmt, args); #endif // #if CONFIG_SHELL_ASYNCLOG } void bk_printf(const char *fmt, ...) { int level = 0; // BK_LOG_INFO; va_list args; if(!printf_is_init()) return; if(!s_printf_enable) return; #if CONFIG_SHELL_ASYNCLOG if( !shell_level_check_valid(level) ) /* check here instead of in shell_log_out to reduce API instructions. */ return; #endif va_start(args, fmt); MULTI_CORE_PRINTF_LOCK(); bk_printf_port_ext(level, NULL, fmt, args); MULTI_CORE_PRINTF_UNLOCK(); va_end(args); return; } #if CONFIG_SHELL_ASYNCLOG static int bk_mod_printf_disbled(char * tag) { int i, result; for(i = 0; i < ARRAY_SIZE(mod_tag_list); i++) { if(mod_tag_list[i].disabled) { result = strncmp(mod_tag_list[i].mod_name, tag, sizeof(mod_tag_list[i].mod_name) - 1); if(result == 0) return 1; } } return 0; } void bk_enable_white_list(int enabled) { if(enabled) whitelist_enabled = 1; else whitelist_enabled = 0; } int bk_white_list_state(void) { return whitelist_enabled; } #endif // #if CONFIG_SHELL_ASYNCLOG /* ========= !! NOTE !! ========= */ /* Obsoleted API */ void bk_buf_printf_sync(char *buf, int buf_len) /* Obsoleted API */ { return; } /* ========= !! NOTE !! ========= */ /* Obsoleted API */ /* use bk_printf_ext(...) instead. */ void bk_printf_ex(int level, char *tag, const char *fmt, ...) /* Obsoleted API */ { #if 0 va_list args; if(!printf_is_init()) return; #if CONFIG_SHELL_ASYNCLOG if( !shell_level_check_valid(level) ) /* check here instead of in shell_log_out to reduce API instructions. */ return; if(bk_mod_printf_disbled(tag) ^ whitelist_enabled) return; #endif va_start(args, fmt); bk_printf_port(level, tag, fmt, args); va_end(args); return; #endif } static void bk_printf_ext_internel(int block_mode, int level, char *tag, const char *fmt, va_list args) { if(!printf_is_init()) return; if(!s_printf_enable) return; #if CONFIG_SHELL_ASYNCLOG if( !shell_level_check_valid(level) ) /* check here instead of in shell_log_out to reduce API instructions. */ return; if(tag != NULL) { if(bk_mod_printf_disbled(tag) ^ whitelist_enabled) return; } #endif bk_printf_port_ext_internel(block_mode, level, tag, fmt, args); return; } void bk_printf_ext(int level, char *tag, const char *fmt, ...) { va_list args; va_start(args, fmt); bk_printf_ext_internel(LOG_COMMON_MODE, level, tag, fmt, args); va_end(args); } void bk_printf_nonblock(int level, char *tag, const char *fmt, ...) { va_list args; va_start(args, fmt); bk_printf_ext_internel(LOG_NONBLOCK_MODE, level, tag, fmt, args); va_end(args); } void bk_printf_static_nonblock(int level, char *tag, const char *fmt, ...) { va_list args; va_start(args, fmt); bk_printf_ext_internel(LOG_STAIC_NONBLOCK_MODE, level, tag, fmt, args); va_end(args); } void bk_printf_static_block(int level, char *tag, const char *fmt, ...) { va_list args; va_start(args, fmt); bk_printf_ext_internel(LOG_STATIC_BLOCK_MODE, level, tag, fmt, args); va_end(args); } void bk_vprintf_ext(int level, char *tag, const char *fmt, va_list args) { bk_printf_ext_internel(LOG_COMMON_MODE, level, tag, fmt, args); } static void bk_printf_raw_internel(int block_mode, int level, char *tag, const char *fmt, va_list args) { if(!printf_is_init()) return; if(!s_printf_enable) return; #if CONFIG_SHELL_ASYNCLOG if( !shell_level_check_valid(level) ) /* check here instead of in shell_log_out to reduce API instructions. */ return; if(tag != NULL) { if(bk_mod_printf_disbled(tag) ^ whitelist_enabled) return; } #endif bk_printf_raw_port(block_mode, level, fmt, args); return; } void bk_printf_raw(int level, char *tag, const char *fmt, ...) { va_list args; va_start(args, fmt); bk_printf_raw_internel(LOG_COMMON_MODE, level, tag, fmt, args); va_end(args); } void bk_printf_raw_nonblock(int level, char *tag, const char *fmt, ...) { va_list args; va_start(args, fmt); bk_printf_raw_internel(LOG_NONBLOCK_MODE, level, tag, fmt, args); va_end(args); } void bk_vprintf_raw(int level, char *tag, const char *fmt, va_list args) { bk_printf_raw_internel(LOG_COMMON_MODE, level, tag, fmt, args); } void bk_set_printf_enable(uint8_t enable) { #if CONFIG_SHELL_ASYNCLOG if(0 == enable) { shell_echo_set(0); shell_set_log_level(0); } else { shell_echo_set(1); shell_set_log_level(LOG_LEVEL); } #endif s_printf_enable = enable; } void bk_set_printf_sync(uint8_t enable) { #if CONFIG_SHELL_ASYNCLOG #if CONFIG_SYS_CPU1 s_printf_sync = 0; #else s_printf_sync = enable; #endif #endif } int bk_get_printf_sync(void) { #if CONFIG_SHELL_ASYNCLOG return s_printf_sync; #endif return 1; } void bk_disable_mod_printf(char *mod_name, uint8_t disable) { #if CONFIG_SHELL_ASYNCLOG int i, j, result; disable = disable ^ whitelist_enabled; if(disable == 0) { for(i = 0; i < ARRAY_SIZE(mod_tag_list); i++) { if(mod_tag_list[i].disabled) { result = strncmp(mod_tag_list[i].mod_name, mod_name, sizeof(mod_tag_list[i].mod_name) - 1); if(result == 0) { mod_tag_list[i].disabled = 0; } } } } else { j = ARRAY_SIZE(mod_tag_list); for(i = 0; i < ARRAY_SIZE(mod_tag_list); i++) { if(mod_tag_list[i].disabled) { result = strncmp(mod_tag_list[i].mod_name, mod_name, sizeof(mod_tag_list[i].mod_name) - 1); if(result == 0) { return; } } else j = i; } if(j >= ARRAY_SIZE(mod_tag_list)) /* no free slot to record this module name. */ return; else { strncpy(mod_tag_list[j].mod_name, mod_name, sizeof(mod_tag_list[j].mod_name) - 1); mod_tag_list[j].mod_name[sizeof(mod_tag_list[j].mod_name) - 1] = 0; mod_tag_list[j].disabled = 1; } } return; #endif } char * bk_get_disable_mod(int * idx) { #if CONFIG_SHELL_ASYNCLOG int i; for(i = *idx; i < ARRAY_SIZE(mod_tag_list); i++) { (*idx)++; if(mod_tag_list[i].disabled) { return &mod_tag_list[i].mod_name[0]; } } return NULL; #endif return NULL; }