添加 ppp 串口测试功能,检验串口读的性能,目前看来中断模式效果最好。但是1M的情况下,还是会有丢数据的情况出现。
author孙春阳 <snickersun@163.com>
Fri, 10 Oct 2025 01:15:50 +0000 (09:15 +0800)
committer孙春阳 <snickersun@163.com>
Fri, 10 Oct 2025 01:15:50 +0000 (09:15 +0800)
15 files changed:
code/sdk/drivers/chips/brandy/porting/uart/uart_porting.c
code/sdk/zhihui/ppp/doc/serial_test/SERIAL_TEST_USAGE.md [new file with mode: 0644]
code/sdk/zhihui/ppp/doc/serial_test/compare_logs.py [new file with mode: 0644]
code/sdk/zhihui/ppp/doc/serial_test/serial_test.py [new file with mode: 0644]
code/sdk/zhihui/ppp/example/ppp_at_cmd.c
code/sdk/zhihui/ppp/include/ppp_api.h
code/sdk/zhihui/ppp/include/ppp_config.h
code/sdk/zhihui/ppp/src/ppp_api.c
code/sdk/zhihui/ppp/src/ppp_at_handler.c
code/sdk/zhihui/ppp/src/ppp_interrupt.c
code/sdk/zhihui/ppp/src/ppp_lwip_thread.c
code/sdk/zhihui/ppp/src/ppp_power_ctl.c
code/sdk/zhihui/ppp/src/ppp_serial.c
code/sdk/zhihui/tcptest/include/zhihui_tcp_debug.h
code/sdk/zhihui/tcptest/include/zhihui_tcp_test.h

index 35e02ec..7399f2b 100644 (file)
 #define UART_RX_BUFFER_SIZE 1
 #else
 
-#if defined(SUPPORT_PPP_SERVICE)    
-#define UART_RX_BUFFER_SIZE 2048
-// #warning "UART_RX_BUFFER_SIZE is 2048"
-#else
-#define UART_RX_BUFFER_SIZE 56
-// #warning "UART_RX_BUFFER_SIZE is 56"
-#endif
+/**
+ * UART_RX_BUFFER SIZE  似乎只能是 56 更多没用
+ */
+#define UART_RX_BUFFER_SIZE 56 
 
 #endif
 
