From: 孙春阳 Date: Tue, 30 Sep 2025 07:23:38 +0000 (+0800) Subject: pppc测试相关更新,目前主要问题在串口数据接收 X-Git-Tag: V1.0.9_20251128_194606_LN~282 X-Git-Url: http://git.snicker.com.cn/css/static/gitweb.css?a=commitdiff_plain;h=refs%2Fchanges%2F2451%2Fhead;p=mirrors%2FFD230.git pppc测试相关更新,目前主要问题在串口数据接收 --- diff --git a/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include/lwip/lwipopts_default.h b/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include/lwip/lwipopts_default.h index f48813ef8..0ec4bb52f 100644 --- a/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include/lwip/lwipopts_default.h +++ b/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include/lwip/lwipopts_default.h @@ -55,9 +55,16 @@ extern "C" { #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 @@ -136,6 +143,17 @@ extern "C" { #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 @@ -1342,11 +1360,11 @@ extern "C" { * 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 @@ -1354,7 +1372,7 @@ extern "C" { #endif #ifndef NETIF_DEBUG -#define NETIF_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_ON #endif #ifndef L3_EVENT_MSG_DEBUG @@ -2122,7 +2140,7 @@ upto 255 interfaces . New versions donot have these restrictions but we stick to * 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 diff --git a/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/include/netif/ppp/pppdebug.h b/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/include/netif/ppp/pppdebug.h index 36ee4f9bf..1a1c6bd56 100644 --- a/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/include/netif/ppp/pppdebug.h +++ b/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/include/netif/ppp/pppdebug.h @@ -49,7 +49,7 @@ extern "C" { #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) diff --git a/code/sdk/zhihui/ai_stub/src/ppp_stub_functions.c b/code/sdk/zhihui/ai_stub/src/ppp_stub_functions.c index cc4caa5be..4ac37f2b3 100644 --- a/code/sdk/zhihui/ai_stub/src/ppp_stub_functions.c +++ b/code/sdk/zhihui/ai_stub/src/ppp_stub_functions.c @@ -28,63 +28,9 @@ int httpc_get_file_dns_to_disk(const char *url, const char *file_path, int timeo 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 diff --git a/code/sdk/zhihui/ppp/CMakeLists.txt b/code/sdk/zhihui/ppp/CMakeLists.txt index bd03b9385..80950319c 100644 --- a/code/sdk/zhihui/ppp/CMakeLists.txt +++ b/code/sdk/zhihui/ppp/CMakeLists.txt @@ -13,15 +13,16 @@ set(PPP_AT_CMD_SOURCE ) # 源文件列表 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} ) @@ -62,7 +63,7 @@ set(PUBLIC_DEFINES 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 @@ -70,7 +71,7 @@ set(PUBLIC_DEFINES LWIP_DNS=1 DNS_TABLE_SIZE=2 # 启用IPCP调试 - IPCP_DEBUG=LWIP_DBG_ON + IPCP_DEBUG=0x80U # 确保IPCP功能完全启用 PPP_IPV4_SUPPORT=1 # 启用LCP相关功能 diff --git a/code/sdk/zhihui/ppp/example/ppp_at_cmd.c b/code/sdk/zhihui/ppp/example/ppp_at_cmd.c index 8442a88fd..e8aff5d63 100644 --- a/code/sdk/zhihui/ppp/example/ppp_at_cmd.c +++ b/code/sdk/zhihui/ppp/example/ppp_at_cmd.c @@ -1796,7 +1796,7 @@ static errcode_t at_ppp_tcp_performance_test(uint8_t *para, uint32_t paraLen) config.test_duration = (uint32_t)test_time; config.connection_count = (uint16_t)connections; config.verbose = true; // AT命令模式不使用详细输出 - config.send_interval_ms = 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; // 可配置的接收超时 diff --git a/code/sdk/zhihui/ppp/include/ppp_config.h b/code/sdk/zhihui/ppp/include/ppp_config.h index d4c15cf66..1bad8038a 100644 --- a/code/sdk/zhihui/ppp/include/ppp_config.h +++ b/code/sdk/zhihui/ppp/include/ppp_config.h @@ -49,6 +49,23 @@ extern "C" { #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 // 发送缓冲区大小 @@ -57,10 +74,6 @@ extern "C" { #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) diff --git a/code/sdk/zhihui/ppp/include/ppp_interrupt.h b/code/sdk/zhihui/ppp/include/ppp_interrupt.h new file mode 100644 index 000000000..19bdd8f6b --- /dev/null +++ b/code/sdk/zhihui/ppp/include/ppp_interrupt.h @@ -0,0 +1,93 @@ +/** + * @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 +#include + +#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 diff --git a/code/sdk/zhihui/ppp/include/ppp_lwip.h b/code/sdk/zhihui/ppp/include/ppp_lwip.h index 8c91bd8b7..40acb8ec5 100644 --- a/code/sdk/zhihui/ppp/include/ppp_lwip.h +++ b/code/sdk/zhihui/ppp/include/ppp_lwip.h @@ -159,6 +159,23 @@ ppp_error_t ppp_lwip_trigger_keepalive(void); */ 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 diff --git a/code/sdk/zhihui/ppp/include/ppp_serial.h b/code/sdk/zhihui/ppp/include/ppp_serial.h index 876339622..2d7f2b538 100644 --- a/code/sdk/zhihui/ppp/include/ppp_serial.h +++ b/code/sdk/zhihui/ppp/include/ppp_serial.h @@ -99,6 +99,15 @@ ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length); */ 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 超时时间(毫秒) @@ -150,8 +159,33 @@ ppp_error_t ppp_serial_set_rx_callback(ppp_serial_rx_callback_t callback, void * /** * @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 重置串口状态 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/performance_test.c b/code/sdk/zhihui/ppp/ppp_dec_test/performance_test.c new file mode 100644 index 000000000..64972aa8e --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/performance_test.c @@ -0,0 +1,318 @@ +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_analyzer.py b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_analyzer.py new file mode 100644 index 000000000..6d11c3a5c --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_analyzer.py @@ -0,0 +1,514 @@ +#!/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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_file_reader.c b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_file_reader.c new file mode 100644 index 000000000..ae01ea0eb --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_file_reader.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include +#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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_packet_analyzer.c b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_packet_analyzer.c new file mode 100644 index 000000000..28500ceeb --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_packet_analyzer.c @@ -0,0 +1,519 @@ +#include "ppp_packet_analyzer.h" +#include +#include +#include + +/* 内部辅助函数声明 */ +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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_packet_analyzer.h b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_packet_analyzer.h new file mode 100644 index 000000000..b09b24ede --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_packet_analyzer.h @@ -0,0 +1,236 @@ +#ifndef PPP_PACKET_ANALYZER_H +#define PPP_PACKET_ANALYZER_H + +#include +#include +#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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser.c b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser.c new file mode 100644 index 000000000..a2f3c54ee --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser.c @@ -0,0 +1,383 @@ +#include "ppp_parser.h" +#include +#include +#include + +/* 内部辅助函数声明 */ +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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser.h b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser.h new file mode 100644 index 000000000..0453da52e --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser.h @@ -0,0 +1,158 @@ +#ifndef PPP_PARSER_H +#define PPP_PARSER_H + +#include +#include +#include + +/* 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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_configurable.h b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_configurable.h new file mode 100644 index 000000000..79450da31 --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_configurable.h @@ -0,0 +1,158 @@ +#ifndef PPP_PARSER_CONFIGURABLE_H +#define PPP_PARSER_CONFIGURABLE_H + +#include +#include +#include + +/* 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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_dynamic.c b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_dynamic.c new file mode 100644 index 000000000..f7cae640b --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_dynamic.c @@ -0,0 +1,272 @@ +#include "ppp_parser_dynamic.h" +#include +#include +#include + +/** + * 初始化动态缓冲区 + */ +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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_dynamic.h b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_dynamic.h new file mode 100644 index 000000000..c580aaa39 --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_dynamic.h @@ -0,0 +1,125 @@ +#ifndef PPP_PARSER_DYNAMIC_H +#define PPP_PARSER_DYNAMIC_H + +#include +#include +#include + +/* 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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_streaming.h b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_streaming.h new file mode 100644 index 000000000..c199213cd --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_parser_streaming.h @@ -0,0 +1,164 @@ +#ifndef PPP_PARSER_STREAMING_H +#define PPP_PARSER_STREAMING_H + +#include +#include +#include + +/* 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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_parser.c b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_parser.c new file mode 100644 index 000000000..8b076d9a4 --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_parser.c @@ -0,0 +1,397 @@ +#include "ppp_stream_parser.h" +#include +#include +#include + +/** + * 初始化流式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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_parser.h b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_parser.h new file mode 100644 index 000000000..b71009483 --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_parser.h @@ -0,0 +1,206 @@ +#ifndef PPP_STREAM_PARSER_H +#define PPP_STREAM_PARSER_H + +#include +#include +#include + +/* 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 diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_test b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_test new file mode 100644 index 000000000..d63d4e01a Binary files /dev/null and b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_test differ diff --git a/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_test.c b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_test.c new file mode 100644 index 000000000..b03bb9537 --- /dev/null +++ b/code/sdk/zhihui/ppp/ppp_dec_test/ppp_stream_test.c @@ -0,0 +1,376 @@ +#include +#include +#include +#include +#include +#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 diff --git a/code/sdk/zhihui/ppp/src/ppp_api.c b/code/sdk/zhihui/ppp/src/ppp_api.c index f2ebc5201..4e33027f3 100644 --- a/code/sdk/zhihui/ppp/src/ppp_api.c +++ b/code/sdk/zhihui/ppp/src/ppp_api.c @@ -6,6 +6,7 @@ #include "ppp_serial.h" // 添加串口处理头文件 #include "ppp_lwip.h" #include "ppp_cat1_api.h" +#include "ppp_interrupt.h" // 添加中断处理头文件 #include "soc_osal.h" #include #include // 添加malloc/free支持 @@ -432,12 +433,26 @@ errcode_t ppp_start_dial(void) 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 = "", @@ -568,14 +583,11 @@ errcode_t ppp_stop_dial(void) 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..."); @@ -591,6 +603,23 @@ errcode_t ppp_stop_dial(void) // 等待确保前面的操作完成 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[] = "+++"; diff --git a/code/sdk/zhihui/ppp/src/ppp_interrupt.c b/code/sdk/zhihui/ppp/src/ppp_interrupt.c new file mode 100644 index 000000000..1827c178a --- /dev/null +++ b/code/sdk/zhihui/ppp/src/ppp_interrupt.c @@ -0,0 +1,257 @@ +/** + * @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 +#include + +/* 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 diff --git a/code/sdk/zhihui/ppp/src/ppp_lwip.c b/code/sdk/zhihui/ppp/src/ppp_lwip.c index 619b358f3..b57fa1e25 100644 --- a/code/sdk/zhihui/ppp/src/ppp_lwip.c +++ b/code/sdk/zhihui/ppp/src/ppp_lwip.c @@ -64,7 +64,7 @@ typedef struct { 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); @@ -293,16 +293,22 @@ ppp_error_t ppp_lwip_init(const ppp_lwip_config_t *config) 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; @@ -930,13 +936,22 @@ static void ppp_lwip_netif_status_callback(struct netif *netif) */ 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(); @@ -1309,5 +1324,78 @@ ppp_error_t ppp_lwip_get_output_stats(ppp_lwip_output_stats_t *stats) 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 diff --git a/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c b/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c index bf798adaa..661032289 100644 --- a/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c +++ b/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c @@ -1,6 +1,10 @@ /** * @file ppp_lwip_thread.c - * @brief PPP接收线程实现 - 双线程架构:接收线程拼包 + 处理线程处理 + * @brief PPP接收线程实现 - 支持单线程和双线程模式 + * + * 线程模式配置: + * - PPP_USE_DUAL_THREAD=1: 双线程模式(接收线程拼包 + 处理线程处理) + * - PPP_USE_DUAL_THREAD=0: 单线程模式(接收线程直接处理) */ #include "ppp_api.h" @@ -11,104 +15,100 @@ #include "soc_osal.h" #include "schedule/osal_task.h" #include "msgqueue/osal_msgqueue.h" +#include "custom_utils.h" #include #include -/* 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 初始化PPP帧拼包器 + * @brief 处理PPP数据并打印详细信息(单线程模式专用) */ -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 发送完整PPP帧到队列 + * @brief 处理接收到的数据块(双线程模式) */ -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; } @@ -118,9 +118,8 @@ static ppp_error_t ppp_send_frame_to_queue(const uint8_t *data, uint32_t length) 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; } @@ -131,9 +130,8 @@ static ppp_error_t ppp_send_frame_to_queue(const uint8_t *data, uint32_t length) 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; @@ -146,100 +144,30 @@ static ppp_error_t ppp_send_frame_to_queue(const uint8_t *data, uint32_t length) // 发送到队列 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); @@ -250,60 +178,88 @@ static void ppp_lwip_receive_thread(void *arg) } 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) { @@ -311,45 +267,47 @@ 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) { // 超时或其他错误 @@ -357,95 +315,118 @@ static void ppp_lwip_process_thread(void *arg) 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; } @@ -454,14 +435,20 @@ ppp_error_t ppp_lwip_start_receive_thread(void) */ 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; // 等待接收线程完成 @@ -479,12 +466,13 @@ ppp_error_t ppp_lwip_stop_receive_thread(void) 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; // 等待处理线程完成 @@ -502,8 +490,8 @@ ppp_error_t ppp_lwip_stop_receive_thread(void) 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; } // 清理队列 @@ -511,15 +499,15 @@ ppp_error_t ppp_lwip_stop_receive_thread(void) 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; @@ -530,8 +518,12 @@ ppp_error_t ppp_lwip_stop_receive_thread(void) */ bool ppp_lwip_is_receive_thread_running(void) { - return g_ppp_rx_thread_running && (g_ppp_rx_thread != NULL) && - 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 } /** diff --git a/code/sdk/zhihui/ppp/src/ppp_serial.c b/code/sdk/zhihui/ppp/src/ppp_serial.c index 822706a93..a444b64bd 100644 --- a/code/sdk/zhihui/ppp/src/ppp_serial.c +++ b/code/sdk/zhihui/ppp/src/ppp_serial.c @@ -2,6 +2,7 @@ #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" @@ -171,14 +172,26 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) // } // 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", @@ -191,7 +204,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) 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..."); @@ -484,33 +497,55 @@ ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *byt 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; @@ -549,6 +584,42 @@ ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *byt 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 等待数据接收 */ @@ -786,7 +857,7 @@ ppp_serial_mode_t ppp_serial_get_mode(void) /** * @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; @@ -808,6 +879,15 @@ uint32_t ppp_serial_get_stats(ppp_serial_stats_t *stats) 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; } /* 内部函数实现 */ diff --git a/code/sdk/zhihui/tcptest/include/zhihui_tcp_test.h b/code/sdk/zhihui/tcptest/include/zhihui_tcp_test.h index b3b7cfe38..80ac3726a 100644 --- a/code/sdk/zhihui/tcptest/include/zhihui_tcp_test.h +++ b/code/sdk/zhihui/tcptest/include/zhihui_tcp_test.h @@ -118,7 +118,7 @@ extern "C" { #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测试配置结构体 */ diff --git a/code/sdk/zhihui/tcptest/src/zhihui_tcp_test.c b/code/sdk/zhihui/tcptest/src/zhihui_tcp_test.c index a59c7567f..0f62ad9cd 100644 --- a/code/sdk/zhihui/tcptest/src/zhihui_tcp_test.c +++ b/code/sdk/zhihui/tcptest/src/zhihui_tcp_test.c @@ -350,7 +350,7 @@ static errcode_t tcp_test_create_connection_threads(uint16_t conn_id) } *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)); @@ -361,11 +361,10 @@ static errcode_t tcp_test_create_connection_threads(uint16_t conn_id) } *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 发送工作线程 - 只负责发送固定模式数据 */ @@ -379,19 +378,23 @@ static void* tcp_test_send_worker(void *arg) conn->send_thread_running = true; - // 分配发送缓冲区 - 使用动态分配避免栈溢出 - uint8_t *send_buffer = malloc(TCP_TEST_FIXED_DATA_SIZE); - if (!send_buffer) { + // 发送固定大小的数据包 + 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; @@ -408,7 +411,7 @@ static void* tcp_test_send_worker(void *arg) 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++; @@ -419,7 +422,7 @@ static void* tcp_test_send_worker(void *arg) } // 发送数据 - 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); @@ -459,7 +462,8 @@ static void* tcp_test_send_worker(void *arg) 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); @@ -480,7 +484,7 @@ static void* tcp_test_recv_worker(void *arg) 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++;