Files

1211 lines
42 KiB
C
Raw Permalink 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 debug_files.c
* @brief 文件类业务:FileOperations (FATFS) + FirmwareUpgrade (Flash IAP) — 阶段2合并
*/
#include "debug_files.h"
#include "tcp_protocol.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "publicdata/publicdata.h"
#include "publicdata/public_define.h"
#include "app_fatfs/app_fatfs.h"
#include "app_fatfs/fatfs_init.h"
#include "mylog.h"
#include "bsp_include.h"
#include "app_rtc/app_rtc.h"
#include "externalflash/flash_upgrade.h"
#include "tcp_server.h"
#if TCP_DEBUG_EN
/* ========== FileOperations (FATFS) ========== */
#if FATFS_EN
#define TCP_DEBUG_PRINTF_LOG(fmt, ...) \
MYLOG_MSG(0xFF,fmt, ##__VA_ARGS__) //任务打印
/* 全局上传上下文 */
typedef struct {
char path[256];
uint32_t total_size;
uint32_t received_size;
uint8_t *buffer;
} file_upload_context_t;
static file_upload_context_t g_upload_context = {0};
/* FileCtrl 侧也做一次文件系统就绪检查,避免与 shell ls 行为不一致 */
static FS_Status ensure_fs_ready(void)
{
if (!fs_get_is_mounted()) {
FS_Status st = fs_init();
if (st != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] FS init failed: %d\r\n", st);
return st;
}
TCP_DEBUG_PRINTF_LOG("[FileCtrl] FS init ok\r\n");
}
return FS_STATUS_OK;
}
/**
* @brief 将外部路径规范化为 FatFs 可识别路径(0:/...
*/
static void normalize_fs_path(const char *input_path, char *output_path, size_t output_len)
{
if (output_path == NULL || output_len == 0) {
return;
}
output_path[0] = '\0';
if (input_path == NULL || input_path[0] == '\0') {
snprintf(output_path, output_len, "0:/");
return;
}
/* 已是标准盘符路径 */
if (strncmp(input_path, "0:/", 3) == 0) {
snprintf(output_path, output_len, "%s", input_path);
return;
}
/* 兼容 "0:log/xx" -> "0:/log/xx" */
if (strncmp(input_path, "0:", 2) == 0) {
if (input_path[2] == '/') {
snprintf(output_path, output_len, "%s", input_path);
} else {
snprintf(output_path, output_len, "0:/%s", input_path + 2);
}
return;
}
/* 兼容 "/log" 形式 */
if (input_path[0] == '/') {
snprintf(output_path, output_len, "0:%s", input_path);
return;
}
/* 兼容 "log/xxx" 形式 */
snprintf(output_path, output_len, "0:/%s", input_path);
}
/**
* @brief 初始化文件操作模块
* @retval 0成功,-1失败
*/
int system_filectrl_init(void)
{
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Initializing file control module...\r\n");
/* 重置上传上下文 */
memset(&g_upload_context, 0, sizeof(g_upload_context));
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File control module initialized successfully\r\n");
return 0;
}
/**
* @brief 将FS_FileInfo转换为file_info_t
* @param fs_info 输入FS_FileInfo结构体
* @param file_info 输出file_info_t结构体
*/
static void convert_fs_fileinfo_to_fileinfo(const FS_FileInfo *fs_info, file_info_t *file_info)
{
if (fs_info == NULL || file_info == NULL) {
return;
}
/* 复制文件名 */
strncpy(file_info->name, fs_info->name, sizeof(file_info->name) - 1);
file_info->name[sizeof(file_info->name) - 1] = '\0';
/* 设置文件类型(FS_FileInfo没有类型信息,默认为普通文件) */
file_info->type = FILE_TYPE_REGULAR;
/* 复制文件大小 */
file_info->size = fs_info->size;
/* 格式化时间字符串 */
snprintf(file_info->modified_time, sizeof(file_info->modified_time),
"%04u-%02u-%02u %02u:%02u:%02u",
fs_info->year, fs_info->month, fs_info->day,
fs_info->hour, fs_info->minute, fs_info->second);
/* 创建时间使用修改时间(FS_FileInfo没有创建时间) */
strncpy(file_info->created_time, file_info->modified_time, sizeof(file_info->created_time) - 1);
file_info->created_time[sizeof(file_info->created_time) - 1] = '\0';
}
/**
* @brief 处理文件查询请求
* @param request 查询请求结构体指针
* @param response 查询响应结构体指针
* @retval 0成功,-1失败
*/
int system_filectrl_process_query(const file_query_request_t *request, file_query_response_t *response)
{
char normalized_path[256] = {0};
if (request == NULL || response == NULL) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Invalid parameters for file query\r\n");
return -1;
}
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Processing file query request\r\n");
TCP_DEBUG_PRINTF_LOG(" Path: %s\r\n", request->path);
TCP_DEBUG_PRINTF_LOG(" Recursive: %s\r\n", request->recursive ? "Yes" : "No");
/* 确保文件系统已初始化/已挂载(对齐 shell ls 行为) */
if (ensure_fs_ready() != FS_STATUS_OK) {
response->file_count = 0;
response->dir_count = 0;
response->total_size = 0;
response->files = NULL;
return 0;
}
normalize_fs_path(request->path, normalized_path, sizeof(normalized_path));
TCP_DEBUG_PRINTF_LOG(" Normalized Path: %s\r\n", normalized_path);
/* 复制规范化路径 */
strncpy(response->path, normalized_path, sizeof(response->path) - 1);
response->path[sizeof(response->path) - 1] = '\0';
/* 使用app_fatfs进行实际文件查询 */
FS_FileInfo file_list[16]; /* 最大16个文件 */
uint32_t file_count = 0;
uint32_t total_size = 0;
/* 查询文件列表 */
FS_Status fs_status = fs_list_dir(normalized_path, file_list, &file_count, 16);
TCP_DEBUG_PRINTF_LOG("[FileCtrl] fs_list_dir(path=%s) => status=%d, file_count=%u\r\n",
normalized_path, fs_status, (unsigned)file_count);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to list files in directory: %s, status=%d\r\n",
normalized_path, fs_status);
/* 如果目录不存在,返回空结果 */
response->file_count = 0;
response->dir_count = 0;
response->total_size = 0;
response->files = NULL;
return 0;
}
/* Debug: print first few files */
for (uint32_t i = 0; i < file_count && i < 5; i++) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] [%u] name=%s size=%u\r\n",
(unsigned)i, file_list[i].name, (unsigned)file_list[i].size);
}
/* 计算总大小 */
for (uint32_t i = 0; i < file_count; i++) {
total_size += file_list[i].size;
}
response->file_count = (uint16_t)file_count;
response->dir_count = 0; /* 目录不需要查询 */
response->total_size = total_size;
/* 分配文件信息数组 */
if (file_count > 0) {
response->files = (file_info_t *)pvPortMalloc(file_count * sizeof(file_info_t));
if (response->files == NULL) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to allocate memory for file list (%u files)\r\n", file_count);
return -1;
}
/* 填充文件信息 */
for (uint32_t i = 0; i < file_count; i++) {
convert_fs_fileinfo_to_fileinfo(&file_list[i], &response->files[i]);
}
} else {
response->files = NULL;
}
// TCP_DEBUG_PRINTF_LOG("[FileCtrl] Query result: %u files, total size: %u bytes\r\n",
// file_count, total_size);
return 0;
}
/**
* @brief 处理文件删除请求
* @param request 删除请求结构体指针
* @param response 删除响应结构体指针
* @retval 0成功,-1失败
*/
int system_filectrl_process_delete(const file_delete_request_t *request, file_delete_response_t *response)
{
if (request == NULL || response == NULL) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Invalid parameters for file delete\r\n");
return -1;
}
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Processing file delete request\r\n");
TCP_DEBUG_PRINTF_LOG(" Path: %s\r\n", request->path);
TCP_DEBUG_PRINTF_LOG(" Force: %s\r\n", request->force ? "Yes" : "No");
/* 复制路径 */
strncpy(response->path, request->path, sizeof(response->path) - 1);
response->path[sizeof(response->path) - 1] = '\0';
/* 检查文件是否存在 */
bool file_exists = false;
FS_Status fs_status = fs_file_exists(request->path, &file_exists);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Error checking file existence: %s, status=%d\r\n",
request->path, fs_status);
response->status = FILE_OP_STATUS_FAILED;
strncpy(response->message, "Error checking file existence", sizeof(response->message) - 1);
response->message[sizeof(response->message) - 1] = '\0';
return 0;
}
if (!file_exists) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File not found: %s\r\n", request->path);
response->status = FILE_OP_STATUS_NOT_FOUND;
strncpy(response->message, "File not found", sizeof(response->message) - 1);
response->message[sizeof(response->message) - 1] = '\0';
return 0;
}
/* 检查是否为系统文件(简单检查,防止删除关键文件) */
const char *system_files[] = {"system", "config", "boot", "firmware"};
for (size_t i = 0; i < sizeof(system_files) / sizeof(system_files[0]); i++) {
if (strstr(request->path, system_files[i]) != NULL) {
/* 如果是强制删除,允许删除 */
if (!request->force) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Cannot delete system file: %s (use force flag)\r\n", request->path);
response->status = FILE_OP_STATUS_PERMISSION_DENIED;
strncpy(response->message, "Cannot delete system file without force flag",
sizeof(response->message) - 1);
response->message[sizeof(response->message) - 1] = '\0';
return 0;
}
}
}
/* 使用app_fatfs删除文件 */
fs_status = fs_delete_file(request->path);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to delete file: %s, status=%d\r\n",
request->path, fs_status);
/* 根据错误状态设置响应 */
switch (fs_status) {
case FS_STATUS_NO_SPACE:
response->status = FILE_OP_STATUS_NO_SPACE;
strncpy(response->message, "No space available", sizeof(response->message) - 1);
break;
case FS_STATUS_FILE_NOT_FOUND:
response->status = FILE_OP_STATUS_NOT_FOUND;
strncpy(response->message, "File not found", sizeof(response->message) - 1);
break;
default:
response->status = FILE_OP_STATUS_FAILED;
strncpy(response->message, "Failed to delete file", sizeof(response->message) - 1);
break;
}
} else {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File deleted successfully: %s\r\n", request->path);
response->status = FILE_OP_STATUS_SUCCESS;
strncpy(response->message, "File deleted successfully", sizeof(response->message) - 1);
}
response->message[sizeof(response->message) - 1] = '\0';
return 0;
}
/**
* @brief 处理文件下载请求
* @param request 下载请求结构体指针
* @param response 下载响应结构体指针
* @retval 0成功,-1失败
*/
int system_filectrl_process_download(const file_download_request_t *request, file_download_response_t *response)
{
if (request == NULL || response == NULL) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Invalid parameters for file download\r\n");
return -1;
}
// TCP_DEBUG_PRINTF_LOG("[FileCtrl] Processing file download request\r\n");
// TCP_DEBUG_PRINTF_LOG(" Path: %s\r\n", request->path);
// TCP_DEBUG_PRINTF_LOG(" Offset: %u bytes\r\n", request->offset);
// TCP_DEBUG_PRINTF_LOG(" Chunk size: %u bytes\r\n", request->chunk_size);
/* 在文件读取操作开始前,使能文件写入禁用标志(TCP调试功能标志位),避免文件系统写入冲突 */
/* 注意:文件读取是分包读取的,需要在读取过程中都禁用文件写入,直到最后一块读取完成 */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 1);
// TCP_DEBUG_PRINTF_LOG("[FileCtrl] File write disabled flag (TCP debug) enabled for file download operation\r\n");
/* 复制路径 */
strncpy(response->path, request->path, sizeof(response->path) - 1);
response->path[sizeof(response->path) - 1] = '\0';
/* 检查文件是否存在 */
bool file_exists = false;
FS_Status fs_status = fs_file_exists(request->path, &file_exists);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Error checking file existence: %s, status=%d\r\n",
request->path, fs_status);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
if (!file_exists) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File not found: %s\r\n", request->path);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
/* 获取文件大小 */
uint32_t file_size = 0;
fs_status = fs_get_file_size(request->path, &file_size);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to get file size: %s, status=%d\r\n",
request->path, fs_status);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
/* 验证偏移量 */
if (request->offset >= file_size) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Offset %u exceeds file size %u\r\n",
request->offset, file_size);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
/* 计算实际读取大小 */
uint32_t chunk_size = request->chunk_size;
if (chunk_size > 1024) {
chunk_size = 1024; /* 最大1024字节 */
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Chunk size limited to %u bytes (max 1024)\r\n", chunk_size);
}
uint32_t remaining = file_size - request->offset;
uint32_t read_size = (remaining < chunk_size) ? remaining : chunk_size;
/* 检查是否为最后一块 */
uint8_t is_last_chunk = (request->offset + read_size >= file_size) ? 1 : 0;
/* 分配读取缓冲区 */
uint8_t *read_buffer = (uint8_t *)pvPortMalloc(read_size);
if (read_buffer == NULL) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to allocate read buffer (%u bytes)\r\n", read_size);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
/* 读取文件内容 */
FS_ReadRange range = {
.start_pos = request->offset,
.end_pos = request->offset + read_size,
.actual_read = 0
};
fs_status = fs_read_file_content(request->path, (char *)read_buffer, read_size, &range);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to read file content: %s, status=%d (offset=%u, size=%u)\r\n",
request->path, fs_status, request->offset, read_size);
vPortFree(read_buffer);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
if (range.actual_read == 0) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Read failed: expected %u, got 0\r\n", read_size);
vPortFree(read_buffer);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
/* 更新实际读取大小(可能小于请求的大小) */
if (range.actual_read != read_size) {
// TCP_DEBUG_PRINTF_LOG("[FileCtrl] Read size adjusted: expected %u, got %u\r\n",
// read_size, range.actual_read);
read_size = range.actual_read;
/* 重新计算是否为最后一块 */
is_last_chunk = (request->offset + read_size >= file_size - 20) ? 1 : 0;
}
/* 过滤掉读取数据中的'\0'字符,确保文本数据完整 */
/* 首先计算过滤后的数据长度(去掉'\0'字符) */
uint32_t filtered_size = 0;
for (uint32_t i = 0; i < read_size; i++) {
if (read_buffer[i] != '\0') {
filtered_size++;
}
}
/* 分配过滤后的文本缓冲区 */
char *text_data = (char *)pvPortMalloc(filtered_size + 1);
if (text_data == NULL) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to allocate text buffer (%u bytes)\r\n", filtered_size + 1);
vPortFree(read_buffer);
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
return -1;
}
/* 复制数据,过滤掉'\0'字符 */
uint32_t dest_index = 0;
for (uint32_t i = 0; i < read_size; i++) {
if (read_buffer[i] != '\0') {
text_data[dest_index++] = read_buffer[i];
}
}
/* 添加null终止符 */
text_data[filtered_size] = '\0';
/* 如果过滤后的数据长度与原始长度不同,打印调试信息 */
// if (filtered_size != read_size) {
// TCP_DEBUG_PRINTF_LOG("[FileCtrl] Filtered null characters: original %u bytes, filtered %u bytes, removed %u null chars\r\n",
// read_size, filtered_size, read_size - filtered_size);
// }
/* 设置响应参数 */
response->file_size = file_size;
response->offset = request->offset;
response->chunk_size = chunk_size;
response->data_len = filtered_size; /* 使用过滤后的数据长度 */
response->is_last_chunk = is_last_chunk;
response->data = (uint8_t *)text_data; /* 存储过滤后的文本数据 */
/* 打印调试信息 */
// TCP_DEBUG_PRINTF_LOG("[FileCtrl] File download successful:\r\n");
// TCP_DEBUG_PRINTF_LOG(" File size: %u bytes\r\n", file_size);
// TCP_DEBUG_PRINTF_LOG(" Read offset: %u bytes\r\n", request->offset);
// TCP_DEBUG_PRINTF_LOG(" Read size: %u bytes\r\n", read_size);
// TCP_DEBUG_PRINTF_LOG(" Is last chunk: %s\r\n", is_last_chunk ? "Yes" : "No");
TCP_DEBUG_PRINTF_LOG(" Progress: %.1f%% (%u/%u bytes)\r\n",
(float)(request->offset + read_size) / file_size * 100.0f,
request->offset + read_size, file_size);
/* 释放读取缓冲区 */
vPortFree(read_buffer);
/* 文件读取操作完成后,只有在最后一块读取完成时才禁用文件写入禁用标志(清除TCP调试功能标志位) */
/* 文件读取是分包读取的,需要在读取过程中都禁用文件写入,直到最后一块读取完成 */
if (is_last_chunk) {
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File write disabled flag (TCP debug) disabled after final chunk download operation\r\n");
} else {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File write disabled flag (TCP debug) remains enabled for next chunk download\r\n");
}
return 0;
}
/**
* @brief 处理文件上传请求
* @param request 上传请求结构体指针
* @param response 上传响应结构体指针
* @retval 0成功,-1失败
*/
int system_filectrl_process_upload(const file_upload_request_t *request, file_upload_response_t *response)
{
if (request == NULL || response == NULL) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Invalid parameters for file upload\r\n");
return -1;
}
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Processing file upload request\r\n");
TCP_DEBUG_PRINTF_LOG(" Path: %s\r\n", request->path);
TCP_DEBUG_PRINTF_LOG(" File size: %u bytes\r\n", request->file_size);
TCP_DEBUG_PRINTF_LOG(" Chunk size: %u bytes\r\n", request->chunk_size);
TCP_DEBUG_PRINTF_LOG(" Offset: %u bytes\r\n", request->offset);
TCP_DEBUG_PRINTF_LOG(" Data length: %u bytes\r\n", request->data_len);
TCP_DEBUG_PRINTF_LOG(" Is last chunk: %s\r\n", request->is_last_chunk ? "Yes" : "No");
/* 复制路径 */
strncpy(response->path, request->path, sizeof(response->path) - 1);
response->path[sizeof(response->path) - 1] = '\0';
response->total_size = request->file_size;
response->received_size = 0;
/* 文件上传功能暂时不实现,返回错误 */
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File upload feature not implemented yet\r\n");
response->status = FILE_OP_STATUS_FAILED;
strncpy(response->message, "File upload feature not implemented", sizeof(response->message) - 1);
response->message[sizeof(response->message) - 1] = '\0';
return 0;
}
/**
* @brief 释放文件查询响应内存
* @param response 查询响应结构体指针
*/
void system_filectrl_free_query_response(file_query_response_t *response)
{
if (response == NULL) {
return;
}
if (response->files != NULL) {
vPortFree(response->files);
response->files = NULL;
}
response->file_count = 0;
response->dir_count = 0;
response->total_size = 0;
}
/**
* @brief 释放文件下载响应内存
* @param response 下载响应结构体指针
*/
void system_filectrl_free_download_response(file_download_response_t *response)
{
if (response == NULL) {
return;
}
if (response->data != NULL) {
vPortFree(response->data);
response->data = NULL;
}
response->data_len = 0;
}
/**
* @brief 释放文件上传请求内存
* @param request 上传请求结构体指针
*/
void system_filectrl_free_upload_request(file_upload_request_t *request)
{
if (request == NULL) {
return;
}
if (request->data != NULL) {
vPortFree(request->data);
request->data = NULL;
}
request->data_len = 0;
}
/**
* @brief 获取文件系统信息
* @param total_space 输出总空间(字节)
* @param free_space 输出可用空间(字节)
* @retval 0成功,-1失败
*/
int system_filectrl_get_filesystem_info(uint32_t *total_space, uint32_t *free_space)
{
if (total_space == NULL || free_space == NULL) {
return -1;
}
/* 使用app_fatfs获取实际文件系统信息 */
uint32_t total_kb = 0;
uint32_t free_kb = 0;
float usage_percent = 0.0f;
FS_Status fs_status = fs_get_volume_info("/", &total_kb, &free_kb, &usage_percent);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to get file system info, status=%d\r\n", fs_status);
/* 返回默认值 */
*total_space = 0;
*free_space = 0;
return -1;
}
/* 转换为字节 */
*total_space = total_kb * 1024;
*free_space = free_kb * 1024;
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File system info: total=%u bytes (%u KB), free=%u bytes (%u KB), usage=%.1f%%\r\n",
*total_space, total_kb, *free_space, free_kb, usage_percent);
return 0;
}
/**
* @brief 检查文件是否存在
* @param path 文件路径
* @retval 0存在,-1不存在
*/
int system_filectrl_file_exists(const char *path)
{
char normalized_path[256] = {0};
if (path == NULL || path[0] == '\0') {
return -1;
}
if (ensure_fs_ready() != FS_STATUS_OK) {
return -1;
}
normalize_fs_path(path, normalized_path, sizeof(normalized_path));
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Checking if file exists: %s (normalized: %s)\r\n", path, normalized_path);
/* 使用app_fatfs检查文件是否存在 */
bool exists = false;
FS_Status fs_status = fs_file_exists(normalized_path, &exists);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Error checking file existence: %s, status=%d\r\n", normalized_path, fs_status);
return -1;
}
if (exists) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File found: %s\r\n", normalized_path);
return 0;
} else {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File not found: %s\r\n", normalized_path);
return -1;
}
}
/**
* @brief 获取文件信息
* @param path 文件路径
* @param info 输出文件信息结构体
* @retval 0成功,-1失败
*/
int system_filectrl_get_file_info(const char *path, file_info_t *info)
{
if (path == NULL || info == NULL) {
return -1;
}
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Getting file info: %s\r\n", path);
/* 使用app_fatfs获取文件信息 */
FS_FileInfo fs_info;
FS_Status fs_status = fs_get_file_info(path, &fs_info);
if (fs_status != FS_STATUS_OK) {
TCP_DEBUG_PRINTF_LOG("[FileCtrl] Failed to get file info: %s, status=%d\r\n", path, fs_status);
return -1;
}
/* 转换文件信息 */
convert_fs_fileinfo_to_fileinfo(&fs_info, info);
TCP_DEBUG_PRINTF_LOG("[FileCtrl] File info retrieved: %s, size=%u bytes\r\n",
info->name, info->size);
return 0;
}
#else /* !FATFS_EN — 桩实现,返回安全默认值 */
int system_filectrl_init(void) { return 0; }
int system_filectrl_process_query(const file_query_request_t *r, file_query_response_t *resp) {
(void)r; if (resp) { resp->file_count = 0; resp->dir_count = 0; resp->total_size = 0; resp->files = NULL; } return 0;
}
int system_filectrl_process_delete(const file_delete_request_t *r, file_delete_response_t *resp) {
(void)r; if (resp) { resp->status = FILE_OP_STATUS_FAILED; } return 0;
}
int system_filectrl_process_download(const file_download_request_t *r, file_download_response_t *resp) {
(void)r; if (resp) { resp->data_len = 0; resp->data = NULL; } return 0;
}
int system_filectrl_process_upload(const file_upload_request_t *r, file_upload_response_t *resp) {
(void)r; if (resp) { resp->status = FILE_OP_STATUS_FAILED; } return 0;
}
void system_filectrl_free_query_response(file_query_response_t *resp) { (void)resp; }
void system_filectrl_free_download_response(file_download_response_t *resp) { (void)resp; }
void system_filectrl_free_upload_request(file_upload_request_t *req) { (void)req; }
int system_filectrl_get_filesystem_info(uint32_t *total, uint32_t *free) {
if (total) *total = 0; if (free) *free = 0; return -1;
}
int system_filectrl_file_exists(const char *path) { (void)path; return -1; }
int system_filectrl_get_file_info(const char *path, file_info_t *info) { (void)path; (void)info; return -1; }
#endif /* FATFS_EN */
/* ========== FirmwareUpgrade (Flash IAP) ========== */
/* 远程固件升级:直接写外置 Flash 升级区(flash_upgrade),与 FATFS 无关 */
static firmware_upgrade_context_t g_firmware_context = {0};
static uint8_t g_reboot_after_upgrade = 0;
static U32_T g_upgrade_last_activity_sec = 0U;
#define FIRMWARE_UPGRADE_IDLE_TIMEOUT_SEC 120U
static uint32_t fw_crc32_update(uint32_t crc, const uint8_t *data, uint32_t len)
{
uint32_t i;
int bit;
crc = ~crc;
for (i = 0U; i < len; i++) {
crc ^= data[i];
for (bit = 0; bit < 8; bit++) {
if (crc & 1U) {
crc = (crc >> 1) ^ 0xEDB88320U;
} else {
crc >>= 1;
}
}
}
return ~crc;
}
/**
* @brief 初始化文件传输模块
* @retval 0成功,-1失败
*/
int system_filetransfer_init(void)
{
TCP_PRINT("[FileTransfer] Initializing file transfer module...\r\n");
memset(&g_firmware_context, 0, sizeof(g_firmware_context));
g_firmware_context.state = FILE_TRANSFER_IDLE;
TCP_PRINT("[FileTransfer] File transfer module initialized successfully\r\n");
return 0;
}
/**
* @brief 升级头部信息控制
* @param u8_flag 0升级前 1升级成功 2升级失败
* @return 0 成功,-1 写 Flash 失败
*/
static int v_upgrade_header_data(U8_T u8_flag)
{
upgrade_header_t header_data;
Comm_Time time;
GetCurrentTime(&time);
memset(&header_data, 0, sizeof(upgrade_header_t));
header_data.file_size = g_firmware_context.file_size;
header_data.packet_count = g_firmware_context.total_packets;
header_data.crc32 = g_firmware_context.crc32;
header_data.timestamp = xDate2Seconds(&time);
if (g_firmware_context.firmware_version[0] != '\0') {
strncpy((char *)header_data.version, g_firmware_context.firmware_version,
sizeof(header_data.version) - 1U);
}
if (u8_flag == 0U) {
header_data.upgrade_flag = UPGRADE_FLAG_IDLE;
} else if (u8_flag == 1U) {
header_data.upgrade_flag = UPGRADE_FLAG_NEED_UP;
} else {
header_data.upgrade_flag = UPGRADE_FLAG_ERROR;
}
printf("upgrade_header flag(0x%04X) fileSize[%lu] crc32[0x%08lX]\r\n",
(unsigned int)header_data.upgrade_flag,
(unsigned long)header_data.file_size,
(unsigned long)header_data.crc32);
if (upgrade_success_update_header(&header_data) != 0) {
printf("upgrade_header write FAILED\r\n");
return -1;
}
printf("upgrade_header write done\r\n");
return 0;
}
int system_filetransfer_start_firmware_upgrade(uint32_t file_size, uint32_t total_packets,
uint32_t packet_size, const char *firmware_version)
{
TCP_PRINT("[FileTransfer] Starting firmware upgrade:\r\n");
TCP_PRINT(" File size: %u bytes\r\n", file_size);
TCP_PRINT(" Total packets: %u\r\n", total_packets);
TCP_PRINT(" Packet size: %u bytes\r\n", packet_size);
TCP_PRINT(" Firmware version: %s\r\n", firmware_version);
if (file_size == 0U || total_packets == 0U || packet_size == 0U) {
TCP_PRINT("[FileTransfer] Invalid parameters\r\n");
return -1;
}
if (file_size > PROGRAM_MAX_SIZE) {
TCP_PRINT("[FileTransfer] File too large: %u > %u\r\n", file_size, PROGRAM_MAX_SIZE);
return -1;
}
if (g_firmware_context.buffer != NULL) {
vPortFree(g_firmware_context.buffer);
g_firmware_context.buffer = NULL;
}
{
uint8_t *rx_buf;
rx_buf = (uint8_t *)pvPortMalloc(packet_size);
if (rx_buf == NULL) {
TCP_PRINT("[FileTransfer] Failed to allocate buffer for firmware (%u bytes)\r\n", packet_size);
return -1;
}
memset(&g_firmware_context, 0, sizeof(g_firmware_context));
g_firmware_context.buffer = rx_buf;
}
g_firmware_context.state = FILE_TRANSFER_STARTED;
g_firmware_context.file_size = file_size;
g_firmware_context.total_packets = total_packets;
g_firmware_context.packet_size = packet_size;
g_firmware_context.received_packets = 0;
g_firmware_context.received_bytes = 0;
g_firmware_context.crc32 = 0;
if (firmware_version != NULL) {
strncpy(g_firmware_context.firmware_version, firmware_version,
sizeof(g_firmware_context.firmware_version) - 1);
}
TCP_PRINT("[FileTransfer] Firmware upgrade session ready (erase pending ACK)\r\n");
TCP_PRINT("[FileTransfer] Will receive %u packets after erase\r\n", total_packets);
g_upgrade_last_activity_sec = get_current_seconds();
return 0;
}
int system_filetransfer_commit_firmware_start(void)
{
if (g_firmware_context.state != FILE_TRANSFER_STARTED) {
TCP_PRINT("[FileTransfer] commit_firmware_start: invalid state\r\n");
return -1;
}
if (upgrade_erase_program_area_for_size(g_firmware_context.file_size) != 0) {
TCP_PRINT("[FileTransfer] Failed to erase upgrade program area\r\n");
system_filetransfer_reset();
return -1;
}
g_firmware_context.state = FILE_TRANSFER_RECEIVING;
g_upgrade_last_activity_sec = get_current_seconds();
TCP_PRINT("[FileTransfer] Writing upgrade idle header...\r\n");
if (v_upgrade_header_data(0) != 0) {
TCP_PRINT("[FileTransfer] Idle header write failed\r\n");
system_filetransfer_reset();
return -1;
}
TCP_PRINT("[FileTransfer] Idle header written\r\n");
printf("[FileTransfer] Firmware upgrade started successfully\r\n");
TCP_PRINT("[FileTransfer] Firmware upgrade started successfully\r\n");
return 0;
}
static void print_hex_data(const uint8_t *data, uint32_t len, const char *prefix)
{
if (data == NULL || len == 0) {
return;
}
char hex_buffer[128];
uint32_t hex_pos = 0;
uint32_t i;
for (i = 0; i < len && hex_pos < sizeof(hex_buffer) - 3; i++) {
hex_pos += snprintf(hex_buffer + hex_pos, sizeof(hex_buffer) - hex_pos,
"%02X ", data[i]);
}
TCP_PRINT("%s%s\r\n", prefix, hex_buffer);
}
int system_filetransfer_receive_firmware_packet(uint32_t packet_index, const uint8_t *data,
uint32_t data_len, uint32_t crc)
{
(void)crc;
TCP_PRINT("[FileTransfer] Receiving firmware packet %u/%u\r\n",
packet_index + 1, g_firmware_context.total_packets);
TCP_PRINT(" Data length: %u bytes (Base64)\r\n", data_len);
TCP_PRINT(" CRC: 0x%08X\r\n", crc);
if (g_firmware_context.state != FILE_TRANSFER_STARTED &&
g_firmware_context.state != FILE_TRANSFER_RECEIVING) {
TCP_PRINT("[FileTransfer] Firmware upgrade not started or already completed\r\n");
return -1;
}
int decoded_len = 0;
uint8_t *decoded_data = NULL;
if (data != NULL && data_len > 0) {
uint32_t max_decoded_size = (data_len * 3) / 4 + 4;
decoded_data = (uint8_t *)pvPortMalloc(max_decoded_size);
if (decoded_data != NULL) {
char *temp_str = (char *)pvPortMalloc(data_len + 1);
if (temp_str == NULL) {
TCP_PRINT("[FileTransfer] Failed to allocate temp buffer for Base64 decoding\r\n");
vPortFree(decoded_data);
return -1;
}
memcpy(temp_str, data, data_len);
temp_str[data_len] = '\0';
decoded_len = base64_decode(temp_str, decoded_data, max_decoded_size);
vPortFree(temp_str);
if (decoded_len <= 0) {
TCP_PRINT("[FileTransfer] Base64 decode failed\r\n");
vPortFree(decoded_data);
return -1;
}
TCP_PRINT("[FileTransfer] Base64 decoded successfully: %d bytes\r\n", decoded_len);
} else {
TCP_PRINT("[FileTransfer] Failed to allocate memory for Base64 decoding\r\n");
return -1;
}
} else {
TCP_PRINT("[FileTransfer] No data to decode\r\n");
return -1;
}
if (packet_index != g_firmware_context.received_packets) {
TCP_PRINT("[FileTransfer] Unexpected packet index %u, expect %u\r\n",
packet_index, g_firmware_context.received_packets);
vPortFree(decoded_data);
return -1;
}
if (packet_index >= g_firmware_context.total_packets) {
TCP_PRINT("[FileTransfer] Invalid packet index: %u (max: %u)\r\n",
packet_index, g_firmware_context.total_packets - 1);
vPortFree(decoded_data);
return -1;
}
if (decoded_len > (int)g_firmware_context.packet_size) {
TCP_PRINT("[FileTransfer] Decoded data length exceeds packet size: %d > %u\r\n",
decoded_len, g_firmware_context.packet_size);
vPortFree(decoded_data);
return -1;
}
{
uint32_t offset = packet_index * g_firmware_context.packet_size;
if (offset + (uint32_t)decoded_len > g_firmware_context.file_size) {
TCP_PRINT("[FileTransfer] Data would exceed file size\r\n");
vPortFree(decoded_data);
return -1;
}
}
if (decoded_len > 0) {
uint32_t print_front = (decoded_len > 10) ? 10 : (uint32_t)decoded_len;
if (print_front > 0) {
print_hex_data(decoded_data, print_front,
"[FileTransfer] First 10 bytes: ");
}
if (decoded_len > 10) {
uint32_t print_back = 10;
uint32_t start_pos = (uint32_t)decoded_len - print_back;
print_hex_data(decoded_data + start_pos, print_back,
"[FileTransfer] Last 10 bytes: ");
}
int flash_write = upgrade_write_packet(packet_index, decoded_data, (uint32_t)decoded_len);
printf("[FW_UPGRADE] flash_write %d ,packet %d (%d), data length: %d(%d) bytes\r\n",
flash_write, packet_index, g_firmware_context.total_packets,
g_firmware_context.received_bytes, g_firmware_context.file_size);
if (flash_write == -1) {
vPortFree(decoded_data);
return -1;
}
g_firmware_context.crc32 = fw_crc32_update(g_firmware_context.crc32, decoded_data, (uint32_t)decoded_len);
}
g_firmware_context.received_packets++;
g_firmware_context.received_bytes += (uint32_t)decoded_len;
g_firmware_context.state = FILE_TRANSFER_RECEIVING;
{
float progress = (float)g_firmware_context.received_packets / g_firmware_context.total_packets * 100.0f;
TCP_PRINT("[FileTransfer] Progress: %u/%u packets (%.1f%%), %u/%u bytes\r\n",
g_firmware_context.received_packets, g_firmware_context.total_packets,
progress, g_firmware_context.received_bytes, g_firmware_context.file_size);
}
vPortFree(decoded_data);
return 0;
}
int system_filetransfer_end_firmware_upgrade(uint8_t status, const char *error_message)
{
uint8_t upgrade_ok = 0U;
TCP_PRINT("[FileTransfer] Ending firmware upgrade\r\n");
TCP_PRINT(" Status: %u\r\n", status);
if (error_message != NULL && error_message[0] != '\0') {
TCP_PRINT(" Error message: %s\r\n", error_message);
}
if (g_firmware_context.state == FILE_TRANSFER_IDLE) {
TCP_PRINT("[FileTransfer] No firmware upgrade in progress\r\n");
return -1;
}
g_reboot_after_upgrade = 0U;
if (status == FIRMWARE_STATUS_SUCCESS || status == FIRMWARE_STATUS_COMPLETED) {
if (g_firmware_context.received_packets == g_firmware_context.total_packets &&
g_firmware_context.received_bytes >= g_firmware_context.file_size) {
g_firmware_context.state = FILE_TRANSFER_COMPLETED;
upgrade_ok = 1U;
TCP_PRINT("[FileTransfer] Firmware upgrade completed: %u packets, %u bytes, CRC32=0x%08lX\r\n",
g_firmware_context.received_packets,
g_firmware_context.received_bytes,
(unsigned long)g_firmware_context.crc32);
} else {
g_firmware_context.state = FILE_TRANSFER_FAILED;
TCP_PRINT("[FileTransfer] Incomplete data: expect %u packets / %u bytes; got %u packets / %u bytes\r\n",
g_firmware_context.total_packets, g_firmware_context.file_size,
g_firmware_context.received_packets, g_firmware_context.received_bytes);
}
} else {
g_firmware_context.state = FILE_TRANSFER_FAILED;
TCP_PRINT("[FileTransfer] Firmware upgrade failed with status %u\r\n", status);
}
if (g_firmware_context.buffer != NULL) {
vPortFree(g_firmware_context.buffer);
g_firmware_context.buffer = NULL;
}
if (upgrade_ok) {
v_upgrade_header_data(1U);
g_reboot_after_upgrade = 1U;
tcp_server_rx_upgrade_end();
TCP_PRINT("[FileTransfer] Upgrade complete, rebooting for IAP...\r\n");
v_sys_reboot();
} else {
v_upgrade_header_data(2U);
tcp_server_rx_upgrade_end();
}
return upgrade_ok ? 0 : 1;
}
int system_filetransfer_is_reboot_pending(void)
{
return (g_reboot_after_upgrade != 0U) ? 1 : 0;
}
void system_filetransfer_clear_reboot_pending(void)
{
g_reboot_after_upgrade = 0U;
}
int system_filetransfer_get_firmware_status(firmware_upgrade_context_t *context)
{
if (context == NULL) {
return -1;
}
memcpy(context, &g_firmware_context, sizeof(firmware_upgrade_context_t));
return 0;
}
int system_filetransfer_is_active(void)
{
return (g_firmware_context.state == FILE_TRANSFER_STARTED ||
g_firmware_context.state == FILE_TRANSFER_RECEIVING) ? 1 : 0;
}
int system_filetransfer_get_expected_packet_bytes(uint32_t packet_index, uint32_t *out_len)
{
uint32_t offset;
uint32_t expect;
if (out_len == NULL) {
return -1;
}
*out_len = 0U;
if (g_firmware_context.state != FILE_TRANSFER_STARTED &&
g_firmware_context.state != FILE_TRANSFER_RECEIVING) {
return -1;
}
if (packet_index >= g_firmware_context.total_packets) {
return -1;
}
offset = packet_index * g_firmware_context.packet_size;
expect = g_firmware_context.file_size - offset;
if (expect > g_firmware_context.packet_size) {
expect = g_firmware_context.packet_size;
}
*out_len = expect;
return 0;
}
void system_filetransfer_touch_activity_on_rx(void)
{
if (system_filetransfer_is_active() != 0) {
g_upgrade_last_activity_sec = get_current_seconds();
}
}
void system_filetransfer_poll_idle_timeout(void)
{
if (system_filetransfer_is_active() == 0) {
return;
}
if (g_upgrade_last_activity_sec == 0U) {
return;
}
if (u32_safe_seconds_since(g_upgrade_last_activity_sec) >= FIRMWARE_UPGRADE_IDLE_TIMEOUT_SEC) {
TCP_PRINT("[FileTransfer] Idle %u s (no RX), abort upgrade\r\n",
(unsigned)FIRMWARE_UPGRADE_IDLE_TIMEOUT_SEC);
system_filetransfer_reset();
}
}
void system_filetransfer_reset(void)
{
TCP_PRINT("[FileTransfer] Resetting file transfer module...\r\n");
g_reboot_after_upgrade = 0U;
if (g_firmware_context.buffer != NULL) {
vPortFree(g_firmware_context.buffer);
g_firmware_context.buffer = NULL;
}
memset(&g_firmware_context, 0, sizeof(g_firmware_context));
g_firmware_context.state = FILE_TRANSFER_IDLE;
TCP_PRINT("[FileTransfer] File transfer module reset successfully\r\n");
tcp_server_rx_upgrade_end();
}
#endif /* TCP_DEBUG_EN */