Files
ESPC3-wireless/app/config/app_log.c
2025-07-09 15:41:50 +08:00

277 lines
7.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file app_log.c
* @author LokLiang
* @brief app_log.h 模块源码
* @version 0.1
* @date 2023-11-242
*
* @copyright Copyright (c) 2023
*
*/
#include "app_log.h"
#include "nvs.h"
#include "utils/crc.h"
#include "os/os.h"
#undef CONFIG_SYS_LOG_LEVEL
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF
#define SYS_LOG_DOMAIN "APLOG"
#define CONS_ABORT()
#include "sys_log.h"
#define _NVS_KEY_MAIN "log-main"
/* 数据区 -------------------------------------------------------------------------------------- */
extern nvs_handle g_nvs_hdl;
static struct
{
os_time_t flight_time_start;
} s_cm;
/* nvs 接口 ------------------------------------------------------------------------------------ */
static int _read_key(const char *key, void *out_value, size_t tar_length, uint32_t *crc_base);
static int _set_crc(const void *struct_base, size_t struct_length, uint32_t *crc_base);
static int _do_factory_set(log_app_t *log);
/**
* @brief 读取指定的数据,并按给出的特性进行校验,返回校验结果
*
* @param key 在 nvs 的存储块的键值
* @param out_value[out] 输出内存
* @param tar_length 输出的内存预期的长度
* @param crc_base[io] CRC 校验值所在内存块的地址(绝对值)。输入:校验值,输出:新的正确校验值
* @retval 0 正确读取了已存储数据
* @retval 1 nvs 模块可用, CRC 校验值已更新
* @retval -1 nvs 模块不可用
*/
static int _read_key(const char *key, void *out_value, size_t tar_length, uint32_t *crc_base)
{
size_t required_size = 0;
esp_err_t err = ESP_OK;
/* 在确认已存储的数据长度前,仅获取长度以免数据溢出 */
err = nvs_get_blob(g_nvs_hdl, key, NULL, &required_size);
if (err != ESP_OK)
{
SYS_LOG_WRN("failed to read prfsdata data length, err:%d", err);
return -1;
}
if (required_size != tar_length)
{
SYS_LOG_WRN("invalid prfsdata length, length:%d, err:%d", required_size, err);
return -1;
}
/* 读出已存储的数据 */
err = nvs_get_blob(g_nvs_hdl, key, out_value, &required_size);
if (err != ESP_OK)
{
SYS_LOG_ERR("failed to read prfsdata data, err:%d", err);
return -1;
}
/* 设置并校验 CRC */
if (_set_crc(out_value, tar_length, crc_base))
{
SYS_LOG_WRN("read frs failed, incorrect crc and update");
return 1;
}
return 0;
}
/**
* @brief 校验并更新结构体中 CRC 的值。
* 这将校验整个结构(包含 CRC 本身),因此 CRC 自身的初始值为 0然后更新 CRC 的结果到结构中
*
* @param struct_base 待分析和设置的内存块
* @param struct_length 待分析和设置的内存块的实际长度
* @param crc_base[io] CRC 校验值所在内存块的地址(绝对值)
* @retval 0 校验正确
* @retval 1 校验错误,并且设置了正确的校验值
*/
static int _set_crc(const void *struct_base, size_t struct_length, uint32_t *crc_base)
{
// 校验读出来的数据的正确性
uint32_t crc_read = *crc_base;
*crc_base = 0;
*crc_base = crc32_calc(0, struct_base, struct_length);
return (crc_read != *crc_base);
}
static int _do_factory_set(log_app_t *log)
{
memset(log, 0, sizeof(*log));
log->flight_data.crc16 = crc16_calc(NULL, 0);
return app_log_do_save(log);
}
/**
* @brief 初始化
*/
void app_log_init(void)
{
SYS_ASSERT(g_nvs_hdl != 0, "");
}
/**
* @brief 使内存的数据恢复到默认设置
*
* @retval 0 操作成功
* @retval -1 操作失败
*/
int app_log_factory_set(void)
{
log_app_t *log = os_malloc(sizeof(log_app_t));
if (log == NULL)
{
SYS_LOG_WRN("malloc fail");
return -1;
}
int ret = _do_factory_set(log);
os_free(log);
return ret;
}
/**
* @brief 立即执行保存 配置数据 到 nvs 的动作
*
* @param delay_ms 0: 立即保存, > 0 多少毫秒后执行保存
* @return int @ref esp_err_t
*/
int app_log_do_save(log_app_t *log)
{
log->version = APP_LOG_DATA_VER;
_set_crc(log, sizeof(*log), &log->crc32);
esp_err_t err = nvs_set_blob(g_nvs_hdl, _NVS_KEY_MAIN, log, sizeof(*log));
if (err != ESP_OK)
{
SYS_LOG_WRN("nvs_set_blob() err: %d", err);
}
return err;
}
/* 读接口 -------------------------------------------------------------------------------------- */
/**
* @brief 读取日志信息
* 将从 nvs 读取已保存的数据到内存 log_app_t 中。
* 当出现以下情况时,配置数据被恢复到默认值:
* nvs 未初始化或操作失败;
* 使用 app_log_factory_set() 立即恢复到默认值;
* 结构体的长度 log_app_t 发生改变;
* APP_CONFIG_DATA_VER 定义的值发生改变;
*
* @param out_log[out] 用于保存日志信息的内存
* @retval 0 成功读取已有记录
* @retval 1 已恢复默认设置
* @retval -1 nvs 操作失败
*/
int app_log_read(log_app_t *out_log)
{
int ret = _read_key(_NVS_KEY_MAIN, out_log, sizeof(*out_log), &out_log->crc32);
if (ret)
{
goto use_default_prfs;
}
if (out_log->version != APP_LOG_DATA_VER)
{
ret = 1;
SYS_LOG_WRN("Upgrade to the latest version: %u ==> %u", out_log->version, APP_LOG_DATA_VER);
goto use_default_prfs;
}
return ret;
use_default_prfs:
_do_factory_set(out_log);
return ret;
}
/* 写接口 -------------------------------------------------------------------------------------- */
/**
* @brief 开始计时
*
*/
void app_log_flight_time_start(void)
{
log_app_t *log = os_malloc(sizeof(log_app_t));
if (log == NULL)
{
SYS_LOG_WRN("malloc fail");
return;
}
if (log->flight_data.flight_number < __ARRAY_SIZE(log->flight_data.datas))
{
s_cm.flight_time_start = os_get_sys_time();
}
else
{
s_cm.flight_time_start = 0;
SYS_LOG_INF("The maximum number of groups: %d", __ARRAY_SIZE(log->flight_data.datas));
}
os_free(log);
}
/**
* @brief 结束计时,并保存这个记录
*
*/
void app_log_flight_time_stop(void)
{
if (s_cm.flight_time_start == 0)
{
SYS_LOG_WRN("never exec app_log_flight_time_start()");
return;
}
log_app_t *log = os_malloc(sizeof(log_app_t));
if (log == NULL)
{
SYS_LOG_WRN("malloc fail");
return;
}
os_time_t time_cost_sec = (os_get_sys_time() - s_cm.flight_time_start) / 1000;
if (time_cost_sec > 10)
{
log->flight_data.datas[log->flight_data.flight_number++] = time_cost_sec;
log->flight_data.crc16 = crc16_calc(log->flight_data.datas, sizeof(log->flight_data.datas[0]) * log->flight_data.flight_number);
app_log_do_save(log);
}
s_cm.flight_time_start = 0;
os_free(log);
}
/**
* @brief 清除全部计时记录
*
*/
void app_log_flight_time_clr(void)
{
log_app_t *log = os_malloc(sizeof(log_app_t));
if (log == NULL)
{
SYS_LOG_WRN("malloc fail");
return;
}
memset(&log->flight_data, 0, sizeof(log->flight_data));
app_log_do_save(log);
os_free(log);
}