From dd8a6e2ace2f2d3785c8fc19c983b48d280ca3ca Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AD=99=E6=98=A5=E9=98=B3?= Date: Fri, 26 Sep 2025 15:57:30 +0800 Subject: [PATCH] =?utf8?q?=E6=B7=BB=E5=8A=A0=E4=B8=B2=E5=8F=A3=E6=B5=8B?= =?utf8?q?=E8=AF=95=E5=8F=8A=E4=BC=98=E5=8C=96at=E6=8C=87=E4=BB=A4?= =?utf8?q?=E5=93=8D=E5=BA=94=E6=A3=80=E6=B5=8B=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- code/sdk/zhihui/ppp/example/ppp_at_cmd.c | 364 +++++++++++++++++++++++ code/sdk/zhihui/ppp/include/ppp_config.h | 2 +- code/sdk/zhihui/ppp/src/ppp_at_handler.c | 262 +++++++++++----- code/sdk/zhihui/utils/custom_utils.c | 2 +- 4 files changed, 556 insertions(+), 74 deletions(-) diff --git a/code/sdk/zhihui/ppp/example/ppp_at_cmd.c b/code/sdk/zhihui/ppp/example/ppp_at_cmd.c index 118f4aa9a..755842d1f 100644 --- a/code/sdk/zhihui/ppp/example/ppp_at_cmd.c +++ b/code/sdk/zhihui/ppp/example/ppp_at_cmd.c @@ -1984,6 +1984,366 @@ static errcode_t at_ppp_tcp_test_stats(uint8_t *para, uint32_t paraLen) #endif } +/* AT+DEMO串口循环测试相关定义和实现 */ +#define DEMO_TEST_CMD_MAX_LEN (1024*5) +#define DEMO_TEST_RESPONSE_MAX_LEN (1024*5) +#define DEMO_TEST_DEFAULT_INTERVAL_MS 20 +#define DEMO_TEST_DEFAULT_DURATION_SEC 60 + +/* AT+DEMO测试统计结构 */ +typedef struct { + uint32_t total_sent; // 总发送次数 + uint32_t total_received; // 总接收次数 + uint32_t total_errors; // 总错误次数 + uint32_t response_errors; // 响应错误次数 + uint32_t timeout_errors; // 超时错误次数 + uint32_t start_time; // 测试开始时间(ms) + uint32_t end_time; // 测试结束时间(ms) + bool is_running; // 测试是否正在运行 +} demo_test_stats_t; + +/* 全局测试统计变量 */ +static demo_test_stats_t g_demo_test_stats = {0}; +static bool g_demo_test_stop_flag = false; + +/** + * @brief 获取系统时间(毫秒) + */ +static uint32_t demo_test_get_time_ms(void) +{ + return osal_jiffies_to_msecs(osal_get_jiffies()); +} + +/** + * @brief 验证AT+DEMO响应是否正确 + * @param sent_cmd 发送的命令 + * @param response 接收的响应 + * @param response_len 响应长度 + * @return true=正确, false=错误 + */ +static bool demo_test_verify_response(const char *sent_cmd, const char *response, uint32_t response_len) +{ + if (!sent_cmd || !response || response_len == 0) { + return false; + } + + // 查找响应中是否包含发送的命令内容 + // 期望格式: AT+DEMO=\r\n\r\nOK\r\n + const char *demo_data = strstr(sent_cmd, "AT+DEMO="); + if (!demo_data) { + return false; + } + + demo_data += 8; // 跳过"AT+DEMO=" + + // 查找命令数据在响应中的位置 + const char *response_data = strstr(response, demo_data); + if (!response_data) { + ppp_print_err("DEMO TEST: Response data not found in response\n"); + return false; + } + + // 检查是否包含OK + if (!strstr(response, "OK")) { + ppp_print_err("DEMO TEST: OK not found in response\n"); + return false; + } + + return true; +} + +/** + * @brief AT+DEMO串口循环测试主函数 + * @param interval_ms 发送间隔(毫秒) + * @param duration_sec 测试时长(秒) + * @return ERRCODE_SUCC=成功, 其他=失败 + */ +static const char test_cmd[] = "AT+DEMO=0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; +static errcode_t demo_test_run_loop(uint32_t interval_ms, uint32_t duration_sec) +{ + // 构建测试命令 - 使用动态内存分配避免栈溢出 + + char *response = malloc(DEMO_TEST_RESPONSE_MAX_LEN); + if (!response) { + ppp_print_err("DEMO TEST: Failed to allocate memory for response buffer\n"); + return ERRCODE_FAIL; + } + + uint32_t response_len; + uint32_t test_end_time = g_demo_test_stats.start_time + (duration_sec * 1000); + + ppp_print_info("DEMO TEST: Starting loop test...\n"); + ppp_print_info("DEMO TEST: Command length: %d bytes\n", strlen(test_cmd)); + ppp_print_info("DEMO TEST: Interval: %d ms, Duration: %d seconds\n", interval_ms, duration_sec); + memset(response, 0, DEMO_TEST_RESPONSE_MAX_LEN); + errcode_t ret = ppp_execute_at_command("ATE0", response, DEMO_TEST_RESPONSE_MAX_LEN, &response_len, 5000); + if (ret != ERRCODE_SUCC) { + ppp_print_err("DEMO TEST: Failed to execute AT+DEMO command\n"); + return ret; + } + ppp_print_info("DEMO TEST: ATE0 command executed successfully %s\n", response); + + while (!g_demo_test_stop_flag && demo_test_get_time_ms() < test_end_time) { + uint32_t loop_start_time = demo_test_get_time_ms(); + + memset(response, 0, DEMO_TEST_RESPONSE_MAX_LEN); + // 发送AT+DEMO命令 + errcode_t ret = ppp_execute_at_command(test_cmd, response, DEMO_TEST_RESPONSE_MAX_LEN, &response_len, 5000); + g_demo_test_stats.total_sent++; + + if (ret == ERRCODE_SUCC) { + g_demo_test_stats.total_received++; + + // 验证响应内容 + if (demo_test_verify_response(test_cmd, response, response_len)) { + // 响应正确,无需额外处理 + } else { + g_demo_test_stats.response_errors++; + g_demo_test_stats.total_errors++; + ppp_print_warning("DEMO TEST: Response verification failed (sent: %d)\n", g_demo_test_stats.total_sent); + } + } else { + g_demo_test_stats.total_errors++; + // 检查是否为超时错误 - 简化错误处理,所有非成功都视为错误 + g_demo_test_stats.timeout_errors++; + ppp_print_warning("DEMO TEST: Command failed with error 0x%x (sent: %d)\n", ret, g_demo_test_stats.total_sent); + } + + // 每100次循环打印一次进度 + if (g_demo_test_stats.total_sent % 100 == 0) { + uint32_t elapsed_sec = (demo_test_get_time_ms() - g_demo_test_stats.start_time) / 1000; + ppp_print_info("DEMO TEST: Progress - Sent: %d, Received: %d, Errors: %d, Elapsed: %d sec\n", + g_demo_test_stats.total_sent, g_demo_test_stats.total_received, + g_demo_test_stats.total_errors, elapsed_sec); + } + + // 计算需要等待的时间 + uint32_t loop_duration = demo_test_get_time_ms() - loop_start_time; + if (loop_duration < interval_ms) { + osal_msleep(interval_ms - loop_duration); + } + } + + g_demo_test_stats.end_time = demo_test_get_time_ms(); + g_demo_test_stats.is_running = false; + + // 释放动态分配的内存 + free(response); + + return ERRCODE_SUCC; +} + +/** + * @brief AT^DEMOTEST - AT+DEMO串口循环测试 + * @param para 参数: [间隔ms],[测试时长秒],[波特率] + * @param paraLen 参数长度 + */ +static errcode_t at_demo_serial_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(strCommonCmd); + + uint32_t interval_ms = DEMO_TEST_DEFAULT_INTERVAL_MS; + uint32_t duration_sec = DEMO_TEST_DEFAULT_DURATION_SEC; + uint32_t baudrate = 0; // 0表示不改变波特率 + uint32_t original_baudrate = 0; // 保存原始波特率 + + // 解析参数 + if (para && paraLen > 0) { + uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN] = { 0 }; + uint32_t argc = 0; + + int ret = ConvertCmdToParam(para, paraLen, argv, &argc); + if (ret == CUSTOM_UTILS_SUCCESS) { + if (argc >= 1) { + interval_ms = atoi((char*)argv[0]); + if (interval_ms < 10 || interval_ms > 10000) { + ppp_print_err("DEMO TEST: Invalid interval %d ms (must be 10-10000)\n", interval_ms); + return ERRCODE_FAIL; + } + } + if (argc >= 2) { + duration_sec = atoi((char*)argv[1]); + if (duration_sec < 1 || duration_sec > 3600) { + ppp_print_err("DEMO TEST: Invalid duration %d sec (must be 1-3600)\n", duration_sec); + return ERRCODE_FAIL; + } + } + if (argc >= 3) { + baudrate = atoi((char*)argv[2]); + // 如果用户明确输入了0,表示不改变波特率 + if (baudrate == 0) { + ppp_print_info("DEMO TEST: Baudrate parameter is 0, will not change baudrate\n"); + } + // 检查波特率是否为支持的值 + else if (baudrate != 9600 && baudrate != 19200 && + baudrate != 38400 && baudrate != 57600 && baudrate != 115200 && + baudrate != 230400 && baudrate != 460800 && baudrate != 921600) { + ppp_print_err("DEMO TEST: Invalid baudrate %d (supported: 0,9600,19200,38400,57600,115200,230400,460800,921600)\n", baudrate); + ppp_print_err("DEMO TEST: Use 0 to keep current baudrate unchanged\n"); + return ERRCODE_FAIL; + } + } + } + } + + // 检查是否已有测试在运行 + if (g_demo_test_stats.is_running) { + ppp_print_err("DEMO TEST: Test already running. Use AT^DEMOSTOP to stop first.\n"); + return ERRCODE_FAIL; + } + + // 如果指定了波特率,先保存当前波特率并设置新波特率 + if (baudrate != 0) { + original_baudrate = ppp_at_get_current_baudrate(); + ppp_print_info("DEMO TEST: Current baudrate: %d, changing to: %d\n", original_baudrate, baudrate); + + ppp_error_t ppp_ret = ppp_at_set_baudrate(baudrate); + if (ppp_ret != PPP_ERR_OK) { + ppp_print_err("DEMO TEST: Failed to set baudrate to %d, error: %d\n", baudrate, ppp_ret); + return ERRCODE_FAIL; + } + + ppp_print_info("DEMO TEST: Baudrate changed successfully to %d\n", baudrate); + + // 等待一段时间让波特率设置生效 + osal_msleep(500); + } + + // 初始化测试统计 + memset(&g_demo_test_stats, 0, sizeof(g_demo_test_stats)); + g_demo_test_stats.is_running = true; + g_demo_test_stats.start_time = demo_test_get_time_ms(); + g_demo_test_stop_flag = false; + + ppp_print_info("DEMO TEST: Starting AT+DEMO serial loop test\n"); + if (baudrate != 0) { + ppp_print_info("DEMO TEST: Parameters - Interval: %d ms, Duration: %d seconds, Baudrate: %d\n", + interval_ms, duration_sec, baudrate); + } else { + ppp_print_info("DEMO TEST: Parameters - Interval: %d ms, Duration: %d seconds\n", interval_ms, duration_sec); + } + + // 运行测试 + errcode_t ret = demo_test_run_loop(interval_ms, duration_sec); + + // 打印测试结果 + uint32_t total_time_ms = g_demo_test_stats.end_time - g_demo_test_stats.start_time; + uint32_t total_time_sec = total_time_ms / 1000; + + ppp_print_info("\n=== DEMO TEST Results ===\n"); + ppp_print_info("Test Duration: %d seconds (%d ms)\n", total_time_sec, total_time_ms); + ppp_print_info("Total Sent: %d\n", g_demo_test_stats.total_sent); + ppp_print_info("Total Received: %d\n", g_demo_test_stats.total_received); + ppp_print_info("Total Errors: %d\n", g_demo_test_stats.total_errors); + ppp_print_info("Response Errors: %d\n", g_demo_test_stats.response_errors); + ppp_print_info("Timeout Errors: %d\n", g_demo_test_stats.timeout_errors); + + if (g_demo_test_stats.total_sent > 0) { + float success_rate = (float)g_demo_test_stats.total_received / g_demo_test_stats.total_sent * 100.0f; + float error_rate = (float)g_demo_test_stats.total_errors / g_demo_test_stats.total_sent * 100.0f; + ppp_print_info("Success Rate: %.2f%%\n", success_rate); + ppp_print_info("Error Rate: %.2f%%\n", error_rate); + + if (total_time_sec > 0) { + float avg_rate = (float)g_demo_test_stats.total_sent / total_time_sec; + ppp_print_info("Average Rate: %.2f commands/sec\n", avg_rate); + } + } + + ppp_print_info("========================\n"); + + // 如果修改了波特率,恢复原始波特率 + if (baudrate != 0 && original_baudrate != 0) { + ppp_print_info("DEMO TEST: Restoring original baudrate: %d\n", original_baudrate); + ppp_error_t ppp_ret = ppp_at_set_baudrate(original_baudrate); + if (ppp_ret != PPP_ERR_OK) { + ppp_print_err("DEMO TEST: Failed to restore original baudrate %d, error: %d\n", original_baudrate, ppp_ret); + } else { + ppp_print_info("DEMO TEST: Baudrate restored successfully to %d\n", original_baudrate); + } + } + + return ret; +} + +/** + * @brief AT^DEMOSTOP - 停止AT+DEMO串口测试 + */ +static errcode_t at_demo_test_stop(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(para); + UNUSED(paraLen); + UNUSED(strCommonCmd); + + if (!g_demo_test_stats.is_running) { + ppp_print_info("DEMO TEST: No test is currently running\n"); + return ERRCODE_SUCC; + } + + ppp_print_info("DEMO TEST: Stopping test...\n"); + g_demo_test_stop_flag = true; + + // 等待测试循环结束 + int wait_count = 0; + while (g_demo_test_stats.is_running && wait_count < 50) { + osal_msleep(100); + wait_count++; + } + + if (g_demo_test_stats.is_running) { + ppp_print_warning("DEMO TEST: Force stop (test loop may still be running)\n"); + g_demo_test_stats.is_running = false; + } else { + ppp_print_info("DEMO TEST: Test stopped successfully\n"); + } + + return ERRCODE_SUCC; +} + +/** + * @brief AT^DEMOSTATS - 获取AT+DEMO测试统计信息 + */ +static errcode_t at_demo_test_stats(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(para); + UNUSED(paraLen); + UNUSED(strCommonCmd); + + ppp_print_info("=== DEMO TEST Statistics ===\n"); + ppp_print_info("Test Status: %s\n", g_demo_test_stats.is_running ? "RUNNING" : "STOPPED"); + + if (g_demo_test_stats.start_time > 0) { + uint32_t current_time = demo_test_get_time_ms(); + uint32_t elapsed_ms = (g_demo_test_stats.is_running ? current_time : g_demo_test_stats.end_time) - g_demo_test_stats.start_time; + uint32_t elapsed_sec = elapsed_ms / 1000; + + ppp_print_info("Elapsed Time: %d seconds (%d ms)\n", elapsed_sec, elapsed_ms); + ppp_print_info("Total Sent: %d\n", g_demo_test_stats.total_sent); + ppp_print_info("Total Received: %d\n", g_demo_test_stats.total_received); + ppp_print_info("Total Errors: %d\n", g_demo_test_stats.total_errors); + ppp_print_info("Response Errors: %d\n", g_demo_test_stats.response_errors); + ppp_print_info("Timeout Errors: %d\n", g_demo_test_stats.timeout_errors); + + if (g_demo_test_stats.total_sent > 0) { + float success_rate = (float)g_demo_test_stats.total_received / g_demo_test_stats.total_sent * 100.0f; + float error_rate = (float)g_demo_test_stats.total_errors / g_demo_test_stats.total_sent * 100.0f; + ppp_print_info("Success Rate: %.2f%%\n", success_rate); + ppp_print_info("Error Rate: %.2f%%\n", error_rate); + + if (elapsed_sec > 0) { + float avg_rate = (float)g_demo_test_stats.total_sent / elapsed_sec; + ppp_print_info("Average Rate: %.2f commands/sec\n", avg_rate); + } + } + } else { + ppp_print_info("No test has been run yet\n"); + } + + ppp_print_info("============================\n"); + + return ERRCODE_SUCC; +} + static const at_cmd_table_t g_ppp_cmd[] = { { (char *)"AT^CAT1POWER", cat1_power, (char *)"1" }, { (char *)"AT^CAT1GETSIGNAL", at_cat1_getsignal, (char *)"1" }, @@ -2040,6 +2400,10 @@ static const at_cmd_table_t g_ppp_cmd[] = { { (char *)"AT^PPPTCPPERF", at_ppp_tcp_performance_test, (char *)"host,port,connections,time" }, { (char *)"AT^PPPTCPSTOP", at_ppp_tcp_test_stop, (char *)" " }, { (char *)"AT^PPPTCPSTATS", at_ppp_tcp_test_stats, (char *)" " }, + /* AT+DEMO串口循环测试指令 */ + { (char *)"AT^DEMOTEST", at_demo_serial_test, (char *)"[interval_ms],[duration_sec],[baudrate]" }, + { (char *)"AT^DEMOSTOP", at_demo_test_stop, (char *)" " }, + { (char *)"AT^DEMOSTATS", at_demo_test_stats, (char *)" " }, }; at_cmd_table_t *get_ppp_cmd_table(uint32_t *cmd_count) diff --git a/code/sdk/zhihui/ppp/include/ppp_config.h b/code/sdk/zhihui/ppp/include/ppp_config.h index d4c15cf66..77e972c54 100644 --- a/code/sdk/zhihui/ppp/include/ppp_config.h +++ b/code/sdk/zhihui/ppp/include/ppp_config.h @@ -27,7 +27,7 @@ extern "C" { #define SIO_UART_IRQ_NUM UART_0_IRQN // UART IRQ引脚 #endif -#define PPP_UART_BAUDRATE 115200 +#define PPP_UART_BAUDRATE 2000000 /* 支持的波特率列表(自适应模式) */ #define PPP_BAUDRATE_AUTO_LIST {9600, 57600, 115200} diff --git a/code/sdk/zhihui/ppp/src/ppp_at_handler.c b/code/sdk/zhihui/ppp/src/ppp_at_handler.c index d0fffdb05..8a609e286 100644 --- a/code/sdk/zhihui/ppp/src/ppp_at_handler.c +++ b/code/sdk/zhihui/ppp/src/ppp_at_handler.c @@ -156,6 +156,7 @@ ppp_error_t ppp_at_baudrate_handshake(void) // 在当前波特率下,设置AT+IPR=1000000 ppp_at_set_baudrate(PPP_UART_BAUDRATE); + ppp_at_set_baudrate(PPP_UART_BAUDRATE); // 再次reset模组,让其自动工作在1000000波特率下 PPP_DEBUG_DEBUG("Resetting module again to switch to baudrate %d...",PPP_UART_BAUDRATE); @@ -182,6 +183,77 @@ ppp_error_t ppp_at_baudrate_handshake(void) return PPP_ERR_AT_FAILED; } +/** + * @brief 解析AT+IPR?响应,提取当前波特率 + * @param response AT+IPR?的响应字符串 + * @return 解析出的波特率,失败返回0 + */ +static uint32_t ppp_parse_ipr_response(const char *response) +{ + if (!response) { + return 0; + } + + PPP_DEBUG_DEBUG("Parsing IPR response: [%s]", response); + + /* 查找 "+IPR: " 字符串 */ + const char *ipr_pos = strstr(response, "+IPR: "); + if (!ipr_pos) { + PPP_DEBUG_WARN("IPR response format error: no '+IPR: ' found in response"); + return 0; + } + + /* 跳过 "+IPR: " 部分 */ + ipr_pos += 6; + + /* 跳过可能的空格 */ + while (*ipr_pos == ' ' || *ipr_pos == '\t') { + ipr_pos++; + } + + /* 解析波特率数字,只读取数字部分 */ + uint32_t baudrate = 0; + const char *num_start = ipr_pos; + + /* 找到数字的结束位置(遇到非数字字符停止) */ + while (*ipr_pos >= '0' && *ipr_pos <= '9') { + baudrate = baudrate * 10 + (*ipr_pos - '0'); + ipr_pos++; + } + + /* 检查是否成功解析到数字 */ + if (ipr_pos == num_start) { + PPP_DEBUG_WARN("IPR response format error: no valid number found after '+IPR: '"); + return 0; + } + + /* 验证波特率是否合理 */ + if (baudrate < 1200 || baudrate > 4000000) { + PPP_DEBUG_WARN("IPR response contains unreasonable baudrate: %u", baudrate); + return 0; + } + + PPP_DEBUG_DEBUG("Successfully parsed current baudrate from IPR response: %u", baudrate); + return baudrate; +} + +/** + * @brief 查询当前modem波特率 + * @return 当前modem波特率,失败返回0 + */ +static uint32_t ppp_query_current_modem_baudrate(void) +{ + ppp_at_response_t response; + ppp_error_t ret = ppp_at_send_command("AT+IPR?", "OK", PPP_AT_CMD_TIMEOUT, &response); + + if (ret != PPP_ERR_OK) { + PPP_DEBUG_WARN("Failed to query current baudrate with AT+IPR?, error: %d", ret); + return 0; + } + + return ppp_parse_ipr_response(response.response); +} + /** * @brief 设置固定波特率 */ @@ -205,6 +277,34 @@ ppp_error_t ppp_at_set_baudrate(uint32_t baudrate) return PPP_ERR_INVALID_PARAM; } + /* 先查询当前modem波特率 */ + uint32_t current_modem_baudrate = ppp_query_current_modem_baudrate(); + if (current_modem_baudrate == baudrate) { + PPP_DEBUG_INFO("Modem already at target baudrate %u, skipping AT+IPR command", baudrate); + + /* 仍需要更新本地UART配置以确保一致性 */ + uart_attr_t uart_attr = { + .baud_rate = baudrate, + .data_bits = UART_DATA_BIT_8, + .parity = UART_PARITY_NONE, + .stop_bits = UART_STOP_BIT_1, + }; + + if (uapi_uart_set_attr(g_at_ctx.uart_bus, &uart_attr) != ERRCODE_SUCC) { + PPP_DEBUG_ERROR("Failed to update UART baudrate"); + return PPP_ERR_UART; + } + + g_at_ctx.current_baudrate = baudrate; + g_at_ctx.auto_baudrate_mode = false; + + PPP_DEBUG_DEBUG("Baudrate confirmed at %u (no change needed)", baudrate); + return PPP_ERR_OK; + } + + /* 需要设置新波特率 */ + PPP_DEBUG_INFO("Changing modem baudrate from %u to %u", current_modem_baudrate, baudrate); + /* 发送AT+IPR命令设置波特率 */ char cmd[64]; snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1, "AT+IPR=%u", baudrate); @@ -233,24 +333,25 @@ ppp_error_t ppp_at_set_baudrate(uint32_t baudrate) g_at_ctx.current_baudrate = baudrate; g_at_ctx.auto_baudrate_mode = false; - PPP_DEBUG_DEBUG("Baudrate set bus(%d) to %u (fixed)",g_at_ctx.uart_bus, baudrate); + PPP_DEBUG_DEBUG("Baudrate set bus(%d) to %u (changed from %u)", g_at_ctx.uart_bus, baudrate, current_modem_baudrate); return PPP_ERR_OK; } /** * @brief 发送AT命令 + * @note 检查内存泄露:所有malloc分配的内存都应在所有分支free */ ppp_error_t ppp_at_send_command(const char *command, const char *expected_response, uint32_t timeout, ppp_at_response_t *response) { uint32_t start_timestamp = (uint32_t)osal_get_jiffies(); - + PPP_DEBUG_CRITICAL("=== AT COMMAND START ==="); PPP_DEBUG_CRITICAL("Timestamp: %u", start_timestamp); PPP_DEBUG_CRITICAL("Command: [%s]", command ? command : "NULL"); PPP_DEBUG_CRITICAL("Expected: [%s]", expected_response ? expected_response : "NULL"); PPP_DEBUG_CRITICAL("Timeout: %u ms", timeout); - + if (!g_at_ctx.initialized || !command || !response) { PPP_DEBUG_ERROR("Invalid parameters: initialized=%d, command=%p, response=%p", g_at_ctx.initialized, command, response); @@ -267,7 +368,7 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon PPP_DEBUG_CRITICAL("Step 1: Attempting to acquire AT mutex..."); uint32_t mutex_start = (uint32_t)osal_get_jiffies(); - + /* 使用带超时的互斥锁获取,防止永久阻塞 */ int mutex_result = osal_mutex_lock_timeout(&g_at_ctx.at_mutex, timeout + 5000); if (mutex_result != OSAL_SUCCESS) { @@ -275,7 +376,7 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon PPP_DEBUG_ERROR("Possible causes: 1) Previous AT command hung 2) Mutex corruption 3) Deadlock"); return PPP_ERR_TIMEOUT; } - + uint32_t mutex_end = (uint32_t)osal_get_jiffies(); PPP_DEBUG_CRITICAL("Step 1: AT mutex acquired in %u ms", osal_jiffies_to_msecs(mutex_end - mutex_start)); @@ -288,26 +389,26 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon memset_s(response, sizeof(ppp_at_response_t), 0, sizeof(ppp_at_response_t)); /* 发送命令 */ - char cmd_with_crlf[PPP_AT_CMD_MAX_LEN + 4]; - snprintf_s(cmd_with_crlf, sizeof(cmd_with_crlf), sizeof(cmd_with_crlf) - 1, "%s\r\n", command); - + size_t command_len = strlen(command); + char *cmd_with_crlf = (char *)malloc(command_len + 4); + if (!cmd_with_crlf) { + PPP_DEBUG_ERROR("Failed to allocate memory for cmd_with_crlf"); + osal_mutex_unlock(&g_at_ctx.at_mutex); + return PPP_ERR_MEMORY; + } + snprintf_s(cmd_with_crlf, command_len + 4, command_len + 3, "%s\r\n", command); + uint32_t cmd_len = strlen(cmd_with_crlf); - - /* 打印发送的原始数据(十六进制) */ - // PPP_DEBUG_INFO("Sending %u bytes:", cmd_len); - // for (uint32_t i = 0; i < cmd_len; i++) { - // PPP_DEBUG_PRINT("%02X ", (uint8_t)cmd_with_crlf[i]); - // } - // PPP_DEBUG_PRINT("\n"); - + /* 打印发送的字符串(可见字符) */ char *printable_cmd = (char *)malloc(PPP_AT_CMD_MAX_LEN + 20); if (printable_cmd == NULL) { PPP_DEBUG_ERROR("Failed to allocate memory for printable command"); + free(cmd_with_crlf); // 防止内存泄露 osal_mutex_unlock(&g_at_ctx.at_mutex); return PPP_ERR_MEMORY; } - + uint32_t j = 0; for (uint32_t i = 0; i < cmd_len && j < (PPP_AT_CMD_MAX_LEN + 20) - 10; i++) { if (cmd_with_crlf[i] == '\r') { @@ -325,22 +426,24 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon printable_cmd[j] = '\0'; PPP_DEBUG_DEBUG("Send String: %s", printable_cmd); free(printable_cmd); - + PPP_DEBUG_CRITICAL("Step 2: Sending AT command via UART..."); uint32_t uart_write_start = (uint32_t)osal_get_jiffies(); - + int32_t write_result = uapi_uart_write(g_at_ctx.uart_bus, (const uint8_t *)cmd_with_crlf, cmd_len, 0); uint32_t uart_write_end = (uint32_t)osal_get_jiffies(); - + + free(cmd_with_crlf); + PPP_DEBUG_CRITICAL("Step 2: UART write completed in %u ms, result: %d (expected: %u)", osal_jiffies_to_msecs(uart_write_end - uart_write_start), write_result, cmd_len); - + if (write_result != cmd_len) { PPP_DEBUG_ERROR("Failed to send AT command: wrote %d bytes, expected %u", write_result, cmd_len); osal_mutex_unlock(&g_at_ctx.at_mutex); return PPP_ERR_UART; } - + PPP_DEBUG_CRITICAL("Step 2: AT command sent successfully on bus %d", g_at_ctx.uart_bus); /* 等待响应 */ @@ -350,19 +453,12 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon uint32_t response_wait_end = (uint32_t)osal_get_jiffies(); PPP_DEBUG_CRITICAL("Step 3: AT response wait completed in %u ms, result: %d", osal_jiffies_to_msecs(response_wait_end - response_wait_start), ret); - + /* 打印响应结果 */ PPP_DEBUG_DEBUG("=== AT Command Response ==="); if (ret == PPP_ERR_OK) { PPP_DEBUG_DEBUG("Response received (%u bytes):", response->length); - - /* 打印接收的原始数据(十六进制) */ - // for (uint32_t i = 0; i < response->length; i++) { - // PPP_DEBUG_PRINT("%02X ", (uint8_t)response->response[i]); - // if ((i + 1) % 16 == 0) PPP_DEBUG_PRINT("\n"); - // } - // if (response->length % 16 != 0) PPP_DEBUG_PRINT("\n"); - + /* 打印接收的字符串(可见字符) */ char *printable_resp = (char *)malloc(PPP_AT_RESPONSE_MAX_LEN + 100); if (printable_resp != NULL) { @@ -388,7 +484,7 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon } else { PPP_DEBUG_ERROR("No response received (error: %d)", ret); } - + if (ret == PPP_ERR_OK) { if (expected_response) { if (!ppp_at_parse_response(response->response, expected_response)) { @@ -411,18 +507,18 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon response->success = false; response->error_code = ret; } - + PPP_DEBUG_DEBUG("=== AT Command Complete (Result: %s) ===", ret == PPP_ERR_OK ? "SUCCESS" : "FAILED"); PPP_DEBUG_CRITICAL("Step 4: Releasing AT mutex..."); uint32_t mutex_unlock_start = (uint32_t)osal_get_jiffies(); osal_mutex_unlock(&g_at_ctx.at_mutex); uint32_t mutex_unlock_end = (uint32_t)osal_get_jiffies(); - + uint32_t total_time = osal_jiffies_to_msecs(mutex_unlock_end - start_timestamp); PPP_DEBUG_CRITICAL("Step 4: AT mutex released in %u ms", osal_jiffies_to_msecs(mutex_unlock_end - mutex_unlock_start)); PPP_DEBUG_CRITICAL("=== AT COMMAND END (Total: %u ms, Result: %d) ===", total_time, ret); - + return ret; } @@ -753,18 +849,20 @@ static bool ppp_at_check_response_complete(const char *buffer, uint32_t length) return false; } - /* 搜索OK终止符 */ - for (uint32_t i = 0; i <= length - 2; i++) { - if (buffer[i] == 'O' && buffer[i+1] == 'K') { - /* 检查OK前面是否有换行符(避免误匹配) */ - if (i == 0 || buffer[i-1] == '\n' || buffer[i-1] == '\r') { - PPP_DEBUG_DEBUG("Found OK terminator at position %u", i); - return true; + /* 搜索OK终止符 - 修复无符号整数下溢问题 */ + if (length >= 2) { + for (uint32_t i = 0; i <= length - 2; i++) { + if (buffer[i] == 'O' && buffer[i+1] == 'K') { + /* 检查OK前面是否有换行符(避免误匹配) */ + if (i == 0 || buffer[i-1] == '\n' || buffer[i-1] == '\r') { + PPP_DEBUG_DEBUG("Found OK terminator at position %u", i); + return true; + } } } } - /* 搜索ERROR终止符 */ + /* 搜索ERROR终止符 - 已经有长度检查,但确保安全 */ if (length >= 5) { for (uint32_t i = 0; i <= length - 5; i++) { if (strncmp(&buffer[i], "ERROR", 5) == 0) { @@ -800,6 +898,12 @@ static bool ppp_at_parse_response(const char *response, const char *expected) return false; } + + // 检查期望响应 ,优先检测期望响应 + if (expected && strstr(response, expected)) { + return true; + } + // 检查ABORT条件 (对应chat文件中的ABORT指令) if (strstr(response, "BUSY") || strstr(response, "ERROR") || @@ -808,10 +912,7 @@ static bool ppp_at_parse_response(const char *response, const char *expected) return false; } - // 检查期望响应 - if (expected && strstr(response, expected)) { - return true; - } + return false; } @@ -819,7 +920,7 @@ static bool ppp_at_parse_response(const char *response, const char *expected) /** * @brief 等待AT命令响应 - 新的直接读取实现(取消timer检测) */ -static ppp_error_t ppp_at_wait_response(ppp_at_response_t *response, uint32_t timeout) +static ppp_error_t ppp_at_wait_response(ppp_at_response_t *response, uint32_t timeout) { PPP_DEBUG_CRITICAL(">>> WAIT_RESPONSE START <<<"); @@ -851,8 +952,8 @@ static ppp_error_t ppp_at_wait_response(ppp_at_response_t *response, uint32_t ti uint32_t current_time = (uint32_t)osal_get_jiffies(); uint32_t elapsed = osal_jiffies_to_msecs(current_time - start_time); - /* 每10次尝试打印一次状态 */ - if (read_attempts % 10 == 1) { + /* 减少状态打印频率以节省栈空间 */ + if (read_attempts % 50 == 1) { // 从每10次改为每50次 PPP_DEBUG_CRITICAL("WAIT_RESPONSE: Attempt #%u, elapsed: %u ms, has_data: %d, bytes_received: %u", read_attempts, elapsed, has_data, bytes_received); } @@ -914,18 +1015,29 @@ static ppp_error_t ppp_at_wait_response(ppp_at_response_t *response, uint32_t ti break; } - g_at_response_buffer[bytes_received] = '\0'; + /* 安全地设置字符串结束符 */ + if (bytes_received < g_at_buffer_size) { + g_at_response_buffer[bytes_received] = '\0'; + } PPP_DEBUG_CRITICAL("WAIT_RESPONSE: Read %d bytes, total: %u bytes", ret, bytes_received); - PPP_DEBUG_CRITICAL("WAIT_RESPONSE: Current buffer content: [%s]", (char*)g_at_response_buffer); - /* 打印接收到的原始数据(十六进制) */ - PPP_DEBUG_DEBUG("WAIT_RESPONSE: Raw data received:"); - for (int i = bytes_received - ret; i < (int)bytes_received; i++) { - PPP_DEBUG_PRINT("%02X ", g_at_response_buffer[i]); - if ((i + 1) % 16 == 0) PPP_DEBUG_PRINT("\n"); + /* 减少调试输出以节省栈空间 */ + /* PPP_DEBUG_CRITICAL("WAIT_RESPONSE: Buffer length: %u", bytes_received); */ + + /* 安全地打印接收到的原始数据(十六进制) - 避免栈溢出 */ + if (ret > 0 && bytes_received >= (uint32_t)ret && ret <= 64) { // 限制最大打印长度 + PPP_DEBUG_DEBUG("WAIT_RESPONSE: New raw data received (%d bytes)", ret); + /* 为了避免栈溢出,简化十六进制打印或完全跳过 */ + /* 在调试时可以临时启用,正常运行时建议注释掉 */ + #ifdef PPP_DEBUG_VERBOSE_HEX + uint32_t start_idx = bytes_received - (uint32_t)ret; + for (uint32_t i = 0; i < (uint32_t)ret && (start_idx + i) < g_at_buffer_size && i < 16; i++) { + PPP_DEBUG_PRINT("%02X ", g_at_response_buffer[start_idx + i]); + } + PPP_DEBUG_PRINT("\n"); + #endif } - if (ret % 16 != 0) PPP_DEBUG_PRINT("\n"); /* 检查是否收到完整响应 */ if (ppp_at_check_response_complete((char*)g_at_response_buffer, bytes_received)) { @@ -933,8 +1045,9 @@ static ppp_error_t ppp_at_wait_response(ppp_at_response_t *response, uint32_t ti response_complete = true; } - /* 重置超时计时器,因为我们收到了数据 */ - start_time = current_time; + /* 不要重置超时计时器!这会导致系统在收到垃圾数据时无限等待 */ + /* 注释掉这行代码以防止超时重置导致的系统挂死 */ + /* start_time = current_time; */ } else if (ret == 0) { /* 没有数据,继续等待 */ @@ -951,19 +1064,24 @@ static ppp_error_t ppp_at_wait_response(ppp_at_response_t *response, uint32_t ti osal_msleep(50); } - /* 检查是否收到了足够的数据但没有完整响应标志 */ + /* 额外的安全检查:防止系统在收到垃圾数据后挂死 */ if (has_data && bytes_received > 0) { - /* 如果收到数据但等待时间过长,可能需要强制结束 */ - uint32_t data_wait_time = osal_jiffies_to_msecs(current_time - start_time); - if (data_wait_time > 1000) { // 收到数据后等待1秒仍无完整响应 - PPP_DEBUG_WARN("WAIT_RESPONSE: Long wait after receiving data (%u ms), checking for partial response", - data_wait_time); - - /* 检查是否至少包含一些有用的响应内容 */ - if (bytes_received >= 2) { // 至少有一些内容 - PPP_DEBUG_WARN("WAIT_RESPONSE: Accepting partial response to prevent hang"); - response_complete = true; - } + /* 如果收到数据但等待时间过长,强制结束以防止挂死 */ + uint32_t total_elapsed = osal_jiffies_to_msecs(current_time - start_time); + + /* 如果总等待时间超过2秒且有数据,强制结束 */ + if (total_elapsed > 2000) { + PPP_DEBUG_WARN("WAIT_RESPONSE: SAFETY EXIT - Total elapsed time %u ms with %u bytes data", + total_elapsed, bytes_received); + PPP_DEBUG_WARN("WAIT_RESPONSE: Forcing exit to prevent system hang"); + response_complete = true; + } + /* 如果收到少量数据(可能是垃圾数据)且等待超过500ms,也强制结束 */ + else if (bytes_received <= 5 && total_elapsed > 500) { + PPP_DEBUG_WARN("WAIT_RESPONSE: GARBAGE DATA PROTECTION - Only %u bytes in %u ms, likely garbage", + bytes_received, total_elapsed); + PPP_DEBUG_WARN("WAIT_RESPONSE: Forcing exit to prevent infinite wait on garbage data"); + response_complete = true; } } } diff --git a/code/sdk/zhihui/utils/custom_utils.c b/code/sdk/zhihui/utils/custom_utils.c index c1eb85d1e..b7379566f 100644 --- a/code/sdk/zhihui/utils/custom_utils.c +++ b/code/sdk/zhihui/utils/custom_utils.c @@ -832,7 +832,7 @@ void startup_post_init(void) taskcfg.create_queue_handle = NULL; taskcfg.attr.name="startup_post_init_task"; taskcfg.attr.priority = osPriorityNormal; - taskcfg.attr.stack_size = 0x1100; + taskcfg.attr.stack_size = 0x2000; // 增加栈大小从4KB到8KB以支持PPP调试 taskcfg.func = startup_post_init_task; taskcfg.use_mem = USE_EXTEND_MEM; -- 2.17.1