优化ppp接收发送 测试程序可以发一包
author孙春阳 <snickersun@163.com>
Sun, 21 Sep 2025 13:59:21 +0000 (21:59 +0800)
committer孙春阳 <snickersun@163.com>
Sun, 21 Sep 2025 13:59:21 +0000 (21:59 +0800)
code/sdk/zhihui/ppp/example/ppp_at_cmd.c
code/sdk/zhihui/ppp/include/ppp_api.h
code/sdk/zhihui/ppp/include/ppp_types.h
code/sdk/zhihui/ppp/src/ppp_lwip.c
code/sdk/zhihui/ppp/src/ppp_lwip_thread.c
code/sdk/zhihui/ppp/src/ppp_serial.c
code/sdk/zhihui/tcptest/src/zhihui_tcp_test.c

index 9e7fbf6..e796366 100644 (file)
@@ -959,7 +959,7 @@ static errcode_t at_ppp_update_single_runtime(uint8_t *para, uint32_t paraLen)
     
     return ret;
 }
-
+extern void ppp_lwip_print_discard_stats(void);
 /* PPP Runtime状态显示指令 */
 static errcode_t at_ppp_show_runtime(uint8_t *para, uint32_t paraLen)
 {
@@ -1013,6 +1013,8 @@ static errcode_t at_ppp_show_runtime(uint8_t *para, uint32_t paraLen)
     
     ppp_print_info("===============================\n");
     
+    ppp_lwip_print_discard_stats();
+
     return ERRCODE_SUCC;
 }
 
index 951c5ca..86c69b1 100644 (file)
@@ -266,6 +266,24 @@ bool ppp_lwip_is_receive_thread_running(void);
  */
 errcode_t ppp_get_network_signal_info(void);
 
+/* ========== PPP字节丢弃统计接口 ========== */
+
+/**
+ * @brief 获取PPP字节丢弃统计信息
+ * @param stats 统计信息结构指针
+ */
+void ppp_lwip_get_discard_stats(ppp_discard_stats_t *stats);
+
+/**
+ * @brief 重置PPP字节丢弃统计信息
+ */
+void ppp_lwip_reset_discard_stats(void);
+
+/**
+ * @brief 打印PPP字节丢弃统计信息
+ */
+void ppp_lwip_print_discard_stats(void);
+
 #ifdef __cplusplus
 }
 #endif
index 4e43cb7..7d865e8 100644 (file)
@@ -70,6 +70,21 @@ typedef struct {
     uint32_t last_activity;                             // 最后活动时间戳
 } ppp_stats_t;
 
