STM_ATEM/User/data_storage.c
zhoujie 9a2d543fcb feat(system-monitor): 新增SD卡存储监控功能并优化系统配置
- 新增SD卡存储监控功能,包含写入次数、错误次数、缓冲区满次数、总写入字节数和文件数量等统计指标
- 新增SD卡监控API函数,包括报告写入、报告错误、报告缓冲区满和报告文件创建
- 在data_storage.c中集成SD卡监控功能,在关键操作点添加监控报告
- 新增详细的使用文档《SD_Storage_Monitoring_Guide.md》,说明监控指标、API使用、集成方法和故障诊断
- 优化系统调试输出,在DebugOutput_PrintSystemStats中增加SD卡统计信息显示,包括基本统计、SD卡统计和计算指标(平均写入大小、错误率)
- 调整SDIO时钟分频器从2改为1以提高SD卡通信速度
- 调整TIM2中断优先级从12改为3以提高定时器响应优先级
- 更新STM32CubeMX配置文件(.ioc)以反映SDIO时钟分频和TIM2中断优先级的更改
- 注释掉USB连接状态检测代码以简化主循环处理
- 优化ADC数据就绪中断处理,每2次触发一次DMA读取,并在DMA读取超时时报告数据溢出
- 移除ProcessAdcData函数中已注释的RS485发送代码
- 将数据溢出报告从ProcessAdcData函数移至HAL_GPIO_EXTI_Callback函数中的DMA读取超时处理
2026-02-06 23:58:56 +08:00

359 lines
10 KiB
C

