510 lines
10 KiB
C
Raw Permalink Normal View History

2025-02-27 17:59:18 +08:00
// 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 <stdarg.h>
#include <string.h>
#include <driver/uart.h>
#include "bk_uart.h"
#include <common/sys_config.h>
#include <common/bk_compiler.h>
#include <os/mem.h>
#include "printf_impl.h"
#if CONFIG_SHELL_ASYNCLOG
#include "bk_api_cli.h"
#endif
#include <os/str.h>
#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;
}