/***************************************************************************** * @file PathTest.c * @brief 路径下载和读取测试模块 + OTA升级测试模块 * @author AI Assistant * @date 2025-12-19 *****************************************************************************/ #include "PathTest.h" #include "PathStorage.h" #include "OTAUpgrade.h" #include "TCPClient.h" #include "HIDO_Debug.h" #include "HIDO_Timer.h" #include /***************************************************************************** * 私有宏定义 *****************************************************************************/ #define MAX_BOUNDARY_POINTS 1000 // 边界点上限 #define MAX_PATH_POINTS 4000 // 路径点上限 #define TEST_CHECK_INTERVAL 1000 // 状态检查间隔(ms) /***************************************************************************** * 私有数据结构 *****************************************************************************/ typedef struct { E_PathTestState state; // 当前测试状态 HIDO_BOOL tcp_connected_triggered; // TCP连接后是否已触发下载 HIDO_UINT32 last_check_tick; // 上次检查时间戳 HIDO_UINT32 boundary_read_count; // 已读取的边界点数 HIDO_UINT32 path_read_count; // 已读取的路径点数 } PathTestContext_t; /***************************************************************************** * 私有全局变量 *****************************************************************************/ static PathTestContext_t s_test_ctx = { .state = PATH_TEST_STATE_IDLE, .tcp_connected_triggered = HIDO_FALSE, .last_check_tick = 0, .boundary_read_count = 0, .path_read_count = 0 }; // 数据缓冲区(避免占用过多栈空间) static PathPoint_t s_boundary_buffer[100]; // 每次读取100个边界点 static PathPoint_t s_path_buffer[100]; // 每次读取100个路径点 /***************************************************************************** * 私有函数声明 *****************************************************************************/ static void PathTest_StartDownload(void); static void PathTest_CheckDownloadStatus(void); static void PathTest_VerifyData(void); static void PathTest_ReadAllPoints(void); static HIDO_BOOL PathTest_IsTCPConnected(void); /***************************************************************************** * 函数实现 *****************************************************************************/ /** * @brief 初始化路径测试模块 */ HIDO_INT32 PathTest_Init(void) { memset(&s_test_ctx, 0, sizeof(s_test_ctx)); s_test_ctx.state = PATH_TEST_STATE_WAIT_NETWORK; s_test_ctx.tcp_connected_triggered = HIDO_FALSE; HIDO_Debug("[PathTest] Initialized, waiting for TCP connection...\r\n"); return 0; } /** * @brief 路径测试主循环(需要在app_task中定期调用) */ void PathTest_Poll(void) { HIDO_UINT32 current_tick = HIDO_TimerGetTick(); // 限制检查频率 if (current_tick - s_test_ctx.last_check_tick < TEST_CHECK_INTERVAL) { return; } s_test_ctx.last_check_tick = current_tick; switch (s_test_ctx.state) { case PATH_TEST_STATE_WAIT_NETWORK: // 等待TCP连接 if (PathTest_IsTCPConnected() && !s_test_ctx.tcp_connected_triggered) { HIDO_Debug("[PathTest] TCP connected! Starting path download test...\r\n"); PathTest_StartDownload(); s_test_ctx.tcp_connected_triggered = HIDO_TRUE; s_test_ctx.state = PATH_TEST_STATE_DOWNLOADING; } break; case PATH_TEST_STATE_DOWNLOADING: // 检查下载状态 PathTest_CheckDownloadStatus(); break; case PATH_TEST_STATE_VERIFY: // 验证数据 PathTest_VerifyData(); break; case PATH_TEST_STATE_READING: // 读取所有点数据 PathTest_ReadAllPoints(); break; case PATH_TEST_STATE_COMPLETE: // 测试完成,停止轮询 HIDO_Debug("[PathTest] ===== TEST COMPLETED SUCCESSFULLY =====\r\n"); s_test_ctx.state = PATH_TEST_STATE_IDLE; break; case PATH_TEST_STATE_FAILED: // 测试失败,恢复TCP连接 HIDO_Debug("[PathTest] ===== TEST FAILED =====\r\n"); extern HIDO_INT32 TCPClient_Resume(void); TCPClient_Resume(); s_test_ctx.state = PATH_TEST_STATE_IDLE; break; default: break; } } /** * @brief 检查TCP是否已连接 */ static HIDO_BOOL PathTest_IsTCPConnected(void) { // 通过extern访问TCPClient的状态 extern E_TCPClientState l_eTCPClientState; return (l_eTCPClientState == TCP_CLIENT_STATE_CONNECTED); } /** * @brief 启动路径文件下载 */ static void PathTest_StartDownload(void) { const HIDO_CHAR *url = "http://39.99.43.227:8866/api/file/download/21b09df9-9232-4e38-a5cc-19458d324019_data.bin"; HIDO_INT32 ret; HIDO_Debug("[PathTest] Starting download from: %s\r\n", url); // 暂停TCP连接以停止差分数据接收 extern HIDO_INT32 TCPClient_Pause(void); TCPClient_Pause(); ret = PathStorage_DownloadFromHTTP(url); if (ret != 0) { HIDO_Debug("[PathTest] Failed to start download: %d\r\n", ret); s_test_ctx.state = PATH_TEST_STATE_FAILED; } } /** * @brief 检查下载状态 */ static void PathTest_CheckDownloadStatus(void) { E_PathStorageStatus status = PathStorage_GetStatus(); HIDO_UINT8 progress = PathStorage_GetProgress(); // 每次检查时打印进度 if (progress > 0) { HIDO_Debug("[PathTest] Download progress: %u%%\r\n", progress); } if (status == PATH_STORAGE_STATUS_SUCCESS) { HIDO_Debug("[PathTest] Download completed successfully!\r\n"); s_test_ctx.state = PATH_TEST_STATE_VERIFY; } else if (status == PATH_STORAGE_STATUS_FAIL_NETWORK) { HIDO_Debug("[PathTest] Download failed: Network error\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; } else if (status == PATH_STORAGE_STATUS_FAIL_FLASH) { HIDO_Debug("[PathTest] Download failed: Flash error\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; } else if (status == PATH_STORAGE_STATUS_FAIL_CRC) { HIDO_Debug("[PathTest] Download failed: CRC error\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; } else if (status == PATH_STORAGE_STATUS_FAIL_FORMAT) { HIDO_Debug("[PathTest] Download failed: Format error\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; } } /** * @brief 验证路径文件头数据 */ static void PathTest_VerifyData(void) { MowerPathHeader_t header; HIDO_INT32 ret; HIDO_Debug("[PathTest] ===== Verifying Path File =====\r\n"); ret = PathStorage_ReadHeader(&header); if (ret != 0) { HIDO_Debug("[PathTest] Failed to read header: %d\r\n", ret); s_test_ctx.state = PATH_TEST_STATE_FAILED; return; } // 打印文件头信息 HIDO_Debug("[PathTest] File Header Info:\r\n"); HIDO_Debug(" SOF: 0x%04X\r\n", header.sof); HIDO_Debug(" Type: 0x%02X\r\n", header.type); HIDO_Debug(" Version: 0x%02X\r\n", header.version); HIDO_Debug(" Path ID: 0x%08X\r\n", header.path_id); HIDO_Debug(" Timestamp: %u\r\n", header.timestamp); HIDO_Debug(" Origin Lon: %.8f\r\n", header.origin_lon); HIDO_Debug(" Origin Lat: %.8f\r\n", header.origin_lat); HIDO_Debug(" Origin Alt: %.2f m\r\n", header.origin_alt); HIDO_Debug(" Boundary Count: %u (Max: %d)\r\n", header.boundary_count, MAX_BOUNDARY_POINTS); HIDO_Debug(" Path Count: %u (Max: %d)\r\n", header.path_count, MAX_PATH_POINTS); // 检查点数是否超出上限 if (header.boundary_count > MAX_BOUNDARY_POINTS) { HIDO_Debug("[PathTest] ERROR: Boundary count exceeds limit!\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; return; } if (header.path_count > MAX_PATH_POINTS) { HIDO_Debug("[PathTest] ERROR: Path count exceeds limit!\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; return; } // 验证CRC32 ret = PathStorage_VerifyCRC32(); if (ret != 0) { HIDO_Debug("[PathTest] ERROR: CRC32 verification failed!\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; return; } HIDO_Debug("[PathTest] File verification passed!\r\n"); s_test_ctx.state = PATH_TEST_STATE_READING; s_test_ctx.boundary_read_count = 0; s_test_ctx.path_read_count = 0; } /** * @brief 读取所有路径点数据 */ static void PathTest_ReadAllPoints(void) { MowerPathHeader_t header; HIDO_INT32 ret; HIDO_UINT32 i; HIDO_Debug("[PathTest] ===== Reading All Points =====\r\n"); // 重新读取头部获取点数 ret = PathStorage_ReadHeader(&header); if (ret != 0) { HIDO_Debug("[PathTest] Failed to read header: %d\r\n", ret); s_test_ctx.state = PATH_TEST_STATE_FAILED; return; } // 读取边界点 HIDO_Debug("[PathTest] Reading %u boundary points...\r\n", header.boundary_count); for (i = 0; i < header.boundary_count; i += 100) { HIDO_UINT32 batch_size = (header.boundary_count - i > 100) ? 100 : (header.boundary_count - i); ret = PathStorage_ReadPoints(HIDO_TRUE, i, batch_size, s_boundary_buffer); if (ret < 0) { HIDO_Debug("[PathTest] Failed to read boundary points at index %u: %d\r\n", i, ret); s_test_ctx.state = PATH_TEST_STATE_FAILED; return; } s_test_ctx.boundary_read_count += ret; // 打印前3个和后3个点作为示例 if (i == 0) { HIDO_Debug("[PathTest] First boundary points:\r\n"); for (HIDO_UINT32 j = 0; j < 3 && j < ret; j++) { HIDO_Debug(" [%u] (%.3f, %.3f)\r\n", j, s_boundary_buffer[j].x, s_boundary_buffer[j].y); } } } HIDO_Debug("[PathTest] Boundary points read: %u/%u\r\n", s_test_ctx.boundary_read_count, header.boundary_count); // 读取路径点 HIDO_Debug("[PathTest] Reading %u path points...\r\n", header.path_count); for (i = 0; i < header.path_count; i += 100) { HIDO_UINT32 batch_size = (header.path_count - i > 100) ? 100 : (header.path_count - i); ret = PathStorage_ReadPoints(HIDO_FALSE, i, batch_size, s_path_buffer); if (ret < 0) { HIDO_Debug("[PathTest] Failed to read path points at index %u: %d\r\n", i, ret); s_test_ctx.state = PATH_TEST_STATE_FAILED; return; } s_test_ctx.path_read_count += ret; // 打印前3个和后3个点作为示例 if (i == 0) { HIDO_Debug("[PathTest] First path points:\r\n"); for (HIDO_UINT32 j = 0; j < 3 && j < ret; j++) { HIDO_Debug(" [%u] (%.3f, %.3f)\r\n", j, s_path_buffer[j].x, s_path_buffer[j].y); } } } HIDO_Debug("[PathTest] Path points read: %u/%u\r\n", s_test_ctx.path_read_count, header.path_count); // 验证读取数量 if (s_test_ctx.boundary_read_count == header.boundary_count && s_test_ctx.path_read_count == header.path_count) { HIDO_Debug("[PathTest] All points read successfully!\r\n"); s_test_ctx.state = PATH_TEST_STATE_COMPLETE; } else { HIDO_Debug("[PathTest] Point count mismatch!\r\n"); s_test_ctx.state = PATH_TEST_STATE_FAILED; } // 恢复TCP连接 extern HIDO_INT32 TCPClient_Resume(void); TCPClient_Resume(); } /** * @brief 手动触发测试(可在Shell中调用) */ void PathTest_Trigger(void) { HIDO_Debug("[PathTest] Manual trigger - resetting test state\r\n"); s_test_ctx.state = PATH_TEST_STATE_WAIT_NETWORK; s_test_ctx.tcp_connected_triggered = HIDO_FALSE; } /** * @brief 获取测试状态 */ E_PathTestState PathTest_GetState(void) { return s_test_ctx.state; } /***************************************************************************** * OTA升级测试功能 *****************************************************************************/ /***************************************************************************** * 私有数据结构(OTA测试) *****************************************************************************/ typedef struct { E_OTATestState state; // 当前测试状态 HIDO_BOOL tcp_connected_triggered; // TCP连接后是否已触发下载 HIDO_UINT32 last_check_tick; // 上次检查时间戳 HIDO_UINT8 last_progress; // 上次进度 } OTATestContext_t; /***************************************************************************** * 私有全局变量(OTA测试) *****************************************************************************/ static OTATestContext_t s_ota_test_ctx = { .state = OTA_TEST_STATE_IDLE, .tcp_connected_triggered = HIDO_FALSE, .last_check_tick = 0, .last_progress = 0 }; /***************************************************************************** * 私有函数声明(OTA测试) *****************************************************************************/ static void OTATest_StartDownload(void); static void OTATest_CheckDownloadStatus(void); static void OTATest_CheckDecryptStatus(void); static void OTATest_CheckVerifyStatus(void); /***************************************************************************** * OTA测试函数实现 *****************************************************************************/ /** * @brief 初始化OTA升级测试模块 */ HIDO_INT32 OTATest_Init(void) { HIDO_INT32 ret; // 初始化OTA模块 ret = OTA_Init(); if (ret != HIDO_OK) { HIDO_Debug("[OTATest] OTA_Init failed: %d\r\n", ret); return ret; } memset(&s_ota_test_ctx, 0, sizeof(s_ota_test_ctx)); s_ota_test_ctx.state = OTA_TEST_STATE_WAIT_NETWORK; s_ota_test_ctx.tcp_connected_triggered = HIDO_FALSE; HIDO_Debug("[OTATest] ===== OTA Upgrade Test Initialized =====\r\n"); HIDO_Debug("[OTATest] Waiting for TCP connection...\r\n"); return HIDO_OK; } /** * @brief OTA测试主循环(需要在app_task中定期调用) */ void OTATest_Poll(void) { HIDO_UINT32 current_tick = HIDO_TimerGetTick(); // OTA模块需要周期调用(处理解密任务) OTA_Poll(); // 限制检查频率 if (current_tick - s_ota_test_ctx.last_check_tick < TEST_CHECK_INTERVAL) { return; } s_ota_test_ctx.last_check_tick = current_tick; switch (s_ota_test_ctx.state) { case OTA_TEST_STATE_WAIT_NETWORK: // 等待TCP连接 if (PathTest_IsTCPConnected() && !s_ota_test_ctx.tcp_connected_triggered) { HIDO_Debug("[OTATest] TCP connected! Starting OTA firmware download test...\r\n"); OTATest_StartDownload(); s_ota_test_ctx.tcp_connected_triggered = HIDO_TRUE; s_ota_test_ctx.state = OTA_TEST_STATE_DOWNLOADING; } break; case OTA_TEST_STATE_DOWNLOADING: // 检查下载状态 OTATest_CheckDownloadStatus(); break; case OTA_TEST_STATE_DECRYPTING: // 检查解密状态 OTATest_CheckDecryptStatus(); break; case OTA_TEST_STATE_VERIFYING: // 检查校验状态 OTATest_CheckVerifyStatus(); break; case OTA_TEST_STATE_COMPLETE: // 测试完成,停止轮询 HIDO_Debug("[OTATest] ===== OTA TEST COMPLETED SUCCESSFULLY =====\r\n"); HIDO_Debug("[OTATest] Decrypted firmware is ready at 0x08140000\r\n"); s_ota_test_ctx.state = OTA_TEST_STATE_IDLE; // 恢复TCP连接 extern HIDO_INT32 TCPClient_Resume(void); TCPClient_Resume(); break; case OTA_TEST_STATE_FAILED: // 测试失败 HIDO_Debug("[OTATest] ===== OTA TEST FAILED =====\r\n"); s_ota_test_ctx.state = OTA_TEST_STATE_IDLE; // 恢复TCP连接 extern HIDO_INT32 TCPClient_Resume(void); TCPClient_Resume(); break; default: break; } } /** * @brief 启动OTA固件下载 */ static void OTATest_StartDownload(void) { const HIDO_CHAR *url = "http://123.57.87.125:7001/hfs/STM32H743.Bin"; HIDO_INT32 ret; HIDO_Debug("[OTATest] ===== Starting OTA Firmware Download =====\r\n"); HIDO_Debug("[OTATest] URL: %s\r\n", url); // 暂停TCP连接以停止差分数据接收 extern HIDO_INT32 TCPClient_Pause(void); TCPClient_Pause(); ret = OTA_StartDownload(url); if (ret != HIDO_OK) { HIDO_Debug("[OTATest] Failed to start download, error: %d\r\n", ret); s_ota_test_ctx.state = OTA_TEST_STATE_FAILED; } else { HIDO_Debug("[OTATest] Download started successfully\r\n"); s_ota_test_ctx.last_progress = 0; } } /** * @brief 检查下载状态 */ static void OTATest_CheckDownloadStatus(void) { E_OTAState ota_state = OTA_GetState(); HIDO_UINT8 progress = OTA_GetProgress(); // 进度变化时打印 if (progress != s_ota_test_ctx.last_progress && progress % 10 == 0) { HIDO_Debug("[OTATest] Download progress: %u%%\r\n", progress); s_ota_test_ctx.last_progress = progress; } if (ota_state == OTA_STATE_DOWNLOAD_COMPLETE) { HIDO_Debug("[OTATest] Download completed! Starting decryption...\r\n"); // 启动解密 if (OTA_StartDecrypt() == HIDO_OK) { s_ota_test_ctx.state = OTA_TEST_STATE_DECRYPTING; s_ota_test_ctx.last_progress = 0; } else { HIDO_Debug("[OTATest] Failed to start decryption\r\n"); s_ota_test_ctx.state = OTA_TEST_STATE_FAILED; } } else if (ota_state == OTA_STATE_DOWNLOAD_FAILED) { ST_OTAInfo info; OTA_GetInfo(&info); HIDO_Debug("[OTATest] Download failed, error code: %d\r\n", info.eLastError); s_ota_test_ctx.state = OTA_TEST_STATE_FAILED; } } /** * @brief 检查解密状态 */ static void OTATest_CheckDecryptStatus(void) { E_OTAState ota_state = OTA_GetState(); HIDO_UINT8 progress = OTA_GetProgress(); // 进度变化时打印 if (progress != s_ota_test_ctx.last_progress && progress % 10 == 0) { HIDO_Debug("[OTATest] Decrypt progress: %u%%\r\n", progress); s_ota_test_ctx.last_progress = progress; } if (ota_state == OTA_STATE_DECRYPT_COMPLETE) { HIDO_Debug("[OTATest] Decryption completed! Starting verification...\r\n"); // 启动校验 if (OTA_VerifyFirmware() == HIDO_OK) { s_ota_test_ctx.state = OTA_TEST_STATE_VERIFYING; } else { HIDO_Debug("[OTATest] Failed to start verification\r\n"); s_ota_test_ctx.state = OTA_TEST_STATE_FAILED; } } else if (ota_state == OTA_STATE_DECRYPT_FAILED) { ST_OTAInfo info; OTA_GetInfo(&info); HIDO_Debug("[OTATest] Decryption failed, error code: %d\r\n", info.eLastError); s_ota_test_ctx.state = OTA_TEST_STATE_FAILED; } } /** * @brief 检查校验状态 */ static void OTATest_CheckVerifyStatus(void) { E_OTAState ota_state = OTA_GetState(); if (ota_state == OTA_STATE_VERIFY_SUCCESS) { ST_OTAInfo info; OTA_GetInfo(&info); HIDO_Debug("[OTATest] ===== Firmware Verification SUCCESS! =====\r\n"); HIDO_Debug("[OTATest] Firmware size: %u bytes (%.1f KB)\r\n", info.u32TotalSize, info.u32TotalSize / 1024.0f); HIDO_Debug("[OTATest] Encrypted firmware at: 0x%08X\r\n", OTA_ENCRYPTED_FLASH_ADDR); HIDO_Debug("[OTATest] Decrypted firmware at: 0x%08X\r\n", OTA_DECRYPTED_FLASH_ADDR); s_ota_test_ctx.state = OTA_TEST_STATE_COMPLETE; } else if (ota_state == OTA_STATE_VERIFY_FAILED) { ST_OTAInfo info; OTA_GetInfo(&info); HIDO_Debug("[OTATest] Firmware verification FAILED, error code: %d\r\n", info.eLastError); s_ota_test_ctx.state = OTA_TEST_STATE_FAILED; } } /** * @brief 手动触发OTA测试(可在Shell中调用) */ void OTATest_Trigger(void) { HIDO_Debug("[OTATest] Manual trigger - resetting test state\r\n"); OTA_Reset(); s_ota_test_ctx.state = OTA_TEST_STATE_WAIT_NETWORK; s_ota_test_ctx.tcp_connected_triggered = HIDO_FALSE; } /** * @brief 获取OTA测试状态 */ E_OTATestState OTATest_GetState(void) { return s_ota_test_ctx.state; }