diff --git a/code/sdk/zhihui/ppp/doc/serial_test/SERIAL_TEST_USAGE.md b/code/sdk/zhihui/ppp/doc/serial_test/SERIAL_TEST_USAGE.md
new file mode 100644 (file)
index 0000000..14ec67a
--- /dev/null
@@ -0,0 +1,335 @@
+# 串口测试工具使用说明
+
+## 主要功能
+
+### ✅ 优雅的测试停止机制
+
+**新特性:先停发送,延时后再停接收**
+
+测试结束时的执行顺序:
+1. 🛑 停止发送线程
+2. ⏱️ 等待1秒(让最后的数据有时间传输)
+3. 🛑 停止接收线程
+4. 📊 打印最终统计
+
+这样可以确保最后发送的数据包能够被完整接收,避免误报丢包。
+
+### 示例输出
+
+```bash
+$ python3 serial_test.py -t /dev/ttyUSB0 -r /dev/ttyUSB1 -d 10 -i 100 -s 64 -b 1000000
+
+======================================================================
+                          串口测试程序
+======================================================================
+发送串口: /dev/ttyUSB0
+接收串口: /dev/ttyUSB1
+波特率: 1000000
+测试时长: 10 秒
+发送间隔: 100 毫秒
+包大小: 64 字节
+======================================================================
+
+打开发送串口: /dev/ttyUSB0 @ 1000000
+打开接收串口: /dev/ttyUSB1 @ 1000000
+串口打开成功!
+
+发送线程启动 (间隔: 100.00ms, 包大小: 64字节)
+接收线程启动
+
+测试开始,运行时长: 10 秒
+按 Ctrl+C 可以提前终止测试
+
+======================================================================
+统计时间: 2025-10-09 14:23:45
+运行时长: 10.05 秒
+----------------------------------------------------------------------
+发送: 100 包, 6,400 字节, 636.82 字节/秒
+接收: 100 包, 6,400 字节, 636.80 字节/秒
+错误: 0 次 (数据不连续: 0)
+丢包率: 0.00%
+======================================================================
+
+正在停止发送...              # ← 先停发送
+发送线程已停止
+等待1秒以接收剩余数据...     # ← 延时1秒
+正在停止接收...              # ← 再停接收
+接收线程已停止
+
+######################################################################
+#                         最终统计信息                              #
+######################################################################
+
+======================================================================
+统计时间: 2025-10-09 14:23:56
+运行时长: 11.08 秒
+----------------------------------------------------------------------
+发送: 100 包, 6,400 字节, 577.62 字节/秒
+接收: 100 包, 6,400 字节, 577.60 字节/秒
+错误: 0 次 (数据不连续: 0)
+丢包率: 0.00%
+======================================================================
+
+发送串口已关闭
+接收串口已关闭
+日志文件已关闭
+```
+
+## 使用场景
+
+### 1. 基本测试
+
+```bash
+python3 serial_test.py \
+  -t /dev/ttyUSB0 \
+  -r /dev/ttyUSB1 \
+  -d 60 \
+  -i 100 \
+  -s 64 \
+  -b 1000000
+```
+
+### 2. 保存日志文件
+
+```bash
+python3 serial_test.py \
+  -t /dev/ttyUSB0 \
+  -r /dev/ttyUSB1 \
+  -d 60 \
+  -i 100 \
+  -s 64 \
+  -b 1000000 \
+  --tx-log tx_data.log \
+  --rx-log rx_data.log
+```
+
+### 3. 测试完成后对比
+
+```bash
+# 运行测试
+python3 serial_test.py \
+  -t /dev/ttyUSB0 -r /dev/ttyUSB1 \
+  -d 30 -i 50 -s 128 -b 1000000 \
+  --tx-log tx.log --rx-log rx.log
+
+# 对比日志
+python3 compare_logs.py tx.log rx.log
+```
+
+## 优雅停止的优势
+
+### 问题场景:没有延时时
+```
+时间轴:
+ 0.0s: 发送最后一个包
+ 0.0s: 同时停止发送和接收线程
+ 结果: 最后一个包可能还在传输中就停止接收 ❌
+```
+
+### 改进后:有延时
+```
+时间轴:
+ 0.0s: 发送最后一个包
+ 0.0s: 停止发送线程
+ 0.1s: 数据在串口传输中...
+ 0.2s: 接收线程接收到最后的数据
+ 1.0s: 停止接收线程
+ 结果: 所有数据都被正确接收 ✅
+```
+
+## 参数说明
+
+| 参数 | 简写 | 必需 | 说明 | 示例 |
+|------|------|------|------|------|
+| `--tx-port` | `-t` | ✅ | 发送串口设备 | `/dev/ttyUSB0` |
+| `--rx-port` | `-r` | ✅ | 接收串口设备 | `/dev/ttyUSB1` |
+| `--duration` | `-d` | ✅ | 测试时长(秒) | `60` |
+| `--interval` | `-i` | ✅ | 发送间隔(毫秒) | `100` |
+| `--size` | `-s` | ✅ | 每包数据大小(字节) | `64` |
+| `--baudrate` | `-b` | ❌ | 波特率(默认115200) | `1000000` |
+| `--tx-log` | | ❌ | 发送日志文件 | `tx_data.log` |
+| `--rx-log` | | ❌ | 接收日志文件 | `rx_data.log` |
+
+## 实时统计
+
+测试运行时会:
+- ✅ 每10秒自动打印统计信息
+- ✅ 发现数据不连续时立即打印错误
+- ✅ 测试结束时打印最终统计
+- ✅ 可以按 `Ctrl+C` 提前终止测试(同样会优雅停止)
+
+## 统计信息说明
+
+```
+发送: 100 包, 6,400 字节, 636.82 字节/秒
+  └─ 包数   └─ 总字节  └─ 平均速率
+
+接收: 100 包, 6,400 字节, 636.80 字节/秒
+  └─ 包数   └─ 总字节  └─ 平均速率
+
+错误: 0 次 (数据不连续: 0)
+  └─ 总错误  └─ 不连续错误
+
+丢包率: 0.00%
+  └─ (发送字节 - 接收字节) / 发送字节 * 100
+```
+
+## 日志文件格式
+
+生成的日志文件每行一个字节(十六进制大写):
+
+**tx_data.log**
+```
+00
+01
+02
+03
+...
+FE
+FF
+00  ← 循环
+```
+
+**rx_data.log**
+```
+00
+01
+02
+03
+...
+```
+
+## 常见问题
+
+### Q1: 为什么要延时1秒?
+
+**A:** 串口数据传输需要时间:
+- 1Mbps波特率下,64字节数据传输约需 **0.5ms**
+- 但系统调度、缓冲区处理可能需要 **几十到几百毫秒**
+- 1秒的延时足够覆盖绝大多数场景
+
+### Q2: 可以调整延时时间吗?
+
+**A:** 当前是硬编码1秒。如需调整,可以修改 `serial_test.py` 第274行:
+```python
+time.sleep(1)  # 改为其他值,如 0.5 或 2
+```
+
+### Q3: 高速传输时会丢数据吗?
+
+**A:** 取决于:
+- 串口驱动缓冲区大小(通常4KB~64KB)
+- 发送间隔和包大小
+- 系统负载
+
+建议:
+- 高速传输时适当增加发送间隔
+- 使用日志文件保存数据,测试完成后对比
+
+### Q4: 为什么最后接收可能比发送多?
+
+**A:** 这是不可能的。如果出现这种情况,可能是:
+- Bug(请报告)
+- 统计计数错误
+
+## 测试技巧
+
+### 1. 压力测试
+```bash
+# 高频小包(每10ms发送64字节)
+python3 serial_test.py -t /dev/ttyUSB0 -r /dev/ttyUSB1 -d 300 -i 10 -s 64 -b 1000000
+
+# 低频大包(每500ms发送2048字节)
+python3 serial_test.py -t /dev/ttyUSB0 -r /dev/ttyUSB1 -d 300 -i 500 -s 2048 -b 1000000
+```
+
+### 2. 稳定性测试
+```bash
+# 长时间运行(1小时)
+python3 serial_test.py -t /dev/ttyUSB0 -r /dev/ttyUSB1 -d 3600 -i 100 -s 128 -b 1000000
+```
+
+### 3. 回环测试
+```bash
+# 设备端开启 PPP_DO_SERIAL_TEST
+# PC端使用同一串口收发
+python3 serial_test.py \
+  -t /dev/ttyUSB0 \
+  -r /dev/ttyUSB0 \
+  -d 60 -i 100 -s 64 -b 1000000 \
+  --tx-log tx.log --rx-log rx.log
+```
+
+## 依赖安装
+
+```bash
+# Ubuntu/Debian
+sudo apt-get install python3-serial
+
+# 或使用 pip
+pip3 install pyserial
+```
+
+## 权限问题
+
+Linux下可能需要串口权限:
+```bash
+# 方法1:临时授权
+sudo chmod 666 /dev/ttyUSB0
+
+# 方法2:将用户加入dialout组(推荐)
+sudo usermod -a -G dialout $USER
+# 重新登录后生效
+```
+
+## 组合使用
+
+完整的测试流程:
+
+```bash
+#!/bin/bash
+# 串口完整测试脚本
+
+DATE=$(date +%Y%m%d_%H%M%S)
+TX_LOG="tx_${DATE}.log"
+RX_LOG="rx_${DATE}.log"
+RESULT="result_${DATE}.txt"
+
+echo "开始串口测试..."
+
+# 1. 运行测试
+python3 serial_test.py \
+  -t /dev/ttyUSB0 \
+  -r /dev/ttyUSB1 \
+  -d 60 \
+  -i 100 \
+  -s 64 \
+  -b 1000000 \
+  --tx-log "$TX_LOG" \
+  --rx-log "$RX_LOG" \
+  | tee test_output.txt
+
+# 2. 对比日志
+echo -e "\n\n对比收发数据..."
+python3 compare_logs.py "$TX_LOG" "$RX_LOG" | tee "$RESULT"
+
+# 3. 检查结果
+if grep -q "✅ 完美匹配" "$RESULT"; then
+    echo -e "\n✅ 测试通过!"
+    exit 0
+else
+    echo -e "\n❌ 测试失败!"
+    exit 1
+fi
+```
+
+## 总结
+
+优雅停止机制确保:
+- ✅ 最后的数据包不会丢失
+- ✅ 统计信息更准确
+- ✅ 测试结果更可靠
+- ✅ 适用于各种波特率和数据量
+
+是串口测试的重要改进!🎯
+
diff --git a/code/sdk/zhihui/ppp/doc/serial_test/compare_logs.py b/code/sdk/zhihui/ppp/doc/serial_test/compare_logs.py
new file mode 100644 (file)
index 0000000..903e13b
--- /dev/null
@@ -0,0 +1,205 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+串口日志对比工具
+用于对比发送日志和接收日志,查找差异
+"""
+
+import sys
+import argparse
+
+def load_hex_log(filename):
+    """加载十六进制日志文件"""
+    data = []
+    try:
+        with open(filename, 'r') as f:
+            for line_num, line in enumerate(f, 1):
+                line = line.strip()
+                if line:
+                    try:
+                        # 解析十六进制值
+                        byte_val = int(line, 16)
+                        data.append((line_num, byte_val))
+                    except ValueError:
+                        print(f"警告: {filename}:{line_num} 无效的十六进制值: {line}")
+        return data
+    except FileNotFoundError:
+        print(f"错误: 文件不存在: {filename}")
+        return None
+    except Exception as e:
+        print(f"错误: 读取文件失败: {e}")
+        return None
+
+def find_missing_ranges(tx_data, rx_data):
+    """
+    找出发送了但没收到的数据范围
+    使用LCS(最长公共子序列)思想来对齐数据
+    """
+    tx_len = len(tx_data)
+    rx_len = len(rx_data)
+    
+    # 创建接收数据的字典,方便快速查找
+    rx_dict = {rx_data[i][1]: i for i in range(rx_len)}
+    
+    # 简单策略:逐个对比,找出丢失的字节
+    missing_ranges = []
+    current_range_start = None
+    current_range_data = []
+    
+    rx_index = 0
+    
+    for tx_index in range(tx_len):
+        tx_line, tx_byte = tx_data[tx_index]
+        
+        # 检查这个字节是否在接收数据中(从当前位置开始)
+        found = False
+        if rx_index < rx_len:
+            rx_line, rx_byte = rx_data[rx_index]
+            if tx_byte == rx_byte:
+                # 匹配,移动到下一个接收位置
+                found = True
+                rx_index += 1
+                
+                # 如果之前有未收到的范围,现在结束它
+                if current_range_start is not None:
+                    missing_ranges.append({
+                        'start': current_range_start,
+                        'end': tx_index - 1,
+                        'count': len(current_range_data),
+                        'data': current_range_data
+                    })
+                    current_range_start = None
+                    current_range_data = []
+        
+        if not found:
+            # 这个字节没有收到
+            if current_range_start is None:
+                current_range_start = tx_index
+            current_range_data.append((tx_line, tx_byte))
+    
+    # 处理最后一个范围
+    if current_range_start is not None:
+        missing_ranges.append({
+            'start': current_range_start,
+            'end': tx_len - 1,
+            'count': len(current_range_data),
+            'data': current_range_data
+        })
+    
+    return missing_ranges
+
+def compare_logs(tx_data, rx_data, max_errors=100):
+    """对比发送和接收数据"""
+    tx_len = len(tx_data)
+    rx_len = len(rx_data)
+    
+    print("="*70)
+    print(" "*25 + "日志对比结果")
+    print("="*70)
+    print(f"发送字节数: {tx_len}")
+    print(f"接收字节数: {rx_len}")
+    print(f"丢失字节数: {tx_len - rx_len}")
+    
+    if tx_len > 0:
+        loss_rate = (tx_len - rx_len) / tx_len * 100
+        print(f"丢包率: {loss_rate:.2f}%")
+    print("-"*70)
+    
+    # 找出丢失的数据范围
+    missing_ranges = find_missing_ranges(tx_data, rx_data)
+    
+    if not missing_ranges:
+        print("\n✅ 完美匹配!所有数据都收到了。")
+        print("="*70)
+        return True
+    
+    # 显示丢失的数据范围
+    print(f"\n发现 {len(missing_ranges)} 个丢失区域:\n")
+    
+    total_missing = 0
+    shown_ranges = 0
+    
+    for i, range_info in enumerate(missing_ranges):
+        if shown_ranges >= max_errors:
+            remaining = len(missing_ranges) - shown_ranges
+            print(f"\n... (还有 {remaining} 个丢失区域未显示)")
+            break
+        
+        start_pos = range_info['start']
+        end_pos = range_info['end']
+        count = range_info['count']
+        data = range_info['data']
+        
+        total_missing += count
+        shown_ranges += 1
+        
+        if count == 1:
+            # 单个字节丢失
+            line, byte_val = data[0]
+            print(f"❌ 位置 {start_pos}: 丢失 1 字节 = 0x{byte_val:02X} (发送行{line})")
+        else:
+            # 连续多个字节丢失
+            print(f"❌ 位置 {start_pos}~{end_pos}: 丢失 {count} 字节")
+            
+            # 显示前8个和后8个字节(如果数据较多)
+            if count <= 16:
+                # 数据不多,全部显示
+                hex_str = ' '.join([f"{byte_val:02X}" for _, byte_val in data])
+                print(f"   数据: {hex_str}")
+            else:
+                # 数据太多,只显示首尾
+                head = ' '.join([f"{byte_val:02X}" for _, byte_val in data[:8]])
+                tail = ' '.join([f"{byte_val:02X}" for _, byte_val in data[-8:]])
+                print(f"   数据: {head} ... {tail}")
+        
+        # 添加空行分隔不同的范围
+        if i < len(missing_ranges) - 1:
+            print()
+    
+    print("-"*70)
+    print(f"总计丢失: {total_missing} 字节")
+    
+    if tx_len != rx_len:
+        print(f"长度差异: {tx_len - rx_len} 字节")
+    
+    print("\n❌ 发现数据丢失!")
+    print("="*70)
+    
+    return False
+
+def main():
+    parser = argparse.ArgumentParser(
+        description='串口日志对比工具 - 对比发送和接收的十六进制日志文件',
+        formatter_class=argparse.RawDescriptionHelpFormatter,
+        epilog="""
+示例:
+  %(prog)s tx.log rx.log
+  %(prog)s tx.log rx.log --max-errors 50
+        """
+    )
+    
+    parser.add_argument('tx_log', help='发送日志文件')
+    parser.add_argument('rx_log', help='接收日志文件')
+    parser.add_argument('--max-errors', type=int, default=100,
+                        help='最多显示的错误数量 (默认: 100)')
+    
+    args = parser.parse_args()
+    
+    print(f"加载发送日志: {args.tx_log}")
+    tx_data = load_hex_log(args.tx_log)
+    if tx_data is None:
+        return 1
+    
+    print(f"加载接收日志: {args.rx_log}")
+    rx_data = load_hex_log(args.rx_log)
+    if rx_data is None:
+        return 1
+    
+    print()
+    success = compare_logs(tx_data, rx_data, args.max_errors)
+    
+    return 0 if success else 1
+
+if __name__ == '__main__':
+    sys.exit(main())
+
diff --git a/code/sdk/zhihui/ppp/doc/serial_test/serial_test.py b/code/sdk/zhihui/ppp/doc/serial_test/serial_test.py
new file mode 100644 (file)
index 0000000..3af7a48
--- /dev/null
@@ -0,0 +1,374 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+串口测试程序
+功能:
+- 支持双串口发送和接收测试
+- 数据按照0x00~0xFF循环发送
+- 检测接收数据连续性
+- 统计错误和吞吐量
+"""
+
+import serial
+import threading
+import time
+import argparse
+import sys
+from datetime import datetime
+
+class SerialTestStats:
+    """统计信息类"""
+    def __init__(self, tx_log_file=None, rx_log_file=None):
+        self.tx_bytes = 0           # 发送字节数
+        self.rx_bytes = 0           # 接收字节数
+        self.tx_packets = 0         # 发送包数
+        self.rx_packets = 0         # 接收包数
+        self.error_count = 0        # 错误计数
+        self.discontinuity_count = 0  # 不连续计数
+        self.last_expected_byte = None  # 期望的下一个字节
+        self.lock = threading.Lock()
+        self.start_time = time.time()
+        
+        # 日志文件
+        self.tx_log_file = None
+        self.rx_log_file = None
+        
+        # 打开日志文件
+        if tx_log_file:
+            try:
+                self.tx_log_file = open(tx_log_file, 'w')
+                print(f"发送数据日志: {tx_log_file}")
+            except Exception as e:
+                print(f"警告: 无法创建发送日志文件: {e}")
+        
+        if rx_log_file:
+            try:
+                self.rx_log_file = open(rx_log_file, 'w')
+                print(f"接收数据日志: {rx_log_file}")
+            except Exception as e:
+                print(f"警告: 无法创建接收日志文件: {e}")
+        
+    def update_tx(self, data):
+        """更新发送统计并记录到日志"""
+        with self.lock:
+            self.tx_bytes += len(data)
+            self.tx_packets += 1
+            
+            # 记录到日志文件(每个字节一行)
+            if self.tx_log_file:
+                for byte in data:
+                    self.tx_log_file.write(f"{byte:02X}\n")
+                self.tx_log_file.flush()  # 实时刷新
+            
+    def update_rx(self, data):
+        """更新接收统计并检查连续性"""
+        with self.lock:
+            self.rx_bytes += len(data)
+            self.rx_packets += 1
+            
+            # 记录到日志文件(每个字节一行)
+            if self.rx_log_file:
+                for byte in data:
+                    self.rx_log_file.write(f"{byte:02X}\n")
+                self.rx_log_file.flush()  # 实时刷新
+            
+            # 检查数据连续性
+            for byte in data:
+                if self.last_expected_byte is None:
+                    # 第一个字节,初始化
+                    self.last_expected_byte = (byte + 1) % 256
+                else:
+                    if byte != self.last_expected_byte:
+                        self.error_count += 1
+                        self.discontinuity_count += 1
+                        print(f"\n[ERROR] 数据不连续! 期望: 0x{self.last_expected_byte:02X}, 实际: 0x{byte:02X}")
+                    self.last_expected_byte = (byte + 1) % 256
+                    
+    def close(self):
+        """关闭日志文件"""
+        if self.tx_log_file:
+            self.tx_log_file.close()
+            self.tx_log_file = None
+        if self.rx_log_file:
+            self.rx_log_file.close()
+            self.rx_log_file = None
+    
+    def print_stats(self):
+        """打印统计信息"""
+        with self.lock:
+            elapsed = time.time() - self.start_time
+            tx_rate = self.tx_bytes / elapsed if elapsed > 0 else 0
+            rx_rate = self.rx_bytes / elapsed if elapsed > 0 else 0
+            
+            print("\n" + "="*70)
+            print(f"统计时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+            print(f"运行时长: {elapsed:.2f} 秒")
+            print("-"*70)
+            print(f"发送: {self.tx_packets:,} 包, {self.tx_bytes:,} 字节, {tx_rate:.2f} 字节/秒")
+            print(f"接收: {self.rx_packets:,} 包, {self.rx_bytes:,} 字节, {rx_rate:.2f} 字节/秒")
+            print(f"错误: {self.error_count:,} 次 (数据不连续: {self.discontinuity_count:,})")
+            if self.tx_bytes > 0:
+                loss_rate = (self.tx_bytes - self.rx_bytes) / self.tx_bytes * 100
+                print(f"丢包率: {loss_rate:.2f}%")
+            print("="*70 + "\n")
+
+class SerialTester:
+    """串口测试器"""
+    def __init__(self, tx_port, rx_port, duration, interval_ms, packet_size, baudrate=115200, 
+                 tx_log_file=None, rx_log_file=None):
+        self.tx_port = tx_port
+        self.rx_port = rx_port
+        self.duration = duration
+        self.interval = interval_ms / 1000.0  # 转换为秒
+        self.packet_size = packet_size
+        self.baudrate = baudrate
+        self.stats = SerialTestStats(tx_log_file, rx_log_file)
+        self.running = False
+        self.tx_running = False  # 发送线程运行标志
+        self.rx_running = False  # 接收线程运行标志
+        self.tx_serial = None
+        self.rx_serial = None
+        self.current_byte = 0  # 当前要发送的字节值
+        
+    def open_ports(self):
+        """打开串口"""
+        try:
+            print(f"打开发送串口: {self.tx_port} @ {self.baudrate}")
+            self.tx_serial = serial.Serial(
+                port=self.tx_port,
+                baudrate=self.baudrate,
+                bytesize=serial.EIGHTBITS,
+                parity=serial.PARITY_NONE,
+                stopbits=serial.STOPBITS_ONE,
+                timeout=1
+            )
+            
+            print(f"打开接收串口: {self.rx_port} @ {self.baudrate}")
+            self.rx_serial = serial.Serial(
+                port=self.rx_port,
+                baudrate=self.baudrate,
+                bytesize=serial.EIGHTBITS,
+                parity=serial.PARITY_NONE,
+                stopbits=serial.STOPBITS_ONE,
+                timeout=1
+            )
+            
+            print("串口打开成功!\n")
+            return True
+            
+        except serial.SerialException as e:
+            print(f"打开串口失败: {e}")
+            return False
+            
+    def close_ports(self):
+        """关闭串口和日志文件"""
+        if self.tx_serial and self.tx_serial.is_open:
+            self.tx_serial.close()
+            print("发送串口已关闭")
+            
+        if self.rx_serial and self.rx_serial.is_open:
+            self.rx_serial.close()
+            print("接收串口已关闭")
+        
+        # 关闭日志文件
+        self.stats.close()
+        print("日志文件已关闭")
+            
+    def generate_packet(self):
+        """生成测试数据包"""
+        packet = bytearray()
+        for i in range(self.packet_size):
+            packet.append(self.current_byte)
+            self.current_byte = (self.current_byte + 1) % 256
+        return bytes(packet)
+        
+    def tx_thread(self):
+        """发送线程"""
+        print(f"发送线程启动 (间隔: {self.interval*1000:.2f}ms, 包大小: {self.packet_size}字节)")
+        
+        while self.tx_running:
+            try:
+                # 生成并发送数据
+                packet = self.generate_packet()
+                self.tx_serial.write(packet)
+                self.stats.update_tx(packet)
+                
+                # 等待指定间隔
+                time.sleep(self.interval)
+                
+            except serial.SerialException as e:
+                print(f"\n[ERROR] 发送错误: {e}")
+                break
+            except Exception as e:
+                print(f"\n[ERROR] 发送异常: {e}")
+                break
+                
+        print("发送线程退出")
+        
+    def rx_thread(self):
+        """接收线程"""
+        print(f"接收线程启动")
+        
+        while self.rx_running:
+            try:
+                # 检查是否有数据可读
+                if self.rx_serial.in_waiting > 0:
+                    data = self.rx_serial.read(self.rx_serial.in_waiting)
+                    self.stats.update_rx(data)
+                else:
+                    time.sleep(0.01)  # 短暂休眠避免CPU占用过高
+                    
+            except serial.SerialException as e:
+                print(f"\n[ERROR] 接收错误: {e}")
+                break
+            except Exception as e:
+                print(f"\n[ERROR] 接收异常: {e}")
+                break
+                
+        print("接收线程退出")
+        
+    def stats_thread(self):
+        """统计打印线程"""
+        while self.running:
+            time.sleep(10)
+            if self.running:
+                self.stats.print_stats()
+                
+    def run(self):
+        """运行测试"""
+        if not self.open_ports():
+            return False
+            
+        # 启动所有线程
+        self.running = True
+        self.tx_running = True
+        self.rx_running = True
+        
+        # 创建线程
+        tx_t = threading.Thread(target=self.tx_thread, name="TX-Thread")
+        rx_t = threading.Thread(target=self.rx_thread, name="RX-Thread")
+        stats_t = threading.Thread(target=self.stats_thread, name="Stats-Thread")
+        
+        # 启动线程
+        tx_t.start()
+        rx_t.start()
+        stats_t.start()
+        
+        print(f"\n测试开始,运行时长: {self.duration} 秒")
+        print("按 Ctrl+C 可以提前终止测试\n")
+        
+        try:
+            # 等待指定时长
+            time.sleep(self.duration)
+        except KeyboardInterrupt:
+            print("\n\n收到中断信号,正在停止测试...")
+            
+        # 优雅地停止测试:先停发送,等1秒后再停接收
+        print("\n正在停止发送...")
+        self.tx_running = False
+        tx_t.join(timeout=5)
+        print("发送线程已停止")
+        
+        # 等待1秒,让接收线程接收最后的数据
+        print("等待1秒以接收剩余数据...")
+        time.sleep(1)
+        
+        print("正在停止接收...")
+        self.rx_running = False
+        rx_t.join(timeout=5)
+        print("接收线程已停止")
+        
+        # 停止统计线程
+        self.running = False
+        stats_t.join(timeout=2)
+        
+        # 打印最终统计
+        print("\n" + "#"*70)
+        print("#" + " "*25 + "最终统计信息" + " "*25 + "#")
+        print("#"*70)
+        self.stats.print_stats()
+        
+        # 关闭串口
+        self.close_ports()
+        
+        return True
+
+def main():
+    parser = argparse.ArgumentParser(
+        description='串口测试程序 - 支持双串口收发测试',
+        formatter_class=argparse.RawDescriptionHelpFormatter,
+        epilog="""
+示例:
+  %(prog)s -t /dev/ttyUSB0 -r /dev/ttyUSB1 -d 60 -i 100 -s 64
+  %(prog)s --tx-port COM1 --rx-port COM2 --duration 120 --interval 50 --size 128 --baudrate 9600
+  %(prog)s -t /dev/ttyUSB0 -r /dev/ttyUSB1 -d 60 -i 100 -s 64 --tx-log tx.log --rx-log rx.log
+        """
+    )
+    
+    parser.add_argument('-t', '--tx-port', required=True,
+                        help='发送串口 (例如: /dev/ttyUSB0 或 COM1)')
+    parser.add_argument('-r', '--rx-port', required=True,
+                        help='接收串口 (例如: /dev/ttyUSB1 或 COM2)')
+    parser.add_argument('-d', '--duration', type=int, required=True,
+                        help='测试时长 (秒)')
+    parser.add_argument('-i', '--interval', type=int, required=True,
+                        help='发送间隔 (毫秒)')
+    parser.add_argument('-s', '--size', type=int, required=True,
+                        help='每包数据大小 (字节)')
+    parser.add_argument('-b', '--baudrate', type=int, default=115200,
+                        help='波特率 (默认: 115200)')
+    parser.add_argument('--tx-log', type=str, default=None,
+                        help='发送数据日志文件路径 (十六进制格式,一字节一行)')
+    parser.add_argument('--rx-log', type=str, default=None,
+                        help='接收数据日志文件路径 (十六进制格式,一字节一行)')
+    
+    args = parser.parse_args()
+    
+    # 参数验证
+    if args.duration <= 0:
+        print("错误: 测试时长必须大于0")
+        return 1
+        
+    if args.interval <= 0:
+        print("错误: 发送间隔必须大于0")
+        return 1
+        
+    if args.size <= 0 or args.size > 4096:
+        print("错误: 数据大小必须在1-4096字节之间")
+        return 1
+        
+    # 打印配置信息
+    print("="*70)
+    print(" "*25 + "串口测试程序" + " "*25)
+    print("="*70)
+    print(f"发送串口: {args.tx_port}")
+    print(f"接收串口: {args.rx_port}")
+    print(f"波特率: {args.baudrate}")
+    print(f"测试时长: {args.duration} 秒")
+    print(f"发送间隔: {args.interval} 毫秒")
+    print(f"包大小: {args.size} 字节")
+    if args.tx_log:
+        print(f"发送日志: {args.tx_log}")
+    if args.rx_log:
+        print(f"接收日志: {args.rx_log}")
+    print("="*70 + "\n")
+    
+    # 创建测试器并运行
+    tester = SerialTester(
+        tx_port=args.tx_port,
+        rx_port=args.rx_port,
+        duration=args.duration,
+        interval_ms=args.interval,
+        packet_size=args.size,
+        baudrate=args.baudrate,
+        tx_log_file=args.tx_log,
+        rx_log_file=args.rx_log
+    )
+    
+    success = tester.run()
+    
+    return 0 if success else 1
+
+if __name__ == '__main__':
+    sys.exit(main())
+
index 7cf9425..5851e43 100644 (file)
@@ -1318,13 +1318,13 @@ static errcode_t at_ppp_get_signal_info(uint8_t *para, uint32_t paraLen)
     (void)para;
     (void)paraLen;
     
-    PRINT("[PPP_INFO]PPP SIGNAL INFO: Getting network signal information...\r\n");
+    PRINT("[PPP_INFO]PPP SIGNAL INFO IN ALL MODE: Getting network signal information...\r\n");
     
-    errcode_t ret = ppp_get_network_signal_info();
+    errcode_t ret = ppp_api_update_netinfo_in_all_mode();
     if (ret == ERRCODE_SUCC) {
-        PRINT("[PPP_INFO]PPP SIGNAL INFO: Network signal information retrieved successfully\r\n");
+        PRINT("[PPP_INFO]PPP SIGNAL INFO IN ALL MODE: Network signal information retrieved successfully\r\n");
     } else {
-        PRINT("[PPP_ERR]PPP SIGNAL INFO: Failed to get network signal information, error: %d\r\n", ret);
+        PRINT("[PPP_ERR]PPP SIGNAL INFO IN ALL MODE: Failed to get network signal information, error: %d\r\n", ret);
     }
     
     return ret;
@@ -1782,9 +1782,9 @@ static errcode_t at_ppp_tcp_performance_test(uint8_t *para, uint32_t paraLen)
 {
     if (!para || paraLen == 0) {
         PRINT("[PPP_ERR]PPP TCP PERF: Missing parameters\r\n");
-        PRINT("[PPP_INFO]Usage: AT^PPPTCPPERF=<host>,<port>,<connections>,<time>[,<recv_timeout_ms>]\r\n");
+        PRINT("[PPP_INFO]Usage: AT^PPPTCPPERF=<host>,<port>,<connections>,<time>[,<send_interval_ms>]\r\n");
         PRINT("[PPP_INFO]Example: AT^PPPTCPPERF=110.42.224.129,8910,5,30\r\n");
-        PRINT("[PPP_INFO]Example: AT^PPPTCPPERF=110.42.224.129,8910,5,30,2000\r\n");
+        PRINT("[PPP_INFO]Example: AT^PPPTCPPERF=110.42.224.129,8910,1,300,500\r\n");
         return ERRCODE_FAIL;
     }
     
@@ -1793,7 +1793,7 @@ static errcode_t at_ppp_tcp_performance_test(uint8_t *para, uint32_t paraLen)
     
     if (ConvertCmdToParam(para, paraLen, argv, &argc) != CUSTOM_UTILS_SUCCESS || (argc != 4 && argc != 5)) {
         PRINT("[PPP_ERR]PPP TCP PERF: Invalid parameters, need 4 or 5 parameters, got %d\r\n", argc);
-        PRINT("[PPP_INFO]Usage: AT^PPPTCPPERF=<host>,<port>,<connections>,<time>[,<recv_timeout_ms>]\r\n");
+        PRINT("[PPP_INFO]Usage: AT^PPPTCPPERF=<host>,<port>,<connections>,<time>[,<send_interval_ms>]\r\n");
         return ERRCODE_FAIL;
     }
     
@@ -1802,13 +1802,13 @@ static errcode_t at_ppp_tcp_performance_test(uint8_t *para, uint32_t paraLen)
     int port = atoi((char*)argv[1]);
     int connections = atoi((char*)argv[2]);
     int test_time = atoi((char*)argv[3]);
-    int recv_timeout_ms = TCP_TEST_DEFAULT_RECV_TIMEOUT_MS; // 默认值
+    int send_interval_ms = TCP_TEST_DEFAULT_SEND_INTERVAL_MS; // 默认值
     
     // 解析可选的接收超时参数
     if (argc == 5) {
-        recv_timeout_ms = atoi((char*)argv[4]);
-        if (recv_timeout_ms < 100 || recv_timeout_ms > 30000) {
-            PRINT("[PPP_ERR]PPP TCP PERF: Invalid recv timeout %d (must be 100-30000 ms)\r\n", recv_timeout_ms);
+        send_interval_ms = atoi((char*)argv[4]);
+        if (send_interval_ms < 10 || send_interval_ms > 1000) {
+            PRINT("[PPP_ERR]PPP TCP PERF: Invalid send interval %d (must be 10-1000 ms)\r\n", send_interval_ms);
             return ERRCODE_FAIL;
         }
     }
@@ -1834,7 +1834,7 @@ static errcode_t at_ppp_tcp_performance_test(uint8_t *para, uint32_t paraLen)
     PRINT("[PPP_INFO]Target: %s:%d\r\n", server_host, port);
     PRINT("[PPP_INFO]Connections: %d\r\n", connections);
     PRINT("[PPP_INFO]Duration: %d seconds\r\n", test_time);
-    PRINT("[PPP_INFO]Receive Timeout: %d ms\r\n", recv_timeout_ms);
+    PRINT("[PPP_INFO]Send interval: %d ms\r\n", send_interval_ms);
     
 #ifdef SUPPORT_TCP_TEST
     // 初始化TCP测试配置
@@ -1845,10 +1845,10 @@ static errcode_t at_ppp_tcp_performance_test(uint8_t *para, uint32_t paraLen)
     config.test_duration = (uint32_t)test_time;
     config.connection_count = (uint16_t)connections;
     config.verbose = true; // AT命令模式不使用详细输出
-    config.send_interval_ms = 500; // 500ms间隔,给其他进程更多CPU时间
+    config.recv_timeout_ms = 500; // 可配置的接收超时
     config.data_min_size = 1024;    // 较小的数据包
     config.data_max_size = 4096;  // 适中的最大包
-    config.recv_timeout_ms = (uint32_t)recv_timeout_ms; // 可配置的接收超时
+    config.send_interval_ms = (uint32_t)send_interval_ms;// 500ms间隔,给其他进程更多CPU时间 
     
     // 初始化TCP测试
     errcode_t ret = tcp_test_init();
@@ -2460,7 +2460,7 @@ static errcode_t at_ppp_set_config_baudrate(uint8_t *para, uint32_t paraLen, cha
     
     if (current_baudrate == baudrate) {
         ppp_print_info("PPP SET BAUDRATE: Baudrate already set to %d, no change needed\n", baudrate);
-        return ERRCODE_SUCC;
+        // return ERRCODE_SUCC;
     }
     
     // 设置新的波特率到配置模型
index b67aef7..c3c1f12 100644 (file)
@@ -35,6 +35,34 @@ errcode_t ppp_start_dial(void);
  */
 errcode_t ppp_stop_dial(void);
 
+/**
+ * @brief 暂停PPP通讯,切换到AT命令模式(不断开连接)
+ * @return 错误码
+ * 
+ * 功能说明:
+ * - 发送 "+++" 转义序列切换到AT命令模式
+ * - 停止PPP数据接收线程/中断
+ * - 初始化AT处理器
+ * - 执行AT测试验证
+ * 
+ * 注意:PPP连接保持,只是暂时切换到AT模式,与 ppp_resume() 配对使用
+ */
+errcode_t ppp_ppp_mode_pause(void);
+
+/**
+ * @brief 恢复PPP通讯,从AT命令模式返回PPP数据模式
+ * @return 错误码
+ * 
+ * 功能说明:
+ * - 发送 "ATO\r\n" 命令恢复PPP数据模式
+ * - 等待 "CONNECT" 响应
+ * - 去初始化AT处理器
+ * - 恢复PPP数据接收线程/中断
+ * 
+ * 注意:与 ppp_pause() 配对使用
+ */
+errcode_t ppp_ppp_mode_resume(void);
+
 /* PPP数据接收线程函数已移至ppp_lwip_thread.c */
 
 /**
@@ -146,6 +174,12 @@ errcode_t ppp_api_update_sim_status(void);
  */
 errcode_t ppp_api_update_all_runtime_status(void);
 
+/**
+ * @brief 更新所有runtime变量值
+ * @return ERRCODE_SUCC-成功,其他-失败
+ */
+errcode_t ppp_api_update_netinfo_in_all_mode(void);
+    
 /**
  * @brief 设置默认网卡
  * @param netif_name 网卡名称
index 531135b..3a92b02 100644 (file)
@@ -51,14 +51,14 @@ extern "C" {
 
 /* PPP接收模式配置 */
 #ifndef PPP_USE_INTERRUPT_MODE
-#define PPP_USE_INTERRUPT_MODE      1                   // 1=中断模式(UART中断接收), 0=轮询模式(线程轮询)
+#define PPP_USE_INTERRUPT_MODE      1                  // 1=中断模式(UART中断接收), 0=轮询模式(线程轮询)
 #endif
 
-/* PPP线程模式配置(仅轮询模式有效) */
-#ifndef PPP_USE_DUAL_THREAD
-#define PPP_USE_DUAL_THREAD         1                   // 1=双线程模式(接收+处理), 0=单线程模式(接收直接处理)
+#ifndef PPP_DO_SERIAL_TEST
+#define PPP_DO_SERIAL_TEST          0                   // 1=进行串口读取能力测试, 0=不进行串口读取能力测试
 #endif
 
+
 /* PPP性能优化配置 - 解决接收阻塞问题 */
 #define PPP_LWIP_PBUF_POOL_SIZE     32                  // 增加pbuf池大小,默认16太小
 #define PPP_LWIP_TCPIP_MSG_INPKT    64                  // 增加输入消息数量,默认32太小
index 4e33027..811d88c 100644 (file)
@@ -142,7 +142,10 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config)
     // 保存用户配置
     memcpy_s(&g_ppp_config, sizeof(ppp_config_t), config, sizeof(ppp_config_t));
 
+    // PPP_DO_SERIAL_TEST 不进行电源初始化, 用于调试串口读取能力测试。
+    #ifndef PPP_DO_SERIAL_TEST
     ppp_api_power_init();
+    #endif
 
 #define PPP_SERIAL_INIT 1 //外接串口调试模组时,串口要设置input防止干扰。
 #if PPP_SERIAL_INIT
@@ -167,6 +170,9 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config)
         goto init_failed;
     }
 
+
+    #ifndef PPP_DO_SERIAL_TEST
+
     // 初始化AT命令处理器
     ret = ppp_at_handler_init(SIO_UART_BUS, g_ppp_config.baudrate, true);
     if (ret != PPP_ERR_OK) {
@@ -184,6 +190,18 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config)
     } else {
         PPP_DEBUG_PRINT("Successfully switched to AT mode\n");
     }
