mcu_hi3321_watch/tjd/log/log_port.c
2025-05-26 20:15:20 +08:00

258 lines
7.3 KiB
C

/*----------------------------------------------------------------------------
* Copyright (c) Fenda Technologies Co., Ltd. 2020. All rights reserved.
*
* Description: log_port.c
*
* Author: saimen
*
* Create: 2022-7-16
*--------------------------------------------------------------------------*/
//lib
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>
//os
#include "FreeRTOS.h"
#include "semphr.h"
//sdk
#include "apollo4b.h"
//#include "am_mcu_apollo.h"
//drv
#include "sys_typedef.h"
#include "sys_config.h"
#include "rtc_api.h"
#include "fs_api.h"
//user
#include "fs_user_init.h"
#include "log_port.h"
#include "cm_backtrace.h"
#include "task_ancillary.h"
#define ENABLE_STATIC_PRINT false
extern uint32_t am_util_stdio_printf(const char *pcFmt, ...);
#define static_print_remind(...) am_util_stdio_printf(__VA_ARGS__)
#if ENABLE_STATIC_PRINT
#define static_print_info(...) am_util_stdio_printf(__VA_ARGS__)
#else
#define static_print_info(...)
#endif
//fs log
#define LOG_DIR_DEFINE DIR_DATA_LOG
#define LOG_FILE_FULL_NAME_DEFINE "/FD/log_device.bin"
#define LOG_FILE_MAX_NUMBER (3) //日志文件的最大个数
#define LOG_FILE_MAX_SIZE (100*1024) //单个日志文件的最大尺寸
#define LOG_FILE_PATH_MAX 64 //日志数据文件绝对路径的最大长度
static SemaphoreHandle_t g_log_mutex_handle = NULL;
/**
* @brief 创建日志模块嵌套互斥锁
* @retval int| 返回错误码,0=成功.
*/
int log_port_create_lock(void)
{
g_log_mutex_handle = xSemaphoreCreateRecursiveMutex();
if(g_log_mutex_handle == NULL)
{
static_print_remind("log create mutex failed\r\n");
return -1;
} else {
static_print_remind("log create mutex success\r\n");
}
return RET_SUCCESS;
}
/**
* @brief 日志模块获取锁
* @param type:DATA_LOG_TYPE|需要获取锁的日志种类
* @retval int| 返回错误码,0=成功.
*/
int log_port_lock(void)
{
BaseType_t ret;
//在中断函数中,放弃获取锁
if (__get_IPSR() != 0) {
return 0;
}
if(g_log_mutex_handle != NULL) {
ret = xSemaphoreTakeRecursive(g_log_mutex_handle, portMAX_DELAY);
if(ret != pdTRUE) {
static_print_remind("log take mutex failed, call ret false\r\n");
return -1;
} else {
static_print_info("log take mutex success\r\n");
}
} else {
static_print_info("log take mutex failed, mutex is null\r\n");
}
return RET_SUCCESS;;
}
/**
* @brief 日志模块释放锁
* @param type:DATA_LOG_TYPE|需要释放锁的日志种类
* @retval int| 返回错误码,0=成功.
*/
int log_port_unlock(void)
{
BaseType_t ret;
//在中断函数中,放弃释放锁
if (__get_IPSR() != 0) {
return 0;
}
if(g_log_mutex_handle != NULL) {
ret = xSemaphoreGiveRecursive(g_log_mutex_handle);
if(ret != pdTRUE) {
static_print_remind("log give mutex failed, call ret false\r\n");
return -1;
} else {
static_print_info("log give mutex success\r\n");
}
} else {
static_print_info("log give mutex failed, mutex is null\r\n");
}
return RET_SUCCESS;;
}
/**
* @brief 日志模块事件通知
* @param event 需要释放事件
* @retval int| 返回错误码,0=成功.
*/
int log_port_notify(uint32_t event)
{
int ret;
switch(event)
{
case LOG_EVENT_CACHE_FULL:
task_ancillary_notify(ANCILLARY_MSG_LOG_BUF_FULL, NULL);
break;
default:
break;
}
return RET_SUCCESS;;
}
/**
* @brief 根据时间戳及日志种类拼接日志文件的绝对路径.
* @param type:DATA_LOG_TYPE|日志种类.
* @param timestamp:UINT32|unix时间戳.
* @param buf:char*|缓存绝对路径的指针.
* @retval int|返回路径的长度.
*/
int log_port_get_full_path(uint32_t index, char *buf)
{
#if 1
uint8_t i;
int ret;
char dir[64];
struct tm *p_time;
char *name_file;
bool is_dir;
name_file = buf;
ret = fs_user_get_newest_file_exclude_child_dir(LOG_DIR_DEFINE,name_file);
if(ret)
{
ret = fs_api_stat(name_file,&is_dir);
}
else
{
ret = RET_ERROR;
}
if(ret > LOG_FILE_MAX_SIZE || ret < 0)
{
p_time = rtc_api_get_utc_time();
#if 1
sprintf(name_file, "%s/%02d%02d%02d%02d%02d%02d.bin", LOG_DIR_DEFINE, p_time->tm_year+1900, p_time->tm_mon+1, \
p_time->tm_mday, p_time->tm_hour, p_time->tm_min, p_time->tm_sec);
#else
sprintf(name_file, "%s",LOG_FILE_FULL_NAME_DEFINE);
#endif
}
if(fs_api_file_exist(name_file) < RET_SUCCESS)
{
fs_user_get_dir_by_full_path(name_file, dir);
static_print_info("file [%s] not exist, dir[%s]\r\n", name_file,dir);
if(fs_api_dir_exist(dir) != RET_SUCCESS)
{
static_print_info("dir [%s] not exist, create dir\r\n", dir);
ret = fs_user_create_dir(dir);
if(ret != 0)
{
static_print_remind("create dir [%s] failed:%d\r\n", dir,ret);
return ret;
}
}
ret = fs_api_file_create(name_file);
static_print_info("fs_api_file_create()=%d\r\n",ret);
// fs_user_print_dir_list(dir);
}
if (fs_user_get_file_number_exclude_child_dir(LOG_DIR_DEFINE)>LOG_FILE_MAX_NUMBER)
{
for(i=0;i<3;i++)//最多执行3次
{
if(fs_user_delete_oldest_file_exclude_child_dir(LOG_DIR_DEFINE,LOG_FILE_MAX_NUMBER) < LOG_FILE_MAX_NUMBER)
{
break;
}
}
}
static_print_info("log_port_get_full_path():%s\r\n",buf);
return RET_SUCCESS;
#endif
}
int log_port_read_file(char *path, uint32_t offset, uint8_t *dat, uint32_t len)
{
return fs_api_file_load(path, offset, dat, len);
}
/**
* @brief 写入数据到文件.
* @param path:const char *|文件的绝对路径.
* @param dat:const uint8_t *|数据指针.
* @param len:UINT16|数据的长度.
* @param newPath:const char *|当文件超出大小时,新建文件的绝对路径.
* @param useNewPath:bool *|传参给调用者是否使用了新路径
* @retval int|返回写入的数据长度,负数表示错误码.
* @note 新建文件的目录与旧文件的目录必须相同,只能是文件名不同.
*/
int log_port_write_file(char *path, uint8_t *dat, uint16_t len)
{
int err = 0;
uint32_t size;
bool is_dir;
size = fs_api_stat(path,&is_dir);
if((size + len) > LOG_FILE_MAX_NUMBER)
{
log_port_get_full_path(0, path);
static_print_info("file [%s] size reach limit[size:%d |wrt:%d] new \r\n", path, size, len);
err = fs_api_file_append(path, dat, len);
}
else
{
err = fs_api_file_append(path, dat, len);
}
static_print_info("file [%s] write bytes: %d, now total size: %d bytes\r\n", path, len, fs_api_stat(path,&is_dir));
return err;
}