#include "data_storage.h"
#include "system_monitor.h"
#include <string.h>
#include <stdio.h>
/**
* @brief 初始化数据存储模块
* @param handle: 数据存储句柄指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_Init(DataStorageHandle_t *handle)
{
if (handle == NULL) {
return HAL_ERROR;
}
// 初始化句柄
memset(handle, 0, sizeof(DataStorageHandle_t));
// 初始化双缓冲区
for (int i = 0; i < 2; i++) {
handle->buffers[i].index = 0;
handle->buffers[i].state = BUFFER_IDLE;
memset(handle->buffers[i].data, 0, DATA_STORAGE_BUFFER_SIZE);
}
// 设置活动缓冲区为0
handle->active_buffer = 0;
handle->flush_buffer = 1;
handle->flush_in_progress = 0;
// 创建数据存储目录
FRESULT res = f_mkdir(DATA_STORAGE_PATH);
if (res != FR_OK && res != FR_EXIST) {
return HAL_ERROR;
}
handle->stats.state = DATA_STORAGE_IDLE;
handle->initialized = 1;
return HAL_OK;
}
/**
* @brief 停止数据记录
* @param handle: 数据存储句柄指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_StopRecording(DataStorageHandle_t *handle)
{
if (handle == NULL || !handle->initialized) {
return HAL_ERROR;
}
if (handle->stats.state != DATA_STORAGE_RECORDING) {
return HAL_OK; // 没有在记录中
}
// 刷新所有缓冲区
for (int i = 0; i < 2; i++) {
if (handle->buffers[i].index > 0) {
handle->buffers[i].state = BUFFER_READY_TO_FLUSH;
DataStorage_FlushBuffer(handle, i);
}
}
// 关闭文件
f_close(&handle->file);
handle->stats.state = DATA_STORAGE_IDLE;
return HAL_OK;
}
/**
* @brief 写入数据包到存储
* @param handle: 数据存储句柄指针
* @param packet: 数据包指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_WriteData(DataStorageHandle_t *handle, const DataPacket_t *packet)
{
if (handle == NULL || packet == NULL || !handle->initialized) {
return HAL_ERROR;
}
if (handle->stats.state != DATA_STORAGE_RECORDING) {
return HAL_ERROR;
}
DataBuffer_t *active_buf = &handle->buffers[handle->active_buffer];
// 检查当前活动缓冲区空间
if (active_buf->index + sizeof(DataPacket_t) > DATA_STORAGE_BUFFER_SIZE) {
// 切换缓冲区
if (DataStorage_SwitchBuffer(handle) != HAL_OK) {
handle->stats.error_count++;
return HAL_ERROR;
}
active_buf = &handle->buffers[handle->active_buffer];
}
// 复制数据到活动缓冲区
memcpy(&active_buf->data[active_buf->index], packet, sizeof(DataPacket_t));
active_buf->index += sizeof(DataPacket_t);
active_buf->state = BUFFER_WRITING;
handle->stats.total_samples++;
return HAL_OK;
}
/**
* @brief 写入校正后的数据包到存储
* @param handle: 数据存储句柄指针
* @param packet: 数据包指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_WriteCorrectedData(DataStorageHandle_t *handle, const CorrectedDataPacket_t *packet)
{
if (handle == NULL || packet == NULL || !handle->initialized) {
return HAL_ERROR;
}
if (handle->stats.state != DATA_STORAGE_RECORDING) {
return HAL_ERROR;
}
DataBuffer_t *active_buf = &handle->buffers[handle->active_buffer];
// 检查当前活动缓冲区空间
if (active_buf->index + sizeof(CorrectedDataPacket_t) > DATA_STORAGE_BUFFER_SIZE) {
// 切换缓冲区
if (DataStorage_SwitchBuffer(handle) != HAL_OK) {
handle->stats.error_count++;
return HAL_ERROR;
}
active_buf = &handle->buffers[handle->active_buffer];
}
// 复制校正后的数据到活动缓冲区
memcpy(&active_buf->data[active_buf->index], packet, sizeof(CorrectedDataPacket_t));
active_buf->index += sizeof(CorrectedDataPacket_t);
active_buf->state = BUFFER_WRITING;
handle->stats.total_samples++;
return HAL_OK;
}
/**
* @brief 刷新缓冲区到文件
* @param handle: 数据存储句柄指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_Flush(DataStorageHandle_t *handle)
{
if (handle == NULL || !handle->initialized) {
return HAL_ERROR;
}
// 处理后台刷新任务
DataStorage_ProcessBackgroundTasks(handle);
return HAL_OK;
}
/**
* @brief 创建新的数据文件
* @param handle: 数据存储句柄指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle)
{
if (handle == NULL || !handle->initialized) {
return HAL_ERROR;
}
// 生成文件名 (基于时间戳)
uint32_t timestamp = HAL_GetTick();
snprintf(handle->stats.current_filename, sizeof(handle->stats.current_filename),
"%s%s%08lX.dat", DATA_STORAGE_PATH, DATA_STORAGE_FILE_PREFIX, timestamp);
// 创建并打开文件
FRESULT res = f_open(&handle->file, handle->stats.current_filename,
FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK) {
handle->stats.error_count++;
SystemMonitor_ReportSDWriteError(); // 报告文件创建错误
return HAL_ERROR;
}
handle->stats.file_count++;
handle->stats.current_file_size = 0;
SystemMonitor_ReportSDFileCreated(); // 报告文件创建成功
return HAL_OK;
}
/**
* @brief 获取数据存储统计信息
* @param handle: 数据存储句柄指针
* @param stats: 统计信息结构体指针
* @retval None
*/
void DataStorage_GetStats(DataStorageHandle_t *handle, DataStorageStats_t *stats)
{
if (handle == NULL || stats == NULL || !handle->initialized) {
return;
}
memcpy(stats, &handle->stats, sizeof(DataStorageStats_t));
}
/**
* @brief 开始数据记录
* @param handle: 数据存储句柄指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_StartRecording(DataStorageHandle_t *handle)
{
if (handle == NULL || !handle->initialized) {
return HAL_ERROR;
}
if (handle->stats.state == DATA_STORAGE_RECORDING) {
return HAL_OK; // 已经在记录中
}
// 创建新文件
if (DataStorage_CreateNewFile(handle) != HAL_OK) {
handle->stats.state = DATA_STORAGE_ERROR;
return HAL_ERROR;
}
// 重置双缓冲区状态
for (int i = 0; i < 2; i++) {
handle->buffers[i].index = 0;
handle->buffers[i].state = BUFFER_IDLE;
}
handle->active_buffer = 0;
handle->flush_buffer = 1;
handle->flush_in_progress = 0;
handle->stats.state = DATA_STORAGE_RECORDING;
return HAL_OK;
}
/**
* @brief 刷新指定缓冲区到文件
* @param handle: 数据存储句柄指针
* @param buffer_index: 缓冲区索引 (0 或 1)
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t buffer_index)
{
if (handle == NULL || !handle->initialized || buffer_index > 1) {
return HAL_ERROR;
}
DataBuffer_t *buffer = &handle->buffers[buffer_index];
// 检查缓冲区状态和数据
if (buffer->state != BUFFER_READY_TO_FLUSH || buffer->index == 0) {
return HAL_OK; // 没有数据需要刷新
}
// 标记缓冲区正在刷新
buffer->state = BUFFER_FLUSHING;
UINT bytes_written;
FRESULT res = f_write(&handle->file, buffer->data, buffer->index, &bytes_written);
if (res != FR_OK || bytes_written != buffer->index) {
handle->stats.error_count++;
buffer->state = BUFFER_READY_TO_FLUSH; // 恢复状态以便重试
SystemMonitor_ReportSDWriteError(); // 报告SD卡写入错误
return HAL_ERROR;
}
// 同步到存储设备
f_sync(&handle->file);
// 更新统计信息
handle->stats.current_file_size += bytes_written;
SystemMonitor_ReportSDWrite(bytes_written); // 报告SD卡写入成功
// 重置缓冲区
buffer->index = 0;
buffer->state = BUFFER_IDLE;
// 检查文件大小是否超过限制
if (handle->stats.current_file_size >= DATA_STORAGE_FILE_MAX_SIZE) {
f_close(&handle->file);
DataStorage_CreateNewFile(handle);
}
return HAL_OK;
}
/**
* @brief 处理后台任务(异步刷新缓冲区)
* @param handle: 数据存储句柄指针
* @retval None
*/
void DataStorage_ProcessBackgroundTasks(DataStorageHandle_t *handle)
{
if (handle == NULL || !handle->initialized) {
return;
}
// 检查是否有缓冲区需要刷新
for (int i = 0; i < 2; i++) {
if (handle->buffers[i].state == BUFFER_READY_TO_FLUSH) {
// 刷新缓冲区
DataStorage_FlushBuffer(handle, i);
break; // 一次只处理一个缓冲区,避免阻塞太久
}
}
}
/**
* @brief 切换活动缓冲区
* @param handle: 数据存储句柄指针
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_SwitchBuffer(DataStorageHandle_t *handle)
{
if (handle == NULL || !handle->initialized) {
return HAL_ERROR;
}
DataBuffer_t *current_buf = &handle->buffers[handle->active_buffer];
// 标记当前缓冲区准备刷新
if (current_buf->index > 0) {
current_buf->state = BUFFER_READY_TO_FLUSH;
}
// 切换到另一个缓冲区
uint8_t next_buffer = (handle->active_buffer == 0) ? 1 : 0;
DataBuffer_t *next_buf = &handle->buffers[next_buffer];
// 检查目标缓冲区是否可用
if (next_buf->state == BUFFER_FLUSHING) {
// 目标缓冲区正在刷新,等待完成
handle->stats.error_count++;
SystemMonitor_ReportSDBufferFull(); // 报告缓冲区满
return HAL_ERROR;
}
// 切换活动缓冲区
handle->active_buffer = next_buffer;
next_buf->index = 0;
next_buf->state = BUFFER_WRITING;
return HAL_OK;
}