+#else
+    PPP_DEBUG_PRINT("PPP_DO_SERIAL_TEST is defined, skip switch to AT mode\n");
+    ret = ppp_serial_switch_to_ppp_mode();
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_PRINT("Failed to switch to PPP mode: %d\n", ret);
+        ppp_serial_deinit();
+        goto init_failed;
+    } else {
+        PPP_DEBUG_PRINT("Successfully switched to PPP mode\n");
+    }
+#endif
+
 #else
     ppp_api_leiniao_serial_pin_to_gpio_input();
 #endif
@@ -191,9 +209,11 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config)
     g_ppp_state = PPP_STATE_INITIALIZED;
     
     PPP_DEBUG_PRINT("PPP module initialized successfully\n");
-    
+
     // 打开4G电源
     ppp_api_power_control(true);
+
+#ifndef PPP_DO_SERIAL_TEST
     PPP_DEBUG_PRINT("Waiting for modem stabilization after power control...\n");
     // 等待5秒让调制解调器完全稳定
     osal_msleep(5000);
@@ -203,8 +223,30 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config)
     ppp_api_update_all_runtime_status();
     
     ppp_get_network_signal_info();
+#else
+    // 9. 启动PPP数据接收处理(根据配置选择中断或轮询模式)
+    #if PPP_USE_INTERRUPT_MODE
+        // 中断模式:注册UART中断回调(UART总线号从ppp_serial_get_uart_bus()获取)
+        PPP_DEBUG_PRINT("Enabling PPP interrupt mode...\n");
+        ret = ppp_interrupt_enable();
+        if (ret != PPP_ERR_OK) {
+            PPP_DEBUG_PRINT("Failed to enable PPP interrupt: %d\n", ret);
+            goto init_failed;
+        }
+        PPP_DEBUG_PRINT("PPP interrupt mode enabled successfully\n");
+    #else
+        // 轮询模式:启动接收线程
+        PPP_DEBUG_PRINT("Starting PPP receive thread (polling mode)...\n");
+        ret = ppp_lwip_start_receive_thread();
+        if (ret != PPP_ERR_OK) {
+            PPP_DEBUG_PRINT("Failed to start PPP data receive thread: %d\n", ret);
+            goto init_failed;
+        }
+        PPP_DEBUG_PRINT("PPP receive thread started successfully\n");
+    #endif
+#endif
 
-    return ERRCODE_SUCC;
+return ERRCODE_SUCC;
 #if PPP_SERIAL_INIT
 init_failed:
 #endif
@@ -570,6 +612,250 @@ error_recovery_at_mode:
     return ERRCODE_SUCC;
 }
 
+/**
+ * @brief 暂停PPP通讯,切换到AT命令模式(不断开连接)
+ * @return ERRCODE_SUCC-成功,其他-失败
+ * 
+ * 功能说明:
+ * 1. 发送 "+++" 转义序列切换到AT命令模式
+ * 2. 停止PPP数据接收线程/中断
+ * 3. 初始化AT处理器
+ * 4. 执行AT测试验证
+ * 
+ * 注意:PPP连接保持,只是暂时切换到AT模式
+ */
+errcode_t ppp_ppp_mode_pause(void)
+{
+    PPP_DEBUG_CRITICAL("=== PPP Pause Started ===");
+    
+    // 检查PPP状态
+    if (g_ppp_state != PPP_STATE_CONNECTED) {
+        PPP_DEBUG_ERROR("PPP not connected, cannot pause (state: %d)", g_ppp_state);
+        return ERRCODE_FAIL;
+    }
+    
+    ppp_error_t ret = PPP_ERR_OK;
+    
+    // 1. 停止PPP数据接收(根据配置选择中断或轮询模式)
+#if PPP_USE_INTERRUPT_MODE
+    PPP_DEBUG_INFO("Disabling PPP interrupt mode...");
+    ppp_interrupt_disable();
+    PPP_DEBUG_INFO("PPP interrupt mode disabled");
+#else
+    PPP_DEBUG_INFO("Stopping PPP receive thread...");
+    ppp_lwip_stop_receive_thread();
+    PPP_DEBUG_INFO("PPP receive thread stopped");
+#endif
+    
+    // 2. 发送 "+++" 转义序列切换到AT命令模式
+    PPP_DEBUG_INFO("Sending escape sequence (+++) to switch to AT mode...");
+    
+    // 根据Hayes标准,转义序列前后需要1秒的静默期
+    osal_msleep(1000);  // 前置静默期
+    
+    const char escape_seq[] = "+++";
+    ret = ppp_serial_write((uint8_t*)escape_seq, strlen(escape_seq));
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to send escape sequence: %d", ret);
+        goto error_recovery;
+    }
+    
+    osal_msleep(1000);  // 后置静默期
+    PPP_DEBUG_INFO("Escape sequence sent, waiting for modem response...");
+    
+    // 3. 等待调制解调器响应(通常是 "OK")
+    osal_msleep(1000);  // 等待响应
+    
+    // 读取调制解调器响应
+    uint8_t response_buffer[64];
+    uint32_t bytes_read = 0;
+    ret = ppp_serial_read(response_buffer, sizeof(response_buffer), &bytes_read);
+    if (ret == PPP_ERR_OK && bytes_read > 0) {
+        PPP_DEBUG_INFO("Modem response to escape sequence: %u bytes", bytes_read);
+        // 可以检查是否包含 "OK"
+        bool found_ok = false;
+        for (uint32_t i = 0; i < bytes_read - 1; i++) {
+            if (response_buffer[i] == 'O' && response_buffer[i+1] == 'K') {
+                found_ok = true;
+                break;
+            }
+        }
+        if (found_ok) {
+            PPP_DEBUG_INFO("Modem confirmed AT mode with OK");
+        } else {
+            PPP_DEBUG_WARN("No OK response from modem, continuing anyway...");
+        }
+    } else {
+        PPP_DEBUG_WARN("No immediate response from modem after escape sequence");
+    }
+    
+    // 4. 切换串口到AT模式
+    PPP_DEBUG_INFO("Switching serial to AT mode...");
+    ret = ppp_serial_switch_to_at_mode();
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to switch to AT mode: %d", ret);
+        goto error_recovery;
+    }
+    
+    // 5. 初始化AT处理器
+    PPP_DEBUG_INFO("Initializing AT handler...");
+    ret = ppp_at_handler_init(SIO_UART_BUS, g_ppp_config.baudrate, true);
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to initialize AT handler: %d", ret);
+        goto error_recovery;
+    }
+    
+    // 6. 测试AT通信
+    PPP_DEBUG_INFO("Testing AT communication...");
+    ret = ppp_at_test_communication();
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_WARN("AT communication test failed: %d", ret);
+        // 尝试第二次
+        osal_msleep(500);
+        ret = ppp_at_test_communication();
+        if (ret != PPP_ERR_OK) {
+            PPP_DEBUG_ERROR("AT communication still failed after retry");
+            goto error_recovery;
+        }
+    }
+    
+    PPP_DEBUG_CRITICAL("=== PPP Paused - Now in AT Mode ===");
+    PPP_DEBUG_INFO("PPP connection is suspended but not terminated");
+    PPP_DEBUG_INFO("Use ppp_resume() to return to PPP data mode");
+    
+    // 更新状态(暂停状态,但保留CONNECTED信息)
+    // 不修改 g_ppp_state,保持 PPP_STATE_CONNECTED
+    
+    return ERRCODE_SUCC;
+
+error_recovery:
+    PPP_DEBUG_ERROR("Failed to pause PPP, attempting to resume data mode...");
+    
+    // 尝试恢复到PPP数据模式
+    ppp_at_handler_deinit();
+    ppp_serial_switch_to_ppp_mode();
+    
+#if PPP_USE_INTERRUPT_MODE
+    ppp_interrupt_enable();
+#else
+    ppp_lwip_start_receive_thread();
+#endif
+    
+    return ERRCODE_FAIL;
+}
+
+/**
+ * @brief 恢复PPP通讯,从AT命令模式返回PPP数据模式
+ * @return ERRCODE_SUCC-成功,其他-失败
+ * 
+ * 功能说明:
+ * 1. 发送 "ATO\r\n" 命令恢复PPP数据模式
+ * 2. 等待 "CONNECT" 响应
+ * 3. 去初始化AT处理器
+ * 4. 恢复PPP数据接收线程/中断
+ * 
+ * 注意:与 ppp_pause() 配对使用
+ */
+errcode_t ppp_ppp_mode_resume(void)
+{
+    PPP_DEBUG_CRITICAL("=== PPP Resume Started ===");
+    
+    // 检查串口模式
+    if (ppp_serial_get_mode() != PPP_SERIAL_MODE_AT) {
+        PPP_DEBUG_ERROR("Serial not in AT mode, cannot resume (mode: %d)", 
+                       ppp_serial_get_mode());
+        return ERRCODE_FAIL;
+    }
+    
+    ppp_error_t ret = PPP_ERR_OK;
+    
+    // 1. 发送 ATO 命令恢复数据模式
+    PPP_DEBUG_INFO("Sending ATO command to resume PPP data mode...");
+    
+    const char ato_cmd[] = "ATO\r\n";
+    ret = ppp_serial_write((uint8_t*)ato_cmd, strlen(ato_cmd));
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to send ATO command: %d", ret);
+        return ERRCODE_FAIL;
+    }
+    
+    PPP_DEBUG_INFO("ATO command sent, waiting for CONNECT response...");
+    
+    // 2. 等待 CONNECT 响应(最多等待10秒)
+    bool connect_found = false;
+    uint8_t response_buffer[128];
+    uint32_t total_wait = 0;
+    const uint32_t max_wait = 10000;  // 10秒超时
+    
+    while (total_wait < max_wait) {
+        uint32_t bytes_read = 0;
+        ret = ppp_serial_read(response_buffer, sizeof(response_buffer), &bytes_read);
+        
+        if (ret == PPP_ERR_OK && bytes_read > 0) {
+            PPP_DEBUG_INFO("Received %u bytes from modem", bytes_read);
+            
+            // 检查是否包含 "CONNECT"
+            for (uint32_t i = 0; i < bytes_read - 6; i++) {
+                if (strncmp((char*)&response_buffer[i], "CONNECT", 7) == 0) {
+                    connect_found = true;
+                    PPP_DEBUG_INFO("Received CONNECT response from modem");
+                    break;
+                }
+            }
+            
+            if (connect_found) {
+                break;
+            }
+        }
+        
+        osal_msleep(500);
+        total_wait += 500;
+    }
+    
+    if (!connect_found) {
+        PPP_DEBUG_ERROR("Timeout waiting for CONNECT response after ATO");
+        return ERRCODE_FAIL;
+    }
+    
+    // 3. 去初始化AT处理器
+    PPP_DEBUG_INFO("Deinitializing AT handler...");
+    ppp_at_handler_deinit();
+    
+    // 4. 切换串口到PPP数据模式
+    PPP_DEBUG_INFO("Switching serial to PPP data mode...");
+    ret = ppp_serial_switch_to_ppp_mode();
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to switch to PPP data mode: %d", ret);
+        return ERRCODE_FAIL;
+    }
+    
+    // 5. 恢复PPP数据接收(根据配置选择中断或轮询模式)
+#if PPP_USE_INTERRUPT_MODE
+    PPP_DEBUG_INFO("Re-enabling PPP interrupt mode...");
+    ret = ppp_interrupt_enable();
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to enable PPP interrupt: %d", ret);
+        return ERRCODE_FAIL;
+    }
+    PPP_DEBUG_INFO("PPP interrupt mode re-enabled");
+#else
+    PPP_DEBUG_INFO("Restarting PPP receive thread...");
+    ret = ppp_lwip_start_receive_thread();
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to restart PPP receive thread: %d", ret);
+        return ERRCODE_FAIL;
+    }
+    PPP_DEBUG_INFO("PPP receive thread restarted");
+#endif
+    
+    PPP_DEBUG_CRITICAL("=== PPP Resumed - Back to Data Mode ===");
+    PPP_DEBUG_INFO("PPP connection restored and active");
+    
+    // 状态保持 PPP_STATE_CONNECTED(未改变)
+    
+    return ERRCODE_SUCC;
+}
+
 /**
  * @brief 停止PPP连接
  */
@@ -1669,9 +1955,45 @@ errcode_t ppp_api_get_default_netif(char* netif_name, uint32_t buffer_size)
     return ERRCODE_SUCC;
 }
 
-// 重复函数定义已删除 - 使用后面的新实现
+errcode_t ppp_api_update_netinfo_in_all_mode(void)
+{
+
+    errcode_t ret = ERRCODE_SUCC;
+    uint8_t need_resume = 0;
+    if(ppp_serial_get_mode() == PPP_SERIAL_MODE_PPP_DATA) {
+        PPP_DEBUG_ERROR("In ppp mode pause it");
+        ppp_ppp_mode_pause();
+        need_resume = 1;
+    }else{
+        PPP_DEBUG_ERROR("In AT mode");
+        need_resume = 0;
+    }
+     // 更新信号强度
+    PPP_DEBUG_CRITICAL("Step 2: Starting signal strength update...");
+    if (ppp_api_update_signal() != ERRCODE_SUCC) {
+        PPP_DEBUG_ERROR("Failed to update signal");
+        ret = ERRCODE_FAIL;
+    } else {
+        PPP_DEBUG_CRITICAL("Step 2: Signal strength update completed successfully");
+    }
+    
+    // 更新网络状态
+    if (ppp_api_update_network_status() != ERRCODE_SUCC) {
+        PPP_DEBUG_ERROR("Failed to update network status");
+        ret = ERRCODE_FAIL;
+    }
+
+    if(ppp_get_network_signal_info() != ERRCODE_SUCC) {
+        PPP_DEBUG_ERROR("Failed to get network signal info");
+        ret = ERRCODE_FAIL;
+    }
 
-// 重复函数定义已删除 - 使用后面的新实现 
+    if( need_resume) {
+        ppp_ppp_mode_resume();
+    }
+     
+    return ret;
+}
 
 /**
  * @brief 获取PPP网络接口的实际名称
index 8e86735..aa6c56f 100644 (file)
@@ -280,6 +280,7 @@ ppp_error_t ppp_at_set_baudrate(uint32_t baudrate)
         PPP_DEBUG_ERROR("Unsupported baudrate: %u", baudrate);
         return PPP_ERR_INVALID_PARAM;
     }
+#ifndef PPP_DO_SERIAL_TEST
 
     /* 先查询当前modem波特率 */
     uint32_t current_modem_baudrate = ppp_query_current_modem_baudrate();
@@ -320,7 +321,9 @@ ppp_error_t ppp_at_set_baudrate(uint32_t baudrate)
         PPP_DEBUG_ERROR("Failed to set baudrate to %u", baudrate);
         return ret;
     }
