/*---------------------------------------------------------------------------- * Copyright (c) Fenda Technologies Co., Ltd. 2020. All rights reserved. * * Description: log_port.c * * Author: saimen * * Create: 2022-7-16 *--------------------------------------------------------------------------*/ //lib #include #include #include #include //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; }