/** * @file debug_files.c * @brief 文件类业务:FileOperations (FATFS) + FirmwareUpgrade (Flash IAP) — 阶段2合并 */ #include "debug_files.h" #include "tcp_protocol.h" #include #include #include #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 */