-
+#else
+    uint32_t current_modem_baudrate = baudrate;
+#endif
     /* 更新串口配置 */
     uart_attr_t uart_attr = {
         .baud_rate = baudrate,
index e03756a..d19877d 100644 (file)
@@ -1,12 +1,13 @@
 /**
  * @file ppp_interrupt.c
- * @brief PPP UART中断接收处理 - 使用消息队列和专用处理线程
+ * @brief PPP UART中断接收处理 - 使用乒乓缓冲区优化
  * 
  * 核心设计:
- * - ISR中只做快速数据复制到动态分配的缓冲区
- * - 通过消息队列传递数据指针到处理线程
- * - 处理线程负责调用pppos_input_tcpip()和释放缓冲区
- * - 避免ISR中执行耗时操作(pbuf_alloc、内存复制、消息队列投递等)
+ * - 使用乒乓缓冲区(2个buffer,每个2KB)避免频繁malloc/free
+ * - ISR中写入当前buffer,满了自动切换到另一个buffer
+ * - 通过消息队列传递buffer索引(而非拷贝数据)
+ * - 定时器监控buffer状态,超时自动flush(30ms)
+ * - 处理线程负责调用pppos_input_tcpip()并释放buffer
  */
 
 #include "ppp_interrupt.h"
@@ -18,6 +19,7 @@
 #include "errcode.h"
 #include "osal_task.h"
 #include "osal_msgqueue.h"
+#include "time/osal_timer.h"
 #include "soc_osal.h"
 #include <string.h>
 #include <stdbool.h>
 #include "netif/ppp/ppp.h"
 #include "netif/ppp/pppos.h"
 
-/* PPP UART硬件缓冲区大小 
- 与uart_porting.c中 UART_RX_BUFFER_SIZE 要一一对应
- #if defined(SUPPORT_PPP_SERVICE)    
- #define UART_RX_BUFFER_SIZE 2048
- #else
- */
-#define PPP_UART_RX_BUFFER_SIZE    2048  // 硬件缓冲区大小(足够容纳MTU 1500 + PPP开销)
+/* 乒乓缓冲区配置 */
+#ifndef PPP_PING_PONG_BUFFER_SIZE
+#define PPP_PING_PONG_BUFFER_SIZE  2048  // 每个buffer大小(2KB)
+#endif
+
+#define PPP_PING_PONG_BUFFER_COUNT 2     // 乒乓buffer数量(固定2个)
+#define PPP_PING_PONG_TIMEOUT_MS   30    // buffer超时时间(30ms)
 
 /* PPP中断消息队列配置 */
-#define PPP_IRQ_MSG_QUEUE_SIZE     128   // 消息队列深度(从32增加到128,应对突发流量)
+#define PPP_IRQ_MSG_QUEUE_SIZE     16    // 队列深度(乒乓模式下无需太大)
 #define PPP_IRQ_PROCESS_TASK_PRIO  24    // 处理线程优先级
 #define PPP_IRQ_PROCESS_STACK_SIZE 4096  // 处理线程栈大小
 
-/* PPP中断数据块结构 - 通过消息队列传递 */
+/* 乒乓缓冲区状态 */
+typedef enum {
+    PPP_BUFFER_STATE_EMPTY = 0,      // 空闲,可以写入
+    PPP_BUFFER_STATE_FILLING,        // 正在填充中
+    PPP_BUFFER_STATE_FULL,           // 已满或超时,等待处理
+    PPP_BUFFER_STATE_PROCESSING      // 正在处理中
+} ppp_buffer_state_t;
+
+/* 乒乓缓冲区结构 */
+typedef struct {
+    uint8_t data[PPP_PING_PONG_BUFFER_SIZE];  // 数据缓冲区
+    volatile uint32_t write_pos;              // 当前写入位置
+    volatile ppp_buffer_state_t state;        // 缓冲区状态
+    volatile uint32_t last_write_time;        // 最后写入时间戳(ms)
+} ppp_ping_pong_buffer_t;
+
+/* PPP中断消息结构 - 通过消息队列传递buffer索引 */
 typedef struct {
-    uint8_t *data;      // 动态分配的数据缓冲区指针
-    uint16_t length;    // 数据长度
-} ppp_irq_data_block_t;
+    uint8_t buffer_index;   // 缓冲区索引(0或1)
+    uint16_t length;        // 数据长度
+} ppp_irq_msg_t;
 
 /* 中断使能标志 */
 static bool g_ppp_interrupt_enabled = false;
@@ -55,169 +73,353 @@ static osal_task *g_ppp_irq_process_task = NULL;
 static unsigned long g_ppp_irq_msg_queue = 0;  // 消息队列ID (OSAL使用unsigned long)
 static volatile bool g_ppp_irq_task_running = false;
 
+/* 乒乓缓冲区 */
+static ppp_ping_pong_buffer_t g_ping_pong_buffers[PPP_PING_PONG_BUFFER_COUNT];
+static volatile uint8_t g_current_buffer_index = 0;  // 当前正在填充的buffer索引
+
+/* 定时器相关 */
+static osal_timer g_ppp_timeout_timer;
+static volatile bool g_ppp_timer_running = false;
+
 /* 统计信息 */
 static ppp_interrupt_stats_t g_ppp_interrupt_stats = {0};
 
+/* 扩展统计信息:乒乓缓冲区相关 */
+typedef struct {
+    uint32_t buffer_full_count;      // buffer满次数
+    uint32_t buffer_timeout_count;   // buffer超时flush次数
+    uint32_t buffer_switch_count;    // buffer切换次数
+    uint32_t dropped_both_full;      // 两个buffer都满导致丢弃的字节数
+} ppp_pingpong_stats_t;
+
+static ppp_pingpong_stats_t g_pingpong_stats = {0};
+
 /* 外部函数声明(在ppp_lwip.c中实现) */
 extern ppp_pcb* ppp_lwip_get_pcb(void);
 extern bool ppp_lwip_is_initialized(void);
 
+/* 内部函数声明 */
+static uint32_t ppp_get_current_time_ms(void);
+static ppp_error_t ppp_flush_buffer(uint8_t buffer_index);
+static void ppp_timeout_timer_callback(unsigned long arg);
+
+/**
+ * @brief 获取当前时间戳(毫秒)
+ */
+static uint32_t ppp_get_current_time_ms(void)
+{
+    unsigned long long jiffies = osal_get_jiffies();
+    return (uint32_t)osal_jiffies_to_msecs((unsigned int)jiffies);
+}
+
 /**
- * @brief PPP中断数据处理线程
- * @note 从消息队列接收数据块,调用pppos_input_tcpip(),然后释放缓冲区
+ * @brief PPP中断数据处理线程(乒乓缓冲区模式)
+ * @note 从消息队列接收buffer索引,直接访问乒乓缓冲区,调用pppos_input_tcpip()
  */
 static void ppp_irq_process_thread(void *arg)
 {
     (void)arg;
-    ppp_irq_data_block_t data_block;
-    unsigned int buffer_size = sizeof(ppp_irq_data_block_t);
-    
-    PPP_DEBUG_INFO("PPP IRQ process thread started");
-    
+    ppp_irq_msg_t msg;
+    unsigned int msg_size = sizeof(ppp_irq_msg_t);
+    
+    PPP_DEBUG_INFO("PPP IRQ process thread started (ping-pong mode)");
+    #ifdef PPP_DO_SERIAL_TEST
+    const uint8_t print_data[] = "PPP IRQ process thread started (ping-pong mode)\n";
+    uapi_uart_write(SIO_UART_BUS, print_data, sizeof(print_data), 100);
+    #endif
     while (g_ppp_irq_task_running) {
-        // 从消息队列读取数据块(阻塞等待)
+        // 从消息队列读取buffer索引消息(阻塞等待)
         int ret = osal_msg_queue_read_copy(
             g_ppp_irq_msg_queue,
-            &data_block,
-            &buffer_size,
+            &msg,
+            &msg_size,
             OSAL_MSGQ_WAIT_FOREVER
         );
         
-        if (ret != OSAL_SUCCESS) {
-            // 读取失败,继续等待
+        if (ret != OSAL_SUCCESS || !g_ppp_irq_task_running) {
             continue;
         }
         
-        // 检查数据有效性
-        if (!data_block.data || data_block.length == 0) {
-            PPP_DEBUG_ERROR("Invalid data block: data=%p, length=%u", 
-                          data_block.data, data_block.length);
-            if (data_block.data) {
-                free(data_block.data);  // 释放无效数据
-            }
+        // 验证buffer索引
+        if (msg.buffer_index >= PPP_PING_PONG_BUFFER_COUNT) {
+            PPP_DEBUG_ERROR("Invalid buffer index: %u", msg.buffer_index);
+            continue;
+        }
+        
+        ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[msg.buffer_index];
+        
+        // 验证数据长度
+        if (msg.length == 0 || msg.length > PPP_PING_PONG_BUFFER_SIZE) {
+            PPP_DEBUG_ERROR("Invalid data length: %u", msg.length);
+            buffer->state = PPP_BUFFER_STATE_EMPTY;
+            buffer->write_pos = 0;
             continue;
         }
         
-        // ===== 注意:不要在此检测"异常帧" =====
-        // 7D 5D、7D 5E 等是PPP协议的正常转义序列,lwIP会自动解码:
-        //   7D 5D → 0x7D (5D ^ 0x20 = 0x7D)
-        //   7D 5E → 0x7E (5E ^ 0x20 = 0x7E)
-        // 大量的7D 5D数据说明原始TCP数据包含很多0x7D字节,这是正常的!
-        // 必须将所有数据交给lwIP的pppos_input处理,不能在此丢弃!
+        // 标记为处理中
+        buffer->state = PPP_BUFFER_STATE_PROCESSING;
         
-        // 打印摘要(减少详细数据打印以提高性能)
-        PPP_DEBUG_DEBUG("PPP Process: %u bytes", data_block.length);
+        // 打印摘要
+        PPP_DEBUG_DEBUG("PPP Process: buffer[%u], %u bytes", msg.buffer_index, msg.length);
         
-        // 只打印前16字节(从64减到16,减少打印开销)
+        // 只打印前16字节
         PPP_DEBUG_PRINT("  Data: ");
-        for (int i = 0; i < data_block.length && i < 16; i++) {
-            PPP_DEBUG_PRINT("%02X ", data_block.data[i]);
+        for (uint32_t i = 0; i < msg.length && i < 16; i++) {
+            PPP_DEBUG_PRINT("%02X ", buffer->data[i]);
         }
-        if (data_block.length > 16) {
-            PPP_DEBUG_PRINT("... (%u more bytes)", data_block.length - 16);
+        if (msg.length > 16) {
+            PPP_DEBUG_PRINT("... (%u more bytes)", msg.length - 16);
         }
         PPP_DEBUG_PRINT("\n");
         
+#ifndef PPP_DO_SERIAL_TEST
         // 获取PPP控制块
         ppp_pcb *ppp_pcb_ptr = ppp_lwip_get_pcb();
         if (!ppp_pcb_ptr || !ppp_lwip_is_initialized()) {
-            PPP_DEBUG_WARN("PPP not initialized, dropping %u bytes", data_block.length);
-            g_ppp_interrupt_stats.dropped_not_initialized += data_block.length;
-            free(data_block.data);
+            PPP_DEBUG_WARN("PPP not initialized, dropping %u bytes", msg.length);
+            g_ppp_interrupt_stats.dropped_not_initialized += msg.length;
+            buffer->state = PPP_BUFFER_STATE_EMPTY;
+            buffer->write_pos = 0;
             continue;
         }
+
         
-        // 调用lwIP的线程安全接口处理PPP数据(仅处理正常帧)
-        // pppos_input_tcpip会:
-        //   1. 分配pbuf
-        //   2. 复制数据到pbuf
-        //   3. 通过tcpip_inpkt()发送到TCPIP线程
-        //   4. TCPIP线程自动调用pppos_input()进行协议解析
-        err_t result = pppos_input_tcpip(ppp_pcb_ptr, data_block.data, data_block.length);
-        
+        // 调用lwIP的线程安全接口处理PPP数据
+        // pppos_input_tcpip会复制数据到pbuf,所以我们可以安全地重用buffer
+        err_t result = pppos_input_tcpip(ppp_pcb_ptr, buffer->data, msg.length);
         if (result != ERR_OK) {
             PPP_DEBUG_WARN("pppos_input_tcpip failed: %d, dropped %u bytes", 
-                          result, data_block.length);
-            g_ppp_interrupt_stats.dropped_lwip_error += data_block.length;
+                          result, msg.length);
+            g_ppp_interrupt_stats.dropped_lwip_error += msg.length;
             g_ppp_interrupt_stats.lwip_error_count++;
         } else {
-            g_ppp_interrupt_stats.total_bytes_sent_to_lwip += data_block.length;
+            g_ppp_interrupt_stats.total_bytes_sent_to_lwip += msg.length;
             g_ppp_interrupt_stats.success_count++;
         }
-        
-        // 释放动态分配的缓冲区
-        free(data_block.data);
+#else
+        err_t result = ERR_OK;
+        uint32_t write_result = uapi_uart_write(SIO_UART_BUS, buffer->data, msg.length, 100);
+        if (write_result != msg.length) {
+            PPP_DEBUG_WARN("uapi_uart_write failed: %d, dropped %u bytes", write_result, msg.length);
+            g_ppp_interrupt_stats.dropped_lwip_error += msg.length;
+            g_ppp_interrupt_stats.lwip_error_count++;
+        } else {
+            PPP_DEBUG_WARN("uapi_uart_write : %u bytes", msg.length);
+            g_ppp_interrupt_stats.total_bytes_sent_to_lwip += msg.length;
+            g_ppp_interrupt_stats.success_count++;
+        }
+#endif
+        // 释放buffer(标记为空闲)
+        buffer->state = PPP_BUFFER_STATE_EMPTY;
+        buffer->write_pos = 0;
     }
     
     PPP_DEBUG_INFO("PPP IRQ process thread exited");
 }
 
 /**
- * @brief UART接收中断回调函数(中断上下文)
- * @note 此函数在中断上下文中调用,必须极快返回(目标<7μs)
+ * @brief 刷新指定buffer到消息队列
+ * @param buffer_index 缓冲区索引
+ * @return PPP_ERR_OK 成功,其他值失败
+ */
+static ppp_error_t ppp_flush_buffer(uint8_t buffer_index)
+{
+    if (buffer_index >= PPP_PING_PONG_BUFFER_COUNT) {
+        return PPP_ERR_INVALID_PARAM;
+    }
+    
+    ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[buffer_index];
+    
+    // 只flush FILLING状态的buffer
+    if (buffer->state != PPP_BUFFER_STATE_FILLING || buffer->write_pos == 0) {
+        return PPP_ERR_OK;  // 没有数据需要flush
+    }
+    
+    // 标记为FULL状态
+    buffer->state = PPP_BUFFER_STATE_FULL;
+    
+    // 准备消息
+    ppp_irq_msg_t msg = {
+        .buffer_index = buffer_index,
+        .length = (uint16_t)buffer->write_pos
+    };
+    
+    // 发送到消息队列(非阻塞)
+    int ret = osal_msg_queue_write_copy(
+        g_ppp_irq_msg_queue,
+        &msg,
+        sizeof(ppp_irq_msg_t),
+        OSAL_MSGQ_NO_WAIT
+    );
+    
+    if (ret != OSAL_SUCCESS) {
+        // 队列满,无法发送,保持FULL状态等待下次重试
+        g_ppp_interrupt_stats.dropped_queue_full += buffer->write_pos;
+        return PPP_ERR_UNKNOWN;
+    }
+    
+    return PPP_ERR_OK;
+}
+
+/**
+ * @brief 定时器回调:检查buffer超时并flush
+ * @note 定时器上下文,应快速返回
+ * @param arg 定时器参数(未使用)
+ * @warning osal_timer默认是one-shot,必须在回调中手动重启实现周期性执行
+ */
+static void ppp_timeout_timer_callback(unsigned long arg)
+{
+    (void)arg;
+    
+    // 增加定时器调用计数(用于诊断)
+    static volatile uint32_t timer_call_count = 0;
+    timer_call_count++;
+    
+    // 每100次(约3秒)打印一次诊断信息
+    if ((timer_call_count % 100) == 1) {
+        PPP_DEBUG_INFO("[TIMER] Callback executed %u times, enabled=%d, running=%d", 
+                      timer_call_count, g_ppp_interrupt_enabled, g_ppp_timer_running);
+    }
+    
+    if (!g_ppp_interrupt_enabled || !g_ppp_timer_running) {
+        return;
+    }
+    
+    uint32_t current_time = ppp_get_current_time_ms();
+    
+    // 检查所有buffer的超时状态
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[i];
+        
+        // 只处理FILLING状态的buffer
+        if (buffer->state == PPP_BUFFER_STATE_FILLING && buffer->write_pos > 0) {
+            uint32_t elapsed = current_time - buffer->last_write_time;
+            
+            // 超时检查
+            if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
+                // 超时,flush buffer
+                PPP_DEBUG_DEBUG("[TIMER] Flushing buffer[%u] due to timeout (%u ms)", i, elapsed);
+                if (ppp_flush_buffer(i) == PPP_ERR_OK) {
+                    g_pingpong_stats.buffer_timeout_count++;
+                    
+                    // ⚠️ 关键修复:Timer flush后切换buffer(类似ISR中buffer满的逻辑)
+                    // 只有当前flush的是正在使用的buffer时才切换
+                    if (i == g_current_buffer_index) {
+                        uint8_t next_idx = (i + 1) % PPP_PING_PONG_BUFFER_COUNT;
+                        ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+                        
+                        if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+                            g_current_buffer_index = next_idx;
+                            g_pingpong_stats.buffer_switch_count++;
+                        }
+                        // 如果next_buffer不是EMPTY,保持当前索引,等待其处理完成
+                    }
+                }
+            }
+        }
+    }
+    
+    // ⚠️ 关键修复:osal_timer是one-shot类型,必须手动重启以实现周期性执行
+    // 不重启的话,定时器只会执行一次!
+    if (g_ppp_timer_running) {
+        osal_timer_start(&g_ppp_timeout_timer);
+    }
+}
+
+/**
+ * @brief UART接收中断回调函数(乒乓缓冲区模式)
+ * @note 中断上下文,必须极快返回
  * 
- * 数据流:
- * 1. UART硬件接收数据 -> 2048字节硬件缓冲区
- * 2. 触发中断回调(本函数)
- * 3. 快速复制数据到动态分配的缓冲区(~1-3μs)
- * 4. 将缓冲区指针发送到消息队列(~1-2μs)
- * 5. 返回(总耗时<7μs,远低于之前的20-50μs)
- * 6. 处理线程接收数据并调用pppos_input_tcpip()
+ * 优化策略:
+ * 1. 写入当前buffer(memcpy,~60字节 < 1μs)
+ * 2. buffer满了直接flush并切换(~2μs)
+ * 3. 无malloc/free,减少内存碎片和延迟
+ * 4. 总耗时目标:< 5μs(比之前的7μs更快)
  */
 void _ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error)
 {
     // 快速路径:参数校验
-    if (error || !buffer || length == 0 || length > PPP_UART_RX_BUFFER_SIZE) {
+    if (error || !buffer || length == 0 || length > 200) {  // 单次中断最多200字节
         if (error) {
             g_ppp_interrupt_stats.error_count++;
         }
         return;
     }
     
-    // 更新接收统计
+    // 更新统计(用于诊断 - 可以在统计打印中看到)
     g_ppp_interrupt_stats.total_interrupts++;
     g_ppp_interrupt_stats.total_bytes_received += length;
     
-    // ⚠️ 中断中禁止打印!打印会导致严重延迟(1-10ms vs 目标<7μs)
-    // 所有日志都在处理线程中打印
-    
-    // 动态分配缓冲区(使用malloc,~1-2μs)
-    uint8_t *data_copy = (uint8_t *)malloc(length);
-    if (!data_copy) {
-        // 内存分配失败,丢弃数据
-        g_ppp_interrupt_stats.dropped_malloc_fail += length;
-        // ⚠️ 中断中禁止打印!统计已记录,错误会在线程中通过统计信息体现
-        return;
+    // 诊断:每10次中断增加一个标记(避免频繁打印)
+    static volatile uint32_t irq_count_marker = 0;
+    if ((g_ppp_interrupt_stats.total_interrupts % 10) == 1) {
+        irq_count_marker = g_ppp_interrupt_stats.total_interrupts;
+        // 不能在中断中打印,但可以更新这个全局变量,在统计中查看
     }
     
-    // 快速复制数据(~1-3μs for 2KB @ 1GB/s memcpy speed)
-    memcpy(data_copy, buffer, length);
+    // ⚠️ 中断中禁止打印!
     
-    // 准备消息队列数据块
-    ppp_irq_data_block_t data_block = {
-        .data = data_copy,
-        .length = length
-    };
+    // 获取当前buffer
+    uint8_t current_idx = g_current_buffer_index;
+    ppp_ping_pong_buffer_t *current_buffer = &g_ping_pong_buffers[current_idx];
     
-    // 发送到消息队列(非阻塞,~1-2μs)
-    int ret = osal_msg_queue_write_copy(
-        g_ppp_irq_msg_queue,
-        &data_block,
-        sizeof(ppp_irq_data_block_t),
-        OSAL_MSGQ_NO_WAIT  // 非阻塞
-    );
+    // 尝试写入当前buffer
+    uint32_t available = PPP_PING_PONG_BUFFER_SIZE - current_buffer->write_pos;
     
-    if (ret != OSAL_SUCCESS) {
-        // 消息队列满,丢弃数据
-        g_ppp_interrupt_stats.dropped_queue_full += length;
-        free(data_copy);
-        // ⚠️ 中断中禁止打印!统计已记录,队列满错误会在线程中通过统计信息体现
-        return;
+    if (current_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+        // buffer是空的,初始化为FILLING状态
+        current_buffer->state = PPP_BUFFER_STATE_FILLING;
+        current_buffer->write_pos = 0;
     }
     
-    // 成功入队
-    // 总耗时估算:malloc(1-2μs) + memcpy(1-3μs) + queue_write(1-2μs) ≈ 3-7μs
-    // ✓ 无打印,实际耗时符合设计目标
+    if (current_buffer->state == PPP_BUFFER_STATE_FILLING && length <= available) {
+        // 空间足够,直接写入
+        memcpy(current_buffer->data + current_buffer->write_pos, buffer, length);
+        current_buffer->write_pos += length;
+        current_buffer->last_write_time = ppp_get_current_time_ms();
+        
+        // 检查是否满了
+        if (current_buffer->write_pos >= PPP_PING_PONG_BUFFER_SIZE) {
+            // buffer满,flush
+            ppp_flush_buffer(current_idx);
+            g_pingpong_stats.buffer_full_count++;
+            
+            // 切换到另一个buffer
+            uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+            ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+            
+            if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+                g_current_buffer_index = next_idx;
+                g_pingpong_stats.buffer_switch_count++;
+            }
+            // 如果next_buffer不是EMPTY,保持当前索引,下次数据会被丢弃
+        }
+    } else {
+        // 当前buffer空间不足或不可用,尝试切换到另一个buffer
+        uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+        ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+        
+        if (next_buffer->state == PPP_BUFFER_STATE_EMPTY && length <= PPP_PING_PONG_BUFFER_SIZE) {
+            // 先flush当前buffer(如果有数据)
+            if (current_buffer->state == PPP_BUFFER_STATE_FILLING && current_buffer->write_pos > 0) {
+                ppp_flush_buffer(current_idx);
+            }
+            
+            // 切换到新buffer
+            g_current_buffer_index = next_idx;
+            g_pingpong_stats.buffer_switch_count++;
+            
+            // 写入新buffer
+            next_buffer->state = PPP_BUFFER_STATE_FILLING;
+            next_buffer->write_pos = 0;
+            memcpy(next_buffer->data, buffer, length);
+            next_buffer->write_pos = length;
+            next_buffer->last_write_time = ppp_get_current_time_ms();
+        } else {
+            // 两个buffer都不可用,丢弃数据
+            g_pingpong_stats.dropped_both_full += length;
+        }
+    }
 }
 
 void ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error)
@@ -227,7 +429,7 @@ void ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool err
 }
 
 /**
- * @brief 启用PPP UART中断接收
+ * @brief 启用PPP UART中断接收(乒乓缓冲区模式)
  * @return PPP_ERR_OK 成功,其他值失败
  */
 ppp_error_t ppp_interrupt_enable(void)
