#include "data_storage.h" #include "system_monitor.h" #include #include #include /** * @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; // 读取Flash计数器,计算本次会话起始值并立即写回 // 策略:上电读取存储值+1000作为本次起始,立即写入,防止异常断电重复使用同一区间 uint32_t flash_base = 0; FlashCounter_Init(&flash_base); handle->file_counter = flash_base + 1000; FlashCounter_Write(handle->file_counter); 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); } } // 强制同步所有数据到SD卡 f_sync(&handle->file); // 关闭文件 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 通用字节流写入,支持任意包长度(方案Y混流存储) * @param handle: 数据存储句柄指针 * @param data: 数据缓冲区指针 * @param size: 写入字节数 * @retval HAL_StatusTypeDef */ HAL_StatusTypeDef DataStorage_WriteRawBytes(DataStorageHandle_t *handle, const uint8_t *data, uint16_t size) { if (handle == NULL || data == NULL || !handle->initialized || size == 0) { 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 + size > 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], data, size); active_buf->index += size; 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; } GPS_Data_t gps; GPS_GetData(&gps); if (gps.data_valid) { // GPS有效:用 HHMMSS 命名,同秒冲突时追加 _1 _2 ... char base[DATA_STORAGE_MAX_PATH_LEN]; snprintf(base, sizeof(base), "%s/%02u%02u%02u", handle->current_session_path, gps.time.hour, gps.time.minute, gps.time.second); FILINFO fno; snprintf(handle->stats.current_filename, sizeof(handle->stats.current_filename), "%s.dat", base); if (f_stat(handle->stats.current_filename, &fno) == FR_OK) { for (int i = 1; i <= 99; i++) { snprintf(handle->stats.current_filename, sizeof(handle->stats.current_filename), "%s_%d.dat", base, i); if (f_stat(handle->stats.current_filename, &fno) != FR_OK) break; } } } else { // 无GPS:用Flash计数器命名 C0001000.dat snprintf(handle->stats.current_filename, sizeof(handle->stats.current_filename), "%s/C%08lu.dat", handle->current_session_path, handle->file_counter++); } 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; // 已经在记录中 } // 每次开始录制时确定会话目录(此时GPS可能已定位) if (DataStorage_CreateSessionFolder(handle) != HAL_OK) { handle->stats.state = DATA_STORAGE_ERROR; return HAL_ERROR; } // 创建新文件 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; } // 优化:减少同步频率以提高性能 // 使用静态变量记录刷新次数 static uint32_t flush_count = 0; flush_count++; // 每10次刷新才同步一次,或者文件即将达到最大大小时同步 if (flush_count % 10 == 0 || handle->stats.current_file_size + bytes_written >= DATA_STORAGE_FILE_MAX_SIZE) { 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; } /** * @brief 检查缓冲区是否有足够空间可用 * @param handle: 数据存储句柄指针 * @param required_size: 需要的空间大小(字节) * @retval 1: 缓冲区可用, 0: 缓冲区不可用 */ uint8_t DataStorage_IsBufferAvailable(DataStorageHandle_t *handle, uint32_t required_size) { if (handle == NULL || !handle->initialized) { return 0; } // 如果未在记录状态,返回不可用 if (handle->stats.state != DATA_STORAGE_RECORDING) { return 0; } DataBuffer_t *active_buf = &handle->buffers[handle->active_buffer]; // 检查当前活动缓冲区是否有足够空间 if (active_buf->index + required_size <= DATA_STORAGE_BUFFER_SIZE) { return 1; // 当前缓冲区有足够空间 } // 当前缓冲区空间不足,检查是否可以切换到另一个缓冲区 uint8_t next_buffer = (handle->active_buffer == 0) ? 1 : 0; DataBuffer_t *next_buf = &handle->buffers[next_buffer]; // 如果另一个缓冲区正在刷新或准备刷新,则不可用 if (next_buf->state == BUFFER_FLUSHING || next_buf->state == BUFFER_READY_TO_FLUSH) { return 0; // 无法切换,缓冲区不可用 } // 另一个缓冲区可用 return 1; } /** * @brief 创建新的会话文件夹 * @param handle: 数据存储句柄指针 * @retval HAL_StatusTypeDef */ HAL_StatusTypeDef DataStorage_CreateSessionFolder(DataStorageHandle_t *handle) { if (handle == NULL) { return HAL_ERROR; } // 创建基础数据目录 FRESULT res = f_mkdir(DATA_STORAGE_BASE_PATH); if (res != FR_OK && res != FR_EXIST) { return HAL_ERROR; } GPS_Data_t gps; GPS_GetData(&gps); if (gps.date_valid) { // GPS日期有效:目录格式 0:/DATA/YYYYMMDD snprintf(handle->current_session_path, sizeof(handle->current_session_path), "%s/%04u%02u%02u", DATA_STORAGE_BASE_PATH, gps.date.year, gps.date.month, gps.date.day); } else { // 无GPS日期:统一放入 NOFX 目录 snprintf(handle->current_session_path, sizeof(handle->current_session_path), "%s", DATA_STORAGE_NOFX_DIR); } res = f_mkdir(handle->current_session_path); if (res != FR_OK && res != FR_EXIST) { return HAL_ERROR; } return HAL_OK; }