添加串口测试及优化at指令响应检测函数
author孙春阳 <snickersun@163.com>
Fri, 26 Sep 2025 07:57:30 +0000 (15:57 +0800)
committer孙春阳 <snickersun@163.com>
Fri, 26 Sep 2025 07:57:30 +0000 (15:57 +0800)
code/sdk/zhihui/ppp/example/ppp_at_cmd.c
code/sdk/zhihui/ppp/include/ppp_config.h
code/sdk/zhihui/ppp/src/ppp_at_handler.c
code/sdk/zhihui/utils/custom_utils.c

index 118f4aa..755842d 100644 (file)
@@ -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=<data>\r\n<data>\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)
index d4c15cf..77e972c 100644 (file)
@@ -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}
index d0fffdb..8a609e2 100644 (file)
@@ -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;
             }
         }
     }
index c1eb85d..b737956 100644 (file)
@@ -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;