@@ -237,15 +439,28 @@ ppp_error_t ppp_interrupt_enable(void)
         return PPP_ERR_OK;
     }
     
-    PPP_DEBUG_INFO("Enabling PPP UART interrupt mode");
+    PPP_DEBUG_INFO("Enabling PPP UART interrupt mode (ping-pong buffer)");
+    
+    // 1. 初始化乒乓缓冲区
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        g_ping_pong_buffers[i].write_pos = 0;
+        g_ping_pong_buffers[i].state = PPP_BUFFER_STATE_EMPTY;
+        g_ping_pong_buffers[i].last_write_time = 0;
+        memset(g_ping_pong_buffers[i].data, 0, PPP_PING_PONG_BUFFER_SIZE);
+    }
+    g_current_buffer_index = 0;
+    
+    PPP_DEBUG_INFO("Ping-pong buffers initialized: %d x %d bytes = %d KB total", 
+                  PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE,
+                  (PPP_PING_PONG_BUFFER_COUNT * PPP_PING_PONG_BUFFER_SIZE) / 1024);
     
-    // 1. 创建消息队列
+    // 2. 创建消息队列(只传递buffer索引,所以队列可以更小)
     int ret = osal_msg_queue_create(
         "ppp_irq_queue",
         PPP_IRQ_MSG_QUEUE_SIZE,
         &g_ppp_irq_msg_queue,
         0,
-        sizeof(ppp_irq_data_block_t)
+        sizeof(ppp_irq_msg_t)
     );
     
     if (ret != OSAL_SUCCESS) {
@@ -253,10 +468,10 @@ ppp_error_t ppp_interrupt_enable(void)
         return PPP_ERR_MEMORY;
     }
     
-    PPP_DEBUG_INFO("Message queue created (depth=%d, item_size=%d)", 
-                  PPP_IRQ_MSG_QUEUE_SIZE, sizeof(ppp_irq_data_block_t));
+    PPP_DEBUG_INFO("Message queue created (depth=%d, item_size=%d bytes)", 
+                  PPP_IRQ_MSG_QUEUE_SIZE, sizeof(ppp_irq_msg_t));
     
-    // 2. 启动处理线程
+    // 3. 启动处理线程
     g_ppp_irq_task_running = true;
     
     osal_kthread_lock();
@@ -275,37 +490,85 @@ ppp_error_t ppp_interrupt_enable(void)
         return PPP_ERR_MEMORY;
     }
     
-    PPP_DEBUG_INFO("Process thread created (stack=%d, prio=%d)", 
-                  PPP_IRQ_PROCESS_STACK_SIZE, PPP_IRQ_PROCESS_TASK_PRIO);
+    PPP_DEBUG_INFO("Process thread created (stack=%d)", PPP_IRQ_PROCESS_STACK_SIZE);
+    
+    // 4. 启动定时器(30ms周期检查buffer超时)
+    // 先设置timer的handler、data和interval
+    g_ppp_timeout_timer.handler = ppp_timeout_timer_callback;
+    g_ppp_timeout_timer.data = 0;
+    g_ppp_timeout_timer.interval = PPP_PING_PONG_TIMEOUT_MS;
+    
+    ret = osal_timer_init(&g_ppp_timeout_timer);
+    if (ret != OSAL_SUCCESS) {
+        PPP_DEBUG_ERROR("Failed to init timeout timer: 0x%x", ret);
+        g_ppp_irq_task_running = false;
+        osal_msleep(100);
+        osal_msg_queue_delete(g_ppp_irq_msg_queue);
+        return PPP_ERR_MEMORY;
+    }
+    
+    g_ppp_timer_running = true;
+    ret = osal_timer_start(&g_ppp_timeout_timer);
+    if (ret != OSAL_SUCCESS) {
+        PPP_DEBUG_ERROR("Failed to start timeout timer: 0x%x", ret);
+        g_ppp_timer_running = false;
+        g_ppp_irq_task_running = false;
+        osal_timer_destroy(&g_ppp_timeout_timer);
+        osal_msleep(100);
+        osal_msg_queue_delete(g_ppp_irq_msg_queue);
+        return PPP_ERR_MEMORY;
+    }
+    
+    PPP_DEBUG_INFO("Timeout timer started (period=%d ms)", PPP_PING_PONG_TIMEOUT_MS);
     
-    // 3. 注册UART中断回调
+    // 5. 注册UART中断回调
     uint8_t uart_bus = ppp_serial_get_uart_bus();
     
+    PPP_DEBUG_INFO("Registering UART RX callback:");
+    PPP_DEBUG_INFO("  UART Bus: %d", uart_bus);
+    PPP_DEBUG_INFO("  Condition: 0x07 (FULL_OR_SUFFICIENT_DATA_OR_IDLE)");
+    PPP_DEBUG_INFO("  Threshold: 56 bytes");
+    PPP_DEBUG_INFO("  Callback: ppp_uart_rx_interrupt_handler @ %p", ppp_uart_rx_interrupt_handler);
+    
+    // ⚠️ 关键修复:降低阈值从200到56字节,确保小数据包也能触发中断
+    // PPP LCP/IPCP响应通常只有30-50字节,200字节阈值太高会导致无法触发
     ret = uapi_uart_register_rx_callback(
         uart_bus,
         0x07,  // UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE
-        PPP_UART_RX_BUFFER_SIZE,
+        8,    // 56字节阈值
         ppp_uart_rx_interrupt_handler
     );
     
+    PPP_DEBUG_INFO("uapi_uart_register_rx_callback returned: 0x%x (ERRCODE_SUCC=0x%x)", 
+                  ret, ERRCODE_SUCC);
+    
     if (ret != ERRCODE_SUCC) {
         PPP_DEBUG_ERROR("Failed to register UART RX callback: 0x%x", ret);
         
         // 清理资源
+        g_ppp_timer_running = false;
+        osal_timer_stop(&g_ppp_timeout_timer);
+        osal_timer_destroy(&g_ppp_timeout_timer);
         g_ppp_irq_task_running = false;
-        osal_msleep(100);  // 等待线程退出
+        osal_msleep(100);
         osal_msg_queue_delete(g_ppp_irq_msg_queue);
         
         return PPP_ERR_UART;
     }
     
+    PPP_DEBUG_INFO("UART RX callback registered successfully!");
+    
     g_ppp_interrupt_enabled = true;
     
-    PPP_DEBUG_INFO("PPP UART interrupt enabled successfully");
-    PPP_DEBUG_INFO("  Hardware buffer: %d bytes", PPP_UART_RX_BUFFER_SIZE);
-    PPP_DEBUG_INFO("  Message queue: %d slots", PPP_IRQ_MSG_QUEUE_SIZE);
-    PPP_DEBUG_INFO("  ISR latency: <7μs (malloc + memcpy + queue_write)");
-    PPP_DEBUG_INFO("  Data flow: UART IRQ -> malloc/memcpy -> msg_queue -> process_thread -> pppos_input_tcpip");
+    PPP_DEBUG_INFO("PPP UART interrupt enabled successfully (ping-pong mode)");
+    PPP_DEBUG_INFO("  Ping-pong buffers: %d x %d KB", 
+                  PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE / 1024);
+    PPP_DEBUG_INFO("  Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
+    PPP_DEBUG_INFO("  Message queue: %d slots (only %d bytes per message)", 
+                  PPP_IRQ_MSG_QUEUE_SIZE, sizeof(ppp_irq_msg_t));
+    PPP_DEBUG_INFO("  ISR latency: <5μs (memcpy + queue_write, no malloc!)");
+    PPP_DEBUG_INFO("  Data flow: UART IRQ -> ping-pong buffer -> timer/full flush -> msg_queue -> process_thread -> pppos_input_tcpip");
+    PPP_DEBUG_INFO("  DIAGNOSTIC: Watch for [TIMER] and interrupt stats in ppp_interrupt_print_stats()");
     
     return PPP_ERR_OK;
 }
@@ -319,26 +582,42 @@ ppp_error_t ppp_interrupt_disable(void)
         return PPP_ERR_OK;
     }
     
-    PPP_DEBUG_INFO("Disabling PPP UART interrupt");
+    PPP_DEBUG_INFO("Disabling PPP UART interrupt (ping-pong mode)");
     
     // 1. 注销UART中断回调
     uint8_t uart_bus = ppp_serial_get_uart_bus();
     uapi_uart_unregister_rx_callback(uart_bus);
     
-    // 2. 停止处理线程
+    // 2. 停止定时器
+    if (g_ppp_timer_running) {
+        g_ppp_timer_running = false;
+        osal_timer_stop(&g_ppp_timeout_timer);
+        osal_timer_destroy(&g_ppp_timeout_timer);
+        PPP_DEBUG_INFO("Timeout timer stopped");
+    }
+    
+    // 3. 停止处理线程
     g_ppp_irq_task_running = false;
     
     // 发送一个空消息以唤醒线程(如果阻塞在队列读取)
-    ppp_irq_data_block_t empty_block = {0};
-    osal_msg_queue_write_copy(g_ppp_irq_msg_queue, &empty_block, 
-                             sizeof(ppp_irq_data_block_t), OSAL_MSGQ_NO_WAIT);
+    ppp_irq_msg_t empty_msg = {0};
+    osal_msg_queue_write_copy(g_ppp_irq_msg_queue, &empty_msg, 
+                             sizeof(ppp_irq_msg_t), OSAL_MSGQ_NO_WAIT);
     
     // 等待线程退出
     osal_msleep(200);
     
-    // 3. 删除消息队列
+    // 4. 删除消息队列
     osal_msg_queue_delete(g_ppp_irq_msg_queue);
     
+    // 5. 清空乒乓缓冲区
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        g_ping_pong_buffers[i].write_pos = 0;
+        g_ping_pong_buffers[i].state = PPP_BUFFER_STATE_EMPTY;
+        g_ping_pong_buffers[i].last_write_time = 0;
+    }
+    g_current_buffer_index = 0;
+    
     g_ppp_interrupt_enabled = false;
     g_ppp_irq_process_task = NULL;
     
