#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS
#define LWIP_DISABLE_TCP_SANITY_CHECKS 1
#endif
-#define LWIP_DEBUG 0
-#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF
-#define SOCKETS_DEBUG LWIP_DBG_OFF
+
+#if 0
+#define LWIP_DEBUG LWIP_DBG_ON
+#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
+#define SOCKETS_DEBUG LWIP_DBG_ON
+#define TCP_DEBUG LWIP_DBG_ON
+#define TCP_INPUT_DEBUG LWIP_DBG_ON
+#define TCP_OUTPUT_DEBUG LWIP_DBG_ON
+#define TCP_INPKT_DEBUG LWIP_DBG_ON
+#endif
#ifndef LWIP_SLIP
#define LWIP_SLIP 0
#define PPP_INPROC_IRQ_SAFE 0
#endif
+/* PPP MRU配置控制 - 用于防止发送分片 */
+#ifndef PPP_ENABLE_LARGE_MRU
+#define PPP_ENABLE_LARGE_MRU 0 // 0=禁用1500字节MRU(防止分片), 1=启用1500字节MRU
+#endif
+
+#if PPP_ENABLE_LARGE_MRU
+#define PPP_MRU_SIZE 1500 // PPP MRU大小 - 启用大MRU
+#else
+#define PPP_MRU_SIZE 1500 // PPP MRU大小 - 限制为128字节防止分片
+#endif
+
#elif defined(SLIP_MODULE_ENABLED) && !defined(PPP_MODULE_ENABLED)
/* SLIP模式配置 */
#ifndef LWIP_SLIP
* debug messages of certain types.
*/
#ifndef LWIP_DBG_TYPES_ON
-#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF
+#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
#endif
#ifndef IP_DEBUG
-#define IP_DEBUG LWIP_DBG_OFF
+#define IP_DEBUG LWIP_DBG_ON
#endif
#ifndef ETHARP_DEBUG
#endif
#ifndef NETIF_DEBUG
-#define NETIF_DEBUG LWIP_DBG_OFF
+#define NETIF_DEBUG LWIP_DBG_ON
#endif
#ifndef L3_EVENT_MSG_DEBUG
* messages are written.
*/
#ifndef LWIP_DBG_MIN_LEVEL
-#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_OFF
+#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
#endif
#ifndef LWIP_SOCKET_POLL
#define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE)
#define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING)
#define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING)
-#define LOG_INFO (PPP_DEBUG)
+#define LOG_INFO (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING)
#define LOG_DETAIL (PPP_DEBUG)
#define LOG_DEBUG (PPP_DEBUG)
return -1;
}
#endif
-/**
- * @brief AI流式录音发送桩函数
- * @param data 音频数据
- * @param len 数据长度
- * @param session_id 会话ID
- * @return 总是返回失败(-1)
- */
-int streamingRecordAndSend_AI(void *data, int len, const char *session_id)
-{
- (void)data;
- (void)len;
- (void)session_id;
-
- // 桩函数 - 不实现实际功能
- return -1;
-}
-/**
- * @brief AI消息队列发送桩函数
- * @param msg_data 消息数据
- * @param data_len 数据长度
- * @param type 消息类型
- * @return 总是返回失败(-1)
- */
-int send_msg_data_into_Ai_msg_queue(void *msg_data, uint16_t data_len, uint16_t type)
-{
- (void)msg_data;
- (void)data_len;
- (void)type;
-
- // 桩函数 - 不实现实际功能
- return -1;
-}
-/**
- * @brief 蓝牙设置AI回答字符串桩函数
- * @param answer_str AI回答字符串
- * @param type 消息类型
- */
-void ble_set_ai_Answer_str(char *answer_str, uint8_t type)
-{
- (void)answer_str;
- (void)type;
-
- // 桩函数 - 不实现实际功能
-}
-/**
- * @brief 蓝牙设置AI问题字符串桩函数
- * @param question_str AI问题字符串
- */
-void ble_set_ai_Question_str(char *question_str)
-{
- (void)question_str;
-
- // 桩函数 - 不实现实际功能
-}
#ifdef SUPPORT_CAT1_SERVICE
)
# 源文件列表
set(SOURCES
- src/ppp_api.c
- src/ppp_at_handler.c
- src/ppp_serial.c
- src/ppp_lwip.c
- src/ppp_lwip_thread.c
- src/ppp_debug.c
- src/ppp_debug_manager.c
- src/ppp_power_ctl.c
- src/ppp_cat1_api.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_api.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_at_handler.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_serial.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_lwip.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_lwip_thread.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_debug.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_debug_manager.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_power_ctl.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_cat1_api.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ppp_interrupt.c
${PPP_AT_CMD_SOURCE}
)
PPP_USE_PBUF_RAM=1
PPP_FCS_TABLE=1
PRINTPKT_SUPPORT=1
- PPP_DEBUG=LWIP_DBG_ON
+ PPP_DEBUG=0x80U
PPP_INPROC_IRQ_SAFE=0
# 添加IPCP相关配置
IPCP_SUPPORT=1
LWIP_DNS=1
DNS_TABLE_SIZE=2
# 启用IPCP调试
- IPCP_DEBUG=LWIP_DBG_ON
+ IPCP_DEBUG=0x80U
# 确保IPCP功能完全启用
PPP_IPV4_SUPPORT=1
# 启用LCP相关功能
config.test_duration = (uint32_t)test_time;
config.connection_count = (uint16_t)connections;
config.verbose = true; // AT命令模式不使用详细输出
- config.send_interval_ms = 100; // 100ms间隔,适合AT命令模式
+ config.send_interval_ms = 500; // 500ms间隔,给其他进程更多CPU时间
config.data_min_size = 1024; // 较小的数据包
config.data_max_size = 4096; // 适中的最大包
config.recv_timeout_ms = (uint32_t)recv_timeout_ms; // 可配置的接收超时
#define PPP_DIAL_RETRY_COUNT 3 // 拨号重试次数
#define PPP_KEEPALIVE_INTERVAL 30 // 保活间隔(秒)
+/* PPP接收模式配置 */
+#ifndef PPP_USE_INTERRUPT_MODE
+#define PPP_USE_INTERRUPT_MODE 1 // 1=中断模式(UART中断接收), 0=轮询模式(线程轮询)
+#endif
+
+/* PPP线程模式配置(仅轮询模式有效) */
+#ifndef PPP_USE_DUAL_THREAD
+#define PPP_USE_DUAL_THREAD 1 // 1=双线程模式(接收+处理), 0=单线程模式(接收直接处理)
+#endif
+
+/* PPP性能优化配置 - 解决接收阻塞问题 */
+#define PPP_LWIP_PBUF_POOL_SIZE 32 // 增加pbuf池大小,默认16太小
+#define PPP_LWIP_TCPIP_MSG_INPKT 64 // 增加输入消息数量,默认32太小
+#define PPP_LWIP_TCPIP_MBOX_SIZE 128 // 增加TCPIP邮箱大小,默认64太小
+#define PPP_LWIP_TCP_RECVMBOX_SIZE 256 // 增加TCP接收邮箱大小,默认128太小
+#define PPP_LWIP_TCP_WND_SIZE 65536 // 增加TCP接收窗口,默认32KB太小
+
/* 缓冲区大小配置 */
#define PPP_RX_BUFFER_SIZE 2048 // 接收缓冲区大小
#define PPP_TX_BUFFER_SIZE 2048 // 发送缓冲区大小
#define PPP_RX_THREAD_STACK_SIZE 4096 // 接收线程栈大小
#define PPP_RX_THREAD_PRIORITY osPriorityNormal // 接收线程优先级
-/* PPP网络配置 */
-#define PPP_MTU_SIZE 1500 // PPP MTU大小
-#define PPP_MRU_SIZE 1500 // PPP MRU大小
-
/* 调试配置 */
#define PPP_DEBUG_ENABLE 1 // 启用调试输出
#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_INFO // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
--- /dev/null
+/**
+ * @file ppp_interrupt.h
+ * @brief PPP UART中断接收处理头文件
+ */
+
+#ifndef PPP_INTERRUPT_H
+#define PPP_INTERRUPT_H
+
+#include "ppp_types.h"
+#include "uart.h"
+#include "pinctrl.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief PPP中断统计信息
+ */
+typedef struct {
+ uint32_t total_interrupts; // 总中断次数
+ uint32_t success_count; // 成功处理次数
+ uint32_t error_count; // 错误次数
+ uint32_t lwip_error_count; // lwIP错误次数
+
+ uint32_t total_bytes_received; // 总接收字节数
+ uint32_t total_bytes_sent_to_lwip; // 发送到lwIP的字节数
+
+ uint32_t dropped_not_initialized; // 因PPP未初始化丢弃的字节数
+ uint32_t dropped_lwip_error; // 因lwIP错误丢弃的字节数
+} ppp_interrupt_stats_t;
+
+/**
+ * @brief UART接收中断回调函数(由UART驱动调用)
+ * @param buffer 接收数据缓冲区
+ * @param length 数据长度
+ * @param error 是否有错误
+ */
+void ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error);
+
+/**
+ * @brief 获取UART硬件缓冲区配置(供外部UART初始化使用)
+ * @param rx_buffer 返回接收缓冲区指针
+ * @param buffer_size 返回缓冲区大小
+ */
+void ppp_interrupt_get_buffer_config(void **rx_buffer, uint32_t *buffer_size);
+
+/**
+ * @brief 启用PPP UART中断接收
+ * @return PPP_ERR_OK 成功,其他值失败
+ *
+ * @note 调用此函数前:
+ * 1. ppp_serial必须已初始化(UART总线号从ppp_serial_get_uart_bus()获取)
+ * 2. UART必须已经初始化并配置了硬件缓冲区
+ * 3. 使用 ppp_interrupt_get_buffer_config() 获取缓冲区配置
+ */
+ppp_error_t ppp_interrupt_enable(void);
+
+/**
+ * @brief 禁用PPP UART中断接收
+ * @return PPP_ERR_OK 成功,其他值失败
+ */
+ppp_error_t ppp_interrupt_disable(void);
+
+/**
+ * @brief 检查中断是否已启用
+ * @return true 已启用,false 未启用
+ */
+bool ppp_interrupt_is_enabled(void);
+
+/**
+ * @brief 获取中断统计信息
+ * @param stats 统计信息输出缓冲区
+ */
+void ppp_interrupt_get_stats(ppp_interrupt_stats_t *stats);
+
+/**
+ * @brief 重置中断统计信息
+ */
+void ppp_interrupt_reset_stats(void);
+
+/**
+ * @brief 打印中断统计信息
+ */
+void ppp_interrupt_print_stats(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PPP_INTERRUPT_H */
\ No newline at end of file
*/
ppp_error_t ppp_lwip_get_output_stats(ppp_lwip_output_stats_t *stats);
+// /**
+// * @brief 获取PPP控制块(供中断处理模块使用)
+// * @return PPP控制块指针,如果未初始化则返回NULL
+// */
+// ppp_pcb* ppp_lwip_get_pcb(void);
+
+/**
+ * @brief 检查PPP lwIP是否已初始化(供中断处理模块使用)
+ * @return true 已初始化,false 未初始化
+ */
+bool ppp_lwip_is_initialized(void);
+
+/**
+ * @brief 打印lwIP内存使用情况(用于诊断)
+ */
+void ppp_lwip_print_memory_stats(void);
+
#ifdef __cplusplus
}
#endif
*/
ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *bytes_read);
+/**
+ * @brief PPP快速尝试读取 - 类似SLIP的sio_tryread,使用1ms超时
+ * @param buffer 接收缓冲区
+ * @param buffer_size 缓冲区大小
+ * @param bytes_read 实际读取字节数
+ * @return 错误码
+ */
+ppp_error_t ppp_serial_tryread(uint8_t *buffer, uint32_t buffer_size, uint32_t *bytes_read);
+
/**
* @brief 等待数据接收
* @param timeout_ms 超时时间(毫秒)
/**
* @brief 获取串口统计信息
+ * @param stats 统计信息结构指针
+ * @return 错误码
+ */
+ppp_error_t ppp_serial_get_stats(ppp_serial_stats_t *stats);
+
+/**
+ * @brief 获取UART总线号
+ * @return UART总线号,如果未初始化返回UART_BUS_0
+ */
+uint8_t ppp_serial_get_uart_bus(void);
+
+/**
+ * @brief PPP中断接收回调函数 - 用于高效数据接收
+ * @param buffer 接收到的数据缓冲区
+ * @param length 数据长度
+ * @param error 是否有错误
+ * @note 此函数应该在UART中断回调中调用,类似SLIP的uart_read_data_int_handler
+ */
+void ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error);
+
+/**
+ * @brief 获取中断接收队列统计信息
+ * @param queue_count 队列中的数据块数量
+ * @param bytes_queued 队列中的字节数
+ * @param chunks_dropped 丢弃的数据块数量
*/
-uint32_t ppp_serial_get_stats(ppp_serial_stats_t *stats);
+void ppp_get_interrupt_rx_stats(uint32_t *queue_count, uint32_t *bytes_queued, uint32_t *chunks_dropped);
/**
* @brief 重置串口状态
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "ppp_parser.h"
+#include "ppp_packet_analyzer.h"
+#include "ppp_stream_parser.h"
+
+/* 配置常量 */
+#define MAX_FILE_SIZE (1024 * 1024) /* 最大文件大小1MB */
+#define MAX_FRAMES 10000 /* 最大帧数量 */
+#define CHUNK_SIZE 256 /* 流式处理块大小 */
+
+/* 全局变量 */
+static uint8_t g_hex_data[MAX_FILE_SIZE]; /* 十六进制数据缓冲区 */
+static ppp_frame_t g_frames[MAX_FRAMES]; /* PPP帧数组 */
+static packet_analysis_result_t g_results[MAX_FRAMES]; /* 分析结果数组 */
+
+/**
+ * 获取当前时间(微秒)
+ */
+static uint64_t get_time_us(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+/**
+ * 从十六进制字符串转换为字节值
+ */
+static int hex_char_to_byte(char hex_char)
+{
+ if (hex_char >= '0' && hex_char <= '9') {
+ return hex_char - '0';
+ } else if (hex_char >= 'A' && hex_char <= 'F') {
+ return hex_char - 'A' + 10;
+ } else if (hex_char >= 'a' && hex_char <= 'f') {
+ return hex_char - 'a' + 10;
+ }
+ return -1;
+}
+
+/**
+ * 从文件中读取十六进制数据
+ */
+static uint32_t read_hex_file(const char *file_path, uint8_t *data, uint32_t max_size)
+{
+ if (!file_path || !data || max_size == 0) {
+ return 0;
+ }
+
+ FILE *file = fopen(file_path, "r");
+ if (!file) {
+ printf("错误: 无法打开文件 %s: %s\n", file_path, strerror(errno));
+ return 0;
+ }
+
+ char line[256];
+ uint32_t data_len = 0;
+
+ while (fgets(line, sizeof(line), file) && data_len < max_size) {
+ /* 移除行尾的换行符和空白字符 */
+ char *end = line + strlen(line) - 1;
+ while (end >= line && isspace(*end)) {
+ *end-- = '\0';
+ }
+
+ /* 跳过空行 */
+ if (strlen(line) == 0) {
+ continue;
+ }
+
+ /* 处理每行的十六进制字符串 */
+ char *ptr = line;
+ while (*ptr && data_len < max_size) {
+ /* 跳过空白字符 */
+ while (*ptr && isspace(*ptr)) {
+ ptr++;
+ }
+
+ if (!*ptr) break;
+
+ /* 读取两个十六进制字符组成一个字节 */
+ if (strlen(ptr) >= 2) {
+ int high = hex_char_to_byte(ptr[0]);
+ int low = hex_char_to_byte(ptr[1]);
+
+ if (high >= 0 && low >= 0) {
+ data[data_len++] = (high << 4) | low;
+ ptr += 2;
+ } else {
+ ptr += 2;
+ }
+ } else if (strlen(ptr) == 1) {
+ /* 单个十六进制字符,当作一个字节处理 */
+ int value = hex_char_to_byte(ptr[0]);
+ if (value >= 0) {
+ data[data_len++] = value;
+ ptr++;
+ } else {
+ ptr++;
+ }
+ }
+ }
+ }
+
+ fclose(file);
+ return data_len;
+}
+
+/**
+ * 传统解析器性能测试
+ */
+static void test_traditional_parser(const char *file_path, uint32_t data_len)
+{
+ printf("\n=== 传统解析器性能测试 ===\n");
+
+ uint64_t start_time = get_time_us();
+
+ /* 初始化解析器 */
+ ppp_parser_t parser;
+ ppp_parser_init(&parser);
+
+ uint64_t init_time = get_time_us();
+
+ /* 解析PPP帧 */
+ uint32_t frame_count = ppp_parser_process_data(&parser, g_hex_data, data_len,
+ g_frames, MAX_FRAMES);
+
+ uint64_t parse_time = get_time_us();
+
+ /* 包内容分析 */
+ packet_stats_t packet_stats;
+ uint32_t analyzed_count = analyze_ppp_frames(g_frames, frame_count,
+ g_results, &packet_stats);
+
+ uint64_t analyze_time = get_time_us();
+
+ /* 打印性能统计 */
+ printf("文件: %s\n", file_path);
+ printf("数据大小: %u 字节\n", data_len);
+ printf("解析帧数: %u\n", frame_count);
+ printf("分析帧数: %u\n", analyzed_count);
+ printf("时间统计:\n");
+ printf(" 初始化时间: %lu 微秒\n", init_time - start_time);
+ printf(" 解析时间: %lu 微秒\n", parse_time - init_time);
+ printf(" 分析时间: %lu 微秒\n", analyze_time - parse_time);
+ printf(" 总时间: %lu 微秒\n", analyze_time - start_time);
+ printf("性能指标:\n");
+ printf(" 解析速度: %.2f MB/s\n",
+ (double)data_len / (parse_time - init_time) * 1000000 / (1024 * 1024));
+ printf(" 分析速度: %.2f 帧/秒\n",
+ (double)frame_count / (analyze_time - parse_time) * 1000000);
+ printf(" 总体速度: %.2f MB/s\n",
+ (double)data_len / (analyze_time - start_time) * 1000000 / (1024 * 1024));
+
+ /* 内存使用估算 */
+ size_t memory_usage = sizeof(ppp_parser_t) +
+ sizeof(ppp_frame_t) * MAX_FRAMES +
+ sizeof(packet_analysis_result_t) * MAX_FRAMES;
+ printf("内存使用: %.2f KB (估算)\n", (double)memory_usage / 1024);
+}
+
+/**
+ * 流式解析器性能测试
+ */
+static void test_streaming_parser(const char *file_path, uint32_t data_len)
+{
+ printf("\n=== 流式解析器性能测试 ===\n");
+
+ uint64_t start_time = get_time_us();
+
+ /* 初始化帧收集器 */
+ ppp_frame_collector_t collector;
+ if (!ppp_frame_collector_init(&collector, MAX_FRAMES)) {
+ printf("错误: 无法初始化帧收集器\n");
+ return;
+ }
+
+ /* 初始化流式解析器 */
+ ppp_stream_parser_t parser;
+ if (!ppp_stream_parser_init(&parser,
+ 0, /* 使用默认最大帧大小 */
+ ppp_collector_start_callback,
+ ppp_collector_data_callback,
+ ppp_collector_complete_callback,
+ ppp_collector_error_callback,
+ &collector)) {
+ printf("错误: 无法初始化流式解析器\n");
+ ppp_frame_collector_free(&collector);
+ return;
+ }
+
+ uint64_t init_time = get_time_us();
+
+ /* 分块处理数据 */
+ uint32_t total_processed = 0;
+ uint32_t chunk_count = 0;
+
+ for (uint32_t offset = 0; offset < data_len; offset += CHUNK_SIZE) {
+ uint32_t chunk_size = (offset + CHUNK_SIZE > data_len) ?
+ (data_len - offset) : CHUNK_SIZE;
+
+ chunk_count++;
+ uint32_t processed = ppp_stream_parser_process(&parser,
+ g_hex_data + offset,
+ chunk_size);
+ total_processed += processed;
+ }
+
+ uint64_t parse_time = get_time_us();
+
+ /* 分析收集到的帧 */
+ uint32_t analyzed_count = 0;
+ for (uint32_t i = 0; i < collector.frame_count; i++) {
+ const uint8_t *frame_data;
+ uint32_t frame_len;
+
+ if (ppp_frame_collector_get_frame(&collector, i, &frame_data, &frame_len)) {
+ ppp_frame_t temp_frame;
+ temp_frame.payload_len = frame_len;
+ memcpy(temp_frame.payload, frame_data,
+ (frame_len > PPP_MAX_FRAME_SIZE) ? PPP_MAX_FRAME_SIZE : frame_len);
+
+ packet_analysis_result_t result;
+ if (analyze_ppp_frame(&temp_frame, &result)) {
+ analyzed_count++;
+ }
+ }
+ }
+
+ uint64_t analyze_time = get_time_us();
+
+ /* 打印性能统计 */
+ printf("文件: %s\n", file_path);
+ printf("数据大小: %u 字节\n", data_len);
+ printf("处理块数: %u (块大小: %d 字节)\n", chunk_count, CHUNK_SIZE);
+ printf("解析帧数: %u\n", collector.frame_count);
+ printf("分析帧数: %u\n", analyzed_count);
+ printf("时间统计:\n");
+ printf(" 初始化时间: %lu 微秒\n", init_time - start_time);
+ printf(" 解析时间: %lu 微秒\n", parse_time - init_time);
+ printf(" 分析时间: %lu 微秒\n", analyze_time - parse_time);
+ printf(" 总时间: %lu 微秒\n", analyze_time - start_time);
+ printf("性能指标:\n");
+ printf(" 解析速度: %.2f MB/s\n",
+ (double)data_len / (parse_time - init_time) * 1000000 / (1024 * 1024));
+ printf(" 分析速度: %.2f 帧/秒\n",
+ (double)collector.frame_count / (analyze_time - parse_time) * 1000000);
+ printf(" 总体速度: %.2f MB/s\n",
+ (double)data_len / (analyze_time - start_time) * 1000000 / (1024 * 1024));
+
+ /* 内存使用估算 */
+ size_t base_memory = sizeof(ppp_stream_parser_t) + sizeof(ppp_frame_collector_t);
+ size_t dynamic_memory = 0;
+ for (uint32_t i = 0; i < collector.frame_count; i++) {
+ dynamic_memory += collector.frame_lengths[i];
+ }
+ printf("内存使用: %.2f KB (基础) + %.2f KB (动态) = %.2f KB (总计)\n",
+ (double)base_memory / 1024,
+ (double)dynamic_memory / 1024,
+ (double)(base_memory + dynamic_memory) / 1024);
+
+ /* 清理资源 */
+ ppp_frame_collector_free(&collector);
+}
+
+/**
+ * 主函数
+ */
+int main(int argc, char *argv[])
+{
+ printf("PPP解析器性能测试工具\n");
+ printf("对比传统解析器和流式解析器的性能\n\n");
+
+ /* 确定要测试的文件 */
+ const char *test_file = (argc > 1) ? argv[1] : "out0.txt";
+
+ /* 读取测试数据 */
+ printf("读取测试文件: %s\n", test_file);
+ uint32_t data_len = read_hex_file(test_file, g_hex_data, MAX_FILE_SIZE);
+ if (data_len == 0) {
+ printf("错误: 无法读取测试文件\n");
+ return 1;
+ }
+
+ printf("成功读取 %u 字节数据\n", data_len);
+
+ /* 运行性能测试 */
+ test_traditional_parser(test_file, data_len);
+ test_streaming_parser(test_file, data_len);
+
+ /* 打印对比总结 */
+ printf("\n=== 性能对比总结 ===\n");
+ printf("传统解析器特点:\n");
+ printf(" - 一次性加载所有数据到内存\n");
+ printf(" - 固定大小的缓冲区\n");
+ printf(" - 简单的线性处理\n");
+ printf(" - 内存使用可预测\n\n");
+
+ printf("流式解析器特点:\n");
+ printf(" - 分块处理数据,内存占用固定\n");
+ printf(" - 支持任意大小的PPP帧\n");
+ printf(" - 回调机制,灵活的数据处理\n");
+ printf(" - 适合实时数据流处理\n");
+ printf(" - 动态内存分配,按需使用\n\n");
+
+ printf("推荐使用场景:\n");
+ printf(" 传统解析器: 小文件、批处理、内存充足\n");
+ printf(" 流式解析器: 大文件、实时处理、内存受限、嵌入式系统\n");
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+PPP协议解析工具
+用于解析out.txt和in.txt中的十六进制数据,识别TCP/UDP包并提取基本信息
+"""
+import struct
+import os
+import binascii
+
+class PPPFrameParser:
+ """PPP帧解析器,处理帧边界检测、字节填充和数据验证"""
+ def __init__(self):
+ self.buffer = bytearray() # 帧数据缓冲区
+ self.in_frame = False # 是否处于帧接收状态
+ self.dropped_data = [] # 记录丢弃的数据
+ self.last_dropped_position = -1 # 上一次丢弃数据的位置
+ self.fragmented_frames = {} # 存储分片的PPP帧 {frame_id: fragmented_data}
+
+ def process_byte(self, byte, position=None):
+ """处理单个字节,返回完整PPP帧(包含头尾0x7E)"""
+ if byte == 0x7E: # PPP帧标志位
+ if self.in_frame and len(self.buffer) > 0:
+ # 帧结束:添加结束标志并处理缓冲区数据
+ self.buffer.append(byte) # 添加结束0x7E
+ frame = self._parse_buffer_with_flags()
+ self.buffer.clear()
+ self.in_frame = False
+ return frame
+ else:
+ # 帧开始:初始化缓冲区并添加开始标志
+ # 如果有未处理的缓冲区数据,记录为丢弃数据
+ if self.in_frame and len(self.buffer) > 0:
+ self._record_dropped_data(self.buffer, position - len(self.buffer))
+ self.in_frame = True
+ self.buffer.clear()
+ self.buffer.append(byte) # 添加开始0x7E
+ else:
+ if self.in_frame:
+ self.buffer.append(byte)
+ return None
+
+ def _parse_buffer_with_flags(self):
+ """处理包含头尾0x7E的完整PPP帧,返回原始帧数据"""
+ # 验证帧头尾标志
+ if len(self.buffer) < 6: # 最小:0x7E + 地址1 + 控制1 + 协议2 + 0x7E = 6字节
+ self._record_dropped_data(self.buffer, None)
+ return None
+
+ if self.buffer[0] != 0x7E or self.buffer[-1] != 0x7E:
+ self._record_dropped_data(self.buffer, None)
+ return None
+
+ # 返回完整帧数据(包含头尾0x7E),转义字符处理将在分析阶段进行
+ return bytes(self.buffer)
+
+ def _unescape_ppp_frame(self, frame_content):
+ """处理PPP转义字符,输入是去掉头尾0x7E的帧内容"""
+ processed = bytearray()
+ i = 0
+ while i < len(frame_content):
+ if frame_content[i] == 0x7D: # 转义字符
+ if i + 1 < len(frame_content):
+ processed.append(frame_content[i+1] ^ 0x20)
+ i += 2
+ else:
+ # 不完整的转义序列
+ return None
+ else:
+ processed.append(frame_content[i])
+ i += 1
+ return processed
+
+ def _parse_buffer_simple(self):
+ """简化版缓冲区处理,只还原字节填充,不进行FCS校验"""
+ # 还原字节填充(0x7D后字节异或0x20)
+ processed = bytearray()
+ i = 0
+ while i < len(self.buffer):
+ if self.buffer[i] == 0x7D: # 转义字符
+ if i + 1 < len(self.buffer):
+ processed.append(self.buffer[i+1] ^ 0x20)
+ i += 2
+ else:
+ # 不完整的转义序列,记录为丢弃数据
+ self.dropped_data.append({
+ 'reason': '不完整的转义序列',
+ 'data': bytes(self.buffer),
+ 'position': self.last_dropped_position
+ })
+ return None
+ else:
+ processed.append(self.buffer[i])
+ i += 1
+
+ # 校验帧长度(最小:地址1 + 控制1 + 协议2 = 4字节)
+ if len(processed) < 4:
+ # 帧长度不足,记录为丢弃数据
+ self.dropped_data.append({
+ 'reason': '帧长度不足4字节',
+ 'data': bytes(self.buffer),
+ 'position': self.last_dropped_position
+ })
+ return None
+
+ # 返回处理后的数据
+ return processed
+
+ def _record_dropped_data(self, data, position):
+ """记录丢弃的数据"""
+ self.dropped_data.append({
+ 'reason': '帧同步丢失或格式错误',
+ 'data': bytes(data),
+ 'position': position
+ })
+ self.last_dropped_position = position
+
+ def get_dropped_data_count(self):
+ """获取丢弃的数据数量"""
+ return len(self.dropped_data)
+
+ def print_dropped_data(self):
+ """打印所有丢弃的数据"""
+ if not self.dropped_data:
+ print(" 没有丢弃的数据")
+ return
+
+ print(f" 丢弃的数据总数: {len(self.dropped_data)}")
+ # 只打印前5条丢弃的数据,避免输出过多
+ for i, dropped in enumerate(self.dropped_data[:5]):
+ print(f" 丢弃数据 #{i+1}:")
+ print(f" 原因: {dropped['reason']}")
+ print(f" 位置: {dropped['position']}")
+ print(f" 数据: {dropped['data'].hex().upper()}")
+
+ if len(self.dropped_data) > 5:
+ print(f" ... 还有{len(self.dropped_data) - 5}条丢弃的数据未显示")
+
+ def reassemble_fragment(self, frame):
+ """尝试重组分片的PPP帧
+ 在PPP中,分片是通过MP(多链路PPP)协议实现的,但这里我们使用简化的方式
+ 实际应用中可能需要根据具体的PPP扩展协议实现更复杂的重组逻辑
+ """
+ # 这个简化版本假设所有帧都是完整的,不处理分片
+ # 如果需要处理实际的PPP分片,需要根据具体的PPP扩展协议实现
+ return frame
+
+ def get_fragmented_frame_count(self):
+ """获取当前缓存的分片帧数量"""
+ return len(self.fragmented_frames)
+
+
+def calculate_ip_checksum(ip_header):
+ """计算IP头部校验和"""
+ # 将IP头部视为16位字的序列
+ words = [struct.unpack('!H', ip_header[i:i+2])[0] for i in range(0, len(ip_header), 2)]
+
+ # 如果头部长度为奇数,最后一个字节补零
+ if len(ip_header) % 2 == 1:
+ words.append(ip_header[-1] << 8)
+
+ # 计算校验和
+ checksum = sum(words)
+ # 将溢出的部分加到低16位
+ checksum = (checksum >> 16) + (checksum & 0xffff)
+ checksum += (checksum >> 16) # 再次处理溢出
+ # 取反得到最终校验和
+ return ~checksum & 0xffff
+
+
+def verify_ip_packet(ip_data):
+ """验证IP数据包的完整性和正确性"""
+ # 检查最小长度
+ if len(ip_data) < 20:
+ return False, "IP数据包长度不足20字节"
+
+ # 验证版本号(应为4)
+ version = (ip_data[0] >> 4) & 0x0F
+ if version != 4:
+ return False, f"非IPv4数据包,版本号: {version}"
+
+ # 验证头部长度
+ ihl = ip_data[0] & 0x0F
+ if ihl < 5 or ihl > 15:
+ return False, f"无效的IP头部长度: {ihl}"
+
+ # 检查总长度是否合理
+ total_length = (ip_data[2] << 8) | ip_data[3]
+ # 允许实际长度比声明长度多2字节(可能是PPP填充)
+ if not (total_length == len(ip_data) or total_length == len(ip_data) - 2):
+ return False, f"IP数据包长度不匹配: 头部声明{total_length}字节,实际{len(ip_data)}字节"
+
+ # 保存原始校验和
+ original_checksum = (ip_data[10] << 8) | ip_data[11]
+
+ # 清零校验和字段后重新计算
+ ip_header_copy = bytearray(ip_data[:ihl*4])
+ ip_header_copy[10] = 0
+ ip_header_copy[11] = 0
+
+ # 计算校验和
+ calculated_checksum = calculate_ip_checksum(ip_header_copy)
+
+ # 验证校验和
+ if original_checksum != calculated_checksum:
+ return False, f"IP校验和错误: 接收{original_checksum:04X},计算{calculated_checksum:04X}"
+
+ return True, "IP数据包验证通过"
+
+
+def parse_ip_packet(ip_data):
+ """解析IP数据包,提取基本信息"""
+ if len(ip_data) < 20: # IP头部最小长度为20字节
+ return None
+
+ # 解析IP头部(不考虑选项字段)
+ ip_header = struct.unpack('!BBHHHBBH4s4s', ip_data[:20])
+ version_ihl = ip_header[0]
+ protocol = ip_header[6] # 协议类型
+ src_ip = '.'.join(map(str, ip_header[8])) # 源IP地址
+ dst_ip = '.'.join(map(str, ip_header[9])) # 目标IP地址
+
+ # 计算IP数据部分的偏移量
+ ihl = (version_ihl & 0x0F) * 4
+ payload = ip_data[ihl:]
+
+ result = {
+ 'src_ip': src_ip,
+ 'dst_ip': dst_ip,
+ 'protocol': protocol
+ }
+
+ # 根据协议类型解析传输层数据
+ if protocol == 6: # TCP协议
+ result['protocol_name'] = 'TCP'
+ tcp_info = parse_tcp_packet(payload)
+ if tcp_info:
+ result.update(tcp_info)
+ elif protocol == 17: # UDP协议
+ result['protocol_name'] = 'UDP'
+ udp_info = parse_udp_packet(payload)
+ if udp_info:
+ result.update(udp_info)
+ else:
+ result['protocol_name'] = f'Unknown({protocol})'
+
+ return result
+
+def parse_tcp_packet(tcp_data):
+ """解析TCP数据包,提取端口信息"""
+ if len(tcp_data) < 20: # TCP头部最小长度为20字节
+ return None
+
+ # 解析TCP头部
+ tcp_header = struct.unpack('!HHLLBBHHH', tcp_data[:20])
+ src_port = tcp_header[0] # 源端口
+ dst_port = tcp_header[1] # 目标端口
+
+ return {
+ 'src_port': src_port,
+ 'dst_port': dst_port
+ }
+
+def parse_udp_packet(udp_data):
+ """解析UDP数据包,提取端口信息"""
+ if len(udp_data) < 8: # UDP头部固定为8字节
+ return None
+
+ # 解析UDP头部
+ udp_header = struct.unpack('!HHHH', udp_data[:8])
+ src_port = udp_header[0] # 源端口
+ dst_port = udp_header[1] # 目标端口
+
+ return {
+ 'src_port': src_port,
+ 'dst_port': dst_port
+ }
+
+def read_hex_file(file_path):
+ """从文件中读取十六进制数据"""
+ try:
+ with open(file_path, 'r', encoding='utf-8') as f:
+ lines = f.readlines()
+ # 移除每行的换行符并转换为字节
+ bytes_data = []
+ for i, line in enumerate(lines):
+ stripped_line = line.strip()
+ if stripped_line:
+ try:
+ # 转换十六进制字符串为整数
+ byte_value = int(stripped_line, 16)
+ if 0 <= byte_value <= 255:
+ bytes_data.append(byte_value)
+ else:
+ print(f"警告: 文件{file_path}第{i+1}行值{stripped_line}超出字节范围")
+ except ValueError:
+ print(f"警告: 文件{file_path}第{i+1}行'{stripped_line}'不是有效的十六进制字符串")
+ print(f"成功读取文件{file_path}: {len(bytes_data)}字节")
+ return bytearray(bytes_data)
+ except Exception as e:
+ print(f"读取文件{file_path}错误: {e}")
+ return None
+
+
+def group_ppp_frames(frames):
+ """对PPP帧进行组包处理,目前主要是简单的收集,后续可以扩展更复杂的组包逻辑"""
+ # 按协议类型对帧进行分组
+ grouped_frames = {}
+ for frame in frames:
+ if len(frame) >= 4:
+ protocol = (frame[2] << 8) | frame[3]
+ if protocol not in grouped_frames:
+ grouped_frames[protocol] = []
+ grouped_frames[protocol].append(frame)
+ else:
+ # 帧长度不足,无法解析协议
+ if 'invalid' not in grouped_frames:
+ grouped_frames['invalid'] = []
+ grouped_frames['invalid'].append(frame)
+
+ return grouped_frames
+
+def analyze_ppp_file(file_path):
+ """分析PPP文件并输出TCP/UDP包信息"""
+ print(f"\n开始分析文件: {file_path}")
+
+ # 读取文件数据
+ data = read_hex_file(file_path)
+ if not data:
+ return
+
+ parser = PPPFrameParser()
+ tcp_count = 0
+ udp_count = 0
+ other_count = 0
+ ppp_frame_count = 0
+ reassembled_count = 0 # 重组的帧数量
+ protocol_counts = {}
+ frames = [] # 存储所有解析出的PPP帧
+ ip_validation_results = [] # 存储IP帧验证结果
+
+ # 处理每个字节
+ for i, byte in enumerate(data):
+ frame = parser.process_byte(byte, position=i)
+ if frame:
+ # frame现在包含完整PPP帧(包含头尾0x7E)
+ # 尝试重组分片帧(暂时跳过重组,直接处理单个帧)
+ raw_frame = frame # 完整帧数据(包含头尾0x7E)
+ frames.append(raw_frame)
+ ppp_frame_count += 1
+
+ # 打印PPP帧信息(显示完整帧长度)
+ print(f"PPP帧 #{ppp_frame_count}: 长度={len(raw_frame)}字节, 起始位置={i-len(raw_frame)+1}")
+ print(f" 内容: {raw_frame.hex().upper()}")
+
+ # 验证帧头尾标志
+ if len(raw_frame) >= 6 and raw_frame[0] == 0x7E and raw_frame[-1] == 0x7E:
+ # 提取帧内容(去掉头尾0x7E)
+ frame_content = raw_frame[1:-1]
+
+ # 处理转义字符
+ processed_frame = parser._unescape_ppp_frame(frame_content)
+ if processed_frame and len(processed_frame) >= 4:
+ # 解析PPP头部
+ address = processed_frame[0]
+ control = processed_frame[1]
+ # 协议字段是大端模式的两字节
+ protocol = (processed_frame[2] << 8) | processed_frame[3]
+
+ # 更新协议计数
+ if protocol not in protocol_counts:
+ protocol_counts[protocol] = 0
+ protocol_counts[protocol] += 1
+
+ payload = processed_frame[4:]
+
+ print(f" 协议: 0x{protocol:04X}, 地址: 0x{address:02X}, 控制: 0x{control:02X}, 负载长度: {len(payload)}字节")
+
+ # 检查是否为IP协议或其他常见PPP协议
+ if protocol == 0x0021: # IP协议
+ # 验证IP数据包完整性
+ is_valid, validation_msg = verify_ip_packet(payload)
+ ip_validation_results.append({
+ 'frame_number': ppp_frame_count,
+ 'is_valid': is_valid,
+ 'message': validation_msg
+ })
+
+ print(f" IP验证: {'通过' if is_valid else '失败'} - {validation_msg}")
+
+ if is_valid:
+ # 解析IP数据包
+ ip_info = parse_ip_packet(payload)
+ if ip_info:
+ # 输出TCP/UDP包信息
+ if ip_info['protocol'] == 6: # TCP
+ tcp_count += 1
+ print(f" TCP #{tcp_count}: {ip_info['src_ip']}:{ip_info['src_port']} -> {ip_info['dst_ip']}:{ip_info['dst_port']}")
+ elif ip_info['protocol'] == 17: # UDP
+ udp_count += 1
+ print(f" UDP #{udp_count}: {ip_info['src_ip']}:{ip_info['src_port']} -> {ip_info['dst_ip']}:{ip_info['dst_port']}")
+ else:
+ other_count += 1
+ else:
+ other_count += 1
+ else:
+ other_count += 1
+ elif protocol == 0xC021: # LCP协议
+ # LCP协议不需要进一步分析
+ print(f" LCP协议帧")
+ elif protocol == 0x8021: # IPCP协议
+ print(f" IPCP协议帧")
+ else:
+ print(f" 其他PPP协议: 0x{protocol:04X}")
+ else:
+ print(f" 警告: 帧长度不足4字节,无法解析PPP头部")
+
+ # 打印PPP帧组包结果
+ if frames:
+ print(f"\nPPP帧组包结果:")
+ grouped_frames = group_ppp_frames(frames)
+ for proto, proto_frames in grouped_frames.items():
+ if proto == 'invalid':
+ print(f" 无效帧: {len(proto_frames)}个")
+ else:
+ protocol_name = "未知"
+ if proto == 0x0021:
+ protocol_name = "IP (IPv4)"
+ elif proto == 0xC021:
+ protocol_name = "LCP (链路控制协议)"
+ elif proto == 0x8021:
+ protocol_name = "IPCP (IP控制协议)"
+ print(f" 0x{proto:04X} ({protocol_name}): {len(proto_frames)}个帧")
+
+ # 验证组包结果是否正确
+ total_grouped = sum(len(frames) for frames in grouped_frames.values())
+ if total_grouped == len(frames):
+ print(f" 组包验证: 成功,所有{total_grouped}个帧都已正确分组")
+ else:
+ print(f" 组包验证: 警告,分组总数({total_grouped})与原始帧总数({len(frames)})不匹配")
+
+ # 打印分片重组统计
+ fragmented_count = parser.get_fragmented_frame_count()
+ print(f"\nPPP帧分片重组统计:")
+ print(f" 解析的原始帧数量: {ppp_frame_count}")
+ print(f" 成功重组的帧数量: {reassembled_count}")
+ print(f" 当前缓存的分片数量: {fragmented_count}")
+
+ # 打印IP帧验证统计
+ if ip_validation_results:
+ valid_ip_count = sum(1 for result in ip_validation_results if result['is_valid'])
+ print(f"\nIP帧验证统计:")
+ print(f" 总共验证IP帧: {len(ip_validation_results)}")
+ print(f" 验证通过: {valid_ip_count}")
+ print(f" 验证失败: {len(ip_validation_results) - valid_ip_count}")
+
+ # 打印前几个验证失败的详细信息
+ failed_results = [r for r in ip_validation_results if not r['is_valid']][:3]
+ for result in failed_results:
+ print(f" 帧 #{result['frame_number']} 验证失败: {result['message']}")
+
+ # 打印丢弃的数据信息
+ print(f"\n丢弃的数据信息:")
+ parser.print_dropped_data()
+
+ # 打印协议统计信息
+ print(f"\n文件分析完成: {file_path}")
+ print(f"总共发现 PPP 帧: {ppp_frame_count}")
+ print(f"发现 TCP 包: {tcp_count}")
+ print(f"发现 UDP 包: {udp_count}")
+ print(f"其他/未知包: {other_count}")
+
+ # 打印协议分布
+ print("\nPPP协议分布:")
+ for proto, count in sorted(protocol_counts.items()):
+ protocol_name = "未知"
+ if proto == 0x0021:
+ protocol_name = "IP (IPv4)"
+ elif proto == 0xC021:
+ protocol_name = "LCP (链路控制协议)"
+ elif proto == 0x8021:
+ protocol_name = "IPCP (IP控制协议)"
+ print(f" 0x{proto:04X} ({protocol_name}): {count}个帧")
+
+
+def main():
+ """主函数"""
+ import sys
+
+ # 检查是否有命令行参数指定要分析的文件
+ if len(sys.argv) > 1:
+ # 使用命令行参数中的文件列表
+ files_to_analyze = sys.argv[1:]
+ else:
+ # 默认分析out.txt和in.txt
+ files_to_analyze = ['out.txt', 'in.txt']
+
+ # 遍历并分析每个文件
+ for file_name in files_to_analyze:
+ # 构建完整的文件路径
+ if os.path.isabs(file_name):
+ file_path = file_name
+ else:
+ file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), file_name)
+
+ if os.path.exists(file_path):
+ print(f"\n=== 开始分析文件: {file_path} ===")
+ analyze_ppp_file(file_path)
+ else:
+ print(f"文件不存在: {file_path}")
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include "ppp_parser.h"
+#include "ppp_packet_analyzer.h"
+
+/* 配置常量 */
+#define MAX_FILE_SIZE (1024 * 1024) /* 最大文件大小1MB */
+#define MAX_FRAMES 1000 /* 最大帧数量 */
+#define MAX_RESULTS 1000 /* 最大分析结果数量 */
+#define HEX_BUFFER_SIZE 16384 /* 十六进制读取缓冲区大小 */
+#define MAX_LINE_LENGTH 256 /* 最大行长度 */
+
+/* 全局变量 */
+static uint8_t g_hex_data[MAX_FILE_SIZE]; /* 十六进制数据缓冲区 */
+static ppp_frame_t g_frames[MAX_FRAMES]; /* PPP帧数组 */
+static packet_analysis_result_t g_results[MAX_RESULTS]; /* 分析结果数组 */
+
+/**
+ * 从十六进制字符串转换为字节值
+ * @param hex_char 十六进制字符
+ * @return 字节值,失败返回-1
+ */
+static int hex_char_to_byte(char hex_char)
+{
+ if (hex_char >= '0' && hex_char <= '9') {
+ return hex_char - '0';
+ } else if (hex_char >= 'A' && hex_char <= 'F') {
+ return hex_char - 'A' + 10;
+ } else if (hex_char >= 'a' && hex_char <= 'f') {
+ return hex_char - 'a' + 10;
+ }
+ return -1;
+}
+
+/**
+ * 从文件中读取十六进制数据
+ * @param file_path 文件路径
+ * @param data 输出数据缓冲区
+ * @param max_size 最大数据大小
+ * @return 实际读取的字节数,失败返回0
+ */
+static uint32_t read_hex_file(const char *file_path, uint8_t *data, uint32_t max_size)
+{
+ if (!file_path || !data || max_size == 0) {
+ printf("错误: 无效的参数\n");
+ return 0;
+ }
+
+ FILE *file = fopen(file_path, "r");
+ if (!file) {
+ printf("错误: 无法打开文件 %s: %s\n", file_path, strerror(errno));
+ return 0;
+ }
+
+ char line[MAX_LINE_LENGTH];
+ uint32_t data_len = 0;
+ uint32_t line_number = 0;
+
+ printf("开始读取文件: %s\n", file_path);
+
+ while (fgets(line, sizeof(line), file) && data_len < max_size) {
+ line_number++;
+
+ /* 移除行尾的换行符和空白字符 */
+ char *end = line + strlen(line) - 1;
+ while (end >= line && isspace(*end)) {
+ *end-- = '\0';
+ }
+
+ /* 跳过空行 */
+ if (strlen(line) == 0) {
+ continue;
+ }
+
+ /* 处理每行的十六进制字符串 */
+ char *ptr = line;
+ while (*ptr && data_len < max_size) {
+ /* 跳过空白字符 */
+ while (*ptr && isspace(*ptr)) {
+ ptr++;
+ }
+
+ if (!*ptr) break;
+
+ /* 读取两个十六进制字符组成一个字节 */
+ if (strlen(ptr) >= 2) {
+ int high = hex_char_to_byte(ptr[0]);
+ int low = hex_char_to_byte(ptr[1]);
+
+ if (high >= 0 && low >= 0) {
+ data[data_len++] = (high << 4) | low;
+ ptr += 2;
+ } else {
+ printf("警告: 文件%s第%u行包含无效的十六进制字符: %c%c\n",
+ file_path, line_number, ptr[0], ptr[1]);
+ ptr += 2;
+ }
+ } else if (strlen(ptr) == 1) {
+ /* 单个十六进制字符,当作一个字节处理 */
+ int value = hex_char_to_byte(ptr[0]);
+ if (value >= 0) {
+ data[data_len++] = value;
+ ptr++;
+ } else {
+ printf("警告: 文件%s第%u行包含无效的十六进制字符: %c\n",
+ file_path, line_number, ptr[0]);
+ ptr++;
+ }
+ }
+ }
+ }
+
+ fclose(file);
+
+ if (data_len >= max_size) {
+ printf("警告: 文件%s数据量超过缓冲区大小,只读取了前%u字节\n", file_path, max_size);
+ }
+
+ printf("成功读取文件%s: %u字节\n", file_path, data_len);
+ return data_len;
+}
+
+/**
+ * 分析PPP文件并输出详细信息
+ * @param file_path 文件路径
+ */
+static void analyze_ppp_file(const char *file_path)
+{
+ printf("\n=== 开始分析文件: %s ===\n", file_path);
+
+ /* 读取文件数据 */
+ uint32_t data_len = read_hex_file(file_path, g_hex_data, MAX_FILE_SIZE);
+ if (data_len == 0) {
+ printf("文件读取失败,跳过分析\n");
+ return;
+ }
+
+ /* 初始化PPP解析器 */
+ ppp_parser_t parser;
+ ppp_parser_init(&parser);
+
+ /* 解析PPP帧 */
+ printf("\n--- PPP帧解析阶段 ---\n");
+ uint32_t frame_count = ppp_parser_process_data(&parser, g_hex_data, data_len,
+ g_frames, MAX_FRAMES);
+
+ printf("解析完成,共发现 %u 个PPP帧\n", frame_count);
+
+ /* 打印解析器统计信息 */
+ ppp_parser_print_stats(&parser);
+ ppp_parser_print_dropped_data(&parser);
+
+ if (frame_count == 0) {
+ printf("未发现有效的PPP帧\n");
+ return;
+ }
+
+ /* 打印前几个PPP帧的详细信息 */
+ printf("\n--- PPP帧详细信息 ---\n");
+ uint32_t print_count = (frame_count > 5) ? 5 : frame_count;
+ for (uint32_t i = 0; i < print_count; i++) {
+ ppp_print_frame_info(&g_frames[i], i + 1);
+ }
+
+ if (frame_count > 5) {
+ printf("... 还有%u个帧未显示详细信息\n", frame_count - 5);
+ }
+
+ /* 包内容分析 */
+ printf("\n--- 包内容分析阶段 ---\n");
+ packet_stats_t packet_stats;
+ uint32_t analyzed_count = analyze_ppp_frames(g_frames, frame_count,
+ g_results, &packet_stats);
+
+ /* PPP帧组包分析(在analyzer处理后进行,这样协议信息已经解析) */
+ printf("\n--- PPP帧组包分析 ---\n");
+ ppp_group_result_t group_result;
+ ppp_classify_frames(g_frames, frame_count, &group_result);
+ ppp_print_group_result(&group_result);
+
+ printf("包分析完成,成功分析 %u 个包\n", analyzed_count);
+
+ /* 打印包统计信息 */
+ print_packet_stats(&packet_stats);
+
+ /* 打印前几个包的详细分析结果 */
+ printf("\n--- 包详细分析结果 ---\n");
+ uint32_t detail_count = (analyzed_count > 3) ? 3 : analyzed_count;
+ for (uint32_t i = 0; i < detail_count; i++) {
+ if (g_results[i].has_ip) {
+ print_packet_analysis_result(&g_results[i], i + 1);
+ }
+ }
+
+ if (analyzed_count > 3) {
+ printf("... 还有%u个包未显示详细分析结果\n", analyzed_count - 3);
+ }
+
+ /* 简化的TCP/UDP包统计输出 */
+ printf("\n--- TCP/UDP包简要统计 ---\n");
+ uint32_t tcp_count = 0, udp_count = 0;
+ for (uint32_t i = 0; i < analyzed_count; i++) {
+ if (g_results[i].has_tcp) {
+ tcp_count++;
+ if (tcp_count <= 10) { /* 只显示前10个 */
+ char src_ip[16], dst_ip[16];
+ format_ip_address(&g_results[i].ip_info.src_ip, src_ip, sizeof(src_ip));
+ format_ip_address(&g_results[i].ip_info.dst_ip, dst_ip, sizeof(dst_ip));
+ printf(" TCP #%u: %s:%u -> %s:%u\n", tcp_count,
+ src_ip, g_results[i].tcp_info.src_port,
+ dst_ip, g_results[i].tcp_info.dst_port);
+ }
+ } else if (g_results[i].has_udp) {
+ udp_count++;
+ if (udp_count <= 10) { /* 只显示前10个 */
+ char src_ip[16], dst_ip[16];
+ format_ip_address(&g_results[i].ip_info.src_ip, src_ip, sizeof(src_ip));
+ format_ip_address(&g_results[i].ip_info.dst_ip, dst_ip, sizeof(dst_ip));
+ printf(" UDP #%u: %s:%u -> %s:%u\n", udp_count,
+ src_ip, g_results[i].udp_info.src_port,
+ dst_ip, g_results[i].udp_info.dst_port);
+ }
+ }
+ }
+
+ if (tcp_count > 10) {
+ printf(" ... 还有%u个TCP包未显示\n", tcp_count - 10);
+ }
+ if (udp_count > 10) {
+ printf(" ... 还有%u个UDP包未显示\n", udp_count - 10);
+ }
+
+ printf("\n=== 文件分析完成: %s ===\n", file_path);
+ printf("总结: 发现PPP帧%u个, TCP包%u个, UDP包%u个, 其他包%u个\n",
+ frame_count, packet_stats.tcp_packets, packet_stats.udp_packets,
+ packet_stats.other_packets);
+}
+
+/**
+ * 打印使用说明
+ */
+static void print_usage(const char *program_name)
+{
+ printf("PPP协议解析工具 (C语言版本)\n");
+ printf("用于解析十六进制文件中的PPP协议数据,识别TCP/UDP包并提取基本信息\n\n");
+ printf("使用方法:\n");
+ printf(" %s [文件1] [文件2] ...\n\n", program_name);
+ printf("参数说明:\n");
+ printf(" 文件1, 文件2, ... : 要分析的十六进制数据文件\n");
+ printf(" 如果不指定文件,默认分析 out.txt 和 in.txt\n\n");
+ printf("文件格式:\n");
+ printf(" 每行包含十六进制数据,可以是单个字节或多个字节\n");
+ printf(" 例如: 7E FF 03 00 21 45 00 00 1C 7E\n");
+ printf(" 或者: 7E\n");
+ printf(" FF\n");
+ printf(" 03\n\n");
+ printf("示例:\n");
+ printf(" %s out.txt in.txt\n", program_name);
+ printf(" %s data1.hex data2.hex data3.hex\n", program_name);
+}
+
+/**
+ * 主函数
+ */
+int main(int argc, char *argv[])
+{
+ printf("PPP协议解析工具 (C语言版本) - 启动\n");
+ printf("版本: 1.0\n");
+ printf("功能: PPP帧解析、IP包分析、TCP/UDP包识别\n\n");
+
+ /* 检查命令行参数 */
+ if (argc > 1 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
+ print_usage(argv[0]);
+ return 0;
+ }
+
+ /* 确定要分析的文件列表 */
+ const char **files_to_analyze;
+ int file_count;
+ const char *default_files[] = {"out.txt", "in.txt"};
+
+ if (argc > 1) {
+ /* 使用命令行参数中的文件列表 */
+ files_to_analyze = (const char **)&argv[1];
+ file_count = argc - 1;
+ } else {
+ /* 使用默认文件列表 */
+ files_to_analyze = default_files;
+ file_count = 2;
+ printf("未指定文件,使用默认文件: out.txt, in.txt\n");
+ }
+
+ /* 遍历并分析每个文件 */
+ int success_count = 0;
+ for (int i = 0; i < file_count; i++) {
+ const char *file_path = files_to_analyze[i];
+
+ /* 检查文件是否存在 */
+ FILE *test_file = fopen(file_path, "r");
+ if (test_file) {
+ fclose(test_file);
+ analyze_ppp_file(file_path);
+ success_count++;
+ } else {
+ printf("\n错误: 文件不存在或无法访问: %s\n", file_path);
+ }
+ }
+
+ /* 打印总结信息 */
+ printf("\n============================================================\n");
+ printf("分析总结:\n");
+ printf(" 指定文件数量: %d\n", file_count);
+ printf(" 成功分析文件: %d\n", success_count);
+ printf(" 失败文件数量: %d\n", file_count - success_count);
+
+ if (success_count == 0) {
+ printf("\n警告: 没有成功分析任何文件\n");
+ printf("请检查:\n");
+ printf("1. 文件是否存在\n");
+ printf("2. 文件格式是否正确(十六进制数据)\n");
+ printf("3. 文件权限是否允许读取\n");
+ return 1;
+ }
+
+ printf("\nPPP协议解析工具运行完成\n");
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+#include "ppp_packet_analyzer.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* 内部辅助函数声明 */
+static bool ppp_unescape_frame(const uint8_t *raw_data, uint16_t raw_len,
+ uint8_t *processed_data, uint16_t *processed_len);
+
+/**
+ * PPP转义字符处理:还原字节填充
+ * @param raw_data 原始帧数据(包含转义字符)
+ * @param raw_len 原始数据长度
+ * @param processed_data 输出的处理后数据
+ * @param processed_len 输出的处理后数据长度
+ * @return 处理是否成功
+ */
+static bool ppp_unescape_frame(const uint8_t *raw_data, uint16_t raw_len,
+ uint8_t *processed_data, uint16_t *processed_len)
+{
+ if (!raw_data || !processed_data || !processed_len || raw_len == 0) {
+ return false;
+ }
+
+ uint16_t out_len = 0;
+
+ /* 还原字节填充(0x7D后字节异或0x20) */
+ for (uint16_t i = 0; i < raw_len; i++) {
+ if (raw_data[i] == 0x7D) { /* PPP转义字符 */
+ /* 转义字符 */
+ if (i + 1 < raw_len) {
+ processed_data[out_len++] = raw_data[i + 1] ^ 0x20;
+ i++; /* 跳过下一个字节 */
+ } else {
+ /* 不完整的转义序列 */
+ return false;
+ }
+ } else {
+ processed_data[out_len++] = raw_data[i];
+ }
+
+ /* 防止输出缓冲区溢出 */
+ if (out_len >= PPP_MAX_FRAME_SIZE) {
+ return false;
+ }
+ }
+
+ *processed_len = out_len;
+ return true;
+}
+
+/**
+ * 计算IP头部校验和
+ */
+uint16_t calculate_ip_checksum(const uint8_t *ip_header, uint8_t header_len)
+{
+ if (!ip_header || header_len < IP_MIN_HEADER_SIZE || header_len % 2 != 0) {
+ return 0;
+ }
+
+ uint32_t sum = 0;
+
+ /* 将IP头部视为16位字的序列进行累加 */
+ for (uint8_t i = 0; i < header_len; i += 2) {
+ uint16_t word = (ip_header[i] << 8) | ip_header[i + 1];
+ sum += word;
+ }
+
+ /* 处理进位 */
+ while (sum >> 16) {
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ }
+
+ /* 取反得到校验和 */
+ return ~sum & 0xFFFF;
+}
+
+/**
+ * 验证IP数据包的完整性和正确性
+ */
+bool verify_ip_packet(const uint8_t *ip_data, uint16_t data_len, ip_validation_result_t *result)
+{
+ if (!ip_data || !result) {
+ *result = IP_ERROR_TOO_SHORT;
+ return false;
+ }
+
+ /* 检查最小长度 */
+ if (data_len < IP_MIN_HEADER_SIZE) {
+ *result = IP_ERROR_TOO_SHORT;
+ return false;
+ }
+
+ /* 验证版本号(应为4) */
+ uint8_t version = (ip_data[0] >> 4) & 0x0F;
+ if (version != IP_VERSION_4) {
+ *result = IP_ERROR_INVALID_VERSION;
+ return false;
+ }
+
+ /* 验证头部长度 */
+ uint8_t ihl = (ip_data[0] & 0x0F) * 4;
+ if (ihl < IP_MIN_HEADER_SIZE || ihl > IP_MAX_HEADER_SIZE || ihl > data_len) {
+ *result = IP_ERROR_INVALID_HEADER_LEN;
+ return false;
+ }
+
+ /* 检查总长度是否合理 */
+ uint16_t total_length = (ip_data[2] << 8) | ip_data[3];
+ /* 允许实际长度比声明长度多几个字节(可能是PPP填充),或者实际长度大于等于声明长度 */
+ if (total_length > data_len || (data_len - total_length) > 4) {
+ *result = IP_ERROR_LENGTH_MISMATCH;
+ return false;
+ }
+
+ /* 验证校验和 */
+ uint16_t original_checksum = (ip_data[10] << 8) | ip_data[11];
+
+ /* 创建头部副本并清零校验和字段 */
+ uint8_t header_copy[IP_MAX_HEADER_SIZE];
+ memcpy(header_copy, ip_data, ihl);
+ header_copy[10] = 0;
+ header_copy[11] = 0;
+
+ uint16_t calculated_checksum = calculate_ip_checksum(header_copy, ihl);
+
+ if (original_checksum != calculated_checksum) {
+ *result = IP_ERROR_CHECKSUM_FAILED;
+ return false;
+ }
+
+ *result = IP_VALID;
+ return true;
+}
+
+/**
+ * 解析IP数据包,提取基本信息
+ */
+bool parse_ip_packet(const uint8_t *ip_data, uint16_t data_len, ip_packet_info_t *ip_info)
+{
+ if (!ip_data || !ip_info || data_len < IP_MIN_HEADER_SIZE) {
+ return false;
+ }
+
+ memset(ip_info, 0, sizeof(ip_packet_info_t));
+
+ /* 解析IP头部字段 */
+ ip_info->version = (ip_data[0] >> 4) & 0x0F;
+ ip_info->header_len = (ip_data[0] & 0x0F) * 4;
+ ip_info->tos = ip_data[1];
+ ip_info->total_len = (ip_data[2] << 8) | ip_data[3];
+ ip_info->id = (ip_data[4] << 8) | ip_data[5];
+ ip_info->flags_frag = (ip_data[6] << 8) | ip_data[7];
+ ip_info->ttl = ip_data[8];
+ ip_info->protocol = ip_data[9];
+ ip_info->checksum = (ip_data[10] << 8) | ip_data[11];
+
+ /* 解析IP地址 */
+ memcpy(ip_info->src_ip.addr, &ip_data[12], 4);
+ memcpy(ip_info->dst_ip.addr, &ip_data[16], 4);
+
+ /* 计算负载信息 */
+ if (ip_info->header_len <= data_len) {
+ ip_info->payload = ip_data + ip_info->header_len;
+ ip_info->payload_len = data_len - ip_info->header_len;
+ }
+
+ /* 验证IP包 */
+ bool is_valid = verify_ip_packet(ip_data, data_len, &ip_info->validation);
+ ip_info->validation_msg = get_ip_validation_message(ip_info->validation);
+
+ return true; /* 总是返回true,即使验证失败也要解析IP包信息 */
+}
+
+/**
+ * 解析TCP数据包,提取端口和基本信息
+ */
+bool parse_tcp_packet(const uint8_t *tcp_data, uint16_t data_len, tcp_packet_info_t *tcp_info)
+{
+ if (!tcp_data || !tcp_info || data_len < TCP_MIN_HEADER_SIZE) {
+ return false;
+ }
+
+ memset(tcp_info, 0, sizeof(tcp_packet_info_t));
+
+ /* 解析TCP头部字段 */
+ tcp_info->src_port = (tcp_data[0] << 8) | tcp_data[1];
+ tcp_info->dst_port = (tcp_data[2] << 8) | tcp_data[3];
+ tcp_info->seq_num = (tcp_data[4] << 24) | (tcp_data[5] << 16) |
+ (tcp_data[6] << 8) | tcp_data[7];
+ tcp_info->ack_num = (tcp_data[8] << 24) | (tcp_data[9] << 16) |
+ (tcp_data[10] << 8) | tcp_data[11];
+
+ uint8_t data_offset = (tcp_data[12] >> 4) & 0x0F;
+ tcp_info->header_len = data_offset * 4;
+ tcp_info->flags = tcp_data[13];
+ tcp_info->window = (tcp_data[14] << 8) | tcp_data[15];
+ tcp_info->checksum = (tcp_data[16] << 8) | tcp_data[17];
+ tcp_info->urgent_ptr = (tcp_data[18] << 8) | tcp_data[19];
+
+ /* 计算负载信息 */
+ if (tcp_info->header_len <= data_len) {
+ tcp_info->payload = tcp_data + tcp_info->header_len;
+ tcp_info->payload_len = data_len - tcp_info->header_len;
+ }
+
+ return true;
+}
+
+/**
+ * 解析UDP数据包,提取端口和基本信息
+ */
+bool parse_udp_packet(const uint8_t *udp_data, uint16_t data_len, udp_packet_info_t *udp_info)
+{
+ if (!udp_data || !udp_info || data_len < UDP_HEADER_SIZE) {
+ return false;
+ }
+
+ memset(udp_info, 0, sizeof(udp_packet_info_t));
+
+ /* 解析UDP头部字段 */
+ udp_info->src_port = (udp_data[0] << 8) | udp_data[1];
+ udp_info->dst_port = (udp_data[2] << 8) | udp_data[3];
+ udp_info->length = (udp_data[4] << 8) | udp_data[5];
+ udp_info->checksum = (udp_data[6] << 8) | udp_data[7];
+
+ /* 计算负载信息 */
+ udp_info->payload = udp_data + UDP_HEADER_SIZE;
+ udp_info->payload_len = data_len - UDP_HEADER_SIZE;
+
+ return true;
+}
+
+/**
+ * 分析PPP帧内容,解析其中的IP/TCP/UDP包
+ */
+bool analyze_ppp_frame(const ppp_frame_t *frame, packet_analysis_result_t *result)
+{
+ if (!frame || !result) {
+ return false;
+ }
+
+ memset(result, 0, sizeof(packet_analysis_result_t));
+ result->ppp_frame = frame;
+
+ /* 检查原始帧长度 */
+ if (frame->raw_frame_len < 6) { /* 最小:0x7E + 地址1 + 控制1 + 协议2 + 0x7E = 6字节 */
+ result->protocol_name = "PPP Frame Too Short";
+ return false;
+ }
+
+ /* 验证帧头尾标志 */
+ if (frame->raw_frame[0] != PPP_FLAG_BYTE ||
+ frame->raw_frame[frame->raw_frame_len - 1] != PPP_FLAG_BYTE) {
+ result->protocol_name = "Invalid PPP Frame Flags";
+ return false;
+ }
+
+ /* 提取帧内容(去掉头尾0x7E) */
+ const uint8_t *frame_content = &frame->raw_frame[1];
+ uint16_t frame_content_len = frame->raw_frame_len - 2;
+
+ /* 处理PPP转义字符 */
+ uint8_t processed_data[PPP_MAX_FRAME_SIZE];
+ uint16_t processed_len;
+
+ if (!ppp_unescape_frame(frame_content, frame_content_len, processed_data, &processed_len)) {
+ result->protocol_name = "Invalid PPP Frame";
+ return false;
+ }
+
+ /* 检查处理后的帧长度 */
+ if (processed_len < 4) { /* 最小:地址1 + 控制1 + 协议2 = 4字节 */
+ result->protocol_name = "PPP Frame Too Short";
+ return false;
+ }
+
+ /* 解析PPP帧头部 */
+ uint8_t address = processed_data[0];
+ uint8_t control = processed_data[1];
+ uint16_t protocol = (processed_data[2] << 8) | processed_data[3];
+
+ /* 更新frame结构中的协议信息(用于组包统计) */
+ ((ppp_frame_t*)frame)->address = address;
+ ((ppp_frame_t*)frame)->control = control;
+ ((ppp_frame_t*)frame)->protocol = protocol;
+
+ /* 复制处理后的负载数据 */
+ ((ppp_frame_t*)frame)->payload_len = processed_len;
+ memcpy(((ppp_frame_t*)frame)->payload, processed_data, processed_len);
+
+ /* 获取IP负载数据 */
+ const uint8_t *ip_payload = &processed_data[4];
+ uint16_t ip_payload_len = processed_len - 4;
+
+ /* 检查是否为IP协议 */
+ if (protocol == PPP_PROTOCOL_IP && ip_payload_len > 0) {
+ /* 解析IP包 */
+ result->has_ip = parse_ip_packet(ip_payload, ip_payload_len, &result->ip_info);
+
+ if (result->has_ip) {
+ if (result->ip_info.validation == IP_VALID) {
+ /* 根据IP协议类型解析传输层 */
+ if (result->ip_info.protocol == IP_PROTOCOL_TCP && result->ip_info.payload_len > 0) {
+ result->has_tcp = parse_tcp_packet(result->ip_info.payload,
+ result->ip_info.payload_len, &result->tcp_info);
+ result->protocol_name = "TCP";
+ } else if (result->ip_info.protocol == IP_PROTOCOL_UDP && result->ip_info.payload_len > 0) {
+ result->has_udp = parse_udp_packet(result->ip_info.payload,
+ result->ip_info.payload_len, &result->udp_info);
+ result->protocol_name = "UDP";
+ } else if (result->ip_info.protocol == IP_PROTOCOL_ICMP) {
+ result->protocol_name = "ICMP";
+ } else {
+ result->protocol_name = "Other IP";
+ }
+ } else {
+ result->protocol_name = "Invalid IP";
+ }
+ }
+ } else {
+ /* 非IP协议 */
+ result->protocol_name = ppp_get_protocol_name(protocol);
+ }
+
+ return true;
+}
+
+/**
+ * 批量分析PPP帧
+ */
+uint32_t analyze_ppp_frames(const ppp_frame_t *frames, uint32_t frame_count,
+ packet_analysis_result_t *results, packet_stats_t *stats)
+{
+ if (!frames || !results || !stats || frame_count == 0) {
+ return 0;
+ }
+
+ init_packet_stats(stats);
+ uint32_t success_count = 0;
+
+ for (uint32_t i = 0; i < frame_count; i++) {
+ if (analyze_ppp_frame(&frames[i], &results[i])) {
+ success_count++;
+ stats->total_packets++;
+
+ /* 更新统计信息 */
+ if (results[i].has_ip) {
+ stats->ip_packets++;
+
+ /* 更新IP验证统计 */
+ ip_validation_result_t validation = results[i].ip_info.validation;
+ if (validation < 6) {
+ stats->ip_validation_counts[validation]++;
+ }
+
+ if (validation != IP_VALID) {
+ stats->invalid_ip_packets++;
+ }
+
+ /* 更新传输层统计 */
+ if (results[i].has_tcp) {
+ stats->tcp_packets++;
+ } else if (results[i].has_udp) {
+ stats->udp_packets++;
+ } else {
+ stats->other_packets++;
+ }
+ } else {
+ stats->other_packets++;
+ }
+ }
+ }
+
+ return success_count;
+}
+
+/**
+ * 获取IP验证结果的描述字符串
+ */
+const char* get_ip_validation_message(ip_validation_result_t result)
+{
+ switch (result) {
+ case IP_VALID:
+ return "IP数据包验证通过";
+ case IP_ERROR_TOO_SHORT:
+ return "IP数据包长度不足20字节";
+ case IP_ERROR_INVALID_VERSION:
+ return "非IPv4数据包";
+ case IP_ERROR_INVALID_HEADER_LEN:
+ return "无效的IP头部长度";
+ case IP_ERROR_LENGTH_MISMATCH:
+ return "IP数据包长度不匹配";
+ case IP_ERROR_CHECKSUM_FAILED:
+ return "IP校验和错误";
+ default:
+ return "未知错误";
+ }
+}
+
+/**
+ * 格式化IP地址为字符串
+ */
+void format_ip_address(const ip_addr_t *ip_addr, char *buffer, size_t buffer_size)
+{
+ if (!ip_addr || !buffer || buffer_size < 16) {
+ return;
+ }
+
+ snprintf(buffer, buffer_size, "%u.%u.%u.%u",
+ ip_addr->addr[0], ip_addr->addr[1],
+ ip_addr->addr[2], ip_addr->addr[3]);
+}
+
+/**
+ * 打印IP包信息
+ */
+void print_ip_packet_info(const ip_packet_info_t *ip_info)
+{
+ if (!ip_info) return;
+
+ char src_ip_str[16], dst_ip_str[16];
+ format_ip_address(&ip_info->src_ip, src_ip_str, sizeof(src_ip_str));
+ format_ip_address(&ip_info->dst_ip, dst_ip_str, sizeof(dst_ip_str));
+
+ printf(" IP验证: %s - %s\n",
+ (ip_info->validation == IP_VALID) ? "通过" : "失败",
+ ip_info->validation_msg);
+
+ if (ip_info->validation == IP_VALID) {
+ printf(" IP信息: %s -> %s, 协议=%u, 长度=%u, TTL=%u\n",
+ src_ip_str, dst_ip_str, ip_info->protocol,
+ ip_info->total_len, ip_info->ttl);
+ }
+}
+
+/**
+ * 打印TCP包信息
+ */
+void print_tcp_packet_info(const tcp_packet_info_t *tcp_info)
+{
+ if (!tcp_info) return;
+
+ printf(" TCP: 端口 %u -> %u, 序列号=%u, 确认号=%u, 标志=0x%02X\n",
+ tcp_info->src_port, tcp_info->dst_port,
+ tcp_info->seq_num, tcp_info->ack_num, tcp_info->flags);
+}
+
+/**
+ * 打印UDP包信息
+ */
+void print_udp_packet_info(const udp_packet_info_t *udp_info)
+{
+ if (!udp_info) return;
+
+ printf(" UDP: 端口 %u -> %u, 长度=%u\n",
+ udp_info->src_port, udp_info->dst_port, udp_info->length);
+}
+
+/**
+ * 打印包分析结果
+ */
+void print_packet_analysis_result(const packet_analysis_result_t *result, uint32_t packet_number)
+{
+ if (!result || !result->ppp_frame) return;
+
+ printf("\n=== 包 #%u 分析结果 ===\n", packet_number);
+
+ /* 打印PPP帧基本信息 */
+ printf("PPP帧: 协议=0x%04X (%s), 负载长度=%u字节\n",
+ result->ppp_frame->protocol, result->protocol_name,
+ result->ppp_frame->payload_len);
+
+ /* 打印IP包信息 */
+ if (result->has_ip) {
+ print_ip_packet_info(&result->ip_info);
+
+ /* 打印传输层信息 */
+ if (result->has_tcp) {
+ print_tcp_packet_info(&result->tcp_info);
+ } else if (result->has_udp) {
+ print_udp_packet_info(&result->udp_info);
+ }
+ }
+}
+
+/**
+ * 打印包统计信息
+ */
+void print_packet_stats(const packet_stats_t *stats)
+{
+ if (!stats) return;
+
+ printf("\n=== 包分析统计信息 ===\n");
+ printf("总包数: %u\n", stats->total_packets);
+ printf("IP包数: %u\n", stats->ip_packets);
+ printf("TCP包数: %u\n", stats->tcp_packets);
+ printf("UDP包数: %u\n", stats->udp_packets);
+ printf("其他包数: %u\n", stats->other_packets);
+ printf("无效IP包数: %u\n", stats->invalid_ip_packets);
+
+ printf("\nIP验证结果统计:\n");
+ printf(" 验证通过: %u\n", stats->ip_validation_counts[IP_VALID]);
+ printf(" 长度不足: %u\n", stats->ip_validation_counts[IP_ERROR_TOO_SHORT]);
+ printf(" 版本错误: %u\n", stats->ip_validation_counts[IP_ERROR_INVALID_VERSION]);
+ printf(" 头部长度错误: %u\n", stats->ip_validation_counts[IP_ERROR_INVALID_HEADER_LEN]);
+ printf(" 长度不匹配: %u\n", stats->ip_validation_counts[IP_ERROR_LENGTH_MISMATCH]);
+ printf(" 校验和错误: %u\n", stats->ip_validation_counts[IP_ERROR_CHECKSUM_FAILED]);
+}
+
+/**
+ * 初始化包统计信息
+ */
+void init_packet_stats(packet_stats_t *stats)
+{
+ if (!stats) return;
+
+ memset(stats, 0, sizeof(packet_stats_t));
+}
\ No newline at end of file
--- /dev/null
+#ifndef PPP_PACKET_ANALYZER_H
+#define PPP_PACKET_ANALYZER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ppp_parser.h"
+
+/* IP协议常量定义 */
+#define IP_VERSION_4 4 /* IPv4版本号 */
+#define IP_MIN_HEADER_SIZE 20 /* IP头部最小长度 */
+#define IP_MAX_HEADER_SIZE 60 /* IP头部最大长度 */
+#define IP_PROTOCOL_TCP 6 /* TCP协议 */
+#define IP_PROTOCOL_UDP 17 /* UDP协议 */
+#define IP_PROTOCOL_ICMP 1 /* ICMP协议 */
+
+/* TCP/UDP常量定义 */
+#define TCP_MIN_HEADER_SIZE 20 /* TCP头部最小长度 */
+#define UDP_HEADER_SIZE 8 /* UDP头部固定长度 */
+
+/* IP验证结果枚举 */
+typedef enum {
+ IP_VALID = 0, /* IP包有效 */
+ IP_ERROR_TOO_SHORT, /* 包长度不足 */
+ IP_ERROR_INVALID_VERSION, /* 版本号错误 */
+ IP_ERROR_INVALID_HEADER_LEN, /* 头部长度错误 */
+ IP_ERROR_LENGTH_MISMATCH, /* 长度不匹配 */
+ IP_ERROR_CHECKSUM_FAILED /* 校验和错误 */
+} ip_validation_result_t;
+
+/* IP地址结构 */
+typedef struct {
+ uint8_t addr[4]; /* IP地址字节数组 */
+} ip_addr_t;
+
+/* IP包信息结构 */
+typedef struct {
+ uint8_t version; /* IP版本 */
+ uint8_t header_len; /* 头部长度(字节) */
+ uint8_t tos; /* 服务类型 */
+ uint16_t total_len; /* 总长度 */
+ uint16_t id; /* 标识符 */
+ uint16_t flags_frag; /* 标志和片偏移 */
+ uint8_t ttl; /* 生存时间 */
+ uint8_t protocol; /* 协议类型 */
+ uint16_t checksum; /* 头部校验和 */
+ ip_addr_t src_ip; /* 源IP地址 */
+ ip_addr_t dst_ip; /* 目标IP地址 */
+
+ /* 负载信息 */
+ const uint8_t *payload; /* 负载数据指针 */
+ uint16_t payload_len; /* 负载长度 */
+
+ /* 验证结果 */
+ ip_validation_result_t validation; /* 验证结果 */
+ const char *validation_msg; /* 验证消息 */
+} ip_packet_info_t;
+
+/* TCP包信息结构 */
+typedef struct {
+ uint16_t src_port; /* 源端口 */
+ uint16_t dst_port; /* 目标端口 */
+ uint32_t seq_num; /* 序列号 */
+ uint32_t ack_num; /* 确认号 */
+ uint8_t header_len; /* 头部长度(字节) */
+ uint8_t flags; /* 控制标志 */
+ uint16_t window; /* 窗口大小 */
+ uint16_t checksum; /* 校验和 */
+ uint16_t urgent_ptr; /* 紧急指针 */
+
+ /* 负载信息 */
+ const uint8_t *payload; /* 负载数据指针 */
+ uint16_t payload_len; /* 负载长度 */
+} tcp_packet_info_t;
+
+/* UDP包信息结构 */
+typedef struct {
+ uint16_t src_port; /* 源端口 */
+ uint16_t dst_port; /* 目标端口 */
+ uint16_t length; /* UDP长度 */
+ uint16_t checksum; /* 校验和 */
+
+ /* 负载信息 */
+ const uint8_t *payload; /* 负载数据指针 */
+ uint16_t payload_len; /* 负载长度 */
+} udp_packet_info_t;
+
+/* 包分析结果结构 */
+typedef struct {
+ /* PPP帧信息 */
+ const ppp_frame_t *ppp_frame; /* PPP帧指针 */
+
+ /* IP包信息 */
+ bool has_ip; /* 是否包含IP包 */
+ ip_packet_info_t ip_info; /* IP包信息 */
+
+ /* 传输层信息 */
+ bool has_tcp; /* 是否包含TCP包 */
+ bool has_udp; /* 是否包含UDP包 */
+ tcp_packet_info_t tcp_info; /* TCP包信息 */
+ udp_packet_info_t udp_info; /* UDP包信息 */
+
+ /* 协议名称 */
+ const char *protocol_name; /* 协议名称字符串 */
+} packet_analysis_result_t;
+
+/* 包统计信息结构 */
+typedef struct {
+ uint32_t total_packets; /* 总包数 */
+ uint32_t ip_packets; /* IP包数 */
+ uint32_t tcp_packets; /* TCP包数 */
+ uint32_t udp_packets; /* UDP包数 */
+ uint32_t other_packets; /* 其他包数 */
+ uint32_t invalid_ip_packets; /* 无效IP包数 */
+
+ /* IP验证统计 */
+ uint32_t ip_validation_counts[6]; /* 各种验证结果的计数 */
+} packet_stats_t;
+
+/* 函数声明 */
+
+/**
+ * 计算IP头部校验和
+ * @param ip_header IP头部数据
+ * @param header_len 头部长度
+ * @return 计算出的校验和
+ */
+uint16_t calculate_ip_checksum(const uint8_t *ip_header, uint8_t header_len);
+
+/**
+ * 验证IP数据包的完整性和正确性
+ * @param ip_data IP数据包
+ * @param data_len 数据长度
+ * @param result 验证结果
+ * @return 验证是否通过
+ */
+bool verify_ip_packet(const uint8_t *ip_data, uint16_t data_len, ip_validation_result_t *result);
+
+/**
+ * 解析IP数据包,提取基本信息
+ * @param ip_data IP数据包
+ * @param data_len 数据长度
+ * @param ip_info 输出的IP包信息
+ * @return 解析是否成功
+ */
+bool parse_ip_packet(const uint8_t *ip_data, uint16_t data_len, ip_packet_info_t *ip_info);
+
+/**
+ * 解析TCP数据包,提取端口和基本信息
+ * @param tcp_data TCP数据包
+ * @param data_len 数据长度
+ * @param tcp_info 输出的TCP包信息
+ * @return 解析是否成功
+ */
+bool parse_tcp_packet(const uint8_t *tcp_data, uint16_t data_len, tcp_packet_info_t *tcp_info);
+
+/**
+ * 解析UDP数据包,提取端口和基本信息
+ * @param udp_data UDP数据包
+ * @param data_len 数据长度
+ * @param udp_info 输出的UDP包信息
+ * @return 解析是否成功
+ */
+bool parse_udp_packet(const uint8_t *udp_data, uint16_t data_len, udp_packet_info_t *udp_info);
+
+/**
+ * 分析PPP帧内容,解析其中的IP/TCP/UDP包
+ * @param frame PPP帧
+ * @param result 分析结果
+ * @return 分析是否成功
+ */
+bool analyze_ppp_frame(const ppp_frame_t *frame, packet_analysis_result_t *result);
+
+/**
+ * 批量分析PPP帧
+ * @param frames PPP帧数组
+ * @param frame_count 帧数量
+ * @param results 分析结果数组
+ * @param stats 统计信息
+ * @return 成功分析的帧数量
+ */
+uint32_t analyze_ppp_frames(const ppp_frame_t *frames, uint32_t frame_count,
+ packet_analysis_result_t *results, packet_stats_t *stats);
+
+/**
+ * 获取IP验证结果的描述字符串
+ * @param result 验证结果
+ * @return 描述字符串
+ */
+const char* get_ip_validation_message(ip_validation_result_t result);
+
+/**
+ * 格式化IP地址为字符串
+ * @param ip_addr IP地址结构
+ * @param buffer 输出缓冲区
+ * @param buffer_size 缓冲区大小
+ */
+void format_ip_address(const ip_addr_t *ip_addr, char *buffer, size_t buffer_size);
+
+/**
+ * 打印IP包信息
+ * @param ip_info IP包信息
+ */
+void print_ip_packet_info(const ip_packet_info_t *ip_info);
+
+/**
+ * 打印TCP包信息
+ * @param tcp_info TCP包信息
+ */
+void print_tcp_packet_info(const tcp_packet_info_t *tcp_info);
+
+/**
+ * 打印UDP包信息
+ * @param udp_info UDP包信息
+ */
+void print_udp_packet_info(const udp_packet_info_t *udp_info);
+
+/**
+ * 打印包分析结果
+ * @param result 分析结果
+ * @param packet_number 包序号
+ */
+void print_packet_analysis_result(const packet_analysis_result_t *result, uint32_t packet_number);
+
+/**
+ * 打印包统计信息
+ * @param stats 统计信息
+ */
+void print_packet_stats(const packet_stats_t *stats);
+
+/**
+ * 初始化包统计信息
+ * @param stats 统计信息结构
+ */
+void init_packet_stats(packet_stats_t *stats);
+
+#endif /* PPP_PACKET_ANALYZER_H */
\ No newline at end of file
--- /dev/null
+#include "ppp_parser.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* 内部辅助函数声明 */
+static bool ppp_parse_buffer(ppp_parser_t *parser, ppp_frame_t *frame);
+static void ppp_record_dropped_data(ppp_parser_t *parser, ppp_drop_reason_t reason,
+ const uint8_t *data, uint16_t data_len);
+static const char* ppp_get_drop_reason_string(ppp_drop_reason_t reason);
+
+/**
+ * 初始化PPP解析器
+ */
+void ppp_parser_init(ppp_parser_t *parser)
+{
+ if (!parser) return;
+
+ memset(parser, 0, sizeof(ppp_parser_t));
+ parser->in_frame = false;
+ parser->buffer_len = 0;
+ parser->current_position = 0;
+ parser->dropped_data_head = 0;
+ parser->dropped_data_tail = 0;
+}
+
+/**
+ * 重置PPP解析器状态
+ */
+void ppp_parser_reset(ppp_parser_t *parser)
+{
+ if (!parser) return;
+
+ parser->buffer_len = 0;
+ parser->in_frame = false;
+ /* 保留统计信息,只重置解析状态 */
+}
+
+/**
+ * 处理单个字节,返回是否解析出完整PPP帧
+ */
+bool ppp_parser_process_byte(ppp_parser_t *parser, uint8_t byte, ppp_frame_t *frame)
+{
+ if (!parser || !frame) return false;
+
+ parser->total_bytes_processed++;
+ parser->current_position++;
+
+ if (byte == PPP_FLAG_BYTE) {
+ /* PPP帧标志位 */
+ if (parser->in_frame && parser->buffer_len > 0) {
+ /* 帧结束:添加结束标志并处理缓冲区数据 */
+ if (parser->buffer_len < PPP_MAX_BUFFER_SIZE) {
+ parser->buffer[parser->buffer_len++] = byte; /* 添加结束0x7E */
+ }
+ bool result = ppp_parse_buffer(parser, frame);
+ parser->buffer_len = 0;
+ parser->in_frame = false;
+ return result;
+ } else {
+ /* 帧开始:初始化缓冲区并添加开始标志 */
+ if (parser->in_frame && parser->buffer_len > 0) {
+ /* 记录丢弃的数据 */
+ ppp_record_dropped_data(parser, PPP_DROP_REASON_FRAME_SYNC_LOST,
+ parser->buffer, parser->buffer_len);
+ }
+ parser->in_frame = true;
+ parser->buffer_len = 0;
+ parser->buffer[parser->buffer_len++] = byte; /* 添加开始0x7E */
+ }
+ } else {
+ if (parser->in_frame) {
+ /* 检查缓冲区溢出 */
+ if (parser->buffer_len >= PPP_MAX_BUFFER_SIZE) {
+ ppp_record_dropped_data(parser, PPP_DROP_REASON_BUFFER_OVERFLOW,
+ parser->buffer, parser->buffer_len);
+ parser->buffer_len = 0;
+ parser->in_frame = false;
+ return false;
+ }
+ parser->buffer[parser->buffer_len++] = byte;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * 批量处理字节数据
+ */
+uint32_t ppp_parser_process_data(ppp_parser_t *parser, const uint8_t *data,
+ uint32_t data_len, ppp_frame_t *frames, uint32_t max_frames)
+{
+ if (!parser || !data || !frames || max_frames == 0) return 0;
+
+ uint32_t frame_count = 0;
+
+ for (uint32_t i = 0; i < data_len && frame_count < max_frames; i++) {
+ if (ppp_parser_process_byte(parser, data[i], &frames[frame_count])) {
+ frame_count++;
+ }
+ }
+
+ return frame_count;
+}
+
+/**
+ * 解析缓冲区数据,保留完整PPP帧(包含头尾0x7E),不处理转义字符
+ */
+static bool ppp_parse_buffer(ppp_parser_t *parser, ppp_frame_t *frame)
+{
+ if (!parser || !frame || parser->buffer_len == 0) return false;
+
+ /* 校验帧长度(最小:0x7E + 地址1 + 控制1 + 协议2 + 0x7E = 6字节) */
+ if (parser->buffer_len < (PPP_MIN_FRAME_SIZE + 2)) {
+ ppp_record_dropped_data(parser, PPP_DROP_REASON_FRAME_TOO_SHORT,
+ parser->buffer, parser->buffer_len);
+ return false;
+ }
+
+ /* 检查帧长度是否超过最大限制 */
+ if (parser->buffer_len > (PPP_MAX_FRAME_SIZE + 2)) {
+ ppp_record_dropped_data(parser, PPP_DROP_REASON_FRAME_TOO_LONG,
+ parser->buffer, parser->buffer_len);
+ return false;
+ }
+
+ /* 验证帧头尾标志 */
+ if (parser->buffer[0] != PPP_FLAG_BYTE ||
+ parser->buffer[parser->buffer_len - 1] != PPP_FLAG_BYTE) {
+ ppp_record_dropped_data(parser, PPP_DROP_REASON_FRAME_SYNC_LOST,
+ parser->buffer, parser->buffer_len);
+ return false;
+ }
+
+ /* 复制完整PPP帧数据(包含头尾0x7E和转义字符) */
+ frame->raw_frame_len = parser->buffer_len;
+ memcpy(frame->raw_frame, parser->buffer, parser->buffer_len);
+
+ /* 暂时将其他字段设为0,由analyzer处理转义后再解析 */
+ frame->address = 0;
+ frame->control = 0;
+ frame->protocol = 0;
+ frame->payload_len = 0;
+
+ parser->total_frames_parsed++;
+ return true;
+}
+
+/**
+ * 记录丢弃的数据
+ */
+static void ppp_record_dropped_data(ppp_parser_t *parser, ppp_drop_reason_t reason,
+ const uint8_t *data, uint16_t data_len)
+{
+ if (!parser || !data) return;
+
+ /* 计算下一个写入位置 */
+ uint8_t next_tail = (parser->dropped_data_tail + 1) % 32;
+
+ /* 如果缓冲区满了,覆盖最旧的数据 */
+ if (next_tail == parser->dropped_data_head) {
+ parser->dropped_data_head = (parser->dropped_data_head + 1) % 32;
+ }
+
+ /* 记录丢弃数据 */
+ ppp_dropped_data_t *dropped = &parser->dropped_data[parser->dropped_data_tail];
+ dropped->reason = reason;
+ dropped->position = parser->current_position;
+ dropped->data_len = (data_len > 256) ? 256 : data_len;
+ memcpy(dropped->data, data, dropped->data_len);
+
+ parser->dropped_data_tail = next_tail;
+ parser->dropped_data_count++;
+}
+
+/**
+ * 对PPP帧进行组包处理
+ */
+void ppp_classify_frames(const ppp_frame_t *frames, uint32_t frame_count, ppp_group_result_t *result)
+{
+ if (!frames || !result || frame_count == 0) return;
+
+ memset(result, 0, sizeof(ppp_group_result_t));
+ result->total_frames = frame_count;
+
+ for (uint32_t i = 0; i < frame_count; i++) {
+ const ppp_frame_t *frame = &frames[i];
+
+ /* 查找是否已存在该协议的统计 */
+ int protocol_index = -1;
+ for (int j = 0; j < result->protocol_count; j++) {
+ if (result->protocols[j].protocol == frame->protocol) {
+ protocol_index = j;
+ break;
+ }
+ }
+
+ if (protocol_index >= 0) {
+ /* 更新现有协议统计 */
+ result->protocols[protocol_index].frame_count++;
+ } else if (result->protocol_count < 16) {
+ /* 添加新协议统计 */
+ protocol_index = result->protocol_count++;
+ result->protocols[protocol_index].protocol = frame->protocol;
+ result->protocols[protocol_index].frame_count = 1;
+ result->protocols[protocol_index].protocol_name = ppp_get_protocol_name(frame->protocol);
+ } else {
+ /* 协议种类超过限制,计入无效帧 */
+ result->invalid_frames++;
+ }
+ }
+}
+
+/**
+ * 获取协议名称
+ */
+const char* ppp_get_protocol_name(uint16_t protocol)
+{
+ switch (protocol) {
+ case PPP_PROTOCOL_IP:
+ return "IP (IPv4)";
+ case PPP_PROTOCOL_LCP:
+ return "LCP (链路控制协议)";
+ case PPP_PROTOCOL_IPCP:
+ return "IPCP (IP控制协议)";
+ default:
+ return "未知协议";
+ }
+}
+
+/**
+ * 获取丢弃原因字符串
+ */
+static const char* ppp_get_drop_reason_string(ppp_drop_reason_t reason)
+{
+ switch (reason) {
+ case PPP_DROP_REASON_FRAME_SYNC_LOST:
+ return "帧同步丢失或格式错误";
+ case PPP_DROP_REASON_INCOMPLETE_ESCAPE:
+ return "不完整的转义序列";
+ case PPP_DROP_REASON_FRAME_TOO_SHORT:
+ return "帧长度不足4字节";
+ case PPP_DROP_REASON_FRAME_TOO_LONG:
+ return "帧长度过长";
+ case PPP_DROP_REASON_BUFFER_OVERFLOW:
+ return "缓冲区溢出";
+ default:
+ return "未知原因";
+ }
+}
+
+/**
+ * 打印PPP解析器统计信息
+ */
+void ppp_parser_print_stats(const ppp_parser_t *parser)
+{
+ if (!parser) return;
+
+ printf("\nPPP解析器统计信息:\n");
+ printf(" 处理的总字节数: %u\n", parser->total_bytes_processed);
+ printf(" 解析的总帧数: %u\n", parser->total_frames_parsed);
+ printf(" 丢弃数据次数: %u\n", parser->dropped_data_count);
+}
+
+/**
+ * 打印丢弃数据信息
+ */
+void ppp_parser_print_dropped_data(const ppp_parser_t *parser)
+{
+ if (!parser) return;
+
+ printf("\n丢弃的数据信息:\n");
+
+ if (parser->dropped_data_count == 0) {
+ printf(" 没有丢弃的数据\n");
+ return;
+ }
+
+ printf(" 丢弃的数据总数: %u\n", parser->dropped_data_count);
+
+ /* 计算要显示的数据数量(最多5条) */
+ uint8_t count = 0;
+ uint8_t current = parser->dropped_data_head;
+
+ while (current != parser->dropped_data_tail && count < 5) {
+ const ppp_dropped_data_t *dropped = &parser->dropped_data[current];
+
+ printf(" 丢弃数据 #%d:\n", count + 1);
+ printf(" 原因: %s\n", ppp_get_drop_reason_string(dropped->reason));
+ printf(" 位置: %u\n", dropped->position);
+ printf(" 数据: ");
+ for (uint16_t i = 0; i < dropped->data_len && i < 32; i++) {
+ printf("%02X", dropped->data[i]);
+ }
+ if (dropped->data_len > 32) {
+ printf("...");
+ }
+ printf("\n");
+
+ current = (current + 1) % 32;
+ count++;
+ }
+
+ if (parser->dropped_data_count > 5) {
+ printf(" ... 还有%u条丢弃的数据未显示\n", parser->dropped_data_count - 5);
+ }
+}
+
+/**
+ * 打印PPP帧信息
+ */
+void ppp_print_frame_info(const ppp_frame_t *frame, uint32_t frame_number)
+{
+ if (!frame) return;
+
+ printf("PPP帧 #%u: 完整长度=%u字节 (包含头尾0x7E)\n", frame_number, frame->raw_frame_len);
+
+ /* 显示完整PPP帧数据 */
+ printf(" 完整帧数据: ");
+ for (uint16_t i = 0; i < frame->raw_frame_len && i < 32; i++) {
+ printf("%02X", frame->raw_frame[i]);
+ }
+ if (frame->raw_frame_len > 32) {
+ printf("...");
+ }
+ printf("\n");
+
+ /* 如果已经解析过,显示解析后的信息 */
+ if (frame->payload_len > 0) {
+ printf(" 协议: 0x%04X, 地址: 0x%02X, 控制: 0x%02X\n",
+ frame->protocol, frame->address, frame->control);
+ printf(" 处理后负载长度: %u字节 (已处理转义字符)\n", frame->payload_len);
+
+ /* 显示处理后的负载数据(最多显示前32字节) */
+ printf(" 处理后负载: ");
+ uint16_t print_len = (frame->payload_len > 32) ? 32 : frame->payload_len;
+ for (uint16_t i = 0; i < print_len; i++) {
+ printf("%02X", frame->payload[i]);
+ }
+ if (frame->payload_len > 32) {
+ printf("...");
+ }
+ printf("\n");
+ } else {
+ printf(" (未解析 - 需要通过analyzer处理转义字符)\n");
+ }
+}
+
+/**
+ * 打印组包结果
+ */
+void ppp_print_group_result(const ppp_group_result_t *result)
+{
+ if (!result) return;
+
+ printf("\nPPP帧组包结果:\n");
+ printf(" 总帧数: %u\n", result->total_frames);
+ printf(" 协议种类: %u\n", result->protocol_count);
+
+ for (uint8_t i = 0; i < result->protocol_count; i++) {
+ const ppp_protocol_stats_t *stats = &result->protocols[i];
+ printf(" 0x%04X (%s): %u个帧\n",
+ stats->protocol, stats->protocol_name, stats->frame_count);
+ }
+
+ if (result->invalid_frames > 0) {
+ printf(" 无效帧: %u个\n", result->invalid_frames);
+ }
+
+ /* 验证组包结果 */
+ uint32_t total_grouped = result->invalid_frames;
+ for (uint8_t i = 0; i < result->protocol_count; i++) {
+ total_grouped += result->protocols[i].frame_count;
+ }
+
+ if (total_grouped == result->total_frames) {
+ printf(" 组包验证: 成功,所有%u个帧都已正确分组\n", total_grouped);
+ } else {
+ printf(" 组包验证: 警告,分组总数(%u)与原始帧总数(%u)不匹配\n",
+ total_grouped, result->total_frames);
+ }
+}
\ No newline at end of file
--- /dev/null
+#ifndef PPP_PARSER_H
+#define PPP_PARSER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/* PPP协议常量定义 */
+#define PPP_FLAG_BYTE 0x7E /* PPP帧标志位 */
+#define PPP_ESCAPE_BYTE 0x7D /* PPP转义字符 */
+#define PPP_ESCAPE_XOR 0x20 /* PPP转义异或值 */
+#define PPP_MIN_FRAME_SIZE 4 /* PPP帧最小长度(地址+控制+协议) */
+#define PPP_MAX_FRAME_SIZE 1500 /* PPP帧最大长度 */
+#define PPP_MAX_BUFFER_SIZE 2048 /* 解析缓冲区最大长度 */
+
+/* PPP协议类型定义 */
+#define PPP_PROTOCOL_IP 0x0021 /* IPv4协议 */
+#define PPP_PROTOCOL_LCP 0xC021 /* 链路控制协议 */
+#define PPP_PROTOCOL_IPCP 0x8021 /* IP控制协议 */
+
+/* 丢弃数据原因枚举 */
+typedef enum {
+ PPP_DROP_REASON_NONE = 0,
+ PPP_DROP_REASON_FRAME_SYNC_LOST, /* 帧同步丢失 */
+ PPP_DROP_REASON_INCOMPLETE_ESCAPE, /* 不完整的转义序列 */
+ PPP_DROP_REASON_FRAME_TOO_SHORT, /* 帧长度不足 */
+ PPP_DROP_REASON_FRAME_TOO_LONG, /* 帧长度过长 */
+ PPP_DROP_REASON_BUFFER_OVERFLOW /* 缓冲区溢出 */
+} ppp_drop_reason_t;
+
+/* 丢弃数据记录结构 */
+typedef struct {
+ ppp_drop_reason_t reason; /* 丢弃原因 */
+ uint8_t data[256]; /* 丢弃的数据(最多256字节) */
+ uint16_t data_len; /* 丢弃数据长度 */
+ uint32_t position; /* 丢弃位置 */
+} ppp_dropped_data_t;
+
+/* PPP帧结构 */
+typedef struct {
+ uint8_t address; /* 地址字段 */
+ uint8_t control; /* 控制字段 */
+ uint16_t protocol; /* 协议字段 */
+ uint8_t raw_frame[PPP_MAX_FRAME_SIZE + 2]; /* 完整PPP帧数据(包含头尾0x7E) */
+ uint16_t raw_frame_len; /* 完整帧长度 */
+ uint8_t payload[PPP_MAX_FRAME_SIZE]; /* 负载数据(处理转义后) */
+ uint16_t payload_len; /* 负载长度 */
+} ppp_frame_t;
+
+/* PPP帧解析器状态结构 */
+typedef struct {
+ uint8_t buffer[PPP_MAX_BUFFER_SIZE]; /* 帧数据缓冲区 */
+ uint16_t buffer_len; /* 缓冲区当前长度 */
+ bool in_frame; /* 是否处于帧接收状态 */
+ uint32_t current_position; /* 当前处理位置 */
+
+ /* 统计信息 */
+ uint32_t total_frames_parsed; /* 解析的总帧数 */
+ uint32_t total_bytes_processed; /* 处理的总字节数 */
+ uint32_t dropped_data_count; /* 丢弃数据次数 */
+
+ /* 丢弃数据记录(环形缓冲区) */
+ ppp_dropped_data_t dropped_data[32]; /* 最多记录32条丢弃数据 */
+ uint8_t dropped_data_head; /* 丢弃数据头指针 */
+ uint8_t dropped_data_tail; /* 丢弃数据尾指针 */
+} ppp_parser_t;
+
+/* PPP协议统计结构 */
+typedef struct {
+ uint16_t protocol; /* 协议类型 */
+ uint32_t frame_count; /* 帧数量 */
+ const char *protocol_name; /* 协议名称 */
+} ppp_protocol_stats_t;
+
+/* PPP帧组包结果结构 */
+typedef struct {
+ ppp_protocol_stats_t protocols[16]; /* 最多支持16种协议统计 */
+ uint8_t protocol_count; /* 协议种类数量 */
+ uint32_t total_frames; /* 总帧数 */
+ uint32_t invalid_frames; /* 无效帧数 */
+} ppp_group_result_t;
+
+/* 函数声明 */
+
+/**
+ * 初始化PPP解析器
+ * @param parser PPP解析器指针
+ */
+void ppp_parser_init(ppp_parser_t *parser);
+
+/**
+ * 重置PPP解析器状态
+ * @param parser PPP解析器指针
+ */
+void ppp_parser_reset(ppp_parser_t *parser);
+
+/**
+ * 处理单个字节,返回是否解析出完整PPP帧
+ * @param parser PPP解析器指针
+ * @param byte 输入字节
+ * @param frame 输出的PPP帧指针
+ * @return true表示解析出完整帧,false表示需要更多数据
+ */
+bool ppp_parser_process_byte(ppp_parser_t *parser, uint8_t byte, ppp_frame_t *frame);
+
+/**
+ * 批量处理字节数据
+ * @param parser PPP解析器指针
+ * @param data 输入数据指针
+ * @param data_len 输入数据长度
+ * @param frames 输出帧数组
+ * @param max_frames 最大帧数量
+ * @return 实际解析出的帧数量
+ */
+uint32_t ppp_parser_process_data(ppp_parser_t *parser, const uint8_t *data,
+ uint32_t data_len, ppp_frame_t *frames, uint32_t max_frames);
+
+/**
+ * 对PPP帧进行组包处理
+ * @param frames PPP帧数组
+ * @param frame_count 帧数量
+ * @param result 组包结果
+ */
+void ppp_classify_frames(const ppp_frame_t *frames, uint32_t frame_count, ppp_group_result_t *result);
+
+/**
+ * 获取协议名称
+ * @param protocol 协议类型
+ * @return 协议名称字符串
+ */
+const char* ppp_get_protocol_name(uint16_t protocol);
+
+/**
+ * 打印PPP解析器统计信息
+ * @param parser PPP解析器指针
+ */
+void ppp_parser_print_stats(const ppp_parser_t *parser);
+
+/**
+ * 打印丢弃数据信息
+ * @param parser PPP解析器指针
+ */
+void ppp_parser_print_dropped_data(const ppp_parser_t *parser);
+
+/**
+ * 打印PPP帧信息
+ * @param frame PPP帧指针
+ * @param frame_number 帧序号
+ */
+void ppp_print_frame_info(const ppp_frame_t *frame, uint32_t frame_number);
+
+/**
+ * 打印组包结果
+ * @param result 组包结果指针
+ */
+void ppp_print_group_result(const ppp_group_result_t *result);
+
+#endif /* PPP_PARSER_H */
\ No newline at end of file
--- /dev/null
+#ifndef PPP_PARSER_CONFIGURABLE_H
+#define PPP_PARSER_CONFIGURABLE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/* PPP协议常量定义 */
+#define PPP_FLAG_BYTE 0x7E /* PPP帧标志位 */
+#define PPP_ESCAPE_BYTE 0x7D /* PPP转义字符 */
+#define PPP_ESCAPE_XOR 0x20 /* PPP转义异或值 */
+#define PPP_MIN_FRAME_SIZE 4 /* PPP帧最小长度(地址+控制+协议) */
+
+/* 可配置的缓冲区大小 */
+#ifndef PPP_MAX_BUFFER_SIZE
+#define PPP_MAX_BUFFER_SIZE 2048 /* 默认解析缓冲区最大长度 */
+#endif
+
+#ifndef PPP_MAX_FRAME_SIZE
+#define PPP_MAX_FRAME_SIZE 1500 /* 默认PPP帧最大长度 */
+#endif
+
+/* 编译时检查 */
+#if PPP_MAX_BUFFER_SIZE < PPP_MIN_FRAME_SIZE
+#error "PPP_MAX_BUFFER_SIZE must be at least PPP_MIN_FRAME_SIZE"
+#endif
+
+#if PPP_MAX_FRAME_SIZE > PPP_MAX_BUFFER_SIZE
+#error "PPP_MAX_FRAME_SIZE cannot be larger than PPP_MAX_BUFFER_SIZE"
+#endif
+
+/* 运行时配置结构 */
+typedef struct {
+ uint32_t max_buffer_size; /* 最大缓冲区大小 */
+ uint32_t max_frame_size; /* 最大帧大小 */
+ bool enable_size_warnings; /* 启用大小警告 */
+ bool auto_drop_oversized; /* 自动丢弃超大帧 */
+} ppp_parser_config_t;
+
+/* PPP帧结构(可配置版本) */
+typedef struct {
+ uint8_t address; /* 地址字段 */
+ uint8_t control; /* 控制字段 */
+ uint16_t protocol; /* 协议字段 */
+ uint8_t *payload; /* 负载数据指针 */
+ uint32_t payload_len; /* 负载长度 */
+ uint32_t payload_capacity; /* 负载容量 */
+} ppp_frame_configurable_t;
+
+/* PPP解析器状态结构(可配置版本) */
+typedef struct {
+ /* 配置信息 */
+ ppp_parser_config_t config;
+
+ /* 缓冲区 */
+ uint8_t *buffer; /* 动态分配的缓冲区 */
+ uint32_t buffer_len; /* 缓冲区当前长度 */
+ uint32_t buffer_capacity; /* 缓冲区容量 */
+ bool in_frame; /* 是否处于帧接收状态 */
+ uint32_t current_position; /* 当前处理位置 */
+
+ /* 统计信息 */
+ uint32_t total_frames_parsed; /* 解析的总帧数 */
+ uint32_t total_bytes_processed; /* 处理的总字节数 */
+ uint32_t dropped_data_count; /* 丢弃数据次数 */
+ uint32_t oversized_frames_dropped; /* 丢弃的超大帧数 */
+ uint32_t max_frame_size_seen; /* 见过的最大帧大小 */
+} ppp_parser_configurable_t;
+
+/* 默认配置 */
+extern const ppp_parser_config_t PPP_DEFAULT_CONFIG;
+
+/* 大缓冲区配置(用于处理大帧) */
+extern const ppp_parser_config_t PPP_LARGE_BUFFER_CONFIG;
+
+/* 嵌入式配置(内存受限) */
+extern const ppp_parser_config_t PPP_EMBEDDED_CONFIG;
+
+/* 函数声明 */
+
+/**
+ * 创建配置
+ * @param max_buffer_size 最大缓冲区大小
+ * @param max_frame_size 最大帧大小
+ * @param enable_warnings 启用警告
+ * @param auto_drop 自动丢弃超大帧
+ * @return 配置结构
+ */
+ppp_parser_config_t ppp_create_config(uint32_t max_buffer_size, uint32_t max_frame_size,
+ bool enable_warnings, bool auto_drop);
+
+/**
+ * 初始化可配置PPP解析器
+ * @param parser PPP解析器指针
+ * @param config 配置指针(NULL使用默认配置)
+ * @return 成功返回true
+ */
+bool ppp_parser_configurable_init(ppp_parser_configurable_t *parser,
+ const ppp_parser_config_t *config);
+
+/**
+ * 释放可配置PPP解析器
+ * @param parser PPP解析器指针
+ */
+void ppp_parser_configurable_free(ppp_parser_configurable_t *parser);
+
+/**
+ * 处理单个字节(可配置版本)
+ * @param parser PPP解析器指针
+ * @param byte 输入字节
+ * @param frame 输出的PPP帧指针
+ * @return true表示解析出完整帧
+ */
+bool ppp_parser_configurable_process_byte(ppp_parser_configurable_t *parser, uint8_t byte,
+ ppp_frame_configurable_t *frame);
+
+/**
+ * 批量处理字节数据(可配置版本)
+ * @param parser PPP解析器指针
+ * @param data 输入数据指针
+ * @param data_len 输入数据长度
+ * @param frames 输出帧数组
+ * @param max_frames 最大帧数量
+ * @return 实际解析出的帧数量
+ */
+uint32_t ppp_parser_configurable_process_data(ppp_parser_configurable_t *parser,
+ const uint8_t *data, uint32_t data_len,
+ ppp_frame_configurable_t *frames,
+ uint32_t max_frames);
+
+/**
+ * 释放PPP帧资源(可配置版本)
+ * @param frame PPP帧指针
+ */
+void ppp_frame_configurable_free(ppp_frame_configurable_t *frame);
+
+/**
+ * 打印配置信息
+ * @param config 配置指针
+ */
+void ppp_print_config(const ppp_parser_config_t *config);
+
+/**
+ * 打印解析器统计信息(可配置版本)
+ * @param parser 解析器指针
+ */
+void ppp_parser_configurable_print_stats(const ppp_parser_configurable_t *parser);
+
+/* 便利宏定义 */
+#define PPP_CONFIG_DEFAULT() (&PPP_DEFAULT_CONFIG)
+#define PPP_CONFIG_LARGE_BUFFER() (&PPP_LARGE_BUFFER_CONFIG)
+#define PPP_CONFIG_EMBEDDED() (&PPP_EMBEDDED_CONFIG)
+
+/* 自定义配置宏 */
+#define PPP_CONFIG_CUSTOM(buf_size, frame_size, warnings, auto_drop) \
+ ppp_create_config(buf_size, frame_size, warnings, auto_drop)
+
+#endif /* PPP_PARSER_CONFIGURABLE_H */
\ No newline at end of file
--- /dev/null
+#include "ppp_parser_dynamic.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * 初始化动态缓冲区
+ */
+bool ppp_dynamic_buffer_init(ppp_dynamic_buffer_t *buffer, uint32_t initial_size)
+{
+ if (!buffer) return false;
+
+ memset(buffer, 0, sizeof(ppp_dynamic_buffer_t));
+
+ if (initial_size == 0) {
+ initial_size = PPP_INITIAL_BUFFER_SIZE;
+ }
+
+ buffer->data = malloc(initial_size);
+ if (!buffer->data) {
+ return false;
+ }
+
+ buffer->capacity = initial_size;
+ buffer->len = 0;
+ buffer->size = initial_size;
+
+ return true;
+}
+
+/**
+ * 释放动态缓冲区
+ */
+void ppp_dynamic_buffer_free(ppp_dynamic_buffer_t *buffer)
+{
+ if (!buffer) return;
+
+ if (buffer->data) {
+ free(buffer->data);
+ buffer->data = NULL;
+ }
+
+ buffer->capacity = 0;
+ buffer->len = 0;
+ buffer->size = 0;
+}
+
+/**
+ * 确保缓冲区有足够空间
+ */
+bool ppp_dynamic_buffer_ensure_space(ppp_dynamic_buffer_t *buffer, uint32_t required_size)
+{
+ if (!buffer) return false;
+
+ if (buffer->capacity >= required_size) {
+ return true; /* 已有足够空间 */
+ }
+
+ /* 检查是否超过最大限制 */
+ if (required_size > PPP_MAX_BUFFER_SIZE) {
+ printf("错误: 请求的缓冲区大小(%u)超过最大限制(%u)\n",
+ required_size, PPP_MAX_BUFFER_SIZE);
+ return false;
+ }
+
+ /* 计算新的容量(按步长增长) */
+ uint32_t new_capacity = buffer->capacity;
+ while (new_capacity < required_size) {
+ new_capacity += PPP_BUFFER_GROW_STEP;
+ if (new_capacity > PPP_MAX_BUFFER_SIZE) {
+ new_capacity = PPP_MAX_BUFFER_SIZE;
+ break;
+ }
+ }
+
+ /* 重新分配内存 */
+ uint8_t *new_data = realloc(buffer->data, new_capacity);
+ if (!new_data) {
+ printf("错误: 无法重新分配缓冲区内存(大小: %u)\n", new_capacity);
+ return false;
+ }
+
+ buffer->data = new_data;
+ buffer->capacity = new_capacity;
+
+ printf("缓冲区扩展: %u -> %u 字节\n", buffer->size, new_capacity);
+ buffer->size = new_capacity;
+
+ return true;
+}
+
+/**
+ * 向缓冲区添加数据
+ */
+bool ppp_dynamic_buffer_append(ppp_dynamic_buffer_t *buffer, const uint8_t *data, uint32_t len)
+{
+ if (!buffer || !data || len == 0) return false;
+
+ if (!ppp_dynamic_buffer_ensure_space(buffer, buffer->len + len)) {
+ return false;
+ }
+
+ memcpy(buffer->data + buffer->len, data, len);
+ buffer->len += len;
+
+ return true;
+}
+
+/**
+ * 向缓冲区添加单个字节
+ */
+bool ppp_dynamic_buffer_append_byte(ppp_dynamic_buffer_t *buffer, uint8_t byte)
+{
+ return ppp_dynamic_buffer_append(buffer, &byte, 1);
+}
+
+/**
+ * 清空缓冲区(不释放内存)
+ */
+void ppp_dynamic_buffer_clear(ppp_dynamic_buffer_t *buffer)
+{
+ if (!buffer) return;
+ buffer->len = 0;
+}
+
+/**
+ * 初始化动态PPP解析器
+ */
+bool ppp_parser_dynamic_init(ppp_parser_dynamic_t *parser)
+{
+ if (!parser) return false;
+
+ memset(parser, 0, sizeof(ppp_parser_dynamic_t));
+
+ if (!ppp_dynamic_buffer_init(&parser->buffer, PPP_INITIAL_BUFFER_SIZE)) {
+ return false;
+ }
+
+ parser->in_frame = false;
+ parser->current_position = 0;
+
+ return true;
+}
+
+/**
+ * 释放动态PPP解析器
+ */
+void ppp_parser_dynamic_free(ppp_parser_dynamic_t *parser)
+{
+ if (!parser) return;
+
+ ppp_dynamic_buffer_free(&parser->buffer);
+ memset(parser, 0, sizeof(ppp_parser_dynamic_t));
+}
+
+/**
+ * 处理单个字节(动态版本)
+ */
+bool ppp_parser_dynamic_process_byte(ppp_parser_dynamic_t *parser, uint8_t byte,
+ ppp_frame_dynamic_t *frame)
+{
+ if (!parser || !frame) return false;
+
+ parser->total_bytes_processed++;
+ parser->current_position++;
+
+ if (byte == PPP_FLAG_BYTE) {
+ /* PPP帧标志位 */
+ if (parser->in_frame && parser->buffer.len > 0) {
+ /* 帧结束:处理缓冲区数据 */
+ bool result = ppp_parse_buffer_dynamic(parser, frame);
+ ppp_dynamic_buffer_clear(&parser->buffer);
+ parser->in_frame = false;
+ return result;
+ } else {
+ /* 帧开始:初始化缓冲区 */
+ if (parser->in_frame && parser->buffer.len > 0) {
+ /* 记录丢弃的数据 */
+ parser->dropped_data_count++;
+ printf("警告: 丢弃未完成的帧数据(%u字节)\n", parser->buffer.len);
+ }
+ parser->in_frame = true;
+ ppp_dynamic_buffer_clear(&parser->buffer);
+ }
+ } else {
+ if (parser->in_frame) {
+ /* 添加字节到缓冲区 */
+ if (!ppp_dynamic_buffer_append_byte(&parser->buffer, byte)) {
+ /* 缓冲区添加失败,可能是内存不足 */
+ printf("错误: 无法添加字节到缓冲区,丢弃当前帧\n");
+ parser->dropped_data_count++;
+ parser->in_frame = false;
+ ppp_dynamic_buffer_clear(&parser->buffer);
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+ * 解析缓冲区数据(动态版本)
+ */
+static bool ppp_parse_buffer_dynamic(ppp_parser_dynamic_t *parser, ppp_frame_dynamic_t *frame)
+{
+ if (!parser || !frame || parser->buffer.len == 0) return false;
+
+ /* 校验帧长度 */
+ if (parser->buffer.len < PPP_MIN_FRAME_SIZE) {
+ printf("警告: 帧长度不足(%u字节)\n", parser->buffer.len);
+ parser->dropped_data_count++;
+ return false;
+ }
+
+ /* 更新最大帧大小统计 */
+ if (parser->buffer.len > parser->max_frame_size_seen) {
+ parser->max_frame_size_seen = parser->buffer.len;
+ printf("发现更大的帧: %u字节\n", parser->buffer.len);
+ }
+
+ /* 初始化帧结构 */
+ memset(frame, 0, sizeof(ppp_frame_dynamic_t));
+
+ /* 初始化动态负载缓冲区 */
+ if (!ppp_dynamic_buffer_init(&frame->payload, parser->buffer.len)) {
+ printf("错误: 无法为帧负载分配内存\n");
+ return false;
+ }
+
+ /* 复制原始帧数据 */
+ if (!ppp_dynamic_buffer_append(&frame->payload, parser->buffer.data, parser->buffer.len)) {
+ printf("错误: 无法复制帧数据\n");
+ ppp_dynamic_buffer_free(&frame->payload);
+ return false;
+ }
+
+ /* 暂时将协议字段设为0,由analyzer处理 */
+ frame->address = 0;
+ frame->control = 0;
+ frame->protocol = 0;
+
+ parser->total_frames_parsed++;
+ return true;
+}
+
+/**
+ * 释放PPP帧资源
+ */
+void ppp_frame_dynamic_free(ppp_frame_dynamic_t *frame)
+{
+ if (!frame) return;
+
+ ppp_dynamic_buffer_free(&frame->payload);
+ memset(frame, 0, sizeof(ppp_frame_dynamic_t));
+}
+
+/**
+ * 打印动态解析器统计信息
+ */
+void ppp_parser_dynamic_print_stats(const ppp_parser_dynamic_t *parser)
+{
+ if (!parser) return;
+
+ printf("\n动态PPP解析器统计信息:\n");
+ printf(" 处理的总字节数: %u\n", parser->total_bytes_processed);
+ printf(" 解析的总帧数: %u\n", parser->total_frames_parsed);
+ printf(" 丢弃数据次数: %u\n", parser->dropped_data_count);
+ printf(" 缓冲区重分配次数: %u\n", parser->buffer_reallocations);
+ printf(" 最大帧大小: %u字节\n", parser->max_frame_size_seen);
+ printf(" 当前缓冲区容量: %u字节\n", parser->buffer.capacity);
+}
\ No newline at end of file
--- /dev/null
+#ifndef PPP_PARSER_DYNAMIC_H
+#define PPP_PARSER_DYNAMIC_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/* PPP协议常量定义 */
+#define PPP_FLAG_BYTE 0x7E /* PPP帧标志位 */
+#define PPP_ESCAPE_BYTE 0x7D /* PPP转义字符 */
+#define PPP_ESCAPE_XOR 0x20 /* PPP转义异或值 */
+#define PPP_MIN_FRAME_SIZE 4 /* PPP帧最小长度(地址+控制+协议) */
+
+/* 动态缓冲区配置 */
+#define PPP_INITIAL_BUFFER_SIZE 1500 /* 初始缓冲区大小 */
+#define PPP_MAX_BUFFER_SIZE 65536 /* 最大缓冲区大小 */
+#define PPP_BUFFER_GROW_STEP 1024 /* 缓冲区增长步长 */
+
+/* 动态缓冲区结构 */
+typedef struct {
+ uint8_t *data; /* 缓冲区数据指针 */
+ uint32_t size; /* 缓冲区总大小 */
+ uint32_t len; /* 当前数据长度 */
+ uint32_t capacity; /* 当前容量 */
+} ppp_dynamic_buffer_t;
+
+/* PPP帧结构(动态版本) */
+typedef struct {
+ uint8_t address; /* 地址字段 */
+ uint8_t control; /* 控制字段 */
+ uint16_t protocol; /* 协议字段 */
+ ppp_dynamic_buffer_t payload; /* 动态负载数据 */
+} ppp_frame_dynamic_t;
+
+/* PPP解析器状态结构(动态版本) */
+typedef struct {
+ ppp_dynamic_buffer_t buffer; /* 动态帧数据缓冲区 */
+ bool in_frame; /* 是否处于帧接收状态 */
+ uint32_t current_position; /* 当前处理位置 */
+
+ /* 统计信息 */
+ uint32_t total_frames_parsed; /* 解析的总帧数 */
+ uint32_t total_bytes_processed; /* 处理的总字节数 */
+ uint32_t dropped_data_count; /* 丢弃数据次数 */
+ uint32_t buffer_reallocations; /* 缓冲区重分配次数 */
+ uint32_t max_frame_size_seen; /* 见过的最大帧大小 */
+} ppp_parser_dynamic_t;
+
+/* 函数声明 */
+
+/**
+ * 初始化动态缓冲区
+ * @param buffer 缓冲区指针
+ * @param initial_size 初始大小
+ * @return 成功返回true
+ */
+bool ppp_dynamic_buffer_init(ppp_dynamic_buffer_t *buffer, uint32_t initial_size);
+
+/**
+ * 释放动态缓冲区
+ * @param buffer 缓冲区指针
+ */
+void ppp_dynamic_buffer_free(ppp_dynamic_buffer_t *buffer);
+
+/**
+ * 确保缓冲区有足够空间
+ * @param buffer 缓冲区指针
+ * @param required_size 需要的大小
+ * @return 成功返回true
+ */
+bool ppp_dynamic_buffer_ensure_space(ppp_dynamic_buffer_t *buffer, uint32_t required_size);
+
+/**
+ * 向缓冲区添加数据
+ * @param buffer 缓冲区指针
+ * @param data 要添加的数据
+ * @param len 数据长度
+ * @return 成功返回true
+ */
+bool ppp_dynamic_buffer_append(ppp_dynamic_buffer_t *buffer, const uint8_t *data, uint32_t len);
+
+/**
+ * 向缓冲区添加单个字节
+ * @param buffer 缓冲区指针
+ * @param byte 要添加的字节
+ * @return 成功返回true
+ */
+bool ppp_dynamic_buffer_append_byte(ppp_dynamic_buffer_t *buffer, uint8_t byte);
+
+/**
+ * 清空缓冲区(不释放内存)
+ * @param buffer 缓冲区指针
+ */
+void ppp_dynamic_buffer_clear(ppp_dynamic_buffer_t *buffer);
+
+/**
+ * 初始化动态PPP解析器
+ * @param parser PPP解析器指针
+ * @return 成功返回true
+ */
+bool ppp_parser_dynamic_init(ppp_parser_dynamic_t *parser);
+
+/**
+ * 释放动态PPP解析器
+ * @param parser PPP解析器指针
+ */
+void ppp_parser_dynamic_free(ppp_parser_dynamic_t *parser);
+
+/**
+ * 处理单个字节(动态版本)
+ * @param parser PPP解析器指针
+ * @param byte 输入字节
+ * @param frame 输出的PPP帧指针
+ * @return true表示解析出完整帧
+ */
+bool ppp_parser_dynamic_process_byte(ppp_parser_dynamic_t *parser, uint8_t byte,
+ ppp_frame_dynamic_t *frame);
+
+/**
+ * 释放PPP帧资源
+ * @param frame PPP帧指针
+ */
+void ppp_frame_dynamic_free(ppp_frame_dynamic_t *frame);
+
+#endif /* PPP_PARSER_DYNAMIC_H */
\ No newline at end of file
--- /dev/null
+#ifndef PPP_PARSER_STREAMING_H
+#define PPP_PARSER_STREAMING_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/* PPP协议常量定义 */
+#define PPP_FLAG_BYTE 0x7E /* PPP帧标志位 */
+#define PPP_ESCAPE_BYTE 0x7D /* PPP转义字符 */
+#define PPP_ESCAPE_XOR 0x20 /* PPP转义异或值 */
+#define PPP_MIN_FRAME_SIZE 4 /* PPP帧最小长度(地址+控制+协议) */
+
+/* 流式处理配置 */
+#define PPP_STREAM_BUFFER_SIZE 512 /* 流式缓冲区大小 */
+#define PPP_MAX_FRAME_SIZE 65536 /* 最大支持的帧大小 */
+
+/* 流式处理状态 */
+typedef enum {
+ PPP_STREAM_STATE_IDLE, /* 空闲状态 */
+ PPP_STREAM_STATE_IN_FRAME, /* 帧内状态 */
+ PPP_STREAM_STATE_FRAME_COMPLETE, /* 帧完成状态 */
+ PPP_STREAM_STATE_FRAME_TOO_LARGE, /* 帧过大状态 */
+ PPP_STREAM_STATE_ERROR /* 错误状态 */
+} ppp_stream_state_t;
+
+/* 流式处理回调函数类型 */
+typedef struct ppp_stream_parser ppp_stream_parser_t;
+
+/**
+ * 帧数据回调函数
+ * @param parser 解析器指针
+ * @param data 帧数据
+ * @param len 数据长度
+ * @param user_data 用户数据
+ * @return 处理是否成功
+ */
+typedef bool (*ppp_frame_data_callback_t)(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len,
+ void *user_data);
+
+/**
+ * 帧完成回调函数
+ * @param parser 解析器指针
+ * @param total_len 帧总长度
+ * @param user_data 用户数据
+ * @return 处理是否成功
+ */
+typedef bool (*ppp_frame_complete_callback_t)(ppp_stream_parser_t *parser,
+ uint32_t total_len,
+ void *user_data);
+
+/**
+ * 错误处理回调函数
+ * @param parser 解析器指针
+ * @param error_code 错误代码
+ * @param user_data 用户数据
+ */
+typedef void (*ppp_error_callback_t)(ppp_stream_parser_t *parser,
+ int error_code,
+ void *user_data);
+
+/* 流式PPP解析器结构 */
+struct ppp_stream_parser {
+ /* 状态信息 */
+ ppp_stream_state_t state; /* 当前状态 */
+ uint32_t current_frame_len; /* 当前帧长度 */
+ uint32_t total_frames_parsed; /* 解析的总帧数 */
+ uint32_t total_bytes_processed; /* 处理的总字节数 */
+ uint32_t dropped_frames; /* 丢弃的帧数 */
+ uint32_t oversized_frames; /* 超大帧数 */
+
+ /* 缓冲区(用于小块数据暂存) */
+ uint8_t buffer[PPP_STREAM_BUFFER_SIZE];
+ uint32_t buffer_len;
+
+ /* 回调函数 */
+ ppp_frame_data_callback_t data_callback;
+ ppp_frame_complete_callback_t complete_callback;
+ ppp_error_callback_t error_callback;
+ void *user_data;
+};
+
+/* 错误代码定义 */
+#define PPP_ERROR_FRAME_TOO_LARGE 1 /* 帧过大 */
+#define PPP_ERROR_INVALID_STATE 2 /* 无效状态 */
+#define PPP_ERROR_CALLBACK_FAILED 3 /* 回调函数失败 */
+
+/* 函数声明 */
+
+/**
+ * 初始化流式PPP解析器
+ * @param parser 解析器指针
+ * @param data_callback 数据回调函数
+ * @param complete_callback 完成回调函数
+ * @param error_callback 错误回调函数
+ * @param user_data 用户数据
+ * @return 成功返回true
+ */
+bool ppp_stream_parser_init(ppp_stream_parser_t *parser,
+ ppp_frame_data_callback_t data_callback,
+ ppp_frame_complete_callback_t complete_callback,
+ ppp_error_callback_t error_callback,
+ void *user_data);
+
+/**
+ * 处理输入数据
+ * @param parser 解析器指针
+ * @param data 输入数据
+ * @param len 数据长度
+ * @return 处理的字节数
+ */
+uint32_t ppp_stream_parser_process(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len);
+
+/**
+ * 重置解析器状态
+ * @param parser 解析器指针
+ */
+void ppp_stream_parser_reset(ppp_stream_parser_t *parser);
+
+/**
+ * 获取解析器统计信息
+ * @param parser 解析器指针
+ */
+void ppp_stream_parser_print_stats(const ppp_stream_parser_t *parser);
+
+/* 示例:文件输出处理器 */
+typedef struct {
+ FILE *output_file;
+ uint32_t frame_count;
+ uint8_t *frame_buffer;
+ uint32_t frame_buffer_size;
+ uint32_t frame_buffer_pos;
+} ppp_file_output_t;
+
+/**
+ * 初始化文件输出处理器
+ * @param output 输出处理器
+ * @param filename 输出文件名
+ * @return 成功返回true
+ */
+bool ppp_file_output_init(ppp_file_output_t *output, const char *filename);
+
+/**
+ * 释放文件输出处理器
+ * @param output 输出处理器
+ */
+void ppp_file_output_free(ppp_file_output_t *output);
+
+/* 文件输出回调函数 */
+bool ppp_file_output_data_callback(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len,
+ void *user_data);
+
+bool ppp_file_output_complete_callback(ppp_stream_parser_t *parser,
+ uint32_t total_len,
+ void *user_data);
+
+void ppp_file_output_error_callback(ppp_stream_parser_t *parser,
+ int error_code,
+ void *user_data);
+
+#endif /* PPP_PARSER_STREAMING_H */
\ No newline at end of file
--- /dev/null
+#include "ppp_stream_parser.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * 初始化流式PPP解析器
+ */
+bool ppp_stream_parser_init(ppp_stream_parser_t *parser,
+ uint32_t max_frame_size,
+ ppp_frame_start_callback_t start_callback,
+ ppp_frame_data_callback_t data_callback,
+ ppp_frame_complete_callback_t complete_callback,
+ ppp_error_callback_t error_callback,
+ void *user_data)
+{
+ if (!parser || !data_callback || !complete_callback) {
+ return false;
+ }
+
+ memset(parser, 0, sizeof(ppp_stream_parser_t));
+
+ parser->state = PPP_STREAM_STATE_IDLE;
+ parser->max_frame_size = (max_frame_size > 0) ? max_frame_size : PPP_MAX_FRAME_SIZE;
+ parser->start_callback = start_callback;
+ parser->data_callback = data_callback;
+ parser->complete_callback = complete_callback;
+ parser->error_callback = error_callback;
+ parser->user_data = user_data;
+
+ return true;
+}
+
+/**
+ * 处理输入数据
+ */
+uint32_t ppp_stream_parser_process(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len)
+{
+ if (!parser || !data || len == 0) {
+ return 0;
+ }
+
+ uint32_t processed = 0;
+
+ for (uint32_t i = 0; i < len; i++) {
+ uint8_t byte = data[i];
+ parser->total_bytes_processed++;
+ processed++;
+
+ switch (parser->state) {
+ case PPP_STREAM_STATE_IDLE:
+ if (byte == PPP_FLAG_BYTE) {
+ /* 帧开始 */
+ parser->state = PPP_STREAM_STATE_IN_FRAME;
+ parser->current_frame_len = 1; /* 包含开始的0x7E */
+ parser->buffer_len = 0;
+
+ /* 将开始标志添加到缓冲区 */
+ parser->buffer[parser->buffer_len++] = byte;
+
+ /* 调用帧开始回调 */
+ if (parser->start_callback) {
+ if (!parser->start_callback(parser, parser->user_data)) {
+ if (parser->error_callback) {
+ parser->error_callback(parser, PPP_ERROR_CALLBACK_FAILED,
+ "帧开始回调失败", parser->user_data);
+ }
+ parser->state = PPP_STREAM_STATE_ERROR;
+ }
+ }
+ }
+ /* 其他字节在空闲状态下被忽略 */
+ break;
+
+ case PPP_STREAM_STATE_IN_FRAME:
+ if (byte == PPP_FLAG_BYTE) {
+ /* 帧结束 - 添加结束标志 */
+ parser->current_frame_len++;
+
+ /* 将结束标志添加到缓冲区 */
+ parser->buffer[parser->buffer_len++] = byte;
+
+ if (parser->current_frame_len >= (PPP_MIN_FRAME_SIZE + 2)) { /* 包含头尾0x7E */
+ /* 处理缓冲区中的剩余数据 */
+ if (parser->buffer_len > 0) {
+ if (!parser->data_callback(parser, parser->buffer,
+ parser->buffer_len, parser->user_data)) {
+ if (parser->error_callback) {
+ parser->error_callback(parser, PPP_ERROR_CALLBACK_FAILED,
+ "数据回调失败", parser->user_data);
+ }
+ parser->state = PPP_STREAM_STATE_ERROR;
+ break;
+ }
+ }
+
+ /* 调用帧完成回调 */
+ if (parser->complete_callback(parser, parser->current_frame_len,
+ parser->user_data)) {
+ parser->total_frames_parsed++;
+ parser->state = PPP_STREAM_STATE_FRAME_COMPLETE;
+
+ /* 更新最大帧大小统计 */
+ if (parser->current_frame_len > parser->max_frame_size_seen) {
+ parser->max_frame_size_seen = parser->current_frame_len;
+ }
+ } else {
+ if (parser->error_callback) {
+ parser->error_callback(parser, PPP_ERROR_CALLBACK_FAILED,
+ "帧完成回调失败", parser->user_data);
+ }
+ parser->state = PPP_STREAM_STATE_ERROR;
+ }
+ } else {
+ /* 帧太短,丢弃 */
+ parser->dropped_frames++;
+ if (parser->error_callback) {
+ char msg[64];
+ snprintf(msg, sizeof(msg), "帧长度不足(%u字节)", parser->current_frame_len);
+ parser->error_callback(parser, PPP_ERROR_FRAME_TOO_LARGE, msg, parser->user_data);
+ }
+ }
+
+ /* 重置状态,准备下一帧 */
+ parser->state = PPP_STREAM_STATE_IDLE;
+ parser->current_frame_len = 0;
+ parser->buffer_len = 0;
+ } else {
+ /* 帧内数据 */
+ parser->current_frame_len++;
+
+ /* 检查帧大小限制 */
+ if (parser->current_frame_len > parser->max_frame_size) {
+ parser->oversized_frames++;
+ parser->dropped_frames++;
+ if (parser->error_callback) {
+ char msg[64];
+ snprintf(msg, sizeof(msg), "帧过大(%u字节)", parser->current_frame_len);
+ parser->error_callback(parser, PPP_ERROR_FRAME_TOO_LARGE, msg, parser->user_data);
+ }
+ parser->state = PPP_STREAM_STATE_FRAME_TOO_LARGE;
+ break;
+ }
+
+ /* 将数据添加到缓冲区 */
+ parser->buffer[parser->buffer_len++] = byte;
+
+ /* 如果缓冲区满了,调用数据回调 */
+ if (parser->buffer_len >= PPP_STREAM_BUFFER_SIZE) {
+ if (!parser->data_callback(parser, parser->buffer,
+ parser->buffer_len, parser->user_data)) {
+ if (parser->error_callback) {
+ parser->error_callback(parser, PPP_ERROR_CALLBACK_FAILED,
+ "数据回调失败", parser->user_data);
+ }
+ parser->state = PPP_STREAM_STATE_ERROR;
+ break;
+ }
+ parser->buffer_len = 0;
+ }
+ }
+ break;
+
+ case PPP_STREAM_STATE_FRAME_TOO_LARGE:
+ /* 等待帧结束标志 */
+ if (byte == PPP_FLAG_BYTE) {
+ parser->state = PPP_STREAM_STATE_IDLE;
+ parser->current_frame_len = 0;
+ parser->buffer_len = 0;
+ }
+ break;
+
+ case PPP_STREAM_STATE_FRAME_COMPLETE:
+ /* 帧完成后,重新开始处理 */
+ parser->state = PPP_STREAM_STATE_IDLE;
+ /* 重新处理当前字节 */
+ i--;
+ processed--;
+ parser->total_bytes_processed--;
+ break;
+
+ case PPP_STREAM_STATE_ERROR:
+ /* 错误状态,等待重置 */
+ return processed;
+ }
+ }
+
+ return processed;
+}
+
+/**
+ * 重置解析器状态
+ */
+void ppp_stream_parser_reset(ppp_stream_parser_t *parser)
+{
+ if (!parser) return;
+
+ parser->state = PPP_STREAM_STATE_IDLE;
+ parser->current_frame_len = 0;
+ parser->buffer_len = 0;
+}
+
+/**
+ * 获取解析器统计信息
+ */
+void ppp_stream_parser_print_stats(const ppp_stream_parser_t *parser)
+{
+ if (!parser) return;
+
+ printf("\n流式PPP解析器统计信息:\n");
+ printf(" 当前状态: %s\n", ppp_stream_state_name(parser->state));
+ printf(" 处理的总字节数: %u\n", parser->total_bytes_processed);
+ printf(" 解析的总帧数: %u\n", parser->total_frames_parsed);
+ printf(" 丢弃的帧数: %u\n", parser->dropped_frames);
+ printf(" 超大帧数: %u\n", parser->oversized_frames);
+ printf(" 最大帧大小: %u字节\n", parser->max_frame_size_seen);
+ printf(" 最大允许帧大小: %u字节\n", parser->max_frame_size);
+}
+
+/**
+ * 获取状态名称
+ */
+const char* ppp_stream_state_name(ppp_stream_state_t state)
+{
+ switch (state) {
+ case PPP_STREAM_STATE_IDLE:
+ return "空闲";
+ case PPP_STREAM_STATE_IN_FRAME:
+ return "帧内";
+ case PPP_STREAM_STATE_FRAME_COMPLETE:
+ return "帧完成";
+ case PPP_STREAM_STATE_FRAME_TOO_LARGE:
+ return "帧过大";
+ case PPP_STREAM_STATE_ERROR:
+ return "错误";
+ default:
+ return "未知";
+ }
+}
+
+/* 帧收集器实现 */
+
+/**
+ * 初始化帧收集器
+ */
+bool ppp_frame_collector_init(ppp_frame_collector_t *collector, uint32_t max_frames)
+{
+ if (!collector || max_frames == 0) {
+ return false;
+ }
+
+ memset(collector, 0, sizeof(ppp_frame_collector_t));
+
+ collector->frames = malloc(max_frames * sizeof(uint8_t*));
+ collector->frame_lengths = malloc(max_frames * sizeof(uint32_t));
+
+ if (!collector->frames || !collector->frame_lengths) {
+ free(collector->frames);
+ free(collector->frame_lengths);
+ return false;
+ }
+
+ collector->max_frames = max_frames;
+ collector->frame_count = 0;
+
+ return true;
+}
+
+/**
+ * 释放帧收集器
+ */
+void ppp_frame_collector_free(ppp_frame_collector_t *collector)
+{
+ if (!collector) return;
+
+ /* 释放所有帧数据 */
+ for (uint32_t i = 0; i < collector->frame_count; i++) {
+ free(collector->frames[i]);
+ }
+
+ /* 释放当前帧数据 */
+ free(collector->current_frame_data);
+
+ /* 释放数组 */
+ free(collector->frames);
+ free(collector->frame_lengths);
+
+ memset(collector, 0, sizeof(ppp_frame_collector_t));
+}
+
+/**
+ * 获取收集到的帧数据
+ */
+bool ppp_frame_collector_get_frame(const ppp_frame_collector_t *collector,
+ uint32_t frame_index,
+ const uint8_t **frame_data,
+ uint32_t *frame_len)
+{
+ if (!collector || !frame_data || !frame_len || frame_index >= collector->frame_count) {
+ return false;
+ }
+
+ *frame_data = collector->frames[frame_index];
+ *frame_len = collector->frame_lengths[frame_index];
+
+ return true;
+}
+
+/* 帧收集器的回调函数实现 */
+
+bool ppp_collector_start_callback(ppp_stream_parser_t *parser, void *user_data)
+{
+ ppp_frame_collector_t *collector = (ppp_frame_collector_t*)user_data;
+
+ if (!collector) return false;
+
+ /* 检查是否还能收集更多帧 */
+ if (collector->frame_count >= collector->max_frames) {
+ return false;
+ }
+
+ /* 初始化当前帧 */
+ collector->current_frame_capacity = 1024; /* 初始容量 */
+ collector->current_frame_data = malloc(collector->current_frame_capacity);
+ collector->current_frame_len = 0;
+
+ return (collector->current_frame_data != NULL);
+}
+
+bool ppp_collector_data_callback(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len, void *user_data)
+{
+ ppp_frame_collector_t *collector = (ppp_frame_collector_t*)user_data;
+
+ if (!collector || !data || len == 0) return false;
+
+ /* 确保有足够空间 */
+ uint32_t required_size = collector->current_frame_len + len;
+ if (required_size > collector->current_frame_capacity) {
+ /* 扩展容量 */
+ uint32_t new_capacity = collector->current_frame_capacity;
+ while (new_capacity < required_size) {
+ new_capacity *= 2;
+ }
+
+ uint8_t *new_data = realloc(collector->current_frame_data, new_capacity);
+ if (!new_data) {
+ return false;
+ }
+
+ collector->current_frame_data = new_data;
+ collector->current_frame_capacity = new_capacity;
+ }
+
+ /* 复制数据 */
+ memcpy(collector->current_frame_data + collector->current_frame_len, data, len);
+ collector->current_frame_len += len;
+
+ return true;
+}
+
+bool ppp_collector_complete_callback(ppp_stream_parser_t *parser,
+ uint32_t total_len, void *user_data)
+{
+ ppp_frame_collector_t *collector = (ppp_frame_collector_t*)user_data;
+
+ if (!collector) return false;
+
+ /* 将当前帧添加到收集器 */
+ collector->frames[collector->frame_count] = collector->current_frame_data;
+ collector->frame_lengths[collector->frame_count] = collector->current_frame_len;
+ collector->frame_count++;
+
+ /* 重置当前帧 */
+ collector->current_frame_data = NULL;
+ collector->current_frame_len = 0;
+ collector->current_frame_capacity = 0;
+
+ return true;
+}
+
+void ppp_collector_error_callback(ppp_stream_parser_t *parser,
+ int error_code, const char *error_msg, void *user_data)
+{
+ ppp_frame_collector_t *collector = (ppp_frame_collector_t*)user_data;
+
+ printf("帧收集器错误 [%d]: %s\n", error_code, error_msg ? error_msg : "未知错误");
+
+ /* 清理当前帧数据 */
+ if (collector && collector->current_frame_data) {
+ free(collector->current_frame_data);
+ collector->current_frame_data = NULL;
+ collector->current_frame_len = 0;
+ collector->current_frame_capacity = 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+#ifndef PPP_STREAM_PARSER_H
+#define PPP_STREAM_PARSER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/* PPP协议常量定义 */
+#define PPP_FLAG_BYTE 0x7E /* PPP帧标志位 */
+#define PPP_ESCAPE_BYTE 0x7D /* PPP转义字符 */
+#define PPP_ESCAPE_XOR 0x20 /* PPP转义异或值 */
+#define PPP_MIN_FRAME_SIZE 4 /* PPP帧最小长度(地址+控制+协议) */
+
+/* 流式处理配置 */
+#define PPP_STREAM_BUFFER_SIZE 1024 /* 流式缓冲区大小 */
+#ifndef PPP_MAX_FRAME_SIZE
+#define PPP_MAX_FRAME_SIZE 65536 /* 最大支持的帧大小 */
+#endif
+
+/* 流式处理状态 */
+typedef enum {
+ PPP_STREAM_STATE_IDLE, /* 空闲状态 */
+ PPP_STREAM_STATE_IN_FRAME, /* 帧内状态 */
+ PPP_STREAM_STATE_FRAME_COMPLETE, /* 帧完成状态 */
+ PPP_STREAM_STATE_FRAME_TOO_LARGE, /* 帧过大状态 */
+ PPP_STREAM_STATE_ERROR /* 错误状态 */
+} ppp_stream_state_t;
+
+/* 错误代码定义 */
+#define PPP_ERROR_FRAME_TOO_LARGE 1 /* 帧过大 */
+#define PPP_ERROR_INVALID_STATE 2 /* 无效状态 */
+#define PPP_ERROR_CALLBACK_FAILED 3 /* 回调函数失败 */
+#define PPP_ERROR_OUT_OF_MEMORY 4 /* 内存不足 */
+
+/* 前向声明 */
+typedef struct ppp_stream_parser ppp_stream_parser_t;
+
+/* 回调函数类型定义 */
+
+/**
+ * 帧开始回调函数
+ * @param parser 解析器指针
+ * @param user_data 用户数据
+ * @return 处理是否成功
+ */
+typedef bool (*ppp_frame_start_callback_t)(ppp_stream_parser_t *parser, void *user_data);
+
+/**
+ * 帧数据回调函数
+ * @param parser 解析器指针
+ * @param data 帧数据块
+ * @param len 数据长度
+ * @param user_data 用户数据
+ * @return 处理是否成功
+ */
+typedef bool (*ppp_frame_data_callback_t)(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len,
+ void *user_data);
+
+/**
+ * 帧完成回调函数
+ * @param parser 解析器指针
+ * @param total_len 帧总长度
+ * @param user_data 用户数据
+ * @return 处理是否成功
+ */
+typedef bool (*ppp_frame_complete_callback_t)(ppp_stream_parser_t *parser,
+ uint32_t total_len,
+ void *user_data);
+
+/**
+ * 错误处理回调函数
+ * @param parser 解析器指针
+ * @param error_code 错误代码
+ * @param error_msg 错误消息
+ * @param user_data 用户数据
+ */
+typedef void (*ppp_error_callback_t)(ppp_stream_parser_t *parser,
+ int error_code,
+ const char *error_msg,
+ void *user_data);
+
+/* 流式PPP解析器结构 */
+struct ppp_stream_parser {
+ /* 状态信息 */
+ ppp_stream_state_t state; /* 当前状态 */
+ uint32_t current_frame_len; /* 当前帧长度 */
+ uint32_t max_frame_size; /* 最大允许帧大小 */
+
+ /* 统计信息 */
+ uint32_t total_frames_parsed; /* 解析的总帧数 */
+ uint32_t total_bytes_processed; /* 处理的总字节数 */
+ uint32_t dropped_frames; /* 丢弃的帧数 */
+ uint32_t oversized_frames; /* 超大帧数 */
+ uint32_t max_frame_size_seen; /* 见过的最大帧大小 */
+
+ /* 小缓冲区(用于处理跨块的数据) */
+ uint8_t buffer[PPP_STREAM_BUFFER_SIZE];
+ uint32_t buffer_len;
+
+ /* 回调函数 */
+ ppp_frame_start_callback_t start_callback;
+ ppp_frame_data_callback_t data_callback;
+ ppp_frame_complete_callback_t complete_callback;
+ ppp_error_callback_t error_callback;
+ void *user_data;
+};
+
+/* 函数声明 */
+
+/**
+ * 初始化流式PPP解析器
+ * @param parser 解析器指针
+ * @param max_frame_size 最大帧大小(0使用默认值)
+ * @param start_callback 帧开始回调函数
+ * @param data_callback 数据回调函数
+ * @param complete_callback 完成回调函数
+ * @param error_callback 错误回调函数
+ * @param user_data 用户数据
+ * @return 成功返回true
+ */
+bool ppp_stream_parser_init(ppp_stream_parser_t *parser,
+ uint32_t max_frame_size,
+ ppp_frame_start_callback_t start_callback,
+ ppp_frame_data_callback_t data_callback,
+ ppp_frame_complete_callback_t complete_callback,
+ ppp_error_callback_t error_callback,
+ void *user_data);
+
+/**
+ * 处理输入数据
+ * @param parser 解析器指针
+ * @param data 输入数据
+ * @param len 数据长度
+ * @return 处理的字节数
+ */
+uint32_t ppp_stream_parser_process(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len);
+
+/**
+ * 重置解析器状态
+ * @param parser 解析器指针
+ */
+void ppp_stream_parser_reset(ppp_stream_parser_t *parser);
+
+/**
+ * 获取解析器统计信息
+ * @param parser 解析器指针
+ */
+void ppp_stream_parser_print_stats(const ppp_stream_parser_t *parser);
+
+/**
+ * 获取状态名称
+ * @param state 状态值
+ * @return 状态名称字符串
+ */
+const char* ppp_stream_state_name(ppp_stream_state_t state);
+
+/* 便利函数:创建简单的帧收集器 */
+typedef struct {
+ uint8_t **frames; /* 帧数据数组 */
+ uint32_t *frame_lengths; /* 帧长度数组 */
+ uint32_t frame_count; /* 当前帧数量 */
+ uint32_t max_frames; /* 最大帧数量 */
+ uint32_t current_frame_capacity; /* 当前帧容量 */
+ uint8_t *current_frame_data; /* 当前帧数据 */
+ uint32_t current_frame_len; /* 当前帧长度 */
+} ppp_frame_collector_t;
+
+/**
+ * 初始化帧收集器
+ * @param collector 收集器指针
+ * @param max_frames 最大帧数量
+ * @return 成功返回true
+ */
+bool ppp_frame_collector_init(ppp_frame_collector_t *collector, uint32_t max_frames);
+
+/**
+ * 释放帧收集器
+ * @param collector 收集器指针
+ */
+void ppp_frame_collector_free(ppp_frame_collector_t *collector);
+
+/**
+ * 获取收集到的帧数据
+ * @param collector 收集器指针
+ * @param frame_index 帧索引
+ * @param frame_data 输出帧数据指针
+ * @param frame_len 输出帧长度
+ * @return 成功返回true
+ */
+bool ppp_frame_collector_get_frame(const ppp_frame_collector_t *collector,
+ uint32_t frame_index,
+ const uint8_t **frame_data,
+ uint32_t *frame_len);
+
+/* 帧收集器的回调函数 */
+bool ppp_collector_start_callback(ppp_stream_parser_t *parser, void *user_data);
+bool ppp_collector_data_callback(ppp_stream_parser_t *parser,
+ const uint8_t *data, uint32_t len, void *user_data);
+bool ppp_collector_complete_callback(ppp_stream_parser_t *parser,
+ uint32_t total_len, void *user_data);
+void ppp_collector_error_callback(ppp_stream_parser_t *parser,
+ int error_code, const char *error_msg, void *user_data);
+
+#endif /* PPP_STREAM_PARSER_H */
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include "ppp_stream_parser.h"
+#include "ppp_packet_analyzer.h"
+
+/* 配置常量 */
+#define MAX_FILE_SIZE (1024 * 1024) /* 最大文件大小1MB */
+#define MAX_FRAMES 1000 /* 最大帧数量 */
+#define CHUNK_SIZE 256 /* 流式处理块大小 */
+
+/* 全局变量 */
+static uint8_t g_hex_data[MAX_FILE_SIZE]; /* 十六进制数据缓冲区 */
+
+/**
+ * 从十六进制字符串转换为字节值
+ */
+static int hex_char_to_byte(char hex_char)
+{
+ if (hex_char >= '0' && hex_char <= '9') {
+ return hex_char - '0';
+ } else if (hex_char >= 'A' && hex_char <= 'F') {
+ return hex_char - 'A' + 10;
+ } else if (hex_char >= 'a' && hex_char <= 'f') {
+ return hex_char - 'a' + 10;
+ }
+ return -1;
+}
+
+/**
+ * 从文件中读取十六进制数据
+ */
+static uint32_t read_hex_file(const char *file_path, uint8_t *data, uint32_t max_size)
+{
+ if (!file_path || !data || max_size == 0) {
+ printf("错误: 无效的参数\n");
+ return 0;
+ }
+
+ FILE *file = fopen(file_path, "r");
+ if (!file) {
+ printf("错误: 无法打开文件 %s: %s\n", file_path, strerror(errno));
+ return 0;
+ }
+
+ char line[256];
+ uint32_t data_len = 0;
+ uint32_t line_number = 0;
+
+ printf("开始读取文件: %s\n", file_path);
+
+ while (fgets(line, sizeof(line), file) && data_len < max_size) {
+ line_number++;
+
+ /* 移除行尾的换行符和空白字符 */
+ char *end = line + strlen(line) - 1;
+ while (end >= line && isspace(*end)) {
+ *end-- = '\0';
+ }
+
+ /* 跳过空行 */
+ if (strlen(line) == 0) {
+ continue;
+ }
+
+ /* 处理每行的十六进制字符串 */
+ char *ptr = line;
+ while (*ptr && data_len < max_size) {
+ /* 跳过空白字符 */
+ while (*ptr && isspace(*ptr)) {
+ ptr++;
+ }
+
+ if (!*ptr) break;
+
+ /* 读取两个十六进制字符组成一个字节 */
+ if (strlen(ptr) >= 2) {
+ int high = hex_char_to_byte(ptr[0]);
+ int low = hex_char_to_byte(ptr[1]);
+
+ if (high >= 0 && low >= 0) {
+ data[data_len++] = (high << 4) | low;
+ ptr += 2;
+ } else {
+ printf("警告: 文件%s第%u行包含无效的十六进制字符: %c%c\n",
+ file_path, line_number, ptr[0], ptr[1]);
+ ptr += 2;
+ }
+ } else if (strlen(ptr) == 1) {
+ /* 单个十六进制字符,当作一个字节处理 */
+ int value = hex_char_to_byte(ptr[0]);
+ if (value >= 0) {
+ data[data_len++] = value;
+ ptr++;
+ } else {
+ printf("警告: 文件%s第%u行包含无效的十六进制字符: %c\n",
+ file_path, line_number, ptr[0]);
+ ptr++;
+ }
+ }
+ }
+ }
+
+ fclose(file);
+
+ if (data_len >= max_size) {
+ printf("警告: 文件%s数据量超过缓冲区大小,只读取了前%u字节\n", file_path, max_size);
+ }
+
+ printf("成功读取文件%s: %u字节\n", file_path, data_len);
+ return data_len;
+}
+
+/**
+ * 流式分析PPP文件
+ */
+static void analyze_ppp_file_streaming(const char *file_path)
+{
+ printf("\n=== 流式分析文件: %s ===\n", file_path);
+
+ /* 读取文件数据 */
+ uint32_t data_len = read_hex_file(file_path, g_hex_data, MAX_FILE_SIZE);
+ if (data_len == 0) {
+ printf("文件读取失败,跳过分析\n");
+ return;
+ }
+
+ /* 初始化帧收集器 */
+ ppp_frame_collector_t collector;
+ if (!ppp_frame_collector_init(&collector, MAX_FRAMES)) {
+ printf("错误: 无法初始化帧收集器\n");
+ return;
+ }
+
+ /* 初始化流式解析器 */
+ ppp_stream_parser_t parser;
+ if (!ppp_stream_parser_init(&parser,
+ 0, /* 使用默认最大帧大小 */
+ ppp_collector_start_callback,
+ ppp_collector_data_callback,
+ ppp_collector_complete_callback,
+ ppp_collector_error_callback,
+ &collector)) {
+ printf("错误: 无法初始化流式解析器\n");
+ ppp_frame_collector_free(&collector);
+ return;
+ }
+
+ printf("\n--- 流式PPP帧解析阶段 ---\n");
+ printf("使用块大小: %d字节\n", CHUNK_SIZE);
+
+ /* 分块处理数据 */
+ uint32_t total_processed = 0;
+ uint32_t chunk_count = 0;
+
+ for (uint32_t offset = 0; offset < data_len; offset += CHUNK_SIZE) {
+ uint32_t chunk_size = (offset + CHUNK_SIZE > data_len) ?
+ (data_len - offset) : CHUNK_SIZE;
+
+ chunk_count++;
+ printf("处理块 #%u: 偏移=%u, 大小=%u字节\n", chunk_count, offset, chunk_size);
+
+ uint32_t processed = ppp_stream_parser_process(&parser,
+ g_hex_data + offset,
+ chunk_size);
+ total_processed += processed;
+
+ if (processed != chunk_size) {
+ printf("警告: 块 #%u 只处理了 %u/%u 字节\n", chunk_count, processed, chunk_size);
+ }
+ }
+
+ printf("流式解析完成,总共处理 %u 字节,分 %u 个块\n", total_processed, chunk_count);
+
+ /* 打印解析器统计信息 */
+ ppp_stream_parser_print_stats(&parser);
+
+ /* 处理收集到的帧 */
+ printf("\n--- 收集到的PPP帧分析 ---\n");
+ printf("总共收集到 %u 个PPP帧\n", collector.frame_count);
+
+ if (collector.frame_count > 0) {
+ /* 分析前几个帧 */
+ uint32_t analyze_count = (collector.frame_count > 5) ? 5 : collector.frame_count;
+
+ for (uint32_t i = 0; i < analyze_count; i++) {
+ const uint8_t *frame_data;
+ uint32_t frame_len;
+
+ if (ppp_frame_collector_get_frame(&collector, i, &frame_data, &frame_len)) {
+ printf("\n--- 帧 #%u 分析 (长度: %u字节) ---\n", i + 1, frame_len);
+
+ /* 打印帧数据(前32字节) */
+ printf("帧数据: ");
+ uint32_t print_len = (frame_len > 32) ? 32 : frame_len;
+ for (uint32_t j = 0; j < print_len; j++) {
+ printf("%02X", frame_data[j]);
+ }
+ if (frame_len > 32) {
+ printf("...");
+ }
+ printf("\n");
+
+ /* 使用packet analyzer分析帧内容 */
+ packet_analysis_result_t result;
+
+ /* 创建临时的ppp_frame_t结构 */
+ ppp_frame_t temp_frame;
+ memset(&temp_frame, 0, sizeof(temp_frame));
+
+ /* 设置原始帧数据(包含头尾0x7E) */
+ temp_frame.raw_frame_len = frame_len;
+ memcpy(temp_frame.raw_frame, frame_data,
+ (frame_len > (PPP_MAX_FRAME_SIZE + 2)) ? (PPP_MAX_FRAME_SIZE + 2) : frame_len);
+
+ if (analyze_ppp_frame(&temp_frame, &result)) {
+ printf("协议分析: %s\n", result.protocol_name);
+
+ if (result.has_ip) {
+ char src_ip[16], dst_ip[16];
+ format_ip_address(&result.ip_info.src_ip, src_ip, sizeof(src_ip));
+ format_ip_address(&result.ip_info.dst_ip, dst_ip, sizeof(dst_ip));
+
+ printf("IP: %s -> %s, 验证: %s\n",
+ src_ip, dst_ip,
+ (result.ip_info.validation == IP_VALID) ? "通过" : "失败");
+
+ if (result.has_tcp) {
+ printf("TCP: 端口 %u -> %u\n",
+ result.tcp_info.src_port, result.tcp_info.dst_port);
+ } else if (result.has_udp) {
+ printf("UDP: 端口 %u -> %u\n",
+ result.udp_info.src_port, result.udp_info.dst_port);
+ }
+ }
+ } else {
+ printf("协议分析失败\n");
+ }
+ }
+ }
+
+ if (collector.frame_count > 5) {
+ printf("\n... 还有 %u 个帧未显示详细分析\n", collector.frame_count - 5);
+ }
+
+ /* 统计协议分布 */
+ printf("\n--- 协议统计 ---\n");
+ uint32_t ip_count = 0, tcp_count = 0, udp_count = 0, lcp_count = 0, other_count = 0;
+
+ for (uint32_t i = 0; i < collector.frame_count; i++) {
+ const uint8_t *frame_data;
+ uint32_t frame_len;
+
+ if (ppp_frame_collector_get_frame(&collector, i, &frame_data, &frame_len)) {
+ ppp_frame_t temp_frame;
+ memset(&temp_frame, 0, sizeof(temp_frame));
+
+ /* 设置原始帧数据(包含头尾0x7E) */
+ temp_frame.raw_frame_len = frame_len;
+ memcpy(temp_frame.raw_frame, frame_data,
+ (frame_len > (PPP_MAX_FRAME_SIZE + 2)) ? (PPP_MAX_FRAME_SIZE + 2) : frame_len);
+
+ packet_analysis_result_t result;
+ if (analyze_ppp_frame(&temp_frame, &result)) {
+ if (result.has_ip) {
+ ip_count++;
+ if (result.has_tcp) tcp_count++;
+ else if (result.has_udp) udp_count++;
+ } else if (strstr(result.protocol_name, "LCP")) {
+ lcp_count++;
+ } else {
+ other_count++;
+ }
+ } else {
+ other_count++;
+ }
+ }
+ }
+
+ printf("IP包: %u\n", ip_count);
+ printf("TCP包: %u\n", tcp_count);
+ printf("UDP包: %u\n", udp_count);
+ printf("LCP包: %u\n", lcp_count);
+ printf("其他包: %u\n", other_count);
+ }
+
+ /* 清理资源 */
+ ppp_frame_collector_free(&collector);
+
+ printf("\n=== 流式分析完成: %s ===\n", file_path);
+}
+
+/**
+ * 打印使用说明
+ */
+static void print_usage(const char *program_name)
+{
+ printf("流式PPP协议解析工具\n");
+ printf("演示流式处理大型PPP数据文件的能力\n\n");
+ printf("使用方法:\n");
+ printf(" %s [文件1] [文件2] ...\n\n", program_name);
+ printf("特点:\n");
+ printf(" - 流式处理,内存占用固定\n");
+ printf(" - 支持任意大小的PPP帧\n");
+ printf(" - 分块处理,模拟实时数据流\n");
+ printf(" - 回调机制,灵活的数据处理\n\n");
+ printf("示例:\n");
+ printf(" %s out0.txt\n", program_name);
+ printf(" %s out0.txt out1.txt\n", program_name);
+}
+
+/**
+ * 主函数
+ */
+int main(int argc, char *argv[])
+{
+ printf("流式PPP协议解析工具 - 启动\n");
+ printf("版本: 1.0\n");
+ printf("特性: 流式处理、动态内存管理、回调机制\n\n");
+
+ /* 检查命令行参数 */
+ if (argc > 1 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
+ print_usage(argv[0]);
+ return 0;
+ }
+
+ /* 确定要分析的文件列表 */
+ const char **files_to_analyze;
+ int file_count;
+ const char *default_files[] = {"out0.txt", "out1.txt"};
+
+ if (argc > 1) {
+ /* 使用命令行参数中的文件列表 */
+ files_to_analyze = (const char **)&argv[1];
+ file_count = argc - 1;
+ } else {
+ /* 使用默认文件列表 */
+ files_to_analyze = default_files;
+ file_count = 2;
+ printf("未指定文件,使用默认文件: out0.txt, out1.txt\n");
+ }
+
+ /* 遍历并分析每个文件 */
+ int success_count = 0;
+ for (int i = 0; i < file_count; i++) {
+ const char *file_path = files_to_analyze[i];
+
+ /* 检查文件是否存在 */
+ FILE *test_file = fopen(file_path, "r");
+ if (test_file) {
+ fclose(test_file);
+ analyze_ppp_file_streaming(file_path);
+ success_count++;
+ } else {
+ printf("\n错误: 文件不存在或无法访问: %s\n", file_path);
+ }
+ }
+
+ /* 打印总结信息 */
+ printf("\n============================================================\n");
+ printf("流式分析总结:\n");
+ printf(" 指定文件数量: %d\n", file_count);
+ printf(" 成功分析文件: %d\n", success_count);
+ printf(" 失败文件数量: %d\n", file_count - success_count);
+ printf(" 使用的块大小: %d字节\n", CHUNK_SIZE);
+
+ if (success_count == 0) {
+ printf("\n警告: 没有成功分析任何文件\n");
+ return 1;
+ }
+
+ printf("\n流式PPP协议解析工具运行完成\n");
+ return 0;
+}
\ No newline at end of file
#include "ppp_serial.h" // 添加串口处理头文件
#include "ppp_lwip.h"
#include "ppp_cat1_api.h"
+#include "ppp_interrupt.h" // 添加中断处理头文件
#include "soc_osal.h"
#include <string.h>
#include <stdlib.h> // 添加malloc/free支持
PPP_DEBUG_PRINT("No immediate data after mode switch - this is normal\n");
}
- // 9. 启动PPP数据接收处理(在lwIP连接之前启动)
- ret = ppp_lwip_start_receive_thread();
+ // 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 error_recovery_at_mode;
+ }
+ 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 error_recovery_at_mode;
}
+ PPP_DEBUG_PRINT("PPP receive thread started successfully\n");
+#endif
ppp_lwip_config_t lwip_config = {
.username = "",
ppp_error_t ret = PPP_ERR_OK; // 声明ret变量
bool at_communication_ok = false; // 声明AT通信状态变量
- // 1. 首先停止PPP数据接收线程(在切换串口模式之前)
- PPP_DEBUG_INFO("Stopping PPP receive thread...");
- ppp_lwip_stop_receive_thread();
- PPP_DEBUG_INFO("PPP receive thread stopped");
+
- // 2. 强制等待确保线程完全退出
- PPP_DEBUG_INFO("Waiting for thread cleanup...");
- osal_msleep(200); // 给线程足够时间完全退出
+ // 2. 强制等待确保完全退出
+ PPP_DEBUG_INFO("Waiting for cleanup...");
+ osal_msleep(200); // 给足够时间完全退出
// 3. 断开lwIP PPP连接
PPP_DEBUG_INFO("Disconnecting lwIP PPP...");
// 等待确保前面的操作完成
osal_msleep(1000);
+
+ // 1. 停止PPP数据接收(根据配置选择中断或轮询模式)
+ #if PPP_USE_INTERRUPT_MODE
+ // 中断模式:禁用UART中断
+ PPP_DEBUG_INFO("Disabling PPP interrupt mode...");
+ ppp_interrupt_disable();
+ PPP_DEBUG_INFO("PPP interrupt mode disabled");
+
+ // 打印中断统计信息
+ ppp_interrupt_print_stats();
+ #else
+ // 轮询模式:停止接收线程
+ PPP_DEBUG_INFO("Stopping PPP receive thread...");
+ ppp_lwip_stop_receive_thread();
+ PPP_DEBUG_INFO("PPP receive thread stopped");
+ #endif
+
// // 方法1:发送+++转义序列切换调制解调器到命令模式
// PPP_DEBUG_INFO("Sending escape sequence (+++) to switch modem to command mode...");
// const char escape_seq[] = "+++";
--- /dev/null
+/**
+ * @file ppp_interrupt.c
+ * @brief PPP UART中断接收处理 - 类似SLIP但更简单
+ *
+ * 核心优势:
+ * - 使用512字节UART硬件缓冲区,防止数据丢失
+ * - 中断回调直接调用pppos_input_tcpip(),无需自己管理队列
+ * - lwIP TCPIP线程自动处理协议解析,无需loop线程
+ */
+
+#include "ppp_interrupt.h"
+#include "ppp_debug.h"
+#include "ppp_lwip.h"
+#include "ppp_serial.h"
+#include "uart.h"
+#include "hal_uart.h"
+#include "errcode.h"
+#include <string.h>
+#include <stdbool.h>
+
+/* lwIP相关头文件 */
+#include "lwip/err.h"
+#include "netif/ppp/ppp.h"
+#include "netif/ppp/pppos.h"
+
+/* UART硬件缓冲区配置 */
+#define PPP_UART_RX_BUFFER_SIZE 2048 // 硬件缓冲区大小(足够容纳MTU 1500 + PPP开销)
+
+/* 硬件缓冲区 */
+static uint8_t g_ppp_uart_rx_buffer[PPP_UART_RX_BUFFER_SIZE];
+
+/* 中断使能标志 */
+static bool g_ppp_interrupt_enabled = false;
+
+/* 统计信息 */
+static ppp_interrupt_stats_t g_ppp_interrupt_stats = {0};
+
+/* 外部函数声明(在ppp_lwip.c中实现) */
+extern ppp_pcb* ppp_lwip_get_pcb(void);
+extern bool ppp_lwip_is_initialized(void);
+
+/**
+ * @brief UART接收中断回调函数(中断上下文)
+ * @note 此函数在中断上下文中调用,必须快速返回
+ *
+ * 数据流:
+ * 1. UART硬件接收数据 -> 512字节硬件缓冲区
+ * 2. 触发中断回调(本函数)
+ * 3. 直接调用pppos_input_tcpip() -> lwIP自动封装pbuf并发送到TCPIP线程
+ * 4. TCPIP线程自动调用pppos_input() -> ppp_input() -> IP层
+ *
+ * 关键:pppos_input_tcpip()是lwIP提供的线程安全接口,
+ * 专门设计为可以在中断上下文调用!
+ */
+void ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error)
+{
+ // 快速路径:参数校验
+ if (error || !buffer || length == 0) {
+ if (error) {
+ g_ppp_interrupt_stats.error_count++;
+ }
+ return;
+ }
+
+ // 更新接收统计
+ g_ppp_interrupt_stats.total_interrupts++;
+ g_ppp_interrupt_stats.total_bytes_received += length;
+
+ // 打印接收数据大小(中断中只打印简要信息)
+ PPP_DEBUG_INFO("PPP IRQ RX: %u bytes", length);
+
+ // 获取PPP控制块
+ ppp_pcb *ppp_pcb_ptr = ppp_lwip_get_pcb();
+ if (!ppp_pcb_ptr || !ppp_lwip_is_initialized()) {
+ // PPP未初始化,丢弃数据
+ g_ppp_interrupt_stats.dropped_not_initialized += length;
+ PPP_DEBUG_WARN("PPP IRQ: PPP not initialized, dropping %u bytes", length);
+ return;
+ }
+
+ // 核心操作:直接调用lwIP的线程安全接口
+ // 这个函数会:
+ // 1. 分配pbuf
+ // 2. 复制数据到pbuf
+ // 3. 通过tcpip_inpkt()发送到TCPIP线程
+ // 4. TCPIP线程自动调用pppos_input()进行协议解析
+ err_t result = pppos_input_tcpip(ppp_pcb_ptr, (u8_t *)buffer, length);
+
+ if (result != ERR_OK) {
+ // 发送失败(可能是内存不足或队列满)
+ g_ppp_interrupt_stats.dropped_lwip_error += length;
+ g_ppp_interrupt_stats.lwip_error_count++;
+ PPP_DEBUG_WARN("PPP IRQ: pppos_input_tcpip failed: %d, dropped %u bytes", result, length);
+ } else {
+ // 成功发送到lwIP
+ g_ppp_interrupt_stats.total_bytes_sent_to_lwip += length;
+ g_ppp_interrupt_stats.success_count++;
+ }
+}
+
+/**
+ * @brief 获取UART硬件缓冲区配置(供外部UART初始化使用)
+ * @param rx_buffer 返回接收缓冲区指针
+ * @param buffer_size 返回缓冲区大小
+ */
+void ppp_interrupt_get_buffer_config(void **rx_buffer, uint32_t *buffer_size)
+{
+ if (rx_buffer) {
+ *rx_buffer = g_ppp_uart_rx_buffer;
+ }
+ if (buffer_size) {
+ *buffer_size = PPP_UART_RX_BUFFER_SIZE;
+ }
+}
+
+/**
+ * @brief 启用PPP UART中断接收
+ * @return PPP_ERR_OK 成功,其他值失败
+ *
+ * @note 调用此函数前:
+ * 1. ppp_serial必须已初始化(UART总线号从ppp_serial_get_uart_bus()获取)
+ * 2. UART必须已经初始化并配置了硬件缓冲区
+ * 3. 使用 ppp_interrupt_get_buffer_config() 获取缓冲区配置
+ */
+ppp_error_t ppp_interrupt_enable(void)
+{
+ if (g_ppp_interrupt_enabled) {
+ PPP_DEBUG_WARN("PPP interrupt already enabled");
+ return PPP_ERR_OK; // 已启用
+ }
+
+ // 从ppp_serial获取UART总线号(避免重复定义)
+ uint8_t uart_bus = ppp_serial_get_uart_bus();
+
+ PPP_DEBUG_INFO("Enabling PPP UART interrupt (bus=%d)", uart_bus);
+
+ // 注册UART中断回调
+ // UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE (0x07):
+ // - 缓冲区满时触发(>= PPP_UART_RX_BUFFER_SIZE)
+ // - UART空闲时触发(接收间隔超时,防止小包延迟)
+ //
+ // 参数说明(参考SLIP的实现):
+ // - 第2个参数:触发条件标志(0x07 = 满 OR 空闲)
+ // - 第3个参数:缓冲区大小(2048字节,足够容纳1500 MTU + PPP开销)
+ //
+ // 平衡设计:
+ // - 2048字节缓冲区:可完整接收大包,避免溢出
+ // - 空闲检测:小包(<2048字节)依赖UART空闲超时触发
+ // - 参考SLIP使用256字节,PPP使用2048字节应对更大的MTU
+ errcode_t ret = uapi_uart_register_rx_callback(
+ uart_bus,
+ 0x07, // UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE
+ PPP_UART_RX_BUFFER_SIZE, // 缓冲区大小:2048字节
+ ppp_uart_rx_interrupt_handler // 回调函数
+ );
+
+ if (ret != ERRCODE_SUCC) {
+ PPP_DEBUG_ERROR("Failed to register UART RX callback: 0x%x", ret);
+ return PPP_ERR_UART;
+ }
+
+ g_ppp_interrupt_enabled = true;
+
+ PPP_DEBUG_INFO("PPP UART interrupt enabled successfully");
+ PPP_DEBUG_INFO(" RX buffer: %d bytes (balanced for MTU 1500)", PPP_UART_RX_BUFFER_SIZE);
+ PPP_DEBUG_INFO(" Trigger: buffer full OR UART idle");
+ PPP_DEBUG_INFO(" Data flow: UART IRQ -> pppos_input_tcpip() -> lwIP TCPIP thread");
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 禁用PPP UART中断接收
+ * @return PPP_ERR_OK 成功,其他值失败
+ */
+ppp_error_t ppp_interrupt_disable(void)
+{
+ if (!g_ppp_interrupt_enabled) {
+ return PPP_ERR_OK;
+ }
+
+ // 从ppp_serial获取UART总线号
+ uint8_t uart_bus = ppp_serial_get_uart_bus();
+
+ PPP_DEBUG_INFO("Disabling PPP UART interrupt (bus=%d)", uart_bus);
+
+ // 注销中断回调
+ uapi_uart_unregister_rx_callback(uart_bus);
+
+ g_ppp_interrupt_enabled = false;
+
+ PPP_DEBUG_INFO("PPP UART interrupt disabled");
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 检查中断是否已启用
+ * @return true 已启用,false 未启用
+ */
+bool ppp_interrupt_is_enabled(void)
+{
+ return g_ppp_interrupt_enabled;
+}
+
+/**
+ * @brief 获取中断统计信息
+ * @param stats 统计信息输出缓冲区
+ */
+void ppp_interrupt_get_stats(ppp_interrupt_stats_t *stats)
+{
+ if (stats) {
+ memcpy(stats, &g_ppp_interrupt_stats, sizeof(ppp_interrupt_stats_t));
+ }
+}
+
+/**
+ * @brief 重置中断统计信息
+ */
+void ppp_interrupt_reset_stats(void)
+{
+ memset(&g_ppp_interrupt_stats, 0, sizeof(ppp_interrupt_stats_t));
+ PPP_DEBUG_INFO("PPP interrupt statistics reset");
+}
+
+/**
+ * @brief 打印中断统计信息
+ */
+void ppp_interrupt_print_stats(void)
+{
+ PPP_DEBUG_INFO("=== PPP Interrupt Statistics ===");
+ 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("");
+ 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("");
+
+ // 计算丢包率
+ 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;
+ 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("================================");
+}
\ No newline at end of file
static ppp_output_stats_t g_ppp_output_stats = {0};
/* 内部函数声明 */
-static u32_t ppp_lwip_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx);
+static uint32_t ppp_lwip_output_callback(ppp_pcb *pcb, uint8_t *data, uint32_t len, void *ctx);
static void ppp_lwip_link_status_callback(ppp_pcb *pcb, int err_code, void *ctx);
static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx);
static void ppp_lwip_netif_status_callback(struct netif *netif);
g_lwip_ctx.ppp_pcb->lcp_wantoptions.neg_magicnumber = 0;
g_lwip_ctx.ppp_pcb->lcp_allowoptions.neg_magicnumber = 0;
+ #if PPP_ENABLE_LARGE_MRU
/* 启用并强制MRU协商 - 防止接收超大帧 */
g_lwip_ctx.ppp_pcb->lcp_wantoptions.neg_mru = 1;
- g_lwip_ctx.ppp_pcb->lcp_allowoptions.neg_mru = 1;
g_lwip_ctx.ppp_pcb->lcp_wantoptions.mru = PPP_MRU_SIZE; // 使用配置的1500字节
+ g_lwip_ctx.ppp_pcb->lcp_allowoptions.neg_mru = 1;
g_lwip_ctx.ppp_pcb->lcp_allowoptions.mru = PPP_MRU_SIZE;
+ #else
+ g_lwip_ctx.ppp_pcb->lcp_wantoptions.neg_mru = 0;
+ g_lwip_ctx.ppp_pcb->lcp_wantoptions.mru = 0; // 使用配置的1500字节
+ g_lwip_ctx.ppp_pcb->lcp_allowoptions.neg_mru = 0;
+ g_lwip_ctx.ppp_pcb->lcp_allowoptions.mru = 0;
+ #endif
PPP_DEBUG_INFO("MRU negotiation enabled: want=%u, allow=%u",
- g_lwip_ctx.ppp_pcb->lcp_wantoptions.mru,
- g_lwip_ctx.ppp_pcb->lcp_allowoptions.mru);
-
- /* 启用IPCP接受选项 (对应 ipcp-accept-local/remote) */
+ g_lwip_ctx.ppp_pcb->lcp_wantoptions.mru,
+ g_lwip_ctx.ppp_pcb->lcp_allowoptions.mru);
+/* 启用IPCP接受选项 (对应 ipcp-accept-local/remote) */
g_lwip_ctx.ppp_pcb->ipcp_wantoptions.accept_local = 1;
g_lwip_ctx.ppp_pcb->ipcp_wantoptions.accept_remote = 1;
*/
static u32_t ppp_lwip_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
{
- (void)pcb;
- (void)ctx;
+ /* 严格的参数检查 - 防止空指针访问 */
+ if (!pcb) {
+ PPP_DEBUG_ERROR("CRITICAL: ppp_pcb is NULL in output callback!");
+ return 0;
+ }
if (!data || len == 0) {
PPP_DEBUG_ERROR("Invalid output data: data=%p, len=%u", data, len);
return 0;
}
+
+ /* 检查数据长度是否合理(PPP最大帧1500字节 + 头部) */
+ if (len > 2048) {
+ PPP_DEBUG_ERROR("Abnormal packet size: %u bytes (max expected 2048)", len);
+ return 0;
+ }
/* 记录数据活动 */
ppp_lwip_record_data_activity();
return PPP_ERR_OK;
}
+/**
+ * @brief 获取PPP控制块(供中断处理模块使用)
+ * @return PPP控制块指针,如果未初始化则返回NULL
+ */
+ppp_pcb* ppp_lwip_get_pcb(void)
+{
+#ifdef LWIP_PPP_SUPPORT
+ return g_lwip_ctx.ppp_pcb;
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * @brief 检查PPP lwIP是否已初始化(供中断处理模块使用)
+ * @return true 已初始化,false 未初始化
+ */
+bool ppp_lwip_is_initialized(void)
+{
+ return g_lwip_ctx.initialized;
+}
+
+/**
+ * @brief 打印lwIP内存使用情况(用于诊断)
+ */
+void ppp_lwip_print_memory_stats(void)
+{
+#ifdef LWIP_PPP_SUPPORT
+ PPP_DEBUG_PRINT("\n=== lwIP Memory Statistics ===\n");
+
+ #if MEMP_STATS
+ // 打印pbuf池统计
+ PPP_DEBUG_PRINT("PBUF Pools:\n");
+ PPP_DEBUG_PRINT(" PBUF_POOL: used=%u, max=%u, avail=%u\n",
+ lwip_stats.memp[MEMP_PBUF_POOL]->used,
+ lwip_stats.memp[MEMP_PBUF_POOL]->max,
+ lwip_stats.memp[MEMP_PBUF_POOL]->avail);
+ PPP_DEBUG_PRINT(" PBUF: used=%u, max=%u, avail=%u\n",
+ lwip_stats.memp[MEMP_PBUF]->used,
+ lwip_stats.memp[MEMP_PBUF]->max,
+ lwip_stats.memp[MEMP_PBUF]->avail);
+
+ // 打印TCP相关池统计
+ PPP_DEBUG_PRINT("TCP Pools:\n");
+ PPP_DEBUG_PRINT(" TCP_PCB: used=%u, max=%u, avail=%u\n",
+ lwip_stats.memp[MEMP_TCP_PCB]->used,
+ lwip_stats.memp[MEMP_TCP_PCB]->max,
+ lwip_stats.memp[MEMP_TCP_PCB]->avail);
+ PPP_DEBUG_PRINT(" TCP_SEG: used=%u, max=%u, avail=%u\n",
+ lwip_stats.memp[MEMP_TCP_SEG]->used,
+ lwip_stats.memp[MEMP_TCP_SEG]->max,
+ lwip_stats.memp[MEMP_TCP_SEG]->avail);
+ #else
+ PPP_DEBUG_PRINT(" MEMP_STATS not enabled in lwIP\n");
+ #endif
+
+ #if MEM_STATS
+ // 打印堆内存统计
+ PPP_DEBUG_PRINT("Heap Memory:\n");
+ PPP_DEBUG_PRINT(" Used: %u bytes\n", lwip_stats.mem.used);
+ PPP_DEBUG_PRINT(" Max: %u bytes\n", lwip_stats.mem.max);
+ PPP_DEBUG_PRINT(" Available: %u bytes\n", lwip_stats.mem.avail);
+ PPP_DEBUG_PRINT(" Errors: %u\n", lwip_stats.mem.err);
+ #else
+ PPP_DEBUG_PRINT(" MEM_STATS not enabled in lwIP\n");
+ #endif
+
+ PPP_DEBUG_PRINT("=================================\n\n");
+#else
+ PPP_DEBUG_PRINT("lwIP PPP support not compiled\n");
+#endif
+}
+
#endif /* LWIP_PPP_SUPPORT */
\ No newline at end of file
/**
* @file ppp_lwip_thread.c
- * @brief PPP接收线程实现 - 双线程架构:接收线程拼包 + 处理线程处理
+ * @brief PPP接收线程实现 - 支持单线程和双线程模式
+ *
+ * 线程模式配置:
+ * - PPP_USE_DUAL_THREAD=1: 双线程模式(接收线程拼包 + 处理线程处理)
+ * - PPP_USE_DUAL_THREAD=0: 单线程模式(接收线程直接处理)
*/
#include "ppp_api.h"
#include "soc_osal.h"
#include "schedule/osal_task.h"
#include "msgqueue/osal_msgqueue.h"
+#include "custom_utils.h"
#include <stdlib.h>
#include <string.h>
-/* PPP帧队列相关 */
+/* PPP接收模式配置(中断相关代码已移除,使用独立的ppp_interrupt模块) */
+
+/* PPP线程模式配置 */
+#ifndef PPP_USE_DUAL_THREAD
+#define PPP_USE_DUAL_THREAD 0 // 默认使用双线程模式
+#endif
+
+#if PPP_USE_DUAL_THREAD
+#define PPP_THREAD_MODE_STR "DUAL_THREAD"
+#else
+#define PPP_THREAD_MODE_STR "SINGLE_THREAD"
+#endif
+
+/* PPP帧队列相关(仅双线程模式使用) */
+#if PPP_USE_DUAL_THREAD
#define PPP_FRAME_QUEUE_SIZE 32 // 队列大小
#define PPP_MAX_FRAME_SIZE 2048 // 从1500增加到2048
-/* PPP帧结构 */
+/* PPP帧结构(仅双线程模式使用) */
typedef struct {
uint8_t *data; // 帧数据
uint32_t length; // 帧长度
} ppp_frame_t;
+#endif
/* PPP字节丢弃统计结构已在ppp_types.h中定义 */
/* PPP线程相关 */
-static osal_task *g_ppp_rx_thread = NULL; // 接收线程
-static osal_task *g_ppp_process_thread = NULL; // 处理线程
+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 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帧队列 */
+/* PPP帧队列(仅双线程模式使用) */
+#if PPP_USE_DUAL_THREAD
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转义掩码
+#endif
/* 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};
+static ppp_error_t ppp_process_data_block(const uint8_t *data, uint32_t length);
/**
- * @brief å\88\9då§\8bå\8c\96PPP帧æ\8b¼å\8c\85å\99¨
+ * @brief å¤\84ç\90\86PPPæ\95°æ\8d®å¹¶æ\89\93å\8d°è¯¦ç»\86ä¿¡æ\81¯ï¼\88å\8d\95线ç¨\8b模å¼\8fä¸\93ç\94¨ï¼\89
*/
-static ppp_error_t ppp_frame_assembler_init(void)
+static ppp_error_t ppp_process_and_print_data(const uint8_t *data, uint32_t length)
{
- 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;
+ if (!data || length == 0) {
+ return PPP_ERR_INVALID_PARAM;
}
- g_frame_assembler.data_len = 0;
- g_frame_assembler.in_frame = false;
- g_frame_assembler.escaped = false;
+ // 打印详细的接收数据(在处理阶段,不影响接收效率)
+ 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_DEBUG_PRINT("\n");
- 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;
+ // 调用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;
}
- 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;
}
+#if PPP_USE_DUAL_THREAD
/**
- * @brief å\8f\91é\80\81å®\8cæ\95´PPP帧å\88°é\98\9få\88\97
+ * @brief å¤\84ç\90\86æ\8e¥æ\94¶å\88°ç\9a\84æ\95°æ\8d®å\9d\97ï¼\88å\8f\8c线ç¨\8b模å¼\8fï¼\89
*/
-static ppp_error_t ppp_send_frame_to_queue(const uint8_t *data, uint32_t length)
+static ppp_error_t ppp_process_data_block(const uint8_t *data, uint32_t length)
{
- if (!data || length == 0 || length > PPP_MAX_FRAME_SIZE) {
+ if (!data || length == 0) {
return PPP_ERR_INVALID_PARAM;
}
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;
+ g_ppp_discard_stats.malloc_fail_bytes += length;
return PPP_ERR_MEMORY;
}
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;
+ g_ppp_discard_stats.malloc_fail_bytes += length;
free(frame);
return PPP_ERR_MEMORY;
// 发送到队列
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);
+ PPP_DEBUG_WARN("Failed to send data to queue: %d, dropping data", ret);
// 统计队列满丢弃
- g_ppp_discard_stats.total_frames_discarded++;
- g_ppp_discard_stats.queue_full_bytes += length;
g_ppp_discard_stats.total_bytes_discarded += length;
+ g_ppp_discard_stats.queue_full_bytes += length;
free(frame->data);
free(frame);
- return PPP_ERR_UNKNOWN; // 使用已定义的错误码
- }
-
- PPP_DEBUG_DEBUG("Sent complete PPP frame to queue: %u bytes", length);
-
- // 更新帧统计
- 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;
-
+ PPP_DEBUG_DEBUG("Sent data block to queue: %u bytes", length);
return PPP_ERR_OK;
}
+#endif
/**
- * @brief PPP数据接收线程 - 只负责拼包
+ * @brief PPP数据接收线程 - 轮询模式(类似SLIP的高效策略)
*/
static void ppp_lwip_receive_thread(void *arg)
{
(void)arg;
-
- PPP_DEBUG_INFO("PPP receive thread started (frame assembly mode)");
+
+ PPP_DEBUG_INFO("PPP receive thread started (polling mode)");
// 分配串口接收缓冲区
uint8_t *rx_buffer = (uint8_t *)malloc(PPP_RX_BUFFER_SIZE);
}
uint32_t bytes_read = 0;
- uint32_t total_bytes = 0, total_frames = 0;
+ uint32_t total_bytes = 0;
+ uint32_t idle_count = 0;
- PPP_DEBUG_DEBUG("PPP receive thread: allocated %d bytes RX buffer", PPP_RX_BUFFER_SIZE);
+ PPP_DEBUG_INFO("PPP receive thread: allocated %d bytes RX buffer", PPP_RX_BUFFER_SIZE);
- // 主循环:从串口读取数据并拼包
+ // 主循环:类似SLIP的连续读取策略
while (g_ppp_rx_thread_running) {
- // 从串口读取数据
- ppp_error_t ret = ppp_serial_read(rx_buffer, PPP_RX_BUFFER_SIZE, &bytes_read);
-
- if (ret == PPP_ERR_OK && bytes_read > 0) {
- total_bytes += bytes_read;
+ uint32_t batch_bytes = 0;
+ uint32_t read_count = 0;
+
+ // 连续读取直到无数据,类似SLIP的slipif_poll
+ while (g_ppp_rx_thread_running) {
+ ppp_error_t ret = ppp_serial_tryread(rx_buffer, PPP_RX_BUFFER_SIZE, &bytes_read);
- // 更新接收字节统计
- g_ppp_discard_stats.total_bytes_received += bytes_read;
-
- PPP_DEBUG_DEBUG("PPP RX: Got %u bytes (total: %u bytes)", bytes_read, total_bytes);
+ 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 (read #%u)", bytes_read, read_count);
- // 逐字节处理,进行PPP帧拼包(保留完整帧格式)
- for (uint32_t i = 0; i < bytes_read; i++) {
- ppp_error_t process_ret = ppp_process_received_byte(rx_buffer[i]);
+#if PPP_USE_DUAL_THREAD
+ // 双线程模式:发送到队列由处理线程处理
+ ppp_error_t process_ret = ppp_process_data_block(rx_buffer, bytes_read);
if (process_ret != PPP_ERR_OK) {
- // 字节处理失败,统计丢弃
- g_ppp_discard_stats.total_bytes_discarded++;
- g_ppp_discard_stats.invalid_frame_bytes++;
+ PPP_DEBUG_WARN("Failed to process data block: %d", process_ret);
}
- }
- } else if (ret != PPP_ERR_OK) {
- // 读取错误
- if (!g_ppp_rx_thread_running) {
- PPP_DEBUG_DEBUG("PPP receive thread stopping, ignoring read error");
+#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;
+ } 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;
+ }
+ PPP_DEBUG_ERROR("PPP serial tryread error: %d", ret);
+ break;
+ } else {
+ // 无数据,退出连续读取循环
break;
}
- PPP_DEBUG_ERROR("PPP serial read error: %d", ret);
- } else {
- // 没有数据,短暂休眠
+ }
+
+ if (batch_bytes > 0) {
+ // 有数据处理,重置空闲计数器
+ idle_count = 0;
+ PPP_DEBUG_DEBUG("PPP batch: %u bytes in %u reads", batch_bytes, read_count);
+
+ // 短暂休眠后继续,保持高响应性
osal_msleep(1);
+ } else {
+ // 无数据时使用类似SLIP的休眠策略
+ idle_count++;
+ osal_msleep(20); // 类似SLIP的20ms休眠,不打印避免日志干扰
}
- // 定期打印统计信息
- if ((total_frames % 100) == 0 && total_frames > 0) {
- PPP_DEBUG_DEBUG("PPP RX: %u frames assembled, %u total bytes",
- total_frames, total_bytes);
+ // 定期打印统计信息(减少频率)
+ if ((total_bytes % 4096) == 0 && total_bytes > 0) {
+ PPP_DEBUG_INFO("PPP RX: %u total bytes received", total_bytes);
}
}
// 释放缓冲区
free(rx_buffer);
- PPP_DEBUG_INFO("PPP receive thread completed");
+ PPP_DEBUG_INFO("PPP receive thread completed (polling mode), processed %u bytes", total_bytes);
g_ppp_rx_thread_completed = true;
}
+#if PPP_USE_DUAL_THREAD
/**
- * @brief PPP帧处理线程 - 从队列获取完整帧并处理
+ * @brief PPP数据处理线程 - 从队列获取数据块并处理(仅双线程模式)
*/
static void ppp_lwip_process_thread(void *arg)
{
PPP_DEBUG_INFO("PPP process thread started");
- uint32_t processed_frames = 0;
+ uint32_t processed_blocks = 0;
uint32_t processed_bytes = 0;
- // 主循环:从队列获取完整PPP帧并处理
+ // 主循环:从队列获取数据块并处理
while (g_ppp_process_thread_running) {
- ppp_frame_t *frame = NULL;
+ 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, &frame, &msg_size, OSAL_MSGQ_WAIT_FOREVER);
+ // 从队列获取数据块(超时100ms,避免无限阻塞)
+ int ret = osal_msg_queue_read_copy(g_ppp_frame_queue, &data_block, &msg_size, OSAL_WAIT_FOREVER);
- if (ret == OSAL_SUCCESS && frame) {
- // 处理完整PPP帧
- PPP_DEBUG_DEBUG("Processing PPP frame: %u bytes", frame->length);
+ if (ret == OSAL_SUCCESS && data_block) {
+ // 处理数据块
+ PPP_DEBUG_DEBUG("Processing data block: %u bytes", data_block->length);
- // 调用lwIP处理
- ppp_lwip_input(frame->data, frame->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_frames++;
- processed_bytes += frame->length;
- // 更新处理统计(统计实际传递给lwIP的字节数,但排除我们添加的0x7E)
- g_ppp_discard_stats.total_frames_processed++;
- // 减去我们添加的额外0x7E标志(每帧最多添加1个)
- uint32_t original_bytes = frame->length;
- if (frame->length > 0 && frame->data[frame->length-1] == 0x7E) {
- original_bytes--; // 减去结束时添加的0x7E
+ // 更新统计
+ 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;
}
- g_ppp_discard_stats.total_bytes_processed += original_bytes;
- // 释放帧内存
- free(frame->data);
- free(frame);
+ // 释放数据块内存
+ free(data_block->data);
+ free(data_block);
// 定期打印统计
- if ((processed_frames % 50) == 0) {
- PPP_DEBUG_DEBUG("PPP Process: %u frames, %u bytes processed",
- processed_frames, processed_bytes);
+ if ((processed_blocks % 50) == 0) {
+ PPP_DEBUG_DEBUG("PPP Process: %u blocks, %u bytes processed",
+ processed_blocks, processed_bytes);
}
} else if (ret != OSAL_SUCCESS) {
// 超时或其他错误
PPP_DEBUG_DEBUG("PPP process thread stopping");
break;
}
- // 超时是正常的,其他错误才需要警告
- if (ret != 0) { // 假设超时返回非0值
- PPP_DEBUG_WARN("Failed to read from frame queue: %d", ret);
- }
+ // 超时是正常的,不需要警告。只有真正的错误才需要警告
+ // OSAL_FAILURE (-1) 通常表示超时,这是正常的
+ // 这里我们不再对超时进行警告,因为这是正常的队列空闲状态
+ PPP_DEBUG_DEBUG("Queue read timeout (normal when no data), ret: %d", ret);
}
// 超时是正常的,继续循环
}
- // 清理队列中剩余的帧
- ppp_frame_t *frame = NULL;
+ // 清理队列中剩余的数据块
+ ppp_frame_t *data_block = 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);
+ 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 frames, %u bytes",
- processed_frames, processed_bytes);
+ 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 (g_ppp_rx_thread != NULL || g_ppp_process_thread != NULL) {
+#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_error_t ret = ppp_frame_assembler_init();
- if (ret != PPP_ERR_OK) {
- PPP_DEBUG_ERROR("Failed to initialize frame assembler");
- return ret;
+ 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;
}
- // 创建帧队列
- 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;
- }
+ PPP_DEBUG_INFO("Starting PPP receive thread (" PPP_THREAD_MODE_STR " mode)");
+#endif
// 重置完成标志
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);
+ return PPP_ERR_MEMORY;
+ }
+
// 启动处理线程
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");
+
+ 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.func = ppp_lwip_process_thread;
+ process_task_cfg.task_handle = &g_ppp_process_thread_handle;
+ process_task_cfg.use_mem = USE_EXTEND_MEM;
+
+ errcode_t process_ret = uapi_create_osThread_custom(&process_task_cfg);
+ 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;
- ppp_frame_assembler_cleanup();
return PPP_ERR_MEMORY;
}
+#endif /* PPP_USE_DUAL_THREAD */
// 启动接收线程
g_ppp_rx_thread_running = true;
- g_ppp_rx_thread = osal_kthread_create((osal_kthread_handler)ppp_lwip_receive_thread,
- NULL, "ppp_receive", 4096);
- if (!g_ppp_rx_thread) {
- PPP_DEBUG_ERROR("Failed to create PPP receive thread");
+
+ 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.func = ppp_lwip_receive_thread;
+ rx_task_cfg.task_handle = &g_ppp_rx_thread_handle;
+ rx_task_cfg.use_mem = USE_EXTEND_MEM;
+
+ errcode_t rx_ret = uapi_create_osThread_custom(&rx_task_cfg);
+ if (rx_ret != ERRCODE_SUCC) {
+ 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;
- osal_kthread_destroy(g_ppp_process_thread, 0);
- g_ppp_process_thread = NULL;
+ osThreadTerminate((osThreadId_t)g_ppp_process_thread_handle);
+ g_ppp_process_thread_handle = 0;
// 清理资源
osal_msg_queue_delete(g_ppp_frame_queue);
g_ppp_frame_queue = 0;
- ppp_frame_assembler_cleanup();
+#endif
return PPP_ERR_MEMORY;
}
- PPP_DEBUG_INFO("PPP receive and process threads started successfully");
+ PPP_DEBUG_INFO("PPP threads started successfully (" PPP_THREAD_MODE_STR " mode)");
return PPP_ERR_OK;
}
*/
ppp_error_t ppp_lwip_stop_receive_thread(void)
{
- if (!g_ppp_rx_thread && !g_ppp_process_thread) {
+#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 receive and process threads");
+ PPP_DEBUG_INFO("Stopping PPP threads (" PPP_THREAD_MODE_STR " mode)");
// 停止接收线程
- if (g_ppp_rx_thread) {
+ if (g_ppp_rx_thread_handle != 0) {
g_ppp_rx_thread_running = false;
// 等待接收线程完成
PPP_DEBUG_WARN("PPP receive thread did not complete within timeout");
}
- osal_kthread_destroy(g_ppp_rx_thread, 0);
- g_ppp_rx_thread = NULL;
+ osThreadTerminate((osThreadId_t)g_ppp_rx_thread_handle);
+ g_ppp_rx_thread_handle = 0;
}
+#if PPP_USE_DUAL_THREAD
// 停止处理线程
- if (g_ppp_process_thread) {
+ if (g_ppp_process_thread_handle != 0) {
g_ppp_process_thread_running = false;
// 等待处理线程完成
PPP_DEBUG_WARN("PPP process thread did not complete within timeout");
}
- osal_kthread_destroy(g_ppp_process_thread, 0);
- g_ppp_process_thread = NULL;
+ osThreadTerminate((osThreadId_t)g_ppp_process_thread_handle);
+ g_ppp_process_thread_handle = 0;
}
// 清理队列
osal_msg_queue_delete(g_ppp_frame_queue);
g_ppp_frame_queue = 0;
}
-
- // 清理帧拼包器
- ppp_frame_assembler_cleanup();
+#endif
// 重置状态标志
g_ppp_rx_thread_running = false;
- g_ppp_process_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");
return PPP_ERR_OK;
*/
bool ppp_lwip_is_receive_thread_running(void)
{
- return g_ppp_rx_thread_running && (g_ppp_rx_thread != NULL) &&
- g_ppp_process_thread_running && (g_ppp_process_thread != NULL);
+#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
}
/**
#include "ppp_config.h"
#include "ppp_types.h"
#include "ppp_debug.h"
+#include "ppp_interrupt.h" // 添加此头文件以访问 ppp_interrupt_get_buffer_config
#include "uart.h" // 简化路径
#include "schedule/osal_task.h"
#include "semaphore/osal_semaphore.h"
// }
// PPP_DEBUG_INFO("UART deinitialized successfully");
- /* 初始化UART */
- PPP_DEBUG_DEBUG("Calling uapi_uart_init...");
- // errcode_t ret = uapi_uart_init(g_serial_ctx.uart_bus,
- // &g_serial_ctx.pin_config,
- // &g_serial_ctx.uart_attr,
- // NULL,
- // &g_serial_ctx.buffer_config);
- errcode_t ret = uapi_uart_set_attr(g_serial_ctx.uart_bus, &g_serial_ctx.uart_attr);
+ /* 初始化UART - 使用PPP中断模块提供的硬件缓冲区配置 */
+ PPP_DEBUG_DEBUG("Calling uapi_uart_init with buffer config...");
+
+ // 从ppp_interrupt模块获取硬件缓冲区配置
+ void *hw_buffer = NULL;
+ uint32_t hw_buffer_size = 0;
+ ppp_interrupt_get_buffer_config(&hw_buffer, &hw_buffer_size);
+
+ uart_buffer_config_t hw_buffer_config = {
+ .rx_buffer = hw_buffer,
+ .rx_buffer_size = hw_buffer_size
+ };
+
+ PPP_DEBUG_INFO("Using hardware buffer: %u bytes at 0x%p", hw_buffer_size, hw_buffer);
+
+ errcode_t ret = uapi_uart_init(g_serial_ctx.uart_bus,
+ &g_serial_ctx.pin_config,
+ &g_serial_ctx.uart_attr,
+ NULL,
+ &hw_buffer_config); // 使用硬件缓冲区配置
if (ret != ERRCODE_SUCC) {
PPP_DEBUG_ERROR("Failed to initialize UART: error code = %d (0x%x)", ret, ret);
PPP_DEBUG_ERROR("UART init failed with bus=%u, tx_pin=%u, rx_pin=%u, baudrate=%u",
return PPP_ERR_UART;
}
- PPP_DEBUG_INFO("UART initialized successfully (error code = %d)", ret);
+ PPP_DEBUG_INFO("UART initialized successfully with %u-byte hardware buffer", hw_buffer_size);
/* 创建同步对象 */
PPP_DEBUG_DEBUG("Creating synchronization objects...");
case PPP_SERIAL_MODE_PPP_DATA:
/* PPP数据模式:使用优化的直接UART读取,平衡响应性和完整性 */
{
- /* 使用适中的超时时间来平衡响应性和帧完整性 */
- // PPP_DEBUG_DEBUG("PPP mode: Attempting UART read (timeout: 200ms)");
- /* 优化PPP数据模式读取超时:使用配置的优化值以提高协商响应速度 */
- int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, PPP_OPTIMIZED_UART_READ_TIMEOUT);
- if (read_result > 0) {
- *bytes_read = (uint32_t)read_result;
- g_serial_ctx.rx_bytes += *bytes_read;
+ /* 使用类似SLIP的高效读取策略:
+ * 1. 首次尝试非阻塞读取(1ms超时)
+ * 2. 如果有数据,继续快速读取直到无数据
+ * 3. 这样可以批量读取连续到达的数据,提高效率
+ */
+ uint32_t total_read = 0;
+ const uint32_t MAX_BATCH_READ = 8; // 最多批量读取8次
+ uint32_t batch_count = 0;
+
+ while (batch_count < MAX_BATCH_READ && total_read < buffer_size) {
+ uint32_t remaining = buffer_size - total_read;
+ uint8_t *current_buffer = buffer + total_read;
- PPP_DEBUG_INFO("PPP UART Read: Received %u bytes (optimized mode)", *bytes_read);
- PPP_DEBUG_PRINT("PPP RX Data: ");
- for (uint32_t i = 0; i < *bytes_read && i < 16; i++) {
- PPP_DEBUG_PRINT("%02X ", buffer[i]);
- }
- PPP_DEBUG_PRINT("... (total %u bytes)\n", *bytes_read);
+ // 使用短超时进行读取,类似sio_tryread的1ms超时
+ int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, current_buffer,
+ remaining, batch_count == 0 ? 10 : 1);
- return PPP_ERR_OK;
- } else if (read_result == 0) {
- /* 超时,无数据可读 */
- *bytes_read = 0;
- // PPP_DEBUG_DEBUG("PPP UART Read: No data available (timeout)");
+ if (read_result > 0) {
+ total_read += (uint32_t)read_result;
+ g_serial_ctx.rx_bytes += (uint32_t)read_result;
+ batch_count++;
+
+ PPP_DEBUG_DEBUG("PPP batch read %u: got %d bytes (total: %u)",
+ batch_count, read_result, total_read);
+
+ // 如果读取的数据少于请求的数据,说明没有更多数据了
+ if ((uint32_t)read_result < remaining) {
+ break;
+ }
+ } else if (read_result == 0) {
+ // 超时,无更多数据
+ break;
+ } else {
+ // 读取错误
+ if (total_read == 0) {
+ PPP_DEBUG_ERROR("PPP UART Read: Error %d", read_result);
+ return PPP_ERR_UART;
+ }
+ break;
+ }
+ }
+
+ *bytes_read = total_read;
+
+ if (total_read > 0) {
+ PPP_DEBUG_DEBUG("PPP optimized read: %u bytes in %u batches", total_read, batch_count);
return PPP_ERR_OK;
} else {
- /* UART读取错误 */
- *bytes_read = 0;
- g_serial_ctx.rx_errors++;
- PPP_DEBUG_ERROR("PPP UART Read: Error %d", read_result);
- return PPP_ERR_UART;
+ return PPP_ERR_OK; // 无数据但无错误
}
}
break;
return result;
}
+/**
+ * @brief PPP快速尝试读取 - 类似SLIP的sio_tryread,使用1ms超时
+ * @param buffer 接收缓冲区
+ * @param buffer_size 缓冲区大小
+ * @param bytes_read 实际读取字节数
+ * @return 错误码
+ */
+ppp_error_t ppp_serial_tryread(uint8_t *buffer, uint32_t buffer_size, uint32_t *bytes_read)
+{
+ if (!g_serial_ctx.initialized || !buffer || !bytes_read || buffer_size == 0) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ *bytes_read = 0;
+
+ 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);
+ if (read_result > 0) {
+ *bytes_read = (uint32_t)read_result;
+ g_serial_ctx.rx_bytes += *bytes_read;
+ return PPP_ERR_OK;
+ } else if (read_result == 0) {
+ /* 超时,无数据可读 */
+ return PPP_ERR_OK;
+ } else {
+ /* UART读取错误 */
+ PPP_DEBUG_ERROR("PPP UART tryread error: %d", read_result);
+ return PPP_ERR_UART;
+ }
+ } else {
+ /* AT模式:使用标准读取 */
+ return ppp_serial_read(buffer, buffer_size, bytes_read);
+ }
+}
+
/**
* @brief 等待数据接收
*/
/**
* @brief 获取统计信息
*/
-uint32_t ppp_serial_get_stats(ppp_serial_stats_t *stats)
+ppp_error_t ppp_serial_get_stats(ppp_serial_stats_t *stats)
{
if (!g_serial_ctx.initialized || !stats) {
return PPP_ERR_INVALID_PARAM;
osal_mutex_unlock(&g_serial_ctx.tx_mutex);
return PPP_ERR_OK;
+}
+
+/**
+ * @brief 获取UART总线号
+ * @return UART总线号,如果未初始化返回UART_BUS_0
+ */
+uint8_t ppp_serial_get_uart_bus(void)
+{
+ return g_serial_ctx.uart_bus;
}
/* 内部函数实现 */
#define TCP_TEST_DEFAULT_RECV_TIMEOUT_MS 1000 // 默认接收超时1000ms
/* 新的固定数据模式配置 */
-#define TCP_TEST_FIXED_DATA_SIZE 1024 // 固定数据长度,可通过宏配置
+#define TCP_TEST_FIXED_DATA_SIZE 2048 // 固定数据长度,可通过宏配置
#define TCP_DATA_PATTERN_CYCLE 256 // 数据模式循环:0x00 ~ 0xFF
/* TCP测试配置结构体 */
}
*send_arg = conn_id;
- TCP_TASK_CREATE(tcp_test_send_worker, send_arg, "tcp_send", 2048);
+ TCP_TASK_CREATE(tcp_test_send_worker, send_arg, "tcp_send", 4096);
// 创建接收线程
uint16_t *recv_arg = malloc(sizeof(uint16_t));
}
*recv_arg = conn_id;
- TCP_TASK_CREATE(tcp_test_recv_worker, recv_arg, "tcp_recv", 2048);
+ TCP_TASK_CREATE(tcp_test_recv_worker, recv_arg, "tcp_recv", 4096);
return ERRCODE_SUCC;
}
-
/**
* @brief 发送工作线程 - 只负责发送固定模式数据
*/
conn->send_thread_running = true;
- // å\88\86é\85\8då\8f\91é\80\81ç¼\93å\86²å\8cº - 使ç\94¨å\8a¨æ\80\81å\88\86é\85\8dé\81¿å\85\8dæ \88溢å\87º
- uint8_t *send_buffer = malloc(TCP_TEST_FIXED_DATA_SIZE);
- if (!send_buffer) {
+ // å\8f\91é\80\81å\9bºå®\9a大å°\8fç\9a\84æ\95°æ\8d®å\8c\85
+ uint8_t *send_data = (uint8_t *)malloc(TCP_TEST_FIXED_DATA_SIZE);
+ if (send_data == NULL) {
ZHIHUI_TCP_LOG_ERROR("[发送 %03d] 内存分配失败", conn_id);
- conn->send_thread_running = false;
- return NULL;
+ goto cleanup;
}
- uint32_t test_end_time = g_tcp_test_manager.global_stats.start_time +
- (config->test_duration * 1000);
+ // 填充测试数据
+ for (int i = 0; i < TCP_TEST_FIXED_DATA_SIZE; i++) {
+ send_data[i] = (uint8_t)(i & 0xFF);
+ }
ZHIHUI_TCP_LOG_INFO("[发送 %03d] 开始发送数据,固定长度: %d 字节", conn_id, TCP_TEST_FIXED_DATA_SIZE);
+ uint32_t test_end_time = g_tcp_test_manager.global_stats.start_time +
+ (config->test_duration * 1000);
+
uint32_t packet_counter = 0;
uint32_t send_interval_ms = config->send_interval_ms;
uint32_t last_send_time = 0;
if (can_send) {
// 生成固定模式数据
- errcode_t ret = tcp_test_generate_fixed_pattern_data(current_pattern, send_buffer, TCP_TEST_FIXED_DATA_SIZE);
+ errcode_t ret = tcp_test_generate_fixed_pattern_data(current_pattern, send_data, TCP_TEST_FIXED_DATA_SIZE);
if (ret != ERRCODE_SUCC) {
TCP_MUTEX_LOCK(g_tcp_stats_mutex);
conn->send_errors++;
}
// 发送数据
- ssize_t bytes_sent = TCP_SEND(conn->socket_fd, send_buffer, TCP_TEST_FIXED_DATA_SIZE, 0);
+ ssize_t bytes_sent = TCP_SEND(conn->socket_fd, send_data, TCP_TEST_FIXED_DATA_SIZE, 0);
if (bytes_sent > 0) {
TCP_MUTEX_LOCK(g_tcp_stats_mutex);
TCP_SLEEP_MS(send_interval_ms );
}
- free(send_buffer);
+ free(send_data);
+cleanup:
conn->send_thread_running = false;
ZHIHUI_TCP_LOG_INFO("[发送 %03d] 发送线程结束,总发送: %d 包", conn_id, packet_counter);
conn->recv_thread_running = true;
// 分配接收缓冲区
- uint8_t *recv_buffer = malloc(TCP_TEST_FIXED_DATA_SIZE * 4); // 多缓冲一些数据
+ uint8_t *recv_buffer = malloc(TCP_TEST_FIXED_DATA_SIZE * 4); // 多缓冲一些数据
if (!recv_buffer) {
ZHIHUI_TCP_LOG_ERROR("[接收 %03d] 内存分配失败", conn_id);
conn->recv_errors++;