/*****************************************************************************
|
* @file PathTest.c
|
* @brief 路径下载和读取测试模块
|
* @author AI Assistant
|
* @date 2025-12-19
|
*****************************************************************************/
|
|
#include "PathTest.h"
|
#include "PathStorage.h"
|
#include "TCPClient.h"
|
#include "HIDO_Debug.h"
|
#include "HIDO_Timer.h"
|
#include <string.h>
|
|
/*****************************************************************************
|
* 私有宏定义
|
*****************************************************************************/
|
#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;
|
}
|