@@ -371,51 +650,91 @@ void ppp_interrupt_get_stats(ppp_interrupt_stats_t *stats)
 void ppp_interrupt_reset_stats(void)
 {
     memset(&g_ppp_interrupt_stats, 0, sizeof(ppp_interrupt_stats_t));
-    PPP_DEBUG_INFO("PPP interrupt statistics reset");
+    memset(&g_pingpong_stats, 0, sizeof(ppp_pingpong_stats_t));
+    PPP_DEBUG_INFO("PPP interrupt statistics reset (including ping-pong stats)");
 }
 
 /**
- * @brief 打印中断统计信息
+ * @brief 打印中断统计信息(乒乓缓冲区模式)
  */
 void ppp_interrupt_print_stats(void)
 {
-    PPP_DEBUG_INFO("=== PPP Interrupt Statistics ===");
+    PPP_DEBUG_INFO("=== PPP Interrupt Statistics (Ping-Pong Mode) ===");
     PPP_DEBUG_INFO("Interrupt Status: %s", g_ppp_interrupt_enabled ? "ENABLED" : "DISABLED");
-    PPP_DEBUG_INFO("Hardware Buffer: %d bytes", PPP_UART_RX_BUFFER_SIZE);
-    PPP_DEBUG_INFO("Message Queue: %d slots (capacity: ~%d KB)", 
-                   PPP_IRQ_MSG_QUEUE_SIZE, 
-                   (PPP_IRQ_MSG_QUEUE_SIZE * PPP_UART_RX_BUFFER_SIZE) / 1024);
+    PPP_DEBUG_INFO("Ping-Pong Buffers: %d x %d bytes = %d KB total", 
+                   PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE,
+                   (PPP_PING_PONG_BUFFER_COUNT * PPP_PING_PONG_BUFFER_SIZE) / 1024);
+    PPP_DEBUG_INFO("Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
+    PPP_DEBUG_INFO("Message Queue: %d slots (%d bytes per message)", 
+                   PPP_IRQ_MSG_QUEUE_SIZE, sizeof(ppp_irq_msg_t));
+    PPP_DEBUG_INFO("");
+    
+    // 乒乓缓冲区状态
+    PPP_DEBUG_INFO("Buffer Status:");
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        const char *state_str = "UNKNOWN";
+        switch (g_ping_pong_buffers[i].state) {
+            case PPP_BUFFER_STATE_EMPTY:      state_str = "EMPTY"; break;
+            case PPP_BUFFER_STATE_FILLING:    state_str = "FILLING"; break;
+            case PPP_BUFFER_STATE_FULL:       state_str = "FULL"; break;
+            case PPP_BUFFER_STATE_PROCESSING: state_str = "PROCESSING"; break;
+        }
+        PPP_DEBUG_INFO("  Buffer[%u]: %s, %u/%u bytes%s", 
+                      i, state_str, g_ping_pong_buffers[i].write_pos, PPP_PING_PONG_BUFFER_SIZE,
+                      (i == g_current_buffer_index) ? " (current)" : "");
+    }
+    PPP_DEBUG_INFO("");
+    
+    // 乒乓缓冲区统计
+    PPP_DEBUG_INFO("Ping-Pong Buffer Statistics:");
+    PPP_DEBUG_INFO("  Buffer Full Count: %u", g_pingpong_stats.buffer_full_count);
+    PPP_DEBUG_INFO("  Buffer Timeout Count: %u", g_pingpong_stats.buffer_timeout_count);
+    PPP_DEBUG_INFO("  Buffer Switch Count: %u", g_pingpong_stats.buffer_switch_count);
+    PPP_DEBUG_INFO("  Dropped (Both Full): %u bytes ⚠️", g_pingpong_stats.dropped_both_full);
     PPP_DEBUG_INFO("");
+    
+    // 中断统计
     PPP_DEBUG_INFO("Total Interrupts: %u", g_ppp_interrupt_stats.total_interrupts);
     PPP_DEBUG_INFO("  - Success: %u", g_ppp_interrupt_stats.success_count);
     PPP_DEBUG_INFO("  - Error: %u", g_ppp_interrupt_stats.error_count);
     PPP_DEBUG_INFO("  - lwIP Error: %u", g_ppp_interrupt_stats.lwip_error_count);
     PPP_DEBUG_INFO("");
+    
+    // 字节统计
     PPP_DEBUG_INFO("Total Bytes Received: %u", g_ppp_interrupt_stats.total_bytes_received);
     PPP_DEBUG_INFO("Total Bytes Sent to lwIP: %u", g_ppp_interrupt_stats.total_bytes_sent_to_lwip);
     PPP_DEBUG_INFO("");
+    
+    // 丢弃统计
     PPP_DEBUG_INFO("Dropped Bytes:");
     PPP_DEBUG_INFO("  - Not Initialized: %u", g_ppp_interrupt_stats.dropped_not_initialized);
     PPP_DEBUG_INFO("  - lwIP Error: %u", g_ppp_interrupt_stats.dropped_lwip_error);
-    PPP_DEBUG_INFO("  - malloc Failed: %u", g_ppp_interrupt_stats.dropped_malloc_fail);
-    PPP_DEBUG_INFO("  - Queue Full: %u ⚠️", g_ppp_interrupt_stats.dropped_queue_full);
+    PPP_DEBUG_INFO("  - Queue Full: %u", g_ppp_interrupt_stats.dropped_queue_full);
+    PPP_DEBUG_INFO("  - Both Buffers Full: %u ⚠️", g_pingpong_stats.dropped_both_full);
     PPP_DEBUG_INFO("");
     
-    // 计算丢包率和队列满率
+    // 计算丢包率
     if (g_ppp_interrupt_stats.total_bytes_received > 0) {
         uint32_t total_dropped = g_ppp_interrupt_stats.dropped_not_initialized + 
                                  g_ppp_interrupt_stats.dropped_lwip_error +
-                                 g_ppp_interrupt_stats.dropped_malloc_fail +
-                                 g_ppp_interrupt_stats.dropped_queue_full;
+                                 g_ppp_interrupt_stats.dropped_queue_full +
+                                 g_pingpong_stats.dropped_both_full;
         uint32_t drop_rate = (total_dropped * 10000) / g_ppp_interrupt_stats.total_bytes_received;
-        PPP_DEBUG_INFO("Drop Rate: %u.%02u%%", drop_rate / 100, drop_rate % 100);
+        PPP_DEBUG_INFO("Total Drop Rate: %u.%02u%%", drop_rate / 100, drop_rate % 100);
         
         // 队列满导致的丢失率
         if (g_ppp_interrupt_stats.dropped_queue_full > 0) {
             uint32_t queue_full_rate = (g_ppp_interrupt_stats.dropped_queue_full * 10000) / 
                                        g_ppp_interrupt_stats.total_bytes_received;
-            PPP_DEBUG_WARN("Queue Full Rate: %u.%02u%% ⚠️ (consider increasing queue size)", 
-                          queue_full_rate / 100, queue_full_rate % 100);
+            PPP_DEBUG_INFO("Queue Full Rate: %u.%02u%%", queue_full_rate / 100, queue_full_rate % 100);
+        }
+        
+        // 两个buffer都满导致的丢失率
+        if (g_pingpong_stats.dropped_both_full > 0) {
+            uint32_t both_full_rate = (g_pingpong_stats.dropped_both_full * 10000) / 
+                                     g_ppp_interrupt_stats.total_bytes_received;
+            PPP_DEBUG_WARN("Both Buffers Full Rate: %u.%02u%% ⚠️ (processing too slow or buffers too small)", 
+                          both_full_rate / 100, both_full_rate % 100);
         }
     }
     
@@ -423,8 +742,14 @@ void ppp_interrupt_print_stats(void)
     if (g_ppp_interrupt_stats.success_count > 0) {
         uint32_t avg_bytes = g_ppp_interrupt_stats.total_bytes_sent_to_lwip / 
                             g_ppp_interrupt_stats.success_count;
-        PPP_DEBUG_INFO("Average bytes per packet: %u", avg_bytes);
+        PPP_DEBUG_INFO("Average bytes per message: %u", avg_bytes);
+    }
+    
+    if (g_ppp_interrupt_stats.total_interrupts > 0) {
+        uint32_t avg_bytes_per_irq = g_ppp_interrupt_stats.total_bytes_received / 
+                                     g_ppp_interrupt_stats.total_interrupts;
+        PPP_DEBUG_INFO("Average bytes per interrupt: %u", avg_bytes_per_irq);
     }
     
-    PPP_DEBUG_INFO("================================");
+    PPP_DEBUG_INFO("=================================================");
 } 
\ No newline at end of file
index 6610322..df32dca 100644 (file)
@@ -1,10 +1,12 @@
 /**
  * @file ppp_lwip_thread.c
- * @brief PPP接收线程实现 - 支持单线程和双线程模式
+ * @brief PPP接收线程实现 - 乒乓缓冲区轮询模式(双线程)
  * 
- * 线程模式配置:
- * - PPP_USE_DUAL_THREAD=1: 双线程模式(接收线程拼包 + 处理线程处理)
- * - PPP_USE_DUAL_THREAD=0: 单线程模式(接收线程直接处理)
+ * 设计思路:
+ * - 接收线程:轮询UART读取数据,填充到乒乓buffer
+ * - 处理线程:从消息队列获取buffer索引,调用lwIP处理
+ * - 用轮询替代中断,避免UART中断配置问题
+ * - 保留乒乓buffer的高效性和低延迟优势
  */
 
 #include "ppp_api.h"
 #include "soc_osal.h"
 #include "schedule/osal_task.h"
 #include "msgqueue/osal_msgqueue.h"
+#include "time/osal_timer.h"
 #include "custom_utils.h"
 #include <stdlib.h>
 #include <string.h>
 
-/* PPP接收模式配置(中断相关代码已移除,使用独立的ppp_interrupt模块) */
+/* lwIP相关头文件 */
+#include "lwip/err.h"
+#include "netif/ppp/ppp.h"
+#include "netif/ppp/pppos.h"
 
-/* PPP线程模式配置 */
-#ifndef PPP_USE_DUAL_THREAD
-#define PPP_USE_DUAL_THREAD     0       // 默认使用双线程模式
+/* 乒乓缓冲区配置 */
+#ifndef PPP_PING_PONG_BUFFER_SIZE
+#define PPP_PING_PONG_BUFFER_SIZE  2048  // 每个buffer大小(2KB)
 #endif
 
-#if PPP_USE_DUAL_THREAD
-#define PPP_THREAD_MODE_STR     "DUAL_THREAD"
-#else
-#define PPP_THREAD_MODE_STR     "SINGLE_THREAD"
-#endif
+#define PPP_PING_PONG_BUFFER_COUNT 2     // 乒乓buffer数量(固定2个)
+#define PPP_PING_PONG_TIMEOUT_MS   60    // buffer超时时间(30ms)
+
+/* PPP消息队列配置 */
+#define PPP_MSG_QUEUE_SIZE         16    // 队列深度
+#define PPP_PROCESS_TASK_PRIO      24    // 处理线程优先级
+#define PPP_PROCESS_STACK_SIZE     4096  // 处理线程栈大小
+#define PPP_RX_STACK_SIZE          4096  // 接收线程栈大小
 
-/* PPP帧队列相关(仅双线程模式使用) */
-#if PPP_USE_DUAL_THREAD
-#define PPP_FRAME_QUEUE_SIZE    32      // 队列大小
-#define PPP_MAX_FRAME_SIZE      2048    // 从1500增加到2048
+/* 乒乓缓冲区状态 */
+typedef enum {
+    PPP_BUFFER_STATE_EMPTY = 0,      // 空闲,可以写入
+    PPP_BUFFER_STATE_FILLING,        // 正在填充中
+    PPP_BUFFER_STATE_FULL,           // 已满或超时,等待处理
+    PPP_BUFFER_STATE_PROCESSING      // 正在处理中
+} ppp_buffer_state_t;
 
-/* PPP帧结构(仅双线程模式使用) */
+/* 乒乓缓冲区结构 */
 typedef struct {
-    uint8_t *data;      // 帧数据
-    uint32_t length;    // 帧长度
-} ppp_frame_t;
-#endif
+    uint8_t data[PPP_PING_PONG_BUFFER_SIZE];  // 数据缓冲区
+    volatile uint32_t write_pos;              // 当前写入位置
+    volatile ppp_buffer_state_t state;        // 缓冲区状态
+    volatile uint32_t last_write_time;        // 最后写入时间戳(ms)
+} ppp_ping_pong_buffer_t;
 
-/* PPP字节丢弃统计结构已在ppp_types.h中定义 */
+/* PPP消息结构 - 通过消息队列传递buffer索引 */
+typedef struct {
+    uint8_t buffer_index;   // 缓冲区索引(0或1)
+    uint16_t length;        // 数据长度
+} ppp_msg_t;
 
 /* PPP线程相关 */
 static uint32_t g_ppp_rx_thread_handle = 0;         // 接收线程句柄
-#if PPP_USE_DUAL_THREAD
-static uint32_t g_ppp_process_thread_handle = 0;    // 处理线程句柄(仅双线程模式)
-#endif
+static uint32_t g_ppp_process_thread_handle = 0;    // 处理线程句柄
 static volatile bool g_ppp_rx_thread_running = false;
-#if PPP_USE_DUAL_THREAD
 static volatile bool g_ppp_process_thread_running = false;
-#endif
 static volatile bool g_ppp_rx_thread_completed = false;
-#if PPP_USE_DUAL_THREAD
 static volatile bool g_ppp_process_thread_completed = false;
-#endif
 
-/* PPP帧队列(仅双线程模式使用) */
-#if PPP_USE_DUAL_THREAD
-static unsigned long g_ppp_frame_queue = 0xFFFFFFFFu;
-#endif
+/* 消息队列 */
+static unsigned long g_ppp_msg_queue = 0;
+
+/* 乒乓缓冲区 */
+static ppp_ping_pong_buffer_t g_ping_pong_buffers[PPP_PING_PONG_BUFFER_COUNT];
+static volatile uint8_t g_current_buffer_index = 0;  // 当前正在填充的buffer索引
+
+/* 定时器相关 */
+static osal_timer g_ppp_timeout_timer;
+static volatile bool g_ppp_timer_running = false;
 
-/* PPP丢弃统计 */
-static ppp_discard_stats_t g_ppp_discard_stats = {0};
+/* 统计信息 */
+typedef struct {
+    uint32_t total_bytes_received;      // 总接收字节数
+    uint32_t total_bytes_processed;     // 总处理字节数
+    uint32_t total_bytes_discarded;     // 总丢弃字节数
+    uint32_t buffer_full_count;         // buffer满次数
+    uint32_t buffer_timeout_count;      // buffer超时flush次数
+    uint32_t buffer_switch_count;       // buffer切换次数
+    uint32_t dropped_both_full;         // 两个buffer都满导致丢弃的字节数
+    uint32_t dropped_queue_full;        // 队列满导致丢弃的字节数
+    uint32_t lwip_error_count;          // lwIP错误次数
+    uint32_t read_count;                // UART读取次数
+    uint32_t read_empty_count;          // UART读取为空次数
+} ppp_polling_stats_t;
+
+static ppp_polling_stats_t g_ppp_stats = {0};
+
+/* 外部函数声明 */
+extern ppp_pcb* ppp_lwip_get_pcb(void);
+extern bool ppp_lwip_is_initialized(void);
+
+/* 内部函数声明 */
+static uint32_t ppp_get_current_time_ms(void);
+static ppp_error_t ppp_flush_buffer(uint8_t buffer_index);
+static void ppp_timeout_timer_callback(unsigned long arg);
 
-static ppp_error_t ppp_process_data_block(const uint8_t *data, uint32_t length);
+/**
+ * @brief 获取当前时间戳(毫秒)
+ */
+static uint32_t ppp_get_current_time_ms(void)
+{
+    unsigned long long jiffies = osal_get_jiffies();
+    return (uint32_t)osal_jiffies_to_msecs((unsigned int)jiffies);
+}
 
 /**
- * @brief 处理PPP数据并打印详细信息(单线程模式专用)
+ * @brief 刷新指定buffer到消息队列
+ * @param buffer_index 缓冲区索引
+ * @return PPP_ERR_OK 成功,其他值失败
  */
