#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" },
{ (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)
#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}
// 在当前波特率下,设置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);
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 设置固定波特率
*/
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);
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);
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) {
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));
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') {
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);
/* 等待响应 */
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) {
} 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)) {
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;
}
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) {
return false;
}
+
+ // 检查期望响应 ,优先检测期望响应
+ if (expected && strstr(response, expected)) {
+ return true;
+ }
+
// 检查ABORT条件 (对应chat文件中的ABORT指令)
if (strstr(response, "BUSY") ||
strstr(response, "ERROR") ||
return false;
}
- // 检查期望响应
- if (expected && strstr(response, expected)) {
- return true;
- }
+
return false;
}
/**
* @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 <<<");
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);
}
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)) {
response_complete = true;
}
- /* 重置超时计时器,因为我们收到了数据 */
- start_time = current_time;
+ /* 不要重置超时计时器!这会导致系统在收到垃圾数据时无限等待 */
+ /* 注释掉这行代码以防止超时重置导致的系统挂死 */
+ /* start_time = current_time; */
} else if (ret == 0) {
/* 没有数据,继续等待 */
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;
}
}
}
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;