+/* PPP字节丢弃统计结构 */
+typedef struct {
+    uint32_t total_bytes_received;                      // 总接收字节数
+    uint32_t total_bytes_processed;                     // 总处理字节数
+    uint32_t total_bytes_discarded;                     // 总丢弃字节数
+    uint32_t invalid_frame_bytes;                       // 无效帧丢弃字节数
+    uint32_t queue_full_bytes;                          // 队列满丢弃字节数
+    uint32_t malloc_fail_bytes;                         // 内存分配失败丢弃字节数
+    uint32_t oversized_frame_bytes;                     // 超大帧丢弃字节数
+    uint32_t incomplete_frame_bytes;                    // 不完整帧丢弃字节数
+    uint32_t total_frames_received;                     // 总接收帧数
+    uint32_t total_frames_processed;                    // 总处理帧数
+    uint32_t total_frames_discarded;                    // 总丢弃帧数
+} ppp_discard_stats_t;
+
 /* PPP事件类型 */
 typedef enum {
     PPP_EVENT_CONNECTED = 0,                            // 连接成功
index 27a82df..6188511 100644 (file)
@@ -481,53 +481,21 @@ ppp_error_t ppp_lwip_input(const uint8_t *data, uint32_t length)
 #ifndef LWIP_PPP_SUPPORT
     return PPP_ERR_INVALID_PARAM;
 #else
-    /* 参数和状态验证 */
-    if (!g_lwip_ctx.initialized || !data || length == 0) {
+    if (!g_lwip_ctx.initialized || !g_lwip_ctx.ppp_pcb || !data || length == 0) {
         return PPP_ERR_INVALID_PARAM;
     }
-    
-    /* 记录数据活动 */
-    ppp_lwip_record_data_activity();
-    
-    /* 检查PPP控制块是否有效 */
-    if (!g_lwip_ctx.ppp_pcb) {
-        PPP_DEBUG_ERROR("PPP control block is NULL");
-        return PPP_ERR_INVALID_STATE;
-    }
 
-    /* 添加数据完整性检查 */
-    if (length > 1500) {  // PPP最大帧长度
-        PPP_DEBUG_WARN("PPP frame too large: %u bytes, truncating", length);
-        length = 1500;  // 截断而不是拒绝
-    }
-    
-    /* 检查数据有效性 */
-    if (length < 4) {  // PPP最小帧长度(地址+控制+协议)
-        PPP_DEBUG_DEBUG("PPP frame too small: %u bytes, ignoring", length);
-        return PPP_ERR_OK;  // 忽略而不是报错
-    }
-
-    PPP_DEBUG_PRINT("=== PPP Input Data ===\n");
-    PPP_DEBUG_PRINT("Length: %d bytes\n", length);
-    // PPP_DEBUG_HEXDUMP("RX", data, length > 32 ? 32 : length);
+    ppp_lwip_record_data_activity();
 
 #if !NO_SYS && !PPP_INPROC_IRQ_SAFE
-    /* 在多线程环境中使用线程安全的输入函数,添加异常保护 */
-    err_t result;
-    
-    /* 使用try-catch风格的错误处理 */
-    result = pppos_input_tcpip(g_lwip_ctx.ppp_pcb, (u8_t *)data, length);
+    err_t result = pppos_input_tcpip(g_lwip_ctx.ppp_pcb, (u8_t *)data, length);
     if (result != ERR_OK) {
         PPP_DEBUG_WARN("pppos_input_tcpip failed with error: %d (continuing)", result);
-        /* 不要因为单次输入失败就返回错误,这可能导致连接中断 */
-        return PPP_ERR_OK;
     }
 #else
-    /* 在单线程或中断安全环境中使用直接输入 */
     pppos_input(g_lwip_ctx.ppp_pcb, (u8_t *)data, length);
 #endif
 
-    PPP_DEBUG_PRINT("=== PPP Input Processed ===\n");
     return PPP_ERR_OK;
 #endif
 }
@@ -940,6 +908,16 @@ static u32_t ppp_lwip_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void
     PPP_DEBUG_PRINT("=== PPP Protocol Output ===\n");
     PPP_DEBUG_PRINT("PPP TX: %u bytes\n", len);
     
+    /* 打印发送数据的前几个字节 */
+    PPP_DEBUG_PRINT("Raw Data: ");
+    for (uint32_t i = 0; i < len && i < 32; i++) {
+        PPP_DEBUG_PRINT("%02X ", data[i]);
+    }
+    if (len > 32) {
+        PPP_DEBUG_PRINT("... (total %u bytes)", len);
+    }
+    PPP_DEBUG_PRINT("\n");
+    
     /* 解析PPP协议包 */
     if (len >= 4) {
         /* 跳过PPP Flag (0x7E) 如果存在 */
index 2007eda..57bcf18 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * @file ppp_lwip_thread.c
- * @brief PPPæ\8e¥æ\94¶çº¿ç¨\8bå®\9eç\8e° - å\8f\82è\80\83lwIP slipif_initæ\96¹å¼\8f
+ * @brief PPPæ\8e¥æ\94¶çº¿ç¨\8bå®\9eç\8e° - å\8f\8c线ç¨\8bæ\9e¶æ\9e\84ï¼\9aæ\8e¥æ\94¶çº¿ç¨\8bæ\8b¼å\8c\85 + å¤\84ç\90\86线ç¨\8bå¤\84ç\90\86
  */
 
 #include "ppp_api.h"
 #include "ppp_lwip.h"
 #include "soc_osal.h"
 #include "schedule/osal_task.h"
+#include "msgqueue/osal_msgqueue.h"
 #include <stdlib.h>
 #include <string.h>
 
-/* PPP接收线程相关 - 参考slipif_init方式 */
-static osal_task *g_ppp_rx_thread = NULL;
+/* PPP帧队列相关 */
+#define PPP_FRAME_QUEUE_SIZE    32      // 队列大小
+#define PPP_MAX_FRAME_SIZE      1500    // PPP最大帧大小
+
+/* PPP帧结构 */
+typedef struct {
+    uint8_t *data;      // 帧数据
+    uint32_t length;    // 帧长度
+} ppp_frame_t;
+
+/* PPP字节丢弃统计结构已在ppp_types.h中定义 */
+
+/* PPP线程相关 */
+static osal_task *g_ppp_rx_thread = NULL;           // 接收线程
+static osal_task *g_ppp_process_thread = NULL;      // 处理线程
 static volatile bool g_ppp_rx_thread_running = false;
+static volatile bool g_ppp_process_thread_running = false;
 static volatile bool g_ppp_rx_thread_completed = false;
+static volatile bool g_ppp_process_thread_completed = false;
+
+/* PPP帧队列 */
+static unsigned long g_ppp_frame_queue = 0xFFFFFFFFu;
+
+/* PPP接收缓冲区 */
+static uint8_t g_ppp_rx_buffer[PPP_RX_BUFFER_SIZE * 2];  // 双倍缓冲区用于拼包
+static uint32_t g_buffer_pos = 0;       // 当前缓冲区位置
+
+/* PPP帧标志 */
+#define PPP_FLAG_CHAR           0x7E    // PPP帧标志字符
+#define PPP_ESCAPE_CHAR         0x7D    // PPP转义字符
+#define PPP_ESCAPE_MASK         0x20    // PPP转义掩码
+
+/* PPP丢弃统计 */
+static ppp_discard_stats_t g_ppp_discard_stats = {0};
+
+/* PPP帧拼包状态 */
+typedef struct {
+    uint8_t *buffer;        // 拼包缓冲区
+    uint32_t buffer_size;   // 缓冲区大小
+    uint32_t data_len;      // 当前数据长度
+    bool in_frame;          // 是否在帧内
+    bool escaped;           // 是否转义状态
+} ppp_frame_assembler_t;
+
+static ppp_frame_assembler_t g_frame_assembler = {0};
 
 /**
- * @brief PPP数据接收线程 - 参考slipif_init实现
- * 
- * 这个实现参考了lwIP中slipif_init的线程创建方式:
- * 1. 使用标准的线程函数签名
- * 2. 实现流数据处理和PPP帧重组
- * 3. 直接调用lwIP的输入函数
+ * @brief 初始化PPP帧拼包器
  */
-static void ppp_lwip_receive_thread(void *arg)
+static ppp_error_t ppp_frame_assembler_init(void)
 {
-    (void)arg;
+    g_frame_assembler.buffer_size = PPP_MAX_FRAME_SIZE;
+    g_frame_assembler.buffer = (uint8_t *)malloc(g_frame_assembler.buffer_size);
+    if (!g_frame_assembler.buffer) {
+        PPP_DEBUG_ERROR("Failed to allocate frame assembler buffer");
+        return PPP_ERR_MEMORY;
+    }
     
-    PPP_DEBUG_DEBUG("PPP lwIP receive thread started (slipif-style)");
+    g_frame_assembler.data_len = 0;
+    g_frame_assembler.in_frame = false;
+    g_frame_assembler.escaped = false;
     
-    /* 动态分配接收缓冲区以避免栈溢出 */
-    uint8_t *rx_buffer = (uint8_t *)malloc(PPP_RX_BUFFER_SIZE);
-    if (!rx_buffer) {
-        PPP_DEBUG_ERROR("Failed to allocate RX buffer for PPP thread");
-        return;
+    PPP_DEBUG_INFO("PPP frame assembler initialized with %u bytes buffer", 
+                   g_frame_assembler.buffer_size);
+    return PPP_ERR_OK;
+}
+
+/**
+ * @brief 清理PPP帧拼包器
+ */
+static void ppp_frame_assembler_cleanup(void)
+{
+    if (g_frame_assembler.buffer) {
+        free(g_frame_assembler.buffer);
+        g_frame_assembler.buffer = NULL;
+    }
+    memset(&g_frame_assembler, 0, sizeof(g_frame_assembler));
+}
+
+/**
+ * @brief 重置帧拼包状态
+ */
+static void ppp_frame_assembler_reset(void)
+{
+    g_frame_assembler.data_len = 0;
+    g_frame_assembler.in_frame = false;
+    g_frame_assembler.escaped = false;
+}
+
+/**
+ * @brief 发送完整PPP帧到队列
+ */
+static ppp_error_t ppp_send_frame_to_queue(const uint8_t *data, uint32_t length)
+{
+    if (!data || length == 0 || length > PPP_MAX_FRAME_SIZE) {
+        return PPP_ERR_INVALID_PARAM;
     }
     
-    /* 动态分配PPP流处理缓冲区 */
-    uint8_t *stream_buffer = (uint8_t *)malloc(PPP_RX_BUFFER_SIZE * 2);
-    if (!stream_buffer) {
-        PPP_DEBUG_ERROR("Failed to allocate stream buffer for PPP thread");
-        free(rx_buffer);
-        return;
+    // 分配帧结构
+    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_frames_discarded++;
+        g_ppp_discard_stats.malloc_fail_bytes += length;
+        g_ppp_discard_stats.total_bytes_discarded += length;
+        
+        return PPP_ERR_MEMORY;
     }
     
-    uint32_t bytes_read;
-    uint32_t total_packets = 0;
-    uint32_t total_bytes = 0;
+    // 分配帧数据
+    frame->data = (uint8_t *)malloc(length);
+    if (!frame->data) {
+        PPP_DEBUG_ERROR("Failed to allocate frame data");
+        
+        // 统计内存分配失败丢弃
+        g_ppp_discard_stats.total_frames_discarded++;
+        g_ppp_discard_stats.malloc_fail_bytes += length;
+        g_ppp_discard_stats.total_bytes_discarded += length;
+        
+        free(frame);
+        return PPP_ERR_MEMORY;
+    }
     
-    /* PPP流处理状态 */
-    uint32_t stream_pos = 0;          /* 流缓冲区当前位置 */
-    bool in_frame = false;            /* 是否正在接收PPP帧 */
-    uint32_t frame_start = 0;         /* 当前帧开始位置 */
-    uint32_t complete_frames = 0;     /* 完整帧计数 */
+    // 复制数据
+    memcpy(frame->data, data, length);
+    frame->length = length;
     
-    PPP_DEBUG_DEBUG("PPP lwIP thread: allocated %d bytes RX buffer + %d bytes stream buffer", 
-                   PPP_RX_BUFFER_SIZE, PPP_RX_BUFFER_SIZE * 2);
+    // 发送到队列
+    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 frame to queue: %d, dropping frame", ret);
+        
+        // 统计队列满丢弃
+        g_ppp_discard_stats.total_frames_discarded++;
+        g_ppp_discard_stats.queue_full_bytes += length;
+        g_ppp_discard_stats.total_bytes_discarded += length;
+        
+        free(frame->data);
+        free(frame);
+        return PPP_ERR_UNKNOWN;  // 使用已定义的错误码
+    }
     
-    PPP_DEBUG_CRITICAL("PPP receive thread started and entering main loop");
-    PPP_DEBUG_DEBUG("Thread will read from serial in PPP data mode");
+    PPP_DEBUG_DEBUG("Sent complete PPP frame to queue: %u bytes", length);
     
-    /* 主接收循环 - 参考slipif的实现方式 */
+    // 更新帧统计
+    g_ppp_discard_stats.total_frames_received++;
+    
+    return PPP_ERR_OK;
+}
+
+/**
+ * @brief 处理接收到的字节,进行PPP帧拼包(保留完整帧格式)
+ */
+static ppp_error_t ppp_process_received_byte(uint8_t byte)
+{
+    // PPP帧标志字符
+    if (byte == 0x7E) {
+        if (g_frame_assembler.in_frame && g_frame_assembler.data_len > 0) {
+            // 帧结束,添加结束标志并发送完整帧
+            if (g_frame_assembler.data_len < g_frame_assembler.buffer_size) {
+                g_frame_assembler.buffer[g_frame_assembler.data_len++] = 0x7E;
+                
+                PPP_DEBUG_DEBUG("Complete PPP frame assembled: %u bytes (with 0x7E flags)", g_frame_assembler.data_len);
+                
+                // 发送完整帧(包含首尾0x7E标志)
+                ppp_send_frame_to_queue(g_frame_assembler.buffer, g_frame_assembler.data_len);
+            } else {
+                // 缓冲区满,丢弃帧
+                PPP_DEBUG_WARN("Frame buffer full, dropping frame");
+                g_ppp_discard_stats.total_frames_discarded++;
+                g_ppp_discard_stats.oversized_frame_bytes += g_frame_assembler.data_len;
+                g_ppp_discard_stats.total_bytes_discarded += g_frame_assembler.data_len;
+            }
+        } else if (g_frame_assembler.in_frame && g_frame_assembler.data_len == 0) {
+            // 连续的0x7E标志,这是正常的
+            PPP_DEBUG_DEBUG("Consecutive 0x7E flag, continuing");
+        } else {
+            // 不在帧内收到0x7E,开始新帧
+            PPP_DEBUG_DEBUG("Starting new frame with 0x7E");
+        }
+        
+        // 开始新帧,首先添加起始0x7E标志
+        ppp_frame_assembler_reset();
+        g_frame_assembler.in_frame = true;
+        g_frame_assembler.buffer[g_frame_assembler.data_len++] = 0x7E;
+        return PPP_ERR_OK;
+    }
+    
+    // 如果不在帧内,忽略数据
+    if (!g_frame_assembler.in_frame) {
+        // 统计被忽略的数据
+        g_ppp_discard_stats.total_bytes_discarded++;
+        g_ppp_discard_stats.incomplete_frame_bytes++;
+        PPP_DEBUG_DEBUG("Ignoring byte 0x%02X outside frame", byte);
+        return PPP_ERR_OK;
+    }
+    
+    // 检查缓冲区空间(为结束0x7E预留1字节)
+    if (g_frame_assembler.data_len >= (g_frame_assembler.buffer_size - 1)) {
+        PPP_DEBUG_WARN("Frame too large (%u bytes), resetting assembler", g_frame_assembler.data_len);
+        
+        // 统计超大帧丢弃
+        g_ppp_discard_stats.total_frames_discarded++;
+        g_ppp_discard_stats.oversized_frame_bytes += g_frame_assembler.data_len;
+        g_ppp_discard_stats.total_bytes_discarded += g_frame_assembler.data_len;
+        
+        ppp_frame_assembler_reset();
+        return PPP_ERR_UNKNOWN;
+    }
+    
+    // 直接添加字节到帧缓冲区(保留原始格式,包括转义字符)
+    g_frame_assembler.buffer[g_frame_assembler.data_len++] = byte;
+    
+    return PPP_ERR_OK;
+}
+
+/**
+ * @brief PPP数据接收线程 - 只负责拼包
+ */
+static void ppp_lwip_receive_thread(void *arg)
+{
+    (void)arg;
+
+    PPP_DEBUG_INFO("PPP receive thread started (frame assembly mode)");
+
+    // 分配串口接收缓冲区
+    uint8_t *rx_buffer = (uint8_t *)malloc(PPP_RX_BUFFER_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, total_frames = 0;
+
+    PPP_DEBUG_DEBUG("PPP receive thread: allocated %d bytes RX buffer", PPP_RX_BUFFER_SIZE);
+
+    // 主循环:从串口读取数据并拼包
     while (g_ppp_rx_thread_running) {
-        // 从串口读取PPP数据 - 使用较短的超时时间提高响应性
+        // 从串口读取数据
         ppp_error_t ret = ppp_serial_read(rx_buffer, PPP_RX_BUFFER_SIZE, &bytes_read);
-        
+
         if (ret == PPP_ERR_OK && bytes_read > 0) {
-            total_packets++;
             total_bytes += bytes_read;
             
-            PPP_DEBUG_DEBUG("PPP RX: Got %u bytes (total: %u packets, %u bytes)", 
-                          bytes_read, total_packets, total_bytes);
-            
-            /* 将接收到的数据添加到流缓冲区 - 加强边界检查 */
-            if (stream_pos + bytes_read < PPP_RX_BUFFER_SIZE * 2) {
-                memcpy(stream_buffer + stream_pos, rx_buffer, bytes_read);
-                stream_pos += bytes_read;
-            } else {
-                PPP_DEBUG_WARN("PPP stream buffer overflow, resetting");
-                stream_pos = 0;
-                frame_start = 0;
-                in_frame = false;
-                continue;  // 跳过本次处理,避免缓冲区溢出
-            }
-            
-            /* 处理PPP帧 - 查找0x7E标志并添加边界检查 */
-            for (uint32_t i = frame_start; i < stream_pos && i < PPP_RX_BUFFER_SIZE * 2; i++) {
-                if (stream_buffer[i] == 0x7E) {
-                    if (in_frame && i > frame_start) {
-                        /* 找到帧结束,处理完整的PPP帧 */
-                        uint32_t frame_len = i - frame_start + 1;
-                        
-                        /* 添加帧长度合理性检查 */
-                        if (frame_len > 0 && frame_len <= 1500) {  // PPP最大帧长度
-                            PPP_DEBUG_DEBUG("PPP complete frame found: %u bytes", frame_len);
-                            
-                            /* 确保指针和长度有效 */
-                            if (frame_start + frame_len <= PPP_RX_BUFFER_SIZE * 2 && 
-                                frame_start < PPP_RX_BUFFER_SIZE * 2) {
-                                /* 将完整帧传递给lwIP - 让lwIP自己验证帧的有效性 */
-                                ppp_lwip_input(stream_buffer + frame_start, frame_len);
-                                complete_frames++;
-                            } else {
-                                PPP_DEBUG_WARN("PPP frame pointer out of bounds: start=%u, len=%u", 
-                                              frame_start, frame_len);
-                            }
-                        } else {
-                            PPP_DEBUG_WARN("Invalid PPP frame length: %u (frame_start=%u, i=%u)", 
-                                          frame_len, frame_start, i);
-                        }
-                    }
-                    
-                    /* 开始新帧 */
-                    frame_start = i;
-                    in_frame = true;
-                }
-            }
-            
-            /* 如果缓冲区使用超过一半,移动未处理的数据到缓冲区开头 */
-            if (frame_start > PPP_RX_BUFFER_SIZE) {
-                uint32_t remaining = stream_pos - frame_start;
-                if (remaining > 0) {
-                    memmove(stream_buffer, stream_buffer + frame_start, remaining);
+            // 更新接收字节统计
+            g_ppp_discard_stats.total_bytes_received += bytes_read;
+
+            PPP_DEBUG_DEBUG("PPP RX: Got %u bytes (total: %u bytes)", bytes_read, total_bytes);
+
+            // 逐字节处理,进行PPP帧拼包(保留完整帧格式)
+            for (uint32_t i = 0; i < bytes_read; i++) {
+                ppp_error_t process_ret = ppp_process_received_byte(rx_buffer[i]);
+                if (process_ret != PPP_ERR_OK) {
+                    // 字节处理失败,统计丢弃
+                    g_ppp_discard_stats.total_bytes_discarded++;
+                    g_ppp_discard_stats.invalid_frame_bytes++;
                 }
-                stream_pos = remaining;
-                frame_start = 0;
-                /* 保持in_frame状态,不要重置为false */
-                /* in_frame状态应该保持,因为我们可能正在处理一个跨缓冲区的帧 */
             }
         } else if (ret != PPP_ERR_OK) {
-            /* 检查是否是因为线程停止导致的错误 */
+            // 读取错误
             if (!g_ppp_rx_thread_running) {
-                PPP_DEBUG_DEBUG("PPP thread stopping, ignoring read error");
+                PPP_DEBUG_DEBUG("PPP receive thread stopping, ignoring read error");
                 break;
             }
             PPP_DEBUG_ERROR("PPP serial read error: %d", ret);
         } else {
-            /* ret == PPP_ERR_OK but bytes_read == 0 - no data available */
-            static uint32_t no_data_count = 0;
-            no_data_count++;
+            // 没有数据,短暂休眠
+            osal_msleep(1);
+        }
+
+        // 定期打印统计信息
+        if ((total_frames % 100) == 0 && total_frames > 0) {
+            PPP_DEBUG_DEBUG("PPP RX: %u frames assembled, %u total bytes", 
+                total_frames, total_bytes);
+        }
+    }
+
+    // 释放缓冲区
+    free(rx_buffer);
+
+    PPP_DEBUG_INFO("PPP receive thread completed");
+    g_ppp_rx_thread_completed = true;
+}
+
+/**
+ * @brief PPP帧处理线程 - 从队列获取完整帧并处理
+ */
+static void ppp_lwip_process_thread(void *arg)
+{
+    (void)arg;
+
+    PPP_DEBUG_INFO("PPP process thread started");
+
+    uint32_t processed_frames = 0;
+    uint32_t processed_bytes = 0;
+
+    // 主循环:从队列获取完整PPP帧并处理
+    while (g_ppp_process_thread_running) {
+        ppp_frame_t *frame = NULL;
+        uint32_t msg_size = sizeof(ppp_frame_t *);
+
+        // 从队列获取帧(超时100ms)
+        int ret = osal_msg_queue_read_copy(g_ppp_frame_queue, &frame, &msg_size, OSAL_MSGQ_WAIT_FOREVER);
+        
+        if (ret == OSAL_SUCCESS && frame) {
+            // 处理完整PPP帧
+            PPP_DEBUG_DEBUG("Processing PPP frame: %u bytes", frame->length);
             
-            /* 减少无数据时的日志输出频率,避免日志开销 */
-            if (no_data_count % 5000 == 0) {  /* 每5000次无数据时打印一次 */
-                PPP_DEBUG_DEBUG("PPP RX: No data available (count: %u)", no_data_count);
-            }
+            // 调用lwIP处理
+            ppp_lwip_input(frame->data, frame->length);
+            
+            // 更新统计
+            processed_frames++;
+            processed_bytes += frame->length;
+            
+            // 更新处理统计
+            g_ppp_discard_stats.total_frames_processed++;
+            g_ppp_discard_stats.total_bytes_processed += frame->length;
             
-            /* 适应性休眠策略,避免过度占用CPU */
-            if (no_data_count % 5 == 0) {  /* 每5次无数据后短暂休眠 */
-                osal_msleep(2);  /* 2ms休眠,让出CPU给tcpip_thread */
+            // 释放帧内存
+            free(frame->data);
+            free(frame);
+            
+            // 定期打印统计
+            if ((processed_frames % 50) == 0) {
+                PPP_DEBUG_DEBUG("PPP Process: %u frames, %u bytes processed", 
+                    processed_frames, processed_bytes);
+            }
+        } else if (ret != OSAL_SUCCESS) {
+            // 超时或其他错误
+            if (!g_ppp_process_thread_running) {
+                PPP_DEBUG_DEBUG("PPP process thread stopping");
+                break;
+            }
+            // 超时是正常的,其他错误才需要警告
+            if (ret != 0) {  // 假设超时返回非0值
+                PPP_DEBUG_WARN("Failed to read from frame queue: %d", ret);
             }
         }
-        
-        // 统计信息输出 - 每5000次循环输出一次,减少日志开销
-        if ((total_packets % 5000) == 0 && total_packets > 0) {
-            PPP_DEBUG_DEBUG("PPP lwIP RX: %u fragments, %u complete frames, %u total bytes", 
-                          total_packets, complete_frames, total_bytes);
-        }
-        
-        // 适应性休眠以避免CPU占用过高,给tcpip_thread更多时间
-        if (complete_frames > 0) {
-            osal_msleep(5);  /* 有数据时短休眠 */
-        } else {
-            osal_msleep(15); /* 无数据时长休眠 */
+        // 超时是正常的,继续循环
+    }
+
+    // 清理队列中剩余的帧
+    ppp_frame_t *frame = NULL;
+    uint32_t msg_size = sizeof(ppp_frame_t *);
+    while (osal_msg_queue_read_copy(g_ppp_frame_queue, &frame, &msg_size, 0) == OSAL_SUCCESS) {
+        if (frame) {
+            free(frame->data);
+            free(frame);
         }
     }
-    
-    /* 清理资源 */
-    free(rx_buffer);
-    free(stream_buffer);
-    
-    PPP_DEBUG_INFO("PPP lwIP receive thread completed");
-    g_ppp_rx_thread_completed = true;
-    
-    PPP_DEBUG_INFO("PPP lwIP receive thread exiting");
+
+    PPP_DEBUG_INFO("PPP process thread completed, processed %u frames, %u bytes", 
+                   processed_frames, processed_bytes);
+    g_ppp_process_thread_completed = true;
 }
 
 /**
- * @brief 启动PPP接收线程 - 参考slipif_init方式
+ * @brief 启动PPP接收和处理线程
  */
 ppp_error_t ppp_lwip_start_receive_thread(void)
 {
-    if (g_ppp_rx_thread != NULL) {
-        PPP_DEBUG_WARN("PPP lwIP receive thread already running");
+    if (g_ppp_rx_thread != NULL || g_ppp_process_thread != NULL) {
+        PPP_DEBUG_WARN("PPP threads already running");
         return PPP_ERR_INVALID_STATE;
     }
     
-    PPP_DEBUG_INFO("Starting PPP lwIP receive thread");
+    PPP_DEBUG_INFO("Starting PPP receive and process threads");
+    
+    // 初始化帧拼包器
+    ppp_error_t ret = ppp_frame_assembler_init();
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to initialize frame assembler");
+        return ret;
+    }
+    
+    // 创建帧队列
+    int queue_ret = osal_msg_queue_create("ppp_frames", 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 frame queue: %d", queue_ret);
+        ppp_frame_assembler_cleanup();
+        return PPP_ERR_MEMORY;
+    }
     
-    // 重置线程完成标志
+    // 重置完成标志
     g_ppp_rx_thread_completed = false;
+    g_ppp_process_thread_completed = false;
     
-    // 设置线程运行标志为true(在创建线程之前)
-    g_ppp_rx_thread_running = true;
+    // 启动处理线程
+    g_ppp_process_thread_running = true;
+    g_ppp_process_thread = osal_kthread_create((osal_kthread_handler)ppp_lwip_process_thread, 
+                                               NULL, "ppp_process", 4096);
+    if (!g_ppp_process_thread) {
+        PPP_DEBUG_ERROR("Failed to create PPP process thread");
+        g_ppp_process_thread_running = false;
+        osal_msg_queue_delete(g_ppp_frame_queue);
+        g_ppp_frame_queue = 0;
+        ppp_frame_assembler_cleanup();
+        return PPP_ERR_MEMORY;
+    }
     
-    // 创建线程 - 使用正确的OSAL API
+    // 启动接收线程
+    g_ppp_rx_thread_running = true;
     g_ppp_rx_thread = osal_kthread_create((osal_kthread_handler)ppp_lwip_receive_thread, 
-                                          NULL, "ppp_lwip_rx", 4096);
-    if (g_ppp_rx_thread == NULL) {
-        PPP_DEBUG_ERROR("Failed to create PPP lwIP receive thread");
-        g_ppp_rx_thread_running = false;  // 创建失败时重置标志
+                                          NULL, "ppp_receive", 4096);
+    if (!g_ppp_rx_thread) {
+        PPP_DEBUG_ERROR("Failed to create PPP receive thread");
+        g_ppp_rx_thread_running = false;
+        
+        // 清理处理线程
+        g_ppp_process_thread_running = false;
+        osal_kthread_destroy(g_ppp_process_thread, 0);
+        g_ppp_process_thread = NULL;
+        
+        // 清理资源
+        osal_msg_queue_delete(g_ppp_frame_queue);
+        g_ppp_frame_queue = 0;
+        ppp_frame_assembler_cleanup();
         return PPP_ERR_MEMORY;
     }
     
-    PPP_DEBUG_INFO("PPP lwIP receive thread started successfully");
+    PPP_DEBUG_INFO("PPP receive and process threads started successfully");
     return PPP_ERR_OK;
 }
 
 /**
- * @brief 停止PPP接收线程
+ * @brief 停止PPP接收和处理线程
  */
 ppp_error_t ppp_lwip_stop_receive_thread(void)
 {
-    if (g_ppp_rx_thread == NULL) {
+    if (!g_ppp_rx_thread && !g_ppp_process_thread) {
         return PPP_ERR_OK;
     }
     
-    PPP_DEBUG_INFO("Stopping PPP lwIP receive thread");
-    
-    // 停止线程
-    g_ppp_rx_thread_running = false;
+    PPP_DEBUG_INFO("Stopping PPP receive and process threads");
     
-    // 等待线程完成,使用completion flag进行同步
-    int wait_count = 0;
-    const int max_wait = 100; // 最多等待1秒
+    // 停止接收线程
+    if (g_ppp_rx_thread) {
+        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) {
+            osal_msleep(10);
+            wait_count++;
+        }
+        
+        if (g_ppp_rx_thread_completed) {
+            PPP_DEBUG_DEBUG("PPP receive thread completed gracefully");
+        } else {
+            PPP_DEBUG_WARN("PPP receive thread did not complete within timeout");
+        }
+        
+        osal_kthread_destroy(g_ppp_rx_thread, 0);
+        g_ppp_rx_thread = NULL;
+    }
     
-    while (wait_count < max_wait && !g_ppp_rx_thread_completed) {
-        osal_msleep(10);
-        wait_count++;
+    // 停止处理线程
+    if (g_ppp_process_thread) {
+        g_ppp_process_thread_running = false;
+        
+        // 等待处理线程完成
+        int wait_count = 0;
+        const int max_wait = 100;
+        
+        while (wait_count < max_wait && !g_ppp_process_thread_completed) {
+            osal_msleep(10);
+            wait_count++;
+        }
+        
+        if (g_ppp_process_thread_completed) {
+            PPP_DEBUG_DEBUG("PPP process thread completed gracefully");
+        } else {
+            PPP_DEBUG_WARN("PPP process thread did not complete within timeout");
+        }
+        
+        osal_kthread_destroy(g_ppp_process_thread, 0);
+        g_ppp_process_thread = NULL;
     }
     
-    if (g_ppp_rx_thread_completed) {
-        PPP_DEBUG_DEBUG("PPP thread completed gracefully after %d ms", wait_count * 10);
-    } else {
-        PPP_DEBUG_WARN("PPP thread did not complete within timeout, forcing termination");
+    // 清理队列
+    if (g_ppp_frame_queue != 0) {
+        osal_msg_queue_delete(g_ppp_frame_queue);
+        g_ppp_frame_queue = 0;
     }
     
-    // 销毁线程
-    osal_kthread_destroy(g_ppp_rx_thread, 0);
-    g_ppp_rx_thread = NULL;
+    // 清理帧拼包器
+    ppp_frame_assembler_cleanup();
     
     // 重置状态标志
     g_ppp_rx_thread_running = false;
+    g_ppp_process_thread_running = false;
     g_ppp_rx_thread_completed = false;
+    g_ppp_process_thread_completed = false;
     
-    PPP_DEBUG_INFO("PPP lwIP receive thread stopped");
+    PPP_DEBUG_INFO("PPP receive and process threads stopped");
     return PPP_ERR_OK;
 }
 
@@ -255,5 +525,60 @@ ppp_error_t ppp_lwip_stop_receive_thread(void)
  */
 bool ppp_lwip_is_receive_thread_running(void)
 {
-    return g_ppp_rx_thread_running && (g_ppp_rx_thread != NULL);
+    return g_ppp_rx_thread_running && (g_ppp_rx_thread != NULL) &&
+           g_ppp_process_thread_running && (g_ppp_process_thread != NULL);
+}
+
+/**
+ * @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));
+    }
+}
+
+/**
+ * @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");
+}
+
+/**
+ * @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);
+    }
+    
+    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);
+    }
+    PPP_DEBUG_INFO("==============================");
 } 
\ No newline at end of file
index 4caa55a..804d179 100644 (file)
@@ -377,7 +377,7 @@ ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length)
             // PPP_DEBUG_HEXDUMP(data, length);
             
             PPP_DEBUG_DEBUG("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=1000)...", 
-                          g_serial_ctx.uart_bus, data, length);
+                          g_serial_ctx.uart_bus, data, length, 1000);
             
             write_result = uapi_uart_write(g_serial_ctx.uart_bus, data, length, 1000);
             PPP_DEBUG_DEBUG("uapi_uart_write returned: %d (expected: %u)", write_result, length);
@@ -398,15 +398,19 @@ ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length)
             /* PPP数据模式:直接使用UART发送(与AT模式一致) */
             PPP_DEBUG_INFO("Sending %u bytes via UART (PPP data mode)", length);
             
-            // 打印PPP数据包内容用于调试
-            // PPP_DEBUG_PRINT("PPP TX Data: ");
-            // for (uint32_t i = 0; i < length && i < 16; i++) {
-            //     PPP_DEBUG_PRINT("%02X ", data[i]);
-            // }
-            // if (length > 16) {
-            //     PPP_DEBUG_PRINT("... (total %u bytes)", length);
-            // }
-            // PPP_DEBUG_PRINT("\n");
+            /* 检查UART状态 */
+            PPP_DEBUG_DEBUG("UART Bus: %u, Mode: PPP_DATA, TX Bytes: %u, TX Errors: %u", 
+                          g_serial_ctx.uart_bus, g_serial_ctx.tx_bytes, g_serial_ctx.tx_errors);
+            
+            /* 打印要发送的数据 */
+            PPP_DEBUG_PRINT("PPP TX Data: ");
+            for (uint32_t i = 0; i < length && i < 16; i++) {
+                PPP_DEBUG_PRINT("%02X ", data[i]);
+            }
+            if (length > 16) {
+                PPP_DEBUG_PRINT("... (total %u bytes)", length);
+            }
+            PPP_DEBUG_PRINT("\n");
             
             PPP_DEBUG_DEBUG("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=%d)...", 
                           g_serial_ctx.uart_bus, data, length, PPP_OPTIMIZED_UART_WRITE_TIMEOUT);
@@ -417,7 +421,9 @@ ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length)
             
             if (write_result != (int32_t)length) {
                 PPP_DEBUG_ERROR("UART write failed in PPP data mode: returned %d, expected %u", write_result, length);
-                PPP_DEBUG_ERROR("Possible causes: UART not initialized, hardware error, or timeout");
+                PPP_DEBUG_ERROR("UART状态: bus=%u, 总发送字节=%u, 总错误=%u", 
+                              g_serial_ctx.uart_bus, g_serial_ctx.tx_bytes, g_serial_ctx.tx_errors);
+                PPP_DEBUG_ERROR("可能原因: UART未初始化、硬件错误、超时或缓冲区满");
                 g_serial_ctx.tx_errors++;
                 result = PPP_ERR_UART;
             } else {
index 5e8c977..0365bf0 100644 (file)
@@ -235,11 +235,37 @@ errcode_t tcp_test_stop(void)
         g_tcp_test_manager.stats_timer_id = 0;
     }
     
-    // 等待所有连接线程结束
+    // 等待所有连接线程结束 - 增加等待时间和检查机制
     printf("等待所有连接关闭...\n");
-    TCP_SLEEP_MS(2000); // 给线程时间退出
     
-    // 强制关闭所有socket
+    // 等待线程自然退出,最多等待10秒
+    int wait_count = 0;
+    bool all_threads_stopped = false;
+    
+    while (wait_count < 100 && !all_threads_stopped) { // 最多等待10秒
+        all_threads_stopped = true;
+        
+        for (int i = 0; i < g_tcp_test_manager.config.connection_count; i++) {
+            tcp_connection_stats_t *conn = &g_tcp_test_manager.connections[i];
+            if (conn->thread_running) {
+                all_threads_stopped = false;
+                break;
+            }
+        }
+        
+        if (!all_threads_stopped) {
+            TCP_SLEEP_MS(100); // 每次等待100ms
+            wait_count++;
+        }
+    }
+    
+    if (all_threads_stopped) {
+        printf("所有线程已正常退出\n");
+    } else {
+        printf("警告:部分线程未能在超时时间内退出\n");
+    }
+    
+    // 现在安全地关闭所有socket(线程应该已经退出)
     for (int i = 0; i < g_tcp_test_manager.config.connection_count; i++) {
         tcp_connection_stats_t *conn = &g_tcp_test_manager.connections[i];
         if (conn->socket_fd >= 0) {
@@ -366,16 +392,41 @@ static void* tcp_test_connection_worker(void *arg)
         }
         
         // 发送数据
+        ZHIHUI_TCP_LOG_DEBUG("[连接 %03d] 准备发送 %d 字节数据", conn_id, data_size);
+        ZHIHUI_TCP_LOG_DEBUG("[连接 %03d] Socket FD: %d, 连接状态: %s", 
+                            conn_id, conn->socket_fd, conn->connected ? "已连接" : "未连接");
+        
+        // 检查socket状态
+        int socket_error = 0;
+        socklen_t error_len = sizeof(socket_error);
+        if (TCP_GETSOCKOPT(conn->socket_fd, SOL_SOCKET, SO_ERROR, &socket_error, &error_len) == 0) {
+            if (socket_error != 0) {
+                ZHIHUI_TCP_LOG_ERROR("[连接 %03d] Socket错误状态: %d (%s)", 
+                                    conn_id, socket_error, TCP_STRERROR(socket_error));
+            } else {
+                ZHIHUI_TCP_LOG_DEBUG("[连接 %03d] Socket状态正常", conn_id);
+            }
+        }
+        
         ssize_t bytes_sent = TCP_SEND(conn->socket_fd, send_buffer, data_size, 0);
+        ZHIHUI_TCP_LOG_DEBUG("[连接 %03d] TCP_SEND返回: %ld (期望: %d)", conn_id, bytes_sent, data_size);
+        
         if (bytes_sent != (ssize_t)data_size) {
             if (bytes_sent < 0) {
-                ZHIHUI_TCP_LOG_ERROR("[连接 %03d] 发送失败: %s", conn_id, TCP_STRERROR(TCP_GET_ERRNO()));
+                int err = TCP_GET_ERRNO();
+                ZHIHUI_TCP_LOG_ERROR("[连接 %03d] 发送失败: %s (errno: %d)", 
+                                    conn_id, TCP_STRERROR(err), err);
+                ZHIHUI_TCP_LOG_ERROR("[连接 %03d] 发送失败详情: socket_fd=%d, data_size=%d, flags=0", 
+                                    conn_id, conn->socket_fd, data_size);
                 conn->errors++;
                 break;
             } else {
                 ZHIHUI_TCP_LOG_WARN("[连接 %03d] 发送不完整 (%ld/%d 字节)", 
                               conn_id, bytes_sent, data_size);
+                ZHIHUI_TCP_LOG_WARN("[连接 %03d] 部分发送可能是正常的,继续执行", conn_id);
             }
+        } else {
+            ZHIHUI_TCP_LOG_DEBUG("[连接 %03d] 发送成功: %ld 字节", conn_id, bytes_sent);
         }
         
         conn->packets_sent++;