-static ppp_error_t ppp_process_and_print_data(const uint8_t *data, uint32_t length)
+static ppp_error_t ppp_flush_buffer(uint8_t buffer_index)
 {
-    if (!data || length == 0) {
+    if (buffer_index >= PPP_PING_PONG_BUFFER_COUNT) {
         return PPP_ERR_INVALID_PARAM;
     }
     
-    // 打印详细的接收数据(在处理阶段,不影响接收效率)
-    PPP_DEBUG_INFO("PPP Processing: %u bytes", length);
-    PPP_DEBUG_PRINT("PPP RX Data: ");
-    for (uint32_t i = 0; i < length; i++) {
-        PPP_DEBUG_PRINT("%02X ", data[i]);
-        // 每16字节换行,便于阅读
-        if ((i + 1) % 16 == 0) {
-            PPP_DEBUG_PRINT("\n             ");
-        }
+    ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[buffer_index];
+    
+    // 只flush FILLING状态的buffer
+    if (buffer->state != PPP_BUFFER_STATE_FILLING || buffer->write_pos == 0) {
+        return PPP_ERR_OK;  // 没有数据需要flush
     }
-    PPP_DEBUG_PRINT("\n");
-    
-    // 调用lwIP处理
-    ppp_error_t lwip_ret = ppp_lwip_input(data, length);
-    if (lwip_ret != PPP_ERR_OK) {
-        PPP_DEBUG_WARN("lwIP input failed: %d", lwip_ret);
-        return lwip_ret;
-    } else {
-        PPP_DEBUG_DEBUG("PPP data processed successfully by lwIP");
-        return PPP_ERR_OK;
+    
+    // 标记为FULL状态
+    buffer->state = PPP_BUFFER_STATE_FULL;
+    
+    // 准备消息
+    ppp_msg_t msg = {
+        .buffer_index = buffer_index,
+        .length = (uint16_t)buffer->write_pos
+    };
+    
+    // 发送到消息队列(非阻塞)
+    int ret = osal_msg_queue_write_copy(
+        g_ppp_msg_queue,
+        &msg,
+        sizeof(ppp_msg_t),
+        OSAL_MSGQ_NO_WAIT
+    );
+    
+    if (ret != OSAL_SUCCESS) {
+        // 队列满,无法发送
+        g_ppp_stats.dropped_queue_full += buffer->write_pos;
+        buffer->state = PPP_BUFFER_STATE_FILLING;  // 恢复状态,等待下次重试
+        return PPP_ERR_UNKNOWN;
     }
+    
+    return PPP_ERR_OK;
 }
 
-#if PPP_USE_DUAL_THREAD
 /**
- * @brief å¤\84ç\90\86æ\8e¥æ\94¶å\88°ç\9a\84æ\95°æ\8d®å\9d\97ï¼\88å\8f\8c线ç¨\8b模å¼\8fï¼\89
+ * @brief å®\9aæ\97¶å\99¨å\9b\9eè°\83ï¼\9aæ£\80æ\9f¥bufferè¶\85æ\97¶å¹¶flush
  */
-static ppp_error_t ppp_process_data_block(const uint8_t *data, uint32_t length)
+static void ppp_timeout_timer_callback(unsigned long arg)
 {
-    if (!data || length == 0) {
-        return PPP_ERR_INVALID_PARAM;
-    }
+    (void)arg;
     
-    // 分配帧结构
-    ppp_frame_t *frame = (ppp_frame_t *)malloc(sizeof(ppp_frame_t));
-    if (!frame) {
-        PPP_DEBUG_ERROR("Failed to allocate frame structure");
-        
-        // 统计内存分配失败丢弃
-        g_ppp_discard_stats.total_bytes_discarded += length;
-        g_ppp_discard_stats.malloc_fail_bytes += length;
-        
-        return PPP_ERR_MEMORY;
+    if (!g_ppp_timer_running) {
+        return;
     }
     
-    // 分配帧数据
-    frame->data = (uint8_t *)malloc(length);
-    if (!frame->data) {
-        PPP_DEBUG_ERROR("Failed to allocate frame data");
-        
-        // 统计内存分配失败丢弃
-        g_ppp_discard_stats.total_bytes_discarded += length;
-        g_ppp_discard_stats.malloc_fail_bytes += length;
+    uint32_t current_time = ppp_get_current_time_ms();
+    
+    // 检查所有buffer的超时状态
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[i];
         
-        free(frame);
-        return PPP_ERR_MEMORY;
+        // 只处理FILLING状态的buffer
+        if (buffer->state == PPP_BUFFER_STATE_FILLING && buffer->write_pos > 0) {
+            uint32_t elapsed = current_time - buffer->last_write_time;
+            
+            if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
+                PPP_DEBUG_DEBUG("[TIMER] Flushing buffer[%u] due to timeout (%u ms)", i, elapsed);
+                
+                if (ppp_flush_buffer(i) == PPP_ERR_OK) {
+                    g_ppp_stats.buffer_timeout_count++;
+                    
+                    // Timer flush后切换buffer
+                    if (i == g_current_buffer_index) {
+                        uint8_t next_idx = (i + 1) % PPP_PING_PONG_BUFFER_COUNT;
+                        ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+                        
+                        if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+                            g_current_buffer_index = next_idx;
+                            g_ppp_stats.buffer_switch_count++;
+                        }
+                    }
+                }
+            }
+        }
     }
     
-    // 复制数据
-    memcpy(frame->data, data, length);
-    frame->length = length;
+    // osal_timer是one-shot类型,必须手动重启
+    if (g_ppp_timer_running) {
+        osal_timer_start(&g_ppp_timeout_timer);
+    }
+}
+
+/**
+ * @brief PPP数据处理线程 - 从乒乓buffer处理数据
+ */
+static void ppp_lwip_process_thread(void *arg)
+{
+    (void)arg;
+    ppp_msg_t msg;
+    unsigned int msg_size = sizeof(ppp_msg_t);
     
-    // 发送到队列
-    int ret = osal_msg_queue_write_copy(g_ppp_frame_queue, &frame, sizeof(ppp_frame_t *), 0);
-    if (ret != OSAL_SUCCESS) {
-        PPP_DEBUG_WARN("Failed to send data to queue: %d, dropping data", ret);
+    PPP_DEBUG_INFO("PPP process thread started (ping-pong polling mode)");
+    #ifdef PPP_DO_SERIAL_TEST
+    const uint8_t print_data[] = "PPP process thread started (ping-pong polling mode)\n";
+    uapi_uart_write(SIO_UART_BUS, print_data, sizeof(print_data), 100);
+    #endif
+    while (g_ppp_process_thread_running) {
+        // 从消息队列读取buffer索引消息(阻塞等待)
+        int ret = osal_msg_queue_read_copy(
+            g_ppp_msg_queue,
+            &msg,
+            &msg_size,
+            OSAL_MSGQ_WAIT_FOREVER
+        );
         
-        // 统计队列满丢弃
-        g_ppp_discard_stats.total_bytes_discarded += length;
-        g_ppp_discard_stats.queue_full_bytes += length;
+        if (ret != OSAL_SUCCESS || !g_ppp_process_thread_running) {
+            continue;
+        }
         
-        free(frame->data);
-        free(frame);
-        return PPP_ERR_UNKNOWN;
+        // 验证buffer索引
+        if (msg.buffer_index >= PPP_PING_PONG_BUFFER_COUNT) {
+            PPP_DEBUG_ERROR("Invalid buffer index: %u", msg.buffer_index);
+            continue;
+        }
+        
+        ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[msg.buffer_index];
+        
+        // 验证数据长度
+        if (msg.length == 0 || msg.length > PPP_PING_PONG_BUFFER_SIZE) {
+            PPP_DEBUG_ERROR("Invalid data length: %u", msg.length);
+            buffer->state = PPP_BUFFER_STATE_EMPTY;
+            buffer->write_pos = 0;
+            continue;
+        }
+        
+        // 标记为处理中
+        buffer->state = PPP_BUFFER_STATE_PROCESSING;
+        
+        // 打印摘要
+        PPP_DEBUG_DEBUG("PPP Process: buffer[%u], %u bytes", msg.buffer_index, msg.length);
+        
+        // 只打印前16字节
+        PPP_DEBUG_PRINT("  Data: ");
+        for (uint32_t i = 0; i < msg.length && i < 16; i++) {
+            PPP_DEBUG_PRINT("%02X ", buffer->data[i]);
+        }
+        if (msg.length > 16) {
+            PPP_DEBUG_PRINT("... (%u more bytes)", msg.length - 16);
+        }
+        PPP_DEBUG_PRINT("\n");
+        
+#ifndef PPP_DO_SERIAL_TEST
+        // 获取PPP控制块
+        ppp_pcb *ppp_pcb_ptr = ppp_lwip_get_pcb();
+        if (!ppp_pcb_ptr || !ppp_lwip_is_initialized()) {
+            PPP_DEBUG_WARN("PPP not initialized, dropping %u bytes", msg.length);
+            g_ppp_stats.total_bytes_discarded += msg.length;
+            buffer->state = PPP_BUFFER_STATE_EMPTY;
+            buffer->write_pos = 0;
+            continue;
+        }
+        
+        // 调用lwIP的线程安全接口处理PPP数据
+        // pppos_input_tcpip会复制数据到pbuf,所以我们可以安全地重用buffer
+        err_t result = pppos_input_tcpip(ppp_pcb_ptr, buffer->data, msg.length);
+        
+        if (result != ERR_OK) {
+            PPP_DEBUG_WARN("pppos_input_tcpip failed: %d, dropped %u bytes", 
+                          result, msg.length);
+            g_ppp_stats.total_bytes_discarded += msg.length;
+            g_ppp_stats.lwip_error_count++;
+        } else {
+            g_ppp_stats.total_bytes_processed += msg.length;
+        }
+#else
+        err_t result = ERR_OK;
+        uint32_t write_result = uapi_uart_write(SIO_UART_BUS, buffer->data, msg.length, 100);
+        if (write_result != msg.length) {
+            PPP_DEBUG_WARN("uapi_uart_write failed: %d, dropped %u bytes", write_result, msg.length);
+            g_ppp_stats.total_bytes_discarded += msg.length;
+            g_ppp_stats.lwip_error_count++;
+        } else {
+            PPP_DEBUG_WARN("uapi_uart_write : %u bytes", msg.length);
+            g_ppp_stats.total_bytes_processed += msg.length;
+        }
+#endif
+        // 释放buffer(标记为空闲)
+        buffer->state = PPP_BUFFER_STATE_EMPTY;
+        buffer->write_pos = 0;
     }
     
-    PPP_DEBUG_DEBUG("Sent data block to queue: %u bytes", length);
-    return PPP_ERR_OK;
+    PPP_DEBUG_INFO("PPP process thread completed");
+    g_ppp_process_thread_completed = true;
 }
-#endif
 
 /**
- * @brief PPP数据接收线程 - 轮询模式(类似SLIP的高效策略)
+ * @brief PPP数据接收线程 - 轮询UART并填充到乒乓buffer
  */
 static void ppp_lwip_receive_thread(void *arg)
 {
     (void)arg;
     
-    PPP_DEBUG_INFO("PPP receive thread started (polling mode)");
+    PPP_DEBUG_INFO("PPP receive thread started (ping-pong polling mode)");
 
-    // 分配串口接收缓冲区
-    uint8_t *rx_buffer = (uint8_t *)malloc(PPP_RX_BUFFER_SIZE);
+    // 分配临时读取缓冲区(每次最多读取512字节)
+    const uint32_t read_chunk_size = 1;
+    uint8_t *rx_buffer = (uint8_t *)malloc(read_chunk_size);
     if (!rx_buffer) {
         PPP_DEBUG_ERROR("PPP RX buffer alloc failed");
         g_ppp_rx_thread_completed = true;
         return;
     }
 
-    uint32_t bytes_read = 0;
     uint32_t total_bytes = 0;
-    uint32_t idle_count = 0;
+    uint32_t consecutive_empty = 0;
 
-    PPP_DEBUG_INFO("PPP receive thread: allocated %d bytes RX buffer", PPP_RX_BUFFER_SIZE);
+    PPP_DEBUG_INFO("PPP receive thread: allocated %d bytes temp buffer", read_chunk_size);
 
-    // 主循环:类似SLIP的连续读取策略
+    // 主循环:连续轮询UART读取
     while (g_ppp_rx_thread_running) {
-        uint32_t batch_bytes = 0;
-        uint32_t read_count = 0;
+        uint32_t bytes_read = 0;
+        ppp_error_t ret = ppp_serial_tryread(rx_buffer, read_chunk_size, &bytes_read);
         
-        // 连续读取直到无数据,类似SLIP的slipif_poll
-        while (g_ppp_rx_thread_running) {
-            ppp_error_t ret = ppp_serial_tryread(rx_buffer, PPP_RX_BUFFER_SIZE, &bytes_read);
+        if (ret == PPP_ERR_OK && bytes_read > 0) {
+            // 成功读取数据
+            total_bytes += bytes_read;
+            consecutive_empty = 0;
+            g_ppp_stats.read_count++;
+            g_ppp_stats.total_bytes_received += bytes_read;
             
-            if (ret == PPP_ERR_OK && bytes_read > 0) {
-                total_bytes += bytes_read;
-                batch_bytes += bytes_read;
-                read_count++;
-                
-                // 更新接收字节统计
-                g_ppp_discard_stats.total_bytes_received += bytes_read;
+            PPP_DEBUG_DEBUG("PPP RX: Got %u bytes", bytes_read);
+            
+            // 填充到乒乓buffer
+            uint32_t processed = 0;
+            while (processed < bytes_read && g_ppp_rx_thread_running) {
+                uint8_t current_idx = g_current_buffer_index;
+                ppp_ping_pong_buffer_t *current_buffer = &g_ping_pong_buffers[current_idx];
                 
-                PPP_DEBUG_DEBUG("PPP RX: Got %u bytes (read #%u)", bytes_read, read_count);
-
-#if PPP_USE_DUAL_THREAD
-                // 双线程模式:发送到队列由处理线程处理
-                ppp_error_t process_ret = ppp_process_data_block(rx_buffer, bytes_read);
-                if (process_ret != PPP_ERR_OK) {
-                    PPP_DEBUG_WARN("Failed to process data block: %d", process_ret);
+                // 如果buffer是空的,初始化为FILLING状态
+                if (current_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+                    current_buffer->state = PPP_BUFFER_STATE_FILLING;
+                    current_buffer->write_pos = 0;
                 }
-#else
-                // 单线程模式:调用处理函数(包含详细数据打印)
-                ppp_error_t process_ret = ppp_process_and_print_data(rx_buffer, bytes_read);
-                if (process_ret != PPP_ERR_OK) {
-                    g_ppp_discard_stats.total_bytes_discarded += bytes_read;
+                
+                // 尝试写入当前buffer
+                uint32_t available = PPP_PING_PONG_BUFFER_SIZE - current_buffer->write_pos;
+                uint32_t to_write = bytes_read - processed;
+                
+                if (current_buffer->state == PPP_BUFFER_STATE_FILLING && to_write <= available) {
+                    // 空间足够,直接写入
+                    memcpy(current_buffer->data + current_buffer->write_pos, 
+                           rx_buffer + processed, to_write);
+                    current_buffer->write_pos += to_write;
+                    current_buffer->last_write_time = ppp_get_current_time_ms();
+                    processed += to_write;
+                    
+                    // 检查是否满了
+                    if (current_buffer->write_pos >= PPP_PING_PONG_BUFFER_SIZE) {
+                        // buffer满,flush
+                        ppp_flush_buffer(current_idx);
+                        g_ppp_stats.buffer_full_count++;
+                        
+                        // 切换到另一个buffer
+                        uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+                        ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+                        
+                        if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+                            g_current_buffer_index = next_idx;
+                            g_ppp_stats.buffer_switch_count++;
+                        }
+                    }
                 } else {
-                    g_ppp_discard_stats.total_bytes_processed += bytes_read;
-                }
-#endif
-            } else if (ret != PPP_ERR_OK) {
-                // 读取错误
-                if (!g_ppp_rx_thread_running) {
-                    PPP_DEBUG_DEBUG("PPP receive thread stopping, ignoring read error");
-                    break;
+                    // 当前buffer空间不足或不可用,尝试切换
+                    uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+                    ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+                    
+                    if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+                        // 先flush当前buffer(如果有数据)
+                        if (current_buffer->state == PPP_BUFFER_STATE_FILLING && 
+                            current_buffer->write_pos > 0) {
+                            ppp_flush_buffer(current_idx);
+                        }
+                        
+                        // 切换到新buffer
+                        g_current_buffer_index = next_idx;
+                        g_ppp_stats.buffer_switch_count++;
+                        
+                        // 继续处理剩余数据(下次循环会写入新buffer)
+                    } else {
+                        // 两个buffer都不可用,丢弃数据
+                        uint32_t discarded = bytes_read - processed;
+                        g_ppp_stats.dropped_both_full += discarded;
+                        g_ppp_stats.total_bytes_discarded += discarded;
+                        PPP_DEBUG_WARN("Both buffers full, discarding %u bytes", discarded);
+                        break;
+                    }
                 }
-                PPP_DEBUG_ERROR("PPP serial tryread error: %d", ret);
-                break;
-            } else {
-                // 无数据,退出连续读取循环
+            }
+            
+            // 有数据,不休眠,继续读取
+        } else if (ret != PPP_ERR_OK) {
+            // 读取错误
+            if (!g_ppp_rx_thread_running) {
                 break;
             }
-        }
-        
-        if (batch_bytes > 0) {
-            // æ\9c\89æ\95°æ\8d®å¤\84ç\90\86ï¼\8cé\87\8d置空é\97²è®¡æ\95°å\99¨
-            idle_count = 0;
-            PPP_DEBUG_DEBUG("PPP batch: %u bytes in %u reads", batch_bytes, read_count);
+            PPP_DEBUG_ERROR("PPP serial tryread error: %d", ret);
+            osal_msleep(10);  // 错误时稍微休眠
+        } else {
+            // æ\97 æ\95°æ\8d®
+            consecutive_empty++;
+            g_ppp_stats.read_empty_count++;
             
-            // 短暂休眠后继续,保持高响应性
+            // 无数据时休眠1ms
             osal_msleep(1);
-        } else {
-            // 无数据时使用类似SLIP的休眠策略
-            idle_count++;
-            osal_msleep(20);  // 类似SLIP的20ms休眠,不打印避免日志干扰
         }
 
-        // 定期打印统计信息(减少频率)
-        if ((total_bytes % 4096) == 0 && total_bytes > 0) {
+        // 定期打印统计信息
+        if ((total_bytes % 10240) == 0 && total_bytes > 0) {
             PPP_DEBUG_INFO("PPP RX: %u total bytes received", total_bytes);
         }
     }
@@ -257,131 +447,84 @@ static void ppp_lwip_receive_thread(void *arg)
     g_ppp_rx_thread_completed = true;
 }
 
-#if PPP_USE_DUAL_THREAD
-/**
- * @brief PPP数据处理线程 - 从队列获取数据块并处理(仅双线程模式)
- */
-static void ppp_lwip_process_thread(void *arg)
-{
-    (void)arg;
-
-    PPP_DEBUG_INFO("PPP process thread started");
-
-    uint32_t processed_blocks = 0;
-    uint32_t processed_bytes = 0;
-
-    // 主循环:从队列获取数据块并处理
-    while (g_ppp_process_thread_running) {
-        ppp_frame_t *data_block = NULL;
-        uint32_t msg_size = sizeof(ppp_frame_t *);
-
-        // 从队列获取数据块(超时100ms,避免无限阻塞)
-        int ret = osal_msg_queue_read_copy(g_ppp_frame_queue, &data_block, &msg_size, OSAL_WAIT_FOREVER);
-        
-        if (ret == OSAL_SUCCESS && data_block) {
-            // 处理数据块
-            PPP_DEBUG_DEBUG("Processing data block: %u bytes", data_block->length);
-            
-            PPP_DEBUG_PRINT("PPP RX Data: ");
-            for (uint32_t i = 0; i < data_block->length ; i++) {
-                PPP_DEBUG_PRINT("%02X ", data_block->data[i]);
-            }
-            PPP_DEBUG_PRINT("\n");
-            // 调用lwIP流式处理
-            ppp_error_t process_ret = ppp_process_and_print_data(data_block->data, data_block->length);
-            
-            
-            // 更新统计
-            processed_blocks++;
-            processed_bytes += data_block->length;
-            if (process_ret != PPP_ERR_OK) {
-                g_ppp_discard_stats.total_bytes_discarded += data_block->length;
-            } else {
-                g_ppp_discard_stats.total_bytes_processed += data_block->length;
-            }
-            
-            // 释放数据块内存
-            free(data_block->data);
-            free(data_block);
-            
-            // 定期打印统计
-            if ((processed_blocks % 50) == 0) {
-                PPP_DEBUG_DEBUG("PPP Process: %u blocks, %u bytes processed", 
-                    processed_blocks, processed_bytes);
-            }
-        } else if (ret != OSAL_SUCCESS) {
-            // 超时或其他错误
-            if (!g_ppp_process_thread_running) {
-                PPP_DEBUG_DEBUG("PPP process thread stopping");
-                break;
-            }
-            // 超时是正常的,不需要警告。只有真正的错误才需要警告
-            // OSAL_FAILURE (-1) 通常表示超时,这是正常的
-            // 这里我们不再对超时进行警告,因为这是正常的队列空闲状态
-            PPP_DEBUG_DEBUG("Queue read timeout (normal when no data), ret: %d", ret);
-        }
-        // 超时是正常的,继续循环
-    }
-
-    // 清理队列中剩余的数据块
-    ppp_frame_t *data_block = NULL;
-    uint32_t msg_size = sizeof(ppp_frame_t *);
-    while (osal_msg_queue_read_copy(g_ppp_frame_queue, &data_block, &msg_size, 0) == OSAL_SUCCESS) {
-        if (data_block) {
-            free(data_block->data);
-            free(data_block);
-        }
-    }
-
-    PPP_DEBUG_INFO("PPP process thread completed, processed %u blocks, %u bytes", 
-                   processed_blocks, processed_bytes);
-    g_ppp_process_thread_completed = true;
-}
-#endif /* PPP_USE_DUAL_THREAD */
-
 /**
  * @brief 启动PPP接收和处理线程
  */
 ppp_error_t ppp_lwip_start_receive_thread(void)
 {
-#if PPP_USE_DUAL_THREAD
     if (g_ppp_rx_thread_handle != 0 || g_ppp_process_thread_handle != 0) {
         PPP_DEBUG_WARN("PPP threads already running");
         return PPP_ERR_INVALID_STATE;
     }
     
-    PPP_DEBUG_INFO("Starting PPP receive and process threads (" PPP_THREAD_MODE_STR " mode)");
-#else
-    if (g_ppp_rx_thread_handle != 0) {
-        PPP_DEBUG_WARN("PPP thread already running");
-        return PPP_ERR_INVALID_STATE;
-    }
-    
-    PPP_DEBUG_INFO("Starting PPP receive thread (" PPP_THREAD_MODE_STR " mode)");
-#endif
+    PPP_DEBUG_INFO("Starting PPP receive and process threads (ping-pong polling mode)");
     
     // 重置完成标志
     g_ppp_rx_thread_completed = false;
-
-#if PPP_USE_DUAL_THREAD
     g_ppp_process_thread_completed = false;
     
-    // 创建数据队列(仅双线程模式)
-    int queue_ret = osal_msg_queue_create("ppp_data", PPP_FRAME_QUEUE_SIZE, 
-                                          &g_ppp_frame_queue, 0, sizeof(ppp_frame_t *));
-    if (queue_ret != OSAL_SUCCESS) {
-        PPP_DEBUG_ERROR("Failed to create PPP data queue: %d", queue_ret);
+    // 1. 初始化乒乓缓冲区
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        g_ping_pong_buffers[i].write_pos = 0;
+        g_ping_pong_buffers[i].state = PPP_BUFFER_STATE_EMPTY;
+        g_ping_pong_buffers[i].last_write_time = 0;
+        memset(g_ping_pong_buffers[i].data, 0, PPP_PING_PONG_BUFFER_SIZE);
+    }
+    g_current_buffer_index = 0;
+    
+    PPP_DEBUG_INFO("Ping-pong buffers initialized: %d x %d bytes = %d KB total", 
+                  PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE,
+                  (PPP_PING_PONG_BUFFER_COUNT * PPP_PING_PONG_BUFFER_SIZE) / 1024);
+    
+    // 2. 创建消息队列
+    int ret = osal_msg_queue_create(
+        "ppp_queue",
+        PPP_MSG_QUEUE_SIZE,
+        &g_ppp_msg_queue,
+        0,
+        sizeof(ppp_msg_t)
+    );
+    
+    if (ret != OSAL_SUCCESS) {
+        PPP_DEBUG_ERROR("Failed to create message queue: 0x%x", ret);
         return PPP_ERR_MEMORY;
     }
     
-    // 启动处理线程
+    PPP_DEBUG_INFO("Message queue created (depth=%d, item_size=%d bytes)", 
+                  PPP_MSG_QUEUE_SIZE, sizeof(ppp_msg_t));
+    
+    // 3. 启动定时器(30ms周期检查buffer超时)
+    g_ppp_timeout_timer.handler = ppp_timeout_timer_callback;
+    g_ppp_timeout_timer.data = 0;
+    g_ppp_timeout_timer.interval = PPP_PING_PONG_TIMEOUT_MS;
+    
+    ret = osal_timer_init(&g_ppp_timeout_timer);
+    if (ret != OSAL_SUCCESS) {
+        PPP_DEBUG_ERROR("Failed to init timeout timer: 0x%x", ret);
+        osal_msg_queue_delete(g_ppp_msg_queue);
+        return PPP_ERR_MEMORY;
+    }
+    
+    g_ppp_timer_running = true;
+    ret = osal_timer_start(&g_ppp_timeout_timer);
+    if (ret != OSAL_SUCCESS) {
+        PPP_DEBUG_ERROR("Failed to start timeout timer: 0x%x", ret);
+        g_ppp_timer_running = false;
+        osal_timer_destroy(&g_ppp_timeout_timer);
+        osal_msg_queue_delete(g_ppp_msg_queue);
+        return PPP_ERR_MEMORY;
+    }
+    
+    PPP_DEBUG_INFO("Timeout timer started (period=%d ms)", PPP_PING_PONG_TIMEOUT_MS);
+    
+    // 4. 启动处理线程
     g_ppp_process_thread_running = true;
     
     app_task_definition_t process_task_cfg = {0};
     process_task_cfg.create_queue_handle = NULL;
     process_task_cfg.attr.name = "ppp_process";
     process_task_cfg.attr.priority = osPriorityNormal1;
-    process_task_cfg.attr.stack_size = 4096;
+    process_task_cfg.attr.stack_size = PPP_PROCESS_STACK_SIZE;
     process_task_cfg.func = ppp_lwip_process_thread;
     process_task_cfg.task_handle = &g_ppp_process_thread_handle;
     process_task_cfg.use_mem = USE_EXTEND_MEM;
@@ -390,20 +533,21 @@ ppp_error_t ppp_lwip_start_receive_thread(void)
     if (process_ret != ERRCODE_SUCC) {
         PPP_DEBUG_ERROR("Failed to create PPP process thread: %d", process_ret);
         g_ppp_process_thread_running = false;
-        osal_msg_queue_delete(g_ppp_frame_queue);
-        g_ppp_frame_queue = 0;
+        g_ppp_timer_running = false;
+        osal_timer_stop(&g_ppp_timeout_timer);
+        osal_timer_destroy(&g_ppp_timeout_timer);
+        osal_msg_queue_delete(g_ppp_msg_queue);
         return PPP_ERR_MEMORY;
     }
-#endif /* PPP_USE_DUAL_THREAD */
     
-    // 启动接收线程
+    // 5. 启动接收线程
     g_ppp_rx_thread_running = true;
     
     app_task_definition_t rx_task_cfg = {0};
     rx_task_cfg.create_queue_handle = NULL;
     rx_task_cfg.attr.name = "ppp_receive";
     rx_task_cfg.attr.priority = osPriorityNormal1;
-    rx_task_cfg.attr.stack_size = 6144;  // 单线程模式需要更大栈空间
+    rx_task_cfg.attr.stack_size = PPP_RX_STACK_SIZE;
     rx_task_cfg.func = ppp_lwip_receive_thread;
     rx_task_cfg.task_handle = &g_ppp_rx_thread_handle;
     rx_task_cfg.use_mem = USE_EXTEND_MEM;
@@ -413,20 +557,27 @@ ppp_error_t ppp_lwip_start_receive_thread(void)
         PPP_DEBUG_ERROR("Failed to create PPP receive thread: %d", rx_ret);
         g_ppp_rx_thread_running = false;
         
-#if PPP_USE_DUAL_THREAD
         // 清理处理线程
         g_ppp_process_thread_running = false;
         osThreadTerminate((osThreadId_t)g_ppp_process_thread_handle);
         g_ppp_process_thread_handle = 0;
         
+        // 清理定时器
+        g_ppp_timer_running = false;
+        osal_timer_stop(&g_ppp_timeout_timer);
+        osal_timer_destroy(&g_ppp_timeout_timer);
+        
         // 清理资源
-        osal_msg_queue_delete(g_ppp_frame_queue);
-        g_ppp_frame_queue = 0;
-#endif
+        osal_msg_queue_delete(g_ppp_msg_queue);
         return PPP_ERR_MEMORY;
     }
     
-    PPP_DEBUG_INFO("PPP threads started successfully (" PPP_THREAD_MODE_STR " mode)");
+    PPP_DEBUG_INFO("PPP threads started successfully (ping-pong polling mode)");
+    PPP_DEBUG_INFO("  Mode: Polling (1ms interval when idle)");
+    PPP_DEBUG_INFO("  Buffers: %d x %d KB", PPP_PING_PONG_BUFFER_COUNT, 
+                  PPP_PING_PONG_BUFFER_SIZE / 1024);
+    PPP_DEBUG_INFO("  Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
+    
     return PPP_ERR_OK;
 }
 
@@ -435,27 +586,26 @@ ppp_error_t ppp_lwip_start_receive_thread(void)
  */
 ppp_error_t ppp_lwip_stop_receive_thread(void)
 {
-#if PPP_USE_DUAL_THREAD
     if (g_ppp_rx_thread_handle == 0 && g_ppp_process_thread_handle == 0) {
         return PPP_ERR_OK;
     }
-#else
-    if (g_ppp_rx_thread_handle == 0) {
-        return PPP_ERR_OK;
-    }
-#endif
     
-    PPP_DEBUG_INFO("Stopping PPP threads (" PPP_THREAD_MODE_STR " mode)");
+    PPP_DEBUG_INFO("Stopping PPP threads (ping-pong polling mode)");
+    
+    // 1. 停止定时器
+    if (g_ppp_timer_running) {
+        g_ppp_timer_running = false;
+        osal_timer_stop(&g_ppp_timeout_timer);
+        osal_timer_destroy(&g_ppp_timeout_timer);
+        PPP_DEBUG_INFO("Timeout timer stopped");
+    }
     
-    // 停止接收线程
+    // 2. 停止接收线程
     if (g_ppp_rx_thread_handle != 0) {
         g_ppp_rx_thread_running = false;
         
-        // 等待接收线程完成
         int wait_count = 0;
-        const int max_wait = 100;
-        
-        while (wait_count < max_wait && !g_ppp_rx_thread_completed) {
+        while (wait_count < 100 && !g_ppp_rx_thread_completed) {
             osal_msleep(10);
             wait_count++;
         }
@@ -470,16 +620,17 @@ ppp_error_t ppp_lwip_stop_receive_thread(void)
         g_ppp_rx_thread_handle = 0;
     }
     
-#if PPP_USE_DUAL_THREAD
-    // 停止处理线程
+    // 3. 停止处理线程
     if (g_ppp_process_thread_handle != 0) {
         g_ppp_process_thread_running = false;
         
-        // 等待处理线程完成
-        int wait_count = 0;
-        const int max_wait = 100;
+        // 发送空消息唤醒线程
+        ppp_msg_t empty_msg = {0};
+        osal_msg_queue_write_copy(g_ppp_msg_queue, &empty_msg, 
+                                 sizeof(ppp_msg_t), OSAL_MSGQ_NO_WAIT);
         
-        while (wait_count < max_wait && !g_ppp_process_thread_completed) {
+        int wait_count = 0;
+        while (wait_count < 100 && !g_ppp_process_thread_completed) {
             osal_msleep(10);
             wait_count++;
         }
@@ -494,22 +645,27 @@ ppp_error_t ppp_lwip_stop_receive_thread(void)
         g_ppp_process_thread_handle = 0;
     }
     
-    // 清理队列
-    if (g_ppp_frame_queue != 0) {
-        osal_msg_queue_delete(g_ppp_frame_queue);
-        g_ppp_frame_queue = 0;
+    // 4. 清理队列
+    if (g_ppp_msg_queue != 0) {
+        osal_msg_queue_delete(g_ppp_msg_queue);
+        g_ppp_msg_queue = 0;
     }
-#endif
+    
+    // 5. 清空乒乓缓冲区
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        g_ping_pong_buffers[i].write_pos = 0;
+        g_ping_pong_buffers[i].state = PPP_BUFFER_STATE_EMPTY;
+        g_ping_pong_buffers[i].last_write_time = 0;
+    }
+    g_current_buffer_index = 0;
     
     // 重置状态标志
     g_ppp_rx_thread_running = false;
     g_ppp_rx_thread_completed = false;
-#if PPP_USE_DUAL_THREAD
     g_ppp_process_thread_running = false;
     g_ppp_process_thread_completed = false;
-#endif
     
-    PPP_DEBUG_INFO("PPP receive and process threads stopped");
+    PPP_DEBUG_INFO("PPP threads stopped");
     return PPP_ERR_OK;
 }
 
@@ -518,64 +674,103 @@ ppp_error_t ppp_lwip_stop_receive_thread(void)
  */
 bool ppp_lwip_is_receive_thread_running(void)
 {
-#if PPP_USE_DUAL_THREAD
     return g_ppp_rx_thread_running && (g_ppp_rx_thread_handle != 0) &&
            g_ppp_process_thread_running && (g_ppp_process_thread_handle != 0);
-#else
-    return g_ppp_rx_thread_running && (g_ppp_rx_thread_handle != 0);
-#endif
 }
 
 /**
- * @brief 获取PPP字节丢弃统计信息
+ * @brief 获取PPP统计信息(兼容接口)
  */
 void ppp_lwip_get_discard_stats(ppp_discard_stats_t *stats)
 {
     if (stats) {
-        memcpy(stats, &g_ppp_discard_stats, sizeof(ppp_discard_stats_t));
+        memset(stats, 0, sizeof(ppp_discard_stats_t));
+        stats->total_bytes_received = g_ppp_stats.total_bytes_received;
+        stats->total_bytes_processed = g_ppp_stats.total_bytes_processed;
+        stats->total_bytes_discarded = g_ppp_stats.total_bytes_discarded;
     }
 }
 
 /**
- * @brief 重置PPP字节丢弃统计信息
+ * @brief 重置PPP统计信息
  */
 void ppp_lwip_reset_discard_stats(void)
 {
-    memset(&g_ppp_discard_stats, 0, sizeof(ppp_discard_stats_t));
-    PPP_DEBUG_INFO("PPP discard statistics reset");
+    memset(&g_ppp_stats, 0, sizeof(ppp_polling_stats_t));
+    PPP_DEBUG_INFO("PPP polling statistics reset");
 }
 
 /**
- * @brief 打印PPP字节丢弃统计信息
+ * @brief 打印PPP统计信息
  */
 void ppp_lwip_print_discard_stats(void)
 {
-    PPP_DEBUG_INFO("=== PPP Discard Statistics ===");
-    PPP_DEBUG_INFO("Total Bytes Received: %u", g_ppp_discard_stats.total_bytes_received);
-    PPP_DEBUG_INFO("Total Bytes Processed: %u", g_ppp_discard_stats.total_bytes_processed);
-    PPP_DEBUG_INFO("Total Bytes Discarded: %u", g_ppp_discard_stats.total_bytes_discarded);
-    PPP_DEBUG_INFO("  - Invalid Frame Bytes: %u", g_ppp_discard_stats.invalid_frame_bytes);
-    PPP_DEBUG_INFO("  - Queue Full Bytes: %u", g_ppp_discard_stats.queue_full_bytes);
-    PPP_DEBUG_INFO("  - Malloc Fail Bytes: %u", g_ppp_discard_stats.malloc_fail_bytes);
-    PPP_DEBUG_INFO("  - Oversized Frame Bytes: %u", g_ppp_discard_stats.oversized_frame_bytes);
-    PPP_DEBUG_INFO("  - Incomplete Frame Bytes: %u", g_ppp_discard_stats.incomplete_frame_bytes);
-    PPP_DEBUG_INFO("Total Frames Received: %u", g_ppp_discard_stats.total_frames_received);
-    PPP_DEBUG_INFO("Total Frames Processed: %u", g_ppp_discard_stats.total_frames_processed);
-    PPP_DEBUG_INFO("Total Frames Discarded: %u", g_ppp_discard_stats.total_frames_discarded);
-    
-    // 计算丢弃率
-    if (g_ppp_discard_stats.total_bytes_received > 0) {
-        uint32_t discard_rate = (g_ppp_discard_stats.total_bytes_discarded * 100) / 
-                               g_ppp_discard_stats.total_bytes_received;
-        PPP_DEBUG_INFO("Byte Discard Rate: %u.%02u%%", 
-                      discard_rate / 100, discard_rate % 100);
+    PPP_DEBUG_INFO("=== PPP Polling Statistics (Ping-Pong Mode) ===");
+    PPP_DEBUG_INFO("Mode: Polling (轮询替代中断)");
+    PPP_DEBUG_INFO("Buffers: %d x %d bytes = %d KB total", 
+                   PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE,
+                   (PPP_PING_PONG_BUFFER_COUNT * PPP_PING_PONG_BUFFER_SIZE) / 1024);
+    PPP_DEBUG_INFO("Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
+    PPP_DEBUG_INFO("");
+    
+    // Buffer状态
+    PPP_DEBUG_INFO("Buffer Status:");
+    for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+        const char *state_str = "UNKNOWN";
+        switch (g_ping_pong_buffers[i].state) {
+            case PPP_BUFFER_STATE_EMPTY:      state_str = "EMPTY"; break;
+            case PPP_BUFFER_STATE_FILLING:    state_str = "FILLING"; break;
+            case PPP_BUFFER_STATE_FULL:       state_str = "FULL"; break;
+            case PPP_BUFFER_STATE_PROCESSING: state_str = "PROCESSING"; break;
+        }
+        PPP_DEBUG_INFO("  Buffer[%u]: %s, %u/%u bytes%s", 
+                      i, state_str, g_ping_pong_buffers[i].write_pos, 
+                      PPP_PING_PONG_BUFFER_SIZE,
+                      (i == g_current_buffer_index) ? " (current)" : "");
+    }
+    PPP_DEBUG_INFO("");
+    
+    // 乒乓buffer统计
+    PPP_DEBUG_INFO("Ping-Pong Buffer Statistics:");
+    PPP_DEBUG_INFO("  Buffer Full Count: %u", g_ppp_stats.buffer_full_count);
+    PPP_DEBUG_INFO("  Buffer Timeout Count: %u", g_ppp_stats.buffer_timeout_count);
+    PPP_DEBUG_INFO("  Buffer Switch Count: %u", g_ppp_stats.buffer_switch_count);
+    PPP_DEBUG_INFO("");
+    
+    // UART轮询统计
+    PPP_DEBUG_INFO("UART Polling Statistics:");
+    PPP_DEBUG_INFO("  Total Read Attempts: %u", g_ppp_stats.read_count + g_ppp_stats.read_empty_count);
+    PPP_DEBUG_INFO("  Successful Reads: %u", g_ppp_stats.read_count);
+    PPP_DEBUG_INFO("  Empty Reads: %u", g_ppp_stats.read_empty_count);
+    if (g_ppp_stats.read_count + g_ppp_stats.read_empty_count > 0) {
+        uint32_t hit_rate = (g_ppp_stats.read_count * 100) / 
+                           (g_ppp_stats.read_count + g_ppp_stats.read_empty_count);
+        PPP_DEBUG_INFO("  Hit Rate: %u%%", hit_rate);
     }
+    PPP_DEBUG_INFO("");
+    
+    // 字节统计
+    PPP_DEBUG_INFO("Byte Statistics:");
+    PPP_DEBUG_INFO("  Total Bytes Received: %u", g_ppp_stats.total_bytes_received);
+    PPP_DEBUG_INFO("  Total Bytes Processed: %u", g_ppp_stats.total_bytes_processed);
+    PPP_DEBUG_INFO("  Total Bytes Discarded: %u", g_ppp_stats.total_bytes_discarded);
+    PPP_DEBUG_INFO("    - Both Buffers Full: %u", g_ppp_stats.dropped_both_full);
+    PPP_DEBUG_INFO("    - Queue Full: %u", g_ppp_stats.dropped_queue_full);
+    PPP_DEBUG_INFO("  lwIP Errors: %u", g_ppp_stats.lwip_error_count);
+    PPP_DEBUG_INFO("");
     
-    if (g_ppp_discard_stats.total_frames_received > 0) {
-        uint32_t frame_discard_rate = (g_ppp_discard_stats.total_frames_discarded * 100) / 
-                                     g_ppp_discard_stats.total_frames_received;
-        PPP_DEBUG_INFO("Frame Discard Rate: %u.%02u%%", 
-                      frame_discard_rate / 100, frame_discard_rate % 100);
+    // 丢包率
+    if (g_ppp_stats.total_bytes_received > 0) {
+        uint32_t drop_rate = (g_ppp_stats.total_bytes_discarded * 10000) / 
+                            g_ppp_stats.total_bytes_received;
+        PPP_DEBUG_INFO("Drop Rate: %u.%02u%%", drop_rate / 100, drop_rate % 100);
     }
-    PPP_DEBUG_INFO("==============================");
-} 
\ No newline at end of file
+    
+    // 平均字节数
+    if (g_ppp_stats.read_count > 0) {
+        uint32_t avg_bytes = g_ppp_stats.total_bytes_received / g_ppp_stats.read_count;
+        PPP_DEBUG_INFO("Average bytes per read: %u", avg_bytes);
+    }
+    
+    PPP_DEBUG_INFO("=================================================");
+}
\ No newline at end of file
index b1f2538..f52f448 100644 (file)
@@ -294,6 +294,10 @@ void ppp_power_on_cat1(void)
     ppp_api_cat1_bat_pin(1);
     osal_msleep(900);  // 使用OSAL延时函数
     ppp_api_cat1_power_pin(0);  
+#ifdef PPP_DO_SERIAL_TEST
+    ppp_api_cat1_reset_pin(1);
+#endif
+
 #endif
     
     g_ppp_cat1_power_status = true;
index 3a1e45f..2ef654e 100644 (file)
@@ -173,6 +173,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config)
 
     /* 初始化UART */
     PPP_DEBUG_DEBUG("Calling uapi_uart_init...");
+    // 注意:uart_porting.c中已经做了UART初始化,这里只需要设置属性
     // errcode_t ret = uapi_uart_init(g_serial_ctx.uart_bus, 
     //                                &g_serial_ctx.pin_config,
     //                                &g_serial_ctx.uart_attr, 
@@ -588,7 +589,7 @@ ppp_error_t ppp_serial_tryread(uint8_t *buffer, uint32_t buffer_size, uint32_t *
 
     if (g_serial_ctx.current_mode == PPP_SERIAL_MODE_PPP_DATA) {
         /* PPP数据模式:使用1ms超时快速读取,类似SLIP的sio_tryread */
-        int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 1);
+        int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 0);
         if (read_result > 0) {
             *bytes_read = (uint32_t)read_result;
             g_serial_ctx.rx_bytes += *bytes_read;
index 203734c..562dd52 100644 (file)
@@ -18,7 +18,7 @@ extern "C" {
 #define ZHIHUI_TCP_LOG_LEVEL_INFO    3
 #define ZHIHUI_TCP_LOG_LEVEL_DEBUG   4
 
-#define DEFAULT_ZHIHUI_TCP_LOG_LEVEL ZHIHUI_TCP_LOG_LEVEL_WARN
+#define DEFAULT_ZHIHUI_TCP_LOG_LEVEL ZHIHUI_TCP_LOG_LEVEL_INFO
 
 #if ZHIHUI_TCP_LOG_ENABLE
 
index 80ac372..b414058 100644 (file)
@@ -116,6 +116,7 @@ extern "C" {
 #define TCP_TEST_DEFAULT_TIME       30
 #define TCP_TEST_DEFAULT_CONNECTIONS 10
 #define TCP_TEST_DEFAULT_RECV_TIMEOUT_MS 1000  // 默认接收超时1000ms
+#define TCP_TEST_DEFAULT_SEND_INTERVAL_MS 500  // 默认发送间隔100ms
 
 /* 新的固定数据模式配置 */
 #define TCP_TEST_FIXED_DATA_SIZE    2048    // 固定数据长度,可通过宏配置